pi-bar 0.3.26 → 0.3.27
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/README.md +3 -3
- package/extensions/status-footer.ts +145 -7
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
claude-opus-4.7 ❯ think:med ❯ 2.6% / 1.0M ❯ Inspecting package structure ❯ plan:active
|
|
10
10
|
```
|
|
11
11
|
|
|
12
|
-

|
|
13
|
+

|
|
14
|
+

|
|
15
15
|
|
|
16
16
|
## Why use it?
|
|
17
17
|
|
|
@@ -91,7 +91,9 @@ const TLDR_TARGET_SUMMARY_CHARS = 60;
|
|
|
91
91
|
// Burst debouncing on the generation side: coalesce rapid-fire activities into
|
|
92
92
|
// one model call. Quiet window catches short bursts; max wait surfaces progress
|
|
93
93
|
// during continuous activity.
|
|
94
|
-
|
|
94
|
+
// Quiet window long enough to let tool_result land before flushing, so the
|
|
95
|
+
// model summarizes the completed outcome instead of guessing from tool_call.
|
|
96
|
+
const NORMAL_CHECKPOINT_QUIET_MS = 1_500;
|
|
95
97
|
const NORMAL_CHECKPOINT_MAX_WAIT_MS = 2_500;
|
|
96
98
|
// Defensive ceiling: even if the model ignores the length instruction, never
|
|
97
99
|
// blast a large payload into the footer.
|
|
@@ -650,7 +652,14 @@ class FooterTldrEngine {
|
|
|
650
652
|
}
|
|
651
653
|
|
|
652
654
|
recordUserMessage(ctx: ExtensionContext, prompt: string): void {
|
|
655
|
+
// A new user turn replaces the entire visible TLDR context, so wipe both
|
|
656
|
+
// the rendered text and the prior-turn checkpoint context that feeds the
|
|
657
|
+
// model. Carrying old checkpoints biased the next turn's phrasing toward
|
|
658
|
+
// the previous task.
|
|
653
659
|
this.currentText = null;
|
|
660
|
+
this.lastRenderedText = "";
|
|
661
|
+
this.acceptedCheckpoints.splice(0);
|
|
662
|
+
this.latestAcceptedActivityIndex = 0;
|
|
654
663
|
this.requestRender();
|
|
655
664
|
this.enqueue(ctx, this.facts.recordUserMessage(prompt));
|
|
656
665
|
}
|
|
@@ -661,10 +670,14 @@ class FooterTldrEngine {
|
|
|
661
670
|
}
|
|
662
671
|
|
|
663
672
|
recordToolCall(
|
|
664
|
-
|
|
673
|
+
_ctx: ExtensionContext,
|
|
665
674
|
event: { toolName: string; input?: Record<string, unknown>; toolCallId?: string },
|
|
666
675
|
): void {
|
|
667
|
-
|
|
676
|
+
// Record the fact so a subsequent checkpoint sees the tool was started,
|
|
677
|
+
// but DO NOT enqueue. tool_call alone has no outcome; flushing here
|
|
678
|
+
// before tool_result arrives makes the model hallucinate "completed
|
|
679
|
+
// successfully". The tool_result event triggers the actual checkpoint.
|
|
680
|
+
this.facts.recordToolCall(event);
|
|
668
681
|
}
|
|
669
682
|
|
|
670
683
|
recordToolResult(
|
|
@@ -689,9 +702,33 @@ class FooterTldrEngine {
|
|
|
689
702
|
this.startFreshRun();
|
|
690
703
|
return;
|
|
691
704
|
}
|
|
705
|
+
|
|
706
|
+
// Failure/aborted finals have no narratable content. A model call here
|
|
707
|
+
// fabricates a reason; render a deterministic literal instead.
|
|
708
|
+
if (result.activityType === "assistant_failure") {
|
|
709
|
+
const stopReason = extractStopReason(message);
|
|
710
|
+
this.renderLiteralFinal(stopReason);
|
|
711
|
+
this.facts.resetConversation();
|
|
712
|
+
this.startFreshRun();
|
|
713
|
+
return;
|
|
714
|
+
}
|
|
715
|
+
|
|
692
716
|
this.enqueue(ctx, result);
|
|
693
717
|
}
|
|
694
718
|
|
|
719
|
+
private renderLiteralFinal(stopReason: string | undefined): void {
|
|
720
|
+
this.clearPendingDisplay();
|
|
721
|
+
this.clearPendingNormalCheckpoint();
|
|
722
|
+
this.checkpointQueue.splice(0);
|
|
723
|
+
this.abortInFlightCheckpoint();
|
|
724
|
+
const literal = stopReason === "aborted" ? "Aborted." : `Stopped: ${stopReason ?? "error"}.`;
|
|
725
|
+
this.currentText = literal;
|
|
726
|
+
this.lastRenderedText = literal;
|
|
727
|
+
this.lastRenderedActivityIndex = this.facts.latestActivityIndex();
|
|
728
|
+
this.lastDisplayAt = performance.now();
|
|
729
|
+
this.requestRender();
|
|
730
|
+
}
|
|
731
|
+
|
|
695
732
|
private startFreshRun(): void {
|
|
696
733
|
this.runId++;
|
|
697
734
|
this.cancelWork();
|
|
@@ -930,6 +967,13 @@ class FooterTldrEngine {
|
|
|
930
967
|
private renderCheckpoint(checkpoint: TldrCheckpoint): void {
|
|
931
968
|
if (checkpoint.activityIndex <= this.lastRenderedActivityIndex) return;
|
|
932
969
|
if (checkpoint.text === this.lastRenderedText) return;
|
|
970
|
+
// Skip near-duplicates: a burst of consecutive checkpoints often produces
|
|
971
|
+
// the same action fragment with only punctuation/casing differences. They
|
|
972
|
+
// flash visibly in the footer without adding information.
|
|
973
|
+
if (isNearDuplicateTldr(checkpoint.text, this.lastRenderedText)) {
|
|
974
|
+
this.lastRenderedActivityIndex = checkpoint.activityIndex;
|
|
975
|
+
return;
|
|
976
|
+
}
|
|
933
977
|
this.lastRenderedActivityIndex = checkpoint.activityIndex;
|
|
934
978
|
this.lastRenderedText = checkpoint.text;
|
|
935
979
|
this.lastDisplayAt = performance.now();
|
|
@@ -970,12 +1014,19 @@ function checkpointSystemPrompt(job: TldrCheckpointJob): string {
|
|
|
970
1014
|
? "Start with a past-tense verb."
|
|
971
1015
|
: "Start with a present-tense -ing verb.";
|
|
972
1016
|
// Frame the model as a human developer describing visible work, not an agent
|
|
973
|
-
// summarizing its own mechanics.
|
|
974
|
-
//
|
|
1017
|
+
// summarizing its own mechanics. The banned phrases and few-shot examples
|
|
1018
|
+
// fix concrete regressions observed in backtests: tool-name verbs, success
|
|
1019
|
+
// suffixes, file path leaks, and markdown formatting.
|
|
975
1020
|
return `Write one plain-English TLDR for a Pi coding agent.
|
|
976
1021
|
Describe the work progress as if a human developer were doing it.
|
|
977
1022
|
Focus on the task activity and current outcome, not agent mechanics.
|
|
978
1023
|
Do not mention tools, tool calls, prompts, messages, model output, or implementation details.
|
|
1024
|
+
Do not start with tool-name verbs such as Read, Reading, Grep, Listing, Counting, Extracting, Displaying, Editing, Writing, Running, Publishing.
|
|
1025
|
+
Use human-developer verbs instead: Reviewing, Investigating, Exploring, Updating, Refining, Fixing, Implementing, Wrapping up.
|
|
1026
|
+
Do not use file paths, file extensions, code identifiers, package names, or version strings.
|
|
1027
|
+
Do not use backticks, asterisks, underscores, quotes, or any markdown formatting.
|
|
1028
|
+
Do not append filler suffixes such as "with success", "successfully", or "completed successfully".
|
|
1029
|
+
Do not claim progress or completion that is not present in the activity.
|
|
979
1030
|
Use the prior TLDRs for context and the new activity for the update.
|
|
980
1031
|
Summarize the current state of work; do not narrate the history.
|
|
981
1032
|
If context is sparse, still summarize the available activity.
|
|
@@ -986,9 +1037,45 @@ Prefer verb + direct object. Include outcome only if important.
|
|
|
986
1037
|
Do not address the user.
|
|
987
1038
|
Output only the status fragment itself. No prefixes, labels, bullets, or quotes.
|
|
988
1039
|
Plain text only; no markdown, JSON, code, file paths, or tool names.
|
|
1040
|
+
|
|
1041
|
+
Good examples:
|
|
1042
|
+
- Reviewing footer summary behavior
|
|
1043
|
+
- Investigating live TLDR regressions
|
|
1044
|
+
- Refining sanitizer for stray prefixes
|
|
1045
|
+
- Wrapping up extension release
|
|
1046
|
+
|
|
1047
|
+
Bad examples:
|
|
1048
|
+
- Editing extensions/status-footer.ts with success.
|
|
1049
|
+
- Reading status-footer file completed successfully.
|
|
1050
|
+
- Publishing \`pi-bar@0.3.3\` to npm.
|
|
1051
|
+
- Grepping for sanitizeTldrText callers.
|
|
1052
|
+
|
|
989
1053
|
${tenseInstruction}`;
|
|
990
1054
|
}
|
|
991
1055
|
|
|
1056
|
+
function extractStopReason(message: unknown): string | undefined {
|
|
1057
|
+
if (!message || typeof message !== "object") return undefined;
|
|
1058
|
+
const record = message as Record<string, unknown>;
|
|
1059
|
+
const stopReason = record.stopReason;
|
|
1060
|
+
return typeof stopReason === "string" ? stopReason : undefined;
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
// Two TLDRs are near-duplicates if their normalized action fragments (lowercase,
|
|
1064
|
+
// punctuation/whitespace collapsed) match. Catches bursts of cosmetic variants
|
|
1065
|
+
// like "Editing X." vs "Editing X" vs "editing x.".
|
|
1066
|
+
function normalizedActionFragment(text: string): string {
|
|
1067
|
+
return text
|
|
1068
|
+
.toLowerCase()
|
|
1069
|
+
.replace(/[\p{P}\p{S}]+/gu, " ")
|
|
1070
|
+
.replace(/\s+/gu, " ")
|
|
1071
|
+
.trim();
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
function isNearDuplicateTldr(current: string, previous: string): boolean {
|
|
1075
|
+
if (!previous) return false;
|
|
1076
|
+
return normalizedActionFragment(current) === normalizedActionFragment(previous);
|
|
1077
|
+
}
|
|
1078
|
+
|
|
992
1079
|
function previousCheckpointLines(checkpoints: readonly TldrCheckpoint[]): string {
|
|
993
1080
|
if (checkpoints.length === 0) return "none";
|
|
994
1081
|
return checkpoints
|
|
@@ -1110,6 +1197,7 @@ function stripTerminalControls(text: string): string {
|
|
|
1110
1197
|
const LEAKED_PREFIX_PATTERN =
|
|
1111
1198
|
/^\s*(?:[-*•]\s*)?(?:(?:through\s+activity|activity|checkpoint)\s+\d+\s*[:.\-—–]\s*|(?:tldr|summary)\s*[:.\-—–]\s*)+/i;
|
|
1112
1199
|
const LEADING_PUNCT_PATTERN = /^[\s\-—–•*:#.,;]+/;
|
|
1200
|
+
const TRAILING_PUNCT_PATTERN = /[\s\-—–•*:#.,;]+$/;
|
|
1113
1201
|
|
|
1114
1202
|
function stripLeakedScaffolding(text: string): string {
|
|
1115
1203
|
let cleaned = text;
|
|
@@ -1122,13 +1210,63 @@ function stripLeakedScaffolding(text: string): string {
|
|
|
1122
1210
|
return cleaned;
|
|
1123
1211
|
}
|
|
1124
1212
|
|
|
1213
|
+
// Strip backticks (` and triple-backtick fences) and markdown emphasis markers
|
|
1214
|
+
// the model occasionally adds despite the prompt's plain-text rule. We keep
|
|
1215
|
+
// inner content verbatim; only the formatting characters disappear.
|
|
1216
|
+
function stripMarkdownFormatting(text: string): string {
|
|
1217
|
+
return text
|
|
1218
|
+
.replace(/```+/g, "")
|
|
1219
|
+
.replace(/`+/g, "")
|
|
1220
|
+
.replace(/(^|[^\\])([*_~]{1,3})(.+?)\2/g, "$1$3");
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
// File-path / version / package leaks observed in backtests:
|
|
1224
|
+
// extensions/status-footer.ts, README.md, package.json, pi-bar@0.3.3, …
|
|
1225
|
+
const FILE_PATH_PATTERN =
|
|
1226
|
+
/(?:\b[\w./@-]+\.(?:ts|tsx|js|jsx|mjs|cjs|md|json|yml|yaml|toml|lock|sh|py|rs|go|html|css))\b/g;
|
|
1227
|
+
const PACKAGE_VERSION_PATTERN = /\b[\w./@-]+@\d[\w.+-]*\b/g;
|
|
1228
|
+
const VERSION_PATTERN = /\bv?\d+\.\d+(?:\.\d+(?:[-+][\w.]+)?)?\b/g;
|
|
1229
|
+
|
|
1230
|
+
function stripIdentifierLeaks(text: string): string {
|
|
1231
|
+
return text
|
|
1232
|
+
.replace(PACKAGE_VERSION_PATTERN, "")
|
|
1233
|
+
.replace(FILE_PATH_PATTERN, "")
|
|
1234
|
+
.replace(VERSION_PATTERN, "")
|
|
1235
|
+
.replace(/\s+/g, " ")
|
|
1236
|
+
.trim();
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
// Trailing filler suffixes observed in backtests:
|
|
1240
|
+
// "... with success.", "... completed successfully.", "... successfully."
|
|
1241
|
+
const SUCCESS_SUFFIX_PATTERN =
|
|
1242
|
+
/[\s,;:—–-]*(?:with\s+success|completed\s+successfully|finished\s+successfully|done\s+successfully|successfully\s+completed|successfully\s+finished|successfully)\s*[.!?]*\s*$/i;
|
|
1243
|
+
|
|
1244
|
+
function stripSuccessSuffix(text: string): string {
|
|
1245
|
+
let cleaned = text;
|
|
1246
|
+
let stripped = false;
|
|
1247
|
+
while (true) {
|
|
1248
|
+
const next = cleaned.replace(SUCCESS_SUFFIX_PATTERN, "").trim();
|
|
1249
|
+
if (next === cleaned || next.length === 0) break;
|
|
1250
|
+
cleaned = next;
|
|
1251
|
+
stripped = true;
|
|
1252
|
+
}
|
|
1253
|
+
// Only clean up trailing punctuation when an actual success suffix was
|
|
1254
|
+
// removed; otherwise we would strip the natural period from a normal
|
|
1255
|
+
// sentence like "Reviewing footer behavior.".
|
|
1256
|
+
if (stripped) cleaned = cleaned.replace(TRAILING_PUNCT_PATTERN, "").trim();
|
|
1257
|
+
return cleaned;
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1125
1260
|
function sanitizeTldrText(
|
|
1126
1261
|
text: string,
|
|
1127
1262
|
maxChars = MAX_SAFE_TLDR_CHARS,
|
|
1128
1263
|
): string {
|
|
1129
1264
|
const stripped = stripTerminalControls(text);
|
|
1130
|
-
const
|
|
1131
|
-
|
|
1265
|
+
const withoutMarkdown = stripMarkdownFormatting(stripped);
|
|
1266
|
+
const withoutScaffolding = stripLeakedScaffolding(withoutMarkdown) || withoutMarkdown;
|
|
1267
|
+
const withoutLeaks = stripIdentifierLeaks(withoutScaffolding) || withoutScaffolding;
|
|
1268
|
+
const withoutSuccess = stripSuccessSuffix(withoutLeaks) || withoutLeaks;
|
|
1269
|
+
return truncateText(withoutSuccess, maxChars);
|
|
1132
1270
|
}
|
|
1133
1271
|
|
|
1134
1272
|
function shouldShowStatus(key: string, filter: StatusFilter): boolean {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-bar",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.27",
|
|
4
4
|
"description": "Pi footer/statusline showing active model, thinking level, context pressure, live TLDR, and extension statuses.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -51,6 +51,6 @@
|
|
|
51
51
|
"extensions": [
|
|
52
52
|
"./extensions/status-footer.ts"
|
|
53
53
|
],
|
|
54
|
-
"image": "https://cdn.jsdelivr.net/npm/pi-bar@0.3.
|
|
54
|
+
"image": "https://cdn.jsdelivr.net/npm/pi-bar@0.3.27/assets/screenshot-yellow.png"
|
|
55
55
|
}
|
|
56
56
|
}
|