@zihanw/pi-forge 0.5.6 → 0.5.8

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.
Files changed (59) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +9 -9
  3. package/README.zh-CN.md +9 -9
  4. package/dist/preview-inspection.d.ts +68 -0
  5. package/dist/preview-inspection.d.ts.map +1 -0
  6. package/dist/preview-inspection.js +293 -0
  7. package/dist/preview-inspection.js.map +1 -0
  8. package/dist/preview.d.ts.map +1 -1
  9. package/dist/preview.js +16 -2
  10. package/dist/preview.js.map +1 -1
  11. package/dist/slot-renderers.js +1 -1
  12. package/dist/slot-renderers.js.map +1 -1
  13. package/dist/web-editor/client-script.generated.d.ts.map +1 -1
  14. package/dist/web-editor/client-script.generated.js +1 -1
  15. package/dist/web-editor/client-script.generated.js.map +1 -1
  16. package/dist/web-editor/client-styles.generated.d.ts.map +1 -1
  17. package/dist/web-editor/client-styles.generated.js +1 -1
  18. package/dist/web-editor/client-styles.generated.js.map +1 -1
  19. package/dist/web-editor/types.d.ts +18 -0
  20. package/dist/web-editor/types.d.ts.map +1 -1
  21. package/docs/README.md +1 -0
  22. package/docs/development/release.md +21 -5
  23. package/docs/development/roadmap.md +13 -3
  24. package/docs/development/setup.md +20 -4
  25. package/docs/guides/pi-1-compatibility.md +72 -0
  26. package/docs/guides/web-editor.md +18 -2
  27. package/docs/reference/capabilities.md +3 -3
  28. package/docs/reference/features.md +2 -2
  29. package/docs/reference/provider-support.md +1 -1
  30. package/docs/reference/stack-schema.md +1 -1
  31. package/docs/zh-CN/README.md +1 -0
  32. package/docs/zh-CN/guides/pi-1-compatibility.md +72 -0
  33. package/docs/zh-CN/guides/web-editor.md +18 -2
  34. package/docs/zh-CN/reference/capabilities.md +3 -3
  35. package/docs/zh-CN/reference/provider-support.md +1 -1
  36. package/package.json +17 -16
  37. package/assets/pi-forge-header-concept-1.png +0 -0
  38. package/assets/readme/PROVENANCE.md +0 -95
  39. package/assets/readme/en/capability-tools.gif +0 -0
  40. package/assets/readme/en/context-composition.gif +0 -0
  41. package/assets/readme/en/context-toggle.gif +0 -0
  42. package/assets/readme/en/draft-diff.png +0 -0
  43. package/assets/readme/en/edit-draft-diff.gif +0 -0
  44. package/assets/readme/en/editor-overview-v3.png +0 -0
  45. package/assets/readme/en/editor-overview.png +0 -0
  46. package/assets/readme/en/mode-tools.gif +0 -0
  47. package/assets/readme/en/regex-transforms.gif +0 -0
  48. package/assets/readme/en/tool-selection.gif +0 -0
  49. package/assets/readme/tui-quickstart.gif +0 -0
  50. package/assets/readme/zh-CN/capability-tools.gif +0 -0
  51. package/assets/readme/zh-CN/context-composition.gif +0 -0
  52. package/assets/readme/zh-CN/context-toggle.gif +0 -0
  53. package/assets/readme/zh-CN/draft-diff.png +0 -0
  54. package/assets/readme/zh-CN/edit-draft-diff.gif +0 -0
  55. package/assets/readme/zh-CN/editor-overview-v3.png +0 -0
  56. package/assets/readme/zh-CN/editor-overview.png +0 -0
  57. package/assets/readme/zh-CN/mode-tools.gif +0 -0
  58. package/assets/readme/zh-CN/regex-transforms.gif +0 -0
  59. package/assets/readme/zh-CN/tool-selection.gif +0 -0
package/CHANGELOG.md CHANGED
@@ -8,6 +8,26 @@ In 0.x development, breaking changes may occur in minor releases and will be exp
8
8
 
9
9
  ## [Unreleased]
10
10
 
11
+ ## [0.5.8] - 2026-10-03
12
+
13
+ - Keep README images and demonstration media in the repository, not the npm package. Link the accepted EN/ZH demos to immutable GitHub URLs; retain text documentation, examples, compiled code, types and source maps. Restrict package file patterns, reject media/asset entries and tarballs above 2 MiB during package checks, and run those checks automatically in prepack.
14
+
15
+ - Extend optional host peers to Pi 0.99.0, 0.99.1, 0.99.2 and the Pi 1.0 patch series (`>=1.0.0 <1.1.0`; 1.0.0, 1.0.1 and 1.0.2 tested) while retaining the Pi 0.87.x baseline. Pin development SDKs to 1.0.2 and TypeBox to 1.3.27; ordinary platform CI uses current pins and explicit Linux lanes retain older supported hosts.
16
+ - Parameterize packed consumers with `PI_TEST_VERSION` / `TYPEBOX_TEST_VERSION`, default to the coherent installed host, verify installed family versions and use normal npm peer resolution. Pass the selected host through compatibility/latest CI instead of silently packing against 0.87.0. Optional import smoke uses the companion's declared runtime dependency.
17
+ - Document Pi 1.0.1+ Anthropic native tool changes (fixed request-level list, later tools defined inline in `tool_addition`, at least one initial tool required) in the compatibility guide and provider support reference.
18
+ - Refresh the pi-docs slot and add bilingual native MCP/codemode migration notes and focused catalog/System-section regressions. Native MCP names remain exact: stale deny/remove names require review, not automatic aliases. This patch does not change initial/loadout authorization, Capability ownership, models.* access or usage accounting; published 0.5.7 metadata and personal configurations are unchanged.
19
+
20
+ ## [0.5.7] - 2026-09-28
21
+
22
+ - Preserve inspection choices through same-Preset draft edits with a clearly marked, paused previous preview. Restore native disclosure state after search/full-text, retain filtered history JSON reading positions, and search historical declaration JSON and named System keys without changing prompt text. Keep the Preset dock physically reachable on short narrow screens.
23
+
24
+ - Collapse individual historical tool declarations to one-line names, description excerpts and explicit top-level argument counts. Expand a declaration to inspect/copy its Preview JSON; unknown schemas do not imply zero arguments. This changes only inspection, not active tools or model context.
25
+
26
+ - Make Preview content-first: readable role-colored excerpts, one-line tool calls/results, and collapsible amber Tools groups with visible call/result/failure counts. Search full displayed text and tool identities, reveal matches, and copy individual tool text. Original projection order remains the default; optional call pairing changes only presentation within safe continuous tool intervals.
27
+ - Add ordered read-only inspection metadata from real compiled content parts, preserving System section operations, historical tool declarations, legacy text/token estimates and Draft/Run diff semantics. Correct duplicated history-slot Preview provenance instead of cross-associating identical call IDs from different slots. Same-data refresh retains reading state; the open Preset dock remains scroll-reachable on narrow screens.
28
+
29
+ - Restore scrolling in Current session: apply the expanded workspace's flex sizing to the correct element and constrain this surface to the viewport at narrow widths. Capability controls and context inspection remain independently scrollable on desktop; the stacked workspace and inspector remain reachable on small screens. Other surfaces retain their existing sizing.
30
+
11
31
  ## [0.5.6] - 2026-09-27
