xtrm-tools 0.7.7 → 0.7.10

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 (123) hide show
  1. package/.xtrm/config/hooks.json +0 -3
  2. package/.xtrm/registry.json +537 -565
  3. package/.xtrm/skills/default/gitnexus-cli/SKILL.md +82 -0
  4. package/.xtrm/skills/default/gitnexus-exploring/SKILL.md +78 -0
  5. package/.xtrm/skills/default/gitnexus-guide/SKILL.md +64 -0
  6. package/.xtrm/skills/default/init-session/SKILL.md +3 -0
  7. package/.xtrm/skills/default/last30days/SKILL.md +1 -1
  8. package/.xtrm/skills/default/last30days/scripts/lib/youtube_yt.py +59 -40
  9. package/.xtrm/skills/default/sync-docs/references/doc-structure.md +1 -1
  10. package/.xtrm/skills/default/sync-docs/references/schema.md +1 -1
  11. package/.xtrm/skills/default/sync-docs/scripts/doc_structure_analyzer.py +2 -2
  12. package/.xtrm/skills/default/using-specialists/SKILL.md +346 -138
  13. package/.xtrm/skills/default/using-specialists/SKILL.safe.md +1082 -0
  14. package/.xtrm/skills/default/using-specialists/SKILL.ultra.md +1082 -0
  15. package/.xtrm/skills/default/vaultctl/SKILL.md +150 -0
  16. package/CHANGELOG.md +4 -4
  17. package/cli/dist/index.cjs +328 -192
  18. package/cli/dist/index.cjs.map +1 -1
  19. package/cli/package.json +1 -1
  20. package/package.json +8 -8
  21. package/packages/pi-extensions/MIGRATION_NOTES.md +39 -0
  22. package/packages/pi-extensions/README.md +43 -0
  23. package/packages/pi-extensions/extensions/README.md +5 -0
  24. package/{.xtrm/config/pi → packages/pi-extensions}/extensions/beads/index.ts +1 -1
  25. package/{.xtrm/config/pi → packages/pi-extensions}/extensions/beads/package.json +1 -4
  26. package/{.xtrm/config/pi → packages/pi-extensions}/extensions/custom-footer/index.ts +1 -1
  27. package/{.xtrm/config/pi → packages/pi-extensions}/extensions/custom-footer/package.json +1 -4
  28. package/packages/pi-extensions/extensions/custom-provider-qwen-cli/package.json +16 -0
  29. package/{.xtrm/config/pi → packages/pi-extensions}/extensions/pi-serena-compact/package.json +9 -2
  30. package/{.xtrm/ext-src → packages/pi-extensions/extensions}/quality-gates/index.ts +1 -1
  31. package/{.xtrm/config/pi → packages/pi-extensions}/extensions/quality-gates/package.json +1 -4
  32. package/{.xtrm/config/pi → packages/pi-extensions}/extensions/service-skills/index.ts +1 -1
  33. package/{.xtrm/ext-src → packages/pi-extensions/extensions}/service-skills/package.json +1 -4
  34. package/{.xtrm/ext-src → packages/pi-extensions/extensions}/session-flow/index.ts +1 -1
  35. package/{.xtrm/config/pi → packages/pi-extensions}/extensions/session-flow/package.json +1 -4
  36. package/{.xtrm/config/pi → packages/pi-extensions}/extensions/xtrm-loader/index.ts +1 -1
  37. package/{.xtrm/config/pi → packages/pi-extensions}/extensions/xtrm-loader/package.json +1 -4
  38. package/{.xtrm/config/pi → packages/pi-extensions}/extensions/xtrm-ui/index.ts +1 -1
  39. package/packages/pi-extensions/package.json +46 -0
  40. package/packages/pi-extensions/src/core/README.md +9 -0
  41. package/{.xtrm/ext-src/core/lib.ts → packages/pi-extensions/src/core/index.ts} +3 -1
  42. package/packages/pi-extensions/src/extensions/auto-session-name.ts +3 -0
  43. package/packages/pi-extensions/src/extensions/auto-update.ts +3 -0
  44. package/packages/pi-extensions/src/extensions/beads.ts +3 -0
  45. package/packages/pi-extensions/src/extensions/compact-header.ts +3 -0
  46. package/packages/pi-extensions/src/extensions/custom-footer.ts +3 -0
  47. package/packages/pi-extensions/src/extensions/custom-provider-qwen-cli.ts +3 -0
  48. package/packages/pi-extensions/src/extensions/git-checkpoint.ts +3 -0
  49. package/packages/pi-extensions/src/extensions/lsp-bootstrap.ts +3 -0
  50. package/packages/pi-extensions/src/extensions/pi-serena-compact.ts +3 -0
  51. package/packages/pi-extensions/src/extensions/quality-gates.ts +3 -0
  52. package/packages/pi-extensions/src/extensions/service-skills.ts +3 -0
  53. package/packages/pi-extensions/src/extensions/session-flow.ts +3 -0
  54. package/packages/pi-extensions/src/extensions/xtrm-loader.ts +3 -0
  55. package/packages/pi-extensions/src/extensions/xtrm-ui.ts +3 -0
  56. package/packages/pi-extensions/src/index.ts +9 -0
  57. package/packages/pi-extensions/src/registry.ts +52 -0
  58. package/packages/pi-extensions/src/shared/index.ts +1 -0
  59. package/packages/pi-extensions/src/shared/legacy-path-map.ts +23 -0
  60. package/.xtrm/config/pi/extensions/core/package.json +0 -18
  61. package/.xtrm/config/pi/extensions/custom-provider-qwen-cli/package.json +0 -1
  62. package/.xtrm/config/pi/extensions/quality-gates/index.ts +0 -66
  63. package/.xtrm/config/pi/extensions/service-skills/package.json +0 -19
  64. package/.xtrm/config/pi/extensions/session-flow/index.ts +0 -96
  65. package/.xtrm/config/pi/extensions/xtrm-ui/themes/pidex-dark.json +0 -89
  66. package/.xtrm/config/pi/extensions/xtrm-ui/themes/pidex-light.json +0 -89
  67. package/.xtrm/ext-src/auto-session-name/index.ts +0 -29
  68. package/.xtrm/ext-src/auto-session-name/package.json +0 -16
  69. package/.xtrm/ext-src/auto-update/index.ts +0 -71
  70. package/.xtrm/ext-src/auto-update/package.json +0 -16
  71. package/.xtrm/ext-src/beads/index.ts +0 -232
  72. package/.xtrm/ext-src/beads/package.json +0 -19
  73. package/.xtrm/ext-src/compact-header/index.ts +0 -69
  74. package/.xtrm/ext-src/compact-header/package.json +0 -16
  75. package/.xtrm/ext-src/core/adapter.ts +0 -52
  76. package/.xtrm/ext-src/core/guard-rules.ts +0 -100
  77. package/.xtrm/ext-src/core/logger.ts +0 -45
  78. package/.xtrm/ext-src/core/package.json +0 -18
  79. package/.xtrm/ext-src/core/runner.ts +0 -71
  80. package/.xtrm/ext-src/core/session-state.ts +0 -59
  81. package/.xtrm/ext-src/custom-footer/index.ts +0 -398
  82. package/.xtrm/ext-src/custom-footer/package.json +0 -19
  83. package/.xtrm/ext-src/custom-provider-qwen-cli/index.ts +0 -363
  84. package/.xtrm/ext-src/custom-provider-qwen-cli/package.json +0 -1
  85. package/.xtrm/ext-src/git-checkpoint/index.ts +0 -53
  86. package/.xtrm/ext-src/git-checkpoint/package.json +0 -16
  87. package/.xtrm/ext-src/lsp-bootstrap/index.ts +0 -134
  88. package/.xtrm/ext-src/lsp-bootstrap/package.json +0 -17
  89. package/.xtrm/ext-src/pi-serena-compact/index.ts +0 -121
  90. package/.xtrm/ext-src/pi-serena-compact/package.json +0 -16
  91. package/.xtrm/ext-src/quality-gates/package.json +0 -19
  92. package/.xtrm/ext-src/service-skills/index.ts +0 -108
  93. package/.xtrm/ext-src/session-flow/package.json +0 -19
  94. package/.xtrm/ext-src/xtrm-loader/index.ts +0 -152
  95. package/.xtrm/ext-src/xtrm-loader/package.json +0 -19
  96. package/.xtrm/ext-src/xtrm-ui/format.ts +0 -282
  97. package/.xtrm/ext-src/xtrm-ui/index.ts +0 -1112
  98. package/.xtrm/ext-src/xtrm-ui/package.json +0 -21
  99. /package/.xtrm/{ext-src → config/pi/extensions}/custom-footer/.pi/structured-returns/83051fe4-97da-4e2c-bdaa-343b32f4e714.combined.log +0 -0
  100. /package/.xtrm/{ext-src → config/pi/extensions}/custom-footer/.pi/structured-returns/83051fe4-97da-4e2c-bdaa-343b32f4e714.stderr.log +0 -0
  101. /package/.xtrm/{ext-src → config/pi/extensions}/custom-footer/.pi/structured-returns/83051fe4-97da-4e2c-bdaa-343b32f4e714.stdout.log +0 -0
  102. /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/auto-session-name/index.ts +0 -0
  103. /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/auto-session-name/package.json +0 -0
  104. /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/auto-update/index.ts +0 -0
  105. /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/auto-update/package.json +0 -0
  106. /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/compact-header/index.ts +0 -0
  107. /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/compact-header/package.json +0 -0
  108. /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/custom-provider-qwen-cli/index.ts +0 -0
  109. /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/git-checkpoint/index.ts +0 -0
  110. /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/git-checkpoint/package.json +0 -0
  111. /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/lsp-bootstrap/index.ts +0 -0
  112. /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/lsp-bootstrap/package.json +0 -0
  113. /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/pi-serena-compact/index.ts +0 -0
  114. /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/xtrm-ui/format.ts +0 -0
  115. /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/xtrm-ui/package.json +0 -0
  116. /package/{.xtrm/config/pi/extensions → packages/pi-extensions/src}/core/adapter.ts +0 -0
  117. /package/{.xtrm/config/pi/extensions → packages/pi-extensions/src}/core/guard-rules.ts +0 -0
  118. /package/{.xtrm/config/pi/extensions → packages/pi-extensions/src}/core/lib.ts +0 -0
  119. /package/{.xtrm/config/pi/extensions → packages/pi-extensions/src}/core/logger.ts +0 -0
  120. /package/{.xtrm/config/pi/extensions → packages/pi-extensions/src}/core/runner.ts +0 -0
  121. /package/{.xtrm/config/pi/extensions → packages/pi-extensions/src}/core/session-state.ts +0 -0
  122. /package/{.xtrm/ext-src/xtrm-ui/themes → packages/pi-extensions/themes/xtrm-ui}/pidex-dark.json +0 -0
  123. /package/{.xtrm/ext-src/xtrm-ui/themes → packages/pi-extensions/themes/xtrm-ui}/pidex-light.json +0 -0
