@spences10/pi-footer 0.0.1 → 0.0.3

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 (47) hide show
  1. package/README.md +16 -0
  2. package/dist/commands/footer-command.d.ts +3 -0
  3. package/dist/commands/footer-command.js +202 -0
  4. package/dist/commands/footer-command.js.map +1 -0
  5. package/dist/config.d.ts +4 -0
  6. package/dist/config.js +47 -0
  7. package/dist/config.js.map +1 -0
  8. package/dist/extension/install.d.ts +4 -0
  9. package/dist/extension/install.js +21 -0
  10. package/dist/extension/install.js.map +1 -0
  11. package/dist/index.d.ts +7 -5
  12. package/dist/index.js +12 -264
  13. package/dist/index.js.map +1 -1
  14. package/dist/model/footer-model.d.ts +21 -0
  15. package/dist/model/footer-model.js +94 -0
  16. package/dist/model/footer-model.js.map +1 -0
  17. package/dist/model/git.d.ts +11 -0
  18. package/dist/model/git.js +83 -0
  19. package/dist/model/git.js.map +1 -0
  20. package/dist/model/thinking.d.ts +4 -0
  21. package/dist/model/thinking.js +34 -0
  22. package/dist/model/thinking.js.map +1 -0
  23. package/dist/presets/types.d.ts +23 -0
  24. package/dist/presets/types.js +51 -0
  25. package/dist/presets/types.js.map +1 -0
  26. package/dist/reference/research.d.ts +6 -0
  27. package/dist/reference/research.js +50 -0
  28. package/dist/reference/research.js.map +1 -0
  29. package/dist/render/footer-lines.d.ts +4 -0
  30. package/dist/render/footer-lines.js +117 -0
  31. package/dist/render/footer-lines.js.map +1 -0
  32. package/dist/render/preview.d.ts +6 -0
  33. package/dist/render/preview.js +34 -0
  34. package/dist/render/preview.js.map +1 -0
  35. package/dist/render/status-line.d.ts +3 -0
  36. package/dist/render/status-line.js +32 -0
  37. package/dist/render/status-line.js.map +1 -0
  38. package/dist/test-utils.d.ts +5 -0
  39. package/dist/test-utils.js +46 -0
  40. package/dist/test-utils.js.map +1 -0
  41. package/dist/theme/tokens.d.ts +16 -0
  42. package/dist/theme/tokens.js +26 -0
  43. package/dist/theme/tokens.js.map +1 -0
  44. package/dist/utils/text.d.ts +3 -0
  45. package/dist/utils/text.js +23 -0
  46. package/dist/utils/text.js.map +1 -0
  47. package/package.json +6 -6