12
32
 
13
33
  - Make disabled Block/Slot rows visibly neutral as a whole: muted titles, gray side markers and a distinct background remain disabled-looking even when selected. Keep On/Off controls readable and preserve toggle focus for repeated Space/Enter operation.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [English](README.md) | [简体中文](README.zh-CN.md) · [Documentation](docs/README.md) · [Quick start](#install-and-first-run)
4
4
 
5
- ![pi-forge - Context editor and inspection workbench for Pi](assets/pi-forge-header-concept-1.png)
5
+ ![pi-forge - Context editor and inspection workbench for Pi](https://raw.githubusercontent.com/MacroSony/pi-forge/1184033b0ea1c211dd55aca8a74e9d1bbaa33e2b/assets/pi-forge-header-concept-1.png)
6
6
 
7
7
  **A context editor and inspection workbench for Pi.**
8
8
 
@@ -16,9 +16,9 @@ pi-forge provides visual context composition, tool selection, reusable configura
16
16
 
17
17
  ## Install and first run
18
18
 
19
- Requires Node.js **22.19 or newer**. The 0.5.6 line supports Pi **0.87.x** (`>=0.87.0 <0.88.0`), tested with **0.87.0**.
19
+ Requires Node.js **22.19 or newer**. Forge **0.5.8** supports Pi **0.87.x, 0.99.0–0.99.2 and 1.0.x**; see [compatibility and migration](docs/guides/pi-1-compatibility.md).
20
20
 
21
- > **Version note:** This README describes Forge **0.5.6**. Capabilities and configurable default tools require 0.5.5; optional subagents have a separate [compatibility requirement](docs/reference/subagent-host-port.md#tool-selection-compatibility).
21
+ > **Version note:** This README describes Forge **0.5.8**, a Pi host-compatibility patch. Older installed packages do not gain the expanded peer metadata automatically; tool-policy and Capability execution semantics are unchanged. Capabilities and configurable default tools require 0.5.5; optional subagents have a separate [compatibility requirement](docs/reference/subagent-host-port.md#tool-selection-compatibility).
22
22
 
23
23
  ```bash
24
24
  pi install npm:@zihanw/pi-forge
@@ -40,9 +40,9 @@ Prefer the terminal? Select a Preset with `/preset use <id>` and enable a Capabi
40
40
  Build your agent’s context from editable text blocks and slots for tools, skills, project files, and conversation history. Reorder or toggle them and see the result in Preview.
41
41
 
42
42
  - **Use case**: Give a code-review agent your project guidelines and selected context, instead of keeping one oversized prompt for every task.
43
- - **Try it**: In the editor’s **Stack**, edit or drag a block, toggle project context, and check **Preview**.
43
+ - **Try it**: In **Stack**, toggle a User message block, then drag it after the chat-history slot. Watch the roles and order update in **Preview**.
44
44
 
45
- ![Drag system blocks to reorder them, then toggle project context; Preview follows](assets/readme/en/context-composition.gif)
45
+ ![Toggle a supplemental User message and move it after chat history; Preview follows](https://raw.githubusercontent.com/MacroSony/pi-forge/1184033b0ea1c211dd55aca8a74e9d1bbaa33e2b/assets/readme/en/context-composition.gif)
46
46
 
47
47
  See [Web editor guide](docs/guides/web-editor.md) and [Stack schema](docs/reference/stack-schema.md).
48
48
 
@@ -53,7 +53,7 @@ Choose which tools an agent may use and which are available by default. An allow
53
53
  - **Use case**: Keep a review agent focused on reading and searching, without giving it editing or shell tools.
54
54
  - **Try it**: In **Policy**, choose the permitted tools and a default set such as `read` and `ls`. Add the already-permitted `grep` to the defaults and check the tool list in **Preview**; save and activate to apply the policy.
55
55
 
56
- ![Tool selection with policy defaults read/ls and adding grep](assets/readme/en/tool-selection.gif)
56
+ ![Tool selection with policy defaults read/ls and adding grep](https://raw.githubusercontent.com/MacroSony/pi-forge/1184033b0ea1c211dd55aca8a74e9d1bbaa33e2b/assets/readme/en/tool-selection.gif)
57
57
 
58
58
  See [Tool policy reference](docs/reference/stack-schema.md#tool-and-skill-policy).
59
59
 
@@ -64,7 +64,7 @@ Find and replace text in model input or completed assistant/tool output using re
64
64
  - **Use case**: Replace a known sensitive marker in selected prompt text before sending it, or clean repetitive boilerplate from responses.
65
65
  - **Try it**: In **Regex**, set up an outgoing rule matching the synthetic `SAMPLE_TOKEN`, replacing it with `[REDACTED]`, and targeting system text. The demo toggles this preconfigured rule and compares **Preview**.
66
66
 
67
- ![Regex transformation redacting outgoing synthetic SAMPLE_TOKEN](assets/readme/en/regex-transforms.gif)
67
+ ![Regex transformation redacting outgoing synthetic SAMPLE_TOKEN](https://raw.githubusercontent.com/MacroSony/pi-forge/1184033b0ea1c211dd55aca8a74e9d1bbaa33e2b/assets/readme/en/regex-transforms.gif)
68
68
 
69
69
  See [Regex transformation reference](docs/reference/stack-schema.md#regex-transforms).
70
70
 
@@ -79,7 +79,7 @@ Updates reach the model as native mid-conversation system updates on supported m
79
79
 
80
80
  On supported provider/model combinations, adding or removing tools can preserve the cached prompt prefix. Support differs for additions and removals, and cache hits are not guaranteed; see [provider support and cache observations](docs/reference/provider-support.md#observed-cache-behavior).
81
81
 
82
- ![Enable and locate Explore capability: tools and instruction changes together; Disable restores read and projects a removal](assets/readme/en/capability-tools.gif)
82
+ ![Enable and locate Explore capability: tools and instruction changes together; Disable restores read and projects a removal](https://raw.githubusercontent.com/MacroSony/pi-forge/1184033b0ea1c211dd55aca8a74e9d1bbaa33e2b/assets/readme/en/capability-tools.gif)
83
83
 
84
84
  See [Capabilities reference](docs/reference/capabilities.md).
85
85
 
@@ -90,7 +90,7 @@ See what your edits change before calling a model, then inspect captured request
90
90
  - **Use case**: Check whether a prompt edit adds the intended instructions, or compare successive requests when a run behaves differently than expected.
91
91
  - **Try it**: In `/forge ui`, switch to **Preview** to view compiled messages, open **Draft diff** to see unsaved changes, or run `/forge payload next` in the terminal to inspect the next outgoing request.
92
92
 
93
- ![An unsaved instruction change compared with the saved Preset](assets/readme/en/edit-draft-diff.gif)
93
+ ![An unsaved instruction change compared with the saved Preset](https://raw.githubusercontent.com/MacroSony/pi-forge/1184033b0ea1c211dd55aca8a74e9d1bbaa33e2b/assets/readme/en/edit-draft-diff.gif)
94
94
 
95
95
  **Current session** also shows turn and branch cache-hit rates, with main-model and reported nested-tool usage kept separate. These are recorded usage metrics, not a complete bill. See [cache usage](docs/reference/session-cache.md), [debugging](docs/guides/debugging.md), and [commands](docs/reference/commands.md).
96
96
 
package/README.zh-CN.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [English](README.md) | [简体中文](README.zh-CN.md) · [中文文档](docs/zh-CN/README.md) · [快速开始](#安装与第一次使用)
4
4
 
5
- ![pi-forge:Pi 的上下文编辑与检查工作台](assets/pi-forge-header-concept-1.png)
5
+ ![pi-forge:Pi 的上下文编辑与检查工作台](https://raw.githubusercontent.com/MacroSony/pi-forge/1184033b0ea1c211dd55aca8a74e9d1bbaa33e2b/assets/pi-forge-header-concept-1.png)
6
6
 
7
7
  **面向 Pi 的上下文编辑与检查工作台。**
8
8
 
@@ -16,9 +16,9 @@ pi-forge 为 [Pi](https://github.com/earendil-works/pi) 提供可视化上下文
16
16
 
17
17
  ## 安装与第一次使用
18
18
 
19
- Node.js 需要 **22.19 或更高版本**。0.5.6 支持 Pi **0.87.x**(`>=0.87.0 <0.88.0`),已在 **0.87.0** 上验证。
19
+ Node.js 需要 **22.19 或更高版本**。Forge **0.5.8** 支持 Pi **0.87.x、0.99.0–0.99.2 与 1.0.x**,见[兼容与迁移说明](docs/zh-CN/guides/pi-1-compatibility.md)。
20
20
 
21
- > **版本提示:** 本文介绍 Forge **0.5.6**。能力与可配置默认工具需要 0.5.5;可选 subagents 另有[兼容要求(英文)](docs/reference/subagent-host-port.md#tool-selection-compatibility)。
21
+ > **版本提示:** 本文介绍 Forge **0.5.8**,这是一次 Pi 宿主兼容补丁。旧安装包不会自动获得扩展后的 peer 元数据;工具策略和 Capability 执行语义保持不变。能力与可配置默认工具需要 0.5.5;可选 subagents 另有[兼容要求(英文)](docs/reference/subagent-host-port.md#tool-selection-compatibility)。
22
22
 
23
23
  ```bash
24
24
  pi install npm:@zihanw/pi-forge
@@ -40,9 +40,9 @@ pi install npm:@zihanw/pi-forge
40
40
  用可编辑的内容块和插槽组合 Agent 的上下文:指令、工具说明、技能、项目文件和聊天记录都可以放进来。调整顺序或开关条目,直接在预览中看结果。
41
41
 
42
42
  - **使用场景**:给代码审查 Agent 配上项目规范和相关上下文,而不是让所有任务共用一份越来越长的提示词。
43
- - **上手尝试**:在编辑器的 **Stack** 中编辑或拖动内容块、开关项目上下文,再看 **Preview** 中的变化。
43
+ - **上手尝试**:在 **Stack** 中开关一条 User 消息块,再将它拖到聊天历史插槽之后,在 **Preview** 中查看角色与顺序的变化。
44
44
 
45
- ![拖拽系统内容块排序,再关闭项目上下文插槽,预览随之更新](assets/readme/zh-CN/context-composition.gif)
45
+ ![开关补充 User 消息,再拖到聊天历史之后,预览随之更新](https://raw.githubusercontent.com/MacroSony/pi-forge/1184033b0ea1c211dd55aca8a74e9d1bbaa33e2b/assets/readme/zh-CN/context-composition.gif)
46
46
 
47
47
  详见 [Web 编辑器指南](docs/zh-CN/guides/web-editor.md)与 [Schema 与策略文档(英文)](docs/reference/stack-schema.md)。
48
48
 
@@ -53,7 +53,7 @@ pi install npm:@zihanw/pi-forge
53
53
  - **使用场景**:让代码审查 Agent 专注于阅读和搜索,不提供编辑文件或执行 shell 的工具。
54
54
  - **上手尝试**:在 **Policy** 中选择许可工具,并将默认工具设为 `read` 和 `ls`。把已获准的 `grep` 加入默认集,在 **Preview** 中查看工具列表;保存并启用预设后应用策略。
55
55
 
56
- ![工具选择:策略默认 read/ls 并添加 grep](assets/readme/zh-CN/tool-selection.gif)
56
+ ![工具选择:策略默认 read/ls 并添加 grep](https://raw.githubusercontent.com/MacroSony/pi-forge/1184033b0ea1c211dd55aca8a74e9d1bbaa33e2b/assets/readme/zh-CN/tool-selection.gif)
57
57
 
58
58
  详见 [工具策略参考(英文)](docs/reference/stack-schema.md#tool-and-skill-policy)。
59
59
 
@@ -64,7 +64,7 @@ pi install npm:@zihanw/pi-forge
64
64
  - **使用场景**:发送前替换选定提示词中的已知敏感标记,或者清理回复中反复出现的套话。
65
65
  - **上手尝试**:在 **Regex** 中配置出站规则,将示例文本 `SAMPLE_TOKEN` 替换为 `[REDACTED]`,目标选择 system 文本。演示中开关这条预先配置的规则,在 **Preview** 中对比结果。
66
66
 
67
- ![正则文本变换:出站虚构 SAMPLE_TOKEN 脱敏开关](assets/readme/zh-CN/regex-transforms.gif)
67
+ ![正则文本变换:出站虚构 SAMPLE_TOKEN 脱敏开关](https://raw.githubusercontent.com/MacroSony/pi-forge/1184033b0ea1c211dd55aca8a74e9d1bbaa33e2b/assets/readme/zh-CN/regex-transforms.gif)
68
68
 
69
69
  详见 [正则规则参考(英文)](docs/reference/stack-schema.md#regex-transforms)。
70
70
 
@@ -79,7 +79,7 @@ pi install npm:@zihanw/pi-forge
79
79
 
80
80
  在支持的 provider/模型组合上,新增或移除工具可以保留已有的提示词缓存前缀。新增与移除的支持范围不同,实际缓存命中不作保证;详见[支持情况与缓存实测](docs/zh-CN/reference/provider-support.md#实测缓存表现)。
81
81
 
82
- ![启用并定位探索能力:工具与指令同步可见;停用恢复 read 并显示移除更新](assets/readme/zh-CN/capability-tools.gif)
82
+ ![启用并定位探索能力:工具与指令同步可见;停用恢复 read 并显示移除更新](https://raw.githubusercontent.com/MacroSony/pi-forge/1184033b0ea1c211dd55aca8a74e9d1bbaa33e2b/assets/readme/zh-CN/capability-tools.gif)
83
83
 
84
84
  详见[能力参考](docs/zh-CN/reference/capabilities.md)。
85
85
 
@@ -90,7 +90,7 @@ pi install npm:@zihanw/pi-forge
90
90
  - **使用场景**:确认修改后的提示词包含了想要的指令,或在 Agent 表现不同时对比前后两次请求。
91
91
  - **上手尝试**:在 `/forge ui` 中切换至 **Preview** 查看编译消息,打开 **Draft diff** 对比未保存修改,或在终端运行 `/forge payload next` 捕获下一次出站请求。
92
92
 
93
- ![未保存的指令修改与已保存预设的差异](assets/readme/zh-CN/edit-draft-diff.gif)
93
+ ![未保存的指令修改与已保存预设的差异](https://raw.githubusercontent.com/MacroSony/pi-forge/1184033b0ea1c211dd55aca8a74e9d1bbaa33e2b/assets/readme/zh-CN/edit-draft-diff.gif)
94
94
 
95
95
  **当前会话**还会显示本轮和当前分支的缓存命中率,主模型与已上报的嵌套工具用量分开统计。这是已记录的用量,不是完整账单。详见[缓存用量](docs/zh-CN/reference/session-cache.md)、[调试指南(英文)](docs/guides/debugging.md)与[命令参考](docs/zh-CN/reference/commands.md)。
96
96
 
@@ -0,0 +1,68 @@
1
+ import type { AgentMessage } from "@earendil-works/pi-agent-core";
2
+ import type { CompileMessageSource } from "./types.ts";
3
+ import type { WebEditorPreviewPart, WebEditorPreviewSection } from "./web-editor/types.ts";
4
+ export interface RawPreviewPart {
5
+ kind: WebEditorPreviewPart["kind"];
6
+ text: string;
7
+ toolName?: string;
8
+ callId?: string;
9
+ }
10
+ export interface InspectionToolResultMeta {
11
+ callId?: string;
12
+ toolName?: string;
13
+ isError?: boolean;
14
+ }
15
+ /**
16
+ * Tracks occurrence counts per preview compile to disambiguate identical content
17
+ * or duplicate message identities within the same rendered preview.
18
+ *
19
+ * When duplicate fingerprints are detected, ALL occurrences sharing that fingerprint
20
+ * (including the first occurrence) are marked as temporary (:temp:N), and all of their
21
+ * part keys are retroactively updated as well.
22
+ */
23
+ export declare class InspectionOccurrenceTracker {
24
+ private readonly entriesByBaseKey;
25
+ register(baseKey: string, inspection: NonNullable<WebEditorPreviewSection["inspection"]>): void;
26
+ }
27
+ export declare function createInspectionTracker(): InspectionOccurrenceTracker;
28
+ /**
29
+ * Determines whether an inspection key is a temporary/duplicate key.
30
+ * When identical fingerprints repeat, all occurrences (including the first) are marked
31
+ * with a temporary key (:temp:N) and do not claim cross-insertion stability.
32
+ */
33
+ export declare function isTemporaryInspectionKey(key: string): boolean;
34
+ /**
35
+ * Resolve the inspection scope according to CompileMessageSource history slot instances,
36
+ * stack item identities, or implicit conversation history.
37
+ * Scoping ensures repeating history slots do not cross-pair.
38
+ */
39
+ export declare function resolveInspectionScope(source: CompileMessageSource | undefined, role?: string, isForgeUpdate?: boolean): string;
40
+ /**
41
+ * Format structured tool call arguments into clean display JSON.
42
+ * Preserves structured values without claiming wire raw text, and never
43
+ * substitutes null or missing values with `{}`.
44
+ */
45
+ export declare function formatToolCallArguments(args: unknown): string;
46
+ /**
47
+ * Extract raw ordered parts from a compiled AgentMessage.
48
+ * Does not guess from title or preview text; inspects the actual message content structure.
49
+ */
50
+ export declare function extractRawParts(message: AgentMessage | undefined): RawPreviewPart[];
51
+ /**
52
+ * Extract toolResult metadata strictly from a standard SDK toolResult message.
53
+ * Must be msg.role === 'toolResult' and strictly extract toolCallId from msg.toolCallId.
54
+ * Does not guess from unknown roles or other fields. Unknown roles remain neutral.
55
+ */
56
+ export declare function extractToolResult(message: unknown): InspectionToolResultMeta | undefined;
57
+ /**
58
+ * Compute stable content fingerprint from scope, role, full display parts, and toolResult.
59
+ * Ensures argument or tool changes alter the hash even if legacy content strings match.
60
+ * Distinguishes missing isError from false and true (does not default to false).
61
+ */
62
+ export declare function computeInspectionFingerprint(scope: string, role: string, parts: readonly RawPreviewPart[], toolResult?: InspectionToolResultMeta, systemMetadata?: unknown): string;
63
+ /**
64
+ * Build the complete inspection sidecar for a section from its compiled AgentMessage.
65
+ * Relies strictly on scope + display structure hash rather than heuristics on message fields.
66
+ */
67
+ export declare function buildSectionInspection(message: AgentMessage | undefined, scope: string, tracker: InspectionOccurrenceTracker): NonNullable<WebEditorPreviewSection["inspection"]>;
68
+ //# sourceMappingURL=preview-inspection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview-inspection.d.ts","sourceRoot":"","sources":["../src/preview-inspection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAElE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,KAAK,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAE3F,MAAM,WAAW,cAAc;IAC9B,IAAI,EAAE,oBAAoB,CAAC,MAAM,CAAC,CAAC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,wBAAwB;IACxC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB;AAQD;;;;;;;GAOG;AACH,qBAAa,2BAA2B;IACvC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAA0C;IAE3E,QAAQ,CACP,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,WAAW,CAAC,uBAAuB,CAAC,YAAY,CAAC,CAAC,GAC5D,IAAI;CA2BP;AAED,wBAAgB,uBAAuB,IAAI,2BAA2B,CAErE;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE7D;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACrC,MAAM,EAAE,oBAAoB,GAAG,SAAS,EACxC,IAAI,CAAC,EAAE,MAAM,EACb,aAAa,UAAQ,GACnB,MAAM,CAuBR;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAoB7D;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,YAAY,GAAG,SAAS,GAAG,cAAc,EAAE,CA0FnF;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,wBAAwB,GAAG,SAAS,CAiBxF;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,CAC3C,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,SAAS,cAAc,EAAE,EAChC,UAAU,CAAC,EAAE,wBAAwB,EACrC,cAAc,CAAC,EAAE,OAAO,GACtB,MAAM,CAeR;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACrC,OAAO,EAAE,YAAY,GAAG,SAAS,EACjC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,2BAA2B,GAClC,WAAW,CAAC,uBAAuB,CAAC,YAAY,CAAC,CAAC,CA8CpD"}
@@ -0,0 +1,293 @@
1
+ import { hashText } from "./context-diff.js";
2
+ /**
3
+ * Tracks occurrence counts per preview compile to disambiguate identical content
4
+ * or duplicate message identities within the same rendered preview.
5
+ *
6
+ * When duplicate fingerprints are detected, ALL occurrences sharing that fingerprint
7
+ * (including the first occurrence) are marked as temporary (:temp:N), and all of their
8
+ * part keys are retroactively updated as well.
9
+ */
10
+ export class InspectionOccurrenceTracker {
11
+ entriesByBaseKey = new Map();
12
+ register(baseKey, inspection) {
13
+ const entries = this.entriesByBaseKey.get(baseKey) ?? [];
14
+ const occurrence = entries.length + 1;
15
+ if (occurrence === 1) {
16
+ inspection.key = `${baseKey}:1`;
17
+ for (let i = 0; i < inspection.parts.length; i++) {
18
+ inspection.parts[i].key = `${inspection.key}:part:${i}`;
19
+ }
20
+ entries.push({ inspection, baseKey, occurrence });
21
+ this.entriesByBaseKey.set(baseKey, entries);
22
+ }
23
+ else {
24
+ // Only the first duplicate needs retroactive relabeling; later entries are already temporary.
25
+ for (const prev of occurrence === 2 ? entries : []) {
26
+ prev.inspection.key = `${baseKey}:temp:${prev.occurrence}`;
27
+ for (let i = 0; i < prev.inspection.parts.length; i++) {
28
+ prev.inspection.parts[i].key = `${prev.inspection.key}:part:${i}`;
29
+ }
30
+ }
31
+ // Mark current entry as temporary
32
+ inspection.key = `${baseKey}:temp:${occurrence}`;
33
+ for (let i = 0; i < inspection.parts.length; i++) {
34
+ inspection.parts[i].key = `${inspection.key}:part:${i}`;
35
+ }
36
+ entries.push({ inspection, baseKey, occurrence });
37
+ }
38
+ }
39
+ }
40
+ export function createInspectionTracker() {
41
+ return new InspectionOccurrenceTracker();
42
+ }
43
+ /**
44
+ * Determines whether an inspection key is a temporary/duplicate key.
45
+ * When identical fingerprints repeat, all occurrences (including the first) are marked
46
+ * with a temporary key (:temp:N) and do not claim cross-insertion stability.
47
+ */
48
+ export function isTemporaryInspectionKey(key) {
49
+ return key.includes(":temp:");
50
+ }
51
+ /**
52
+ * Resolve the inspection scope according to CompileMessageSource history slot instances,
53
+ * stack item identities, or implicit conversation history.
54
+ * Scoping ensures repeating history slots do not cross-pair.
55
+ */
56
+ export function resolveInspectionScope(source, role, isForgeUpdate = false) {
57
+ if (isForgeUpdate) {
58
+ return "forge-capability-update";
59
+ }
60
+ if (source?.kind === "stack-item") {
61
+ if (source.mergedItems && source.mergedItems.length > 0) {
62
+ return `stack-items:${source.mergedItems.map((item) => item.itemId ?? "").join("+")}`;
63
+ }
64
+ if (source.itemId) {
65
+ return `stack-item:${source.itemId}`;
66
+ }
67
+ return "stack-item";
68
+ }
69
+ if (source?.kind === "chat-history") {
70
+ return `chat-history:${source.itemId ?? source.slot ?? "history"}`;
71
+ }
72
+ if (source?.kind === "implicit-history") {
73
+ return "implicit-history";
74
+ }
75
+ if (role === "system") {
76
+ return "system";
77
+ }
78
+ return "implicit-history";
79
+ }
80
+ /**
81
+ * Format structured tool call arguments into clean display JSON.
82
+ * Preserves structured values without claiming wire raw text, and never
83
+ * substitutes null or missing values with `{}`.
84
+ */
85
+ export function formatToolCallArguments(args) {
86
+ if (args === undefined) {
87
+ return "[arguments unavailable]";
88
+ }
89
+ if (args === null) {
90
+ return "null";
91
+ }
92
+ if (typeof args === "string") {
93
+ return JSON.stringify(args);
94
+ }
95
+ try {
96
+ const formatted = JSON.stringify(args, null, 2);
97
+ return formatted !== undefined ? formatted : JSON.stringify(String(args));
98
+ }
99
+ catch {
100
+ try {
101
+ return JSON.stringify(String(args));
102
+ }
103
+ catch {
104
+ return String(args);
105
+ }
106
+ }
107
+ }
108
+ /**
109
+ * Extract raw ordered parts from a compiled AgentMessage.
110
+ * Does not guess from title or preview text; inspects the actual message content structure.
111
+ */
112
+ export function extractRawParts(message) {
113
+ if (!message)
114
+ return [];
115
+ const content = message.content;
116
+ if (Array.isArray(content)) {
117
+ const parts = [];
118
+ for (const part of content) {
119
+ if (!part || typeof part !== "object") {
120
+ if (typeof part === "string") {
121
+ parts.push({ kind: "text", text: part });
122
+ }
123
+ else {
124
+ parts.push({ kind: "unknown", text: "[unknown]" });
125
+ }
126
+ continue;
127
+ }
128
+ const item = part;
129
+ const type = item.type;
130
+ if (type === "text") {
131
+ parts.push({
132
+ kind: "text",
133
+ text: typeof item.text === "string" ? item.text : "",
134
+ });
135
+ }
136
+ else if (type === "thinking") {
137
+ parts.push({
138
+ kind: "thinking",
139
+ text: typeof item.thinking === "string" ? item.thinking : "",
140
+ });
141
+ }
142
+ else if (type === "toolCall") {
143
+ parts.push({
144
+ kind: "toolCall",
145
+ toolName: typeof item.name === "string" ? item.name : undefined,
146
+ callId: typeof item.id === "string" ? item.id : undefined,
147
+ text: formatToolCallArguments(item.arguments),
148
+ });
149
+ }
150
+ else if (type === "image") {
151
+ // Provide explicit placeholder/type only. Never copy or leak base64 data.
152
+ const mimeType = typeof item.mimeType === "string" && item.mimeType.trim().length > 0
153
+ ? item.mimeType.trim()
154
+ : "";
155
+ parts.push({
156
+ kind: "image",
157
+ text: mimeType ? `[image: ${mimeType}]` : "[image]",
158
+ });
159
+ }
160
+ else {
161
+ // Neutral type hint preserved for unknown part types
162
+ const typeHint = typeof type === "string" && type.trim().length > 0
163
+ ? type.trim()
164
+ : "unknown";
165
+ parts.push({
166
+ kind: "unknown",
167
+ text: `[unknown: ${typeHint}]`,
168
+ });
169
+ }
170
+ }
171
+ return parts;
172
+ }
173
+ if (typeof content === "string") {
174
+ if (content.length > 0) {
175
+ return [{ kind: "text", text: content }];
176
+ }
177
+ return [];
178
+ }
179
+ // Handle messages without content (e.g. bashExecution, branchSummary, or text property)
180
+ const msg = message;
181
+ const role = typeof msg.role === "string" ? msg.role : "";
182
+ if (role === "bashExecution") {
183
+ const command = typeof msg.command === "string" ? msg.command : "";
184
+ const output = typeof msg.output === "string" ? msg.output : "";
185
+ return [{ kind: "text", text: `Ran ${command}\n${output}` }];
186
+ }
187
+ if (role === "branchSummary" || role === "compactionSummary") {
188
+ const summary = typeof msg.summary === "string" ? msg.summary : "";
189
+ if (summary.length > 0) {
190
+ return [{ kind: "text", text: summary }];
191
+ }
192
+ }
193
+ if (typeof msg.text === "string" && msg.text.length > 0) {
194
+ return [{ kind: "text", text: msg.text }];
195
+ }
196
+ if (typeof msg.summary === "string" && msg.summary.length > 0) {
197
+ return [{ kind: "text", text: msg.summary }];
198
+ }
199
+ return [];
200
+ }
201
+ /**
202
+ * Extract toolResult metadata strictly from a standard SDK toolResult message.
203
+ * Must be msg.role === 'toolResult' and strictly extract toolCallId from msg.toolCallId.
204
+ * Does not guess from unknown roles or other fields. Unknown roles remain neutral.
205
+ */
206
+ export function extractToolResult(message) {
207
+ if (!message || typeof message !== "object")
208
+ return undefined;
209
+ const msg = message;
210
+ if (msg.role !== "toolResult") {
211
+ return undefined;
212
+ }
213
+ const callId = typeof msg.toolCallId === "string" ? msg.toolCallId : undefined;
214
+ const toolName = typeof msg.toolName === "string" ? msg.toolName : undefined;
215
+ const isError = typeof msg.isError === "boolean" ? msg.isError : undefined;
216
+ const res = {};
217
+ if (callId !== undefined)
218
+ res.callId = callId;
219
+ if (toolName !== undefined)
220
+ res.toolName = toolName;
221
+ if (isError !== undefined)
222
+ res.isError = isError;
223
+ return res;
224
+ }
225
+ /**
226
+ * Compute stable content fingerprint from scope, role, full display parts, and toolResult.
227
+ * Ensures argument or tool changes alter the hash even if legacy content strings match.
228
+ * Distinguishes missing isError from false and true (does not default to false).
229
+ */
230
+ export function computeInspectionFingerprint(scope, role, parts, toolResult, systemMetadata) {
231
+ const raw = JSON.stringify({
232
+ scope,
233
+ role,
234
+ systemMetadata,
235
+ parts: parts.map((p) => [p.kind, p.text, p.toolName ?? "", p.callId ?? ""]),
236
+ toolResult: toolResult
237
+ ? {
238
+ callId: toolResult.callId ?? null,
239
+ toolName: toolResult.toolName ?? null,
240
+ isError: toolResult.isError === undefined ? "missing" : toolResult.isError,
241
+ }
242
+ : null,
243
+ });
244
+ return hashText(raw);
245
+ }
246
+ /**
247
+ * Build the complete inspection sidecar for a section from its compiled AgentMessage.
248
+ * Relies strictly on scope + display structure hash rather than heuristics on message fields.
249
+ */
250
+ export function buildSectionInspection(message, scope, tracker) {
251
+ if (!message) {
252
+ const baseKey = `${scope}:system:empty`;
253
+ const inspection = {
254
+ key: "",
255
+ scope,
256
+ parts: [],
257
+ };
258
+ tracker.register(baseKey, inspection);
259
+ return inspection;
260
+ }
261
+ const role = String(message.role ?? "unknown");
262
+ const rawParts = extractRawParts(message);
263
+ const toolResult = extractToolResult(message);
264
+ // Named section operations and tool declarations are displayed separately, but
265
+ // still distinguish reading identity (including null versus an empty string).
266
+ const system = role === "system" ? message : undefined;
267
+ const metadata = system ? { sections: system.sections, added: system.toolsAdded, removed: system.toolsRemoved } : undefined;
268
+ const hash = computeInspectionFingerprint(scope, role, rawParts, toolResult, metadata);
269
+ const baseFingerprintKey = `${scope}:${role}:${hash}`;
270
+ const parts = rawParts.map((raw) => {
271
+ const part = {
272
+ key: "",
273
+ kind: raw.kind,
274
+ text: raw.text,
275
+ };
276
+ if (raw.toolName !== undefined)
277
+ part.toolName = raw.toolName;
278
+ if (raw.callId !== undefined)
279
+ part.callId = raw.callId;
280
+ return part;
281
+ });
282
+ const inspection = {
283
+ key: "",
284
+ scope,
285
+ parts,
286
+ };
287
+ if (toolResult) {
288
+ inspection.toolResult = toolResult;
289
+ }
290
+ tracker.register(baseFingerprintKey, inspection);
291
+ return inspection;
292
+ }
293
+ //# sourceMappingURL=preview-inspection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview-inspection.js","sourceRoot":"","sources":["../src/preview-inspection.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"preview.d.ts","sourceRoot":"","sources":["../src/preview.ts"],"names":[],"mappings":"AACA,OAAO,EAEN,KAAK,uBAAuB,EAC5B,KAAK,gBAAgB,EAErB,MAAM,iCAAiC,CAAC;AAsBzC,OAAO,KAAK,EAAwB,iBAAiB,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACvH,OAAO,KAAK,EAAE,gBAAgB,EAA2B,MAAM,uBAAuB,CAAC;AAEvF;;;;GAIG;AACH,wBAAgB,aAAa,CAC5B,GAAG,EAAE,uBAAuB,EAC5B,MAAM,EAAE,iBAAiB,GACvB,MAAM,CAER;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAC3B,GAAG,EAAE,gBAAgB,EACrB,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,oBAAoB,GAC3B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,gBAAgB,CAAC;IAAC,WAAW,EAAE,qBAAqB,EAAE,CAAA;CAAE,CAwHnF;AAgHD,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,qBAAqB,EAAE,GAAG,MAAM,CAG9E;AAED,wBAAsB,QAAQ,CAAC,GAAG,EAAE,uBAAuB,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMvG"}
1
+ {"version":3,"file":"preview.d.ts","sourceRoot":"","sources":["../src/preview.ts"],"names":[],"mappings":"AACA,OAAO,EAEN,KAAK,uBAAuB,EAC5B,KAAK,gBAAgB,EAErB,MAAM,iCAAiC,CAAC;AA2BzC,OAAO,KAAK,EAAwB,iBAAiB,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACvH,OAAO,KAAK,EAAE,gBAAgB,EAA2B,MAAM,uBAAuB,CAAC;AAEvF;;;;GAIG;AACH,wBAAgB,aAAa,CAC5B,GAAG,EAAE,uBAAuB,EAC5B,MAAM,EAAE,iBAAiB,GACvB,MAAM,CAER;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAC3B,GAAG,EAAE,gBAAgB,EACrB,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,oBAAoB,GAC3B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,gBAAgB,CAAC;IAAC,WAAW,EAAE,qBAAqB,EAAE,CAAA;CAAE,CAuInF;AAgHD,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,qBAAqB,EAAE,GAAG,MAAM,CAG9E;AAED,wBAAsB,QAAQ,CAAC,GAAG,EAAE,uBAAuB,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMvG"}
package/dist/preview.js CHANGED
@@ -10,6 +10,7 @@ import { getCurrentBranchEntries, readCapabilitySession } from "./session-adapte
10
10
  import { isCapabilityDelivery } from "./capability-protocol.js";
11
11
  import { materializeCapabilityAnchors } from "./capability-anchors.js";
12
12
  import { reduceCapabilityEvents } from "./capability-events.js";
13
+ import { buildSectionInspection, createInspectionTracker, resolveInspectionScope, } from "./preview-inspection.js";
13
14
  /**
14
15
  * Render preview for a prompt stack against current session context.
15
16
  * Evaluates the selected draft against current session capability snapshots without
@@ -41,10 +42,15 @@ export function buildPreview(ctx, target, options) {
41
42
  const baseProjected = projectPresetSystemPrompt(messages.messages, system.systemPrompt ?? "");
42
43
  // Base projection clones every System and may insert one new leading System.
43
44
  // Preserve provenance by position here, before capability projection inserts/removes entries.
45
+ // Multiple history slots can output identical message references; track a list per reference
46
+ // so duplicate slots retain their distinct slot instance identities and do not cross-pair.
44
47
  const originalMessageSources = new Map();
45
48
  const baseOffset = baseProjected.length - messages.messages.length;
46
49
  for (let i = 0; i < messages.messages.length; i++) {
47
- originalMessageSources.set(baseProjected[i + baseOffset], messages.messageSources[i]);
50
+ const msg = baseProjected[i + baseOffset];
51
+ const list = originalMessageSources.get(msg) ?? [];
52
+ list.push(messages.messageSources[i]);
53
+ originalMessageSources.set(msg, list);
48
54
  }
49
55
  const beforeCapabilityProjection = new Set(baseProjected);
50
56
  const history = readCapabilitySession(ctx);
@@ -86,6 +92,7 @@ export function buildPreview(ctx, target, options) {
86
92
  message: 'request-frequency regex rules also run on tool-result follow-up requests; only the first request of a turn is previewed.',
87
93
  });
88
94
  }
95
+ const inspectionTracker = createInspectionTracker();
89
96
  const leadingSystem = previewMessages[0]?.role === "system" ? previewMessages[0] : undefined;
90
97
  const systemSection = leadingSystem
91
98
  ? previewMessageSection(leadingSystem, "system", "System prompt", "system")
@@ -95,11 +102,16 @@ export function buildPreview(ctx, target, options) {
95
102
  if (capabilityUpdate)
96
103
  systemSection.capabilityUpdate = capabilityUpdate;
97
104
  }
105
+ systemSection.inspection = buildSectionInspection(leadingSystem, "system", inspectionTracker);
98
106
  const messagesToDisplay = leadingSystem ? previewMessages.slice(1) : previewMessages;
99
107
  const diffKeyOccurrences = new Map();
100
108
  const messageSections = [];
109
+ const sourceUsageCounts = new Map();
101
110
  for (const [index, message] of messagesToDisplay.entries()) {
102
- const source = originalMessageSources.get(message);
111
+ const sourceList = originalMessageSources.get(message);
112
+ const usageIndex = sourceUsageCounts.get(message) ?? 0;
113
+ sourceUsageCounts.set(message, usageIndex + 1);
114
+ const source = sourceList ? sourceList[usageIndex] : undefined;
103
115
  const isForgeUpdate = !beforeCapabilityProjection.has(message);
104
116
  const section = previewMessageSection(message, `message-${index}`, previewMessageTitle(source, index, isForgeUpdate));
105
117
  const capabilityUpdate = capabilityUpdates.get(message);
@@ -112,6 +124,8 @@ export function buildPreview(ctx, target, options) {
112
124
  const occurrence = (diffKeyOccurrences.get(baseDiffKey) ?? 0) + 1;
113
125
  diffKeyOccurrences.set(baseDiffKey, occurrence);
114
126
  section.diffKey = `${baseDiffKey}:${occurrence}`;
127
+ const scope = resolveInspectionScope(source, message.role, isForgeUpdate);
128
+ section.inspection = buildSectionInspection(message, scope, inspectionTracker);
115
129
  messageSections.push(section);
116
130
  }
117
131
  const totalChars = systemSection.chars + messageSections.reduce((sum, section) => sum + section.chars, 0);