@@ -1,398 +0,0 @@
1
- /**
2
- * XTRM Custom Footer Extension
3
- *
4
- * Layout:
5
- * Line 1: ~/path (branch *+↑) — with git status flags, no session name
6
- * Line 2: XX%/window | (provider) model • thinking — simplified stats
7
- * Line 3: ◐ 4843.5 Rework project bootstrap... — beads claim or ○ 6 open
8
- */
9
-
10
- import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
11
- import { truncateToWidth, visibleWidth } from "@mariozechner/pi-tui";
12
-
13
- import { SubprocessRunner, EventAdapter } from "@xtrm/pi-core";
14
-
15
- export default function (pi: ExtensionAPI) {
16
- interface BeadClaim {
17
- id: string;
18
- shortId: string;
19
- title: string | null;
20
- status: string;
21
- }
22
-
23
- interface BeadState {
24
- claims: BeadClaim[];
25
- openCount: number;
26
- lastFetch: number;
27
- }
28
-
29
- interface RuntimeState {
30
- branch: string | null;
31
- gitStatus: string;
32
- lastFetch: number;
33
- }
34
-
35
- const STATUS_ICONS: Record<string, string> = {
36
- open: "○",
37
- in_progress: "◐",
38
- blocked: "●",
39
- closed: "✓",
40
- };
41
-
42
- // Chip background colours (raw ANSI — theme has no bg() API)
43
- const CHIP_BG_NEUTRAL = "\x1b[48;5;238m";
44
- const CHIP_BG_ACTIVE = "\x1b[48;5;39m";
45
- const CHIP_BG_BLOCKED = "\x1b[48;5;88m";
46
- const CHIP_FG = "\x1b[38;5;15m";
47
- const CHIP_RESET = "\x1b[0m";
48
-
49
- const STATUS_BG: Record<string, string> = {
50
- open: CHIP_BG_NEUTRAL,
51
- in_progress: CHIP_BG_ACTIVE,
52
- blocked: CHIP_BG_BLOCKED,
53
- };
54
-
55
- const chip = (text: string, bg = CHIP_BG_NEUTRAL): string => `${bg}${CHIP_FG} ${text} ${CHIP_RESET}`;
56
-
57
- let capturedPi: ExtensionAPI = pi;
58
- let capturedCtx: any = null;
59
- let requestRender: (() => void) | null = null;
60
-
61
- const CACHE_TTL = 5000;
62
- let refreshingBeads = false;
63
- let refreshingRuntime = false;
64
-
65
- let beadState: BeadState = {
66
- claims: [],
67
- openCount: 0,
68
- lastFetch: 0,
69
- };
70
-
71
- let runtimeState: RuntimeState = {
72
- branch: null,
73
- gitStatus: "",
74
- lastFetch: 0,
75
- };
76
-
77
- const getCwd = () => capturedCtx?.cwd || process.cwd();
78
- const getShortId = (id: string) => id.split("-").pop() ?? id;
79
-
80
- /**
81
- * Parse git status --porcelain output into status flags
82
- */
83
- const parseGitFlags = (porcelain: string): string => {
84
- let modified = false;
85
- let staged = false;
86
- let deleted = false;
87
- for (const line of porcelain.split("\n").filter(Boolean)) {
88
- if (/^ M|^AM|^MM/.test(line)) modified = true;
89
- if (/^A |^M /.test(line)) staged = true;
90
- if (/^ D|^D /.test(line)) deleted = true;
91
- }
92
- return `${modified ? "*" : ""}${staged ? "+" : ""}${deleted ? "-" : ""}`;
93
- };
94
-
95
- /**
96
- * Fetch git branch and status
97
- */
98
- const refreshRuntimeState = async () => {
99
- if (refreshingRuntime || Date.now() - runtimeState.lastFetch < CACHE_TTL) return;
100
- refreshingRuntime = true;
101
- const cwd = getCwd();
102
- try {
103
- let branch: string | null = null;
104
- let gitStatus = "";
105
-
106
- const rootResult = await SubprocessRunner.run("git", ["rev-parse", "--show-toplevel"], { cwd });
107
- const repoRoot = rootResult.code === 0 ? rootResult.stdout.trim() : null;
108
-
109
- if (repoRoot) {
110
- const branchResult = await SubprocessRunner.run("git", ["branch", "--show-current"], { cwd });
111
- branch = branchResult.code === 0 ? branchResult.stdout.trim() || null : null;
112
-
113
- const porcelainResult = await SubprocessRunner.run(
114
- "git",
115
- ["--no-optional-locks", "status", "--porcelain"],
116
- { cwd },
117
- );
118
- const baseFlags = porcelainResult.code === 0 ? parseGitFlags(porcelainResult.stdout) : "";
119
-
120
- let upstreamFlags = "";
121
- const abResult = await SubprocessRunner.run(
122
- "git",
123
- ["--no-optional-locks", "rev-list", "--left-right", "--count", "@{upstream}...HEAD"],
124
- { cwd },
125
- );
126
- if (abResult.code === 0) {
127
- const [behindRaw, aheadRaw] = abResult.stdout.trim().split(/\s+/);
128
- const behind = Number(behindRaw || 0);
129
- const ahead = Number(aheadRaw || 0);
130
- if (ahead > 0 && behind > 0) upstreamFlags = "↕";
131
- else if (ahead > 0) upstreamFlags = "↑";
132
- else if (behind > 0) upstreamFlags = "↓";
133
- }
134
-
135
- gitStatus = `${baseFlags}${upstreamFlags}`;
136
- }
137
-
138
- runtimeState = {
139
- branch,
140
- gitStatus,
141
- lastFetch: Date.now(),
142
- };
143
- requestRender?.();
144
- } catch {
145
- // Fail soft — keep last known runtime state.
146
- } finally {
147
- refreshingRuntime = false;
148
- }
149
- };
150
-
151
- /**
152
- * Format token counts (from original footer)
153
- */
154
- const formatTokens = (count: number): string => {
155
- if (count < 1000) return count.toString();
156
- if (count < 10000) return `${(count / 1000).toFixed(1)}k`;
157
- if (count < 1000000) return `${Math.round(count / 1000)}k`;
158
- if (count < 10000000) return `${(count / 1000000).toFixed(1)}M`;
159
- return `${Math.round(count / 1000000)}M`;
160
- };
161
-
162
- const refreshBeadState = async () => {
163
- if (refreshingBeads || Date.now() - beadState.lastFetch < CACHE_TTL) return;
164
- const cwd = getCwd();
165
- if (!EventAdapter.isBeadsProject(cwd)) return;
166
- refreshingBeads = true;
167
- try {
168
- const inProgressResult = await SubprocessRunner.run("bd", ["list", "--status=in_progress"], { cwd });
169
- const inProgressRaw = inProgressResult.code === 0 ? inProgressResult.stdout : "";
170
- const ids = [...new Set([...inProgressRaw.matchAll(/^◐\s+([a-z][\w-]+)/gm)].map((m) => m[1]).filter((id) => id.includes("-")))];
171
-
172
- let claims: BeadClaim[] = [];
173
- if (ids.length === 1) {
174
- const [id] = ids;
175
- const showResult = await SubprocessRunner.run("bd", ["show", id, "--json"], { cwd });
176
- if (showResult.code === 0) {
177
- try {
178
- const issue = JSON.parse(showResult.stdout)?.[0];
179
- claims = [{ id, shortId: getShortId(id), title: issue?.title ?? null, status: issue?.status ?? "in_progress" }];
180
- } catch {
181
- claims = [{ id, shortId: getShortId(id), title: null, status: "in_progress" }];
182
- }
183
- } else {
184
- claims = [{ id, shortId: getShortId(id), title: null, status: "in_progress" }];
185
- }
186
- } else if (ids.length > 1) {
187
- claims = ids.map((id) => ({ id, shortId: getShortId(id), title: null, status: "in_progress" }));
188
- }
189
-
190
- let openCount = 0;
191
- if (claims.length === 0) {
192
- const listResult = await SubprocessRunner.run("bd", ["list"], { cwd });
193
- if (listResult.code === 0) {
194
- const m = listResult.stdout.match(/\((\d+)\s+open/);
195
- if (m) openCount = parseInt(m[1], 10);
196
- }
197
- }
198
-
199
- beadState = {
200
- claims,
201
- openCount,
202
- lastFetch: Date.now(),
203
- };
204
- requestRender?.();
205
- } catch {
206
- // Fail soft — keep last known beads state.
207
- } finally {
208
- refreshingBeads = false;
209
- }
210
- };
211
-
212
- /**
213
- * Build beads line: ◐ 4843.5 Rework project bootstrap... or ○ 6 open
214
- */
215
- const buildBeadsLine = (width: number, theme: any): string => {
216
- const { claims, openCount } = beadState;
217
-
218
- if (claims.length === 1) {
219
- const [{ shortId, title, status }] = claims;
220
- const icon = STATUS_ICONS[status] ?? "◐";
221
- const idChip = chip(`${icon} ${shortId}`, STATUS_BG[status] ?? CHIP_BG_NEUTRAL);
222
- const cappedTitle = title ? (title.length > 40 ? `${title.slice(0, 39)}…` : title) : "";
223
- const line = cappedTitle ? `${idChip} ${theme.fg("muted", cappedTitle)}` : idChip;
224
- return truncateToWidth(line, width);
225
- }
226
-
227
- if (claims.length > 1) {
228
- const chips = claims.map(({ shortId, status }) => {
229
- const icon = STATUS_ICONS[status] ?? "◐";
230
- return chip(`${icon} ${shortId}`, STATUS_BG[status] ?? CHIP_BG_ACTIVE);
231
- });
232
- return truncateToWidth(chips.join(" "), width);
233
- }
234
-
235
- if (openCount > 0) {
236
- return truncateToWidth(`○ ${openCount} open`, width);
237
- }
238
-
239
- return truncateToWidth(`○ no open issues`, width);
240
- };
241
-
242
- let footerReapplyTimer: ReturnType<typeof setTimeout> | null = null;
243
-
244
- const applyCustomFooter = (ctx: any) => {
245
- capturedCtx = ctx;
246
- ctx.ui.setFooter((tui, theme, footerData) => {
247
- requestRender = () => tui.requestRender();
248
- const unsub = footerData.onBranchChange(() => {
249
- runtimeState.lastFetch = 0;
250
- tui.requestRender();
251
- });
252
-
253
- return {
254
- dispose() {
255
- unsub();
256
- requestRender = null;
257
- },
258
- invalidate() {},
259
- render(width: number): string[] {
260
- refreshRuntimeState().catch(() => {});
261
- refreshBeadState().catch(() => {});
262
-
263
- // === LINE 1: ~/path (branch *+↑) ===
264
- // Like original, no session name, but with git status flags
265
- let pwd = process.cwd();
266
- const home = process.env.HOME || process.env.USERPROFILE;
267
- if (home && pwd.startsWith(home)) {
268
- pwd = `~${pwd.slice(home.length)}`;
269
- }
270
-
271
- // Use runtimeState branch (with git status) or fallback to footerData
272
- const branch = runtimeState.branch || footerData.getGitBranch();
273
- if (branch) {
274
- const branchWithStatus = runtimeState.gitStatus
275
- ? `${branch} ${runtimeState.gitStatus}`
276
- : branch;
277
- pwd = `${pwd} (${branchWithStatus})`;
278
- }
279
-
280
- const pwdLine = truncateToWidth(theme.fg("dim", pwd), width, theme.fg("dim", "..."));
281
-
282
- // === LINE 2: XX%/window (provider) model • thinking ===
283
- const usage = ctx.getContextUsage();
284
- const model = ctx.model;
285
-
286
- const contextWindow = usage?.contextWindow ?? model?.contextWindow ?? 0;
287
- const contextPercentValue = usage?.percent ?? 0;
288
- const contextPercent = usage?.percent !== null ? contextPercentValue.toFixed(1) : "?";
289
-
290
- // Build left side: context %/window (color-coded like original)
291
- const contextDisplay =
292
- contextPercent === "?"
293
- ? `?/${formatTokens(contextWindow)}`
294
- : `${contextPercent}%/${formatTokens(contextWindow)}`;
295
-
296
- const colorizeUsage = (text: string) => {
297
- if (contextPercentValue > 90) return theme.fg("error", text);
298
- if (contextPercentValue > 70) return theme.fg("warning", text);
299
- return text;
300
- };
301
-
302
- // Build right side: (provider) model • thinking
303
- const modelName = model?.id || "no-model";
304
- const providerCount = footerData.getAvailableProviderCount();
305
-
306
- // Thinking level if model supports reasoning
307
- let rightSideWithoutProvider = modelName;
308
- if (model?.reasoning) {
309
- const thinkingLevel = capturedPi.getThinkingLevel() || "off";
310
- rightSideWithoutProvider =
311
- thinkingLevel === "off" ? `${modelName} • thinking off` : `${modelName} • ${thinkingLevel}`;
312
- }
313
-
314
- // Prepend provider if >1
315
- let rightSide = rightSideWithoutProvider;
316
- if (providerCount > 1 && model) {
317
- rightSide = `(${model.provider}) ${rightSideWithoutProvider}`;
318
- if (visibleWidth(contextDisplay) + 3 + visibleWidth(rightSide) > width) {
319
- rightSide = rightSideWithoutProvider;
320
- }
321
- }
322
-
323
- // Keep provider/model adjacent to usage (no right-bound alignment)
324
- const separator = " ";
325
- const leftWidth = visibleWidth(contextDisplay);
326
- const separatorWidth = visibleWidth(separator);
327
-
328
- let line2: string;
329
- if (leftWidth >= width) {
330
- line2 = colorizeUsage(truncateToWidth(contextDisplay, width, ""));
331
- } else {
332
- const availableForRight = Math.max(0, width - leftWidth - separatorWidth);
333
- const truncatedRight = truncateToWidth(rightSide, availableForRight, "");
334
- line2 = `${colorizeUsage(contextDisplay)}${theme.fg("dim", separator)}${theme.fg("dim", truncatedRight)}`;
335
- }
336
-
337
- // === LINE 3: ◐ 4843.5 Rework project bootstrap... ===
338
- const line3 = buildBeadsLine(width, theme);
339
-
340
- return [pwdLine, line2, line3];
341
- },
342
- };
343
- });
344
- };
345
-
346
- const scheduleFooterReapply = (ctx: any, delayMs = 40) => {
347
- if (footerReapplyTimer) clearTimeout(footerReapplyTimer);
348
- footerReapplyTimer = setTimeout(() => {
349
- applyCustomFooter(ctx);
350
- footerReapplyTimer = null;
351
- }, delayMs);
352
- };
353
-
354
- pi.on("session_start", async (_event, ctx) => {
355
- capturedCtx = ctx;
356
- runtimeState.lastFetch = 0;
357
- beadState.lastFetch = 0;
358
- applyCustomFooter(ctx);
359
- scheduleFooterReapply(ctx);
360
- });
361
-
362
- pi.on("session_switch", async (_event, ctx) => {
363
- runtimeState.lastFetch = 0;
364
- scheduleFooterReapply(ctx);
365
- });
366
-
367
- pi.on("session_fork", async (_event, ctx) => {
368
- runtimeState.lastFetch = 0;
369
- scheduleFooterReapply(ctx);
370
- });
371
-
372
- pi.on("model_select", async (_event, ctx) => {
373
- scheduleFooterReapply(ctx);
374
- });
375
-
376
- pi.on("session_shutdown", async () => {
377
- if (footerReapplyTimer) {
378
- clearTimeout(footerReapplyTimer);
379
- footerReapplyTimer = null;
380
- }
381
- });
382
-
383
- // Bust caches immediately after relevant writes
384
- pi.on("tool_result", async (event: any) => {
385
- const cmd = event?.input?.command;
386
- if (!cmd) return undefined;
387
-
388
- if (/\bbd\s+(close|update|create|claim)\b/.test(cmd)) {
389
- beadState.lastFetch = 0;
390
- setTimeout(() => refreshBeadState().catch(() => {}), 200);
391
- }
392
- if (/\bgit\s+/.test(cmd)) {
393
- runtimeState.lastFetch = 0;
394
- setTimeout(() => refreshRuntimeState().catch(() => {}), 200);
395
- }
396
- return undefined;
397
- });
398
- }
@@ -1,19 +0,0 @@
1
- {
2
- "name": "@xtrm/pi-custom-footer",
3
- "version": "1.0.0",
4
- "description": "xtrm Pi extension: custom-footer",
5
- "type": "module",
6
- "exports": {
7
- ".": "./index.ts"
8
- },
9
- "keywords": [
10
- "pi",
11
- "extension",
12
- "xtrm"
13
- ],
14
- "author": "xtrm",
15
- "license": "MIT",
16
- "dependencies": {
17
- "@xtrm/pi-core": "^1.0.0"
18
- }
19
- }