@jaggerxtrm/specialists 2.0.2 → 2.1.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.
- package/dist/index.js +82 -14
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -24568,12 +24568,12 @@ class StdioServerTransport {
|
|
|
24568
24568
|
}
|
|
24569
24569
|
|
|
24570
24570
|
// src/server.ts
|
|
24571
|
-
import { join as
|
|
24571
|
+
import { join as join3 } from "node:path";
|
|
24572
24572
|
|
|
24573
24573
|
// src/constants.ts
|
|
24574
|
-
var LOG_PREFIX = "[
|
|
24574
|
+
var LOG_PREFIX = "[specialists]";
|
|
24575
24575
|
var MCP_CONFIG = {
|
|
24576
|
-
SERVER_NAME: "
|
|
24576
|
+
SERVER_NAME: "specialists",
|
|
24577
24577
|
VERSION: "1.0.0",
|
|
24578
24578
|
CAPABILITIES: {
|
|
24579
24579
|
tools: {},
|
|
@@ -24748,6 +24748,7 @@ var SpecialistSchema = objectType({
|
|
|
24748
24748
|
capabilities: CapabilitiesSchema,
|
|
24749
24749
|
communication: CommunicationSchema,
|
|
24750
24750
|
validation: ValidationSchema,
|
|
24751
|
+
beads_integration: enumType(["auto", "always", "never"]).default("auto"),
|
|
24751
24752
|
heartbeat: unknownType().optional()
|
|
24752
24753
|
})
|
|
24753
24754
|
});
|
|
@@ -25078,6 +25079,15 @@ class PiAgentSession {
|
|
|
25078
25079
|
}
|
|
25079
25080
|
}
|
|
25080
25081
|
|
|
25082
|
+
// src/specialist/beads.ts
|
|
25083
|
+
function shouldCreateBead(beadsIntegration, permissionRequired) {
|
|
25084
|
+
if (beadsIntegration === "never")
|
|
25085
|
+
return false;
|
|
25086
|
+
if (beadsIntegration === "always")
|
|
25087
|
+
return true;
|
|
25088
|
+
return permissionRequired !== "READ_ONLY";
|
|
25089
|
+
}
|
|
25090
|
+
|
|
25081
25091
|
// src/specialist/runner.ts
|
|
25082
25092
|
class SpecialistRunner {
|
|
25083
25093
|
deps;
|
|
@@ -25087,7 +25097,7 @@ class SpecialistRunner {
|
|
|
25087
25097
|
this.sessionFactory = deps.sessionFactory ?? PiAgentSession.create.bind(PiAgentSession);
|
|
25088
25098
|
}
|
|
25089
25099
|
async run(options, onProgress, onEvent, onMeta, onKillRegistered) {
|
|
25090
|
-
const { loader, hooks, circuitBreaker } = this.deps;
|
|
25100
|
+
const { loader, hooks, circuitBreaker, beadsClient } = this.deps;
|
|
25091
25101
|
const invocationId = crypto.randomUUID();
|
|
25092
25102
|
const start = Date.now();
|
|
25093
25103
|
const spec = await loader.get(options.name);
|
|
@@ -25142,6 +25152,11 @@ You have access via Bash:
|
|
|
25142
25152
|
timeout_ms: execution.timeout_ms,
|
|
25143
25153
|
permission_level: permissionLevel
|
|
25144
25154
|
});
|
|
25155
|
+
const beadsIntegration = spec.specialist.beads_integration ?? "auto";
|
|
25156
|
+
let beadId;
|
|
25157
|
+
if (beadsClient && shouldCreateBead(beadsIntegration, execution.permission_required)) {
|
|
25158
|
+
beadId = beadsClient.createBead(metadata.name) ?? undefined;
|
|
25159
|
+
}
|
|
25145
25160
|
let output;
|
|
25146
25161
|
let session;
|
|
25147
25162
|
try {
|
|
@@ -25179,6 +25194,8 @@ You have access via Bash:
|
|
|
25179
25194
|
circuitBreaker.recordSuccess(model);
|
|
25180
25195
|
} catch (err) {
|
|
25181
25196
|
circuitBreaker.recordFailure(model);
|
|
25197
|
+
if (beadId)
|
|
25198
|
+
beadsClient?.closeBead(beadId, "ERROR", Date.now() - start, model);
|
|
25182
25199
|
await hooks.emit("post_execute", invocationId, metadata.name, metadata.version, {
|
|
25183
25200
|
status: "ERROR",
|
|
25184
25201
|
duration_ms: Date.now() - start,
|
|
@@ -25198,12 +25215,17 @@ You have access via Bash:
|
|
|
25198
25215
|
duration_ms: durationMs,
|
|
25199
25216
|
output_valid: true
|
|
25200
25217
|
});
|
|
25218
|
+
if (beadId) {
|
|
25219
|
+
beadsClient?.closeBead(beadId, "COMPLETE", durationMs, model);
|
|
25220
|
+
beadsClient?.auditBead(beadId, metadata.name, model, 0);
|
|
25221
|
+
}
|
|
25201
25222
|
return {
|
|
25202
25223
|
output,
|
|
25203
25224
|
backend: session.meta.backend,
|
|
25204
25225
|
model,
|
|
25205
25226
|
durationMs,
|
|
25206
|
-
specialistVersion: metadata.version
|
|
25227
|
+
specialistVersion: metadata.version,
|
|
25228
|
+
beadId
|
|
25207
25229
|
};
|
|
25208
25230
|
}
|
|
25209
25231
|
async startAsync(options, registry2) {
|
|
@@ -25478,6 +25500,12 @@ class JobRegistry {
|
|
|
25478
25500
|
if (meta.model)
|
|
25479
25501
|
job.model = meta.model;
|
|
25480
25502
|
}
|
|
25503
|
+
setBeadId(id, beadId) {
|
|
25504
|
+
const job = this.jobs.get(id);
|
|
25505
|
+
if (!job)
|
|
25506
|
+
return;
|
|
25507
|
+
job.beadId = beadId;
|
|
25508
|
+
}
|
|
25481
25509
|
setKillFn(id, killFn) {
|
|
25482
25510
|
const job = this.jobs.get(id);
|
|
25483
25511
|
if (!job)
|
|
@@ -25499,6 +25527,8 @@ class JobRegistry {
|
|
|
25499
25527
|
job.model = result.model;
|
|
25500
25528
|
job.specialistVersion = result.specialistVersion;
|
|
25501
25529
|
job.endedAtMs = Date.now();
|
|
25530
|
+
if (result.beadId)
|
|
25531
|
+
job.beadId = result.beadId;
|
|
25502
25532
|
}
|
|
25503
25533
|
fail(id, err) {
|
|
25504
25534
|
const job = this.jobs.get(id);
|
|
@@ -25535,7 +25565,8 @@ class JobRegistry {
|
|
|
25535
25565
|
model: job.model,
|
|
25536
25566
|
specialist_version: job.specialistVersion,
|
|
25537
25567
|
duration_ms: (job.endedAtMs ?? Date.now()) - job.startedAtMs,
|
|
25538
|
-
error: job.error
|
|
25568
|
+
error: job.error,
|
|
25569
|
+
beadId: job.beadId
|
|
25539
25570
|
};
|
|
25540
25571
|
}
|
|
25541
25572
|
delete(id) {
|
|
@@ -25606,15 +25637,50 @@ function createStopSpecialistTool(registry2) {
|
|
|
25606
25637
|
};
|
|
25607
25638
|
}
|
|
25608
25639
|
|
|
25640
|
+
// src/tools/specialist/specialist_init.tool.ts
|
|
25641
|
+
import { spawnSync } from "node:child_process";
|
|
25642
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
25643
|
+
import { join as join2 } from "node:path";
|
|
25644
|
+
var specialistInitSchema = exports_external.object({});
|
|
25645
|
+
function createSpecialistInitTool(loader, deps) {
|
|
25646
|
+
const resolved = deps ?? {
|
|
25647
|
+
bdAvailable: () => spawnSync("bd", ["--version"], { stdio: "ignore" }).status === 0,
|
|
25648
|
+
beadsExists: () => existsSync2(join2(process.cwd(), ".beads")),
|
|
25649
|
+
bdInit: () => spawnSync("bd", ["init"], { stdio: "ignore" })
|
|
25650
|
+
};
|
|
25651
|
+
return {
|
|
25652
|
+
name: "specialist_init",
|
|
25653
|
+
description: "Session bootstrap: initializes beads in the project if not already set up, " + "then returns available specialists. Call at session start for orientation.",
|
|
25654
|
+
inputSchema: specialistInitSchema,
|
|
25655
|
+
async execute(_input) {
|
|
25656
|
+
const available = resolved.bdAvailable();
|
|
25657
|
+
let initialized = false;
|
|
25658
|
+
if (available) {
|
|
25659
|
+
if (resolved.beadsExists()) {
|
|
25660
|
+
initialized = true;
|
|
25661
|
+
} else {
|
|
25662
|
+
const result = resolved.bdInit();
|
|
25663
|
+
initialized = result.status === 0;
|
|
25664
|
+
}
|
|
25665
|
+
}
|
|
25666
|
+
const specialists = await loader.list();
|
|
25667
|
+
return {
|
|
25668
|
+
specialists,
|
|
25669
|
+
beads: { available, initialized }
|
|
25670
|
+
};
|
|
25671
|
+
}
|
|
25672
|
+
};
|
|
25673
|
+
}
|
|
25674
|
+
|
|
25609
25675
|
// src/server.ts
|
|
25610
|
-
class
|
|
25676
|
+
class SpecialistsServer {
|
|
25611
25677
|
server;
|
|
25612
25678
|
tools;
|
|
25613
25679
|
constructor() {
|
|
25614
25680
|
const circuitBreaker = new CircuitBreaker;
|
|
25615
25681
|
const loader = new SpecialistLoader;
|
|
25616
25682
|
const hooks = new HookEmitter({
|
|
25617
|
-
tracePath:
|
|
25683
|
+
tracePath: join3(process.cwd(), ".specialists", "trace.jsonl")
|
|
25618
25684
|
});
|
|
25619
25685
|
const runner = new SpecialistRunner({ loader, hooks, circuitBreaker });
|
|
25620
25686
|
const registry2 = new JobRegistry;
|
|
@@ -25625,7 +25691,8 @@ class UnitAIServer {
|
|
|
25625
25691
|
createSpecialistStatusTool(loader, circuitBreaker),
|
|
25626
25692
|
createStartSpecialistTool(runner, registry2),
|
|
25627
25693
|
createPollSpecialistTool(registry2),
|
|
25628
|
-
createStopSpecialistTool(registry2)
|
|
25694
|
+
createStopSpecialistTool(registry2),
|
|
25695
|
+
createSpecialistInitTool(loader)
|
|
25629
25696
|
];
|
|
25630
25697
|
this.server = new Server({ name: MCP_CONFIG.SERVER_NAME, version: MCP_CONFIG.VERSION }, { capabilities: MCP_CONFIG.CAPABILITIES });
|
|
25631
25698
|
this.setupHandlers();
|
|
@@ -25639,7 +25706,8 @@ class UnitAIServer {
|
|
|
25639
25706
|
specialist_status: exports_external.object({}),
|
|
25640
25707
|
start_specialist: startSpecialistSchema,
|
|
25641
25708
|
poll_specialist: pollSpecialistSchema,
|
|
25642
|
-
stop_specialist: stopSpecialistSchema
|
|
25709
|
+
stop_specialist: stopSpecialistSchema,
|
|
25710
|
+
specialist_init: specialistInitSchema
|
|
25643
25711
|
};
|
|
25644
25712
|
this.toolSchemas = schemaMap;
|
|
25645
25713
|
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
@@ -25665,7 +25733,7 @@ class UnitAIServer {
|
|
|
25665
25733
|
const onProgress = (msg) => {
|
|
25666
25734
|
this.server.notification({
|
|
25667
25735
|
method: "notifications/message",
|
|
25668
|
-
params: { level: "info", logger: "
|
|
25736
|
+
params: { level: "info", logger: "specialists", data: msg }
|
|
25669
25737
|
}).catch(() => {});
|
|
25670
25738
|
};
|
|
25671
25739
|
try {
|
|
@@ -25689,7 +25757,7 @@ class UnitAIServer {
|
|
|
25689
25757
|
try {
|
|
25690
25758
|
const transport = new StdioServerTransport;
|
|
25691
25759
|
await this.server.connect(transport);
|
|
25692
|
-
logger.info(`
|
|
25760
|
+
logger.info(`Specialists MCP Server v2 started — ${this.tools.length} tools registered`);
|
|
25693
25761
|
} catch (error2) {
|
|
25694
25762
|
logger.error("Failed to start server", error2);
|
|
25695
25763
|
process.exit(1);
|
|
@@ -25702,8 +25770,8 @@ class UnitAIServer {
|
|
|
25702
25770
|
|
|
25703
25771
|
// src/index.ts
|
|
25704
25772
|
async function main() {
|
|
25705
|
-
logger.info("Starting
|
|
25706
|
-
const server = new
|
|
25773
|
+
logger.info("Starting Specialists MCP Server...");
|
|
25774
|
+
const server = new SpecialistsServer;
|
|
25707
25775
|
await server.start();
|
|
25708
25776
|
}
|
|
25709
25777
|
main().catch((error2) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jaggerxtrm/specialists",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
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",
|