xtrm-tools 2.1.26 → 2.1.29
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/cli/dist/index.cjs +48 -1
- package/cli/dist/index.cjs.map +1 -1
- package/cli/package.json +1 -1
- package/config/hooks.json +5 -0
- package/config/instructions/agents-top.md +30 -0
- package/config/instructions/claude-top.md +30 -0
- package/config/pi/extensions/custom-footer.ts +16 -14
- package/config/pi/pi-worktrees-settings.json +6 -0
- package/config/pi/settings.json.template +2 -1
- package/hooks/beads-claim-sync.mjs +65 -0
- package/package.json +1 -1
package/cli/package.json
CHANGED
package/config/hooks.json
CHANGED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# XTRM Agent Workflow (Short)
|
|
2
|
+
|
|
3
|
+
This file is an **agent operating manual** (not a project overview).
|
|
4
|
+
|
|
5
|
+
1. **Start with scope**
|
|
6
|
+
- Clarify task intent if ambiguous.
|
|
7
|
+
- Prefer semantic discovery (Serena + GitNexus) over broad grep-first exploration.
|
|
8
|
+
|
|
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>`.
|
|
12
|
+
|
|
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/...`).
|
|
17
|
+
|
|
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.
|
|
21
|
+
|
|
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>`).
|
|
26
|
+
|
|
27
|
+
6. **Before finishing**
|
|
28
|
+
- Run relevant tests/linters.
|
|
29
|
+
- Close/update bead state.
|
|
30
|
+
- Ensure changes are committed and pushed.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# XTRM Agent Workflow (Short)
|
|
2
|
+
|
|
3
|
+
This file is an **agent operating manual** (not a project overview).
|
|
4
|
+
|
|
5
|
+
1. **Start with scope**
|
|
6
|
+
- Clarify task intent if ambiguous.
|
|
7
|
+
- Prefer semantic discovery (Serena + GitNexus) over broad grep-first exploration.
|
|
8
|
+
|
|
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>`.
|
|
12
|
+
|
|
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/...`).
|
|
17
|
+
|
|
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.
|
|
21
|
+
|
|
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>`).
|
|
26
|
+
|
|
27
|
+
6. **Before finishing**
|
|
28
|
+
- Run relevant tests/linters.
|
|
29
|
+
- Close/update bead state.
|
|
30
|
+
- Ensure changes are committed and pushed.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* XTRM Custom Footer Extension
|
|
3
3
|
*
|
|
4
|
-
* Displays: XTRM brand,
|
|
4
|
+
* Displays: XTRM brand, Model, Context%, CWD, Git branch, Beads chip
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
@@ -12,9 +12,6 @@ import * as fs from "node:fs";
|
|
|
12
12
|
import { SubprocessRunner } from "./core/lib";
|
|
13
13
|
|
|
14
14
|
export default function (pi: ExtensionAPI) {
|
|
15
|
-
// Pin session to PID — stable for the life of the Pi process, matches beads.ts
|
|
16
|
-
const SESSION_KEY = process.pid.toString();
|
|
17
|
-
|
|
18
15
|
interface BeadState {
|
|
19
16
|
claimId: string | null;
|
|
20
17
|
shortId: string | null;
|
|
@@ -31,11 +28,12 @@ export default function (pi: ExtensionAPI) {
|
|
|
31
28
|
};
|
|
32
29
|
const STATUS_BG: Record<string, string> = {
|
|
33
30
|
open: "\x1b[48;5;238m",
|
|
34
|
-
in_progress: "\x1b[48;5;
|
|
31
|
+
in_progress: "\x1b[48;5;39m",
|
|
35
32
|
blocked: "\x1b[48;5;88m",
|
|
36
33
|
};
|
|
37
34
|
|
|
38
35
|
let capturedCtx: any = null;
|
|
36
|
+
let sessionId: string = "";
|
|
39
37
|
let beadState: BeadState = { claimId: null, shortId: null, status: null, openCount: 0, lastFetch: 0 };
|
|
40
38
|
let refreshing = false;
|
|
41
39
|
let requestRender: (() => void) | null = null;
|
|
@@ -49,19 +47,20 @@ export default function (pi: ExtensionAPI) {
|
|
|
49
47
|
if (refreshing || Date.now() - beadState.lastFetch < CACHE_TTL) return;
|
|
50
48
|
const cwd = getCwd();
|
|
51
49
|
if (!isBeadsProject(cwd)) return;
|
|
50
|
+
if (!sessionId) return;
|
|
52
51
|
refreshing = true;
|
|
53
52
|
try {
|
|
54
|
-
const claimResult = await SubprocessRunner.run("bd", ["kv", "get", `claimed:${
|
|
53
|
+
const claimResult = await SubprocessRunner.run("bd", ["kv", "get", `claimed:${sessionId}`], { cwd });
|
|
55
54
|
const claimId = claimResult.code === 0 ? claimResult.stdout.trim() || null : null;
|
|
56
55
|
|
|
57
56
|
let status: string | null = null;
|
|
58
57
|
if (claimId) {
|
|
59
58
|
const showResult = await SubprocessRunner.run("bd", ["show", claimId, "--json"], { cwd });
|
|
60
59
|
if (showResult.code === 0) {
|
|
61
|
-
try { status = JSON.parse(showResult.stdout)
|
|
60
|
+
try { status = JSON.parse(showResult.stdout)[0]?.status ?? null; } catch {}
|
|
62
61
|
}
|
|
63
62
|
if (status === "closed") {
|
|
64
|
-
await SubprocessRunner.run("bd", ["kv", "clear", `claimed:${
|
|
63
|
+
await SubprocessRunner.run("bd", ["kv", "clear", `claimed:${sessionId}`], { cwd });
|
|
65
64
|
beadState = { claimId: null, shortId: null, status: null, openCount: beadState.openCount, lastFetch: Date.now() };
|
|
66
65
|
requestRender?.();
|
|
67
66
|
return;
|
|
@@ -96,6 +95,8 @@ export default function (pi: ExtensionAPI) {
|
|
|
96
95
|
|
|
97
96
|
pi.on("session_start", async (_event, ctx) => {
|
|
98
97
|
capturedCtx = ctx;
|
|
98
|
+
// Get session ID from sessionManager (UUID, consistent with hooks)
|
|
99
|
+
sessionId = ctx.sessionManager?.getSessionId?.() ?? process.pid.toString();
|
|
99
100
|
|
|
100
101
|
ctx.ui.setFooter((tui, theme, footerData) => {
|
|
101
102
|
requestRender = () => tui.requestRender();
|
|
@@ -122,15 +123,16 @@ export default function (pi: ExtensionAPI) {
|
|
|
122
123
|
const branchStr = branch ? theme.fg("accent", `⎇ ${branch}`) : "";
|
|
123
124
|
|
|
124
125
|
const modelId = ctx.model?.id || "no-model";
|
|
125
|
-
const
|
|
126
|
+
const modelChip = `\x1b[48;5;238m\x1b[38;5;15m ${modelId} \x1b[0m`;
|
|
126
127
|
|
|
127
128
|
const sep = theme.fg("dim", " | ");
|
|
128
129
|
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
130
|
+
const brandModel = `${brand} ${modelChip}`;
|
|
131
|
+
const leftParts = [brandModel, usageStr, cwdStr];
|
|
132
|
+
|
|
132
133
|
const beadChip = buildBeadChip();
|
|
133
|
-
|
|
134
|
+
const branchWithChip = branchStr ? `${branchStr} ${beadChip}`.trim() : beadChip;
|
|
135
|
+
if (branchWithChip) leftParts.push(branchWithChip);
|
|
134
136
|
|
|
135
137
|
const left = leftParts.join(sep);
|
|
136
138
|
return [truncateToWidth(left, width)];
|
|
@@ -139,7 +141,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
139
141
|
});
|
|
140
142
|
});
|
|
141
143
|
|
|
142
|
-
// Bust the bead cache immediately after any bd write
|
|
144
|
+
// Bust the bead cache immediately after any bd write
|
|
143
145
|
pi.on("tool_result", async (event: any) => {
|
|
144
146
|
const cmd = event?.input?.command;
|
|
145
147
|
if (cmd && /\bbd\s+(close|update|create|claim)\b/.test(cmd)) {
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// beads-claim-sync — PostToolUse hook
|
|
3
|
+
// Auto-sets bd kv claim when bd update --claim is detected.
|
|
4
|
+
// Uses session_id from hook input (UUID, matches Pi's sessionManager.getSessionId())
|
|
5
|
+
|
|
6
|
+
import { spawnSync } from 'node:child_process';
|
|
7
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
|
|
10
|
+
function readInput() {
|
|
11
|
+
try {
|
|
12
|
+
return JSON.parse(readFileSync(0, 'utf-8'));
|
|
13
|
+
} catch {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function isBeadsProject(cwd) {
|
|
19
|
+
return existsSync(join(cwd, '.beads'));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function main() {
|
|
23
|
+
const input = readInput();
|
|
24
|
+
if (!input || input.hook_event_name !== 'PostToolUse') process.exit(0);
|
|
25
|
+
if (input.tool_name !== 'Bash') process.exit(0);
|
|
26
|
+
|
|
27
|
+
const cwd = input.cwd || process.cwd();
|
|
28
|
+
if (!isBeadsProject(cwd)) process.exit(0);
|
|
29
|
+
|
|
30
|
+
const command = input.tool_input?.command || '';
|
|
31
|
+
if (!/\bbd\s+update\b/.test(command) || !/--claim\b/.test(command)) {
|
|
32
|
+
process.exit(0);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Extract issue ID from command
|
|
36
|
+
const match = command.match(/\bbd\s+update\s+(\S+)/);
|
|
37
|
+
if (!match) process.exit(0);
|
|
38
|
+
|
|
39
|
+
const issueId = match[1];
|
|
40
|
+
// Use session_id from hook input (UUID from Pi/Claude Code)
|
|
41
|
+
const sessionId = input.session_id;
|
|
42
|
+
|
|
43
|
+
if (!sessionId) {
|
|
44
|
+
process.stderr.write('Beads claim sync: no session_id in hook input\n');
|
|
45
|
+
process.exit(0);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
spawnSync('bd', ['kv', 'set', `claimed:${sessionId}`, issueId], {
|
|
50
|
+
cwd,
|
|
51
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
52
|
+
timeout: 5000,
|
|
53
|
+
});
|
|
54
|
+
process.stdout.write(JSON.stringify({
|
|
55
|
+
additionalContext: `\n✅ **Beads**: Session \`${sessionId}\` claimed issue \`${issueId}\`.`,
|
|
56
|
+
}));
|
|
57
|
+
process.stdout.write('\n');
|
|
58
|
+
} catch (err) {
|
|
59
|
+
process.stderr.write(`Beads claim sync warning: ${err.message}\n`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
process.exit(0);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
main();
|