@jaggerxtrm/specialists 3.12.0 → 3.13.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.
Files changed (32) hide show
  1. package/config/hooks/specialists-session-start.mjs +1 -1
  2. package/config/mandatory-rules/bead-id-verbatim.md +14 -0
  3. package/config/mandatory-rules/per-turn-handoff-schema.md +16 -0
  4. package/config/skills/specialists-creator/SKILL.md +16 -0
  5. package/config/skills/update-specialists/SKILL.md +183 -350
  6. package/config/skills/using-kpi/SKILL.md +86 -0
  7. package/config/skills/using-specialists-v2/SKILL.md +1 -1
  8. package/config/skills/using-specialists-v3/SKILL.md +390 -112
  9. package/config/specialists/changelog-keeper.specialist.json +2 -1
  10. package/config/specialists/code-sanity.specialist.json +3 -1
  11. package/config/specialists/debugger.specialist.json +3 -1
  12. package/config/specialists/executor.specialist.json +3 -1
  13. package/config/specialists/explorer.specialist.json +2 -1
  14. package/config/specialists/overthinker.specialist.json +2 -1
  15. package/config/specialists/planner.specialist.json +3 -1
  16. package/config/specialists/researcher.specialist.json +2 -1
  17. package/config/specialists/reviewer.specialist.json +3 -1
  18. package/config/specialists/security-auditor.specialist.json +53 -10
  19. package/config/specialists/specialists-creator.specialist.json +2 -2
  20. package/config/specialists/sync-docs.specialist.json +3 -1
  21. package/config/specialists/test-runner.specialist.json +2 -1
  22. package/dist/index.js +247 -355
  23. package/dist/lib.js +38 -19
  24. package/dist/types/cli/help.d.ts.map +1 -1
  25. package/dist/types/cli/run.d.ts.map +1 -1
  26. package/dist/types/cli/version-check.d.ts +3 -0
  27. package/dist/types/cli/version-check.d.ts.map +1 -1
  28. package/dist/types/index.d.ts +1 -1
  29. package/dist/types/specialist/mandatory-rules.d.ts +5 -0
  30. package/dist/types/specialist/mandatory-rules.d.ts.map +1 -1
  31. package/package.json +4 -4
  32. package/config/specialists/.serena/project.yml +0 -151
package/dist/index.js CHANGED
@@ -5,25 +5,43 @@ var __getProtoOf = Object.getPrototypeOf;
5
5
  var __defProp = Object.defineProperty;
6
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ function __accessProp(key) {
9
+ return this[key];
10
+ }
11
+ var __toESMCache_node;
12
+ var __toESMCache_esm;
8
13
  var __toESM = (mod, isNodeMode, target) => {
14
+ var canCache = mod != null && typeof mod === "object";
15
+ if (canCache) {
16
+ var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
17
+ var cached = cache.get(mod);
18
+ if (cached)
19
+ return cached;
20
+ }
9
21
  target = mod != null ? __create(__getProtoOf(mod)) : {};
10
22
  const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
11
23
  for (let key of __getOwnPropNames(mod))
12
24
  if (!__hasOwnProp.call(to, key))
13
25
  __defProp(to, key, {
14
- get: () => mod[key],
26
+ get: __accessProp.bind(mod, key),
15
27
  enumerable: true
16
28
  });
29
+ if (canCache)
30
+ cache.set(mod, to);
17
31
  return to;
18
32
  };
19
33
  var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
34
+ var __returnValue = (v) => v;
35
+ function __exportSetter(name, newValue) {
36
+ this[name] = __returnValue.bind(null, newValue);
37
+ }
20
38
  var __export = (target, all) => {
21
39
  for (var name in all)
22
40
  __defProp(target, name, {
23
41
  get: all[name],
24
42
  enumerable: true,
25
43
  configurable: true,
26
- set: (newValue) => all[name] = () => newValue
44
+ set: __exportSetter.bind(all, name)
27
45
  });
28
46
  };
