@spences10/pi-footer 0.0.1 → 0.0.2

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 +124 -0
  4. package/dist/commands/footer-command.js.map +1 -0
  5. package/dist/config.d.ts +4 -0
  6. package/dist/config.js +44 -0
  7. package/dist/config.js.map +1 -0
  8. package/dist/extension/install.d.ts +3 -0
  9. package/dist/extension/install.js +16 -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 +20 -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 +10 -0
  18. package/dist/model/git.js +64 -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 +20 -0
  24. package/dist/presets/types.js +49 -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,94 @@
1
+ import { error, warning } from '../theme/tokens.js';
2
+ import { format_token_count } from '../utils/text.js';
3
+ import { format_git_summary, get_git_summary, } from './git.js';
4
+ import { get_current_thinking_level } from './thinking.js';
5
+ export function build_footer_model(ctx, footer_data, theme) {
6
+ let total_input = 0;
7
+ let total_output = 0;
8
+ let total_cache_read = 0;
9
+ let total_cache_write = 0;
10
+ let total_cost = 0;
11
+ for (const entry of ctx.sessionManager.getEntries()) {
12
+ if (entry.type === 'message' &&
13
+ entry.message.role === 'assistant') {
14
+ total_input += entry.message.usage.input;
15
+ total_output += entry.message.usage.output;
16
+ total_cache_read += entry.message.usage.cacheRead;
17
+ total_cache_write += entry.message.usage.cacheWrite;
18
+ total_cost += entry.message.usage.cost.total;
19
+ }
20
+ }
21
+ const context_usage = ctx.getContextUsage();
22
+ const context_window = context_usage?.contextWindow ?? ctx.model?.contextWindow ?? 0;
23
+ const context_percent_value = context_usage?.percent ?? 0;
24
+ const context_percent = context_usage?.percent !== null
25
+ ? context_percent_value.toFixed(1)
26
+ : '?';
27
+ let path_text = ctx.cwd;
28
+ const home = process.env.HOME || process.env.USERPROFILE;
29
+ if (home && path_text.startsWith(home)) {
30
+ path_text = `~${path_text.slice(home.length)}`;
31
+ }
32
+ const git_branch = footer_data.getGitBranch() ?? undefined;
33
+ const git = get_git_summary(ctx.cwd, git_branch);
34
+ const git_text = format_git_summary(git);
35
+ const session_text = ctx.sessionManager.getSessionName() || undefined;
36
+ const token_parts = [];
37
+ if (total_input)
38
+ token_parts.push(`↑${format_token_count(total_input)}`);
39
+ if (total_output)
40
+ token_parts.push(`↓${format_token_count(total_output)}`);
41
+ if (total_cache_read)
42
+ token_parts.push(`R${format_token_count(total_cache_read)}`);
43
+ if (total_cache_write)
44
+ token_parts.push(`W${format_token_count(total_cache_write)}`);
45
+ const using_subscription = ctx.model
46
+ ? ctx.modelRegistry.isUsingOAuth(ctx.model)
47
+ : false;
48
+ const cost_text = total_cost || using_subscription
49
+ ? `$${total_cost.toFixed(3)}${using_subscription ? ' (sub)' : ''}`
50
+ : undefined;
51
+ const context_percent_display = context_percent === '?'
52
+ ? `?/${format_token_count(context_window)}`
53
+ : `${context_percent}%/${format_token_count(context_window)}`;
54
+ let context_text = context_percent_display;
55
+ if (context_percent_value > 90) {
56
+ context_text = error(theme, context_percent_display);
57
+ }
58
+ else if (context_percent_value > 70) {
59
+ context_text = warning(theme, context_percent_display);
60
+ }
61
+ const model_name = ctx.model?.id || 'no-model';
62
+ const thinking_level = get_current_thinking_level(ctx);
63
+ const thinking_text = ctx.model?.reasoning
64
+ ? thinking_level === 'off'
65
+ ? 'thinking off'
66
+ : thinking_level
67
+ : undefined;
68
+ let model_text = model_name;
69
+ if (thinking_text)
70
+ model_text = `${model_name} • ${thinking_text}`;
71
+ if (footer_data.getAvailableProviderCount() > 1 && ctx.model) {
72
+ model_text = `(${ctx.model.provider}) ${model_text}`;
73
+ }
74
+ const statuses = new Map(footer_data.getExtensionStatuses());
75
+ const preset_status = statuses.get('preset');
76
+ statuses.delete('preset');
77
+ return {
78
+ cwd: ctx.cwd,
79
+ path_text,
80
+ git,
81
+ git_text,
82
+ session_text,
83
+ token_parts,
84
+ cost_text,
85
+ context_text,
86
+ model_name,
87
+ provider: ctx.model?.provider,
88
+ thinking_text,
89
+ model_text,
90
+ statuses,
91
+ preset_status,
92
+ };
93
+ }
94
+ //# sourceMappingURL=footer-model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"footer-model.js","sourceRoot":"","sources":["../../src/model/footer-model.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export interface GitSummary {
2
+ branch?: string;
3
+ dirty: number;
4
+ staged: number;
5
+ untracked: number;
6
+ ahead: number;
7
+ behind: number;
8
+ }
9
+ export declare function get_git_summary(cwd: string, branch?: string): GitSummary;
10
+ export declare function format_git_summary(summary: GitSummary): string | undefined;
@@ -0,0 +1,64 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ export function get_git_summary(cwd, branch) {
3
+ const summary = {
4
+ branch,
5
+ dirty: 0,
6
+ staged: 0,
7
+ untracked: 0,
8
+ ahead: 0,
9
+ behind: 0,
10
+ };
11
+ try {
12
+ const output = execFileSync('git', ['status', '--porcelain=v1', '--branch'], {
13
+ cwd,
14
+ encoding: 'utf8',
15
+ stdio: ['ignore', 'pipe', 'ignore'],
16
+ timeout: 500,
17
+ });
18
+ for (const line of output.split('\n')) {
19
+ if (!line)
20
+ continue;
21
+ if (line.startsWith('## ')) {
22
+ const match = line.match(/^## ([^.\s]+|[^.]+?)(?:\.\.\.)?/);
23
+ if (match?.[1] && !summary.branch)
24
+ summary.branch = match[1];
25
+ const ahead = line.match(/ahead (\d+)/);
26
+ const behind = line.match(/behind (\d+)/);
27
+ summary.ahead = ahead ? Number(ahead[1]) : 0;
28
+ summary.behind = behind ? Number(behind[1]) : 0;
29
+ continue;
30
+ }
31
+ const index_status = line[0];
32
+ const worktree_status = line[1];
33
+ if (line.startsWith('??')) {
34
+ summary.untracked += 1;
35
+ continue;
36
+ }
37
+ if (index_status !== ' ')
38
+ summary.staged += 1;
39
+ if (worktree_status !== ' ')
40
+ summary.dirty += 1;
41
+ }
42
+ }
43
+ catch {
44
+ return summary;
45
+ }
46
+ return summary;
47
+ }
48
+ export function format_git_summary(summary) {
49
+ const parts = [];
50
+ if (summary.branch)
51
+ parts.push(summary.branch);
52
+ if (summary.dirty)
53
+ parts.push(`±${summary.dirty}`);
54
+ if (summary.staged)
55
+ parts.push(`●${summary.staged}`);
56
+ if (summary.untracked)
57
+ parts.push(`?${summary.untracked}`);
58
+ if (summary.ahead)
59
+ parts.push(`↑${summary.ahead}`);
60
+ if (summary.behind)
61
+ parts.push(`↓${summary.behind}`);
62
+ return parts.length > 0 ? parts.join(' ') : undefined;
63
+ }
64
+ //# sourceMappingURL=git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/model/git.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { type ModelThinkingLevel } from '@earendil-works/pi-ai';
2
+ import type { ExtensionContext } from '@earendil-works/pi-coding-agent';
3
+ export declare function get_default_footer_thinking_level(model: ExtensionContext['model']): ModelThinkingLevel;
4
+ export declare function get_current_thinking_level(ctx: Pick<ExtensionContext, 'model' | 'sessionManager'>): ModelThinkingLevel;
@@ -0,0 +1,34 @@
1
+ import { clampThinkingLevel, getSupportedThinkingLevels, } from '@earendil-works/pi-ai';
2
+ const VALID_THINKING_LEVELS = new Set([
3
+ 'off',
4
+ 'minimal',
5
+ 'low',
6
+ 'medium',
7
+ 'high',
8
+ 'xhigh',
9
+ ]);
10
+ function is_model_thinking_level(level) {
11
+ return VALID_THINKING_LEVELS.has(level);
12
+ }
13
+ export function get_default_footer_thinking_level(model) {
14
+ if (!model?.reasoning)
15
+ return 'off';
16
+ return clampThinkingLevel(model, 'medium');
17
+ }
18
+ export function get_current_thinking_level(ctx) {
19
+ const entries = ctx.sessionManager.getEntries();
20
+ for (let i = entries.length - 1; i >= 0; i--) {
21
+ const entry = entries[i];
22
+ if (entry.type === 'thinking_level_change' &&
23
+ typeof entry.thinkingLevel === 'string' &&
24
+ is_model_thinking_level(entry.thinkingLevel)) {
25
+ if (!ctx.model?.reasoning)
26
+ return 'off';
27
+ return getSupportedThinkingLevels(ctx.model).includes(entry.thinkingLevel)
28
+ ? entry.thinkingLevel
29
+ : clampThinkingLevel(ctx.model, entry.thinkingLevel);
30
+ }
31
+ }
32
+ return get_default_footer_thinking_level(ctx.model);
33
+ }
34
+ //# sourceMappingURL=thinking.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thinking.js","sourceRoot":"","sources":["../../src/model/thinking.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,kBAAkB,EAClB,0BAA0B,GAE1B,MAAM,uBAAuB,CAAC;AAG/B,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAqB;IACzD,KAAK;IACL,SAAS;IACT,KAAK;IACL,QAAQ;IACR,MAAM;IACN,OAAO;CACP,CAAC,CAAC;AAEH,SAAS,uBAAuB,CAC/B,KAAa;IAEb,OAAO,qBAAqB,CAAC,GAAG,CAAC,KAA2B,CAAC,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,iCAAiC,CAChD,KAAgC;IAEhC,IAAI,CAAC,KAAK,EAAE,SAAS;QAAE,OAAO,KAAK,CAAC;IACpC,OAAO,kBAAkB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,0BAA0B,CACzC,GAAuD;IAEvD,MAAM,OAAO,GAAG,GAAG,CAAC,cAAc,CAAC,UAAU,EAAE,CAAC;IAChD,KAAK,IAAI,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC9C,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAGtB,CAAC;QACF,IACC,KAAK,CAAC,IAAI,KAAK,uBAAuB;YACtC,OAAO,KAAK,CAAC,aAAa,KAAK,QAAQ;YACvC,uBAAuB,CAAC,KAAK,CAAC,aAAa,CAAC,EAC3C,CAAC;YACF,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,SAAS;gBAAE,OAAO,KAAK,CAAC;YACxC,OAAO,0BAA0B,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,QAAQ,CACpD,KAAK,CAAC,aAAa,CACnB;gBACA,CAAC,CAAC,KAAK,CAAC,aAAa;gBACrB,CAAC,CAAC,kBAAkB,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC;QACvD,CAAC;IACF,CAAC;IACD,OAAO,iCAAiC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACrD,CAAC"}
@@ -0,0 +1,20 @@
1
+ export declare const FOOTER_PRESETS: readonly ["minimal", "default", "power", "git-heavy"];
2
+ export type FooterPreset = (typeof FOOTER_PRESETS)[number];
3
+ export declare const FOOTER_DENSITIES: readonly ["compact", "comfortable", "expanded"];
4
+ export type FooterDensity = (typeof FOOTER_DENSITIES)[number];
5
+ export declare const STATUS_LABEL_MODES: readonly ["smart", "always", "never"];
6
+ export type StatusLabelMode = (typeof STATUS_LABEL_MODES)[number];
7
+ export declare const FOOTER_TONES: readonly ["muted", "balanced", "bright"];
8
+ export type FooterTone = (typeof FOOTER_TONES)[number];
9
+ export declare const FOOTER_WIDGETS: readonly ["path", "git", "session", "model", "thinking", "context", "cost", "tokens", "statuses", "preset"];
10
+ export type FooterWidget = (typeof FOOTER_WIDGETS)[number];
11
+ export type FooterWidgetState = Record<FooterWidget, boolean>;
12
+ export interface FooterState {
13
+ preset: FooterPreset;
14
+ density: FooterDensity;
15
+ status_label_mode: StatusLabelMode;
16
+ tone: FooterTone;
17
+ widgets: FooterWidgetState;
18
+ }
19
+ export declare const DEFAULT_FOOTER_WIDGETS: FooterWidgetState;
20
+ export declare const DEFAULT_FOOTER_STATE: FooterState;
@@ -0,0 +1,49 @@
1
+ export const FOOTER_PRESETS = [
2
+ 'minimal',
3
+ 'default',
4
+ 'power',
5
+ 'git-heavy',
6
+ ];
7
+ export const FOOTER_DENSITIES = [
8
+ 'compact',
9
+ 'comfortable',
10
+ 'expanded',
11
+ ];
12
+ export const STATUS_LABEL_MODES = [
13
+ 'smart',
14
+ 'always',
15
+ 'never',
16
+ ];
17
+ export const FOOTER_TONES = ['muted', 'balanced', 'bright'];
18
+ export const FOOTER_WIDGETS = [
19
+ 'path',
20
+ 'git',
21
+ 'session',
22
+ 'model',
23
+ 'thinking',
24
+ 'context',
25
+ 'cost',
26
+ 'tokens',
27
+ 'statuses',
28
+ 'preset',
29
+ ];
30
+ export const DEFAULT_FOOTER_WIDGETS = {
31
+ path: true,
32
+ git: true,
33
+ session: true,
34
+ model: true,
35
+ thinking: true,
36
+ context: true,
37
+ cost: true,
38
+ tokens: true,
39
+ statuses: true,
40
+ preset: true,
41
+ };
42
+ export const DEFAULT_FOOTER_STATE = {
43
+ preset: 'default',
44
+ density: 'comfortable',
45
+ status_label_mode: 'smart',
46
+ tone: 'muted',
47
+ widgets: DEFAULT_FOOTER_WIDGETS,
48
+ };
49
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/presets/types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,cAAc,GAAG;IAC7B,SAAS;IACT,SAAS;IACT,OAAO;IACP,WAAW;CACF,CAAC;AAIX,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC/B,SAAS;IACT,aAAa;IACb,UAAU;CACD,CAAC;AAIX,MAAM,CAAC,MAAM,kBAAkB,GAAG;IACjC,OAAO;IACP,QAAQ;IACR,OAAO;CACE,CAAC;AAIX,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,CAAU,CAAC;AAIrE,MAAM,CAAC,MAAM,cAAc,GAAG;IAC7B,MAAM;IACN,KAAK;IACL,SAAS;IACT,OAAO;IACP,UAAU;IACV,SAAS;IACT,MAAM;IACN,QAAQ;IACR,UAAU;IACV,QAAQ;CACC,CAAC;AAcX,MAAM,CAAC,MAAM,sBAAsB,GAAsB;IACxD,IAAI,EAAE,IAAI;IACV,GAAG,EAAE,IAAI;IACT,OAAO,EAAE,IAAI;IACb,KAAK,EAAE,IAAI;IACX,QAAQ,EAAE,IAAI;IACd,OAAO,EAAE,IAAI;IACb,IAAI,EAAE,IAAI;IACV,MAAM,EAAE,IAAI;IACZ,QAAQ,EAAE,IAAI;IACd,MAAM,EAAE,IAAI;CACZ,CAAC;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAgB;IAChD,MAAM,EAAE,SAAS;IACjB,OAAO,EAAE,aAAa;IACtB,iBAAiB,EAAE,OAAO;IAC1B,IAAI,EAAE,OAAO;IACb,OAAO,EAAE,sBAAsB;CAC/B,CAAC"}
@@ -0,0 +1,6 @@
1
+ export interface FooterReference {
2
+ name: string;
3
+ package_name?: string;
4
+ takeaways: string[];
5
+ }
6
+ export declare const FOOTER_RESEARCH_REFERENCES: FooterReference[];
@@ -0,0 +1,50 @@
1
+ export const FOOTER_RESEARCH_REFERENCES = [
2
+ {
3
+ name: 'pi-footer',
4
+ package_name: 'pi-footer',
5
+ takeaways: [
6
+ 'Config UI with live preview',
7
+ 'Preset and widget model',
8
+ 'Persisted footer configuration',
9
+ ],
10
+ },
11
+ {
12
+ name: 'pi-powerline-footer',
13
+ package_name: 'pi-powerline-footer',
14
+ takeaways: [
15
+ 'Color-coded segment system',
16
+ 'Git and context warning priority',
17
+ 'Opinionated powerline presets',
18
+ ],
19
+ },
20
+ {
21
+ name: '@feniix/pi-statusline',
22
+ package_name: '@feniix/pi-statusline',
23
+ takeaways: [
24
+ 'Fixed two-line statusline',
25
+ 'Activity, skill, and worktree indicators',
26
+ ],
27
+ },
28
+ {
29
+ name: '@sentiolabs/pi-scriptable-statusline',
30
+ package_name: '@sentiolabs/pi-scriptable-statusline',
31
+ takeaways: [
32
+ 'User-owned renderer file',
33
+ 'Reload and doctor commands',
34
+ ],
35
+ },
36
+ {
37
+ name: '@ogulcancelik/pi-minimal-footer',
38
+ package_name: '@ogulcancelik/pi-minimal-footer',
39
+ takeaways: [
40
+ 'Usage and quota bars',
41
+ 'Compact git branch/dirty/ahead/behind display',
42
+ ],
43
+ },
44
+ {
45
+ name: 'pi-ui-minimal',
46
+ package_name: 'pi-ui-minimal',
47
+ takeaways: ['Minimal/focus mode for low-noise sessions'],
48
+ },
49
+ ];
50
+ //# sourceMappingURL=research.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"research.js","sourceRoot":"","sources":["../../src/reference/research.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,0BAA0B,GAAsB;IAC5D;QACC,IAAI,EAAE,WAAW;QACjB,YAAY,EAAE,WAAW;QACzB,SAAS,EAAE;YACV,6BAA6B;YAC7B,yBAAyB;YACzB,gCAAgC;SAChC;KACD;IACD;QACC,IAAI,EAAE,qBAAqB;QAC3B,YAAY,EAAE,qBAAqB;QACnC,SAAS,EAAE;YACV,4BAA4B;YAC5B,kCAAkC;YAClC,+BAA+B;SAC/B;KACD;IACD;QACC,IAAI,EAAE,uBAAuB;QAC7B,YAAY,EAAE,uBAAuB;QACrC,SAAS,EAAE;YACV,2BAA2B;YAC3B,0CAA0C;SAC1C;KACD;IACD;QACC,IAAI,EAAE,sCAAsC;QAC5C,YAAY,EAAE,sCAAsC;QACpD,SAAS,EAAE;YACV,0BAA0B;YAC1B,4BAA4B;SAC5B;KACD;IACD;QACC,IAAI,EAAE,iCAAiC;QACvC,YAAY,EAAE,iCAAiC;QAC/C,SAAS,EAAE;YACV,sBAAsB;YACtB,+CAA+C;SAC/C;KACD;IACD;QACC,IAAI,EAAE,eAAe;QACrB,YAAY,EAAE,eAAe;QAC7B,SAAS,EAAE,CAAC,2CAA2C,CAAC;KACxD;CACD,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { ExtensionContext, ReadonlyFooterDataProvider } from '@earendil-works/pi-coding-agent';
2
+ import type { FooterState } from '../presets/types.js';
3
+ import { type FooterTheme } from '../theme/tokens.js';
4
+ export declare function render_footer_lines(ctx: ExtensionContext, theme: FooterTheme, footer_data: ReadonlyFooterDataProvider, state: FooterState, width: number): string[];
@@ -0,0 +1,117 @@
1
+ import { truncateToWidth, visibleWidth, } from '@earendil-works/pi-tui';
2
+ import { build_footer_model, } from '../model/footer-model.js';
3
+ import { muted, themed_text, } from '../theme/tokens.js';
4
+ import { sanitize_status_text } from '../utils/text.js';
5
+ import { render_footer_status_line } from './status-line.js';
6
+ function enabled_items(items) {
7
+ return items.filter(([, enabled]) => enabled).map(([text]) => text);
8
+ }
9
+ function render_stats_line(model, theme, state, width) {
10
+ const stats_left = enabled_items([
11
+ [model.token_parts.join(' '), state.widgets.tokens],
12
+ [
13
+ model.cost_text ?? '',
14
+ state.widgets.cost && Boolean(model.cost_text),
15
+ ],
16
+ [model.context_text, state.widgets.context],
17
+ ]).join(' ');
18
+ const right_parts = enabled_items([
19
+ [model.model_name, state.widgets.model],
20
+ [
21
+ model.thinking_text ?? '',
22
+ state.widgets.thinking && Boolean(model.thinking_text),
23
+ ],
24
+ ]);
25
+ const right_side = right_parts.join(' • ');
26
+ if (!stats_left && !right_side)
27
+ return undefined;
28
+ let left = stats_left;
29
+ let left_width = visibleWidth(left);
30
+ if (left_width > width) {
31
+ left = truncateToWidth(left, width, '...');
32
+ left_width = visibleWidth(left);
33
+ }
34
+ if (!right_side)
35
+ return themed_text(theme, state.tone, left);
36
+ if (!left) {
37
+ return truncateToWidth(themed_text(theme, state.tone, right_side), width, muted(theme, '...'));
38
+ }
39
+ const right_width = visibleWidth(right_side);
40
+ const available_for_right = Math.max(0, width - left_width - 2);
41
+ const rendered_right = left_width + 2 + right_width <= width
42
+ ? right_side
43
+ : truncateToWidth(right_side, available_for_right, '');
44
+ const gap = Math.max(1, width - left_width - visibleWidth(rendered_right));
45
+ return (themed_text(theme, state.tone, left) +
46
+ ' '.repeat(gap) +
47
+ themed_text(theme, state.tone, rendered_right));
48
+ }
49
+ function render_status_label(key, text, state) {
50
+ const sanitized = sanitize_status_text(text);
51
+ if (state.status_label_mode === 'never')
52
+ return sanitized;
53
+ if (state.status_label_mode === 'always')
54
+ return `${key}:${sanitized}`;
55
+ if (sanitized.toLowerCase().startsWith(key.toLowerCase()))
56
+ return sanitized;
57
+ return `${key}:${sanitized}`;
58
+ }
59
+ function prioritized_statuses(statuses) {
60
+ const priority = ['mcp', 'team', 'lsp', 'recall', 'nopeek'];
61
+ return Array.from(statuses.entries()).sort(([a], [b]) => {
62
+ const a_index = priority.indexOf(a);
63
+ const b_index = priority.indexOf(b);
64
+ if (a_index !== -1 || b_index !== -1) {
65
+ return ((a_index === -1 ? 99 : a_index) -
66
+ (b_index === -1 ? 99 : b_index));
67
+ }
68
+ return a.localeCompare(b);
69
+ });
70
+ }
71
+ function render_statuses(model, theme, state, width) {
72
+ if (!state.widgets.statuses && !state.widgets.preset)
73
+ return undefined;
74
+ const other_statuses = state.widgets.statuses
75
+ ? prioritized_statuses(model.statuses).map(([key, text]) => render_status_label(key, text, state))
76
+ : [];
77
+ return render_footer_status_line(theme, width, other_statuses, state.widgets.preset ? model.preset_status : undefined, state.tone);
78
+ }
79
+ function render_path_line(model, theme, state, width) {
80
+ const left = enabled_items([
81
+ [model.path_text, state.widgets.path],
82
+ [
83
+ model.git_text ? `(${model.git_text})` : '',
84
+ state.widgets.git && Boolean(model.git_text),
85
+ ],
86
+ ]);
87
+ const right = state.widgets.session
88
+ ? model.session_text
89
+ : undefined;
90
+ return render_footer_status_line(theme, width, left, right, state.tone);
91
+ }
92
+ export function render_footer_lines(ctx, theme, footer_data, state, width) {
93
+ const model = build_footer_model(ctx, footer_data, theme);
94
+ const lines = [];
95
+ const path_line = render_path_line(model, theme, state, width);
96
+ const stats_line = render_stats_line(model, theme, state, width);
97
+ const status_line = render_statuses(model, theme, state, width);
98
+ if (state.density === 'compact' || state.preset === 'minimal') {
99
+ const compact_left = [path_line, stats_line]
100
+ .filter(Boolean)
101
+ .join(' ');
102
+ const compact = render_footer_status_line(theme, width, [compact_left], status_line, state.tone);
103
+ return compact ? [compact] : [];
104
+ }
105
+ if (path_line)
106
+ lines.push(truncateToWidth(path_line, width, muted(theme, '...')));
107
+ if (stats_line)
108
+ lines.push(truncateToWidth(stats_line, width, muted(theme, '...')));
109
+ if (status_line)
110
+ lines.push(status_line);
111
+ if (state.density === 'expanded' || state.preset === 'power') {
112
+ const footer_mode = themed_text(theme, state.tone, `footer:${state.preset} density:${state.density}`);
113
+ lines.push(truncateToWidth(footer_mode, width, muted(theme, '...')));
114
+ }
115
+ return lines;
116
+ }
117
+ //# sourceMappingURL=footer-lines.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"footer-lines.js","sourceRoot":"","sources":["../../src/render/footer-lines.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { FooterModel } from '../model/footer-model.js';
2
+ import type { FooterState } from '../presets/types.js';
3
+ import type { FooterTheme } from '../theme/tokens.js';
4
+ export declare const PREVIEW_WIDTH = 72;
5
+ export declare function make_preview_footer_model(): FooterModel;
6
+ export declare function render_footer_preview(theme: FooterTheme, state: FooterState, width?: number): string[];
@@ -0,0 +1,34 @@
1
+ import { render_model_footer_lines } from './footer-lines.js';
2
+ export const PREVIEW_WIDTH = 72;
3
+ export function make_preview_footer_model() {
4
+ return {
5
+ cwd: '/home/scott/repos/my-pi',
6
+ path_text: '~/repos/my-pi',
7
+ git: {
8
+ branch: 'main',
9
+ dirty: 2,
10
+ staged: 1,
11
+ untracked: 1,
12
+ ahead: 1,
13
+ behind: 0,
14
+ },
15
+ git_text: 'main ±2 ●1 ?1 ↑1',
16
+ session_text: 'footer-preview',
17
+ token_parts: ['↑12k', '↓4.2k', 'R8k'],
18
+ cost_text: '$0.032',
19
+ context_text: '42.0%/200k',
20
+ model_name: 'claude-sonnet',
21
+ provider: 'anthropic',
22
+ thinking_text: 'high',
23
+ model_text: '(anthropic) claude-sonnet • high',
24
+ statuses: new Map([
25
+ ['mcp', 'MCP 6/6 connected'],
26
+ ['lsp', 'LSP ready'],
27
+ ]),
28
+ preset_status: 'prompt:terse +1',
29
+ };
30
+ }
31
+ export function render_footer_preview(theme, state, width = PREVIEW_WIDTH) {
32
+ return render_model_footer_lines(make_preview_footer_model(), theme, state, width);
33
+ }
34
+ //# sourceMappingURL=preview.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview.js","sourceRoot":"","sources":["../../src/render/preview.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAE9D,MAAM,CAAC,MAAM,aAAa,GAAG,EAAE,CAAC;AAEhC,MAAM,UAAU,yBAAyB;IACxC,OAAO;QACN,GAAG,EAAE,yBAAyB;QAC9B,SAAS,EAAE,eAAe;QAC1B,GAAG,EAAE;YACJ,MAAM,EAAE,MAAM;YACd,KAAK,EAAE,CAAC;YACR,MAAM,EAAE,CAAC;YACT,SAAS,EAAE,CAAC;YACZ,KAAK,EAAE,CAAC;YACR,MAAM,EAAE,CAAC;SACT;QACD,QAAQ,EAAE,kBAAkB;QAC5B,YAAY,EAAE,gBAAgB;QAC9B,WAAW,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC;QACrC,SAAS,EAAE,QAAQ;QACnB,YAAY,EAAE,YAAY;QAC1B,UAAU,EAAE,eAAe;QAC3B,QAAQ,EAAE,WAAW;QACrB,aAAa,EAAE,MAAM;QACrB,UAAU,EAAE,kCAAkC;QAC9C,QAAQ,EAAE,IAAI,GAAG,CAAC;YACjB,CAAC,KAAK,EAAE,mBAAmB,CAAC;YAC5B,CAAC,KAAK,EAAE,WAAW,CAAC;SACpB,CAAC;QACF,aAAa,EAAE,iBAAiB;KAChC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,qBAAqB,CACpC,KAAkB,EAClB,KAAkB,EAClB,KAAK,GAAG,aAAa;IAErB,OAAO,yBAAyB,CAC/B,yBAAyB,EAAE,EAC3B,KAAK,EACL,KAAK,EACL,KAAK,CACL,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { FooterTone } from '../presets/types.js';
2
+ import { type FooterTheme } from '../theme/tokens.js';
3
+ export declare function render_footer_status_line(theme: FooterTheme, width: number, left_items: string[], right_item?: string, tone?: FooterTone): string | undefined;
@@ -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;