@@ -0,0 +1,32 @@
1
+ import { truncateToWidth, visibleWidth, } from '@earendil-works/pi-tui';
2
+ import { muted, themed_text, } from '../theme/tokens.js';
3
+ import { sanitize_status_text } from '../utils/text.js';
4
+ export function render_footer_status_line(theme, width, left_items, right_item, tone = 'muted') {
5
+ const left = sanitize_status_text(left_items.join(' '));
6
+ const right = right_item ? sanitize_status_text(right_item) : '';
7
+ if (!left && !right)
8
+ return undefined;
9
+ if (!right) {
10
+ return truncateToWidth(themed_text(theme, tone, left), width, muted(theme, '...'));
11
+ }
12
+ if (!left) {
13
+ const themed_right = themed_text(theme, tone, right);
14
+ const right_width = visibleWidth(themed_right);
15
+ return right_width >= width
16
+ ? truncateToWidth(themed_right, width, muted(theme, '...'))
17
+ : `${' '.repeat(width - right_width)}${themed_right}`;
18
+ }
19
+ const right_width = visibleWidth(right);
20
+ if (right_width >= width) {
21
+ return truncateToWidth(themed_text(theme, tone, right), width, muted(theme, '...'));
22
+ }
23
+ const min_gap = 1;
24
+ const available_left = Math.max(0, width - right_width - min_gap);
25
+ const truncated_left = truncateToWidth(left, available_left, '...');
26
+ const left_width = visibleWidth(truncated_left);
27
+ const gap = Math.max(min_gap, width - left_width - right_width);
28
+ return (themed_text(theme, tone, truncated_left) +
29
+ ' '.repeat(gap) +
30
+ themed_text(theme, tone, right));
31
+ }
32
+ //# sourceMappingURL=status-line.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status-line.js","sourceRoot":"","sources":["../../src/render/status-line.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,eAAe,EACf,YAAY,GACZ,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACN,KAAK,EACL,WAAW,GAEX,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAExD,MAAM,UAAU,yBAAyB,CACxC,KAAkB,EAClB,KAAa,EACb,UAAoB,EACpB,UAAmB,EACnB,OAAmB,OAAO;IAE1B,MAAM,IAAI,GAAG,oBAAoB,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACxD,MAAM,KAAK,GAAG,UAAU,CAAC,CAAC,CAAC,oBAAoB,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACjE,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IACtC,IAAI,CAAC,KAAK,EAAE,CAAC;QACZ,OAAO,eAAe,CACrB,WAAW,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,EAC9B,KAAK,EACL,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,CACnB,CAAC;IACH,CAAC;IACD,IAAI,CAAC,IAAI,EAAE,CAAC;QACX,MAAM,YAAY,GAAG,WAAW,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;QACrD,MAAM,WAAW,GAAG,YAAY,CAAC,YAAY,CAAC,CAAC;QAC/C,OAAO,WAAW,IAAI,KAAK;YAC1B,CAAC,CAAC,eAAe,CAAC,YAAY,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;YAC3D,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,GAAG,WAAW,CAAC,GAAG,YAAY,EAAE,CAAC;IACxD,CAAC;IAED,MAAM,WAAW,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IACxC,IAAI,WAAW,IAAI,KAAK,EAAE,CAAC;QAC1B,OAAO,eAAe,CACrB,WAAW,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,EAC/B,KAAK,EACL,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,CACnB,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAG,CAAC,CAAC;IAClB,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,WAAW,GAAG,OAAO,CAAC,CAAC;IAClE,MAAM,cAAc,GAAG,eAAe,CAAC,IAAI,EAAE,cAAc,EAAE,KAAK,CAAC,CAAC;IACpE,MAAM,UAAU,GAAG,YAAY,CAAC,cAAc,CAAC,CAAC;IAChD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,GAAG,UAAU,GAAG,WAAW,CAAC,CAAC;IAChE,OAAO,CACN,WAAW,CAAC,KAAK,EAAE,IAAI,EAAE,cAAc,CAAC;QACxC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC;QACf,WAAW,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,CAC/B,CAAC;AACH,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { ExtensionContext, ReadonlyFooterDataProvider } from '@earendil-works/pi-coding-agent';
2
+ import type { FooterTheme } from './theme/tokens.js';
3
+ export declare const test_theme: FooterTheme;
4
+ export declare function make_footer_data(overrides?: Partial<ReadonlyFooterDataProvider>): ReadonlyFooterDataProvider;
5
+ export declare function make_context(overrides?: Record<string, unknown>): ExtensionContext;
@@ -0,0 +1,46 @@
1
+ import { vi } from 'vitest';
2
+ export const test_theme = {
3
+ fg: vi.fn((color, text) => `<${color}>${text}</${color}>`),
4
+ bold: vi.fn((text) => `**${text}**`),
5
+ };
6
+ export function make_footer_data(overrides = {}) {
7
+ return {
8
+ getGitBranch: vi.fn(() => 'main'),
9
+ getAvailableProviderCount: vi.fn(() => 1),
10
+ getExtensionStatuses: vi.fn(() => new Map()),
11
+ onBranchChange: vi.fn(() => vi.fn()),
12
+ ...overrides,
13
+ };
14
+ }
15
+ export function make_context(overrides = {}) {
16
+ return {
17
+ hasUI: true,
18
+ cwd: '/home/scott/repos/my-pi',
19
+ model: {
20
+ id: 'claude-sonnet',
21
+ provider: 'anthropic',
22
+ contextWindow: 200_000,
23
+ reasoning: true,
24
+ },
25
+ modelRegistry: {
26
+ isUsingOAuth: vi.fn(() => false),
27
+ },
28
+ sessionManager: {
29
+ getEntries: vi.fn(() => []),
30
+ getSessionName: vi.fn(() => 'test-session'),
31
+ },
32
+ getContextUsage: vi.fn(() => ({
33
+ tokens: 50_000,
34
+ contextWindow: 200_000,
35
+ percent: 25,
36
+ })),
37
+ ui: {
38
+ theme: test_theme,
39
+ setFooter: vi.fn(),
40
+ setStatus: vi.fn(),
41
+ notify: vi.fn(),
42
+ },
43
+ ...overrides,
44
+ };
45
+ }
46
+ //# sourceMappingURL=test-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-utils.js","sourceRoot":"","sources":["../src/test-utils.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAG5B,MAAM,CAAC,MAAM,UAAU,GAAG;IACzB,EAAE,EAAE,EAAE,CAAC,EAAE,CACR,CAAC,KAAa,EAAE,IAAY,EAAE,EAAE,CAAC,IAAI,KAAK,IAAI,IAAI,KAAK,KAAK,GAAG,CAC/D;IACD,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,IAAI,IAAI,CAAC;CAClB,CAAC;AAE5B,MAAM,UAAU,gBAAgB,CAC/B,YAAiD,EAAE;IAEnD,OAAO;QACN,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC;QACjC,yBAAyB,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACzC,oBAAoB,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,IAAI,GAAG,EAAE,CAAC;QAC5C,cAAc,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACpC,GAAG,SAAS;KAC6B,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,YAAY,CAC3B,YAAqC,EAAE;IAEvC,OAAO;QACN,KAAK,EAAE,IAAI;QACX,GAAG,EAAE,yBAAyB;QAC9B,KAAK,EAAE;YACN,EAAE,EAAE,eAAe;YACnB,QAAQ,EAAE,WAAW;YACrB,aAAa,EAAE,OAAO;YACtB,SAAS,EAAE,IAAI;SACf;QACD,aAAa,EAAE;YACd,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC;SAChC;QACD,cAAc,EAAE;YACf,UAAU,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC;YAC3B,cAAc,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC;SAC3C;QACD,eAAe,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;YAC7B,MAAM,EAAE,MAAM;YACd,aAAa,EAAE,OAAO;YACtB,OAAO,EAAE,EAAE;SACX,CAAC,CAAC;QACH,EAAE,EAAE;YACH,KAAK,EAAE,UAAU;YACjB,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE;YAClB,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE;YAClB,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE;SACf;QACD,GAAG,SAAS;KACmB,CAAC;AAClC,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { ExtensionContext } from '@earendil-works/pi-coding-agent';
2
+ import type { FooterTone } from '../presets/types.js';
3
+ export type FooterTheme = ExtensionContext['ui']['theme'];
4
+ export declare const FOOTER_COLORS: {
5
+ readonly muted: "dim";
6
+ readonly path: "dim";
7
+ readonly stats: "dim";
8
+ readonly status: "dim";
9
+ readonly accent: "accent";
10
+ readonly warning: "warning";
11
+ readonly error: "error";
12
+ };
13
+ export declare function themed_text(theme: FooterTheme, tone: FooterTone, text: string): string;
14
+ export declare function muted(theme: FooterTheme, text: string): string;
15
+ export declare function warning(theme: FooterTheme, text: string): string;
16
+ export declare function error(theme: FooterTheme, text: string): string;
@@ -0,0 +1,26 @@
1
+ export const FOOTER_COLORS = {
2
+ muted: 'dim',
3
+ path: 'dim',
4
+ stats: 'dim',
5
+ status: 'dim',
6
+ accent: 'accent',
7
+ warning: 'warning',
8
+ error: 'error',
9
+ };
10
+ export function themed_text(theme, tone, text) {
11
+ if (tone === 'bright')
12
+ return theme.fg(FOOTER_COLORS.accent, text);
13
+ if (tone === 'balanced')
14
+ return text;
15
+ return theme.fg(FOOTER_COLORS.muted, text);
16
+ }
17
+ export function muted(theme, text) {
18
+ return theme.fg(FOOTER_COLORS.muted, text);
19
+ }
20
+ export function warning(theme, text) {
21
+ return theme.fg(FOOTER_COLORS.warning, text);
22
+ }
23
+ export function error(theme, text) {
24
+ return theme.fg(FOOTER_COLORS.error, text);
25
+ }
26
+ //# sourceMappingURL=tokens.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../src/theme/tokens.ts"],"names":[],"mappings":"AAKA,MAAM,CAAC,MAAM,aAAa,GAAG;IAC5B,KAAK,EAAE,KAAK;IACZ,IAAI,EAAE,KAAK;IACX,KAAK,EAAE,KAAK;IACZ,MAAM,EAAE,KAAK;IACb,MAAM,EAAE,QAAQ;IAChB,OAAO,EAAE,SAAS;IAClB,KAAK,EAAE,OAAO;CACL,CAAC;AAEX,MAAM,UAAU,WAAW,CAC1B,KAAkB,EAClB,IAAgB,EAChB,IAAY;IAEZ,IAAI,IAAI,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC,EAAE,CAAC,aAAa,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACnE,IAAI,IAAI,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC;IACrC,OAAO,KAAK,CAAC,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,KAAkB,EAAE,IAAY;IACrD,OAAO,KAAK,CAAC,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,KAAkB,EAAE,IAAY;IACvD,OAAO,KAAK,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,KAAkB,EAAE,IAAY;IACrD,OAAO,KAAK,CAAC,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AAC5C,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function strip_ansi(text: string): string;
2
+ export declare function sanitize_status_text(text: string): string;
3
+ export declare function format_token_count(count: number): string;
@@ -0,0 +1,23 @@
1
+ const ESC = String.fromCharCode(27);
2
+ const ANSI_PATTERN = new RegExp(`${ESC}\\[[0-?]*[ -/]*[@-~]`, 'g');
3
+ export function strip_ansi(text) {
4
+ return text.replace(ANSI_PATTERN, '');
5
+ }
6
+ export function sanitize_status_text(text) {
7
+ return strip_ansi(text)
8
+ .replace(/[\r\n\t]/g, ' ')
9
+ .replace(/ +/g, ' ')
10
+ .trim();
11
+ }
12
+ export function format_token_count(count) {
13
+ if (count < 1000)
14
+ return count.toString();
15
+ if (count < 10000)
16
+ return `${(count / 1000).toFixed(1)}k`;
17
+ if (count < 1000000)
18
+ return `${Math.round(count / 1000)}k`;
19
+ if (count < 10000000)
20
+ return `${(count / 1000000).toFixed(1)}M`;
21
+ return `${Math.round(count / 1000000)}M`;
22
+ }
23
+ //# sourceMappingURL=text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/utils/text.ts"],"names":[],"mappings":"AAAA,MAAM,GAAG,GAAG,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;AACpC,MAAM,YAAY,GAAG,IAAI,MAAM,CAAC,GAAG,GAAG,sBAAsB,EAAE,GAAG,CAAC,CAAC;AAEnE,MAAM,UAAU,UAAU,CAAC,IAAY;IACtC,OAAO,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAChD,OAAO,UAAU,CAAC,IAAI,CAAC;SACrB,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC;SACzB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,IAAI,EAAE,CAAC;AACV,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,KAAa;IAC/C,IAAI,KAAK,GAAG,IAAI;QAAE,OAAO,KAAK,CAAC,QAAQ,EAAE,CAAC;IAC1C,IAAI,KAAK,GAAG,KAAK;QAAE,OAAO,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;IAC1D,IAAI,KAAK,GAAG,OAAO;QAAE,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC;IAC3D,IAAI,KAAK,GAAG,QAAQ;QAAE,OAAO,GAAG,CAAC,KAAK,GAAG,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;IAChE,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC;AAC1C,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spences10/pi-footer",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "Configurable footer/statusline extension for Pi",
5
5
  "keywords": [
6
6
  "footer",
@@ -34,7 +34,7 @@
34
34
  "access": "public"
35
35
  },
