xtrm-tools 0.5.10 → 0.5.13
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/CHANGELOG.md +4 -1
- package/README.md +28 -30
- package/cli/dist/index.cjs +1509 -2722
- package/cli/dist/index.cjs.map +1 -1
- package/cli/package.json +1 -1
- package/config/instructions/agents-top.md +87 -23
- package/config/instructions/claude-top.md +101 -23
- package/config/pi/extensions/beads/index.ts +3 -1
- package/config/pi/extensions/session-flow/index.ts +26 -90
- package/config/pi/extensions/xtrm-loader/index.ts +39 -2
- package/hooks/README.md +0 -14
- package/hooks/beads-gate-messages.mjs +8 -22
- package/hooks/gitnexus/gitnexus-hook.cjs +1 -1
- package/hooks/hooks.json +25 -27
- package/hooks/quality-check-env.mjs +79 -0
- package/hooks/quality-check.cjs +6 -6
- package/hooks/statusline.mjs +115 -0
- package/hooks/using-xtrm-reminder.mjs +35 -0
- package/package.json +1 -1
- package/skills/sync-docs-workspace/iteration-1/benchmark.json +293 -0
- package/skills/sync-docs-workspace/iteration-1/benchmark.md +13 -0
- package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/eval_metadata.json +27 -0
- package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/with_skill/outputs/result.md +210 -0
- package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/with_skill/run-1/grading.json +28 -0
- package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/with_skill/run-1/timing.json +1 -0
- package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/without_skill/outputs/result.md +101 -0
- package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/without_skill/run-1/grading.json +28 -0
- package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/without_skill/run-1/timing.json +5 -0
- package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/without_skill/timing.json +5 -0
- package/skills/sync-docs-workspace/iteration-1/eval-fix-mode/eval_metadata.json +27 -0
- package/skills/sync-docs-workspace/iteration-1/eval-fix-mode/with_skill/outputs/result.md +198 -0
- package/skills/sync-docs-workspace/iteration-1/eval-fix-mode/with_skill/run-1/grading.json +28 -0
- package/skills/sync-docs-workspace/iteration-1/eval-fix-mode/with_skill/run-1/timing.json +1 -0
- package/skills/sync-docs-workspace/iteration-1/eval-fix-mode/without_skill/outputs/result.md +94 -0
- package/skills/sync-docs-workspace/iteration-1/eval-fix-mode/without_skill/run-1/grading.json +28 -0
- package/skills/sync-docs-workspace/iteration-1/eval-fix-mode/without_skill/run-1/timing.json +1 -0
- package/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/eval_metadata.json +27 -0
- package/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/with_skill/outputs/result.md +237 -0
- package/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/with_skill/run-1/grading.json +28 -0
- package/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/with_skill/run-1/timing.json +1 -0
- package/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/without_skill/outputs/result.md +134 -0
- package/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/without_skill/run-1/grading.json +28 -0
- package/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/without_skill/run-1/timing.json +1 -0
- package/skills/sync-docs-workspace/iteration-2/benchmark.json +297 -0
- package/skills/sync-docs-workspace/iteration-2/benchmark.md +13 -0
- package/skills/sync-docs-workspace/iteration-2/eval-doc-audit/eval_metadata.json +27 -0
- package/skills/sync-docs-workspace/iteration-2/eval-doc-audit/with_skill/outputs/result.md +137 -0
- package/skills/sync-docs-workspace/iteration-2/eval-doc-audit/with_skill/run-1/grading.json +92 -0
- package/skills/sync-docs-workspace/iteration-2/eval-doc-audit/with_skill/run-1/timing.json +1 -0
- package/skills/sync-docs-workspace/iteration-2/eval-doc-audit/without_skill/outputs/result.md +134 -0
- package/skills/sync-docs-workspace/iteration-2/eval-doc-audit/without_skill/run-1/grading.json +86 -0
- package/skills/sync-docs-workspace/iteration-2/eval-doc-audit/without_skill/run-1/timing.json +1 -0
- package/skills/sync-docs-workspace/iteration-2/eval-fix-mode/eval_metadata.json +27 -0
- package/skills/sync-docs-workspace/iteration-2/eval-fix-mode/with_skill/outputs/result.md +193 -0
- package/skills/sync-docs-workspace/iteration-2/eval-fix-mode/with_skill/run-1/grading.json +72 -0
- package/skills/sync-docs-workspace/iteration-2/eval-fix-mode/with_skill/run-1/timing.json +1 -0
- package/skills/sync-docs-workspace/iteration-2/eval-fix-mode/without_skill/outputs/result.md +211 -0
- package/skills/sync-docs-workspace/iteration-2/eval-fix-mode/without_skill/run-1/grading.json +91 -0
- package/skills/sync-docs-workspace/iteration-2/eval-fix-mode/without_skill/run-1/timing.json +5 -0
- package/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/eval_metadata.json +27 -0
- package/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/with_skill/outputs/result.md +182 -0
- package/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/with_skill/run-1/grading.json +95 -0
- package/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/with_skill/run-1/timing.json +1 -0
- package/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/without_skill/outputs/result.md +222 -0
- package/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/without_skill/run-1/grading.json +88 -0
- package/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/without_skill/run-1/timing.json +5 -0
- package/skills/sync-docs-workspace/iteration-3/benchmark.json +298 -0
- package/skills/sync-docs-workspace/iteration-3/benchmark.md +13 -0
- package/skills/sync-docs-workspace/iteration-3/eval-doc-audit/eval_metadata.json +27 -0
- package/skills/sync-docs-workspace/iteration-3/eval-doc-audit/with_skill/outputs/result.md +125 -0
- package/skills/sync-docs-workspace/iteration-3/eval-doc-audit/with_skill/run-1/grading.json +97 -0
- package/skills/sync-docs-workspace/iteration-3/eval-doc-audit/with_skill/run-1/timing.json +5 -0
- package/skills/sync-docs-workspace/iteration-3/eval-doc-audit/without_skill/outputs/result.md +144 -0
- package/skills/sync-docs-workspace/iteration-3/eval-doc-audit/without_skill/run-1/grading.json +78 -0
- package/skills/sync-docs-workspace/iteration-3/eval-doc-audit/without_skill/run-1/timing.json +5 -0
- package/skills/sync-docs-workspace/iteration-3/eval-fix-mode/eval_metadata.json +27 -0
- package/skills/sync-docs-workspace/iteration-3/eval-fix-mode/with_skill/outputs/result.md +104 -0
- package/skills/sync-docs-workspace/iteration-3/eval-fix-mode/with_skill/run-1/grading.json +91 -0
- package/skills/sync-docs-workspace/iteration-3/eval-fix-mode/with_skill/run-1/timing.json +5 -0
- package/skills/sync-docs-workspace/iteration-3/eval-fix-mode/without_skill/outputs/result.md +79 -0
- package/skills/sync-docs-workspace/iteration-3/eval-fix-mode/without_skill/run-1/grading.json +82 -0
- package/skills/sync-docs-workspace/iteration-3/eval-fix-mode/without_skill/run-1/timing.json +5 -0
- package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/eval_metadata.json +27 -0
- package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase1_context.json +302 -0
- package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase2_drift.txt +33 -0
- package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase3_analysis.json +114 -0
- package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase4_fix.txt +118 -0
- package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase5_validate.txt +38 -0
- package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/result.md +158 -0
- package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/run-1/grading.json +95 -0
- package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/run-1/timing.json +5 -0
- package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/without_skill/outputs/result.md +71 -0
- package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/without_skill/run-1/grading.json +90 -0
- package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/without_skill/run-1/timing.json +5 -0
- package/skills/using-xtrm/SKILL.md +84 -205
- package/config/pi/extensions/bg-process/index.ts +0 -230
- package/config/pi/extensions/bg-process/package.json +0 -16
- package/config/pi/extensions/minimal-mode/index.ts +0 -201
- package/config/pi/extensions/minimal-mode/package.json +0 -16
- package/config/pi/extensions/todo/index.ts +0 -299
- package/config/pi/extensions/todo/package.json +0 -16
- package/hooks/agent_context.py +0 -105
- package/hooks/branch-state.mjs +0 -39
- package/hooks/guard-rules.mjs +0 -118
- package/hooks/main-guard-post-push.mjs +0 -71
- package/hooks/main-guard.mjs +0 -119
package/cli/package.json
CHANGED
|
@@ -1,30 +1,94 @@
|
|
|
1
|
-
# XTRM Agent Workflow
|
|
1
|
+
# XTRM Agent Workflow
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> Full reference: [XTRM-GUIDE.md](XTRM-GUIDE.md)
|
|
4
|
+
> Run `bd prime` at session start (or after context reset) for live beads workflow context.
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
- Clarify task intent if ambiguous.
|
|
7
|
-
- Prefer semantic discovery (Serena + GitNexus) over broad grep-first exploration.
|
|
6
|
+
## Session Start
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
1. `bd prime` — load workflow context and active claims
|
|
9
|
+
2. `bd memories <keyword>` — retrieve memories relevant to today's task
|
|
10
|
+
3. `bd recall <key>` — retrieve a specific memory by key if needed
|
|
11
|
+
4. `bd ready` — find available work
|
|
12
|
+
5. `bd update <id> --claim` — claim before any file edit
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
- Create a **new branch for each issue** from latest `main`.
|
|
15
|
-
- Do **not** continue new work on a previously used branch.
|
|
16
|
-
- Branch format: `feature/<issue-id>-<short-description>` (or `fix/...`, `chore/...`).
|
|
14
|
+
## Active Gates (extensions enforce these — not optional)
|
|
17
15
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
| Gate | Trigger | Required action |
|
|
17
|
+
|------|---------|-----------------|
|
|
18
|
+
| **Edit** | Write/Edit without active claim | `bd update <id> --claim` |
|
|
19
|
+
| **Commit** | `git commit` while claim is open | `bd close <id>` first, then commit |
|
|
20
|
+
| **Stop** | Session end with unclosed claim | `bd close <id>` |
|
|
21
|
+
| **Memory** | Auto-fires at session end if issue closed | `bd remember "<insight>"` then `touch .beads/.memory-gate-done` |
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
- Always merge via PR (squash merge preferred).
|
|
24
|
-
- After merge: switch to `main` and sync (`git reset --hard origin/main`).
|
|
25
|
-
- Delete merged branch locally and remotely (`git branch -d <branch>` and `git push origin --delete <branch>`).
|
|
23
|
+
> `bd close` auto-commits via `git commit -am`. Do not double-commit after closing.
|
|
26
24
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
## bd Command Reference
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# Work discovery
|
|
29
|
+
bd ready # Unblocked open issues
|
|
30
|
+
bd show <id> # Full detail + deps + blockers
|
|
31
|
+
bd list --status=in_progress # Your active claims
|
|
32
|
+
bd query "status=in_progress AND assignee=me" # Complex filter
|
|
33
|
+
bd search <text> # Full-text search across issues
|
|
34
|
+
|
|
35
|
+
# Claiming & updating
|
|
36
|
+
bd update <id> --claim # Claim (sets you as owner, status→in_progress)
|
|
37
|
+
bd update <id> --notes "..." # Append notes inline
|
|
38
|
+
bd update <id> --status=blocked # Mark blocked
|
|
39
|
+
bd update # Update last-touched issue (no ID needed)
|
|
40
|
+
|
|
41
|
+
# Creating
|
|
42
|
+
bd create --title="..." --description="..." --type=task --priority=2
|
|
43
|
+
# --deps "discovered-from:<parent-id>" link follow-ups to source
|
|
44
|
+
# priority: 0=critical 1=high 2=medium 3=low 4=backlog
|
|
45
|
+
# types: task | bug | feature | epic | chore | decision
|
|
46
|
+
|
|
47
|
+
# Closing
|
|
48
|
+
bd close <id> # Close + auto-commit
|
|
49
|
+
bd close <id> --reason="Done: ..." # Close with context
|
|
50
|
+
bd close <id1> <id2> <id3> # Batch close
|
|
51
|
+
|
|
52
|
+
# Dependencies
|
|
53
|
+
bd dep add <issue> <depends-on> # issue depends on depends-on (depends-on blocks issue)
|
|
54
|
+
bd dep <blocker> --blocks <blocked> # shorthand: blocker blocks blocked
|
|
55
|
+
bd dep relate <a> <b> # non-blocking "relates to" link
|
|
56
|
+
bd dep tree <id> # visualise dependency tree
|
|
57
|
+
bd blocked # show all currently blocked issues
|
|
58
|
+
|
|
59
|
+
# Persistent memory
|
|
60
|
+
bd remember "<insight>" # Store across sessions (project-scoped)
|
|
61
|
+
bd memories <keyword> # Search stored memories
|
|
62
|
+
bd recall <key> # Retrieve full memory by key
|
|
63
|
+
bd forget <key> # Remove a memory
|
|
64
|
+
|
|
65
|
+
# Health & pre-flight
|
|
66
|
+
bd stats # Open/closed/blocked counts
|
|
67
|
+
bd preflight --check # Pre-PR readiness (lint, tests, beads)
|
|
68
|
+
bd doctor # Diagnose installation issues
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Git Workflow (strict: one branch per issue)
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
git checkout -b feature/<issue-id>-<slug> # or fix/... chore/...
|
|
75
|
+
bd update <id> --claim # claim before any edit
|
|
76
|
+
# ... write code ...
|
|
77
|
+
bd close <id> --reason="..." # closes issue + auto-commits
|
|
78
|
+
xt end # push, PR, merge, worktree cleanup
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**Never** continue new work on a previously used branch.
|
|
82
|
+
|
|
83
|
+
## Quality Gates (automatic)
|
|
84
|
+
|
|
85
|
+
Run on every file edit via PostToolUse extension:
|
|
86
|
+
- **TypeScript/JS**: ESLint + tsc
|
|
87
|
+
- **Python**: ruff + mypy
|
|
88
|
+
|
|
89
|
+
Gate output appears as extension context. Fix failures before proceeding — do not commit with lint errors.
|
|
90
|
+
|
|
91
|
+
## Worktree Sessions
|
|
92
|
+
|
|
93
|
+
- `xt pi` — launch Pi in a sandboxed worktree
|
|
94
|
+
- `xt end` — close session: commit / push / PR / cleanup
|
|
@@ -1,30 +1,108 @@
|
|
|
1
|
-
# XTRM Agent Workflow
|
|
1
|
+
# XTRM Agent Workflow
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> Full reference: [XTRM-GUIDE.md](XTRM-GUIDE.md) | Session manual: `/using-xtrm` skill
|
|
4
|
+
> Run `bd prime` at session start (or after `/compact`) for live beads workflow context.
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
- Clarify task intent if ambiguous.
|
|
7
|
-
- Prefer semantic discovery (Serena + GitNexus) over broad grep-first exploration.
|
|
6
|
+
## Session Start
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
1. `bd prime` — load workflow context and active claims
|
|
9
|
+
2. `bd memories <keyword>` — retrieve memories relevant to today's task
|
|
10
|
+
3. `bd recall <key>` — retrieve a specific memory by key if needed
|
|
11
|
+
4. `bd ready` — find available work
|
|
12
|
+
5. `bd update <id> --claim` — claim before any file edit
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
- Create a **new branch for each issue** from latest `main`.
|
|
15
|
-
- Do **not** continue new work on a previously used branch.
|
|
16
|
-
- Branch format: `feature/<issue-id>-<short-description>` (or `fix/...`, `chore/...`).
|
|
14
|
+
## Active Gates (hooks enforce these — not optional)
|
|
17
15
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
| Gate | Trigger | Required action |
|
|
17
|
+
|------|---------|-----------------|
|
|
18
|
+
| **Edit** | Write/Edit without active claim | `bd update <id> --claim` |
|
|
19
|
+
| **Commit** | `git commit` while claim is open | `bd close <id>` first, then commit |
|
|
20
|
+
| **Stop** | Session end with unclosed claim | `bd close <id>` |
|
|
21
|
+
| **Memory** | Auto-fires at Stop if issue closed this session | `bd remember "<insight>"` then `touch .beads/.memory-gate-done` |
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
- Always merge via PR (squash merge preferred).
|
|
24
|
-
- After merge: switch to `main` and sync (`git reset --hard origin/main`).
|
|
25
|
-
- Delete merged branch locally and remotely (`git branch -d <branch>` and `git push origin --delete <branch>`).
|
|
23
|
+
> `bd close` auto-commits via `git commit -am`. Do not double-commit after closing.
|
|
26
24
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
## bd Command Reference
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# Work discovery
|
|
29
|
+
bd ready # Unblocked open issues
|
|
30
|
+
bd show <id> # Full detail + deps + blockers
|
|
31
|
+
bd list --status=in_progress # Your active claims
|
|
32
|
+
bd query "status=in_progress AND assignee=me" # Complex filter
|
|
33
|
+
bd search <text> # Full-text search across issues
|
|
34
|
+
|
|
35
|
+
# Claiming & updating
|
|
36
|
+
bd update <id> --claim # Claim (sets you as owner, status→in_progress)
|
|
37
|
+
bd update <id> --notes "..." # Append notes inline
|
|
38
|
+
bd update <id> --status=blocked # Mark blocked
|
|
39
|
+
bd update # Update last-touched issue (no ID needed)
|
|
40
|
+
|
|
41
|
+
# Creating
|
|
42
|
+
bd create --title="..." --description="..." --type=task --priority=2
|
|
43
|
+
# --deps "discovered-from:<parent-id>" link follow-ups to source
|
|
44
|
+
# priority: 0=critical 1=high 2=medium 3=low 4=backlog
|
|
45
|
+
# types: task | bug | feature | epic | chore | decision
|
|
46
|
+
|
|
47
|
+
# Closing
|
|
48
|
+
bd close <id> # Close + auto-commit
|
|
49
|
+
bd close <id> --reason="Done: ..." # Close with context
|
|
50
|
+
bd close <id1> <id2> <id3> # Batch close
|
|
51
|
+
|
|
52
|
+
# Dependencies
|
|
53
|
+
bd dep add <issue> <depends-on> # issue depends on depends-on (depends-on blocks issue)
|
|
54
|
+
bd dep <blocker> --blocks <blocked> # shorthand: blocker blocks blocked
|
|
55
|
+
bd dep relate <a> <b> # non-blocking "relates to" link
|
|
56
|
+
bd dep tree <id> # visualise dependency tree
|
|
57
|
+
bd blocked # show all currently blocked issues
|
|
58
|
+
|
|
59
|
+
# Persistent memory
|
|
60
|
+
bd remember "<insight>" # Store across sessions (project-scoped)
|
|
61
|
+
bd memories <keyword> # Search stored memories
|
|
62
|
+
bd recall <key> # Retrieve full memory by key
|
|
63
|
+
bd forget <key> # Remove a memory
|
|
64
|
+
|
|
65
|
+
# Health & pre-flight
|
|
66
|
+
bd stats # Open/closed/blocked counts
|
|
67
|
+
bd preflight --check # Pre-PR readiness (lint, tests, beads)
|
|
68
|
+
bd doctor # Diagnose installation issues
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Git Workflow (strict: one branch per issue)
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
git checkout -b feature/<issue-id>-<slug> # or fix/... chore/...
|
|
75
|
+
bd update <id> --claim # claim before any edit
|
|
76
|
+
# ... write code ...
|
|
77
|
+
bd close <id> --reason="..." # closes issue + auto-commits
|
|
78
|
+
xt end # push, PR, merge, worktree cleanup
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**Never** continue new work on a previously used branch.
|
|
82
|
+
|
|
83
|
+
## Code Intelligence (mandatory before edits)
|
|
84
|
+
|
|
85
|
+
Use **Serena** (`using-serena-lsp` skill) for all code reads and edits:
|
|
86
|
+
- `find_symbol` → `get_symbols_overview` → `replace_symbol_body`
|
|
87
|
+
- Never grep-read-sed when symbolic tools are available
|
|
88
|
+
|
|
89
|
+
Use **GitNexus** MCP tools before touching any symbol:
|
|
90
|
+
- `gitnexus_impact({target: "symbolName", direction: "upstream"})` — blast radius
|
|
91
|
+
- `gitnexus_context({name: "symbolName"})` — callers, callees, execution flows
|
|
92
|
+
- `gitnexus_detect_changes()` — verify scope before every commit
|
|
93
|
+
- `gitnexus_query({query: "concept"})` — explore unfamiliar areas
|
|
94
|
+
|
|
95
|
+
Stop and warn the user if impact returns HIGH or CRITICAL risk.
|
|
96
|
+
|
|
97
|
+
## Quality Gates (automatic)
|
|
98
|
+
|
|
99
|
+
Run on every file edit via PostToolUse hooks:
|
|
100
|
+
- **TypeScript/JS**: ESLint + tsc
|
|
101
|
+
- **Python**: ruff + mypy
|
|
102
|
+
|
|
103
|
+
Gate output appears as hook context. Fix failures before proceeding — do not commit with lint errors.
|
|
104
|
+
|
|
105
|
+
## Worktree Sessions
|
|
106
|
+
|
|
107
|
+
- `xt claude` — launch Claude Code in a sandboxed worktree
|
|
108
|
+
- `xt end` — close session: commit / push / PR / cleanup
|
|
@@ -149,7 +149,9 @@ export default function (pi: ExtensionAPI) {
|
|
|
149
149
|
pi.sendUserMessage(
|
|
150
150
|
`🧠 Memory gate: claim \`${claimId}\` was closed this session.\n` +
|
|
151
151
|
`For each closed issue, worth persisting?\n` +
|
|
152
|
-
` YES → \`bd remember "<insight>"
|
|
152
|
+
` YES → \`bd remember "<insight>"\`\n` +
|
|
153
|
+
` NO → note "nothing to persist"\n` +
|
|
154
|
+
` Then acknowledge: \`touch .beads/.memory-gate-done\``,
|
|
153
155
|
);
|
|
154
156
|
};
|
|
155
157
|
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
2
2
|
import { isBashToolResult } from "@mariozechner/pi-coding-agent";
|
|
3
|
-
import fs from "node:fs";
|
|
4
|
-
import path from "node:path";
|
|
5
3
|
import { SubprocessRunner, EventAdapter } from "../core/lib";
|
|
6
|
-
import { readSessionState } from "../core/session-state";
|
|
7
4
|
|
|
8
5
|
function isClaimCommand(command: string): { isClaim: boolean; issueId: string | null } {
|
|
9
6
|
if (!/\bbd\s+update\b/.test(command) || !/--claim\b/.test(command)) {
|
|
@@ -13,66 +10,14 @@ function isClaimCommand(command: string): { isClaim: boolean; issueId: string |
|
|
|
13
10
|
return { isClaim: true, issueId: match?.[1] ?? null };
|
|
14
11
|
}
|
|
15
12
|
|
|
16
|
-
function
|
|
17
|
-
|
|
18
|
-
for (;;) {
|
|
19
|
-
const candidate = path.join(current, ".xtrm-session-state.json");
|
|
20
|
-
if (fs.existsSync(candidate)) return candidate;
|
|
21
|
-
const parent = path.dirname(current);
|
|
22
|
-
if (parent === current) return path.join(startCwd, ".xtrm-session-state.json");
|
|
23
|
-
current = parent;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
async function ensureWorktreeSessionState(cwd: string, issueId: string): Promise<{ ok: boolean; message?: string }> {
|
|
28
|
-
const repoRootResult = await SubprocessRunner.run("git", ["rev-parse", "--show-toplevel"], { cwd });
|
|
29
|
-
if (repoRootResult.code !== 0 || !repoRootResult.stdout) return { ok: false, message: "not a git repo" };
|
|
30
|
-
const repoRoot = repoRootResult.stdout.trim();
|
|
31
|
-
|
|
32
|
-
const gitDir = await SubprocessRunner.run("git", ["rev-parse", "--git-dir"], { cwd });
|
|
33
|
-
const commonDir = await SubprocessRunner.run("git", ["rev-parse", "--git-common-dir"], { cwd });
|
|
34
|
-
if (gitDir.code === 0 && commonDir.code === 0 && gitDir.stdout.trim() !== commonDir.stdout.trim()) {
|
|
35
|
-
return { ok: false, message: "already in linked worktree" };
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const overstoryDir = path.join(repoRoot, ".overstory");
|
|
39
|
-
const worktreesBase = fs.existsSync(overstoryDir)
|
|
40
|
-
? path.join(overstoryDir, "worktrees")
|
|
41
|
-
: path.join(repoRoot, ".worktrees");
|
|
42
|
-
fs.mkdirSync(worktreesBase, { recursive: true });
|
|
43
|
-
|
|
44
|
-
const branch = `feature/${issueId}`;
|
|
45
|
-
const worktreePath = path.join(worktreesBase, issueId);
|
|
46
|
-
if (!fs.existsSync(worktreePath)) {
|
|
47
|
-
const branchExists = (await SubprocessRunner.run("git", ["show-ref", "--verify", "--quiet", `refs/heads/${branch}`], { cwd: repoRoot })).code === 0;
|
|
48
|
-
const addArgs = branchExists
|
|
49
|
-
? ["worktree", "add", worktreePath, branch]
|
|
50
|
-
: ["worktree", "add", worktreePath, "-b", branch];
|
|
51
|
-
const add = await SubprocessRunner.run("git", addArgs, { cwd: repoRoot, timeoutMs: 20000 });
|
|
52
|
-
if (add.code !== 0) {
|
|
53
|
-
return { ok: false, message: add.stderr || add.stdout || "worktree creation failed" };
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const statePath = statePathFrom(repoRoot);
|
|
58
|
-
const payload = {
|
|
59
|
-
issueId,
|
|
60
|
-
branch,
|
|
61
|
-
worktreePath,
|
|
62
|
-
prNumber: null,
|
|
63
|
-
prUrl: null,
|
|
64
|
-
phase: "claimed",
|
|
65
|
-
conflictFiles: [],
|
|
66
|
-
startedAt: new Date().toISOString(),
|
|
67
|
-
lastChecked: new Date().toISOString(),
|
|
68
|
-
};
|
|
69
|
-
fs.writeFileSync(statePath, `${JSON.stringify(payload, null, 2)}\n`, "utf8");
|
|
70
|
-
return { ok: true, message: `Worktree created: ${worktreePath} Branch: ${branch}` };
|
|
13
|
+
function isWorktree(cwd: string): boolean {
|
|
14
|
+
return cwd.includes("/.xtrm/worktrees/") || cwd.includes("/.claude/worktrees/");
|
|
71
15
|
}
|
|
72
16
|
|
|
73
17
|
export default function (pi: ExtensionAPI) {
|
|
74
18
|
const getCwd = (ctx: any) => ctx.cwd || process.cwd();
|
|
75
19
|
|
|
20
|
+
// Claim sync: notify when a bd update --claim command is run.
|
|
76
21
|
pi.on("tool_result", async (event, ctx) => {
|
|
77
22
|
if (!isBashToolResult(event)) return undefined;
|
|
78
23
|
const cwd = getCwd(ctx);
|
|
@@ -82,50 +27,41 @@ export default function (pi: ExtensionAPI) {
|
|
|
82
27
|
const { isClaim, issueId } = isClaimCommand(command);
|
|
83
28
|
if (!isClaim || !issueId) return undefined;
|
|
84
29
|
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
const state = readSessionState(cwd);
|
|
88
|
-
const worktreePath = state?.worktreePath;
|
|
89
|
-
const nextStep = worktreePath
|
|
90
|
-
? `\nNext: cd ${worktreePath} && pi (sandboxed session)`
|
|
91
|
-
: "";
|
|
92
|
-
const text = `\n\n🧭 Session Flow: ${ensured.message}${nextStep}`;
|
|
93
|
-
return { content: [...event.content, { type: "text", text }] };
|
|
94
|
-
}
|
|
95
|
-
return undefined;
|
|
30
|
+
const text = `\n\nSession Flow: claimed ${issueId}. Work in this session is tracked.`;
|
|
31
|
+
return { content: [...event.content, { type: "text", text }] };
|
|
96
32
|
});
|
|
97
33
|
|
|
34
|
+
// Stop gate: block agent end if there is an in_progress claimed issue.
|
|
35
|
+
// Also remind to run `xt end` when session ends inside a worktree.
|
|
98
36
|
pi.on("agent_end", async (_event, ctx) => {
|
|
99
37
|
const cwd = getCwd(ctx);
|
|
100
38
|
if (!EventAdapter.isBeadsProject(cwd)) return undefined;
|
|
101
|
-
const state = readSessionState(cwd);
|
|
102
|
-
if (!state) return undefined;
|
|
103
39
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
40
|
+
const inProgressResult = await SubprocessRunner.run(
|
|
41
|
+
"bd",
|
|
42
|
+
["list", "--status=in_progress"],
|
|
43
|
+
{ cwd },
|
|
44
|
+
);
|
|
45
|
+
if (inProgressResult.code === 0 && inProgressResult.stdout) {
|
|
46
|
+
const output = inProgressResult.stdout;
|
|
47
|
+
const m = output.match(/Total:\s*\d+\s+issues?\s*\((\d+)\s+open,\s*(\d+)\s+in progress\)/);
|
|
48
|
+
const inProgressCount = m ? parseInt(m[2], 10) : 0;
|
|
49
|
+
if (inProgressCount > 0) {
|
|
50
|
+
const idMatch = output.match(/^\s*([a-zA-Z0-9._-]+)\s+in_progress/m);
|
|
51
|
+
const issueId = idMatch ? idMatch[1] : "<id>";
|
|
52
|
+
pi.sendUserMessage(
|
|
53
|
+
`Stop blocked: close your issue first: bd close ${issueId}`,
|
|
54
|
+
);
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
112
57
|
}
|
|
113
58
|
|
|
114
|
-
if (
|
|
115
|
-
const files = state.conflictFiles?.length ? state.conflictFiles.join(", ") : "unknown files";
|
|
59
|
+
if (isWorktree(cwd)) {
|
|
116
60
|
pi.sendUserMessage(
|
|
117
|
-
|
|
118
|
-
"Resolve conflicts, then continue with publish-only flow.",
|
|
61
|
+
"Run `xt end` to create a PR and clean up this worktree.",
|
|
119
62
|
);
|
|
120
|
-
return undefined;
|
|
121
63
|
}
|
|
122
64
|
|
|
123
|
-
if (state.phase === "claimed" || state.phase === "phase1-done") {
|
|
124
|
-
pi.sendUserMessage(
|
|
125
|
-
`⚠ Session has an active worktree at ${state.worktreePath}. ` +
|
|
126
|
-
"Use publish-only workflow (no automatic push/PR/merge).",
|
|
127
|
-
);
|
|
128
|
-
}
|
|
129
65
|
return undefined;
|
|
130
66
|
});
|
|
131
67
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
3
|
import * as path from "node:path";
|
|
4
|
+
import { homedir } from "node:os";
|
|
4
5
|
import { Logger } from "../core/lib";
|
|
5
6
|
|
|
6
7
|
const logger = new Logger({ namespace: "xtrm-loader" });
|
|
@@ -24,13 +25,37 @@ function findMarkdownFiles(dir: string, basePath: string = ""): string[] {
|
|
|
24
25
|
return results;
|
|
25
26
|
}
|
|
26
27
|
|
|
28
|
+
// Path to global xtrm skills
|
|
29
|
+
const GLOBAL_SKILLS_DIR = path.join(homedir(), ".agents", "skills");
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Load a skill file, stripping YAML frontmatter.
|
|
33
|
+
*/
|
|
34
|
+
function loadSkillContent(skillPath: string): string | null {
|
|
35
|
+
try {
|
|
36
|
+
const content = fs.readFileSync(skillPath, "utf8");
|
|
37
|
+
// Strip YAML frontmatter (--- ... ---)
|
|
38
|
+
return content.replace(/^---\n[\s\S]*?\n---\n/, "").trim();
|
|
39
|
+
} catch {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
27
44
|
export default function (pi: ExtensionAPI) {
|
|
28
45
|
let projectContext: string = "";
|
|
46
|
+
let usingXtrmContent: string | null = null;
|
|
29
47
|
|
|
30
48
|
pi.on("session_start", async (_event, ctx) => {
|
|
31
49
|
const cwd = ctx.cwd;
|
|
32
50
|
const contextParts: string[] = [];
|
|
33
51
|
|
|
52
|
+
// 0. Load using-xtrm skill (global)
|
|
53
|
+
const usingXtrmPath = path.join(GLOBAL_SKILLS_DIR, "using-xtrm", "SKILL.md");
|
|
54
|
+
usingXtrmContent = loadSkillContent(usingXtrmPath);
|
|
55
|
+
if (usingXtrmContent && ctx.hasUI) {
|
|
56
|
+
logger.info("Loaded using-xtrm skill from global skills directory");
|
|
57
|
+
}
|
|
58
|
+
|
|
34
59
|
// 1. Architecture & Roadmap
|
|
35
60
|
const roadmapPaths = [
|
|
36
61
|
path.join(cwd, "architecture", "project_roadmap.md"),
|
|
@@ -80,10 +105,22 @@ export default function (pi: ExtensionAPI) {
|
|
|
80
105
|
});
|
|
81
106
|
|
|
82
107
|
pi.on("before_agent_start", async (event) => {
|
|
83
|
-
|
|
108
|
+
const parts: string[] = [];
|
|
109
|
+
|
|
110
|
+
// Prepend using-xtrm skill (session operating manual)
|
|
111
|
+
if (usingXtrmContent) {
|
|
112
|
+
parts.push("# XTRM Session Operating Manual\n\n" + usingXtrmContent);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Append project context
|
|
116
|
+
if (projectContext) {
|
|
117
|
+
parts.push("# Project Intelligence Context\n\n" + projectContext);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (parts.length === 0) return undefined;
|
|
84
121
|
|
|
85
122
|
return {
|
|
86
|
-
systemPrompt: event.systemPrompt + "\n\n
|
|
123
|
+
systemPrompt: event.systemPrompt + "\n\n" + parts.join("\n\n---\n\n")
|
|
87
124
|
};
|
|
88
125
|
});
|
|
89
126
|
}
|
package/hooks/README.md
CHANGED
|
@@ -10,20 +10,6 @@ Hooks intercept specific events in the Claude Code lifecycle. Following architec
|
|
|
10
10
|
|
|
11
11
|
## Project Hooks
|
|
12
12
|
|
|
13
|
-
### main-guard.mjs
|
|
14
|
-
|
|
15
|
-
**Purpose**: Enforces PR-only merge workflow with full git protection. Blocks direct commits and dangerous `git checkout`, `git reset`, and file writes via Bash on protected branches (`main`/`master`).
|
|
16
|
-
|
|
17
|
-
**Trigger**: PreToolUse (Write|Edit|MultiEdit|Serena edit tools|Bash)
|
|
18
|
-
|
|
19
|
-
**Configuration**: Installed automatically to protect the main branch from unreviewed changes.
|
|
20
|
-
|
|
21
|
-
### main-guard-post-push.mjs
|
|
22
|
-
|
|
23
|
-
**Purpose**: Workflow enforcement. After pushing a feature branch, reminds to open a PR, merge using `gh pr merge --squash`, and sync local via `git reset --hard origin/main`.
|
|
24
|
-
|
|
25
|
-
**Trigger**: PostToolUse (Bash: git push)
|
|
26
|
-
|
|
27
13
|
### gitnexus-hook.cjs
|
|
28
14
|
|
|
29
15
|
**Purpose**: Enriches tool calls with knowledge graph context via `gitnexus augment`. Now supports Serena tools and uses a deduplication cache for efficiency.
|
|
@@ -7,27 +7,13 @@
|
|
|
7
7
|
|
|
8
8
|
// ── Shared workflow steps ────────────────────────────────────────────
|
|
9
9
|
|
|
10
|
-
export const WORKFLOW_STEPS =
|
|
11
|
-
' 1. git checkout -b feature/<name>\n' +
|
|
12
|
-
' 2. bd update <id> --claim\n' +
|
|
13
|
-
' 3. Edit / write code\n' +
|
|
14
|
-
' 4. bd close <id>\n' +
|
|
15
|
-
' 5. git add -p && git commit -m "<message>"\n' +
|
|
16
|
-
' 6. git push -u origin feature/<name>\n' +
|
|
17
|
-
' 7. gh pr create --fill && gh pr merge --squash\n' +
|
|
18
|
-
' 8. git checkout master && git reset --hard origin/master\n';
|
|
19
|
-
|
|
20
10
|
export const SESSION_CLOSE_PROTOCOL =
|
|
21
|
-
' bd close <id
|
|
22
|
-
'
|
|
23
|
-
' git push -u origin <feature-branch>\n' +
|
|
24
|
-
' gh pr create --fill && gh pr merge --squash\n';
|
|
11
|
+
' bd close <id> --reason="..."\n' +
|
|
12
|
+
' xt end\n';
|
|
25
13
|
|
|
26
14
|
export const COMMIT_NEXT_STEPS =
|
|
27
|
-
' bd close <id
|
|
28
|
-
'
|
|
29
|
-
' git push -u origin <feature-branch>\n' +
|
|
30
|
-
' gh pr create --fill && gh pr merge --squash\n';
|
|
15
|
+
' bd close <id> --reason="..." ← closes issue + auto-commits\n' +
|
|
16
|
+
' xt end ← push, PR, merge, worktree cleanup\n';
|
|
31
17
|
|
|
32
18
|
// ── Edit gate messages ───────────────────────────────────────────
|
|
33
19
|
|
|
@@ -71,12 +57,12 @@ export function stopBlockMessage(summary, claimed) {
|
|
|
71
57
|
// ── Memory gate messages ─────────────────────────────────────────
|
|
72
58
|
|
|
73
59
|
export function memoryPromptMessage(claimId) {
|
|
74
|
-
const claimLine = claimId ? `claim \`${claimId}\` was closed
|
|
60
|
+
const claimLine = claimId ? `claim \`${claimId}\` was closed.\n` : '';
|
|
75
61
|
return (
|
|
76
|
-
|
|
77
|
-
'
|
|
62
|
+
`\u25cf Memory gate: ${claimLine}` +
|
|
63
|
+
'Ask: "Would this be useful in 14 days on a fresh session?"\n' +
|
|
78
64
|
' YES → `bd remember "<insight>"`\n' +
|
|
79
65
|
' NO → note "nothing to persist"\n' +
|
|
80
|
-
' Then
|
|
66
|
+
' Then: `touch .beads/.memory-gate-done`\n'
|
|
81
67
|
);
|
|
82
68
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* GitNexus Claude Code Hook — PostToolUse enrichment
|
|
4
4
|
*
|
|
5
|
-
* Fires AFTER
|
|
5
|
+
* Fires AFTER Bash/Grep/Read/Glob/Serena tools complete.
|
|
6
6
|
* Extracts patterns from both tool input AND output, runs
|
|
7
7
|
* `gitnexus augment <pattern>`, and injects a [GitNexus: ...]
|
|
8
8
|
* block into Claude's context — mirroring pi-gitnexus behavior.
|
package/hooks/hooks.json
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
{
|
|
2
2
|
"hooks": {
|
|
3
|
+
"SessionStart": [
|
|
4
|
+
{
|
|
5
|
+
"hooks": [
|
|
6
|
+
{
|
|
7
|
+
"type": "command",
|
|
8
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/using-xtrm-reminder.mjs"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"type": "command",
|
|
12
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/beads-compact-restore.mjs",
|
|
13
|
+
"timeout": 5000
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"type": "command",
|
|
17
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/quality-check-env.mjs",
|
|
18
|
+
"timeout": 5000
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"type": "command",
|
|
22
|
+
"command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/serena-workflow-reminder.py"
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
],
|
|
3
27
|
"PostToolUse": [
|
|
4
28
|
{
|
|
5
29
|
"matcher": "Bash|execute_shell_command|bash",
|
|
@@ -27,7 +51,7 @@
|
|
|
27
51
|
]
|
|
28
52
|
},
|
|
29
53
|
{
|
|
30
|
-
"matcher": "Bash|mcp__serena__find_symbol|mcp__serena__get_symbols_overview|mcp__serena__search_for_pattern|mcp__serena__find_referencing_symbols|mcp__serena__replace_symbol_body|mcp__serena__insert_after_symbol|mcp__serena__insert_before_symbol|mcp__serena__rename_symbol",
|
|
54
|
+
"matcher": "Bash|Grep|Read|Glob|mcp__serena__find_symbol|mcp__serena__get_symbols_overview|mcp__serena__search_for_pattern|mcp__serena__find_referencing_symbols|mcp__serena__replace_symbol_body|mcp__serena__insert_after_symbol|mcp__serena__insert_before_symbol|mcp__serena__rename_symbol",
|
|
31
55
|
"hooks": [
|
|
32
56
|
{
|
|
33
57
|
"type": "command",
|
|
@@ -53,21 +77,6 @@
|
|
|
53
77
|
]
|
|
54
78
|
}
|
|
55
79
|
],
|
|
56
|
-
"SessionStart": [
|
|
57
|
-
{
|
|
58
|
-
"hooks": [
|
|
59
|
-
{
|
|
60
|
-
"type": "command",
|
|
61
|
-
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/beads-compact-restore.mjs",
|
|
62
|
-
"timeout": 5000
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
"type": "command",
|
|
66
|
-
"command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/serena-workflow-reminder.py"
|
|
67
|
-
}
|
|
68
|
-
]
|
|
69
|
-
}
|
|
70
|
-
],
|
|
71
80
|
"PreToolUse": [
|
|
72
81
|
{
|
|
73
82
|
"matcher": "Edit|Write|MultiEdit|NotebookEdit|mcp__serena__rename_symbol|mcp__serena__replace_symbol_body|mcp__serena__insert_after_symbol|mcp__serena__insert_before_symbol",
|
|
@@ -100,17 +109,6 @@
|
|
|
100
109
|
}
|
|
101
110
|
]
|
|
102
111
|
}
|
|
103
|
-
],
|
|
104
|
-
"UserPromptSubmit": [
|
|
105
|
-
{
|
|
106
|
-
"hooks": [
|
|
107
|
-
{
|
|
108
|
-
"type": "command",
|
|
109
|
-
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/branch-state.mjs",
|
|
110
|
-
"timeout": 3000
|
|
111
|
-
}
|
|
112
|
-
]
|
|
113
|
-
}
|
|
114
112
|
]
|
|
115
113
|
}
|
|
116
114
|
}
|