@jaggerxtrm/specialists 3.3.4 → 3.4.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 (39) hide show
  1. package/README.md +4 -2
  2. package/bin/install.js +15 -204
  3. package/config/hooks/specialists-session-start.mjs +3 -3
  4. package/config/skills/specialists-creator/SKILL.md +22 -1
  5. package/config/skills/using-specialists/SKILL.md +261 -50
  6. package/config/specialists/debugger.specialist.yaml +121 -0
  7. package/config/specialists/executor.specialist.yaml +257 -0
  8. package/config/specialists/explorer.specialist.yaml +13 -7
  9. package/config/specialists/memory-processor.specialist.yaml +15 -1
  10. package/config/specialists/overthinker.specialist.yaml +16 -3
  11. package/config/specialists/{parallel-runner.specialist.yaml → parallel-review.specialist.yaml} +15 -1
  12. package/config/specialists/planner.specialist.yaml +31 -24
  13. package/config/specialists/reviewer.specialist.yaml +142 -0
  14. package/config/specialists/specialists-creator.specialist.yaml +10 -2
  15. package/config/specialists/sync-docs.specialist.yaml +20 -5
  16. package/config/specialists/test-runner.specialist.yaml +8 -1
  17. package/config/specialists/xt-merge.specialist.yaml +97 -16
  18. package/dist/index.js +2775 -1120
  19. package/package.json +1 -1
  20. package/config/skills/specialists-usage-workspace/iteration-1/eval-bead-background/old_skill/outputs/result.md +0 -105
  21. package/config/skills/specialists-usage-workspace/iteration-1/eval-bead-background/with_skill/outputs/result.md +0 -93
  22. package/config/skills/specialists-usage-workspace/iteration-1/eval-fresh-setup/old_skill/outputs/result.md +0 -113
  23. package/config/skills/specialists-usage-workspace/iteration-1/eval-fresh-setup/with_skill/outputs/result.md +0 -131
  24. package/config/skills/specialists-usage-workspace/iteration-1/eval-yaml-debug/old_skill/outputs/result.md +0 -159
  25. package/config/skills/specialists-usage-workspace/iteration-1/eval-yaml-debug/with_skill/outputs/result.md +0 -150
  26. package/config/skills/specialists-usage-workspace/iteration-2/eval-bug-investigation/with_skill/outputs/result.md +0 -180
  27. package/config/skills/specialists-usage-workspace/iteration-2/eval-bug-investigation/with_skill/timing.json +0 -5
  28. package/config/skills/specialists-usage-workspace/iteration-2/eval-bug-investigation/without_skill/outputs/result.md +0 -223
  29. package/config/skills/specialists-usage-workspace/iteration-2/eval-bug-investigation/without_skill/timing.json +0 -5
  30. package/config/skills/specialists-usage-workspace/iteration-2/eval-code-review/with_skill/timing.json +0 -5
  31. package/config/skills/specialists-usage-workspace/iteration-2/eval-code-review/without_skill/outputs/result.md +0 -146
  32. package/config/skills/specialists-usage-workspace/iteration-2/eval-code-review/without_skill/timing.json +0 -5
  33. package/config/skills/specialists-usage-workspace/iteration-2/eval-test-coverage/with_skill/outputs/result.md +0 -89
  34. package/config/skills/specialists-usage-workspace/iteration-2/eval-test-coverage/with_skill/timing.json +0 -5
  35. package/config/skills/specialists-usage-workspace/iteration-2/eval-test-coverage/without_skill/outputs/result.md +0 -96
  36. package/config/skills/specialists-usage-workspace/iteration-2/eval-test-coverage/without_skill/timing.json +0 -5
  37. package/config/skills/specialists-usage-workspace/skill-snapshot/SKILL.md.old +0 -237
  38. package/config/specialists/auto-remediation.specialist.yaml +0 -70
  39. package/config/specialists/bug-hunt.specialist.yaml +0 -96
package/README.md CHANGED
@@ -28,18 +28,20 @@ specialists list
28
28
 
29
29
  ```bash
30
30
  sp list
31
- sp run bug-hunt --bead <id> --background
31
+ sp run bug-hunt --bead <id>
32
32
  ```
33
33
 
34
34
  Tracked work:
35
35
 
36
36
  ```bash
37
37
  bd create "Investigate auth bug" -t bug -p 1 --json
38
- specialists run bug-hunt --bead <id> --background
38
+ specialists run bug-hunt --bead <id>
39
39
  specialists feed -f
40
40
  bd close <id> --reason "Done"
41
41
  ```
42
42
 
43
+ `specialists run` prints `[job started: <id>]` early and also writes the id to `.specialists/jobs/latest`.
44
+
43
45
  Ad-hoc work:
44
46
 
