@jaggerxtrm/specialists 2.1.15 → 2.1.17
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/bin/install.js
CHANGED
|
@@ -122,6 +122,36 @@ const BEADS_STOP_GATE_ENTRY = {
|
|
|
122
122
|
hooks: [{ type: 'command', command: BEADS_STOP_GATE_FILE, timeout: 10000 }],
|
|
123
123
|
};
|
|
124
124
|
|
|
125
|
+
function promptYN(question) {
|
|
126
|
+
if (!process.stdin.isTTY) return true; // non-interactive: default yes
|
|
127
|
+
process.stdout.write(`${question} [Y/n]: `);
|
|
128
|
+
const r = spawnSync('/bin/sh', ['-c', 'read ans; printf "%s" "$ans"'], {
|
|
129
|
+
stdio: ['inherit', 'pipe', 'inherit'],
|
|
130
|
+
encoding: 'utf8',
|
|
131
|
+
});
|
|
132
|
+
const ans = (r.stdout ?? '').trim().toLowerCase();
|
|
133
|
+
return ans === '' || ans === 'y' || ans === 'yes';
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function getHookDrift() {
|
|
137
|
+
const pairs = [
|
|
138
|
+
['specialists-main-guard.mjs', HOOK_FILE],
|
|
139
|
+
['beads-edit-gate.mjs', BEADS_EDIT_GATE_FILE],
|
|
140
|
+
['beads-commit-gate.mjs', BEADS_COMMIT_GATE_FILE],
|
|
141
|
+
['beads-stop-gate.mjs', BEADS_STOP_GATE_FILE],
|
|
142
|
+
];
|
|
143
|
+
return pairs
|
|
144
|
+
.map(([bundled, dest]) => ({
|
|
145
|
+
name: bundled,
|
|
146
|
+
dest,
|
|
147
|
+
missing: !existsSync(dest),
|
|
148
|
+
changed: existsSync(dest) &&
|
|
149
|
+
readFileSync(join(BUNDLED_HOOKS_DIR, bundled), 'utf8') !==
|
|
150
|
+
readFileSync(dest, 'utf8'),
|
|
151
|
+
}))
|
|
152
|
+
.filter(h => h.missing || h.changed);
|
|
153
|
+
}
|
|
154
|
+
|
|
125
155
|
function installHook() {
|
|
126
156
|
mkdirSync(HOOKS_DIR, { recursive: true });
|
|
127
157
|
|
|
@@ -231,11 +261,27 @@ info('Edit any .specialist.yaml in ~/.agents/specialists/ to customise models, p
|
|
|
231
261
|
|
|
232
262
|
// 6. Claude Code hooks
|
|
233
263
|
section('Claude Code hooks');
|
|
234
|
-
const
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
264
|
+
const drift = getHookDrift();
|
|
265
|
+
const hooksExist = existsSync(HOOK_FILE);
|
|
266
|
+
|
|
267
|
+
if (!hooksExist) {
|
|
268
|
+
installHook();
|
|
269
|
+
ok('hooks installed → ~/.claude/hooks/');
|
|
270
|
+
} else if (drift.length === 0) {
|
|
271
|
+
skip('hooks up to date');
|
|
272
|
+
} else {
|
|
273
|
+
const label = (h) => h.missing ? red('missing') : yellow('updated');
|
|
274
|
+
console.log(` ${yellow('○')} ${drift.length} of 4 hook(s) have changes:`);
|
|
275
|
+
for (const h of drift) info(` ${h.name} ${label(h)}`);
|
|
276
|
+
console.log();
|
|
277
|
+
const confirmed = promptYN(' Update hooks?');
|
|
278
|
+
if (confirmed) {
|
|
279
|
+
installHook();
|
|
280
|
+
ok('hooks updated');
|
|
281
|
+
} else {
|
|
282
|
+
skip('hooks update skipped');
|
|
283
|
+
}
|
|
284
|
+
}
|
|
239
285
|
info('main-guard: blocks file edits and direct master pushes (enforces PR workflow)');
|
|
240
286
|
info('beads-edit-gate: requires in_progress bead before editing files');
|
|
241
287
|
info('beads-commit-gate: requires issues closed before git commit');
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// Forces: close issues first, THEN commit.
|
|
5
5
|
// Exit 0: allow | Exit 2: block (stderr shown to Claude)
|
|
6
6
|
//
|
|
7
|
-
// Installed by:
|
|
7
|
+
// Installed by: specialists install
|
|
8
8
|
|
|
9
9
|
import { execSync } from 'node:child_process';
|
|
10
10
|
import { readFileSync, existsSync } from 'node:fs';
|
|
@@ -43,11 +43,14 @@ try {
|
|
|
43
43
|
|
|
44
44
|
if (inProgress > 0) {
|
|
45
45
|
process.stderr.write(
|
|
46
|
-
'
|
|
47
|
-
|
|
48
|
-
'
|
|
49
|
-
'
|
|
50
|
-
|
|
46
|
+
'🚫 BEADS GATE: Close open issues before committing.\n\n' +
|
|
47
|
+
`Open issues:\n${summary}\n\n` +
|
|
48
|
+
'Next steps:\n' +
|
|
49
|
+
' 3. bd close <id1> <id2> ... ← you are here\n' +
|
|
50
|
+
' 4. git add <files> && git commit -m "..."\n' +
|
|
51
|
+
' 5. git push -u origin <feature-branch>\n' +
|
|
52
|
+
' 6. gh pr create --fill && gh pr merge --squash\n' +
|
|
53
|
+
' 7. git checkout master && git reset --hard origin/master\n'
|
|
51
54
|
);
|
|
52
55
|
process.exit(2);
|
|
53
56
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// Only active in projects with a .beads/ directory.
|
|
5
5
|
// Exit 0: allow | Exit 2: block (stderr shown to Claude)
|
|
6
6
|
//
|
|
7
|
-
// Installed by:
|
|
7
|
+
// Installed by: specialists install
|
|
8
8
|
|
|
9
9
|
import { execSync } from 'node:child_process';
|
|
10
10
|
import { readFileSync, existsSync } from 'node:fs';
|
|
@@ -35,11 +35,17 @@ try {
|
|
|
35
35
|
|
|
36
36
|
if (inProgress === 0) {
|
|
37
37
|
process.stderr.write(
|
|
38
|
-
'
|
|
39
|
-
'
|
|
40
|
-
' bd create --title="<task summary>" --type=task --priority=2\n' +
|
|
38
|
+
'🚫 BEADS GATE: No active issue — create one before editing files.\n\n' +
|
|
39
|
+
' bd create --title="<what you\'re doing>" --type=task --priority=2\n' +
|
|
41
40
|
' bd update <id> --status=in_progress\n\n' +
|
|
42
|
-
'
|
|
41
|
+
'Full workflow (do this every session):\n' +
|
|
42
|
+
' 1. bd create + bd update in_progress ← you are here\n' +
|
|
43
|
+
' 2. Edit files / write code\n' +
|
|
44
|
+
' 3. bd close <id> close when done\n' +
|
|
45
|
+
' 4. git add <files> && git commit\n' +
|
|
46
|
+
' 5. git push -u origin <feature-branch>\n' +
|
|
47
|
+
' 6. gh pr create --fill && gh pr merge --squash\n' +
|
|
48
|
+
' 7. git checkout master && git reset --hard origin/master\n'
|
|
43
49
|
);
|
|
44
50
|
process.exit(2);
|
|
45
51
|
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// beads-stop-gate — Claude Code Stop hook
|
|
3
3
|
// Blocks the agent from stopping when in_progress beads issues remain.
|
|
4
|
-
// Forces the session close protocol before declaring done.
|
|
5
4
|
// Exit 0: allow stop | Exit 2: block stop (stderr shown to Claude)
|
|
6
5
|
//
|
|
7
|
-
// Installed by:
|
|
6
|
+
// Installed by: specialists install
|
|
8
7
|
|
|
9
8
|
import { execSync } from 'node:child_process';
|
|
10
9
|
import { readFileSync, existsSync } from 'node:fs';
|
|
@@ -37,12 +36,15 @@ try {
|
|
|
37
36
|
|
|
38
37
|
if (inProgress > 0) {
|
|
39
38
|
process.stderr.write(
|
|
40
|
-
'
|
|
41
|
-
|
|
42
|
-
'
|
|
43
|
-
'
|
|
44
|
-
' git
|
|
45
|
-
|
|
39
|
+
'🚫 BEADS STOP GATE: Unresolved issues — complete the session close protocol.\n\n' +
|
|
40
|
+
`Open issues:\n${summary}\n\n` +
|
|
41
|
+
'Session close protocol:\n' +
|
|
42
|
+
' 3. bd close <id1> <id2> ... close all in_progress issues\n' +
|
|
43
|
+
' 4. git add <files> && git commit -m "..." commit your changes\n' +
|
|
44
|
+
' 5. git push -u origin <feature-branch> push feature branch\n' +
|
|
45
|
+
' 6. gh pr create --fill create PR\n' +
|
|
46
|
+
' 7. gh pr merge --squash merge PR\n' +
|
|
47
|
+
' 8. git checkout master && git reset --hard origin/master\n'
|
|
46
48
|
);
|
|
47
49
|
process.exit(2);
|
|
48
50
|
}
|
|
@@ -28,14 +28,21 @@ try {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
const tool = input.tool_name ?? '';
|
|
31
|
-
const blockMsg =
|
|
32
|
-
`⛔ Direct edits on '${branch}' are not allowed.\n` +
|
|
33
|
-
`Create a feature branch first: git checkout -b feature/<name>`;
|
|
34
31
|
|
|
35
32
|
const WRITE_TOOLS = new Set(['Edit', 'Write', 'MultiEdit', 'NotebookEdit']);
|
|
36
33
|
|
|
37
34
|
if (WRITE_TOOLS.has(tool)) {
|
|
38
|
-
process.stderr.write(
|
|
35
|
+
process.stderr.write(
|
|
36
|
+
`⛔ You are on '${branch}' — never edit files directly on master.\n\n` +
|
|
37
|
+
'Full workflow:\n' +
|
|
38
|
+
' 1. git checkout -b feature/<name> ← start here\n' +
|
|
39
|
+
' 2. bd create + bd update in_progress track your work\n' +
|
|
40
|
+
' 3. Edit files / write code\n' +
|
|
41
|
+
' 4. bd close <id> && git add && git commit\n' +
|
|
42
|
+
' 5. git push -u origin feature/<name>\n' +
|
|
43
|
+
' 6. gh pr create --fill && gh pr merge --squash\n' +
|
|
44
|
+
' 7. git checkout master && git reset --hard origin/master\n'
|
|
45
|
+
);
|
|
39
46
|
process.exit(2);
|
|
40
47
|
}
|
|
41
48
|
|
|
@@ -49,11 +56,15 @@ if (tool === 'Bash') {
|
|
|
49
56
|
const impliedMaster = tokens.length <= 3 && (branch === 'main' || branch === 'master');
|
|
50
57
|
if (explicitMaster || impliedMaster) {
|
|
51
58
|
process.stderr.write(
|
|
52
|
-
`⛔
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
59
|
+
`⛔ Don't push directly to '${branch}' — use the PR workflow.\n\n` +
|
|
60
|
+
'Next steps:\n' +
|
|
61
|
+
' 5. git push -u origin <feature-branch> ← push your branch\n' +
|
|
62
|
+
' 6. gh pr create --fill create PR\n' +
|
|
63
|
+
' gh pr merge --squash merge it\n' +
|
|
64
|
+
' 7. git checkout master sync master\n' +
|
|
65
|
+
' git reset --hard origin/master\n\n' +
|
|
66
|
+
'If you\'re not on a feature branch yet:\n' +
|
|
67
|
+
' git checkout -b feature/<name> (then re-commit and push)\n'
|
|
57
68
|
);
|
|
58
69
|
process.exit(2);
|
|
59
70
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jaggerxtrm/specialists",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.17",
|
|
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",
|