@jaggerxtrm/specialists 2.1.20 → 3.0.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.
- package/README.md +125 -122
- package/bin/install.js +33 -4
- package/dist/index.js +790 -84
- package/hooks/beads-close-memory-prompt.mjs +47 -0
- package/hooks/specialists-complete.mjs +60 -0
- package/package.json +1 -1
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// beads-close-memory-prompt — Claude Code PostToolUse hook
|
|
3
|
+
// After `bd close`: injects a short reminder into Claude's context to capture
|
|
4
|
+
// knowledge and consider underused beads features.
|
|
5
|
+
// Output to stdout is shown to Claude as additional context.
|
|
6
|
+
//
|
|
7
|
+
// Installed by: specialists install
|
|
8
|
+
|
|
9
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
10
|
+
import { join } from 'node:path';
|
|
11
|
+
|
|
12
|
+
let input;
|
|
13
|
+
try {
|
|
14
|
+
input = JSON.parse(readFileSync(0, 'utf8'));
|
|
15
|
+
} catch {
|
|
16
|
+
process.exit(0);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Only fire on Bash tool
|
|
20
|
+
if (input.tool_name !== 'Bash') process.exit(0);
|
|
21
|
+
|
|
22
|
+
const cmd = (input.tool_input?.command ?? '').trim();
|
|
23
|
+
|
|
24
|
+
// Only fire when the command is `bd close ...`
|
|
25
|
+
if (!/\bbd\s+close\b/.test(cmd)) process.exit(0);
|
|
26
|
+
|
|
27
|
+
// Only fire in projects that use beads
|
|
28
|
+
const cwd = input.cwd ?? process.env.CLAUDE_PROJECT_DIR ?? process.cwd();
|
|
29
|
+
if (!existsSync(join(cwd, '.beads'))) process.exit(0);
|
|
30
|
+
|
|
31
|
+
// Inject reminder into Claude's context
|
|
32
|
+
process.stdout.write(
|
|
33
|
+
'\n[beads] Issue(s) closed. Before moving on:\n\n' +
|
|
34
|
+
' Knowledge worth keeping?\n' +
|
|
35
|
+
' bd remember "key insight from this work"\n' +
|
|
36
|
+
' bd memories <keyword> -- search what is already stored\n\n' +
|
|
37
|
+
' Discovered related work while implementing?\n' +
|
|
38
|
+
' bd create --title="..." --deps=discovered-from:<id>\n\n' +
|
|
39
|
+
' Underused features to consider:\n' +
|
|
40
|
+
' bd dep add <a> <b> -- link blocking relationships between issues\n' +
|
|
41
|
+
' bd graph -- visualize issue dependency graph\n' +
|
|
42
|
+
' bd orphans -- issues referenced in commits but still open\n' +
|
|
43
|
+
' bd preflight -- PR readiness checklist before gh pr create\n' +
|
|
44
|
+
' bd stale -- issues not touched recently\n'
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
process.exit(0);
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// specialists-complete — Claude Code UserPromptSubmit hook
|
|
3
|
+
// Checks .specialists/ready/ for completed background job markers and injects
|
|
4
|
+
// completion banners into Claude's context.
|
|
5
|
+
//
|
|
6
|
+
// Installed by: specialists install
|
|
7
|
+
|
|
8
|
+
import { existsSync, readdirSync, readFileSync, unlinkSync } from 'node:fs';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
|
|
11
|
+
const cwd = process.env.CLAUDE_PROJECT_DIR ?? process.cwd();
|
|
12
|
+
const readyDir = join(cwd, '.specialists', 'ready');
|
|
13
|
+
|
|
14
|
+
// Exit silently if no ready dir or nothing to report
|
|
15
|
+
if (!existsSync(readyDir)) process.exit(0);
|
|
16
|
+
|
|
17
|
+
let markers;
|
|
18
|
+
try {
|
|
19
|
+
markers = readdirSync(readyDir).filter(f => !f.startsWith('.'));
|
|
20
|
+
} catch {
|
|
21
|
+
process.exit(0);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (markers.length === 0) process.exit(0);
|
|
25
|
+
|
|
26
|
+
const banners = [];
|
|
27
|
+
|
|
28
|
+
for (const jobId of markers) {
|
|
29
|
+
const markerPath = join(readyDir, jobId);
|
|
30
|
+
const statusPath = join(cwd, '.specialists', 'jobs', jobId, 'status.json');
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
let specialist = jobId;
|
|
34
|
+
let elapsed = '';
|
|
35
|
+
|
|
36
|
+
if (existsSync(statusPath)) {
|
|
37
|
+
const status = JSON.parse(readFileSync(statusPath, 'utf-8'));
|
|
38
|
+
specialist = status.specialist ?? jobId;
|
|
39
|
+
elapsed = status.elapsed_s !== undefined ? `, ${status.elapsed_s}s` : '';
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
banners.push(
|
|
43
|
+
`[Specialist '${specialist}' completed (job ${jobId}${elapsed}). Run: specialists result ${jobId}]`
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
// Delete marker so it only fires once
|
|
47
|
+
unlinkSync(markerPath);
|
|
48
|
+
} catch {
|
|
49
|
+
// Ignore malformed entries
|
|
50
|
+
try { unlinkSync(markerPath); } catch { /* ignore */ }
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (banners.length === 0) process.exit(0);
|
|
55
|
+
|
|
56
|
+
// UserPromptSubmit hooks inject content via JSON
|
|
57
|
+
process.stdout.write(JSON.stringify({
|
|
58
|
+
type: 'inject',
|
|
59
|
+
content: banners.join('\n'),
|
|
60
|
+
}) + '\n');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jaggerxtrm/specialists",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
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",
|