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.
Files changed (106) hide show
  1. package/CHANGELOG.md +4 -1
  2. package/README.md +28 -30
  3. package/cli/dist/index.cjs +1509 -2722
  4. package/cli/dist/index.cjs.map +1 -1
  5. package/cli/package.json +1 -1
  6. package/config/instructions/agents-top.md +87 -23
  7. package/config/instructions/claude-top.md +101 -23
  8. package/config/pi/extensions/beads/index.ts +3 -1
  9. package/config/pi/extensions/session-flow/index.ts +26 -90
  10. package/config/pi/extensions/xtrm-loader/index.ts +39 -2
  11. package/hooks/README.md +0 -14
  12. package/hooks/beads-gate-messages.mjs +8 -22
  13. package/hooks/gitnexus/gitnexus-hook.cjs +1 -1
  14. package/hooks/hooks.json +25 -27
  15. package/hooks/quality-check-env.mjs +79 -0
  16. package/hooks/quality-check.cjs +6 -6
  17. package/hooks/statusline.mjs +115 -0
  18. package/hooks/using-xtrm-reminder.mjs +35 -0
  19. package/package.json +1 -1
  20. package/skills/sync-docs-workspace/iteration-1/benchmark.json +293 -0
  21. package/skills/sync-docs-workspace/iteration-1/benchmark.md +13 -0
  22. package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/eval_metadata.json +27 -0
  23. package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/with_skill/outputs/result.md +210 -0
  24. package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/with_skill/run-1/grading.json +28 -0
  25. package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/with_skill/run-1/timing.json +1 -0
  26. package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/without_skill/outputs/result.md +101 -0
  27. package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/without_skill/run-1/grading.json +28 -0
  28. package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/without_skill/run-1/timing.json +5 -0
  29. package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/without_skill/timing.json +5 -0
  30. package/skills/sync-docs-workspace/iteration-1/eval-fix-mode/eval_metadata.json +27 -0
  31. package/skills/sync-docs-workspace/iteration-1/eval-fix-mode/with_skill/outputs/result.md +198 -0
  32. package/skills/sync-docs-workspace/iteration-1/eval-fix-mode/with_skill/run-1/grading.json +28 -0
  33. package/skills/sync-docs-workspace/iteration-1/eval-fix-mode/with_skill/run-1/timing.json +1 -0
  34. package/skills/sync-docs-workspace/iteration-1/eval-fix-mode/without_skill/outputs/result.md +94 -0
  35. package/skills/sync-docs-workspace/iteration-1/eval-fix-mode/without_skill/run-1/grading.json +28 -0
  36. package/skills/sync-docs-workspace/iteration-1/eval-fix-mode/without_skill/run-1/timing.json +1 -0
  37. package/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/eval_metadata.json +27 -0
  38. package/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/with_skill/outputs/result.md +237 -0
  39. package/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/with_skill/run-1/grading.json +28 -0
  40. package/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/with_skill/run-1/timing.json +1 -0
  41. package/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/without_skill/outputs/result.md +134 -0
  42. package/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/without_skill/run-1/grading.json +28 -0
  43. package/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/without_skill/run-1/timing.json +1 -0
  44. package/skills/sync-docs-workspace/iteration-2/benchmark.json +297 -0
  45. package/skills/sync-docs-workspace/iteration-2/benchmark.md +13 -0
  46. package/skills/sync-docs-workspace/iteration-2/eval-doc-audit/eval_metadata.json +27 -0
  47. package/skills/sync-docs-workspace/iteration-2/eval-doc-audit/with_skill/outputs/result.md +137 -0
  48. package/skills/sync-docs-workspace/iteration-2/eval-doc-audit/with_skill/run-1/grading.json +92 -0
  49. package/skills/sync-docs-workspace/iteration-2/eval-doc-audit/with_skill/run-1/timing.json +1 -0
  50. package/skills/sync-docs-workspace/iteration-2/eval-doc-audit/without_skill/outputs/result.md +134 -0
  51. package/skills/sync-docs-workspace/iteration-2/eval-doc-audit/without_skill/run-1/grading.json +86 -0
  52. package/skills/sync-docs-workspace/iteration-2/eval-doc-audit/without_skill/run-1/timing.json +1 -0
  53. package/skills/sync-docs-workspace/iteration-2/eval-fix-mode/eval_metadata.json +27 -0
  54. package/skills/sync-docs-workspace/iteration-2/eval-fix-mode/with_skill/outputs/result.md +193 -0
  55. package/skills/sync-docs-workspace/iteration-2/eval-fix-mode/with_skill/run-1/grading.json +72 -0
  56. package/skills/sync-docs-workspace/iteration-2/eval-fix-mode/with_skill/run-1/timing.json +1 -0
  57. package/skills/sync-docs-workspace/iteration-2/eval-fix-mode/without_skill/outputs/result.md +211 -0
  58. package/skills/sync-docs-workspace/iteration-2/eval-fix-mode/without_skill/run-1/grading.json +91 -0
  59. package/skills/sync-docs-workspace/iteration-2/eval-fix-mode/without_skill/run-1/timing.json +5 -0
  60. package/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/eval_metadata.json +27 -0
  61. package/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/with_skill/outputs/result.md +182 -0
  62. package/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/with_skill/run-1/grading.json +95 -0
  63. package/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/with_skill/run-1/timing.json +1 -0
  64. package/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/without_skill/outputs/result.md +222 -0
  65. package/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/without_skill/run-1/grading.json +88 -0
  66. package/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/without_skill/run-1/timing.json +5 -0
  67. package/skills/sync-docs-workspace/iteration-3/benchmark.json +298 -0
  68. package/skills/sync-docs-workspace/iteration-3/benchmark.md +13 -0
  69. package/skills/sync-docs-workspace/iteration-3/eval-doc-audit/eval_metadata.json +27 -0
  70. package/skills/sync-docs-workspace/iteration-3/eval-doc-audit/with_skill/outputs/result.md +125 -0
  71. package/skills/sync-docs-workspace/iteration-3/eval-doc-audit/with_skill/run-1/grading.json +97 -0
  72. package/skills/sync-docs-workspace/iteration-3/eval-doc-audit/with_skill/run-1/timing.json +5 -0
  73. package/skills/sync-docs-workspace/iteration-3/eval-doc-audit/without_skill/outputs/result.md +144 -0
  74. package/skills/sync-docs-workspace/iteration-3/eval-doc-audit/without_skill/run-1/grading.json +78 -0
  75. package/skills/sync-docs-workspace/iteration-3/eval-doc-audit/without_skill/run-1/timing.json +5 -0
  76. package/skills/sync-docs-workspace/iteration-3/eval-fix-mode/eval_metadata.json +27 -0
  77. package/skills/sync-docs-workspace/iteration-3/eval-fix-mode/with_skill/outputs/result.md +104 -0
  78. package/skills/sync-docs-workspace/iteration-3/eval-fix-mode/with_skill/run-1/grading.json +91 -0
  79. package/skills/sync-docs-workspace/iteration-3/eval-fix-mode/with_skill/run-1/timing.json +5 -0
  80. package/skills/sync-docs-workspace/iteration-3/eval-fix-mode/without_skill/outputs/result.md +79 -0
  81. package/skills/sync-docs-workspace/iteration-3/eval-fix-mode/without_skill/run-1/grading.json +82 -0
  82. package/skills/sync-docs-workspace/iteration-3/eval-fix-mode/without_skill/run-1/timing.json +5 -0
  83. package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/eval_metadata.json +27 -0
  84. package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase1_context.json +302 -0
  85. package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase2_drift.txt +33 -0
  86. package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase3_analysis.json +114 -0
  87. package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase4_fix.txt +118 -0
  88. package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase5_validate.txt +38 -0
  89. package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/result.md +158 -0
  90. package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/run-1/grading.json +95 -0
  91. package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/run-1/timing.json +5 -0
  92. package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/without_skill/outputs/result.md +71 -0
  93. package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/without_skill/run-1/grading.json +90 -0
  94. package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/without_skill/run-1/timing.json +5 -0
  95. package/skills/using-xtrm/SKILL.md +84 -205
  96. package/config/pi/extensions/bg-process/index.ts +0 -230
  97. package/config/pi/extensions/bg-process/package.json +0 -16
  98. package/config/pi/extensions/minimal-mode/index.ts +0 -201
  99. package/config/pi/extensions/minimal-mode/package.json +0 -16
  100. package/config/pi/extensions/todo/index.ts +0 -299
  101. package/config/pi/extensions/todo/package.json +0 -16
  102. package/hooks/agent_context.py +0 -105
  103. package/hooks/branch-state.mjs +0 -39
  104. package/hooks/guard-rules.mjs +0 -118
  105. package/hooks/main-guard-post-push.mjs +0 -71
  106. package/hooks/main-guard.mjs +0 -119
