@clapecho233/pi-smart-fold 0.1.0 → 0.2.0

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/README.md CHANGED
@@ -1,64 +1,141 @@
1
1
  # pi-smart-fold
2
2
 
3
- [pi](https://github.com/earendil-works/pi-mono) coding-agent 插件:保持会话记录紧凑。
3
+ A [pi](https://github.com/earendil-works/pi-mono) coding-agent extension that keeps the session transcript compact — without losing key information.
4
4
 
5
- - **工具输出默认折叠** — 每次 `session_start`(启动 / `/reload` / `/new` / `/resume` / `/fork`)自动调用 `ctx.ui.setToolsExpanded(false)`,工具输出保持折叠,需要时用 `ctrl+o` 手动展开。
6
- - **Thinking 折叠为单行、默认滚动显示最后一行** — 通过 pi 的 markdown transformer(`messageType: "assistant-thinking"`)把每个思考块折叠成一行,只显示**最后一行**内容;流式输出时该行随最新内容持续刷新,效果如同 `tail -f`。
7
- - 截断按**终端显示宽度**计算(中文/emoji 等宽字符占 2 列),超宽时保留行尾并加 `…` 前缀。
8
- - 折叠仅影响 TUI 显示,不改动会话文件与发送给模型的上下文。
5
+ | Without smart-fold | With smart-fold |
6
+ | --- | --- |
7
+ | Long thinking walls, verbose tool output, full file previews | One-line `Thought for 12.4s` summaries, folded tool output, `write src/index.ts +12 -3` headers |
9
8
 
10
- ## 使用
9
+ ## Features
10
+
11
+ ### 1. Thinking fold + live timer (`smart` mode, default)
12
+
13
+ **While the model thinks**, the block shows a bold **`Thinking… (8s)`** header line, followed by the scrolling *tail* of the thinking text (like `tail -f`). **One click toggles directly to the full text so far** (the ticking **`Thinking… (8s)`** line stays pinned at the bottom and keeps updating); **one more click toggles back** to the scrolling tail. There is no intermediate label state — a single click always switches between `scrolling tail ↔ full view`:
11
14
 
12
15
  ```text
13
- /fold 查看当前状态
14
- /fold thinking on|off 开关 thinking 折叠(持久化到 smart-fold.config.json)
15
- /fold tools on|off 开关启动时工具输出折叠(立即作用于当前会话,并持久化)
16
+ Scrolling tail (default) Full view (after one click)
17
+ Thinking… (8s) …earlier thinking text…
18
+ …latest line of thinking …thinking still streaming…
19
+ Thinking… (9s) ← pinned at the bottom, live-updating
16
20
  ```
17
21
 
18
- 配置文件 `smart-fold.config.json`(位于插件目录,可手工编辑):
22
+ **After the thinking run finishes**, the block collapses to a single bold **`Thought for 12.4s`** line (measured duration). If the block was in full view at that moment, it transitions smoothly to the pinned duration footer first.
23
+
24
+ **Single-click expand/collapse per block**: finished thinking starts hidden (seeded by a prototype patch). **One click → that block expands to its full text** (with the bold duration line kept at the bottom); **one more click → collapses back**. No intermediate states, and only the clicked block is affected — other thinking runs in the same message are untouched. The same one-click toggle works for a run that already finished *while its message is still streaming* (e.g. thinking done, answer text or a tool call still coming): the folded `Thought for …` line expands directly — never through pi's bare `Thought…` label middle state.
25
+
26
+ - **Fully takes over native folding**: pi's built-in hidden-thinking label (`Thinking...`) is replaced with per-message `Thought for …` labels generated by this extension. What you see after clicks or `ctrl+t` is always our text, never the native one. (In `smart` mode `ctrl+t` has no extra effect — use clicks or `/fold expand` instead.)
27
+ - **Exact click detection**: an idempotent prototype patch on pi's publicly exported `AssistantMessageComponent` seeds the hidden state of finished thinking runs and observes writes to the component's internal visibility map (distinguishing `ctrl+t`'s clear operation). Clicks on runs of a still-streaming message — the live run as well as already-finished ones — are redirected so the native two-state toggle's hidden middle state never appears. Global re-renders — theme changes, window resizes, layout redraws — are never mistaken for clicks. If a future pi version can't be patched, the extension degrades gracefully to pi's native display (with `/fold expand` as a fallback).
28
+ - **Persistent durations**: each thinking run's duration is recorded in the session file keyed by content hash (a `smart-fold-thinking` custom entry, never sent to the LLM context), so durations still show after `/resume`. Multiple thinking runs within one message (between tool calls) are timed individually.
29
+ - **Code-block safe**: while a code fence streams through the thinking text, structural fence lines are skipped in the collapsed tail — the block never flashes fully open for a frame. In the expanded view an unclosed code fence is closed automatically so the `Thinking…/Thought for …` footer renders below it as bold text, never swallowed into the code block as literal `**asterisks**`.
30
+ - Truncation is measured in **terminal display columns** (CJK characters / emoji count as 2), keeping the line ending with an `…` prefix when over-wide.
31
+ - Folding is **display-only**: the session file and the context sent to the model are never modified.
32
+
33
+ Other modes: `tail` (always one line — the text tail with a bold duration prefix), `full` (show full text after the run ends, with the duration footer), `off` (disable and restore pi's default thinking display).
34
+
35
+ Fallback: `/fold expand on|off` (or "Expand all thinking" in the settings panel) temporarily expands/collapses *all* finished thinking blocks. Daily usage only needs single clicks on individual blocks; new sessions always start fully folded.
36
+
37
+ ### 2. Tool output folding
38
+
39
+ On every `session_start` (startup, `/reload`, `/new`, `/resume`, `/fork`) the extension calls `ctx.ui.setToolsExpanded(false)` so tool output stays collapsed; press `ctrl+o` to expand manually.
40
+
41
+ ### 3. Tool call line truncation + write/edit diff stats
42
+
43
+ - **Long call lines are truncated**: `bash` / `read` / `grep` / `find` / `ls` call lines collapse to a single line, cut to the terminal width with a trailing `…` (pi's ANSI-aware `truncateToWidth`). An extra ` …` marker is appended when the command has more lines. Click or `ctrl+o` to expand and see everything.
44
+ - **write / edit line-diff stats**:
45
+ - `write`: reads the original file content *before* the write executes and computes a line-level diff (common prefix/suffix trimming + LCS). The header line gains a **green `+added` / red `-removed`** suffix, e.g. `write src/index.ts +12 -3`; new files show `+N -0`. Files larger than 8 MB are skipped. Stats are **persisted with the tool result in the session file**, so they still show in restored sessions (writes made before this version have no record and show nothing).
46
+ - `edit`: diffs each `edits[]` entry's `oldText → newText` directly and sums the result, e.g. `edit src/app.ts +2 -1` (updates live while arguments stream in).
47
+ - **write/edit collapse to a header-only line by default** (`writeCollapsed: header`): collapsed rows show just the one-line header — no code content or diff preview (not natively possible in pi; implemented by wrapping both `renderCall` and `renderResult` — the result area renders an empty component while collapsed, and error messages remain visible). Click / `ctrl+o` expands to the full diff / syntax-highlighted content. The **`+N -M` stat stays in the header line in both states** (edit's native full-width background bar is preserved; the stat is injected into the trailing padding without changing the line width). Switch to `preview` in settings to restore pi's native preview.
48
+ - Implemented as rendering wrappers around pi's built-in tools (execution logic is fully reused from each `create*ToolDefinition`).
49
+
50
+ ## Settings
51
+
52
+ ```
53
+ /fold Open a /config-style interactive settings list (Enter/Space to change, Esc to close)
54
+ ```
55
+
56
+ Or change values directly (with autocompletion):
57
+
58
+ ```text
59
+ /fold thinking smart|tail|full|off # on=smart, off=off accepted for compatibility
60
+ /fold tools on|off # fold tool output at session start
61
+ /fold writestat on|off # write/edit diff stats toggle
62
+ /fold writecollapsed header|preview # write rows: header-only / keep preview when collapsed
63
+ ```
64
+
65
+ Config file `smart-fold.config.json` (next to the extension entry; the legacy boolean `thinkingFold` is migrated automatically):
19
66
 
20
67
  ```json
21
68
  {
22
69
  "toolsFold": true,
23
- "thinkingFold": true
70
+ "thinking": "smart",
71
+ "writeStat": true,
72
+ "writeCollapsed": "header"
24
73
  }
25
74
  ```
26
75
 
27
- ## 安装
76
+ ## Installation
28
77
 
29
- 任选其一:
78
+ Any one of these:
30
79
 
31
80
  ```bash
32
- # 方式 A:作为目录插件放入全局自动发现路径
81
+ # Option A: clone into pi's global extension auto-discovery directory
33
82
  git clone <this-repo> ~/.pi/agent/extensions/smart-fold
34
83
 
35
- # 方式 B:通过 pi 包管理安装
84
+ # Option B: install via the pi package manager
36
85
  pi install git:<repo-url>
37
86
 
38
- # 方式 C:加入 settings.json
87
+ # Option C: add to settings.json
39
88
  # ~/.pi/agent/settings.json → { "extensions": ["/path/to/pi-smart-fold"] }
40
89
 
41
- # 临时测试
90
+ # Try it temporarily
42
91
  pi -e /path/to/pi-smart-fold/index.ts
43
92
  ```
44
93
 
45
- > 插件无任何 npm 依赖,pi 通过 jiti 直接加载 TypeScript。
94
+ > The extension has no npm dependencies — pi loads the TypeScript directly via jiti.
46
95
 
47
- ## 开发
96
+ ## Development
48
97
 
49
98
  ```bash
50
- npm test # 纯函数单元测试(Node ≥ 22.18 原生 TS 类型剥离,无需构建)
99
+ npm install # dev deps + relink node_modules/@earendil-works to the installed pi (postinstall)
100
+ npm run link:pi # re-point the type/runtime links after a pi upgrade — always current version
101
+ npm run typecheck # strict tsc against the installed pi's .d.ts (no emit)
102
+ npm run check # link + typecheck + jiti load-check + unit tests + click simulation
103
+ npm test # unit tests for the pure functions (native TS type stripping, Node ≥ 22.18, no build step)
104
+ npm run test:sim # click-cycle simulation against the real pi AssistantMessageComponent
51
105
  ```
52
106
 
53
- 结构:
107
+ The extension itself has no npm dependencies — pi loads the TypeScript directly via jiti.
108
+ `typescript` / `@types/node` are dev-only, and `node_modules/@earendil-works/*` are symlinks into
109
+ the pi installation that loads the extension (created by `scripts/link-pi.mjs`), so typecheck
110
+ always runs against the exact pi version installed on the machine.
111
+
112
+ Project layout:
54
113
 
55
114
  ```
56
- index.ts 插件入口(事件 / transformer / /fold 命令)
57
- lib/fold.ts 纯函数:显示宽度、行尾截断、思考折叠(无依赖、可单测)
58
- lib/config.ts 配置读写(缺失/损坏时回退默认值)
59
- test/fold.test.mjs 单元测试
115
+ index.ts Extension entry (transformer / events / write render wrappers / /fold settings UI)
116
+ lib/fold.ts Pure functions: display width, tail truncation, duration formatting, line diff
117
+ lib/thinking.ts Thinking timer state machine (per-run durations keyed by content hash)
118
+ lib/config.ts Config load/save (with legacy migration; falls back to defaults when missing/corrupt)
119
+ scripts/link-pi.mjs Symlink the installed pi runtime into node_modules (version-following)
120
+ scripts/load-check.mjs Smoke test: load the extension via pi's jiti and exercise registration
121
+ test/fold.test.mjs Unit tests
122
+ test/click-sim.mjs Click-cycle simulation (real pi component + simulated clicks, verifies tail ↔ full toggling)
60
123
  ```
61
124
 
62
- ## 兼容性
125
+ ## Known limitations
126
+
127
+ - Single-click toggling of thinking runs in a *live* message depends on the prototype patch's redirect; without the patch it degrades to pi's native two-state toggle (two clicks to expand).
128
+ - Expand state is runtime-only: new sessions/reloads start folded again. Window resizes never collapse blocks you've expanded.
129
+ - write diff stats only apply to writes executed in the current session (restored older sessions have no pre-execution snapshot to diff against).
130
+ - When stacked with pi's native "Hide thinking blocks" (`ctrl+t` toggle): if thinking is hidden that way, the live scrolling line won't show — keep the native display at its default and let this extension handle folding.
131
+
132
+ ## Compatibility
133
+
134
+ Built and verified against pi **`0.86.1`** public extension APIs: `registerMarkdownTransformer`,
135
+ `ctx.ui.setToolsExpanded` / `setHiddenThinkingLabel`, `create*ToolDefinition` (and friends),
136
+ `registerTool` (`renderCall` / `renderResult` + `ToolRenderContext`), `registerCommand`, `appendEntry`,
137
+ `SettingsList`, and the `AssistantMessageComponent` click-internals patch (`updateContent`,
138
+ `thinkingVisibilityOverrides`, `hiddenThinkingLabel`).
63
139
 
64
- 基于 pi `0.85.1` 的公开扩展 API(`registerMarkdownTransformer`、`ctx.ui.setToolsExpanded`、`registerCommand`)。
140
+ After upgrading pi, run `npm run link:pi && npm run check` — the links follow the newly installed
141
+ version automatically, and the check verifies types, jiti loading, and behavior against it.