45
47
  ```bash
package/bin/install.js CHANGED
@@ -1,209 +1,20 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { spawnSync } from 'node:child_process';
4
- import {
5
- chmodSync,
6
- copyFileSync,
7
- existsSync,
8
- mkdirSync,
9
- readdirSync,
10
- readFileSync,
11
- writeFileSync,
12
- } from 'node:fs';
13
- import { homedir } from 'node:os';
14
- import { join } from 'node:path';
3
+ // DEPRECATED: This script is deprecated. Use `specialists init` instead.
15
4
 
16
- const CWD = process.cwd();
17
- const CLAUDE_DIR = join(CWD, '.claude');
18
- const HOOKS_DIR = join(CLAUDE_DIR, 'hooks');
19
- const SETTINGS_FILE = join(CLAUDE_DIR, 'settings.json');
20
- const MCP_FILE = join(CWD, '.mcp.json');
21
- const BUNDLED_HOOKS_DIR = new URL('../hooks', import.meta.url).pathname;
22
- const BUNDLED_SPECIALISTS_DIR = new URL('../specialists', import.meta.url).pathname;
23
- const USER_SPECIALISTS_DIR = join(homedir(), '.agents', 'specialists');
24
-
25
- const dim = (s) => `\x1b[2m${s}\x1b[0m`;
26
- const green = (s) => `\x1b[32m${s}\x1b[0m`;
27
- const yellow = (s) => `\x1b[33m${s}\x1b[0m`;
28
5
  const bold = (s) => `\x1b[1m${s}\x1b[0m`;
29
- const red = (s) => `\x1b[31m${s}\x1b[0m`;
30
-
31
- function section(label) {
32
- const line = '─'.repeat(Math.max(0, 44 - label.length));
33
- console.log(`\n${bold(`── ${label} ${line}`)}`);
34
- }
35
-
36
- function ok(label) { console.log(` ${green('✓')} ${label}`); }
37
- function skip(label) { console.log(` ${yellow('○')} ${label}`); }
38
- function info(label) { console.log(` ${dim(label)}`); }
39
- function fail(label) { console.log(` ${red('✗')} ${label}`); }
40
-
41
- function run(cmd, args, options = {}) {
42
- return spawnSync(cmd, args, {
43
- encoding: 'utf8',
44
- stdio: 'pipe',
45
- ...options,
46
- });
47
- }
48
-
49
- function commandOk(cmd, args = ['--version']) {
50
- const result = run(cmd, args);
51
- return result.status === 0 && !result.error;
52
- }
53
-
54
- function loadJson(path, fallback) {
55
- if (!existsSync(path)) return structuredClone(fallback);
56
- try {
57
- return JSON.parse(readFileSync(path, 'utf8'));
58
- } catch {
59
- return structuredClone(fallback);
60
- }
61
- }
62
-
63
- function saveJson(path, value) {
64
- writeFileSync(path, JSON.stringify(value, null, 2) + '\n', 'utf8');
65
- }
66
-
67
- function sameFileContent(a, b) {
68
- if (!existsSync(a) || !existsSync(b)) return false;
69
- return readFileSync(a, 'utf8') === readFileSync(b, 'utf8');
70
- }
71
-
72
- const HOOKS = [
73
- {
74
- event: 'UserPromptSubmit',
75
- file: 'specialists-complete.mjs',
76
- timeout: 5000,
77
- },
78
- {
79
- event: 'SessionStart',
80
- file: 'specialists-session-start.mjs',
81
- timeout: 8000,
82
- },
83
- ];
84
-
85
- function findHookCommands(settings, event, fileName) {
86
- const entries = settings?.hooks?.[event];
87
- if (!Array.isArray(entries)) return [];
88
- return entries.flatMap((entry) =>
89
- (entry.hooks ?? [])
90
- .map((hook) => hook.command)
91
- .filter((command) => typeof command === 'string' && command.includes(fileName)),
92
- );
93
- }
94
-
95
- function ensureHook(settings, hook) {
96
- const dest = join(HOOKS_DIR, hook.file);
97
- const source = join(BUNDLED_HOOKS_DIR, hook.file);
98
- const existingCommands = findHookCommands(settings, hook.event, hook.file);
99
- const externalOwner = existingCommands.find((command) => command !== dest);
100
-
101
- if (externalOwner) {
102
- skip(`${hook.file} already managed externally — deferring`);
103
- info(`existing command: ${externalOwner}`);
104
- return false;
105
- }
106
-
107
- mkdirSync(HOOKS_DIR, { recursive: true });
108
- const changed = !sameFileContent(source, dest);
109
- if (changed) {
110
- copyFileSync(source, dest);
111
- chmodSync(dest, 0o755);
112
- ok(`${hook.file} installed in .claude/hooks/`);
113
- } else {
114
- skip(`${hook.file} already up to date`);
115
- }
116
-
117
- settings.hooks ??= {};
118
- settings.hooks[hook.event] ??= [];
119
- settings.hooks[hook.event] = settings.hooks[hook.event].filter(
120
- (entry) => !(entry.hooks ?? []).some((h) => h.command === dest),
121
- );
122
- settings.hooks[hook.event].push({
123
- hooks: [{ type: 'command', command: dest, timeout: hook.timeout }],
124
- });
125
- ok(`${hook.file} registered for ${hook.event}`);
126
- return true;
127
- }
128
-
129
- function installBundledSpecialists() {
130
- if (!existsSync(BUNDLED_SPECIALISTS_DIR)) {
131
- skip('bundled specialists dir not found — skipping');
132
- return;
133
- }
134
- mkdirSync(USER_SPECIALISTS_DIR, { recursive: true });
135
- const files = readdirSync(BUNDLED_SPECIALISTS_DIR).filter(f => f.endsWith('.specialist.yaml'));
136
- for (const file of files) {
137
- const source = join(BUNDLED_SPECIALISTS_DIR, file);
138
- const dest = join(USER_SPECIALISTS_DIR, file);
139
- if (sameFileContent(source, dest)) {
140
- skip(`${file} already up to date`);
141
- } else {
142
- copyFileSync(source, dest);
143
- ok(`${file} installed in ~/.agents/specialists/`);
144
- }
145
- }
146
- }
147
-
148
- function ensureMcpRegistration() {
149
- const mcp = loadJson(MCP_FILE, { mcpServers: {} });
150
- mcp.mcpServers ??= {};
151
- const existing = mcp.mcpServers.specialists;
152
- const desired = { command: 'specialists', args: [] };
153
-
154
- if (
155
- existing &&
156
- existing.command === desired.command &&
157
- Array.isArray(existing.args) &&
158
- existing.args.length === 0
159
- ) {
160
- skip('.mcp.json already registers specialists');
161
- return;
162
- }
163
-
164
- mcp.mcpServers.specialists = desired;
165
- saveJson(MCP_FILE, mcp);
166
- ok('registered specialists in .mcp.json');
167
- }
168
-
169
- console.log(`\n${bold('Specialists installer')}`);
170
- console.log(dim('Project scope: prerequisite check, bundled specialists, hooks, MCP registration'));
171
-
172
- section('Prerequisite check');
173
- const prereqs = [
174
- { name: 'pi', ok: commandOk('pi', ['--version']), required: true, help: 'Install pi first.' },
175
- { name: 'bd', ok: commandOk('bd', ['--version']), required: true, help: 'Install beads (bd) first.' },
176
- { name: 'xt', ok: commandOk('xt', ['--version']), required: true, help: 'xtrm-tools is required for hooks and workflow integration.' },
177
- ];
178
-
179
- let prereqFailed = false;
180
- for (const prereq of prereqs) {
181
- if (prereq.ok) {
182
- ok(`${prereq.name} available`);
183
- } else {
184
- prereqFailed = prereqFailed || prereq.required;
185
- fail(`${prereq.name} not found`);
186
- info(prereq.help);
187
- }
188
- }
189
-
190
- if (prereqFailed) {
191
- console.log(`\n${red('Install aborted: required prerequisites are missing.')}`);
192
- process.exit(1);
193
- }
194
-
195
- section('Specialists hooks');
196
- mkdirSync(CLAUDE_DIR, { recursive: true });
197
- const settings = loadJson(SETTINGS_FILE, {});
198
- for (const hook of HOOKS) ensureHook(settings, hook);
199
- saveJson(SETTINGS_FILE, settings);
200
- ok(`updated ${SETTINGS_FILE}`);
201
-
202
- section('Bundled specialists');
203
- installBundledSpecialists();
204
-
205
- section('MCP registration');
206
- ensureMcpRegistration();
6
+ const yellow = (s) => `\x1b[33m${s}\x1b[0m`;
7
+ const dim = (s) => `\x1b[2m${s}\x1b[0m`;
207
8
 
208
- console.log(`\n${bold(green('Done!'))}`);
209
- console.log(` ${dim('Hooks are project-local in .claude/, and MCP is project-local in .mcp.json.')}`);
9
+ console.log('');
10
+ console.log(yellow(' DEPRECATED: `bin/install.js` is deprecated'));
11
+ console.log('');
12
+ console.log(` Use ${bold('specialists init')} instead.`);
13
+ console.log('');
14
+ console.log(' The init command handles all setup tasks:');
15
+ console.log(' • creates specialists/ and .specialists/ directories');
16
+ console.log(' • registers the MCP server in .mcp.json');
17
+ console.log(' • injects workflow context into AGENTS.md/CLAUDE.md');
18
+ console.log('');
19
+ console.log(` ${dim('Run: specialists init --help for full details')}`);
20
+ console.log('');
@@ -99,15 +99,15 @@ lines.push('');
99
99
  lines.push('```');
100
100
  lines.push('specialists list # discover available specialists');
101
101
  lines.push('specialists run <name> --prompt "..." # run foreground (streams output)');
102
- lines.push('specialists run <name> --prompt "..." --background # run async returns job ID');
103
- lines.push('specialists run <name> --follow # background + stream live output');
102
+ lines.push('process start "specialists run <name> --prompt "..."" name="sp-<name>" # async via process extension');
103
+ lines.push('specialists run <name> --prompt "..." # foreground stream');
104
104
  lines.push('specialists feed <job-id> --follow # tail live events');
105
105
  lines.push('specialists result <job-id> # read final output');
106
106
  lines.push('specialists status # system health');
107
107
  lines.push('specialists doctor # troubleshoot issues');
108
108
  lines.push('```');
109
109
  lines.push('');
110
- lines.push('MCP tools: specialist_init · use_specialist · start_specialist · poll_specialist · run_parallel');
110
+ lines.push('MCP tools: specialist_init · use_specialist · start_specialist · feed_specialist · run_parallel');
111
111
 
112
112
  // ── Output ─────────────────────────────────────────────────────────────────
113
113
  if (lines.length === 0) process.exit(0);
@@ -1,3 +1,13 @@
1
+ ---
2
+ name: specialists-creator
3
+ description: >
4
+ Use this skill when creating or fixing a specialist definition. It guides the
5
+ agent through writing a valid `.specialist.yaml`, choosing supported models,
6
+ validating against the schema, and avoiding common specialist authoring
7
+ mistakes.
8
+ version: 1.0
9
+ ---
10
+
1
11
  # Specialist Author Guide
2
12
 
3
13
  > Source of truth: `src/specialist/schema.ts` | Runtime: `src/specialist/runner.ts`
@@ -73,7 +83,7 @@ Read both outputs carefully:
73
83
  |------|-----------------------|------------------------|
74
84
  | **Heavy** — deep reasoning, multi-phase, architecture | `overthinker`, `feature-design`, `bug-hunt`, `planner`, `parallel-review` | Opus / Pro / GLM-5 |
75
85
  | **Standard** — code generation, review, authoring, docs | `codebase-explorer`, `specialist-author`, `sync-docs`, `xt-merge` | Sonnet / Flash-Pro |
76
- | **Light** — fast context, reporting, test runs | `init-session`, `report-generator`, `test-runner`, `auto-remediation` | Haiku / Flash |
86
+ | **Light** — fast context, reporting, test runs | `init-session`, `report-generator`, `test-runner` | Haiku / Flash |
77
87
 
78
88
  Adjust tiers based on what the user actually has installed. Custom specialists: read their `description` and `permission_required` to infer tier.
79
89
 
@@ -202,10 +212,20 @@ bun skills/specialist-author/scripts/validate-specialist.ts specialists/my-speci
202
212
  | `mode` | enum | `auto` | `tool` \| `skill` \| `auto` |
203
213
  | `timeout_ms` | number | `120000` | ms |
204
214
  | `stall_timeout_ms` | number | — | kill if no event for N ms |
215
+ | `interactive` | boolean | `false` | enable multi-turn keep-alive by default |
205
216
  | `response_format` | enum | `text` | `text` \| `json` \| `markdown` |
206
217
  | `permission_required` | enum | `READ_ONLY` | see tier table below |
207
218
  | `thinking_level` | enum | — | `off` \| `minimal` \| `low` \| `medium` \| `high` \| `xhigh` |
208
219
 
220
+ **When to use `execution.interactive`**
221
+
222
+ - Set `interactive: true` for specialists intended for multi-turn workflows (`resume`, iterative planning, long investigations).
223
+ - Leave it unset/`false` for one-shot specialists where each run should end immediately.
224
+ - Run-level overrides still apply:
225
+ - CLI: `--keep-alive` enables, `--no-keep-alive` disables.
226
+ - MCP `start_specialist`: `keep_alive` enables, `no_keep_alive` disables.
227
+ - Effective precedence: explicit disable (`--no-keep-alive` / `no_keep_alive`) → explicit enable (`--keep-alive` / `keep_alive`) → `execution.interactive` → one-shot default.
228
+
209
229
  **Permission tiers** — controls which pi tools are available:
210
230
 
211
231
  | Level | pi --tools | Use when |
@@ -410,6 +430,7 @@ specialist:
410
430
  fallback_model: google-gemini-cli/gemini-3.1-pro-preview
411
431
  timeout_ms: 300000
412
432
  stall_timeout_ms: 60000
433
+ interactive: true # default keep-alive; supports resume flows
413
434
  response_format: markdown
414
435
  permission_required: READ_ONLY # not READ_WRITE
415
436