package/cli/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xtrm-cli",
3
- "version": "0.5.10",
3
+ "version": "0.5.13",
4
4
  "description": "Claude Code tools installer (skills, hooks, MCP servers)",
5
5
  "main": "./dist/index.js",
6
6
  "type": "module",
@@ -1,30 +1,94 @@
1
- # XTRM Agent Workflow (Short)
1
+ # XTRM Agent Workflow
2
2
 
3
- This file is an **agent operating manual** (not a project overview).
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
- 1. **Start with scope**
6
- - Clarify task intent if ambiguous.
7
- - Prefer semantic discovery (Serena + GitNexus) over broad grep-first exploration.
6
+ ## Session Start
8
7
 
9
- 2. **Track work in `bd`**
10
- - Use `bd ready --json` / `bd update <id> --claim --json` before edits.
11
- - Create discovered follow-ups with `--deps discovered-from:<id>`.
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
- 3. **Branch per issue (strict)**
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
- 4. **Edit safely**
19
- - Use Serena symbol tools for code changes when possible.
20
- - Run GitNexus impact checks before symbol changes and detect-changes before commit.
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
- 5. **PR merge + return to main**
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
- 6. **Before finishing**
28
- - Run relevant tests/linters.
29
- - Close/update bead state.
30
- - Ensure changes are committed and pushed.
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 (Short)
1
+ # XTRM Agent Workflow
2
2
 
