@jaggerxtrm/specialists 2.1.0 → 2.1.2
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/dist/index.js +76 -11
- 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/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, {
|
|
@@ -25080,6 +25085,57 @@ class PiAgentSession {
|
|
|
25080
25085
|
}
|
|
25081
25086
|
|
|
25082
25087
|
// src/specialist/beads.ts
|
|
25088
|
+
import { spawnSync } from "node:child_process";
|
|
25089
|
+
|
|
25090
|
+
class BeadsClient {
|
|
25091
|
+
available;
|
|
25092
|
+
constructor() {
|
|
25093
|
+
this.available = BeadsClient.checkAvailable();
|
|
25094
|
+
if (!this.available) {
|
|
25095
|
+
console.warn("[specialists] bd CLI not found — beads tracking disabled");
|
|
25096
|
+
}
|
|
25097
|
+
}
|
|
25098
|
+
static checkAvailable() {
|
|
25099
|
+
const result = spawnSync("bd", ["--version"], { stdio: "ignore" });
|
|
25100
|
+
return result.status === 0;
|
|
25101
|
+
}
|
|
25102
|
+
isAvailable() {
|
|
25103
|
+
return this.available;
|
|
25104
|
+
}
|
|
25105
|
+
createBead(specialistName) {
|
|
25106
|
+
if (!this.available)
|
|
25107
|
+
return null;
|
|
25108
|
+
const result = spawnSync("bd", ["q", `specialist:${specialistName}`, "--type", "task", "--labels", "specialist"], { encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] });
|
|
25109
|
+
if (result.status !== 0)
|
|
25110
|
+
return null;
|
|
25111
|
+
const id = result.stdout?.trim();
|
|
25112
|
+
return id || null;
|
|
25113
|
+
}
|
|
25114
|
+
closeBead(id, status, durationMs, model) {
|
|
25115
|
+
if (!this.available || !id)
|
|
25116
|
+
return;
|
|
25117
|
+
const reason = `${status}, ${Math.round(durationMs)}ms, ${model}`;
|
|
25118
|
+
spawnSync("bd", ["close", id, "-r", reason], { stdio: "ignore" });
|
|
25119
|
+
}
|
|
25120
|
+
auditBead(id, toolName, model, exitCode) {
|
|
25121
|
+
if (!this.available || !id)
|
|
25122
|
+
return;
|
|
25123
|
+
spawnSync("bd", [
|
|
25124
|
+
"audit",
|
|
25125
|
+
"record",
|
|
25126
|
+
"--kind",
|
|
25127
|
+
"tool_call",
|
|
25128
|
+
"--tool-name",
|
|
25129
|
+
toolName,
|
|
25130
|
+
"--model",
|
|
25131
|
+
model,
|
|
25132
|
+
"--issue-id",
|
|
25133
|
+
id,
|
|
25134
|
+
"--exit-code",
|
|
25135
|
+
String(exitCode)
|
|
25136
|
+
], { stdio: "ignore" });
|
|
25137
|
+
}
|
|
25138
|
+
}
|
|
25083
25139
|
function shouldCreateBead(beadsIntegration, permissionRequired) {
|
|
25084
25140
|
if (beadsIntegration === "never")
|
|
25085
25141
|
return false;
|
|
@@ -25096,7 +25152,7 @@ class SpecialistRunner {
|
|
|
25096
25152
|
this.deps = deps;
|
|
25097
25153
|
this.sessionFactory = deps.sessionFactory ?? PiAgentSession.create.bind(PiAgentSession);
|
|
25098
25154
|
}
|
|
25099
|
-
async run(options, onProgress, onEvent, onMeta, onKillRegistered) {
|
|
25155
|
+
async run(options, onProgress, onEvent, onMeta, onKillRegistered, onBeadCreated) {
|
|
25100
25156
|
const { loader, hooks, circuitBreaker, beadsClient } = this.deps;
|
|
25101
25157
|
const invocationId = crypto.randomUUID();
|
|
25102
25158
|
const start = Date.now();
|
|
@@ -25156,6 +25212,8 @@ You have access via Bash:
|
|
|
25156
25212
|
let beadId;
|
|
25157
25213
|
if (beadsClient && shouldCreateBead(beadsIntegration, execution.permission_required)) {
|
|
25158
25214
|
beadId = beadsClient.createBead(metadata.name) ?? undefined;
|
|
25215
|
+
if (beadId)
|
|
25216
|
+
onBeadCreated?.(beadId);
|
|
25159
25217
|
}
|
|
25160
25218
|
let output;
|
|
25161
25219
|
let session;
|
|
@@ -25240,7 +25298,7 @@ You have access via Bash:
|
|
|
25240
25298
|
model: "?",
|
|
25241
25299
|
specialistVersion
|
|
25242
25300
|
});
|
|
25243
|
-
this.run(options, (text) => registry2.appendOutput(jobId, text), (eventType) => registry2.setCurrentEvent(jobId, eventType), (meta) => registry2.setMeta(jobId, meta), (killFn) => registry2.setKillFn(jobId, killFn)).then((result) => registry2.complete(jobId, result)).catch((err) => registry2.fail(jobId, err));
|
|
25301
|
+
this.run(options, (text) => registry2.appendOutput(jobId, text), (eventType) => registry2.setCurrentEvent(jobId, eventType), (meta) => registry2.setMeta(jobId, meta), (killFn) => registry2.setKillFn(jobId, killFn), (beadId) => registry2.setBeadId(jobId, beadId)).then((result) => registry2.complete(jobId, result)).catch((err) => registry2.fail(jobId, err));
|
|
25244
25302
|
return jobId;
|
|
25245
25303
|
}
|
|
25246
25304
|
}
|
|
@@ -25343,7 +25401,7 @@ var useSpecialistSchema = exports_external.object({
|
|
|
25343
25401
|
function createUseSpecialistTool(runner) {
|
|
25344
25402
|
return {
|
|
25345
25403
|
name: "use_specialist",
|
|
25346
|
-
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.",
|
|
25347
25405
|
inputSchema: useSpecialistSchema,
|
|
25348
25406
|
async execute(input, onProgress) {
|
|
25349
25407
|
return runner.run({
|
|
@@ -25584,7 +25642,7 @@ var startSpecialistSchema = exports_external.object({
|
|
|
25584
25642
|
function createStartSpecialistTool(runner, registry2) {
|
|
25585
25643
|
return {
|
|
25586
25644
|
name: "start_specialist",
|
|
25587
|
-
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.",
|
|
25588
25646
|
inputSchema: startSpecialistSchema,
|
|
25589
25647
|
async execute(input) {
|
|
25590
25648
|
const jobId = await runner.startAsync({
|
|
@@ -25606,7 +25664,7 @@ var pollSpecialistSchema = exports_external.object({
|
|
|
25606
25664
|
function createPollSpecialistTool(registry2) {
|
|
25607
25665
|
return {
|
|
25608
25666
|
name: "poll_specialist",
|
|
25609
|
-
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.',
|
|
25610
25668
|
inputSchema: pollSpecialistSchema,
|
|
25611
25669
|
async execute(input) {
|
|
25612
25670
|
const snapshot = registry2.snapshot(input.job_id, input.cursor ?? 0);
|
|
@@ -25638,19 +25696,19 @@ function createStopSpecialistTool(registry2) {
|
|
|
25638
25696
|
}
|
|
25639
25697
|
|
|
25640
25698
|
// src/tools/specialist/specialist_init.tool.ts
|
|
25641
|
-
import { spawnSync } from "node:child_process";
|
|
25699
|
+
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
25642
25700
|
import { existsSync as existsSync2 } from "node:fs";
|
|
25643
25701
|
import { join as join2 } from "node:path";
|
|
25644
|
-
var specialistInitSchema =
|
|
25702
|
+
var specialistInitSchema = objectType({});
|
|
25645
25703
|
function createSpecialistInitTool(loader, deps) {
|
|
25646
25704
|
const resolved = deps ?? {
|
|
25647
|
-
bdAvailable: () =>
|
|
25705
|
+
bdAvailable: () => spawnSync2("bd", ["--version"], { stdio: "ignore" }).status === 0,
|
|
25648
25706
|
beadsExists: () => existsSync2(join2(process.cwd(), ".beads")),
|
|
25649
|
-
bdInit: () =>
|
|
25707
|
+
bdInit: () => spawnSync2("bd", ["init"], { stdio: "ignore" })
|
|
25650
25708
|
};
|
|
25651
25709
|
return {
|
|
25652
25710
|
name: "specialist_init",
|
|
25653
|
-
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.",
|
|
25654
25712
|
inputSchema: specialistInitSchema,
|
|
25655
25713
|
async execute(_input) {
|
|
25656
25714
|
const available = resolved.bdAvailable();
|
|
@@ -25682,7 +25740,8 @@ class SpecialistsServer {
|
|
|
25682
25740
|
const hooks = new HookEmitter({
|
|
25683
25741
|
tracePath: join3(process.cwd(), ".specialists", "trace.jsonl")
|
|
25684
25742
|
});
|
|
25685
|
-
const
|
|
25743
|
+
const beadsClient = new BeadsClient;
|
|
25744
|
+
const runner = new SpecialistRunner({ loader, hooks, circuitBreaker, beadsClient });
|
|
25686
25745
|
const registry2 = new JobRegistry;
|
|
25687
25746
|
this.tools = [
|
|
25688
25747
|
createListSpecialistsTool(loader),
|
|
@@ -25769,6 +25828,12 @@ class SpecialistsServer {
|
|
|
25769
25828
|
}
|
|
25770
25829
|
|
|
25771
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
|
+
}
|
|
25772
25837
|
async function main() {
|
|
25773
25838
|
logger.info("Starting Specialists MCP Server...");
|
|
25774
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.2",
|
|
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",
|