36
36
  "dependencies": {
37
- "@spences10/pi-tui-modal": "0.0.16"
37
+ "@spences10/pi-tui-modal": "0.0.17"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@earendil-works/pi-ai": "^0.74.1",
@@ -60,12 +60,12 @@
60
60
  },
61
61
  "scripts": {
62
62
  "build": "pnpm --filter \"$npm_package_name^...\" run build:self && pnpm run build:self",
63
- "build:self": "tsc -p tsconfig.build.json",
63
+ "build:self": "vp exec tsc -p tsconfig.build.json",
64
64
  "check": "pnpm --filter \"$npm_package_name^...\" run build:self && pnpm run check:self",
65
- "check:self": "tsc --noEmit -p tsconfig.json",
65
+ "check:self": "vp exec tsc --noEmit -p tsconfig.json",
66
66
  "test": "pnpm --filter \"$npm_package_name^...\" run build:self && pnpm run test:self",
67
- "test:self": "vitest run",
68
- "coverage:self": "vitest run --coverage",
67
+ "test:self": "vp exec vitest run",
68
+ "coverage:self": "vp exec vitest run --coverage",
69
69
  "coverage": "pnpm --filter \"$npm_package_name^...\" run build:self && pnpm run coverage:self"
70
70
  }
71
71
  }