3
- This file is an **agent operating manual** (not a project overview).
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
- 1. **Start with scope**
6
- - Clarify task intent if ambiguous.
7
- - Prefer semantic discovery (Serena + GitNexus) over broad grep-first exploration.
6
+ ## Session Start
8
7
 
9
- 2. **Track work in `bd`**
10
- - Use `bd ready --json` / `bd update <id> --claim --json` before edits.
11
- - Create discovered follow-ups with `--deps discovered-from:<id>`.
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
- 3. **Branch per issue (strict)**
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
- 4. **Edit safely**
19
- - Use Serena symbol tools for code changes when possible.
20
- - Run GitNexus impact checks before symbol changes and detect-changes before commit.
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
- 5. **PR merge + return to main**
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
- 6. **Before finishing**
28
- - Run relevant tests/linters.
29
- - Close/update bead state.
30
- - Ensure changes are committed and pushed.
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>"\` NO → note "nothing to persist"`,
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 statePathFrom(startCwd: string): string {
17
- let current = path.resolve(startCwd || process.cwd());
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 ensured = await ensureWorktreeSessionState(cwd, issueId);
86
- if (ensured.ok) {
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
- if (state.phase === "waiting-merge" || state.phase === "pending-cleanup") {
105
- const pr = state.prNumber != null ? `#${state.prNumber}` : "(pending PR)";
106
- const url = state.prUrl ? ` ${state.prUrl}` : "";
107
- pi.sendUserMessage(
108
- `⚠ PR ${pr}${url} is still pending. xtrm finish is deprecated for Pi workflow. ` +
109
- "Use xtpi publish (when available) and external merge/cleanup steps.",
110
- );
111
- return undefined;
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 (state.phase === "conflicting") {
115
- const files = state.conflictFiles?.length ? state.conflictFiles.join(", ") : "unknown files";
59
+ if (isWorktree(cwd)) {
116
60
  pi.sendUserMessage(
117
- `⚠ Conflicts in: ${files}. xtrm finish is deprecated for Pi workflow. ` +
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
- if (!projectContext) return undefined;
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# Project Intelligence Context\n\n" + projectContext
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>\n' +
22
- ' git add -p && git commit -m "<message>"\n' +
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>\n' +
28
- ' git add -p && git commit -m "<message>"\n' +
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 this session.\n` : '';
60
+ const claimLine = claimId ? `claim \`${claimId}\` was closed.\n` : '';
75
61
  return (
76
- `🧠 Memory gate: ${claimLine}` +
77
- 'For each closed issue, worth persisting?\n' +
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 acknowledge: `touch .beads/.memory-gate-done`\n'
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 Read/Grep/Glob/Bash/Serena tools complete.
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
  }