pum-agent 0.2.26-beta.3 → 0.2.27-beta.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pum-agent",
3
- "version": "0.2.26-beta.3",
3
+ "version": "0.2.27-beta.2",
4
4
  "description": "A compact terminal coding agent powered by pi and OpenTUI.",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/animation.tsx CHANGED
@@ -50,7 +50,7 @@ const SHIMMER_WIDTH = 7;
50
50
  const SHIMMER_TAIL = 120;
51
51
 
52
52
  const CARET = "▊";
53
- export const CARET_PERIOD_MS = 900;
53
+ export const CARET_PERIOD_MS = 1_800;
54
54
  /** Ramp length at each end of the caret's cycle, as a share of the period. */
55
55
  const CARET_RAMP = 0.12;
56
56
  /** Quantised fade steps, so one ramp costs a bounded number of repaints. */
@@ -139,7 +139,7 @@ export function weightedGlyph(glyph: string, strength: number): string {
139
139
  return glyph === "\u2500" && strength >= HEAVY_RULE_STRENGTH ? "\u2501" : glyph;
140
140
  }
141
141
 
142
- const RULE_CHARS_PER_MS = 0.08;
142
+ const RULE_CHARS_PER_MS = 0.04;
143
143
  const RULE_HIGHLIGHT_WIDTH = 10;
144
144
  const COMET_CHARS_PER_MS = 0.035;
145
145
  const ELECTRIC_FRAME_MS = 140;
@@ -344,7 +344,7 @@ const RAISED_LETTERS: Record<string, string> = {
344
344
  };
345
345
 
346
346
  /** How long one crest takes to cross the phrase, and the rest between sweeps. */
347
- const WAVE_CHARS_PER_MS = 0.022;
347
+ const WAVE_CHARS_PER_MS = 0.011;
348
348
  const WAVE_WIDTH = 5;
349
349
  const WAVE_REST_CHARS = 90;
350
350
 
package/src/app.tsx CHANGED
@@ -356,6 +356,9 @@ type PromptTextareaAction =
356
356
  | "select-buffer-home"
357
357
  | "select-buffer-end";
358
358
 
359
+ /** Half of OpenTUI's default drag auto-scroll rate. */
360
+ export const PROMPT_SCROLL_SPEED = 8;
361
+
359
362
  /** Standard editor navigation, with wrapped rows treated as visible lines. */
