@saifymatteo/pi-compact-tools 0.1.4 → 0.1.5

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/CHANGELOG.md CHANGED
@@ -4,6 +4,12 @@ Release notes are recorded from 0.1.3 onward.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.1.5]
8
+
9
+ ### Fixed
10
+
11
+ - Keep new-request thinking and activity out of earlier tool cards, including steering messages received before session history is updated.
12
+
7
13
  ## [0.1.4]
8
14
 
9
15
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saifymatteo/pi-compact-tools",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Groups consecutive tool calls into compact expandable transcript cards.",
5
5
  "type": "module",
6
6
  "license": "AGPL-3.0-only",
package/src/index.ts CHANGED
@@ -455,7 +455,7 @@ function nestedSkills(result: SkillResult, toolName: string | undefined): string
455
455
  // Anything visible between two calls (user/custom message, assistant text)
456
456
  // starts a new group; tool results and thinking do not. A call seen twice
457
457
  // (the in-flight copy of an already persisted message) keeps its first group.
458
- function buildGroups(messages: Msg[]): { groupOf: Map<string, Group>; last?: Group } {
458
+ function buildGroups(messages: Msg[]): { groupOf: Map<string, Group>; last?: Group; active?: Group } {
459
459
  const groupOf = new Map<string, Group>();
460
460
  let current: Group | undefined;
461
461
  let last: Group | undefined;
@@ -488,7 +488,9 @@ function buildGroups(messages: Msg[]): { groupOf: Map<string, Group>; last?: Gro
488
488
  last = current;
489
489
  }
490
490
  }
491
- return { groupOf, last };
491
+ // Historical cards remain addressable, but only an unbroken trailing run
492
+ // can own live activity. A user message or assistant text ends that run.
493
+ return { groupOf, last, active: current };
492
494
  }
493
495
 
494
496
  // [verb, singular, plural]; tools sharing verb+noun are counted together.
@@ -680,9 +682,9 @@ function markToolContexts(): void {
680
682
  export default function (pi: ExtensionAPI) {
681
683
  let retired = false;
682
684
  let sessionManager: ExtensionContext["sessionManager"] | undefined;
683
- let live: Msg | undefined; // in-flight assistant message, maybe not persisted yet
685
+ let live: Msg | undefined; // latest user boundary or in-flight assistant, maybe not persisted yet
684
686
  let running = false;
685
- let cache: { key: string; groupOf: Map<string, Group>; last?: Group } | undefined;
687
+ let cache: (ReturnType<typeof buildGroups> & { key: string }) | undefined;
686
688
  const invalidators = new Map<string, () => void>(); // toolCallId -> row redraw
687
689
  // Native expanded belongs to Ctrl+O; pointer disclosure is local to the card.
688
690
  const openHeads = new Set<string>();
@@ -705,7 +707,7 @@ export default function (pi: ExtensionAPI) {
705
707
  }
706
708
 
707
709
  function syncActivity() {
708
- const head = running && !latestThought(live) ? groups().last?.head : undefined;
710
+ const head = running && !latestThought(live) ? groups().active?.head : undefined;
709
711
  if (!head || !invalidators.has(head)) { stopActivity(); return; }
710
712
  if (activityTimer !== undefined) return;
711
713
  // One timer for the current parent, never one per row or historical card.
@@ -713,7 +715,7 @@ export default function (pi: ExtensionAPI) {
713
715
  syncActivity();
714
716
  if (activityTimer === undefined) return;
715
717
  activityFrame = (activityFrame + 1) % activityFrames.length;
716
- invalidators.get(groups().last!.head)?.();
718
+ invalidators.get(groups().active!.head)?.();
717
719
  }, 160);
718
720
  }
719
721
 
@@ -829,7 +831,15 @@ export default function (pi: ExtensionAPI) {
829
831
  if (event.message.role === "assistant") {
830
832
  live = event.message as Msg;
831
833
  syncActivity();
832
- } else refresh();
834
+ } else {
835
+ if (event.message.role === "user") {
836
+ // message_start precedes persistence: do not wait for getBranch()
837
+ // to contain this boundary, especially for steering mid-run.
838
+ live = event.message as Msg;
839
+ cache = undefined;
840
+ }
841
+ refresh();
842
+ }
833
843
  });
834
844
  pi.on("message_update", (event) => {
835
845
  if (event.message.role !== "assistant") return;
@@ -848,7 +858,7 @@ export default function (pi: ExtensionAPI) {
848
858
  }
849
859
  // nf-fa-caret_down and nf-fa-caret_right
850
860
  let text = theme.fg("warning", theme.bold(`${openHeads.has(group.head) ? "\uf0d7" : "\uf0da"} ${summarize(names, images) || "Skill instructions"}`));
851
- if (running && group === groups().last) {
861
+ if (running && group === groups().active) {
852
862
  const thought = latestThought(live);
853
863
  // nf-md-thought_bubble_outline
854
864
  text += theme.fg("dim", thought ? ` \udb81\udff7 ${thought}` : ` ${activityFrames[activityFrame]}`);