29
47
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
@@ -10248,7 +10266,7 @@ var require_formats = __commonJS((exports) => {
10248
10266
  }
10249
10267
  var TIME = /^(\d\d):(\d\d):(\d\d(?:\.\d+)?)(z|([+-])(\d\d)(?::?(\d\d))?)?$/i;
10250
10268
  function getTime(strictTimeZone) {
10251
- return function time(str) {
10269
+ return function time3(str) {
10252
10270
  const matches = TIME.exec(str);
10253
10271
  if (!matches)
10254
10272
  return false;
@@ -11014,6 +11032,8 @@ var require_Alias = __commonJS((exports) => {
11014
11032
  });
11015
11033
  }
11016
11034
  resolve(doc2, ctx) {
11035
+ if (ctx?.maxAliasCount === 0)
11036
+ throw new ReferenceError("Alias resolution is disabled");
11017
11037
  let nodes;
11018
11038
  if (ctx?.aliasResolveCache) {
11019
11039
  nodes = ctx.aliasResolveCache;
@@ -11793,6 +11813,7 @@ var require_stringify = __commonJS((exports) => {
11793
11813
  nullStr: "null",
11794
11814
  simpleKeys: false,
11795
11815
  singleQuote: null,
11816
+ trailingComma: false,
11796
11817
  trueStr: "true",
11797
11818
  verifyAliasOrder: true
11798
11819
  }, doc2.schema.toStringOptions, options);
@@ -12062,18 +12083,18 @@ var require_merge = __commonJS((exports) => {
12062
12083
  };
12063
12084
  var isMergeKey = (ctx, key) => (merge2.identify(key) || identity.isScalar(key) && (!key.type || key.type === Scalar.Scalar.PLAIN) && merge2.identify(key.value)) && ctx?.doc.schema.tags.some((tag) => tag.tag === merge2.tag && tag.default);
12064
12085
  function addMergeToJSMap(ctx, map2, value) {
12065
- value = ctx && identity.isAlias(value) ? value.resolve(ctx.doc) : value;
12066
- if (identity.isSeq(value))
12067
- for (const it of value.items)
12086
+ const source = resolveAliasValue(ctx, value);
12087
+ if (identity.isSeq(source))
12088
+ for (const it of source.items)
12068
12089
  mergeValue(ctx, map2, it);
12069
- else if (Array.isArray(value))
12070
- for (const it of value)
12090
+ else if (Array.isArray(source))
12091
+ for (const it of source)
12071
12092
  mergeValue(ctx, map2, it);
12072
12093
  else
12073
- mergeValue(ctx, map2, value);
12094
+ mergeValue(ctx, map2, source);
12074
12095
  }
12075
12096
  function mergeValue(ctx, map2, value) {
12076
- const source = ctx && identity.isAlias(value) ? value.resolve(ctx.doc) : value;
12097
+ const source = resolveAliasValue(ctx, value);
12077
12098
  if (!identity.isMap(source))
12078
12099
  throw new Error("Merge sources must be maps or map aliases");
12079
12100
  const srcMap = source.toJSON(null, ctx, Map);
@@ -12094,6 +12115,9 @@ var require_merge = __commonJS((exports) => {
12094
12115
  }
12095
12116
  return map2;
12096
12117
  }
12118
+ function resolveAliasValue(ctx, value) {
12119
+ return ctx && identity.isAlias(value) ? value.resolve(ctx.doc, ctx) : value;
12120
+ }
12097
12121
  exports.addMergeToJSMap = addMergeToJSMap;
12098
12122
  exports.isMergeKey = isMergeKey;
12099
12123
  exports.merge = merge2;
@@ -12301,13 +12325,20 @@ ${indent}${line}` : `
12301
12325
  if (comment)
12302
12326
  reqNewline = true;
12303
12327
  let str = stringify.stringify(item, itemCtx, () => comment = null);
12304
- if (i < items.length - 1)
12328
+ reqNewline || (reqNewline = lines.length > linesAtValue || str.includes(`
12329
+ `));
12330
+ if (i < items.length - 1) {
12305
12331
  str += ",";
12332
+ } else if (ctx.options.trailingComma) {
12333
+ if (ctx.options.lineWidth > 0) {
12334
+ reqNewline || (reqNewline = lines.reduce((sum, line) => sum + line.length + 2, 2) + (str.length + 2) > ctx.options.lineWidth);
12335
+ }
12336
+ if (reqNewline) {
12337
+ str += ",";
12338
+ }
12339
+ }
12306
12340
  if (comment)
12307
12341
  str += stringifyComment.lineComment(str, itemIndent, commentString(comment));
12308
- if (!reqNewline && (lines.length > linesAtValue || str.includes(`
12309
- `)))
12310
- reqNewline = true;
12311
12342
  lines.push(str);
12312
12343
  linesAtValue = lines.length;
12313
12344
  }
@@ -12662,7 +12693,7 @@ var require_stringifyNumber = __commonJS((exports) => {
12662
12693
  if (!isFinite(num))
12663
12694
  return isNaN(num) ? ".nan" : num < 0 ? "-.inf" : ".inf";
12664
12695
  let n = Object.is(value, -0) ? "-0" : JSON.stringify(value);
12665
- if (!format && minFractionDigits && (!tag || tag === "tag:yaml.org,2002:float") && /^\d/.test(n)) {
12696
+ if (!format && minFractionDigits && (!tag || tag === "tag:yaml.org,2002:float") && /^-?\d/.test(n) && !n.includes("e")) {
12666
12697
  let i = n.indexOf(".");
12667
12698
  if (i < 0) {
12668
12699
  i = n.length;
@@ -14887,7 +14918,7 @@ var require_resolve_flow_scalar = __commonJS((exports) => {
14887
14918
  while (next === " " || next === "\t")
14888
14919
  next = source[++i + 1];
14889
14920
  } else if (next === "x" || next === "u" || next === "U") {
14890
- const length = { x: 2, u: 4, U: 8 }[next];
14921
+ const length = next === "x" ? 2 : next === "u" ? 4 : 8;
14891
14922
  res += parseCharCode(source, i + 1, length, onError);
14892
14923
  i += length;
14893
14924
  } else {
@@ -14956,12 +14987,13 @@ var require_resolve_flow_scalar = __commonJS((exports) => {
14956
14987
  const cc = source.substr(offset, length);
14957
14988
  const ok = cc.length === length && /^[0-9a-fA-F]+$/.test(cc);
14958
14989
  const code = ok ? parseInt(cc, 16) : NaN;
14959
- if (isNaN(code)) {
14990
+ try {
14991
+ return String.fromCodePoint(code);
14992
+ } catch {
14960
14993
  const raw = source.substr(offset - 2, length + 2);
14961
14994
  onError(offset - 2, "BAD_DQ_ESCAPE", `Invalid escape sequence ${raw}`);
14962
14995
  return raw;
14963
14996
  }
14964
- return String.fromCodePoint(code);
14965
14997
  }
14966
14998
  exports.resolveFlowScalar = resolveFlowScalar;
14967
14999
  });
@@ -15102,17 +15134,22 @@ var require_compose_node = __commonJS((exports) => {
15102
15134
  case "block-map":
15103
15135
  case "block-seq":
15104
15136
  case "flow-collection":
15105
- node = composeCollection.composeCollection(CN, ctx, token, props, onError);
15106
- if (anchor)
15107
- node.anchor = anchor.source.substring(1);
15137
+ try {
15138
+ node = composeCollection.composeCollection(CN, ctx, token, props, onError);
15139
+ if (anchor)
15140
+ node.anchor = anchor.source.substring(1);
15141
+ } catch (error2) {
15142
+ const message = error2 instanceof Error ? error2.message : String(error2);
15143
+ onError(token, "RESOURCE_EXHAUSTION", message);
15144
+ }
15108
15145
  break;
15109
15146
  default: {
15110
15147
  const message = token.type === "error" ? token.message : `Unsupported token (type: ${token.type})`;
15111
15148
  onError(token, "UNEXPECTED_TOKEN", message);
15112
- node = composeEmptyNode(ctx, token.offset, undefined, null, props, onError);
15113
15149
  isSrcToken = false;
15114
15150
  }
15115
15151
  }
15152
+ node ?? (node = composeEmptyNode(ctx, token.offset, undefined, null, props, onError));
15116
15153
  if (anchor && node.anchor === "")
15117
15154
  onError(anchor, "BAD_ALIAS", "Anchor cannot be an empty string");
15118
15155
  if (atKey && ctx.options.stringKeys && (!identity.isScalar(node) || typeof node.value !== "string" || node.tag && node.tag !== "tag:yaml.org,2002:str")) {
@@ -21582,24 +21619,27 @@ function readMandatoryRuleSet(cwd, id) {
21582
21619
  }
21583
21620
  function formatMandatoryRulesBlock(sets, inlineRules = []) {
21584
21621
  if (sets.length === 0 && inlineRules.length === 0)
21585
- return "";
21622
+ return { block: "", sections: [] };
21586
21623
  const sections = [
21587
21624
  ...sets.map((set2) => {
21588
21625
  const rules = set2.rules.map((rule) => `- [${rule.level}] ${rule.text}`).join(`
21589
21626
  `);
21590
- return `### ${set2.id}
21591
- ${rules}`;
21627
+ return { setId: set2.id, block: `### ${set2.id}
21628
+ ${rules}` };
21592
21629
  }),
21593
21630
  ...inlineRules.length > 0 ? [
21594
- `### specialist-inline-rules
21631
+ {
21632
+ setId: "specialist-inline-rules",
21633
+ block: `### specialist-inline-rules
21595
21634
  ${inlineRules.map((rule, index) => `- [${rule.level}] ${rule.text}${rule.id ? ` (id: ${rule.id})` : ` (id: inline-${index + 1})`}`).join(`
21596
21635
  `)}`
21636
+ }
21597
21637
  ] : []
21598
21638
  ];
21599
- return `## MANDATORY_RULES
21600
- ${sections.join(`
21639
+ return { block: `## MANDATORY_RULES
21640
+ ${sections.map((section) => section.block).join(`
21601
21641
 
21602
- `)}`;
21642
+ `)}`, sections };
21603
21643
  }
21604
21644
  function collectMandatoryRuleSets(cwd, setIds) {
21605
21645
  const seen = new Set;
@@ -21633,9 +21673,10 @@ function buildMandatoryRulesInjection(specialistConfig) {
21633
21673
  id: "workflow-quick-rules",
21634
21674
  rules: [{ id: "workflow-quick-rules-1", level: "required", text: STATIC_WORKFLOW_RULES_BLOCK.trim().replace(/^##\s+Beads Workflow Quick Rules\n/, "") }]
21635
21675
  }];
21636
- const block = formatMandatoryRulesBlock([...globals, ...sets], inlineRules);
21676
+ const formatted = formatMandatoryRulesBlock([...globals, ...sets], inlineRules);
21637
21677
  return {
21638
- block,
21678
+ block: formatted.block,
21679
+ sections: formatted.sections,
21639
21680
  setsLoaded: [...globals.map((set2) => set2.id), ...sets.map((set2) => set2.id)],
21640
21681
  ruleCount: [...globals, ...sets].reduce((count, set2) => count + set2.rules.length, 0) + inlineRules.length,
21641
21682
  inlineRulesCount: inlineRules.length,
@@ -22565,9 +22606,8 @@ ${summaries.join(`
22565
22606
  skillPaths.push(prompt.skill_inherit);
22566
22607
  skillPaths.push(...spec.specialist.skills?.paths ?? []);
22567
22608
  if (mandatoryRulesInjection) {
22568
- for (const setId of mandatoryRulesInjection.setsLoaded) {
22569
- payloadComponents.push(measurePayloadComponent("mandatory_rule", setId, `${setId}
22570
- ${mandatoryRulesBlock}`));
22609
+ for (const section of mandatoryRulesInjection.sections) {
22610
+ payloadComponents.push(measurePayloadComponent("mandatory_rule", section.setId, section.block));
22571
22611
  }
22572
22612
  }
22573
22613
  for (const skillPath of skillPaths) {
@@ -31105,7 +31145,7 @@ function resolveWorkingDirectory(args, jobsDir, permissionRequired, readStatus)
31105
31145
  if (args.reuseJobId !== undefined) {
31106
31146
  const targetStatus = readStatus(args.reuseJobId);
31107
31147
  if (!targetStatus) {
31108
- console.error(`Error: cannot read status for job '${args.reuseJobId}'. ` + `Check the job id with: specialists poll ${args.reuseJobId} --json`);
31148
+ console.error(`Error: cannot read status for job '${args.reuseJobId}'. ` + `Check the job id with: specialists ps ${args.reuseJobId} --json`);
31109
31149
  process.exit(1);
31110
31150
  }
31111
31151
  const targetJobStatus = targetStatus.status;
@@ -31553,7 +31593,9 @@ ${bold11(`Running ${cyan6(args.name)}`)}
31553
31593
  ${green9("\u2713")} ${footer}
31554
31594
 
31555
31595
  `);
31556
- process.stderr.write(dim9(`Poll: specialists poll ${jobId} --json
31596
+ process.stderr.write(dim9(`Status: specialists ps ${jobId} --json
31597
+ `));
31598
+ process.stderr.write(dim9(`Events: specialists feed ${jobId}
31557
31599
 
31558
31600
  `));
31559
31601
  process.exit(0);
@@ -35458,6 +35500,16 @@ import { spawnSync as spawnSync16 } from "child_process";
35458
35500
  import { existsSync as existsSync20, mkdirSync as mkdirSync9, readFileSync as readFileSync20, writeFileSync as writeFileSync9 } from "fs";
35459
35501
  import { dirname as dirname8, join as join22 } from "path";
35460
35502
  import { createRequire as createRequire3 } from "module";
35503
+ function readBundledPackageVersion(requireFn = require3) {
35504
+ for (const candidate of ["../package.json", "../../package.json"]) {
35505
+ try {
35506
+ const pkg = requireFn(candidate);
35507
+ if (typeof pkg.version === "string" && pkg.version.length > 0)
35508
+ return pkg.version;
35509
+ } catch {}
35510
+ }
35511
+ return "0.0.0";
35512
+ }
35461
35513
  function shouldRunVersionCheck() {
35462
35514
  if (process.env.SPECIALISTS_OFFLINE === "1")
35463
35515
  return false;
@@ -35565,7 +35617,7 @@ function markVersionCheckNotified(result) {
35565
35617
  var require3, packageVersion, localVersion, CACHE_PATH, CACHE_MAX_AGE_MS2, NETWORK_TIMEOUT_MS = 2000;
35566
35618
  var init_version_check = __esm(() => {
35567
35619
  require3 = createRequire3(import.meta.url);
35568
- ({ version: packageVersion } = require3("../../package.json"));
35620
+ packageVersion = readBundledPackageVersion();
35569
35621
  localVersion = packageVersion;
35570
35622
  CACHE_PATH = join22(process.cwd(), ".specialists", "version-check.json");
35571
35623
  CACHE_MAX_AGE_MS2 = 6 * 60 * 60 * 1000;
@@ -37382,9 +37434,6 @@ function readJobEvents(jobDir) {
37382
37434
  events.sort(compareTimelineEvents);
37383
37435
  return events;
37384
37436
  }
37385
- function readJobEventsById(jobsDir, jobId) {
37386
- return readJobEvents(join26(jobsDir, jobId));
37387
- }
37388
37437
  function readAllJobEvents(jobsDir) {
37389
37438
  const sqliteClient = createObservabilitySqliteClient();
37390
37439
  try {
@@ -38189,130 +38238,13 @@ var init_feed = __esm(() => {
38189
38238
  init_format_helpers();
38190
38239
  });
38191
38240
 
38192
- // src/cli/poll.ts
38193
- var exports_poll = {};
38194
- __export(exports_poll, {
38195
- run: () => run19
38196
- });
38197
- import { existsSync as existsSync26, readFileSync as readFileSync26 } from "fs";
38198
- import { join as join28 } from "path";
38199
- function parseArgs11(argv) {
38200
- let jobId;
38201
- let cursor = 0;
38202
- let outputCursor = 0;
38203
- for (let i = 0;i < argv.length; i++) {
38204
- if (argv[i] === "--cursor" && argv[i + 1]) {
38205
- cursor = parseInt(argv[++i], 10);
38206
- if (isNaN(cursor) || cursor < 0)
38207
- cursor = 0;
38208
- continue;
38209
- }
38210
- if (argv[i] === "--output-cursor" && argv[i + 1]) {
38211
- outputCursor = parseInt(argv[++i], 10);
38212
- if (isNaN(outputCursor) || outputCursor < 0)
38213
- outputCursor = 0;
38214
- continue;
38215
- }
38216
- if (argv[i] === "--json") {
38217
- continue;
38218
- }
38219
- if (argv[i] === "--follow" || argv[i] === "-f") {
38220
- process.stderr.write(`--follow removed from poll. Use 'specialists feed --follow' for live human-readable output.
38221
- `);
38222
- process.exit(1);
38223
- }
38224
- if (!argv[i].startsWith("-")) {
38225
- jobId = argv[i];
38226
- }
38227
- }
38228
- if (!jobId) {
38229
- console.error("Usage: specialists poll <job-id> [--cursor N] [--output-cursor N]");
38230
- process.exit(1);
38231
- }
38232
- return { jobId, cursor, outputCursor };
38233
- }
38234
- function readJobState(jobsDir, jobId, cursor, outputCursor) {
38235
- const jobDir = join28(jobsDir, jobId);
38236
- const statusPath = join28(jobDir, "status.json");
38237
- let status = null;
38238
- if (existsSync26(statusPath)) {
38239
- try {
38240
- status = JSON.parse(readFileSync26(statusPath, "utf-8"));
38241
- } catch {}
38242
- }
38243
- const resultPath = join28(jobDir, "result.txt");
38244
- let fullOutput = "";
38245
- if (existsSync26(resultPath)) {
38246
- try {
38247
- fullOutput = readFileSync26(resultPath, "utf-8");
38248
- } catch {}
38249
- }
38250
- const events = readJobEventsById(jobsDir, jobId);
38251
- const newEvents = events.slice(cursor);
38252
- const nextCursor = events.length;
38253
- const startedAt = status?.started_at_ms ?? Date.now();
38254
- const lastEvent = status?.last_event_at_ms ?? Date.now();
38255
- const elapsedMs = status?.status === "done" || status?.status === "error" ? lastEvent - startedAt : Date.now() - startedAt;
38256
- const isDone = status?.status === "done";
38257
- const output2 = isDone ? fullOutput : "";
38258
- const outputDelta = fullOutput.length > outputCursor ? fullOutput.slice(outputCursor) : "";
38259
- const nextOutputCursor = fullOutput.length;
38260
- return {
38261
- job_id: jobId,
38262
- status: status?.status ?? "starting",
38263
- elapsed_ms: elapsedMs,
38264
- cursor: nextCursor,
38265
- output_cursor: nextOutputCursor,
38266
- output: output2,
38267
- output_delta: outputDelta,
38268
- events: newEvents,
38269
- current_event: status?.current_event,
38270
- current_tool: status?.current_tool,
38271
- model: status?.model,
38272
- backend: status?.backend,
38273
- bead_id: status?.bead_id,
38274
- error: status?.error
38275
- };
38276
- }
38277
- async function run19() {
38278
- process.stderr.write(`[DEPRECATED] 'specialists poll' is scheduled for removal. Use 'sp ps <id> --json' for status and 'sp feed <id>' for events.
38279
- `);
38280
- const { jobId, cursor, outputCursor } = parseArgs11(process.argv.slice(3));
38281
- const jobsDir = join28(process.cwd(), ".specialists", "jobs");
38282
- const jobDir = join28(jobsDir, jobId);
38283
- if (!existsSync26(jobDir)) {
38284
- const result2 = {
38285
- job_id: jobId,
38286
- status: "error",
38287
- elapsed_ms: 0,
38288
- cursor: 0,
38289
- output_cursor: 0,
38290
- output: "",
38291
- output_delta: "",
38292
- events: [],
38293
- error: `Job not found: ${jobId}`
38294
- };
38295
- console.log(JSON.stringify(result2));
38296
- process.exit(1);
38297
- }
38298
- const result = readJobState(jobsDir, jobId, cursor, outputCursor);
38299
- if (result.status !== "done" && result.status !== "error" && !result.output_delta) {
38300
- process.stderr.write(`Tip: use 'specialists feed --follow' for live human-readable output.
38301
- `);
38302
- }
38303
- console.log(JSON.stringify(result));
38304
- }
38305
- var init_poll = __esm(() => {
38306
- init_timeline_query();
38307
- });
38308
-
38309
38241
  // src/cli/steer.ts
38310
38242
  var exports_steer = {};
38311
38243
  __export(exports_steer, {
38312
- run: () => run20
38244
+ run: () => run19
38313
38245
  });
38314
38246
  import { writeFileSync as writeFileSync10 } from "fs";
38315
- async function run20() {
38247
+ async function run19() {
38316
38248
  const jobId = process.argv[3];
38317
38249
  const message = process.argv[4];
38318
38250
  if (!jobId || !message) {
@@ -38363,10 +38295,10 @@ var init_steer = __esm(() => {
38363
38295
  // src/cli/resume.ts
38364
38296
  var exports_resume = {};
38365
38297
  __export(exports_resume, {
38366
- run: () => run21
38298
+ run: () => run20
38367
38299
  });
38368
38300
  import { writeFileSync as writeFileSync11 } from "fs";
38369
- async function run21() {
38301
+ async function run20() {
38370
38302
  const jobId = process.argv[3];
38371
38303
  const task = process.argv[4];
38372
38304
  if (!jobId || !task) {
@@ -38419,24 +38351,24 @@ var init_resume = __esm(() => {
38419
38351
  // src/cli/follow-up.ts
38420
38352
  var exports_follow_up = {};
38421
38353
  __export(exports_follow_up, {
38422
- run: () => run22
38354
+ run: () => run21
38423
38355
  });
38424
- async function run22() {
38356
+ async function run21() {
38425
38357
  process.stderr.write("\x1B[33m\u26A0 DEPRECATED:\x1B[0m `specialists follow-up` is deprecated. Use `specialists resume` instead.\n\n");
38426
38358
  const { run: resumeRun } = await Promise.resolve().then(() => (init_resume(), exports_resume));
38427
38359
  return resumeRun();
38428
38360
  }
38429
38361
 
38430
38362
  // src/specialist/worktree-gc.ts
38431
- import { existsSync as existsSync27, readdirSync as readdirSync11, readFileSync as readFileSync27 } from "fs";
38432
- import { join as join29 } from "path";
38363
+ import { existsSync as existsSync26, readdirSync as readdirSync11, readFileSync as readFileSync26 } from "fs";
38364
+ import { join as join28 } from "path";
38433
38365
  import { spawnSync as spawnSync19 } from "child_process";
38434
38366
  function readJobStatus2(jobDir) {
38435
- const statusPath = join29(jobDir, "status.json");
38436
- if (!existsSync27(statusPath))
38367
+ const statusPath = join28(jobDir, "status.json");
38368
+ if (!existsSync26(statusPath))
38437
38369
  return null;
38438
38370
  try {
38439
- return JSON.parse(readFileSync27(statusPath, "utf-8"));
38371
+ return JSON.parse(readFileSync26(statusPath, "utf-8"));
38440
38372
  } catch {
38441
38373
  return null;
38442
38374
  }
@@ -38458,7 +38390,7 @@ function collectWorktreeGcCandidates(jobsDir) {
38458
38390
  const worktreePath = status.worktree_path;
38459
38391
  if (!worktreePath)
38460
38392
  return null;
38461
- if (!existsSync27(worktreePath))
38393
+ if (!existsSync26(worktreePath))
38462
38394
  return null;
38463
38395
  return {
38464
38396
  jobId: status.id,
@@ -38470,13 +38402,13 @@ function collectWorktreeGcCandidates(jobsDir) {
38470
38402
  }
38471
38403
  if (!getFileFallbackEnabled())
38472
38404
  return [];
38473
- if (!existsSync27(jobsDir))
38405
+ if (!existsSync26(jobsDir))
38474
38406
  return [];
38475
38407
  const candidates = [];
38476
38408
  for (const entry of readdirSync11(jobsDir, { withFileTypes: true })) {
38477
38409
  if (!entry.isDirectory())
38478
38410
  continue;
38479
- const status = readJobStatus2(join29(jobsDir, entry.name));
38411
+ const status = readJobStatus2(join28(jobsDir, entry.name));
38480
38412
  if (!status)
38481
38413
  continue;
38482
38414
  if (isActive(status.status))
@@ -38486,7 +38418,7 @@ function collectWorktreeGcCandidates(jobsDir) {
38486
38418
  const { worktree_path: worktreePath, branch } = status;
38487
38419
  if (!worktreePath)
38488
38420
  continue;
38489
- if (!existsSync27(worktreePath))
38421
+ if (!existsSync26(worktreePath))
38490
38422
  continue;
38491
38423
  candidates.push({
38492
38424
  jobId: status.id,
@@ -38530,10 +38462,10 @@ var init_worktree_gc = __esm(() => {
38530
38462
  // src/cli/clean.ts
38531
38463
  var exports_clean = {};
38532
38464
  __export(exports_clean, {
38533
- run: () => run23
38465
+ run: () => run22
38534
38466
  });
38535
- import { existsSync as existsSync28, readFileSync as readFileSync28, readdirSync as readdirSync12, rmSync as rmSync3, statSync as statSync4 } from "fs";
38536
- import { join as join30 } from "path";
38467
+ import { existsSync as existsSync27, readFileSync as readFileSync27, readdirSync as readdirSync12, rmSync as rmSync3, statSync as statSync4 } from "fs";
38468
+ import { join as join29 } from "path";
38537
38469
  function parseTtlDaysFromEnvironment() {
38538
38470
  const rawValue = process.env.SPECIALISTS_JOB_TTL_DAYS ?? process.env.JOB_TTL_DAYS;
38539
38471
  if (!rawValue)
@@ -38616,7 +38548,7 @@ function parseOptions2(argv) {
38616
38548
  function readDirectorySizeBytes(directoryPath) {
38617
38549
  let totalBytes = 0;
38618
38550
  for (const entry of readdirSync12(directoryPath, { withFileTypes: true })) {
38619
- const entryPath = join30(directoryPath, entry.name);
38551
+ const entryPath = join29(directoryPath, entry.name);
38620
38552
  const stats = statSync4(entryPath);
38621
38553
  totalBytes += stats.isDirectory() ? readDirectorySizeBytes(entryPath) : stats.size;
38622
38554
  }
@@ -38624,7 +38556,7 @@ function readDirectorySizeBytes(directoryPath) {
38624
38556
  }
38625
38557
  function containsProtectedSqliteArtifact(directoryPath) {
38626
38558
  for (const entry of readdirSync12(directoryPath, { withFileTypes: true })) {
38627
- const entryPath = join30(directoryPath, entry.name);
38559
+ const entryPath = join29(directoryPath, entry.name);
38628
38560
  if (entry.isDirectory()) {
38629
38561
  if (containsProtectedSqliteArtifact(entryPath))
38630
38562
  return true;
@@ -38645,15 +38577,15 @@ function getJobTimestamps(status) {
38645
38577
  function readCompletedJobDirectory(baseDirectory, entry) {
38646
38578
  if (!entry.isDirectory())
38647
38579
  return null;
38648
- const directoryPath = join30(baseDirectory, entry.name);
38580
+ const directoryPath = join29(baseDirectory, entry.name);
38649
38581
  if (containsProtectedSqliteArtifact(directoryPath))
38650
38582
  return null;
38651
- const statusFilePath = join30(directoryPath, "status.json");
38652
- if (!existsSync28(statusFilePath))
38583
+ const statusFilePath = join29(directoryPath, "status.json");
38584
+ if (!existsSync27(statusFilePath))
38653
38585
  return null;
38654
38586
  let statusData;
38655
38587
  try {
38656
- statusData = JSON.parse(readFileSync28(statusFilePath, "utf-8"));
38588
+ statusData = JSON.parse(readFileSync27(statusFilePath, "utf-8"));
38657
38589
  } catch {
38658
38590
  return null;
38659
38591
  }
@@ -38667,8 +38599,8 @@ function collectCompletedJobs(jobsDirectoryPath) {
38667
38599
  const statuses = sqliteClient?.listStatuses() ?? [];
38668
38600
  if (statuses.length > 0) {
38669
38601
  return statuses.filter((status) => COMPLETED_STATUSES.has(status.status)).map((status) => {
38670
- const directoryPath = join30(jobsDirectoryPath, status.id);
38671
- if (!existsSync28(directoryPath) || containsProtectedSqliteArtifact(directoryPath))
38602
+ const directoryPath = join29(jobsDirectoryPath, status.id);
38603
+ if (!existsSync27(directoryPath) || containsProtectedSqliteArtifact(directoryPath))
38672
38604
  return null;
38673
38605
  const { createdAtMs, completedAtMs } = getJobTimestamps(status);
38674
38606
  return { id: status.id, directoryPath, completedAtMs, createdAtMs, sizeBytes: readDirectorySizeBytes(directoryPath) };
@@ -38808,7 +38740,7 @@ function removeStaleProcesses(statuses, dryRun) {
38808
38740
  }
38809
38741
  return updatedCount;
38810
38742
  }
38811
- async function run23() {
38743
+ async function run22() {
38812
38744
  let options;
38813
38745
  try {
38814
38746
  options = parseOptions2(process.argv.slice(3));
@@ -38817,7 +38749,7 @@ async function run23() {
38817
38749
  printUsageAndExit2(message);
38818
38750
  }
38819
38751
  const jobsDirectoryPath = resolveJobsDir();
38820
- if (!existsSync28(jobsDirectoryPath)) {
38752
+ if (!existsSync27(jobsDirectoryPath)) {
38821
38753
  console.log("No jobs directory found.");
38822
38754
  return;
38823
38755
  }
@@ -38871,7 +38803,7 @@ var init_clean = __esm(() => {
38871
38803
  // src/cli/end.ts
38872
38804
  var exports_end = {};
38873
38805
  __export(exports_end, {
38874
- run: () => run24
38806
+ run: () => run23
38875
38807
  });
38876
38808
  import { spawnSync as spawnSync20 } from "child_process";
38877
38809
  function parseOptions3(argv) {
@@ -38955,7 +38887,7 @@ async function publishChain(beadId, options) {
38955
38887
  console.log("Publication mode: direct merge");
38956
38888
  }
38957
38889
  }
38958
- async function run24() {
38890
+ async function run23() {
38959
38891
  let options;
38960
38892
  try {
38961
38893
  options = parseOptions3(process.argv.slice(3));
@@ -38996,7 +38928,7 @@ var init_end = __esm(() => {
38996
38928
  // src/cli/stop.ts
38997
38929
  var exports_stop = {};
38998
38930
  __export(exports_stop, {
38999
- run: () => run25
38931
+ run: () => run24
39000
38932
  });
39001
38933
  function resolveTerminalStatus(jobId) {
39002
38934
  return hasRunCompleteEvent(jobId) ? "done" : "cancelled";
@@ -39039,7 +38971,7 @@ function tryKillProcessGroup(pid) {
39039
38971
  throw err;
39040
38972
  }
39041
38973
  }
39042
- async function run25() {
38974
+ async function run24() {
39043
38975
  let parsed;
39044
38976
  try {
39045
38977
  parsed = parseStopArgs(process.argv.slice(3));
@@ -39153,18 +39085,18 @@ var init_stop = __esm(() => {
39153
39085
  // src/cli/attach.ts
39154
39086
  var exports_attach = {};
39155
39087
  __export(exports_attach, {
39156
- run: () => run26
39088
+ run: () => run25
39157
39089
  });
39158
39090
  import { execFileSync as execFileSync3, spawnSync as spawnSync21 } from "child_process";
39159
- import { readFileSync as readFileSync29 } from "fs";
39160
- import { join as join31 } from "path";
39091
+ import { readFileSync as readFileSync28 } from "fs";
39092
+ import { join as join30 } from "path";
39161
39093
  function exitWithError(message) {
39162
39094
  console.error(message);
39163
39095
  process.exit(1);
39164
39096
  }
39165
39097
  function readStatus(statusPath, jobId) {
39166
39098
  try {
39167
- return JSON.parse(readFileSync29(statusPath, "utf-8"));
39099
+ return JSON.parse(readFileSync28(statusPath, "utf-8"));
39168
39100
  } catch (error2) {
39169
39101
  if (error2 && typeof error2 === "object" && "code" in error2 && error2.code === "ENOENT") {
39170
39102
  exitWithError(`Job \`${jobId}\` not found. Run \`specialists status\` to see active jobs in current mode.`);
@@ -39173,13 +39105,13 @@ function readStatus(statusPath, jobId) {
39173
39105
  exitWithError(`Failed to read status for job \`${jobId}\`: ${details}`);
39174
39106
  }
39175
39107
  }
39176
- async function run26() {
39108
+ async function run25() {
39177
39109
  const [jobId] = process.argv.slice(3);
39178
39110
  if (!jobId) {
39179
39111
  exitWithError("Usage: specialists attach <job-id> (normal runtime is DB-backed; job files are legacy/operator-only)");
39180
39112
  }
39181
- const jobsDir = join31(process.cwd(), ".specialists", "jobs");
39182
- const statusPath = join31(jobsDir, jobId, "status.json");
39113
+ const jobsDir = join30(process.cwd(), ".specialists", "jobs");
39114
+ const statusPath = join30(jobsDir, jobId, "status.json");
39183
39115
  const status = readStatus(statusPath, jobId);
39184
39116
  if (status.status === "done" || status.status === "error") {
39185
39117
  exitWithError(`Job \`${jobId}\` has already completed (status: ${status.status}). Use \`specialists result ${jobId}\` to read output.`);
@@ -39201,15 +39133,15 @@ async function run26() {
39201
39133
  var init_attach = () => {};
39202
39134
 
39203
39135
  // src/specialist/drift-detector.ts
39204
- import { existsSync as existsSync29, readFileSync as readFileSync30, readdirSync as readdirSync13, rmSync as rmSync4 } from "fs";
39205
- import { join as join32, resolve as resolve10, relative as relative2 } from "path";
39136
+ import { existsSync as existsSync28, readFileSync as readFileSync29, readdirSync as readdirSync13, rmSync as rmSync4 } from "fs";
39137
+ import { join as join31, resolve as resolve10, relative as relative2 } from "path";
39206
39138
  function listFiles(root) {
39207
- if (!existsSync29(root))
39139
+ if (!existsSync28(root))
39208
39140
  return [];
39209
39141
  const out = [];
39210
39142
  const visit2 = (dir) => {
39211
39143
  for (const entry of readdirSync13(dir, { withFileTypes: true })) {
39212
- const full = join32(dir, entry.name);
39144
+ const full = join31(dir, entry.name);
39213
39145
  if (entry.isDirectory()) {
39214
39146
  visit2(full);
39215
39147
  continue;
@@ -39244,14 +39176,14 @@ function detectDriftForRepo(repoRoot) {
39244
39176
  { scope: "user", dir: resolve10(repoRoot, ".specialists/user") }
39245
39177
  ];
39246
39178
  for (const { scope, dir } of scopes) {
39247
- if (!existsSync29(dir))
39179
+ if (!existsSync28(dir))
39248
39180
  continue;
39249
39181
  for (const file of listFiles(dir)) {
39250
39182
  const rel = relPath(file, dir);
39251
- const canonicalPath = join32(asset.canonicalDir, rel);
39252
- if (!existsSync29(canonicalPath))
39183
+ const canonicalPath = join31(asset.canonicalDir, rel);
39184
+ if (!existsSync28(canonicalPath))
39253
39185
  continue;
39254
- const bytesEqual = readFileSync30(file).equals(readFileSync30(canonicalPath));
39186
+ const bytesEqual = readFileSync29(file).equals(readFileSync29(canonicalPath));
39255
39187
  findings.push(makeFinding(repoRoot, asset.kind, scope, file, canonicalPath, bytesEqual));
39256
39188
  }
39257
39189
  }
@@ -39275,7 +39207,7 @@ function detectDriftUnderRoot(root) {
39275
39207
  continue;
39276
39208
  if (entry.name === "node_modules" || entry.name === ".git")
39277
39209
  continue;
39278
- visit2(join32(dir, entry.name));
39210
+ visit2(join31(dir, entry.name));
39279
39211
  }
39280
39212
  };
39281
39213
  visit2(resolve10(root));
@@ -39315,10 +39247,10 @@ var init_drift_detector = __esm(() => {
39315
39247
  // src/cli/prune-stale-defaults.ts
39316
39248
  var exports_prune_stale_defaults = {};
39317
39249
  __export(exports_prune_stale_defaults, {
39318
- run: () => run27
39250
+ run: () => run26
39319
39251
  });
39320
39252
  import { resolve as resolve11 } from "path";
39321
- function parseArgs12(argv) {
39253
+ function parseArgs11(argv) {
39322
39254
  let dryRun = false;
39323
39255
  let root = process.cwd();
39324
39256
  let help = false;
@@ -39349,8 +39281,8 @@ function printHelp() {
39349
39281
  console.log(" --dry-run List stale default snapshots without pruning");
39350
39282
  console.log(" --root Repo root to scan");
39351
39283
  }
39352
- async function run27(argv = process.argv.slice(3)) {
39353
- const { dryRun, root, help } = parseArgs12(argv);
39284
+ async function run26(argv = process.argv.slice(3)) {
39285
+ const { dryRun, root, help } = parseArgs11(argv);
39354
39286
  if (help) {
39355
39287
  printHelp();
39356
39288
  return;
@@ -39376,7 +39308,7 @@ var init_prune_stale_defaults = __esm(() => {
39376
39308
  // src/cli/quickstart.ts
39377
39309
  var exports_quickstart = {};
39378
39310
  __export(exports_quickstart, {
39379
- run: () => run28
39311
+ run: () => run27
39380
39312
  });
39381
39313
  function section2(title) {
39382
39314
  const bar = "\u2500".repeat(60);
@@ -39390,7 +39322,7 @@ function cmd2(s) {
39390
39322
  function flag(s) {
39391
39323
  return green13(s);
39392
39324
  }
39393
- async function run28() {
39325
+ async function run27() {
39394
39326
  const lines = [
39395
39327
  "",
39396
39328
  bold12("specialists \xB7 Quick Start Guide"),
@@ -39605,7 +39537,7 @@ var bold12 = (s) => `\x1B[1m${s}\x1B[0m`, dim12 = (s) => `\x1B[2m${s}\x1B[0m`, y
39605
39537
  var exports_doctor = {};
39606
39538
  __export(exports_doctor, {
39607
39539
  setStatusError: () => setStatusError,
39608
- run: () => run29,
39540
+ run: () => run28,
39609
39541
  renderProcessSummary: () => renderProcessSummary,
39610
39542
  parseVersionTuple: () => parseVersionTuple,
39611
39543
  compareVersions: () => compareVersions2,
@@ -39613,8 +39545,8 @@ __export(exports_doctor, {
39613
39545
  });
39614
39546
  import { createHash as createHash5 } from "crypto";
39615
39547
  import { spawnSync as spawnSync22 } from "child_process";
39616
- import { existsSync as existsSync30, lstatSync as lstatSync2, mkdirSync as mkdirSync10, readdirSync as readdirSync14, readFileSync as readFileSync31, readlinkSync as readlinkSync2, writeFileSync as writeFileSync12 } from "fs";
39617
- import { dirname as dirname9, join as join33, relative as relative3, resolve as resolve12 } from "path";
39548
+ import { existsSync as existsSync29, lstatSync as lstatSync2, mkdirSync as mkdirSync10, readdirSync as readdirSync14, readFileSync as readFileSync30, readlinkSync as readlinkSync2, writeFileSync as writeFileSync12 } from "fs";
39549
+ import { dirname as dirname9, join as join32, relative as relative3, resolve as resolve12 } from "path";
39618
39550
  function ok3(msg) {
39619
39551
  console.log(` ${green14("\u2713")} ${msg}`);
39620
39552
  }
@@ -39643,10 +39575,10 @@ function isInstalled3(bin) {
39643
39575
  return spawnSync22("which", [bin], { encoding: "utf8", timeout: 2000 }).status === 0;
39644
39576
  }
39645
39577
  function loadJson2(path) {
39646
- if (!existsSync30(path))
39578
+ if (!existsSync29(path))
39647
39579
  return null;
39648
39580
  try {
39649
- return JSON.parse(readFileSync31(path, "utf8"));
39581
+ return JSON.parse(readFileSync30(path, "utf8"));
39650
39582
  } catch {
39651
39583
  return null;
39652
39584
  }
@@ -39689,7 +39621,7 @@ function checkBd() {
39689
39621
  return false;
39690
39622
  }
39691
39623
  ok3(`bd installed ${dim13(sp("bd", ["--version"]).stdout || "")}`);
39692
- if (existsSync30(join33(CWD, ".beads")))
39624
+ if (existsSync29(join32(CWD, ".beads")))
39693
39625
  ok3(".beads/ present in project");
39694
39626
  else
39695
39627
  warn3(".beads/ not found in project");
@@ -39709,15 +39641,15 @@ function checkHooks() {
39709
39641
  section3("Claude Code hooks (2 expected)");
39710
39642
  let allPresent = true;
39711
39643
  for (const name of HOOK_NAMES) {
39712
- const canonicalPath = join33(HOOKS_DIR, name);
39713
- if (!existsSync30(canonicalPath)) {
39644
+ const canonicalPath = join32(HOOKS_DIR, name);
39645
+ if (!existsSync29(canonicalPath)) {
39714
39646
  fail4(`${relative3(CWD, canonicalPath)} ${red7("missing")}`);
39715
39647
  fix("specialists init");
39716
39648
  allPresent = false;
39717
39649
  } else {
39718
39650
  ok3(relative3(CWD, canonicalPath));
39719
39651
  }
39720
- const claudeHookPath = join33(CLAUDE_HOOKS_DIR, name);
39652
+ const claudeHookPath = join32(CLAUDE_HOOKS_DIR, name);
39721
39653
  const symlinkState = isSymlinkTo(claudeHookPath, canonicalPath);
39722
39654
  if (symlinkState.ok) {
39723
39655
  ok3(`${relative3(CWD, claudeHookPath)} -> ${relative3(dirname9(claudeHookPath), canonicalPath)}`);
@@ -39792,14 +39724,14 @@ function checkVersion() {
39792
39724
  }
39793
39725
  function hashFile(path) {
39794
39726
  const hash = createHash5("sha256");
39795
- hash.update(readFileSync31(path));
39727
+ hash.update(readFileSync30(path));
39796
39728
  return hash.digest("hex");
39797
39729
  }
39798
39730
  function collectFileHashes(rootDir) {
39799
39731
  const hashes = new Map;
39800
39732
  const visit2 = (dir) => {
39801
39733
  for (const entry of readdirSync14(dir, { withFileTypes: true })) {
39802
- const fullPath = join33(dir, entry.name);
39734
+ const fullPath = join32(dir, entry.name);
39803
39735
  if (entry.isDirectory()) {
39804
39736
  visit2(fullPath);
39805
39737
  continue;
@@ -39810,12 +39742,12 @@ function collectFileHashes(rootDir) {
39810
39742
  hashes.set(relPath2, hashFile(fullPath));
39811
39743
  }
39812
39744
  };
39813
- if (existsSync30(rootDir))
39745
+ if (existsSync29(rootDir))
39814
39746
  visit2(rootDir);
39815
39747
  return hashes;
39816
39748
  }
39817
39749
  function isSymlinkTo(linkPath, expectedTargetPath) {
39818
- if (!existsSync30(linkPath))
39750
+ if (!existsSync29(linkPath))
39819
39751
  return { ok: false, reason: "missing" };
39820
39752
  let stats;
39821
39753
  try {
@@ -39839,12 +39771,12 @@ function isSymlinkTo(linkPath, expectedTargetPath) {
39839
39771
  }
39840
39772
  function checkSkillDrift() {
39841
39773
  section3("Skill drift (.xtrm skill sync)");
39842
- if (!existsSync30(CONFIG_SKILLS_DIR)) {
39774
+ if (!existsSync29(CONFIG_SKILLS_DIR)) {
39843
39775
  fail4("config/skills/ missing");
39844
39776
  fix("restore config/skills/ from git");
39845
39777
  return false;
39846
39778
  }
39847
- if (!existsSync30(XTRM_DEFAULT_SKILLS_DIR)) {
39779
+ if (!existsSync29(XTRM_DEFAULT_SKILLS_DIR)) {
39848
39780
  fail4(".xtrm/skills/default/ missing");
39849
39781
  fix("specialists init --sync-skills");
39850
39782
  return false;
@@ -39886,8 +39818,8 @@ function checkSkillDrift() {
39886
39818
  }
39887
39819
  let linksOk = true;
39888
39820
  for (const scope of ["claude", "pi"]) {
39889
- const activeRoot = join33(XTRM_ACTIVE_SKILLS_DIR, scope);
39890
- if (!existsSync30(activeRoot)) {
39821
+ const activeRoot = join32(XTRM_ACTIVE_SKILLS_DIR, scope);
39822
+ if (!existsSync29(activeRoot)) {
39891
39823
  fail4(`${relative3(CWD, activeRoot)}/ missing`);
39892
39824
  fix("specialists init --sync-skills");
39893
39825
  linksOk = false;
@@ -39895,8 +39827,8 @@ function checkSkillDrift() {
39895
39827
  }
39896
39828
  const defaultSkills = readdirSync14(XTRM_DEFAULT_SKILLS_DIR, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
39897
39829
  for (const skillName of defaultSkills) {
39898
- const activeLinkPath = join33(activeRoot, skillName);
39899
- const expectedTarget = join33(XTRM_DEFAULT_SKILLS_DIR, skillName);
39830
+ const activeLinkPath = join32(activeRoot, skillName);
39831
+ const expectedTarget = join32(XTRM_DEFAULT_SKILLS_DIR, skillName);
39900
39832
  const state = isSymlinkTo(activeLinkPath, expectedTarget);
39901
39833
  if (state.ok)
39902
39834
  continue;
@@ -39915,8 +39847,8 @@ function checkSkillDrift() {
39915
39847
  }
39916
39848
  }
39917
39849
  const skillRootChecks = [
39918
- { root: join33(CLAUDE_DIR, "skills"), expected: ACTIVE_CLAUDE_SKILLS_DIR },
39919
- { root: join33(PI_DIR, "skills"), expected: ACTIVE_PI_SKILLS_DIR }
39850
+ { root: join32(CLAUDE_DIR, "skills"), expected: ACTIVE_CLAUDE_SKILLS_DIR },
39851
+ { root: join32(PI_DIR, "skills"), expected: ACTIVE_PI_SKILLS_DIR }
39920
39852
  ];
39921
39853
  let rootLinksOk = true;
39922
39854
  for (const check2 of skillRootChecks) {
@@ -39941,12 +39873,12 @@ function checkSkillDrift() {
39941
39873
  return drifted.length === 0 && missingInDefault.length === 0 && linksOk && rootLinksOk;
39942
39874
  }
39943
39875
  function checkManagedMirror(label, sourceDir, mirrorDir, fixHint) {
39944
- if (!existsSync30(sourceDir)) {
39876
+ if (!existsSync29(sourceDir)) {
39945
39877
  warn3(`${label} source missing: ${relative3(CWD, sourceDir)}`);
39946
39878
  fix(fixHint);
39947
39879
  return false;
39948
39880
  }
39949
- if (!existsSync30(mirrorDir)) {
39881
+ if (!existsSync29(mirrorDir)) {
39950
39882
  fail4(`${label} mirror missing: ${relative3(CWD, mirrorDir)}`);
39951
39883
  fix(fixHint);
39952
39884
  return false;
@@ -39978,13 +39910,13 @@ function checkManagedMirror(label, sourceDir, mirrorDir, fixHint) {
39978
39910
  function checkManagedAssetMirrors() {
39979
39911
  section3("Managed mirrors (specialists / mandatory-rules / nodes)");
39980
39912
  const specialistsOk = checkManagedMirror("specialists", CONFIG_SPECIALISTS_DIR, DEFAULT_SPECIALISTS_DIR, "specialists init --sync-defaults");
39981
- const rulesOk = checkManagedMirror("mandatory-rules", CONFIG_MANDATORY_RULES_DIR, join33(DEFAULT_SPECIALISTS_DIR, "mandatory-rules"), "specialists init --sync-defaults");
39982
- const nodesOk = checkManagedMirror("nodes", CONFIG_NODES_DIR, join33(DEFAULT_SPECIALISTS_DIR, "nodes"), "specialists init --sync-defaults");
39913
+ const rulesOk = checkManagedMirror("mandatory-rules", CONFIG_MANDATORY_RULES_DIR, join32(DEFAULT_SPECIALISTS_DIR, "mandatory-rules"), "specialists init --sync-defaults");
39914
+ const nodesOk = checkManagedMirror("nodes", CONFIG_NODES_DIR, join32(DEFAULT_SPECIALISTS_DIR, "nodes"), "specialists init --sync-defaults");
39983
39915
  return specialistsOk && rulesOk && nodesOk;
39984
39916
  }
39985
39917
  function checkUserOverlayDrift() {
39986
39918
  section3("User specialist overlays");
39987
- if (!existsSync30(USER_SPECIALISTS_DIR)) {
39919
+ if (!existsSync29(USER_SPECIALISTS_DIR)) {
39988
39920
  ok3("no user overlays present");
39989
39921
  return true;
39990
39922
  }
@@ -39995,14 +39927,14 @@ function checkUserOverlayDrift() {
39995
39927
  }
39996
39928
  let allOk = true;
39997
39929
  for (const name of overlays) {
39998
- const userPath = join33(USER_SPECIALISTS_DIR, name);
39999
- const defaultPath = join33(DEFAULT_SPECIALISTS_DIR, name);
39930
+ const userPath = join32(USER_SPECIALISTS_DIR, name);
39931
+ const defaultPath = join32(DEFAULT_SPECIALISTS_DIR, name);
40000
39932
  const userSpec = loadJson2(userPath);
40001
39933
  if (!userSpec) {
40002
39934
  warn3(`${name}: failed to parse \u2014 skipping drift check`);
40003
39935
  continue;
40004
39936
  }
40005
- if (!existsSync30(defaultPath)) {
39937
+ if (!existsSync29(defaultPath)) {
40006
39938
  ok3(`${name}: user-only overlay (no default to drift from)`);
40007
39939
  continue;
40008
39940
  }
@@ -40030,18 +39962,18 @@ function checkUserOverlayDrift() {
40030
39962
  }
40031
39963
  function checkRuntimeDirs() {
40032
39964
  section3(".specialists/ runtime directories");
40033
- const rootDir = join33(CWD, ".specialists");
40034
- const jobsDir = join33(rootDir, "jobs");
40035
- const readyDir = join33(rootDir, "ready");
39965
+ const rootDir = join32(CWD, ".specialists");
39966
+ const jobsDir = join32(rootDir, "jobs");
39967
+ const readyDir = join32(rootDir, "ready");
40036
39968
  let allOk = true;
40037
- if (!existsSync30(rootDir)) {
39969
+ if (!existsSync29(rootDir)) {
40038
39970
  warn3(".specialists/ not found in current project");
40039
39971
  fix("specialists init");
40040
39972
  allOk = false;
40041
39973
  } else {
40042
39974
  ok3(".specialists/ present");
40043
39975
  for (const [subDir, label] of [[jobsDir, "jobs"], [readyDir, "ready"]]) {
40044
- if (!existsSync30(subDir)) {
39976
+ if (!existsSync29(subDir)) {
40045
39977
  warn3(`.specialists/${label}/ missing \u2014 auto-creating`);
40046
39978
  mkdirSync10(subDir, { recursive: true });
40047
39979
  ok3(`.specialists/${label}/ created`);
@@ -40055,8 +39987,8 @@ function checkRuntimeDirs() {
40055
39987
  function checkClaudeMdFragments() {
40056
39988
  section3("CLAUDE.md fragments");
40057
39989
  const projectRoot = process.cwd();
40058
- const claudeMd = join33(projectRoot, "CLAUDE.md");
40059
- if (!existsSync30(claudeMd)) {
39990
+ const claudeMd = join32(projectRoot, "CLAUDE.md");
39991
+ if (!existsSync29(claudeMd)) {
40060
39992
  warn3("No CLAUDE.md in project root \u2014 skipping fragment check");
40061
39993
  return true;
40062
39994
  }
@@ -40182,7 +40114,7 @@ function compareVersions2(left, right) {
40182
40114
  }
40183
40115
  function setStatusError(statusPath) {
40184
40116
  try {
40185
- const raw = readFileSync31(statusPath, "utf8");
40117
+ const raw = readFileSync30(statusPath, "utf8");
40186
40118
  const status = JSON.parse(raw);
40187
40119
  status.status = "error";
40188
40120
  writeFileSync12(statusPath, `${JSON.stringify(status, null, 2)}
@@ -40236,11 +40168,11 @@ function cleanupProcesses(jobsDir, dryRun) {
40236
40168
  zombieJobIds: []
40237
40169
  };
40238
40170
  for (const jobId of entries) {
40239
- const statusPath = join33(jobsDir, jobId, "status.json");
40240
- if (!existsSync30(statusPath))
40171
+ const statusPath = join32(jobsDir, jobId, "status.json");
40172
+ if (!existsSync29(statusPath))
40241
40173
  continue;
40242
40174
  try {
40243
- const status = JSON.parse(readFileSync31(statusPath, "utf8"));
40175
+ const status = JSON.parse(readFileSync30(statusPath, "utf8"));
40244
40176
  result.total += 1;
40245
40177
  if (status.status !== "running" && status.status !== "starting")
40246
40178
  continue;
@@ -40325,8 +40257,8 @@ function resolveWatchdogMode() {
40325
40257
  function checkZombieJobs() {
40326
40258
  section3("Background jobs");
40327
40259
  hint(`watchdog mode: ${resolveWatchdogMode()}`);
40328
- const jobsDir = join33(CWD, ".specialists", "jobs");
40329
- if (!existsSync30(jobsDir)) {
40260
+ const jobsDir = join32(CWD, ".specialists", "jobs");
40261
+ if (!existsSync29(jobsDir)) {
40330
40262
  hint("No .specialists/jobs/ \u2014 skipping");
40331
40263
  return true;
40332
40264
  }
@@ -40344,7 +40276,7 @@ function checkZombieJobs() {
40344
40276
  }
40345
40277
  return result.zombies === 0;
40346
40278
  }
40347
- async function run29(argv = process.argv.slice(3)) {
40279
+ async function run28(argv = process.argv.slice(3)) {
40348
40280
  const subcommand = argv[0];
40349
40281
  if (subcommand === "orphans") {
40350
40282
  runDoctorOrphans();
@@ -40391,24 +40323,24 @@ var init_doctor = __esm(() => {
40391
40323
  init_drift_detector();
40392
40324
  init_version_check();
40393
40325
  CWD = process.cwd();
40394
- CLAUDE_DIR = join33(CWD, ".claude");
40395
- PI_DIR = join33(CWD, ".pi");
40396
- XTRM_SKILLS_DIR = join33(CWD, ".xtrm", "skills");
40397
- XTRM_DEFAULT_SKILLS_DIR = join33(XTRM_SKILLS_DIR, "default");
40398
- XTRM_ACTIVE_SKILLS_DIR = join33(XTRM_SKILLS_DIR, "active");
40399
- ACTIVE_CLAUDE_SKILLS_DIR = join33(XTRM_ACTIVE_SKILLS_DIR, "claude");
40400
- ACTIVE_PI_SKILLS_DIR = join33(XTRM_ACTIVE_SKILLS_DIR, "pi");
40401
- CONFIG_SKILLS_DIR = join33(CWD, "config", "skills");
40402
- CONFIG_SPECIALISTS_DIR = join33(CWD, "config", "specialists");
40403
- CONFIG_MANDATORY_RULES_DIR = join33(CWD, "config", "mandatory-rules");
40404
- CONFIG_NODES_DIR = join33(CWD, "config", "nodes");
40405
- SPECIALISTS_DIR = join33(CWD, ".specialists");
40406
- DEFAULT_SPECIALISTS_DIR = join33(SPECIALISTS_DIR, "default");
40407
- USER_SPECIALISTS_DIR = join33(SPECIALISTS_DIR, "user");
40408
- HOOKS_DIR = join33(CWD, ".xtrm", "hooks", "specialists");
40409
- CLAUDE_HOOKS_DIR = join33(CLAUDE_DIR, "hooks");
40410
- SETTINGS_FILE = join33(CLAUDE_DIR, "settings.json");
40411
- MCP_FILE2 = join33(CWD, ".mcp.json");
40326
+ CLAUDE_DIR = join32(CWD, ".claude");
40327
+ PI_DIR = join32(CWD, ".pi");
40328
+ XTRM_SKILLS_DIR = join32(CWD, ".xtrm", "skills");
40329
+ XTRM_DEFAULT_SKILLS_DIR = join32(XTRM_SKILLS_DIR, "default");
40330
+ XTRM_ACTIVE_SKILLS_DIR = join32(XTRM_SKILLS_DIR, "active");
40331
+ ACTIVE_CLAUDE_SKILLS_DIR = join32(XTRM_ACTIVE_SKILLS_DIR, "claude");
40332
+ ACTIVE_PI_SKILLS_DIR = join32(XTRM_ACTIVE_SKILLS_DIR, "pi");
40333
+ CONFIG_SKILLS_DIR = join32(CWD, "config", "skills");
40334
+ CONFIG_SPECIALISTS_DIR = join32(CWD, "config", "specialists");
40335
+ CONFIG_MANDATORY_RULES_DIR = join32(CWD, "config", "mandatory-rules");
40336
+ CONFIG_NODES_DIR = join32(CWD, "config", "nodes");
40337
+ SPECIALISTS_DIR = join32(CWD, ".specialists");
40338
+ DEFAULT_SPECIALISTS_DIR = join32(SPECIALISTS_DIR, "default");
40339
+ USER_SPECIALISTS_DIR = join32(SPECIALISTS_DIR, "user");
40340
+ HOOKS_DIR = join32(CWD, ".xtrm", "hooks", "specialists");
40341
+ CLAUDE_HOOKS_DIR = join32(CLAUDE_DIR, "hooks");
40342
+ SETTINGS_FILE = join32(CLAUDE_DIR, "settings.json");
40343
+ MCP_FILE2 = join32(CWD, ".mcp.json");
40412
40344
  HOOK_NAMES = [
40413
40345
  "specialists-complete.mjs",
40414
40346
  "specialists-session-start.mjs"
@@ -40418,9 +40350,9 @@ var init_doctor = __esm(() => {
40418
40350
  // src/cli/setup.ts
40419
40351
  var exports_setup = {};
40420
40352
  __export(exports_setup, {
40421
- run: () => run30
40353
+ run: () => run29
40422
40354
  });
40423
- async function run30() {
40355
+ async function run29() {
40424
40356
  console.log("");
40425
40357
  console.log(yellow13("\u26A0 DEPRECATED: `specialists setup` is deprecated"));
40426
40358
  console.log("");
@@ -40441,20 +40373,20 @@ async function run30() {
40441
40373
  var bold14 = (s) => `\x1B[1m${s}\x1B[0m`, yellow13 = (s) => `\x1B[33m${s}\x1B[0m`, dim14 = (s) => `\x1B[2m${s}\x1B[0m`;
40442
40374
 
40443
40375
  // src/cli/serve-hot-reload.ts
40444
- import { existsSync as existsSync31, readdirSync as readdirSync15, statSync as statSync5, watch as fsWatch } from "fs";
40445
- import { join as join34 } from "path";
40376
+ import { existsSync as existsSync30, readdirSync as readdirSync15, statSync as statSync5, watch as fsWatch } from "fs";
40377
+ import { join as join33 } from "path";
40446
40378
  function specialistNameFromFile(file) {
40447
40379
  const match = file.match(/^(.+)\.specialist\.(json|yaml)$/);
40448
40380
  return match ? match[1] : null;
40449
40381
  }
40450
40382
  function snapshotMtimes(dir) {
40451
40383
  const out = new Map;
40452
- if (!existsSync31(dir))
40384
+ if (!existsSync30(dir))
40453
40385
  return out;
40454
40386
  const entries = readdirSync15(dir).filter((name) => specialistNameFromFile(name) !== null);
40455
40387
  for (const name of entries) {
40456
40388
  try {
40457
- out.set(name, statSync5(join34(dir, name)).mtimeMs);
40389
+ out.set(name, statSync5(join33(dir, name)).mtimeMs);
40458
40390
  } catch {}
40459
40391
  }
40460
40392
  return out;
@@ -40511,7 +40443,7 @@ function createUserDirWatcher(opts) {
40511
40443
  for (const file of changed)
40512
40444
  queue(file);
40513
40445
  }, opts.pollMs);
40514
- } else if (existsSync31(opts.userDir)) {
40446
+ } else if (existsSync30(opts.userDir)) {
40515
40447
  try {
40516
40448
  watcher = fsWatch(opts.userDir, { persistent: false }, (_eventType, filename) => {
40517
40449
  queue(filename ? String(filename) : null);
@@ -40543,7 +40475,7 @@ var init_serve_hot_reload = () => {};
40543
40475
  var exports_serve = {};
40544
40476
  __export(exports_serve, {
40545
40477
  startServe: () => startServe,
40546
- run: () => run31,
40478
+ run: () => run30,
40547
40479
  recordAuditFailure: () => recordAuditFailure,
40548
40480
  evaluateReadiness: () => evaluateReadiness2,
40549
40481
  createReadinessState: () => createReadinessState
@@ -40551,9 +40483,9 @@ __export(exports_serve, {
40551
40483
  import { createServer } from "http";
40552
40484
  import { once } from "events";
40553
40485
  import { access, readdir as readdir2, readFile as readFile5, constants } from "fs/promises";
40554
- import { existsSync as existsSync32 } from "fs";
40486
+ import { existsSync as existsSync31 } from "fs";
40555
40487
  import { homedir as homedir3 } from "os";
40556
- import { join as join35 } from "path";
40488
+ import { join as join34 } from "path";
40557
40489
  function createReadinessState() {
40558
40490
  return { shuttingDown: false, auditFailures: [], dbWriteFailuresTotal: 0 };
40559
40491
  }
@@ -40569,7 +40501,7 @@ function pruneAuditFailures(state, now = Date.now()) {
40569
40501
  }
40570
40502
  }
40571
40503
  async function checkUserDirSpecs(userDir) {
40572
- if (!existsSync32(userDir))
40504
+ if (!existsSync31(userDir))
40573
40505
  return "empty";
40574
40506
  const entries = await readdir2(userDir).catch(() => []);
40575
40507
  const specFiles = entries.filter((name) => name.endsWith(".specialist.json") || name.endsWith(".specialist.yaml"));
@@ -40578,7 +40510,7 @@ async function checkUserDirSpecs(userDir) {
40578
40510
  let validCount = 0;
40579
40511
  for (const file of specFiles) {
40580
40512
  try {
40581
- const content = await readFile5(join35(userDir, file), "utf-8");
40513
+ const content = await readFile5(join34(userDir, file), "utf-8");
40582
40514
  const json = file.endsWith(".json") ? content : null;
40583
40515
  if (!json)
40584
40516
  continue;
@@ -40596,7 +40528,7 @@ async function evaluateReadiness2(opts) {
40596
40528
  if (opts.state.auditFailures.length > opts.auditFailureThreshold) {
40597
40529
  return { ready: false, reason: "degraded:audit" };
40598
40530
  }
40599
- const piConfigPath = opts.piConfigPath ?? join35(homedir3(), ".pi", "agent", "auth.json");
40531
+ const piConfigPath = opts.piConfigPath ?? join34(homedir3(), ".pi", "agent", "auth.json");
40600
40532
  try {
40601
40533
  await access(piConfigPath, constants.R_OK);
40602
40534
  } catch {
@@ -40607,7 +40539,7 @@ async function evaluateReadiness2(opts) {
40607
40539
  } catch {
40608
40540
  return { ready: false, reason: "db_not_writable" };
40609
40541
  }
40610
- const userDir = join35(opts.projectDir, ".specialists", "user");
40542
+ const userDir = join34(opts.projectDir, ".specialists", "user");
40611
40543
  const userDirResult = await checkUserDirSpecs(userDir);
40612
40544
  if (userDirResult === "empty")
40613
40545
  return { ready: false, reason: "empty_user_dir" };
@@ -40615,7 +40547,7 @@ async function evaluateReadiness2(opts) {
40615
40547
  return { ready: false, reason: "invalid_spec_in_user_dir" };
40616
40548
  return { ready: true };
40617
40549
  }
40618
- function parseArgs13(argv) {
40550
+ function parseArgs12(argv) {
40619
40551
  let port = 8000;
40620
40552
  let concurrency = 4;
40621
40553
  let queueTimeoutMs = 5000;
@@ -40677,13 +40609,13 @@ async function waitForSlot(limit, timeoutMs, getActive) {
40677
40609
  return true;
40678
40610
  }
40679
40611
  async function startServe(argv = process.argv.slice(3)) {
40680
- const args = parseArgs13(argv);
40612
+ const args = parseArgs12(argv);
40681
40613
  const loader = new SpecialistLoader({ projectDir: args.projectDir });
40682
40614
  const dbLocation = resolveObservabilityDbLocation(args.projectDir);
40683
40615
  ensureObservabilityDbFile(dbLocation);
40684
40616
  const db = createObservabilitySqliteClient(args.projectDir);
40685
40617
  const readinessState = createReadinessState();
40686
- const userDir = join35(args.projectDir, ".specialists", "user");
40618
+ const userDir = join34(args.projectDir, ".specialists", "user");
40687
40619
  const hotReload = createUserDirWatcher({ loader, userDir, pollMs: args.reloadPollMs });
40688
40620
  let active = 0;
40689
40621
  const children = new Set;
@@ -40768,7 +40700,7 @@ async function startServe(argv = process.argv.slice(3)) {
40768
40700
  console.log(`sp serve listening on ${args.port}`);
40769
40701
  return { server, args, db, readinessState };
40770
40702
  }
40771
- async function run31(argv = process.argv.slice(3)) {
40703
+ async function run30(argv = process.argv.slice(3)) {
40772
40704
  await startServe(argv);
40773
40705
  }
40774
40706
  var AUDIT_WINDOW_MS = 60000;
@@ -40785,8 +40717,8 @@ var init_serve = __esm(() => {
40785
40717
  var exports_script = {};
40786
40718
  __export(exports_script, {
40787
40719
  scriptCli: () => scriptCli,
40788
- run: () => run32,
40789
- parseArgs: () => parseArgs14,
40720
+ run: () => run31,
40721
+ parseArgs: () => parseArgs13,
40790
40722
  mapExitCode: () => mapExitCode
40791
40723
  });
40792
40724
  import { spawnSync as spawnSync23 } from "child_process";
@@ -40796,7 +40728,7 @@ function parseVar(entry) {
40796
40728
  throw new Error(`Invalid --vars entry: ${entry}`);
40797
40729
  return [entry.slice(0, index), entry.slice(index + 1)];
40798
40730
  }
40799
- function parseArgs14(argv) {
40731
+ function parseArgs13(argv) {
40800
40732
  if (argv.length === 0)
40801
40733
  throw new Error("Missing specialist name");
40802
40734
  const specialist = argv[0];
@@ -40902,8 +40834,8 @@ function runUnderLock(lockPath, argv) {
40902
40834
  return 75;
40903
40835
  return flock.status ?? 1;
40904
40836
  }
40905
- async function run32(argv = process.argv.slice(3)) {
40906
- const args = parseArgs14(argv);
40837
+ async function run31(argv = process.argv.slice(3)) {
40838
+ const args = parseArgs13(argv);
40907
40839
  if (args.singleInstance && !process.env.SP_SCRIPT_NO_LOCK) {
40908
40840
  process.exit(runUnderLock(args.singleInstance, argv));
40909
40841
  }
@@ -40916,19 +40848,19 @@ var scriptCli;
40916
40848
  var init_script = __esm(() => {
40917
40849
  init_loader();
40918
40850
  init_script_runner();
40919
- scriptCli = { parseArgs: parseArgs14, mapExitCode };
40851
+ scriptCli = { parseArgs: parseArgs13, mapExitCode };
40920
40852
  });
40921
40853
 
40922
40854
  // src/cli/help.ts
40923
40855
  var exports_help = {};
40924
40856
  __export(exports_help, {
40925
- run: () => run33
40857
+ run: () => run32
40926
40858
  });
40927
40859
  function formatCommands(entries) {
40928
40860
  const width = Math.max(...entries.map(([cmd3]) => cmd3.length));
40929
40861
  return entries.map(([cmd3, desc]) => ` ${cmd3.padEnd(width)} ${desc}`);
40930
40862
  }
40931
- async function run33() {
40863
+ async function run32() {
40932
40864
  const lines = [
40933
40865
  "",
40934
40866
  "Specialists lets you run project-scoped specialist agents with a bead-first workflow.",
@@ -40964,7 +40896,7 @@ async function run33() {
40964
40896
  " Async patterns",
40965
40897
  " MCP: use_specialist (foreground, returns result directly)",
40966
40898
  ' CLI: specialists run <name> --prompt "..." # job ID prints on stderr',
40967
- " specialists feed|poll|result <job-id> # observe/progress/final output",
40899
+ " specialists ps|feed|result <job-id> # observe/progress/final output",
40968
40900
  ' Shell: specialists run <name> --prompt "..." & # native shell backgrounding',
40969
40901
  "",
40970
40902
  " Background workflow",
@@ -41014,7 +40946,6 @@ async function run33() {
41014
40946
  " specialists view --help View specialist configs",
41015
40947
  " specialists edit --help Edit specialist fields (dot-path, presets)",
41016
40948
  " specialists run --help Run command details and flags",
41017
- " specialists poll --help [DEPRECATED] use sp ps + sp feed",
41018
40949
  " specialists steer --help Mid-run steering details",
41019
40950
  " specialists resume --help Multi-turn keep-alive details",
41020
40951
  " specialists init --help Bootstrap behavior and workflow injection",
@@ -41042,7 +40973,6 @@ var init_help = __esm(() => {
41042
40973
  ["node", "Run and inspect NodeSupervisor nodes (run/status)"],
41043
40974
  ["epic", "Epic lifecycle management: list/status/resolve wave-bound chain groups"],
41044
40975
  ["feed", "Tail job events; use -f to follow all jobs"],
41045
- ["poll", "Machine-readable job status polling (for scripts/Claude Code)"],
41046
40976
  ["result", "Print final output of a completed job; --wait polls until done, --timeout <ms> sets a limit"],
41047
40977
  ["clean", "Purge completed job directories (TTL, --all, --keep, --dry-run)"],
41048
40978
  ["merge", "Publish one standalone chain (refuses unresolved epic chains)"],
@@ -44857,7 +44787,7 @@ var AssertObjectSchema = custom2((v) => v !== null && (typeof v === "object" ||
44857
44787
  var ProgressTokenSchema = union([string2(), number2().int()]);
44858
44788
  var CursorSchema = string2();
44859
44789
  var TaskCreationParamsSchema = looseObject({
44860
- ttl: union([number2(), _null3()]).optional(),
44790
+ ttl: number2().optional(),
44861
44791
  pollInterval: number2().optional()
44862
44792
  });
44863
44793
  var TaskMetadataSchema = object2({
@@ -45011,7 +44941,8 @@ var ClientCapabilitiesSchema = object2({
45011
44941
  roots: object2({
45012
44942
  listChanged: boolean2().optional()
45013
44943
  }).optional(),
45014
- tasks: ClientTasksCapabilitySchema.optional()
44944
+ tasks: ClientTasksCapabilitySchema.optional(),
44945
+ extensions: record(string2(), AssertObjectSchema).optional()
45015
44946
  });
45016
44947
  var InitializeRequestParamsSchema = BaseRequestParamsSchema.extend({
45017
44948
  protocolVersion: string2(),
@@ -45036,7 +44967,8 @@ var ServerCapabilitiesSchema = object2({
45036
44967
  tools: object2({
45037
44968
  listChanged: boolean2().optional()
45038
44969
  }).optional(),
45039
- tasks: ServerTasksCapabilitySchema.optional()
44970
+ tasks: ServerTasksCapabilitySchema.optional(),
44971
+ extensions: record(string2(), AssertObjectSchema).optional()
45040
44972
  });
45041
44973
  var InitializeResultSchema = ResultSchema.extend({
45042
44974
  protocolVersion: string2(),
@@ -45151,6 +45083,7 @@ var ResourceSchema = object2({
45151
45083
  uri: string2(),
45152
45084
  description: optional(string2()),
45153
45085
  mimeType: optional(string2()),
45086
+ size: optional(number2()),
45154
45087
  annotations: AnnotationsSchema.optional(),
45155
45088
  _meta: optional(looseObject({}))
45156
45089
  });
@@ -47146,6 +47079,10 @@ class Protocol {
47146
47079
  this._progressHandlers.clear();
47147
47080
  this._taskProgressTokens.clear();
47148
47081
  this._pendingDebouncedNotifications.clear();
47082
+ for (const info of this._timeoutInfo.values()) {
47083
+ clearTimeout(info.timeoutId);
47084
+ }
47085
+ this._timeoutInfo.clear();
47149
47086
  for (const controller of this._requestHandlerAbortControllers.values()) {
47150
47087
  controller.abort();
47151
47088
  }
@@ -47276,7 +47213,9 @@ class Protocol {
47276
47213
  await capturedTransport?.send(errorResponse);
47277
47214
  }
47278
47215
  }).catch((error2) => this._onerror(new Error(`Failed to send response: ${error2}`))).finally(() => {
47279
- this._requestHandlerAbortControllers.delete(request.id);
47216
+ if (this._requestHandlerAbortControllers.get(request.id) === abortController) {
47217
+ this._requestHandlerAbortControllers.delete(request.id);
47218
+ }
47280
47219
  });
47281
47220
  }
47282
47221
  _onprogress(notification) {
@@ -48578,7 +48517,7 @@ var next = process.argv[3];
48578
48517
  function wantsHelp() {
48579
48518
  return next === "--help" || next === "-h";
48580
48519
  }
48581
- async function run34() {
48520
+ async function run33() {
48582
48521
  if (sub === "install") {
48583
48522
  if (wantsHelp()) {
48584
48523
  console.log([
@@ -48963,7 +48902,7 @@ async function run34() {
48963
48902
  "",
48964
48903
  "Async execution patterns:",
48965
48904
  " MCP: use_specialist (foreground, returns result directly)",
48966
- " CLI: run prints [job started: <id>] on stderr, then use feed/poll/result",
48905
+ " CLI: run prints [job started: <id>] on stderr, then use ps/feed/result",
48967
48906
  ' Shell: specialists run <name> --prompt "..." &',
48968
48907
  ""
48969
48908
  ].join(`
@@ -49201,53 +49140,6 @@ async function run34() {
49201
49140
  const { run: handler } = await Promise.resolve().then(() => (init_feed(), exports_feed));
49202
49141
  return handler();
49203
49142
  }
49204
- if (sub === "poll") {
49205
- if (wantsHelp()) {
49206
- console.log([
49207
- "",
49208
- "Usage: specialists poll <job-id> [--cursor N] [--json]",
49209
- "",
49210
- "[DEPRECATED] Scheduled for removal. Use:",
49211
- " sp ps <id> --json for status",
49212
- " sp feed <id> for events",
49213
- "",
49214
- "Machine-readable job status polling for scripts and Claude Code.",
49215
- "Currently file-based; replacements above are DB-canonical.",
49216
- "",
49217
- "Output (JSON mode):",
49218
- " {",
49219
- ' "job_id": "abc123",',
49220
- ' "status": "running" | "done" | "error" | "waiting",',
49221
- ' "elapsed_ms": 45000,',
49222
- ' "cursor": 15,',
49223
- ' "events": [...], // new events since cursor',
49224
- ' "output": "...", // full output when done',
49225
- ' "model": "claude-sonnet-4-6",',
49226
- ' "bead_id": "unitAI-123"',
49227
- " }",
49228
- "",
49229
- "Options:",
49230
- " --cursor N Event index to start from (default: 0)",
49231
- " --json Output as JSON (machine-readable)",
49232
- "",
49233
- "Examples:",
49234
- " specialists poll abc123 --json",
49235
- " specialists poll abc123 --cursor 5 --json",
49236
- "",
49237
- "Polling pattern in Claude Code:",
49238
- " 1. Start job (blocks until done):",
49239
- " specialists run planner --bead xtrm-p38n.1",
49240
- " 2. Or use Claude Code native backgrounding",
49241
- " 3. Poll for incremental status:",
49242
- " specialists poll <job-id> --json",
49243
- ""
49244
- ].join(`
49245
- `));
49246
- return;
49247
- }
49248
- const { run: pollHandler } = await Promise.resolve().then(() => (init_poll(), exports_poll));
49249
- return pollHandler();
49250
- }
49251
49143
  if (sub === "steer") {
49252
49144
  if (wantsHelp()) {
49253
49145
  console.log([
@@ -49587,7 +49479,7 @@ Run 'specialists help' to see available commands.`);
49587
49479
  const server = new SpecialistsServer;
49588
49480
  await server.start();
49589
49481
  }
49590
- run34().catch((error2) => {
49482
+ run33().catch((error2) => {
49591
49483
  logger.error(`Fatal error: ${error2}`);
49592
49484
  process.exit(1);
49593
49485
  });