360
363
  export const PROMPT_TEXTAREA_KEY_BINDINGS: Array<{
361
364
  name: string;
@@ -5758,6 +5761,9 @@ export function App({
5758
5761
  const streamGap = visibleTx.stream
5759
5762
  ? needsTranscriptGap(lastLine, { kind: "text", role: visibleTx.stream.kind, text: visibleTx.stream.text })
5760
5763
  : false;
5764
+ const promptFocused = !transcriptFocused && !settingsOpen && !helpOpen && !historyOpen
5765
+ && !statsOpen && !agentSelectorOpen && !triggersOpen && !loginOpen && !providersOpen
5766
+ && !visibleQuestionnaire && !spawnPreview && !newsOpen && !todoVisible;
5761
5767
 
5762
5768
  // One element for the whole transcript, rebuilt only when what it shows
5763
5769
  // changes. React walks a child list of this size on every render of the app,
@@ -5999,7 +6005,8 @@ export function App({
5999
6005
  wrapMode="word"
6000
6006
  keyBindings={PROMPT_TEXTAREA_KEY_BINDINGS}
6001
6007
  scrollMargin={1}
6002
- focused={!transcriptFocused && !settingsOpen && !helpOpen && !historyOpen && !statsOpen && !agentSelectorOpen && !triggersOpen && !loginOpen && !providersOpen && !visibleQuestionnaire && !spawnPreview && !newsOpen && !todoVisible}
6008
+ scrollSpeed={PROMPT_SCROLL_SPEED}
6009
+ focused={promptFocused}
6003
6010
  onContentChange={handleTextareaChange}
6004
6011
  onCursorChange={scheduleInputMetrics}
6005
6012
  onSubmit={() => shellModeRef.current ? submitShellCommand() : submitPrompt()}
@@ -98,15 +98,12 @@ function joinPhrases(phrases: readonly string[]): string {
98
98
  }
99
99
 
100
100
  /**
101
- * Summarize one consecutive run of successful tool calls.
101
+ * Summarize one consecutive run without exposing arguments or outcomes.
102
102
  *
103
103
  * Tool types stay in first-occurrence order. Repeated types combine even when
104
- * another successful tool type occurs between them.
104
+ * another tool type occurs between them.
105
105
  */
106
- export function summarizeSuccessfulToolCalls(calls: readonly ToolCall[]): MinimalToolSummaryLine {
107
- if (calls.length === 0 || calls.some((call) => call.state !== "ok")) {
108
- throw new Error("A minimal tool summary requires one or more successful calls");
109
- }
106
+ function summarizeToolCalls(calls: readonly ToolCall[]): MinimalToolSummaryLine {
110
107
  const counts = new Map<string, number>();
111
108
  for (const call of calls) counts.set(call.name, (counts.get(call.name) ?? 0) + 1);
112
109
  const phrases = [...counts].map(([name, count]) => minimalToolPhrase(name, count));
@@ -117,32 +114,42 @@ export function summarizeSuccessfulToolCalls(calls: readonly ToolCall[]): Minima
117
114
  };
118
115
  }
119
116
 
117
+ /** Validate and summarize a direct list of successful calls. */
118
+ export function summarizeSuccessfulToolCalls(calls: readonly ToolCall[]): MinimalToolSummaryLine {
119
+ if (calls.length === 0 || calls.some((call) => call.state !== "ok")) {
120
+ throw new Error("A minimal tool summary requires one or more successful calls");
121
+ }
122
+ return summarizeToolCalls(calls);
123
+ }
124
+
120
125
  /**
121
126
  * Convert transcript lines for a grouped output mode.
122
127
  *
123
- * Every non-tool line and every non-successful tool call ends a success run.
124
- * Running, failed, and rejected calls remain unchanged with their details.
125
- * `groupEverySuccess` folds commands and mutations in too, which is what makes
126
- * Quiet minimal; Normal leaves them as their own rows.
128
+ * Every non-tool line ends a grouped run. Normal also ends a run at commands,
129
+ * mutations, running calls, failed calls, and rejected calls. Quiet groups all
130
+ * settled calls, including failed and rejected calls, but keeps running calls
131
+ * visible until they settle.
127
132
  */
128
133
  export function minimalTranscriptLines(
129
134
  lines: readonly Line[],
130
- groupEverySuccess = false,
135
+ groupEverySettled = false,
131
136
  ): MinimalTranscriptLine[] {
132
137
  const result: MinimalTranscriptLine[] = [];
133
- let successful: ToolCall[] = [];
138
+ let grouped: ToolCall[] = [];
134
139
  const groups = (call: ToolCall) =>
135
- groupEverySuccess ? call.state === "ok" : isRoutineSuccessfulTool(call);
140
+ groupEverySettled ? call.state !== "running" : isRoutineSuccessfulTool(call);
136
141
 
137
142
  const flush = () => {
138
- if (successful.length === 0) return;
139
- result.push(summarizeSuccessfulToolCalls(successful));
140
- successful = [];
143
+ if (grouped.length === 0) return;
144
+ result.push(groupEverySettled
145
+ ? summarizeToolCalls(grouped)
146
+ : summarizeSuccessfulToolCalls(grouped));
147
+ grouped = [];
141
148
  };
142
149
 
143
150
  for (const line of lines) {
144
151
  if (line.kind === "tool" && groups(line.call)) {
145
- successful.push(line.call);
152
+ grouped.push(line.call);
146
153
  continue;
147
154
  }
148
155
  flush();
@@ -19,8 +19,9 @@ export function transcriptOutputMode(settings: unknown): TranscriptOutputMode {
19
19
  *
20
20
  * Keep this boundary pure. Mode changes can then rerender the complete live or
21
21
  * resumed transcript without rewriting session entries or model context.
22
- * Quiet and Normal aggregate routine successful calls. Verbose keeps every
23
- * canonical tool row and changes ToolLine presentation only.
22
+ * Normal aggregates routine successful calls. Quiet aggregates every settled
23
+ * call, including failed and rejected calls. Verbose keeps every canonical
24
+ * tool row and changes ToolLine presentation only.
24
25
  *
25
26
  * Inter-agent messages answer to their own setting, not to the mode. What one
26
27
  * agent said to another is a different question from how much tool detail to