@jaggerxtrm/specialists 2.1.0 → 2.1.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.
Files changed (2) hide show
  1. package/dist/index.js +61 -7
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -25080,6 +25080,57 @@ class PiAgentSession {
25080
25080
  }
25081
25081
 
25082
25082
  // src/specialist/beads.ts
25083
+ import { spawnSync } from "node:child_process";
25084
+
25085
+ class BeadsClient {
25086
+ available;
25087
+ constructor() {
25088
+ this.available = BeadsClient.checkAvailable();
25089
+ if (!this.available) {
25090
+ console.warn("[specialists] bd CLI not found — beads tracking disabled");
25091
+ }
25092
+ }
25093
+ static checkAvailable() {
25094
+ const result = spawnSync("bd", ["--version"], { stdio: "ignore" });
25095
+ return result.status === 0;
25096
+ }
25097
+ isAvailable() {
25098
+ return this.available;
25099
+ }
25100
+ createBead(specialistName) {
25101
+ if (!this.available)
25102
+ return null;
25103
+ const result = spawnSync("bd", ["q", `specialist:${specialistName}`, "--type", "task", "--labels", "specialist"], { encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] });
25104
+ if (result.status !== 0)
25105
+ return null;
25106
+ const id = result.stdout?.trim();
25107
+ return id || null;
25108
+ }
25109
+ closeBead(id, status, durationMs, model) {
25110
+ if (!this.available || !id)
25111
+ return;
25112
+ const reason = `${status}, ${Math.round(durationMs)}ms, ${model}`;
25113
+ spawnSync("bd", ["close", id, "-r", reason], { stdio: "ignore" });
25114
+ }
25115
+ auditBead(id, toolName, model, exitCode) {
25116
+ if (!this.available || !id)
25117
+ return;
25118
+ spawnSync("bd", [
25119
+ "audit",
25120
+ "record",
25121
+ "--kind",
25122
+ "tool_call",
25123
+ "--tool-name",
25124
+ toolName,
25125
+ "--model",
25126
+ model,
25127
+ "--issue-id",
25128
+ id,
25129
+ "--exit-code",
25130
+ String(exitCode)
25131
+ ], { stdio: "ignore" });
25132
+ }
25133
+ }
25083
25134
  function shouldCreateBead(beadsIntegration, permissionRequired) {
25084
25135
  if (beadsIntegration === "never")
25085
25136
  return false;
@@ -25096,7 +25147,7 @@ class SpecialistRunner {
25096
25147
  this.deps = deps;
25097
25148
  this.sessionFactory = deps.sessionFactory ?? PiAgentSession.create.bind(PiAgentSession);
25098
25149
  }
25099
- async run(options, onProgress, onEvent, onMeta, onKillRegistered) {
25150
+ async run(options, onProgress, onEvent, onMeta, onKillRegistered, onBeadCreated) {
25100
25151
  const { loader, hooks, circuitBreaker, beadsClient } = this.deps;
25101
25152
  const invocationId = crypto.randomUUID();
25102
25153
  const start = Date.now();
@@ -25156,6 +25207,8 @@ You have access via Bash:
25156
25207
  let beadId;
25157
25208
  if (beadsClient && shouldCreateBead(beadsIntegration, execution.permission_required)) {
25158
25209
  beadId = beadsClient.createBead(metadata.name) ?? undefined;
25210
+ if (beadId)
25211
+ onBeadCreated?.(beadId);
25159
25212
  }
25160
25213
  let output;
25161
25214
  let session;
@@ -25240,7 +25293,7 @@ You have access via Bash:
25240
25293
  model: "?",
25241
25294
  specialistVersion
25242
25295
  });
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));
25296
+ 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
25297
  return jobId;
25245
25298
  }
25246
25299
  }
@@ -25638,15 +25691,15 @@ function createStopSpecialistTool(registry2) {
25638
25691
  }
25639
25692
 
25640
25693
  // src/tools/specialist/specialist_init.tool.ts
25641
- import { spawnSync } from "node:child_process";
25694
+ import { spawnSync as spawnSync2 } from "node:child_process";
25642
25695
  import { existsSync as existsSync2 } from "node:fs";
25643
25696
  import { join as join2 } from "node:path";
25644
- var specialistInitSchema = exports_external.object({});
25697
+ var specialistInitSchema = objectType({});
25645
25698
  function createSpecialistInitTool(loader, deps) {
25646
25699
  const resolved = deps ?? {
25647
- bdAvailable: () => spawnSync("bd", ["--version"], { stdio: "ignore" }).status === 0,
25700
+ bdAvailable: () => spawnSync2("bd", ["--version"], { stdio: "ignore" }).status === 0,
25648
25701
  beadsExists: () => existsSync2(join2(process.cwd(), ".beads")),
25649
- bdInit: () => spawnSync("bd", ["init"], { stdio: "ignore" })
25702
+ bdInit: () => spawnSync2("bd", ["init"], { stdio: "ignore" })
25650
25703
  };
25651
25704
  return {
25652
25705
  name: "specialist_init",
@@ -25682,7 +25735,8 @@ class SpecialistsServer {
25682
25735
  const hooks = new HookEmitter({
25683
25736
  tracePath: join3(process.cwd(), ".specialists", "trace.jsonl")
25684
25737
  });
25685
- const runner = new SpecialistRunner({ loader, hooks, circuitBreaker });
25738
+ const beadsClient = new BeadsClient;
25739
+ const runner = new SpecialistRunner({ loader, hooks, circuitBreaker, beadsClient });
25686
25740
  const registry2 = new JobRegistry;
25687
25741
  this.tools = [
25688
25742
  createListSpecialistsTool(loader),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jaggerxtrm/specialists",
3
- "version": "2.1.0",
3
+ "version": "2.1.1",
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",