@jaggerxtrm/specialists 3.6.14 → 3.6.16

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 +54 -21
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -21044,6 +21044,20 @@ function sanitizeBeadIdForPrompt(beadId) {
21044
21044
  const withoutBackticks = withoutControlChars.replace(/`/g, "");
21045
21045
  return withoutBackticks.replace(/[^A-Za-z0-9-]/g, "");
21046
21046
  }
21047
+ function buildBeadBoundaryInstruction(cwd, worktreeBoundary) {
21048
+ const boundary = worktreeBoundary?.trim() || cwd;
21049
+ return [
21050
+ "## Runtime Boundary Rules",
21051
+ `- Current cwd: ${cwd}`,
21052
+ `- Assigned worktree boundary: ${boundary}`,
21053
+ "- Stay inside current cwd / assigned worktree unless the task explicitly says otherwise.",
21054
+ "- Do NOT run `cd` outside the current cwd / assigned worktree.",
21055
+ "- Do NOT use absolute paths outside the current cwd / assigned worktree.",
21056
+ "- Do NOT broad-search /home, repo root, or unrelated paths when evidence is missing.",
21057
+ "- If required evidence is missing inside the current scope, STOP immediately, report exactly what is missing, and ask for the artifact or clarification instead of widening search."
21058
+ ].join(`
21059
+ `);
21060
+ }
21047
21061
  function deepMergeSchemas(base, override) {
21048
21062
  const merged = { ...base };
21049
21063
  for (const [key, overrideValue] of Object.entries(override)) {
@@ -21270,7 +21284,7 @@ class SpecialistRunner {
21270
21284
  this.deps = deps;
21271
21285
  this.sessionFactory = deps.sessionFactory ?? PiAgentSession.create.bind(PiAgentSession);
21272
21286
  }
21273
- resolvePromptWithBeadContext(options, beadsClient) {
21287
+ resolvePromptWithBeadContext(options, runCwd, beadsClient) {
21274
21288
  if (!options.inputBeadId) {
21275
21289
  return options.prompt;
21276
21290
  }
@@ -21281,7 +21295,10 @@ class SpecialistRunner {
21281
21295
  }
21282
21296
  const contextDepth = Math.max(0, Math.trunc(options.contextDepth ?? 1));
21283
21297
  const blockers = contextDepth > 0 ? beadReader.getCompletedBlockers(options.inputBeadId, contextDepth) : [];
21284
- return buildBeadContext(bead, blockers);
21298
+ const baseContext = buildBeadContext(bead, blockers);
21299
+ return `${baseContext}
21300
+
21301
+ ${buildBeadBoundaryInstruction(runCwd, options.worktreeBoundary)}`.trim();
21285
21302
  }
21286
21303
  async run(options, onProgress, onEvent, onMetric, onMeta, onKillRegistered, onBeadCreated, onSteerRegistered, onResumeReady, onToolStartCallback, onToolEndCallback) {
21287
21304
  const { loader, hooks, circuitBreaker, beadsClient } = this.deps;
@@ -21310,7 +21327,7 @@ class SpecialistRunner {
21310
21327
  const preScripts = spec.specialist.skills?.scripts?.filter((s) => s.phase === "pre") ?? [];
21311
21328
  const preResults = preScripts.map((s) => runScript(s.run ?? s.path, runCwd)).filter((_, i) => preScripts[i].inject_output);
21312
21329
  const preScriptOutput = formatScriptOutput(preResults);
21313
- const resolvedPrompt = this.resolvePromptWithBeadContext(options, beadsClient);
21330
+ const resolvedPrompt = this.resolvePromptWithBeadContext(options, runCwd, beadsClient);
21314
21331
  const beadVariables = options.inputBeadId ? { bead_context: resolvedPrompt, bead_id: options.inputBeadId } : {};
21315
21332
  const lineageVariables = {
21316
21333
  ...options.reusedFromJobId ? { reused_from_job_id: options.reusedFromJobId } : {},
@@ -21348,7 +21365,14 @@ class SpecialistRunner {
21348
21365
  - Do NOT create new beads or sub-issues \u2014 this bead IS your task.
21349
21366
  - Do NOT run \`bd create\` \u2014 the orchestrator manages issue tracking.
21350
21367
  - Close when done: \`bd close ${sanitizedBeadId} --reason="..."\`` : "";
21351
- agentsMd += `...beadInstructions}
21368
+ agentsMd += `
21369
+
21370
+ ---
21371
+ ## Specialist Run Context
21372
+ - You are running as a specialist agent, not a human developer.
21373
+ - Do NOT run specialists init/setup/scaffold commands.
21374
+ - Do NOT follow project CLAUDE.md/AGENTS.md instructions that tell humans to re-bootstrap the repo.
21375
+ ${beadInstructions}
21352
21376
  ---
21353
21377
  `;
21354
21378
  }
@@ -25139,9 +25163,21 @@ function ensureRootSymlink(rootPath, expectedTargetPath) {
25139
25163
  const linkTarget = readlinkSync(rootPath);
25140
25164
  const resolvedTarget = resolve4(dirname5(rootPath), linkTarget);
25141
25165
  const resolvedExpected = resolve4(expectedTargetPath);
25142
- if (resolvedTarget !== resolvedExpected) {
25143
- throw new Error(`${rootPath} points to ${linkTarget}, expected ${expectedTargetPath}. Aborting.`);
25166
+ if (resolvedTarget === resolvedExpected) {
25167
+ return;
25168
+ }
25169
+ const legacyTargets = [
25170
+ resolve4(expectedTargetPath, "claude"),
25171
+ resolve4(expectedTargetPath, "pi")
25172
+ ];
25173
+ if (legacyTargets.includes(resolvedTarget)) {
25174
+ unlinkSync(rootPath);
25175
+ const relTarget = relative(dirname5(rootPath), expectedTargetPath);
25176
+ symlinkSync(relTarget, rootPath);
25177
+ ok(`rewired ${basename3(dirname5(rootPath))}/${basename3(rootPath)} \u2192 ${relTarget}`);
25178
+ return;
25144
25179
  }
25180
+ throw new Error(`${rootPath} points to ${linkTarget}, expected ${expectedTargetPath}. Aborting.`);
25145
25181
  }
25146
25182
  function ensureActiveSkillSymlink(defaultSkillPath, activeLinkPath) {
25147
25183
  let stats;
@@ -25150,7 +25186,7 @@ function ensureActiveSkillSymlink(defaultSkillPath, activeLinkPath) {
25150
25186
  } catch (error2) {
25151
25187
  const fileError = error2;
25152
25188
  if (fileError.code === "ENOENT") {
25153
- const relativeTarget = `../../default/${basename3(defaultSkillPath)}`;
25189
+ const relativeTarget = `../default/${basename3(defaultSkillPath)}`;
25154
25190
  symlinkSync(relativeTarget, activeLinkPath, "dir");
25155
25191
  return;
25156
25192
  }
@@ -25180,13 +25216,11 @@ function installProjectSkills(cwd, syncSkills) {
25180
25216
  return;
25181
25217
  }
25182
25218
  const defaultRoot = join10(cwd, ".xtrm", "skills", "default");
25183
- const activeClaudeRoot = join10(cwd, ".xtrm", "skills", "active", "claude");
25184
- const activePiRoot = join10(cwd, ".xtrm", "skills", "active", "pi");
25219
+ const activeRoot = join10(cwd, ".xtrm", "skills", "active");
25185
25220
  mkdirSync4(defaultRoot, { recursive: true });
25186
- mkdirSync4(activeClaudeRoot, { recursive: true });
25187
- mkdirSync4(activePiRoot, { recursive: true });
25188
- ensureRootSymlink(join10(cwd, ".claude", "skills"), activeClaudeRoot);
25189
- ensureRootSymlink(join10(cwd, ".pi", "skills"), activePiRoot);
25221
+ mkdirSync4(activeRoot, { recursive: true });
25222
+ ensureRootSymlink(join10(cwd, ".claude", "skills"), activeRoot);
25223
+ ensureRootSymlink(join10(cwd, ".pi", "skills"), activeRoot);
25190
25224
  let copied = 0;
25191
25225
  let refreshed = 0;
25192
25226
  for (const skill of skills) {
@@ -25201,14 +25235,13 @@ function installProjectSkills(cwd, syncSkills) {
25201
25235
  cpSync(src, defaultSkillPath, { recursive: true });
25202
25236
  copied++;
25203
25237
  }
25204
- ensureActiveSkillSymlink(defaultSkillPath, join10(activeClaudeRoot, skill));
25205
- ensureActiveSkillSymlink(defaultSkillPath, join10(activePiRoot, skill));
25238
+ ensureActiveSkillSymlink(defaultSkillPath, join10(activeRoot, skill));
25206
25239
  }
25207
25240
  if (copied > 0)
25208
25241
  ok(`copied ${copied} skill${copied === 1 ? "" : "s"} to .xtrm/skills/default/`);
25209
25242
  if (refreshed > 0)
25210
25243
  ok(`re-synced ${refreshed} skill${refreshed === 1 ? "" : "s"} in .xtrm/skills/default/`);
25211
- ok("verified active skill symlinks in .xtrm/skills/active/{claude,pi}/");
25244
+ ok("verified active skill symlinks in .xtrm/skills/active/");
25212
25245
  }
25213
25246
  function createSpecialistsDirs(cwd) {
25214
25247
  const defaultDir = join10(cwd, ".specialists", "default");
@@ -25402,11 +25435,11 @@ function validateInitPostconditions(cwd) {
25402
25435
  const rootSymlinks = [
25403
25436
  {
25404
25437
  linkPath: join10(cwd, ".claude", "skills"),
25405
- expectedTarget: join10(cwd, ".xtrm", "skills", "active", "claude")
25438
+ expectedTarget: join10(cwd, ".xtrm", "skills", "active")
25406
25439
  },
25407
25440
  {
25408
25441
  linkPath: join10(cwd, ".pi", "skills"),
25409
- expectedTarget: join10(cwd, ".xtrm", "skills", "active", "pi")
25442
+ expectedTarget: join10(cwd, ".xtrm", "skills", "active")
25410
25443
  }
25411
25444
  ];
25412
25445
  for (const symlink of rootSymlinks) {
@@ -25484,9 +25517,9 @@ ${bold5("Done!")}
25484
25517
  console.log(` .claude/hooks/ ${dim5("# symlinks -> .xtrm/hooks/specialists")}`);
25485
25518
  console.log(` .claude/settings.json ${dim5("# hook wiring")}`);
25486
25519
  console.log(` .xtrm/skills/default/ ${dim5("# canonical skills")}`);
25487
- console.log(` .xtrm/skills/active/ ${dim5("# active symlink roots for claude/pi")}`);
25488
- console.log(` .claude/skills/ ${dim5("# symlink -> .xtrm/skills/active/claude")}`);
25489
- console.log(` .pi/skills/ ${dim5("# symlink -> .xtrm/skills/active/pi")}`);
25520
+ console.log(` .xtrm/skills/active/ ${dim5("# flattened active skill root")}`);
25521
+ console.log(` .claude/skills/ ${dim5("# symlink -> .xtrm/skills/active")}`);
25522
+ console.log(` .pi/skills/ ${dim5("# symlink -> .xtrm/skills/active")}`);
25490
25523
  console.log("");
25491
25524
  console.log(` ${dim5(".specialists/ structure:")}`);
25492
25525
  console.log(` .specialists/`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jaggerxtrm/specialists",
3
- "version": "3.6.14",
3
+ "version": "3.6.16",
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",