pi-claude-code-ui 1.0.77 → 1.0.79

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
@@ -3,6 +3,18 @@
3
3
  > [!IMPORTANT]
4
4
  > **1.0.69 — package rename (permanent).** Canonical npm name is now [`pi-claude-code-ui`](https://www.npmjs.com/package/pi-claude-code-ui). `pi-claude-style-tools` is legacy and will not receive further releases. Install with `pi install npm:pi-claude-code-ui` or `npm i pi-claude-code-ui`.
5
5
 
6
+ ## 1.0.79 — 2026-08-23
7
+
8
+ ### Fixed
9
+
10
+ - **Hide Magic Context tags in tool output** — tool result renderers now receive sanitized text, so transient `§N§` tags (including live-prefixed streaming chunks and queued ctx_reduce output replayed from history) no longer appear in tool rows. Storage is never mutated — result blocks are cloned only when a tag is present, so context management keeps its data. Also covers the `formatToolExecution` fallback path for renderer-less tools.
11
+
12
+ ## 1.0.78 — 2026-08-22
13
+
14
+ ### Fixed
15
+
16
+ - **Hide transient Magic Context tags** — dynamically filter Magic Context tags (like `§N§`) from all Markdown view components in the Terminal UI. This covers thinking blocks, user messages, assistant prose, and subagent frames, without mutating the underlying message text content or breaking LLM prompt tracking.
17
+
6
18
  ## 1.0.77 — 2026-08-21
7
19
 
8
20
  ### Fixed
@@ -1496,6 +1496,26 @@ function stripTransientMagicContextTags(text: string): string {
1496
1496
  return text.replace(MAGIC_CONTEXT_TAG_LINE_PREFIX, "$1");
1497
1497
  }
1498
1498
 
1499
+ // Tool results can carry transient Magic Context tags too (live-prefixed output
1500
+ // chunks). Renderers must see sanitized text WITHOUT mutating this.result — the
1501
+ // result object is the stored message used by context management. Clone blocks
1502
+ // only when a tag is actually present so the common path stays zero-cost.
1503
+ function sanitizeToolResultForDisplay(result: any): any {
1504
+ if (!result || !Array.isArray(result.content)) return result;
1505
+ let changed = false;
1506
+ const content = result.content.map((block: any) => {
1507
+ if (block && typeof block.text === "string") {
1508
+ const stripped = stripTransientMagicContextTags(block.text);
1509
+ if (stripped !== block.text) {
1510
+ changed = true;
1511
+ return { ...block, text: stripped };
1512
+ }
1513
+ }
1514
+ return block;
1515
+ });
1516
+ return changed ? { ...result, content } : result;
1517
+ }
1518
+
1499
1519
  function replaceInlineMath(text: string): string {
1500
1520
  if (!hasInlineMathMarkers(text)) return text;
1501
1521
  const withParens = text.replace(/\\\(([\s\S]*?)\\\)/g, (_match, body: string) => {
@@ -1783,7 +1803,7 @@ class ThinkingParagraph {
1783
1803
  _markdownTheme: ConstructorParameters<typeof Markdown>[3],
1784
1804
  _defaultTextStyle?: ConstructorParameters<typeof Markdown>[4],
1785
1805
  ) {
1786
- this.text = text;
1806
+ this.text = stripTransientMagicContextTags(text);
1787
1807
  }
1788
1808
 
1789
1809
  private thinkingMarkdown(): InstanceType<typeof Markdown> {
@@ -1961,6 +1981,16 @@ function patchCustomMessageRender(): void {
1961
1981
  syncToolBackgroundMode();
1962
1982
  const cached = messageRenderCacheHit(this, width);
1963
1983
  if (cached) return cached;
1984
+ visitMarkdownDescendants(this, (child) => {
1985
+ const markdownAny = child as any;
1986
+ if (typeof markdownAny.text === "string") {
1987
+ const stripped = stripTransientMagicContextTags(markdownAny.text);
1988
+ if (stripped !== markdownAny.text) {
1989
+ markdownAny.text = stripped;
1990
+ child.invalidate?.();
1991
+ }
1992
+ }
1993
+ });
1964
1994
  const lines = originalRender.call(this, width);
1965
1995
  if (!Array.isArray(lines)) return lines;
1966
1996
  const result = isSubagentNotificationMessage(this?.message)
@@ -2058,6 +2088,13 @@ function patchUserMessageRender(): void {
2058
2088
  if (cached) return cached;
2059
2089
  visitMarkdownDescendants(this, (child) => {
2060
2090
  const markdownAny = child as any;
2091
+ if (typeof markdownAny.text === "string") {
2092
+ const stripped = stripTransientMagicContextTags(markdownAny.text);
2093
+ if (stripped !== markdownAny.text) {
2094
+ markdownAny.text = stripped;
2095
+ child.invalidate?.();
2096
+ }
2097
+ }
2061
2098
  makeMarkdownLinksCopySafe(child);
2062
2099
  if (markdownAny.defaultTextStyle?.bgColor) {
2063
2100
  markdownAny.defaultTextStyle.bgColor = undefined;
@@ -2087,6 +2124,16 @@ function patchAssistantMessages(): void {
2087
2124
  proto.render = function patchedAssistantMessageRender(width: number) {
2088
2125
  const cached = messageRenderCacheHit(this, width);
2089
2126
  if (cached) return cached;
2127
+ visitMarkdownDescendants(this, (child) => {
2128
+ const markdownAny = child as any;
2129
+ if (typeof markdownAny.text === "string") {
2130
+ const stripped = stripTransientMagicContextTags(markdownAny.text);
2131
+ if (stripped !== markdownAny.text) {
2132
+ markdownAny.text = stripped;
2133
+ child.invalidate?.();
2134
+ }
2135
+ }
2136
+ });
2090
2137
  const lines = originalRender.call(this, width);
2091
2138
  if (!Array.isArray(lines) || lines.length === 0) return lines;
2092
2139
  if ((this as any).hasToolCalls) {
@@ -2299,17 +2346,31 @@ function patchToolExecutionRenderers(): void {
2299
2346
 
2300
2347
  proto.getResultRenderer = function patchedGetResultRenderer() {
2301
2348
  const toolName = typeof this?.toolName === "string" ? this.toolName : "";
2349
+ let renderer: any;
2302
2350
  if (toolName === "apply_patch") {
2303
- return (result: any, options: any, theme: Theme, ctx: any) =>
2351
+ renderer = (result: any, options: any, theme: Theme, ctx: any) =>
2304
2352
  renderApplyPatchResult({ content: result.content, details: result.details }, options.isPartial, theme, ctx);
2305
- }
2306
- if (shouldUseGenericToolRenderer(toolName)) {
2307
- return (result: any, options: any, theme: Theme, ctx: any) =>
2353
+ } else if (shouldUseGenericToolRenderer(toolName)) {
2354
+ renderer = (result: any, options: any, theme: Theme, ctx: any) =>
2308
2355
  renderGenericToolResult(toolName, result, options, theme, ctx);
2356
+ } else {
2357
+ renderer = typeof originalGetResultRenderer === "function" ? originalGetResultRenderer.call(this) : undefined;
2309
2358
  }
2310
- return typeof originalGetResultRenderer === "function" ? originalGetResultRenderer.call(this) : undefined;
2359
+ if (typeof renderer !== "function") return renderer;
2360
+ // Strip transient Magic Context tags from the text the renderer sees,
2361
+ // without touching the stored result message.
2362
+ return (result: any, options: any, theme: Theme, ctx: any) => renderer(sanitizeToolResultForDisplay(result), options, theme, ctx);
2311
2363
  };
2312
2364
 
2365
+ // Fallback path for tools without a renderer definition formats raw text.
2366
+ const originalFormatToolExecution = proto.formatToolExecution;
2367
+ if (typeof originalFormatToolExecution === "function") {
2368
+ proto.formatToolExecution = function patchedFormatToolExecution(this: any, ...args: any[]) {
2369
+ const formatted = originalFormatToolExecution.apply(this, args);
2370
+ return typeof formatted === "string" ? stripTransientMagicContextTags(formatted) : formatted;
2371
+ };
2372
+ }
2373
+
2313
2374
  proto[TOOL_EXECUTION_PATCH_FLAG] = true;
2314
2375
  }
2315
2376
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-claude-code-ui",
3
- "version": "1.0.77",
3
+ "version": "1.0.79",
4
4
  "description": "Claude Code-style grouped tool rows for pi with Ctrl+O/Ctrl+Shift+O previews, math rendering, and consistent built-in, MCP, and custom tool rendering",
5
5
  "keywords": [
6
6
  "pi-package",