@jaggerxtrm/specialists 2.1.10 → 2.1.11

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 +207 -8
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -17688,26 +17688,217 @@ var init_list = __esm(() => {
17688
17688
  };
17689
17689
  });
17690
17690
 
17691
+ // src/cli/init.ts
17692
+ var exports_init = {};
17693
+ __export(exports_init, {
17694
+ run: () => run4
17695
+ });
17696
+ import { existsSync as existsSync3, mkdirSync, readFileSync, writeFileSync } from "node:fs";
17697
+ import { join as join5 } from "node:path";
17698
+ function ok(msg) {
17699
+ console.log(` ${green("✓")} ${msg}`);
17700
+ }
17701
+ function skip(msg) {
17702
+ console.log(` ${yellow2("○")} ${msg}`);
17703
+ }
17704
+ async function run4() {
17705
+ const cwd = process.cwd();
17706
+ console.log(`
17707
+ ${bold2("specialists init")}
17708
+ `);
17709
+ const specialistsDir = join5(cwd, "specialists");
17710
+ if (existsSync3(specialistsDir)) {
17711
+ skip("specialists/ already exists");
17712
+ } else {
17713
+ mkdirSync(specialistsDir, { recursive: true });
17714
+ ok("created specialists/");
17715
+ }
17716
+ const agentsPath = join5(cwd, "AGENTS.md");
17717
+ if (existsSync3(agentsPath)) {
17718
+ const existing = readFileSync(agentsPath, "utf-8");
17719
+ if (existing.includes(AGENTS_MARKER)) {
17720
+ skip("AGENTS.md already has Specialists section");
17721
+ } else {
17722
+ writeFileSync(agentsPath, existing.trimEnd() + `
17723
+
17724
+ ` + AGENTS_BLOCK, "utf-8");
17725
+ ok("appended Specialists section to AGENTS.md");
17726
+ }
17727
+ } else {
17728
+ writeFileSync(agentsPath, AGENTS_BLOCK, "utf-8");
17729
+ ok("created AGENTS.md with Specialists section");
17730
+ }
17731
+ console.log(`
17732
+ ${bold2("Done!")}
17733
+ `);
17734
+ console.log(` ${dim2("Next steps:")}`);
17735
+ console.log(` 1. Add your specialists to ${yellow2("specialists/")}`);
17736
+ console.log(` 2. Run ${yellow2("specialists list")} to verify they are discovered`);
17737
+ console.log(` 3. Restart Claude Code to pick up AGENTS.md changes
17738
+ `);
17739
+ }
17740
+ var bold2 = (s) => `\x1B[1m${s}\x1B[0m`, green = (s) => `\x1B[32m${s}\x1B[0m`, yellow2 = (s) => `\x1B[33m${s}\x1B[0m`, dim2 = (s) => `\x1B[2m${s}\x1B[0m`, AGENTS_BLOCK, AGENTS_MARKER = "## Specialists";
17741
+ var init_init = __esm(() => {
17742
+ AGENTS_BLOCK = `
17743
+ ## Specialists
17744
+
17745
+ Call \`specialist_init\` at the start of every session to bootstrap context and
17746
+ see available specialists. Use \`use_specialist\` or \`start_specialist\` to
17747
+ delegate heavy tasks (code review, bug hunting, deep reasoning) to the right
17748
+ specialist without user intervention.
17749
+ `.trimStart();
17750
+ });
17751
+
17752
+ // src/cli/edit.ts
17753
+ var exports_edit = {};
17754
+ __export(exports_edit, {
17755
+ run: () => run5
17756
+ });
17757
+ import { readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
17758
+ function parseArgs2(argv) {
17759
+ const name = argv[0];
17760
+ if (!name || name.startsWith("--")) {
17761
+ console.error("Usage: specialists edit <name> --<field> <value> [--dry-run]");
17762
+ console.error(` Fields: ${Object.keys(FIELD_MAP).join(", ")}`);
17763
+ process.exit(1);
17764
+ }
17765
+ let field;
17766
+ let value;
17767
+ let dryRun = false;
17768
+ let scope;
17769
+ for (let i = 1;i < argv.length; i++) {
17770
+ const token = argv[i];
17771
+ if (token === "--dry-run") {
17772
+ dryRun = true;
17773
+ continue;
17774
+ }
17775
+ if (token === "--scope") {
17776
+ const v = argv[++i];
17777
+ if (v !== "project" && v !== "user") {
17778
+ console.error(`Error: --scope must be "project" or "user", got: "${v ?? ""}"`);
17779
+ process.exit(1);
17780
+ }
17781
+ scope = v;
17782
+ continue;
17783
+ }
17784
+ if (token.startsWith("--") && !field) {
17785
+ field = token.slice(2);
17786
+ value = argv[++i];
17787
+ continue;
17788
+ }
17789
+ }
17790
+ if (!field || !FIELD_MAP[field]) {
17791
+ console.error(`Error: unknown or missing field. Valid fields: ${Object.keys(FIELD_MAP).join(", ")}`);
17792
+ process.exit(1);
17793
+ }
17794
+ if (value === undefined || value === "") {
17795
+ console.error(`Error: --${field} requires a value`);
17796
+ process.exit(1);
17797
+ }
17798
+ if (field === "permission" && !VALID_PERMISSIONS.includes(value)) {
17799
+ console.error(`Error: --permission must be one of: ${VALID_PERMISSIONS.join(", ")}`);
17800
+ process.exit(1);
17801
+ }
17802
+ if (field === "timeout" && !/^\d+$/.test(value)) {
17803
+ console.error("Error: --timeout must be a number (milliseconds)");
17804
+ process.exit(1);
17805
+ }
17806
+ return { name, field, value, dryRun, scope };
17807
+ }
17808
+ function setIn(doc2, path, value) {
17809
+ let node = doc2;
17810
+ for (let i = 0;i < path.length - 1; i++) {
17811
+ node = node.get(path[i], true);
17812
+ }
17813
+ const leaf = path[path.length - 1];
17814
+ if (Array.isArray(value)) {
17815
+ node.set(leaf, value);
17816
+ } else {
17817
+ node.set(leaf, value);
17818
+ }
17819
+ }
17820
+ async function run5() {
17821
+ const args = parseArgs2(process.argv.slice(3));
17822
+ const { name, field, value, dryRun, scope } = args;
17823
+ const loader = new SpecialistLoader;
17824
+ const all = await loader.list();
17825
+ const match = all.find((s) => s.name === name && (scope === undefined || s.scope === scope));
17826
+ if (!match) {
17827
+ const hint = scope ? ` (scope: ${scope})` : "";
17828
+ console.error(`Error: specialist "${name}" not found${hint}`);
17829
+ console.error(` Run ${yellow3("specialists list")} to see available specialists`);
17830
+ process.exit(1);
17831
+ }
17832
+ const raw = readFileSync2(match.filePath, "utf-8");
17833
+ const doc2 = $parseDocument(raw);
17834
+ const yamlPath = FIELD_MAP[field];
17835
+ let typedValue = value;
17836
+ if (field === "timeout") {
17837
+ typedValue = parseInt(value, 10);
17838
+ } else if (field === "tags") {
17839
+ typedValue = value.split(",").map((t) => t.trim()).filter(Boolean);
17840
+ }
17841
+ setIn(doc2, yamlPath, typedValue);
17842
+ const updated = doc2.toString();
17843
+ if (dryRun) {
17844
+ console.log(`
17845
+ ${bold3(`[dry-run] ${match.filePath}`)}
17846
+ `);
17847
+ console.log(dim3("--- current"));
17848
+ console.log(dim3(`+++ updated`));
17849
+ const oldLines = raw.split(`
17850
+ `);
17851
+ const newLines = updated.split(`
17852
+ `);
17853
+ newLines.forEach((line, i) => {
17854
+ if (line !== oldLines[i]) {
17855
+ if (oldLines[i] !== undefined)
17856
+ console.log(dim3(`- ${oldLines[i]}`));
17857
+ console.log(green2(`+ ${line}`));
17858
+ }
17859
+ });
17860
+ console.log();
17861
+ return;
17862
+ }
17863
+ writeFileSync2(match.filePath, updated, "utf-8");
17864
+ const displayValue = field === "tags" ? `[${typedValue.join(", ")}]` : String(typedValue);
17865
+ console.log(`${green2("✓")} ${bold3(name)}: ${yellow3(field)} = ${displayValue}` + dim3(` (${match.filePath})`));
17866
+ }
17867
+ var bold3 = (s) => `\x1B[1m${s}\x1B[0m`, green2 = (s) => `\x1B[32m${s}\x1B[0m`, yellow3 = (s) => `\x1B[33m${s}\x1B[0m`, dim3 = (s) => `\x1B[2m${s}\x1B[0m`, FIELD_MAP, VALID_PERMISSIONS;
17868
+ var init_edit = __esm(() => {
17869
+ init_dist();
17870
+ init_loader();
17871
+ FIELD_MAP = {
17872
+ model: ["specialist", "execution", "model"],
17873
+ "fallback-model": ["specialist", "execution", "fallback_model"],
17874
+ description: ["specialist", "metadata", "description"],
17875
+ permission: ["specialist", "execution", "permission_required"],
17876
+ timeout: ["specialist", "execution", "timeout_ms"],
17877
+ tags: ["specialist", "metadata", "tags"]
17878
+ };
17879
+ VALID_PERMISSIONS = ["READ_ONLY", "LOW", "MEDIUM", "HIGH"];
17880
+ });
17881
+
17691
17882
  // src/cli/help.ts
17692
17883
  var exports_help = {};
17693
17884
  __export(exports_help, {
17694
- run: () => run4
17885
+ run: () => run6
17695
17886
  });
17696
- async function run4() {
17887
+ async function run6() {
17697
17888
  const lines = [
17698
17889
  "",
17699
- bold2("specialists <command>"),
17890
+ bold4("specialists <command>"),
17700
17891
  "",
17701
17892
  "Commands:",
17702
- ...COMMANDS.map(([cmd, desc]) => ` ${cmd.padEnd(COL_WIDTH)} ${dim2(desc)}`),
17893
+ ...COMMANDS.map(([cmd, desc]) => ` ${cmd.padEnd(COL_WIDTH)} ${dim4(desc)}`),
17703
17894
  "",
17704
- dim2("Run 'specialists <command> --help' for command-specific options."),
17895
+ dim4("Run 'specialists <command> --help' for command-specific options."),
17705
17896
  ""
17706
17897
  ];
17707
17898
  console.log(lines.join(`
17708
17899
  `));
17709
17900
  }
17710
- var bold2 = (s) => `\x1B[1m${s}\x1B[0m`, dim2 = (s) => `\x1B[2m${s}\x1B[0m`, COMMANDS, COL_WIDTH;
17901
+ var bold4 = (s) => `\x1B[1m${s}\x1B[0m`, dim4 = (s) => `\x1B[2m${s}\x1B[0m`, COMMANDS, COL_WIDTH;
17711
17902
  var init_help = __esm(() => {
17712
17903
  COMMANDS = [
17713
17904
  ["install", "Full-stack installer: pi, beads, dolt, MCP registration, hooks"],
@@ -26005,7 +26196,7 @@ class SpecialistsServer {
26005
26196
 
26006
26197
  // src/index.ts
26007
26198
  var sub = process.argv[2];
26008
- async function run5() {
26199
+ async function run7() {
26009
26200
  if (sub === "install") {
26010
26201
  const { run: handler } = await Promise.resolve().then(() => (init_install(), exports_install));
26011
26202
  return handler();
@@ -26018,6 +26209,14 @@ async function run5() {
26018
26209
  const { run: handler } = await Promise.resolve().then(() => (init_list(), exports_list));
26019
26210
  return handler();
26020
26211
  }
26212
+ if (sub === "init") {
26213
+ const { run: handler } = await Promise.resolve().then(() => (init_init(), exports_init));
26214
+ return handler();
26215
+ }
26216
+ if (sub === "edit") {
26217
+ const { run: handler } = await Promise.resolve().then(() => (init_edit(), exports_edit));
26218
+ return handler();
26219
+ }
26021
26220
  if (sub === "help" || sub === "--help" || sub === "-h") {
26022
26221
  const { run: handler } = await Promise.resolve().then(() => (init_help(), exports_help));
26023
26222
  return handler();
@@ -26026,7 +26225,7 @@ async function run5() {
26026
26225
  const server = new SpecialistsServer;
26027
26226
  await server.start();
26028
26227
  }
26029
- run5().catch((error2) => {
26228
+ run7().catch((error2) => {
26030
26229
  logger.error(`Fatal error: ${error2}`);
26031
26230
  process.exit(1);
26032
26231
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jaggerxtrm/specialists",
3
- "version": "2.1.10",
3
+ "version": "2.1.11",
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",