@jaggerxtrm/specialists 2.1.1 → 2.1.3
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 +10 -3
- package/bin/install.js +92 -7
- package/dist/index.js +15 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -86,15 +86,22 @@ The orchestrating agent can retrieve the `beadId` from `poll_specialist` output
|
|
|
86
86
|
|
|
87
87
|
## Installation
|
|
88
88
|
|
|
89
|
-
###
|
|
89
|
+
### Recommended
|
|
90
90
|
|
|
91
91
|
```bash
|
|
92
|
-
|
|
92
|
+
npm install -g @jaggerxtrm/specialists
|
|
93
|
+
specialists install
|
|
93
94
|
```
|
|
94
95
|
|
|
95
96
|
Installs: **pi** (`@mariozechner/pi-coding-agent`), **beads** (`@beads/bd`), **dolt** (interactive sudo on Linux / brew on macOS), registers the `specialists` MCP at user scope, scaffolds `~/.agents/specialists/`.
|
|
96
97
|
|
|
97
|
-
After running, **restart Claude Code** to load the MCP.
|
|
98
|
+
After running, **restart Claude Code** to load the MCP. Re-run `specialists install` at any time to update or repair the installation.
|
|
99
|
+
|
|
100
|
+
### One-time (no global install)
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
npx --package=@jaggerxtrm/specialists install
|
|
104
|
+
```
|
|
98
105
|
|
|
99
106
|
---
|
|
100
107
|
|
package/bin/install.js
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
//
|
|
3
|
-
// Usage: npx --package
|
|
2
|
+
// Specialists Installer
|
|
3
|
+
// Usage: npx --package=@jaggerxtrm/specialists install
|
|
4
4
|
|
|
5
5
|
import { spawnSync } from 'node:child_process';
|
|
6
|
-
import { existsSync, mkdirSync } from 'node:fs';
|
|
6
|
+
import { existsSync, mkdirSync, writeFileSync, readFileSync, chmodSync } from 'node:fs';
|
|
7
7
|
import { homedir } from 'node:os';
|
|
8
8
|
import { join } from 'node:path';
|
|
9
9
|
|
|
10
10
|
const HOME = homedir();
|
|
11
11
|
const SPECIALISTS_DIR = join(HOME, '.agents', 'specialists');
|
|
12
|
+
const CLAUDE_DIR = join(HOME, '.claude');
|
|
13
|
+
const HOOKS_DIR = join(CLAUDE_DIR, 'hooks');
|
|
14
|
+
const SETTINGS_FILE = join(CLAUDE_DIR, 'settings.json');
|
|
15
|
+
const HOOK_FILE = join(HOOKS_DIR, 'specialists-main-guard.sh');
|
|
12
16
|
const MCP_NAME = 'specialists';
|
|
13
17
|
const GITHUB_PKG = '@jaggerxtrm/specialists';
|
|
14
18
|
|
|
@@ -72,8 +76,80 @@ function registerMCP() {
|
|
|
72
76
|
return true;
|
|
73
77
|
}
|
|
74
78
|
|
|
79
|
+
// ── Hook installation ─────────────────────────────────────────────────────────
|
|
80
|
+
|
|
81
|
+
const HOOK_SCRIPT = `#!/usr/bin/env bash
|
|
82
|
+
# specialists — Claude Code PreToolUse hook
|
|
83
|
+
# Blocks writes and git commit/push on main/master branch.
|
|
84
|
+
# Exit 0: allow | Exit 2: block (message shown to user)
|
|
85
|
+
#
|
|
86
|
+
# Installed by: npx --package=@jaggerxtrm/specialists install
|
|
87
|
+
|
|
88
|
+
BRANCH=$(git branch --show-current 2>/dev/null)
|
|
89
|
+
|
|
90
|
+
# Not in a git repo or not on a protected branch — allow
|
|
91
|
+
if [ -z "$BRANCH" ] || { [ "$BRANCH" != "main" ] && [ "$BRANCH" != "master" ]; }; then
|
|
92
|
+
exit 0
|
|
93
|
+
fi
|
|
94
|
+
|
|
95
|
+
INPUT=$(cat)
|
|
96
|
+
TOOL=$(echo "$INPUT" | jq -r '.tool_name' 2>/dev/null)
|
|
97
|
+
|
|
98
|
+
BLOCK_MSG="⛔ Direct edits on '$BRANCH' are not allowed.
|
|
99
|
+
Create a feature branch first: git checkout -b feature/<name>"
|
|
100
|
+
|
|
101
|
+
case "$TOOL" in
|
|
102
|
+
Edit|Write|MultiEdit|NotebookEdit)
|
|
103
|
+
echo "$BLOCK_MSG" >&2
|
|
104
|
+
exit 2
|
|
105
|
+
;;
|
|
106
|
+
Bash)
|
|
107
|
+
CMD=$(echo "$INPUT" | jq -r '.tool_input.command' 2>/dev/null)
|
|
108
|
+
if echo "$CMD" | grep -qE '^git (commit|push)'; then
|
|
109
|
+
echo "$BLOCK_MSG" >&2
|
|
110
|
+
exit 2
|
|
111
|
+
fi
|
|
112
|
+
exit 0
|
|
113
|
+
;;
|
|
114
|
+
*)
|
|
115
|
+
exit 0
|
|
116
|
+
;;
|
|
117
|
+
esac
|
|
118
|
+
`;
|
|
119
|
+
|
|
120
|
+
const HOOK_ENTRY = {
|
|
121
|
+
matcher: 'Edit|Write|MultiEdit|NotebookEdit|Bash',
|
|
122
|
+
hooks: [{ type: 'command', command: HOOK_FILE }],
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
function installHook() {
|
|
126
|
+
// 1. Write hook script
|
|
127
|
+
mkdirSync(HOOKS_DIR, { recursive: true });
|
|
128
|
+
writeFileSync(HOOK_FILE, HOOK_SCRIPT, 'utf8');
|
|
129
|
+
chmodSync(HOOK_FILE, 0o755);
|
|
130
|
+
|
|
131
|
+
// 2. Merge into ~/.claude/settings.json
|
|
132
|
+
let settings = {};
|
|
133
|
+
if (existsSync(SETTINGS_FILE)) {
|
|
134
|
+
try { settings = JSON.parse(readFileSync(SETTINGS_FILE, 'utf8')); } catch { /* malformed, overwrite */ }
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (!Array.isArray(settings.hooks?.PreToolUse)) {
|
|
138
|
+
settings.hooks = settings.hooks ?? {};
|
|
139
|
+
settings.hooks.PreToolUse = [];
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Idempotent: remove any previous specialists-main-guard entry, re-add
|
|
143
|
+
settings.hooks.PreToolUse = settings.hooks.PreToolUse
|
|
144
|
+
.filter(e => !e.hooks?.some(h => h.command?.includes('specialists-main-guard')));
|
|
145
|
+
settings.hooks.PreToolUse.push(HOOK_ENTRY);
|
|
146
|
+
|
|
147
|
+
mkdirSync(CLAUDE_DIR, { recursive: true });
|
|
148
|
+
writeFileSync(SETTINGS_FILE, JSON.stringify(settings, null, 2) + '\n', 'utf8');
|
|
149
|
+
}
|
|
150
|
+
|
|
75
151
|
// ── Main ──────────────────────────────────────────────────────────────────────
|
|
76
|
-
console.log('\n' + bold('
|
|
152
|
+
console.log('\n' + bold(' Specialists — full-stack installer'));
|
|
77
153
|
|
|
78
154
|
// 1. pi
|
|
79
155
|
section('pi (coding agent runtime)');
|
|
@@ -119,7 +195,16 @@ if (!existsSync(SPECIALISTS_DIR)) {
|
|
|
119
195
|
skip('~/.agents/specialists/ already exists');
|
|
120
196
|
}
|
|
121
197
|
|
|
122
|
-
// 6.
|
|
198
|
+
// 6. Claude Code hooks
|
|
199
|
+
section('Claude Code hooks');
|
|
200
|
+
const hookExisted = existsSync(HOOK_FILE);
|
|
201
|
+
installHook();
|
|
202
|
+
hookExisted
|
|
203
|
+
? ok('main-guard hook updated')
|
|
204
|
+
: ok('main-guard hook installed → ~/.claude/hooks/specialists-main-guard.sh');
|
|
205
|
+
info('Blocks Edit/Write/git commit/push on main or master branch');
|
|
206
|
+
|
|
207
|
+
// 7. Health check
|
|
123
208
|
section('Health check');
|
|
124
209
|
if (isInstalled('pi')) {
|
|
125
210
|
const r = spawnSync('pi', ['--list-models'], { encoding: 'utf8' });
|
|
@@ -128,9 +213,9 @@ if (isInstalled('pi')) {
|
|
|
128
213
|
: skip('No active provider — run pi config to set one up');
|
|
129
214
|
}
|
|
130
215
|
|
|
131
|
-
//
|
|
216
|
+
// 8. Done
|
|
132
217
|
console.log('\n' + bold(green(' Done!')));
|
|
133
218
|
console.log('\n' + bold(' Next steps:'));
|
|
134
219
|
console.log(` 1. ${bold('Configure pi:')} run ${yellow('pi')} then ${yellow('pi config')} to enable model providers`);
|
|
135
|
-
console.log(` 2. ${bold('Restart Claude Code')} to load the MCP`);
|
|
220
|
+
console.log(` 2. ${bold('Restart Claude Code')} to load the MCP and hooks`);
|
|
136
221
|
console.log(` 3. ${bold('Update later:')} re-run this installer\n`);
|
package/dist/index.js
CHANGED
|
@@ -13393,6 +13393,11 @@ var require_public_api = __commonJS((exports) => {
|
|
|
13393
13393
|
exports.stringify = stringify;
|
|
13394
13394
|
});
|
|
13395
13395
|
|
|
13396
|
+
// src/index.ts
|
|
13397
|
+
import { execFileSync } from "node:child_process";
|
|
13398
|
+
import { fileURLToPath } from "node:url";
|
|
13399
|
+
import { dirname as dirname2, join as join4 } from "node:path";
|
|
13400
|
+
|
|
13396
13401
|
// node_modules/zod/v3/external.js
|
|
13397
13402
|
var exports_external = {};
|
|
13398
13403
|
__export(exports_external, {
|
|
@@ -25396,7 +25401,7 @@ var useSpecialistSchema = exports_external.object({
|
|
|
25396
25401
|
function createUseSpecialistTool(runner) {
|
|
25397
25402
|
return {
|
|
25398
25403
|
name: "use_specialist",
|
|
25399
|
-
description: "
|
|
25404
|
+
description: "Run a specialist synchronously and wait for the result. " + "Full lifecycle: load → agents.md → pi session → output. " + "Response includes output, model, durationMs, and beadId (string | undefined). " + "beadId is set when the specialist's beads_integration policy triggered bead creation " + "(default: auto — creates for LOW/MEDIUM/HIGH permission, skips for READ_ONLY). " + "If beadId is present, use `bd update <beadId> --notes` to attach findings or " + "`bd remember` to persist key discoveries for future sessions.",
|
|
25400
25405
|
inputSchema: useSpecialistSchema,
|
|
25401
25406
|
async execute(input, onProgress) {
|
|
25402
25407
|
return runner.run({
|
|
@@ -25637,7 +25642,7 @@ var startSpecialistSchema = exports_external.object({
|
|
|
25637
25642
|
function createStartSpecialistTool(runner, registry2) {
|
|
25638
25643
|
return {
|
|
25639
25644
|
name: "start_specialist",
|
|
25640
|
-
description: "Start a specialist asynchronously. Returns job_id immediately
|
|
25645
|
+
description: "Start a specialist asynchronously. Returns job_id immediately. " + "Use poll_specialist to track progress, receive output delta, and retrieve beadId " + "(the beads issue auto-created for this run, if beads_integration policy applies). " + "Use stop_specialist to cancel. Enables true parallel execution of multiple specialists.",
|
|
25641
25646
|
inputSchema: startSpecialistSchema,
|
|
25642
25647
|
async execute(input) {
|
|
25643
25648
|
const jobId = await runner.startAsync({
|
|
@@ -25659,7 +25664,7 @@ var pollSpecialistSchema = exports_external.object({
|
|
|
25659
25664
|
function createPollSpecialistTool(registry2) {
|
|
25660
25665
|
return {
|
|
25661
25666
|
name: "poll_specialist",
|
|
25662
|
-
description: "Poll a running specialist job. Returns status (running|done|error), delta (new
|
|
25667
|
+
description: "Poll a running specialist job. Returns status (running|done|error|cancelled), " + "delta (new tokens since cursor), next_cursor, and full output when done. " + "Pass next_cursor back as cursor on each subsequent poll to receive only new content. " + "Response also includes beadId (string | undefined) once the specialist has started — " + "this is the beads issue tracking this run. If present after status=done, consider: " + '`bd update <beadId> --notes "<key finding>"` to attach results, or ' + '`bd remember "<insight>"` to persist discoveries across sessions.',
|
|
25663
25668
|
inputSchema: pollSpecialistSchema,
|
|
25664
25669
|
async execute(input) {
|
|
25665
25670
|
const snapshot = registry2.snapshot(input.job_id, input.cursor ?? 0);
|
|
@@ -25703,7 +25708,7 @@ function createSpecialistInitTool(loader, deps) {
|
|
|
25703
25708
|
};
|
|
25704
25709
|
return {
|
|
25705
25710
|
name: "specialist_init",
|
|
25706
|
-
description: "
|
|
25711
|
+
description: "Call this first at session start. Returns available specialists and initializes beads " + "tracking (runs `bd init` if not already set up). " + "Response includes: specialists[] (use with use_specialist/start_specialist), " + "beads.available (bool), beads.initialized (bool). " + "If beads.available is true, specialists with permission LOW/MEDIUM/HIGH will auto-create " + "a beads issue when they run — no action needed from you.",
|
|
25707
25712
|
inputSchema: specialistInitSchema,
|
|
25708
25713
|
async execute(_input) {
|
|
25709
25714
|
const available = resolved.bdAvailable();
|
|
@@ -25823,6 +25828,12 @@ class SpecialistsServer {
|
|
|
25823
25828
|
}
|
|
25824
25829
|
|
|
25825
25830
|
// src/index.ts
|
|
25831
|
+
if (process.argv[2] === "install") {
|
|
25832
|
+
const __dirname2 = dirname2(fileURLToPath(import.meta.url));
|
|
25833
|
+
const installerPath = join4(__dirname2, "..", "bin", "install.js");
|
|
25834
|
+
execFileSync(process.execPath, [installerPath], { stdio: "inherit" });
|
|
25835
|
+
process.exit(0);
|
|
25836
|
+
}
|
|
25826
25837
|
async function main() {
|
|
25827
25838
|
logger.info("Starting Specialists MCP Server...");
|
|
25828
25839
|
const server = new SpecialistsServer;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jaggerxtrm/specialists",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.3",
|
|
4
4
|
"description": "OmniSpecialist — 7-tool MCP orchestration layer powered by the Specialist System. Discover and execute .specialist.yaml files across project/user/system scopes via pi.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|