@firstpick/pi-extension-git-footer-status 0.1.4 → 0.1.6

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 (3) hide show
  1. package/README.md +1 -0
  2. package/index.ts +52 -1
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -6,6 +6,7 @@ Enhanced Pi footer with git health and model/token telemetry.
6
6
 
7
7
  - Shows compact runtime metrics in the footer:
8
8
  - input/output/cache tokens
9
+ - prompt-injection estimate (`PI: X tok`, compacted as `k` for thousands)
9
10
  - live output token counter + token output speed (`tok/s`) measured from assistant streaming lifecycle events, with a session-history fallback
10
11
  - cost + context-window usage
11
12
  - current model and reasoning level
package/index.ts CHANGED
@@ -23,6 +23,13 @@ type GitSnapshot = {
23
23
  signingMismatch: boolean;
24
24
  };
25
25
 
26
+ type SigningDiagnostics = {
27
+ commitSignRequired: boolean;
28
+ signState: string;
29
+ gpgFormat: string;
30
+ signingKey: string;
31
+ };
32
+
26
33
  const LIVE_TOKEN_SPEED_ROLLING_WINDOW_MS = 2000;
27
34
 
28
35
  // Toggle footer items on/off here.
@@ -96,6 +103,10 @@ function estimateTokensFromCharCount(charCount: number): number {
96
103
  return Math.max(0, Math.round(charCount / 4));
97
104
  }
98
105
 
106
+ function estimatePromptInjectionTokens(systemPrompt: string): number {
107
+ return estimateTokensFromCharCount(systemPrompt.length);
108
+ }
109
+
99
110
  function formatTokenSpeed(tokensPerSecond: number): string {
100
111
  if (tokensPerSecond < 100) {
101
112
  if (tokensPerSecond >= 10) return tokensPerSecond.toFixed(1);
@@ -284,6 +295,22 @@ async function readGitSnapshot(pi: ExtensionAPI, cwd: string): Promise<GitSnapsh
284
295
  };
285
296
  }
286
297
 
298
+ async function getSigningDiagnostics(pi: ExtensionAPI, cwd: string): Promise<SigningDiagnostics> {
299
+ const [commitSignRequiredRaw, headSignState, gpgFormatRaw, signingKeyRaw] = await Promise.all([
300
+ runGit(pi, cwd, ["config", "--bool", "--get", "commit.gpgsign"]),
301
+ runGit(pi, cwd, ["log", "-1", "--format=%G?"]),
302
+ runGit(pi, cwd, ["config", "--get", "gpg.format"]),
303
+ runGit(pi, cwd, ["config", "--get", "user.signingkey"]),
304
+ ]);
305
+
306
+ return {
307
+ commitSignRequired: commitSignRequiredRaw?.toLowerCase() === "true",
308
+ signState: headSignState?.trim().toUpperCase() || "N",
309
+ gpgFormat: gpgFormatRaw?.trim() || "(default:gpg)",
310
+ signingKey: signingKeyRaw?.trim() || "(not set)",
311
+ };
312
+ }
313
+
287
314
  function buildStatusText(ctx: ExtensionContext, snapshot: GitSnapshot): string {
288
315
  const t = ctx.ui.theme;
289
316
  const f = FOOTER_FLAGS;
@@ -314,7 +341,7 @@ function buildStatusText(ctx: ExtensionContext, snapshot: GitSnapshot): string {
314
341
  if (f.worktrees && snapshot.worktreeCount > 1) extraSection.push(t.fg("muted", `📦${snapshot.worktreeCount}`));
315
342
  if (f.tag && snapshot.headTag) extraSection.push(t.fg("accent", `🏷${snapshot.headTag}`));
316
343
  if (f.lastCommitAge && snapshot.lastCommitAge) extraSection.push(t.fg("dim", `⏱${snapshot.lastCommitAge}`));
317
- if (f.signingMismatch && snapshot.signingMismatch) extraSection.push(t.fg("warning", "🔒!"));
344
+ if (f.signingMismatch && snapshot.signingMismatch) extraSection.push(t.fg("warning", "⚠️!"));
318
345
 
319
346
  const isWorkingTreeClean =
320
347
  snapshot.ahead === 0 &&
@@ -473,6 +500,8 @@ export default function gitFooterStatus(pi: ExtensionAPI) {
473
500
  latestTokenSpeed = historicalTokenSpeed;
474
501
  }
475
502
 
503
+ const promptInjectionTokens = estimatePromptInjectionTokens(ctx.getSystemPrompt());
504
+
476
505
  const contextUsage = ctx.getContextUsage();
477
506
  const contextWindow = contextUsage?.contextWindow ?? ctx.model?.contextWindow ?? 0;
478
507
  const contextPercentValue = contextUsage?.percent ?? 0;
@@ -509,6 +538,7 @@ export default function gitFooterStatus(pi: ExtensionAPI) {
509
538
  const segments: string[] = [];
510
539
  if (ioItems.length > 0) segments.push(`${theme.fg("muted", "🪙")} ${ioItems.join(` ${itemSep} `)}`);
511
540
  if (cacheItems.length > 0) segments.push(`${theme.fg("muted", "💾")} ${cacheItems.join(` ${itemSep} `)}`);
541
+ segments.push(`PI: ${formatTokens(promptInjectionTokens)} tok`);
512
542
  if (latestTokenSpeed !== null) {
513
543
  const livePrefix = liveOutputTokens > 0 ? `${formatTokens(liveOutputTokens)} tok @ ` : "";
514
544
  segments.push(`⚡ ${livePrefix}${formatTokenSpeed(latestTokenSpeed)} tok/s`);
@@ -658,4 +688,25 @@ export default function gitFooterStatus(pi: ExtensionAPI) {
658
688
  ctx.ui.notify("Git footer refreshed", "info");
659
689
  },
660
690
  });
691
+
692
+ pi.registerShortcut("ctrl+shift+g", {
693
+ description: "Show git signing mismatch diagnostics",
694
+ handler: async (ctx) => {
695
+ const diagnostics = await getSigningDiagnostics(pi, ctx.cwd);
696
+ if (!diagnostics.commitSignRequired) {
697
+ ctx.ui.notify("Signing mismatch: commit.gpgsign is OFF", "info");
698
+ return;
699
+ }
700
+
701
+ if (!["N", "E"].includes(diagnostics.signState)) {
702
+ ctx.ui.notify("Signing mismatch: not currently triggered", "info");
703
+ return;
704
+ }
705
+
706
+ ctx.ui.notify(
707
+ `Signing mismatch details: commit.gpgsign=ON, last-sign-state=${diagnostics.signState}, gpg.format=${diagnostics.gpgFormat}, user.signingkey=${diagnostics.signingKey}`,
708
+ "warning",
709
+ );
710
+ },
711
+ });
661
712
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@firstpick/pi-extension-git-footer-status",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "Enhanced Pi footer with git status, token usage, context usage, and model telemetry.",
5
5
  "license": "MIT",
6
6
  "keywords": [