@quandev104/pi-style 0.2.9 → 0.2.10
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 +16 -0
- package/README.md +2 -2
- package/dist/extensions/pi-style.js +3086 -2752
- package/dist/extensions/pi-style.js.map +1 -1
- package/extension-src/pi-style/app/command-service.ts +2 -0
- package/extension-src/pi-style/domain/config-normalization.ts +3 -0
- package/extension-src/pi-style/domain/config-types.ts +8 -0
- package/extension-src/pi-style/features/messages/index.ts +436 -35
- package/extension-src/pi-style/features/messages/special-blocks.ts +2 -22
- package/extension-src/pi-style/features/tools/bash-execution.ts +24 -8
- package/extension-src/pi-style/features/tools/boxed/edit.ts +25 -30
- package/extension-src/pi-style/features/tools/boxed/git.ts +21 -13
- package/extension-src/pi-style/features/tools/boxed/quick-edit.ts +35 -38
- package/extension-src/pi-style/features/tools/boxed/shared.ts +34 -0
- package/extension-src/pi-style/features/tools/boxed/turn-summary.ts +114 -38
- package/extension-src/pi-style/features/tools/boxed/write.ts +1 -0
- package/extension-src/pi-style/features/tools/index.ts +10 -6
- package/extension-src/pi-style/pi/compatibility-coordinator.ts +2 -0
- package/extension-src/pi-style/pi/compatibility-probe.ts +20 -9
- package/extension-src/pi-style/pi/session-coordinator.ts +20 -1
- package/extension-src/pi-style/shared/box.ts +126 -47
- package/package.json +1 -1
|
@@ -8,6 +8,13 @@
|
|
|
8
8
|
// global tool-output toggle (Ctrl+O) expands everything again
|
|
9
9
|
// (`options.expanded` is read, never written).
|
|
10
10
|
//
|
|
11
|
+
// The summary also reports the turn's aggregate diff stats (`· Edit +6 -2`,
|
|
12
|
+
// diff colors) computed purely from tool-result data — `details.diff` for
|
|
13
|
+
// edit, the parsed `── diff ──` output section for the quick-edit family
|
|
14
|
+
// (the same sources the box renderers read) — so live, scroll-back, and
|
|
15
|
+
// resume render identically. `write` carries no diff and is skipped; error
|
|
16
|
+
// members keep their visible blocks and never contribute stats.
|
|
17
|
+
//
|
|
11
18
|
// Mutating tools (edit/write/quick_edit/substitute_edit/target_edit) are
|
|
12
19
|
// exempt from the summary by default (`tools.collapseMutatingTools: off`):
|
|
13
20
|
// their blocks are the record of what was done to the user's files, so they
|
|
@@ -34,8 +41,11 @@
|
|
|
34
41
|
import type { Component } from "@earendil-works/pi-tui";
|
|
35
42
|
import type { BoxTheme } from "../../../shared/box.js";
|
|
36
43
|
import { safeTruncateToWidth } from "../../../shared/render-budget.js";
|
|
44
|
+
import { countDiffStats, firstText } from "../../../shared/split-diff.js";
|
|
37
45
|
import { pluralForm } from "./output-tree.js";
|
|
46
|
+
import { extractQuickEditDiff, getQuickEditToolConfig } from "./quick-edit.js";
|
|
38
47
|
import { getToolsRenderConfig } from "./session-config.js";
|
|
48
|
+
import { formatDiffStatsPair } from "./shared.js";
|
|
39
49
|
|
|
40
50
|
export interface TurnMemberInfo {
|
|
41
51
|
readonly toolCallId: string;
|
|
@@ -45,6 +55,8 @@ export interface TurnMemberInfo {
|
|
|
45
55
|
isError: boolean;
|
|
46
56
|
/** Frozen wall-clock elapsed (ms), recorded from the renderer context state. */
|
|
47
57
|
elapsedMs?: number;
|
|
58
|
+
/** Frozen diff line stats recorded from the tool result (edit family). */
|
|
59
|
+
diffStats?: { additions: number; removals: number } | undefined;
|
|
48
60
|
}
|
|
49
61
|
|
|
50
62
|
export interface TurnState {
|
|
@@ -114,22 +126,72 @@ function toolCallsOf(message: unknown): ToolCallLike[] {
|
|
|
114
126
|
return calls;
|
|
115
127
|
}
|
|
116
128
|
|
|
117
|
-
|
|
129
|
+
/** Tool-result fields the registry consumes (ToolResultMessage subset). */
|
|
130
|
+
export interface TurnResultLike {
|
|
131
|
+
readonly toolCallId: string;
|
|
132
|
+
readonly isError?: boolean;
|
|
133
|
+
readonly content?: readonly unknown[] | undefined;
|
|
134
|
+
readonly details?: unknown;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** Result facts per tool call id: presence, error flag, and raw payload. */
|
|
138
|
+
interface RawMemberResult {
|
|
139
|
+
readonly isError: boolean;
|
|
140
|
+
readonly content?: readonly unknown[] | undefined;
|
|
141
|
+
readonly details?: unknown;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Extract a mutating member's diff line stats from its tool result — the
|
|
146
|
+
* same sources the box renderers read: `details.diff` for `edit`, the
|
|
147
|
+
* parsed `── diff ──` output section for the quick-edit family. `write`
|
|
148
|
+
* carries no diff and yields undefined. Pure: no render-time work.
|
|
149
|
+
*/
|
|
150
|
+
function diffStatsFromResult(
|
|
151
|
+
toolName: string,
|
|
152
|
+
result: RawMemberResult | undefined,
|
|
153
|
+
): { additions: number; removals: number } | undefined {
|
|
154
|
+
if (!result) return undefined;
|
|
155
|
+
if (isMutatingTool(toolName) && toolName !== "write") {
|
|
156
|
+
const diff = (result.details as { diff?: unknown } | undefined)?.diff;
|
|
157
|
+
if (typeof diff === "string" && diff.length > 0) return countDiffStats(diff);
|
|
158
|
+
}
|
|
159
|
+
if (getQuickEditToolConfig(toolName)) {
|
|
160
|
+
const text = Array.isArray(result.content)
|
|
161
|
+
? firstText(result.content as Array<{ type: string; text?: string }>)
|
|
162
|
+
: "";
|
|
163
|
+
const diff = text ? extractQuickEditDiff(text) : undefined;
|
|
164
|
+
if (diff) return countDiffStats(diff);
|
|
165
|
+
}
|
|
166
|
+
return undefined;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function buildMembers(
|
|
118
170
|
calls: readonly ToolCallLike[],
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
)
|
|
122
|
-
if (calls.length === 0) return undefined;
|
|
123
|
-
const complete = calls.every((call) => typeof call.id === "string" && isErrorById.has(call.id));
|
|
124
|
-
const members: TurnMemberInfo[] = calls.map((call) => {
|
|
171
|
+
resultsById: ReadonlyMap<string, RawMemberResult>,
|
|
172
|
+
): TurnMemberInfo[] {
|
|
173
|
+
return calls.map((call) => {
|
|
125
174
|
const toolCallId = String(call.id ?? "");
|
|
175
|
+
const toolName = typeof call.name === "string" ? call.name : "tool";
|
|
176
|
+
const result = resultsById.get(toolCallId);
|
|
126
177
|
return {
|
|
127
178
|
toolCallId,
|
|
128
|
-
toolName
|
|
129
|
-
hasResult:
|
|
130
|
-
isError:
|
|
179
|
+
toolName,
|
|
180
|
+
hasResult: result !== undefined,
|
|
181
|
+
isError: result?.isError === true,
|
|
182
|
+
diffStats: diffStatsFromResult(toolName, result),
|
|
131
183
|
};
|
|
132
184
|
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function registerTurn(
|
|
188
|
+
calls: readonly ToolCallLike[],
|
|
189
|
+
resultsById: ReadonlyMap<string, RawMemberResult>,
|
|
190
|
+
ended: boolean,
|
|
191
|
+
): TurnState | undefined {
|
|
192
|
+
if (calls.length === 0) return undefined;
|
|
193
|
+
const complete = calls.every((call) => typeof call.id === "string" && resultsById.has(String(call.id ?? "")));
|
|
194
|
+
const members: TurnMemberInfo[] = buildMembers(calls, resultsById);
|
|
133
195
|
const leader = members.find((member) => !member.isError && (!isMutatingTool(member.toolName) || mutatingCollapses()));
|
|
134
196
|
const turn: TurnState = {
|
|
135
197
|
leaderId: leader?.toolCallId ?? "",
|
|
@@ -140,11 +202,6 @@ function registerTurn(
|
|
|
140
202
|
return turn;
|
|
141
203
|
}
|
|
142
204
|
|
|
143
|
-
export interface TurnResultLike {
|
|
144
|
-
readonly toolCallId: string;
|
|
145
|
-
readonly isError?: boolean;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
205
|
/**
|
|
149
206
|
* One summary group = one agent run (user request → `agent_end`). Pi emits
|
|
150
207
|
* `turn_end` per assistant message, so tool batches of the same request are
|
|
@@ -165,20 +222,16 @@ export function beginAgentRun(): void {
|
|
|
165
222
|
export function registerTurnFromMessage(message: unknown, toolResults: readonly TurnResultLike[]): void {
|
|
166
223
|
const calls = toolCallsOf(message);
|
|
167
224
|
if (calls.length === 0) return;
|
|
168
|
-
const
|
|
225
|
+
const resultsById = new Map<string, RawMemberResult>();
|
|
169
226
|
for (const result of toolResults) {
|
|
170
227
|
if (typeof result?.toolCallId !== "string") continue;
|
|
171
|
-
|
|
228
|
+
resultsById.set(result.toolCallId, {
|
|
229
|
+
isError: result.isError === true,
|
|
230
|
+
content: result.content,
|
|
231
|
+
details: result.details,
|
|
232
|
+
});
|
|
172
233
|
}
|
|
173
|
-
const newMembers: TurnMemberInfo[] = calls
|
|
174
|
-
const toolCallId = String(call.id ?? "");
|
|
175
|
-
return {
|
|
176
|
-
toolCallId,
|
|
177
|
-
toolName: typeof call.name === "string" ? call.name : "tool",
|
|
178
|
-
hasResult: isErrorById.has(toolCallId),
|
|
179
|
-
isError: isErrorById.get(toolCallId) === true,
|
|
180
|
-
};
|
|
181
|
-
});
|
|
234
|
+
const newMembers: TurnMemberInfo[] = buildMembers(calls, resultsById);
|
|
182
235
|
const leader = newMembers.find(
|
|
183
236
|
(member) => !member.isError && (!isMutatingTool(member.toolName) || mutatingCollapses()),
|
|
184
237
|
);
|
|
@@ -215,6 +268,7 @@ interface TurnEntryLike {
|
|
|
215
268
|
readonly message?: {
|
|
216
269
|
readonly role?: unknown;
|
|
217
270
|
readonly content?: unknown;
|
|
271
|
+
readonly details?: unknown;
|
|
218
272
|
readonly stopReason?: unknown;
|
|
219
273
|
readonly toolCallId?: unknown;
|
|
220
274
|
readonly isError?: unknown;
|
|
@@ -231,8 +285,7 @@ interface TurnEntryLike {
|
|
|
231
285
|
export function rebuildTurnRegistryFromEntries(entries: readonly TurnEntryLike[] | undefined): void {
|
|
232
286
|
memberByCallId.clear();
|
|
233
287
|
if (!Array.isArray(entries)) return;
|
|
234
|
-
const
|
|
235
|
-
const resultById = new Set<string>();
|
|
288
|
+
const resultsById = new Map<string, RawMemberResult>();
|
|
236
289
|
const runs: Array<{
|
|
237
290
|
calls: ToolCallLike[];
|
|
238
291
|
lastStopReason: string | undefined;
|
|
@@ -247,8 +300,11 @@ export function rebuildTurnRegistryFromEntries(entries: readonly TurnEntryLike[]
|
|
|
247
300
|
if (entry?.type !== "message") return;
|
|
248
301
|
const message = entry.message;
|
|
249
302
|
if (message?.role === "toolResult" && typeof message.toolCallId === "string") {
|
|
250
|
-
|
|
251
|
-
|
|
303
|
+
resultsById.set(message.toolCallId, {
|
|
304
|
+
isError: message.isError === true,
|
|
305
|
+
content: Array.isArray(message.content) ? (message.content as readonly unknown[]) : undefined,
|
|
306
|
+
details: message.details,
|
|
307
|
+
});
|
|
252
308
|
} else if (message?.role === "assistant") {
|
|
253
309
|
if (!current) current = { calls: [], lastStopReason: undefined, followedByUser: false };
|
|
254
310
|
const calls = toolCallsOf(message);
|
|
@@ -267,9 +323,9 @@ export function rebuildTurnRegistryFromEntries(entries: readonly TurnEntryLike[]
|
|
|
267
323
|
});
|
|
268
324
|
closeRun();
|
|
269
325
|
for (const run of runs) {
|
|
270
|
-
const complete = run.calls.every((call) => typeof call.id === "string" &&
|
|
326
|
+
const complete = run.calls.every((call) => typeof call.id === "string" && resultsById.has(String(call.id ?? "")));
|
|
271
327
|
const ended = complete && (run.followedByUser || run.lastStopReason !== undefined);
|
|
272
|
-
registerTurn(run.calls,
|
|
328
|
+
registerTurn(run.calls, resultsById, ended);
|
|
273
329
|
}
|
|
274
330
|
}
|
|
275
331
|
|
|
@@ -349,25 +405,37 @@ export interface TurnSummaryParts {
|
|
|
349
405
|
readonly failedCount: number;
|
|
350
406
|
/** Sum of members' frozen elapsed; undefined when nothing was recorded. */
|
|
351
407
|
readonly elapsedMs: number | undefined;
|
|
408
|
+
/** Aggregate diff line stats over non-error edit-family members; undefined
|
|
409
|
+
* when none carried a diff. Collected regardless of the mutating exemption:
|
|
410
|
+
* visible edit blocks are exactly what these stats describe. */
|
|
411
|
+
readonly diffStats: { additions: number; removals: number } | undefined;
|
|
352
412
|
}
|
|
353
413
|
|
|
354
414
|
/**
|
|
355
415
|
* Aggregate a turn's collapsed members into summary parts (pure). Mutating
|
|
356
|
-
* members are excluded unless `tools.collapseMutatingTools`
|
|
357
|
-
* their visible blocks are the record; the summary
|
|
358
|
-
* hides.
|
|
416
|
+
* members are excluded from counts/elapsed unless `tools.collapseMutatingTools`
|
|
417
|
+
* is on — by default their visible blocks are the record; the summary counts
|
|
418
|
+
* only what it hides. Their diff stats aggregate either way.
|
|
359
419
|
*/
|
|
360
420
|
export function turnSummaryParts(turn: TurnState): TurnSummaryParts {
|
|
361
421
|
const counts = new Map<string, number>();
|
|
362
422
|
const order: string[] = [];
|
|
363
423
|
let failedCount = 0;
|
|
364
424
|
let elapsedMs: number | undefined;
|
|
425
|
+
let diffAdditions = 0;
|
|
426
|
+
let diffRemovals = 0;
|
|
427
|
+
let diffMembers = 0;
|
|
365
428
|
const collapseMutating = mutatingCollapses();
|
|
366
429
|
for (const member of turn.members) {
|
|
367
430
|
if (member.isError) {
|
|
368
431
|
failedCount++;
|
|
369
432
|
continue;
|
|
370
433
|
}
|
|
434
|
+
if (member.diffStats !== undefined) {
|
|
435
|
+
diffAdditions += member.diffStats.additions;
|
|
436
|
+
diffRemovals += member.diffStats.removals;
|
|
437
|
+
diffMembers++;
|
|
438
|
+
}
|
|
371
439
|
if (!collapseMutating && isMutatingTool(member.toolName)) continue;
|
|
372
440
|
if (member.elapsedMs !== undefined) elapsedMs = (elapsedMs ?? 0) + member.elapsedMs;
|
|
373
441
|
const existing = counts.get(member.toolName);
|
|
@@ -383,16 +451,24 @@ export function turnSummaryParts(turn: TurnState): TurnSummaryParts {
|
|
|
383
451
|
// neutral phrasing with the invariant tool name: `used 5 TaskCreate`.
|
|
384
452
|
return style ? `${style.verb} ${count} ${pluralForm(style.unit, count)}` : `used ${count} ${toolName}`;
|
|
385
453
|
});
|
|
386
|
-
return {
|
|
454
|
+
return {
|
|
455
|
+
parts,
|
|
456
|
+
failedCount,
|
|
457
|
+
elapsedMs,
|
|
458
|
+
diffStats: diffMembers > 0 ? { additions: diffAdditions, removals: diffRemovals } : undefined,
|
|
459
|
+
};
|
|
387
460
|
}
|
|
388
461
|
|
|
389
462
|
function formatTurnSummaryLine(theme: BoxTheme, turn: TurnState): string {
|
|
390
463
|
const summary = turnSummaryParts(turn);
|
|
391
464
|
// The summary is deliberately quiet: the whole line renders dim so completed
|
|
392
|
-
// tool work recedes behind the assistant's answer. Only the
|
|
393
|
-
//
|
|
465
|
+
// tool work recedes behind the assistant's answer. Only the diff stats
|
|
466
|
+
// (`+N` added / `-M` removed) and the failed marker stay color-coded —
|
|
467
|
+
// changes and errors must remain visible at a glance.
|
|
394
468
|
const parts = summary.parts.join(", ");
|
|
395
469
|
let line = `${theme.fg("dim", `➔ ${parts}`)}`;
|
|
470
|
+
if (summary.diffStats !== undefined)
|
|
471
|
+
line += `${theme.fg("dim", " · Edit ")}${formatDiffStatsPair(theme, summary.diffStats.additions, summary.diffStats.removals)}`;
|
|
396
472
|
if (summary.failedCount > 0)
|
|
397
473
|
line += theme.fg("error", ` · ${summary.failedCount} ${pluralForm("failure", summary.failedCount)}`);
|
|
398
474
|
if (summary.elapsedMs !== undefined) line += theme.fg("dim", ` · ${(summary.elapsedMs / 1000).toFixed(2)}s`);
|
|
@@ -89,6 +89,7 @@ function renderWritePreviewBox(
|
|
|
89
89
|
isError: options.isError,
|
|
90
90
|
isPending: options.isPending,
|
|
91
91
|
running: Boolean(options.running),
|
|
92
|
+
tint: true, // the write preview is a framed box — it owns its status tint
|
|
92
93
|
bodyLines: () => {
|
|
93
94
|
if (preview.length === 0) return [];
|
|
94
95
|
const shown = preview.slice(0, budget).map((line) => formatNumberedLine(theme, line));
|
|
@@ -15,13 +15,16 @@ function hideBatchMember(instance: object): void {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
|
-
* Neutralize the native ToolExecutionComponent
|
|
18
|
+
* Neutralize the native ToolExecutionComponent container fill for boxed
|
|
19
19
|
* rendering: Pi's updateDisplay sets contentBox/selfRenderContainer bgFn to
|
|
20
20
|
* toolPendingBg/toolErrorBg/toolSuccessBg before invoking the renderers. The
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
21
|
+
* rendered boxes own their tint (box ⇒ background): boxed components wrap
|
|
22
|
+
* their own lines in the status fill while boxless surfaces (quiet-tool rows,
|
|
23
|
+
* tree panels, git/gh semantic cards, turn summaries) stay transparent — so
|
|
24
|
+
* the container fill is always removed. The native Box padding (1,1) is
|
|
25
|
+
* zeroed as well, or the frame would gain stray blank rows and an indent.
|
|
26
|
+
* Runs on every boxed dispatch; updateDisplay re-applies both on the next
|
|
27
|
+
* pass and this wrapper re-neutralizes them.
|
|
25
28
|
*/
|
|
26
29
|
function neutralizeToolContainerBackground(instance: object): void {
|
|
27
30
|
const host = instance as {
|
|
@@ -421,7 +424,6 @@ export function createToolDecorationOwner(snapshot: Partial<ToolDecorationSnapsh
|
|
|
421
424
|
// fallback renderer, mirroring the generic boxed fallback used for
|
|
422
425
|
// unknown tool names.
|
|
423
426
|
if (typeof renderer !== "function") {
|
|
424
|
-
neutralizeToolContainerBackground(instance);
|
|
425
427
|
if (subtype === "tool-call-renderer")
|
|
426
428
|
return (callArgs: unknown, theme: unknown, context: unknown) => {
|
|
427
429
|
const component = renderBoxedToolCall(
|
|
@@ -430,6 +432,7 @@ export function createToolDecorationOwner(snapshot: Partial<ToolDecorationSnapsh
|
|
|
430
432
|
theme as never,
|
|
431
433
|
context as never,
|
|
432
434
|
);
|
|
435
|
+
neutralizeToolContainerBackground(instance);
|
|
433
436
|
// Same batch-member contract as the native-renderer path: a
|
|
434
437
|
// collapsed turn member (or quiet batch member) returns the
|
|
435
438
|
// singleton and must be hidden, or Pi leaves a stray native
|
|
@@ -445,6 +448,7 @@ export function createToolDecorationOwner(snapshot: Partial<ToolDecorationSnapsh
|
|
|
445
448
|
theme as never,
|
|
446
449
|
context as never,
|
|
447
450
|
);
|
|
451
|
+
neutralizeToolContainerBackground(instance);
|
|
448
452
|
if (component === EMPTY_BATCH_COMPONENT) hideBatchMember(instance);
|
|
449
453
|
return component;
|
|
450
454
|
};
|
|
@@ -168,6 +168,8 @@ export function createCompatibilityCoordinator(dispose = disposePiCompatibilityP
|
|
|
168
168
|
assistantPrefix: authorization.ascii ? "[assistant] " : "│ ",
|
|
169
169
|
assistantEnabled,
|
|
170
170
|
collapseHiddenThinking: thinkingCollapseEnabled,
|
|
171
|
+
thoughtSummary: thinkingCollapseEnabled && config.messages.thoughtSummary,
|
|
172
|
+
thoughtGlyph: authorization.ascii ? ">" : "◈",
|
|
171
173
|
},
|
|
172
174
|
toolSnapshot: {
|
|
173
175
|
callMarker: authorization.ascii ? "[tool] " : "[tool] ",
|
|
@@ -44,6 +44,7 @@ export const SUPPORTED_PI_VERSIONS: readonly string[] = Object.freeze([
|
|
|
44
44
|
"0.84.3",
|
|
45
45
|
"0.84.4",
|
|
46
46
|
"0.85.0",
|
|
47
|
+
"0.85.1",
|
|
47
48
|
]);
|
|
48
49
|
|
|
49
50
|
/** A recorded native identity for one certified surface. */
|
|
@@ -97,7 +98,7 @@ export const KNOWN_NATIVE_IDENTITIES: Readonly<Record<string, readonly KnownNati
|
|
|
97
98
|
name: "render",
|
|
98
99
|
arity: 1,
|
|
99
100
|
fingerprint: "a9be09a3",
|
|
100
|
-
versions: Object.freeze(["0.84.3", "0.84.4", "0.85.0"]),
|
|
101
|
+
versions: Object.freeze(["0.84.3", "0.84.4", "0.85.0", "0.85.1"]),
|
|
101
102
|
}),
|
|
102
103
|
]),
|
|
103
104
|
"native-assistant-message:updateContent": Object.freeze([
|
|
@@ -132,7 +133,7 @@ export const KNOWN_NATIVE_IDENTITIES: Readonly<Record<string, readonly KnownNati
|
|
|
132
133
|
name: "updateContent",
|
|
133
134
|
arity: 1,
|
|
134
135
|
fingerprint: "80e338d2",
|
|
135
|
-
versions: Object.freeze(["0.85.0"]),
|
|
136
|
+
versions: Object.freeze(["0.85.0", "0.85.1"]),
|
|
136
137
|
}),
|
|
137
138
|
// 0.85.0 bundled: same drift, minified.
|
|
138
139
|
Object.freeze({
|
|
@@ -141,6 +142,16 @@ export const KNOWN_NATIVE_IDENTITIES: Readonly<Record<string, readonly KnownNati
|
|
|
141
142
|
fingerprint: "c3d72f2b",
|
|
142
143
|
versions: Object.freeze(["0.85.0"]),
|
|
143
144
|
}),
|
|
145
|
+
// 0.85.1 bundled: the rebundled runtime renames the minified `message2`
|
|
146
|
+
// parameter to `message` — the modular dist is unchanged from 0.85.0 (only
|
|
147
|
+
// the GPT-6 Astra model catalog and fullscreen-scroll fixes landed), so the
|
|
148
|
+
// minified method text drifts while behavior stays identical.
|
|
149
|
+
Object.freeze({
|
|
150
|
+
name: "updateContent",
|
|
151
|
+
arity: 1,
|
|
152
|
+
fingerprint: "31632e19",
|
|
153
|
+
versions: Object.freeze(["0.85.1"]),
|
|
154
|
+
}),
|
|
144
155
|
]),
|
|
145
156
|
"native-compaction-message:updateDisplay": Object.freeze([
|
|
146
157
|
Object.freeze({
|
|
@@ -153,7 +164,7 @@ export const KNOWN_NATIVE_IDENTITIES: Readonly<Record<string, readonly KnownNati
|
|
|
153
164
|
name: "updateDisplay",
|
|
154
165
|
arity: 0,
|
|
155
166
|
fingerprint: "5118a51d",
|
|
156
|
-
versions: Object.freeze(["0.84.3", "0.84.4", "0.85.0"]),
|
|
167
|
+
versions: Object.freeze(["0.84.3", "0.84.4", "0.85.0", "0.85.1"]),
|
|
157
168
|
}),
|
|
158
169
|
]),
|
|
159
170
|
"native-branch-message:updateDisplay": Object.freeze([
|
|
@@ -167,7 +178,7 @@ export const KNOWN_NATIVE_IDENTITIES: Readonly<Record<string, readonly KnownNati
|
|
|
167
178
|
name: "updateDisplay",
|
|
168
179
|
arity: 0,
|
|
169
180
|
fingerprint: "2185274e",
|
|
170
|
-
versions: Object.freeze(["0.84.3", "0.84.4", "0.85.0"]),
|
|
181
|
+
versions: Object.freeze(["0.84.3", "0.84.4", "0.85.0", "0.85.1"]),
|
|
171
182
|
}),
|
|
172
183
|
]),
|
|
173
184
|
"native-skill-message:updateDisplay": Object.freeze([
|
|
@@ -181,7 +192,7 @@ export const KNOWN_NATIVE_IDENTITIES: Readonly<Record<string, readonly KnownNati
|
|
|
181
192
|
name: "updateDisplay",
|
|
182
193
|
arity: 0,
|
|
183
194
|
fingerprint: "4051fd65",
|
|
184
|
-
versions: Object.freeze(["0.84.3", "0.84.4", "0.85.0"]),
|
|
195
|
+
versions: Object.freeze(["0.84.3", "0.84.4", "0.85.0", "0.85.1"]),
|
|
185
196
|
}),
|
|
186
197
|
]),
|
|
187
198
|
"native-custom-message:rebuild": Object.freeze([
|
|
@@ -195,7 +206,7 @@ export const KNOWN_NATIVE_IDENTITIES: Readonly<Record<string, readonly KnownNati
|
|
|
195
206
|
name: "rebuild",
|
|
196
207
|
arity: 0,
|
|
197
208
|
fingerprint: "b89987cc",
|
|
198
|
-
versions: Object.freeze(["0.84.3", "0.84.4", "0.85.0"]),
|
|
209
|
+
versions: Object.freeze(["0.84.3", "0.84.4", "0.85.0", "0.85.1"]),
|
|
199
210
|
}),
|
|
200
211
|
]),
|
|
201
212
|
"tool-call-renderer:getCallRenderer": Object.freeze([
|
|
@@ -224,7 +235,7 @@ export const KNOWN_NATIVE_IDENTITIES: Readonly<Record<string, readonly KnownNati
|
|
|
224
235
|
name: "getCallRenderer",
|
|
225
236
|
arity: 0,
|
|
226
237
|
fingerprint: "73116365",
|
|
227
|
-
versions: Object.freeze(["0.85.0"]),
|
|
238
|
+
versions: Object.freeze(["0.85.0", "0.85.1"]),
|
|
228
239
|
}),
|
|
229
240
|
]),
|
|
230
241
|
"tool-result-renderer:getResultRenderer": Object.freeze([
|
|
@@ -253,7 +264,7 @@ export const KNOWN_NATIVE_IDENTITIES: Readonly<Record<string, readonly KnownNati
|
|
|
253
264
|
name: "getResultRenderer",
|
|
254
265
|
arity: 0,
|
|
255
266
|
fingerprint: "d613a2a3",
|
|
256
|
-
versions: Object.freeze(["0.85.0"]),
|
|
267
|
+
versions: Object.freeze(["0.85.0", "0.85.1"]),
|
|
257
268
|
}),
|
|
258
269
|
]),
|
|
259
270
|
"native-bash-execution:render": Object.freeze([
|
|
@@ -271,7 +282,7 @@ export const KNOWN_NATIVE_IDENTITIES: Readonly<Record<string, readonly KnownNati
|
|
|
271
282
|
name: "BashExecutionComponent",
|
|
272
283
|
arity: 2,
|
|
273
284
|
fingerprint: "98d22d96",
|
|
274
|
-
versions: Object.freeze(["0.84.3", "0.84.4", "0.85.0"]),
|
|
285
|
+
versions: Object.freeze(["0.84.3", "0.84.4", "0.85.0", "0.85.1"]),
|
|
275
286
|
}),
|
|
276
287
|
]),
|
|
277
288
|
});
|
|
@@ -4,6 +4,7 @@ import type { ConfigFilePort } from "../app/config-storage.js";
|
|
|
4
4
|
import { createPiStyleApp, type PiStyleApp } from "../app/index.js";
|
|
5
5
|
import { resolveTheme } from "../domain/theme.js";
|
|
6
6
|
import { resetPendingImageRegistry } from "../features/messages/image-input.js";
|
|
7
|
+
import { setThoughtLabelTheme } from "../features/messages/index.js";
|
|
7
8
|
import { setMessagesRenderConfig } from "../features/messages/render-config.js";
|
|
8
9
|
import { setSpecialBlockTheme } from "../features/messages/special-blocks.js";
|
|
9
10
|
import { setBashExecutionTheme } from "../features/tools/bash-execution.js";
|
|
@@ -94,9 +95,26 @@ export function createPiStyleSessionCoordinator(pi: ExtensionAPI, hooks: Compati
|
|
|
94
95
|
* Hide Pi's "Thinking..." placeholder label: an empty label renders zero
|
|
95
96
|
* lines, so the thinking block leaves no trace while content stays hidden.
|
|
96
97
|
* Passing undefined restores the default label.
|
|
98
|
+
*
|
|
99
|
+
* Gated on the certified `updateContent` surface actually being installed:
|
|
100
|
+
* blanking without the patch leaves Pi's native invisible-row gap (worse
|
|
101
|
+
* than the label it replaces), so an unsupported runtime identity keeps the
|
|
102
|
+
* native `Thinking...` label instead.
|
|
97
103
|
*/
|
|
104
|
+
const thinkingCollapseInstalled = (): boolean => {
|
|
105
|
+
const records = compatibility.report?.recordSnapshots ?? [];
|
|
106
|
+
return records.some(
|
|
107
|
+
(record) =>
|
|
108
|
+
record.subtype === "native-assistant-message" &&
|
|
109
|
+
record.method === "updateContent" &&
|
|
110
|
+
record.shape === "installed" &&
|
|
111
|
+
!record.disposed,
|
|
112
|
+
);
|
|
113
|
+
};
|
|
98
114
|
const applyMessagesConfig = (config: import("../domain/config-types.js").NormalizedPiStyleConfig) => {
|
|
99
|
-
sessionUi?.setHiddenThinkingLabel?.(
|
|
115
|
+
sessionUi?.setHiddenThinkingLabel?.(
|
|
116
|
+
config.messages.hideThinkingLabel && thinkingCollapseInstalled() ? "" : undefined,
|
|
117
|
+
);
|
|
100
118
|
// User-prompt image previews (ADR 0008) + clipboard image input (ADR
|
|
101
119
|
// 0009): the leaves gate their respective sides (preview: stage+render;
|
|
102
120
|
// clipboard: input transform) and size the preview images.
|
|
@@ -211,6 +229,7 @@ export function createPiStyleSessionCoordinator(pi: ExtensionAPI, hooks: Compati
|
|
|
211
229
|
applyMessagesConfig(app.config);
|
|
212
230
|
if (ctx.ui?.theme) setSpecialBlockTheme(ctx.ui.theme as never);
|
|
213
231
|
if (ctx.ui?.theme) setBashExecutionTheme(ctx.ui.theme as never);
|
|
232
|
+
if (ctx.ui?.theme) setThoughtLabelTheme(ctx.ui.theme as never);
|
|
214
233
|
const toolDetails = collectToolDetails(pi.getActiveTools?.(), pi.getAllTools?.());
|
|
215
234
|
app.sessionStart(
|
|
216
235
|
{
|