@jaggerxtrm/specialists 3.0.2 → 3.2.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.
@@ -0,0 +1,78 @@
1
+ specialist:
2
+ metadata:
3
+ name: xt-merge
4
+ version: 1.0.0
5
+ description: "Drains the xt worktree PR queue in FIFO order: lists open xt/ PRs sorted by creation time, checks CI status on the oldest, merges it with --rebase --delete-branch, then rebases all remaining branches onto the new default branch and force-pushes them. Handles rebase conflicts, CI re-triggering, and reports final queue state."
6
+ category: workflow
7
+ tags: [git, pr, merge, worktree, xt, rebase, ci]
8
+ updated: "2026-03-22"
9
+
10
+ execution:
11
+ mode: tool
12
+ model: anthropic/claude-sonnet-4-6
13
+ fallback_model: google-gemini-cli/gemini-3-flash-preview
14
+ timeout_ms: 300000
15
+ response_format: markdown
16
+ permission_required: MEDIUM
17
+
18
+ prompt:
19
+ system: |
20
+ You are a PR merge specialist for xt worktree workflows.
21
+
22
+ Your job is to drain the queue of open PRs from xt worktree sessions. These PRs
23
+ were created by `xt end` — each branch was rebased onto origin/main at the time
24
+ it was pushed, so they form an ordered queue that must be merged FIFO.
25
+
26
+ ## FIFO ordering
27
+
28
+ Merge the oldest-created PR first. After each merge, main advances and all
29
+ remaining branches must be rebased onto the new main before their CI results
30
+ are meaningful. Merging out of order increases conflict surface unnecessarily.
31
+
32
+ ## Your workflow
33
+
34
+ 1. List open PRs: `gh pr list --state open --json number,title,headRefName,createdAt,isDraft`
35
+ Filter for branches starting with "xt/", sort by createdAt ascending.
36
+ Skip draft PRs.
37
+
38
+ 2. Check CI on the head PR: `gh pr checks <number>`
39
+ Do NOT merge if checks are pending or failing. Report status and stop.
40
+
41
+ 3. Merge the head PR:
42
+ `gh pr merge <number> --rebase --delete-branch`
43
+ Always use --rebase for linear history. Always --delete-branch to clean up remote.
44
+
45
+ 4. Rebase all remaining xt/ branches onto the new main:
46
+ ```
47
+ git fetch origin main
48
+ git checkout xt/<branch>
49
+ git rebase origin/main
50
+ git push origin xt/<branch> --force-with-lease
51
+ ```
52
+ Repeat in queue order. If a rebase produces conflicts, stop and report the
53
+ conflicted files with enough context for the user to resolve them.
54
+
55
+ 5. Repeat from step 2 until the queue is empty.
56
+
57
+ ## Constraints
58
+
59
+ - Never merge a PR with failing or pending CI.
60
+ - Never use --squash or --merge; always --rebase.
61
+ - Never force-push without --force-with-lease.
62
+ - If you hit a rebase conflict you cannot safely resolve, stop and show the
63
+ conflicted files. Do not guess at conflict resolution.
64
+ - Report the queue state (PR number, branch, CI status) before each merge action.
65
+
66
+ task_template: |
67
+ Drain the xt worktree PR merge queue.
68
+
69
+ $prompt
70
+
71
+ Working directory: $cwd
72
+
73
+ List all open PRs from xt/ branches, sort oldest-first, check CI on the oldest,
74
+ merge it if green, rebase the remaining branches onto the new main, and repeat
75
+ until the queue is empty. Report final state when done.
76
+
77
+ communication:
78
+ output_to: .specialists/merge-prs-result.md
@@ -1,47 +0,0 @@
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);
@@ -1,58 +0,0 @@
1
- #!/usr/bin/env node
2
- // beads-commit-gate — Claude Code PreToolUse hook
3
- // Blocks `git commit` when in_progress beads issues still exist.
4
- // Forces: close issues first, THEN commit.
5
- // Exit 0: allow | Exit 2: block (stderr shown to Claude)
6
- //
7
- // Installed by: specialists install
8
-
9
- import { execSync } from 'node:child_process';
10
- import { readFileSync, existsSync } from 'node:fs';
11
- import { join } from 'node:path';
12
-
13
- let input;
14
- try {
15
- input = JSON.parse(readFileSync(0, 'utf8'));
16
- } catch {
17
- process.exit(0);
18
- }
19
-
20
- const tool = input.tool_name ?? '';
21
- if (tool !== 'Bash') process.exit(0);
22
-
23
- const cmd = input.tool_input?.command ?? '';
24
- if (!/\bgit\s+commit\b/.test(cmd)) process.exit(0);
25
-
26
- const cwd = input.cwd ?? process.env.CLAUDE_PROJECT_DIR ?? process.cwd();
27
- if (!existsSync(join(cwd, '.beads'))) process.exit(0);
28
-
29
- let inProgress = 0;
30
- let summary = '';
31
- try {
32
- const output = execSync('bd list --status=in_progress', {
33
- encoding: 'utf8',
34
- cwd,
35
- stdio: ['pipe', 'pipe', 'pipe'],
36
- timeout: 8000,
37
- });
38
- inProgress = (output.match(/in_progress/g) ?? []).length;
39
- summary = output.trim();
40
- } catch {
41
- process.exit(0);
42
- }
43
-
44
- if (inProgress > 0) {
45
- process.stderr.write(
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'
54
- );
55
- process.exit(2);
56
- }
57
-
58
- process.exit(0);
@@ -1,53 +0,0 @@
1
- #!/usr/bin/env node
2
- // beads-edit-gate — Claude Code PreToolUse hook
3
- // Blocks file edits when no beads issue is in_progress.
4
- // Only active in projects with a .beads/ directory.
5
- // Exit 0: allow | Exit 2: block (stderr shown to Claude)
6
- //
7
- // Installed by: specialists install
8
-
9
- import { execSync } from 'node:child_process';
10
- import { readFileSync, existsSync } from 'node:fs';
11
- import { join } from 'node:path';
12
-
13
- let input;
14
- try {
15
- input = JSON.parse(readFileSync(0, 'utf8'));
16
- } catch {
17
- process.exit(0);
18
- }
19
-
20
- const cwd = input.cwd ?? process.env.CLAUDE_PROJECT_DIR ?? process.cwd();
21
- if (!existsSync(join(cwd, '.beads'))) process.exit(0);
22
-
23
- let inProgress = 0;
24
- try {
25
- const output = execSync('bd list --status=in_progress', {
26
- encoding: 'utf8',
27
- cwd,
28
- stdio: ['pipe', 'pipe', 'pipe'],
29
- timeout: 8000,
30
- });
31
- inProgress = (output.match(/in_progress/g) ?? []).length;
32
- } catch {
33
- process.exit(0);
34
- }
35
-
36
- if (inProgress === 0) {
37
- process.stderr.write(
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' +
40
- ' bd update <id> --status=in_progress\n\n' +
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'
49
- );
50
- process.exit(2);
51
- }
52
-
53
- process.exit(0);
@@ -1,52 +0,0 @@
1
- #!/usr/bin/env node
2
- // beads-stop-gate — Claude Code Stop hook
3
- // Blocks the agent from stopping when in_progress beads issues remain.
4
- // Exit 0: allow stop | Exit 2: block stop (stderr shown to Claude)
5
- //
6
- // Installed by: specialists install
7
-
8
- import { execSync } from 'node:child_process';
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
- const cwd = input.cwd ?? process.env.CLAUDE_PROJECT_DIR ?? process.cwd();
20
- if (!existsSync(join(cwd, '.beads'))) process.exit(0);
21
-
22
- let inProgress = 0;
23
- let summary = '';
24
- try {
25
- const output = execSync('bd list --status=in_progress', {
26
- encoding: 'utf8',
27
- cwd,
28
- stdio: ['pipe', 'pipe', 'pipe'],
29
- timeout: 8000,
30
- });
31
- inProgress = (output.match(/in_progress/g) ?? []).length;
32
- summary = output.trim();
33
- } catch {
34
- process.exit(0);
35
- }
36
-
37
- if (inProgress > 0) {
38
- process.stderr.write(
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'
48
- );
49
- process.exit(2);
50
- }
51
-
52
- process.exit(0);
@@ -1,90 +0,0 @@
1
- #!/usr/bin/env node
2
- // Claude Code PreToolUse hook — block writes and direct master pushes
3
- // Exit 0: allow | Exit 2: block (message shown to user)
4
- //
5
- // Installed by: specialists install
6
-
7
- import { execSync } from 'node:child_process';
8
- import { readFileSync } from 'node:fs';
9
-
10
- let branch = '';
11
- try {
12
- branch = execSync('git branch --show-current', {
13
- encoding: 'utf8',
14
- stdio: ['pipe', 'pipe', 'pipe'],
15
- }).trim();
16
- } catch {}
17
-
18
- // Not in a git repo or not on a protected branch — allow
19
- if (!branch || (branch !== 'main' && branch !== 'master')) {
20
- process.exit(0);
21
- }
22
-
23
- let input;
24
- try {
25
- input = JSON.parse(readFileSync(0, 'utf8'));
26
- } catch {
27
- process.exit(0);
28
- }
29
-
30
- const tool = input.tool_name ?? '';
31
-
32
- const WRITE_TOOLS = new Set(['Edit', 'Write', 'MultiEdit', 'NotebookEdit']);
33
-
34
- if (WRITE_TOOLS.has(tool)) {
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
- );
46
- process.exit(2);
47
- }
48
-
49
- // Block direct commits and pushes to master — use feature branches + gh pr create/merge
50
- if (tool === 'Bash') {
51
- const cmd = (input.tool_input?.command ?? '').trim().replace(/\s+/g, ' ');
52
-
53
- if (/^git commit/.test(cmd)) {
54
- process.stderr.write(
55
- `⛔ Don't commit directly to '${branch}' — use a feature branch.\n\n` +
56
- 'Full workflow:\n' +
57
- ' 1. git checkout -b feature/<name> ← start here\n' +
58
- ' 2. bd create + bd update in_progress track your work\n' +
59
- ' 3. Edit files / write code\n' +
60
- ' 4. bd close <id> && git add && git commit\n' +
61
- ' 5. git push -u origin feature/<name>\n' +
62
- ' 6. gh pr create --fill && gh pr merge --squash\n' +
63
- ' 7. git checkout master && git reset --hard origin/master\n'
64
- );
65
- process.exit(2);
66
- }
67
-
68
- if (/^git push/.test(cmd)) {
69
- const tokens = cmd.split(' ');
70
- const lastToken = tokens[tokens.length - 1];
71
- const explicitMaster = /^(master|main)$/.test(lastToken) || /:(master|main)$/.test(lastToken);
72
- const impliedMaster = tokens.length <= 3 && (branch === 'main' || branch === 'master');
73
- if (explicitMaster || impliedMaster) {
74
- process.stderr.write(
75
- `⛔ Don't push directly to '${branch}' — use the PR workflow.\n\n` +
76
- 'Next steps:\n' +
77
- ' 5. git push -u origin <feature-branch> ← push your branch\n' +
78
- ' 6. gh pr create --fill create PR\n' +
79
- ' gh pr merge --squash merge it\n' +
80
- ' 7. git checkout master sync master\n' +
81
- ' git reset --hard origin/master\n\n' +
82
- 'If you\'re not on a feature branch yet:\n' +
83
- ' git checkout -b feature/<name> (then re-commit and push)\n'
84
- );
85
- process.exit(2);
86
- }
87
- }
88
- }
89
-
90
- process.exit(0);