pi-minimalist 0.2.4 → 0.3.1
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.fr.md +86 -0
- package/README.md +3 -0
- package/README.zh-CN.md +86 -0
- package/index.ts +9 -7
- package/package.json +1 -1
- package/src/config-file.ts +6 -4
- package/src/config-ui.ts +72 -7
- package/src/config.ts +10 -5
- package/src/row.ts +1 -5
- package/src/thinking.ts +2 -1
package/README.fr.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# pi-minimalist
|
|
2
|
+
|
|
3
|
+
[English](README.md) | [简体中文](README.zh-CN.md) | **Français**
|
|
4
|
+
|
|
5
|
+
> Traduction du [README.md](README.md) anglais ; en cas de divergence, la version anglaise fait foi. Les commandes, les noms de réglages et les clés JSON restent en anglais, pour que vous puissiez les retrouver dans l'interface.
|
|
6
|
+
|
|
7
|
+
**Moins de défilement. Plus de place pour la réponse.**
|
|
8
|
+
|
|
9
|
+
Un historique plus calme pour [Pi](https://pi.dev) : les appels d'outils volumineux deviennent des résumés d'une ligne, et vous ouvrez la sortie complète quand vous en avez besoin.
|
|
10
|
+
|
|
11
|
+
## Voir la différence
|
|
12
|
+
|
|
13
|
+
**Avant :** un seul appel d'outil occupe presque tout l'écran.
|
|
14
|
+
|
|
15
|
+
<img width="656" height="550" alt="before" src="https://github.com/user-attachments/assets/aa1602f7-5db1-49b8-a4d3-cbd1aef69ea0" />
|
|
16
|
+
|
|
17
|
+
**Après :** le même appel, sur une ligne.
|
|
18
|
+
|
|
19
|
+
<img width="699" height="50" alt="after" src="https://github.com/user-attachments/assets/c0e8bca4-afa7-42c1-9bf0-69f267d18d9f" />
|
|
20
|
+
|
|
21
|
+
**Cliquez** sur une ligne repliée pour l'ouvrir en plusieurs lignes. Cliquez sur l'une d'elles pour n'afficher que sa sortie. Cliquez sur la ligne `▾ Expanded · click to fold` au-dessus d'une série ouverte pour la replier.
|
|
22
|
+
|
|
23
|
+
<img src="docs/click.png" width="600" alt="Un clic sur une ligne repliée l'ouvre en lignes ; un clic sur une ligne n'ouvre que celle-ci">
|
|
24
|
+
|
|
25
|
+
Appuyez sur **Ctrl+O** pour développer la sortie des outils, y compris les diffs et la coloration syntaxique. Les lignes développées renvoient aussi à la ligne les longues commandes au lieu de les couper. Rien n'est supprimé de la session ni caché au modèle : seul l'affichage change.
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pi install npm:pi-minimalist
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Redémarrez Pi : les appels d'outils s'affichent en lignes compactes. Aucune configuration n'est nécessaire.
|
|
34
|
+
|
|
35
|
+
## Choisir le niveau de discrétion
|
|
36
|
+
|
|
37
|
+
Lancez **`/minimalist`** pour modifier les réglages en direct. Commencez par les lignes d'outils compactes, ou allez plus loin :
|
|
38
|
+
|
|
39
|
+
- **Combine consecutive tool calls** (regrouper les appels d'outils consécutifs) en un seul résumé, par exemple `read ×2, edit ×1`.
|
|
40
|
+
- **Collapse earlier activity** (replier l'activité précédente) pour garder la dernière réponse au premier plan. L'activité qui la précède est remplacée par le temps de travail ou le nombre d'outils.
|
|
41
|
+
- **Compact thinking rows** (lignes de réflexion compactes), ou garder la réflexion visible pendant qu'elle arrive.
|
|
42
|
+
- **Keep running tools visible** (garder visibles les outils en cours) pendant le regroupement des autres appels, avec un minuteur qui affiche leur durée.
|
|
43
|
+
- **Excluded tools** (outils exclus) : un outil donné (par exemple `subagent`) garde sa propre carte au lieu d'être réduit à une ligne. Ouvrez cette ligne dans `/minimalist`, tapez pour chercher, puis appuyez sur Entrée sur un outil pour le basculer.
|
|
44
|
+
|
|
45
|
+
Une nouvelle installation démarre avec le préréglage **`full`** (voir plus bas) : lignes d'outils compactes, appels regroupés et lignes de réflexion compactes. Le repli de l'activité est facultatif. Choisissez `lite` si vous préférez voir chaque appel séparément.
|
|
46
|
+
|
|
47
|
+
### Préréglages
|
|
48
|
+
|
|
49
|
+
La ligne **Preset** en haut de `/minimalist` règle quatre options à la fois : **Compact tool rows**, **Combine consecutive tool calls**, **Collapse earlier activity** et **Compact thinking rows**.
|
|
50
|
+
|
|
51
|
+
| Préréglage | Ce que vous obtenez |
|
|
52
|
+
| --- | --- |
|
|
53
|
+
| `off` | Les cartes d'outils natives de Pi. |
|
|
54
|
+
| `lite` | Des lignes d'outils d'une ligne, chaque appel sur sa propre ligne. |
|
|
55
|
+
| `full` | `lite`, plus les appels consécutifs regroupés et les lignes de réflexion compactes. |
|
|
56
|
+
| `max` | `full`, plus l'activité précédente repliée (`Worked for …`). |
|
|
57
|
+
| `custom` | Vos propres valeurs pour ces quatre options. |
|
|
58
|
+
|
|
59
|
+
<img src="docs/presets.png" width="600" alt="L'écran de choix du préréglage">
|
|
60
|
+
|
|
61
|
+
Un préréglage n'écrase jamais vos réglages. Tant que `off`, `lite`, `full` ou `max` est sélectionné, seules ces quatre lignes sont grisées et affichent les valeurs du préréglage ; appuyer sur Entrée dessus ne fait rien. Toutes les autres options (Left border, Elapsed timer, Symbols, etc.) restent à vous et restent modifiables. Vos propres valeurs sont conservées et reviennent quand vous choisissez `custom`. La première fois que vous choisissez `custom`, il part de `lite`.
|
|
62
|
+
|
|
63
|
+
**Mise à jour :** si vos réglages contiennent déjà un bloc `minimalist`, vous restez sur `custom` et rien ne change. Seul un utilisateur sans aucun réglage `minimalist` démarre sur `full`, ce qui rend les lignes de réflexion compactes. Pour choisir un autre aspect, changez **Preset**.
|
|
64
|
+
|
|
65
|
+
### Commandes courantes
|
|
66
|
+
|
|
67
|
+
| Commande | Action |
|
|
68
|
+
| --- | --- |
|
|
69
|
+
| `/minimalist` | Ouvrir les réglages (`/minimalist config` fonctionne aussi) |
|
|
70
|
+
| `/minimalist status` | Afficher les réglages actuels |
|
|
71
|
+
| Ctrl+O | Développer ou replier la sortie des outils |
|
|
72
|
+
| Ctrl+T | Développer ou replier la réflexion |
|
|
73
|
+
|
|
74
|
+
Les réglages s'appliquent à l'historique existant et sont enregistrés globalement. Si un symbole s'affiche mal dans votre terminal, choisissez **Symbols → ASCII**. Aucune Nerd Font n'est requise.
|
|
75
|
+
|
|
76
|
+
## Revenir à l'affichage habituel de Pi
|
|
77
|
+
|
|
78
|
+
Désactivez **Compact tool rows** pour retrouver les cartes d'outils natives. Ou choisissez le préréglage `off`.
|
|
79
|
+
|
|
80
|
+
Pour désactiver complètement l'extension, lancez `pi config`, désactivez pi-minimalist, puis redémarrez Pi.
|
|
81
|
+
|
|
82
|
+
## Compatibilité
|
|
83
|
+
|
|
84
|
+
Testé avec Pi **1.0.0**. Les mises à jour de Pi peuvent affecter la compatibilité du rendu ; [signalez un problème](https://github.com/EviHex/pi-minimalist/issues) en indiquant votre version de Pi, votre terminal et une capture d'écran.
|
|
85
|
+
|
|
86
|
+
[Licence MIT](LICENSE).
|
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# pi-minimalist
|
|
2
2
|
|
|
3
|
+
**English** | [简体中文](README.zh-CN.md) | [Français](README.fr.md)
|
|
4
|
+
|
|
3
5
|
**Less scrolling. More room for the answer.**
|
|
4
6
|
|
|
5
7
|
A quieter transcript for [Pi](https://pi.dev): turn bulky tool calls into one-line summaries, and open the full output whenever you need it.
|
|
@@ -36,6 +38,7 @@ Run **`/minimalist`** to change settings live. Start with compact tool rows, or
|
|
|
36
38
|
- **Collapse earlier activity** so the latest reply stays in focus. Replace the preceding activity with elapsed work time or tool counts.
|
|
37
39
|
- **Compact thinking rows**, or keep thinking visible as it arrives.
|
|
38
40
|
- **Keep running tools visible** while grouping other calls, with an elapsed timer to show how long they take.
|
|
41
|
+
- **Excluded tools**: let chosen tools (for example `subagent`) keep their own card instead of a one-line row. Open the row in `/minimalist`, type to search, and press Enter on a tool to flip it.
|
|
39
42
|
|
|
40
43
|
A fresh install starts on the **`full`** preset (see below): compact tool rows, grouped calls and compact thinking. Activity folding is opt-in. Choose `lite` if you prefer to see each call separately.
|
|
41
44
|
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# pi-minimalist
|
|
2
|
+
|
|
3
|
+
[English](README.md) | **简体中文** | [Français](README.fr.md)
|
|
4
|
+
|
|
5
|
+
> 本文翻译自英文版 [README.md](README.md),如有出入以英文版为准。命令、设置名和 JSON 键保持英文原样,方便你在界面里对照。
|
|
6
|
+
|
|
7
|
+
**少滚动,给答案留出更多空间。**
|
|
8
|
+
|
|
9
|
+
让 [Pi](https://pi.dev) 的对话记录更安静:把冗长的工具调用折成一行摘要,需要时再展开完整输出。
|
|
10
|
+
|
|
11
|
+
## 效果对比
|
|
12
|
+
|
|
13
|
+
**之前:** 一次工具调用占掉大半个屏幕。
|
|
14
|
+
|
|
15
|
+
<img width="656" height="550" alt="before" src="https://github.com/user-attachments/assets/aa1602f7-5db1-49b8-a4d3-cbd1aef69ea0" />
|
|
16
|
+
|
|
17
|
+
**之后:** 同一次调用,只占一行。
|
|
18
|
+
|
|
19
|
+
<img width="699" height="50" alt="after" src="https://github.com/user-attachments/assets/c0e8bca4-afa7-42c1-9bf0-69f267d18d9f" />
|
|
20
|
+
|
|
21
|
+
**点击**折叠的一行,会把它展开成多行。点击其中一行,只看这一行的输出。点击展开区域上方的 `▾ Expanded · click to fold`,可以重新折叠。
|
|
22
|
+
|
|
23
|
+
<img src="docs/click.png" width="600" alt="点击折叠的一行会展开成多行;点击其中一行只展开这一行">
|
|
24
|
+
|
|
25
|
+
按 **Ctrl+O** 展开工具输出,包括 diff 和语法高亮。展开后的行会自动换行显示长命令,不会截断。会话内容不会被删除,模型也看得到全部内容;只有显示方式改变。
|
|
26
|
+
|
|
27
|
+
## 安装
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pi install npm:pi-minimalist
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
重启 Pi,工具调用就会显示为紧凑的一行。不需要任何配置。
|
|
34
|
+
|
|
35
|
+
## 选择你想要的安静程度
|
|
36
|
+
|
|
37
|
+
运行 **`/minimalist`** 可以实时修改设置。可以只用紧凑工具行,也可以走得更远:
|
|
38
|
+
|
|
39
|
+
- **Combine consecutive tool calls**(合并连续工具调用):合并成一条摘要,例如 `read ×2, edit ×1`。
|
|
40
|
+
- **Collapse earlier activity**(折叠早先的活动):让最新的回复保持在视线中心。之前的活动会被替换成耗时或工具计数。
|
|
41
|
+
- **Compact thinking rows**(紧凑思考行),或让思考内容在生成时保持可见。
|
|
42
|
+
- **Keep running tools visible**(保持运行中的工具可见):在合并其他调用的同时,运行中的工具会带计时器显示已耗时间。
|
|
43
|
+
- **Excluded tools**(排除的工具):让指定工具(例如 `subagent`)保留自己的卡片,不压缩成一行。在 `/minimalist` 里打开该行,输入关键字搜索,在工具上按 Enter 即可切换。
|
|
44
|
+
|
|
45
|
+
全新安装默认使用 **`full`** 预设(见下文):紧凑工具行、合并调用和紧凑思考行。活动折叠需要手动开启。如果你想逐条看到每次调用,请选择 `lite`。
|
|
46
|
+
|
|
47
|
+
### 预设
|
|
48
|
+
|
|
49
|
+
`/minimalist` 顶部的 **Preset** 一行,可以一次设置四个选项:**Compact tool rows**、**Combine consecutive tool calls**、**Collapse earlier activity** 和 **Compact thinking rows**。
|
|
50
|
+
|
|
51
|
+
| 预设 | 效果 |
|
|
52
|
+
| --- | --- |
|
|
53
|
+
| `off` | Pi 原生的工具卡片。 |
|
|
54
|
+
| `lite` | 单行工具行,每次调用各占一行。 |
|
|
55
|
+
| `full` | `lite` 加上合并连续调用和紧凑思考行。 |
|
|
56
|
+
| `max` | `full` 加上折叠早先的活动(`Worked for …`)。 |
|
|
57
|
+
| `custom` | 这四个选项使用你自己的值。 |
|
|
58
|
+
|
|
59
|
+
<img src="docs/presets.png" width="600" alt="预设选择界面">
|
|
60
|
+
|
|
61
|
+
预设不会覆盖你的设置。选中 `off`、`lite`、`full` 或 `max` 时,只有那四行会变灰并显示预设的值,在它们上面按 Enter 没有任何作用。其他选项(Left border、Elapsed timer、Symbols 等)仍然归你所有,可以继续编辑。你自己的值会被保留,选回 `custom` 时会恢复。第一次选择 `custom` 时,会从 `lite` 开始。
|
|
62
|
+
|
|
63
|
+
**升级说明:** 如果你的设置里已经有 `minimalist` 配置块,你会继续停留在 `custom`,什么都不会变。只有完全没有 `minimalist` 设置的用户才会从 `full` 开始,这会让思考行变得紧凑。想换一种外观,修改 **Preset** 即可。
|
|
64
|
+
|
|
65
|
+
### 日常操作
|
|
66
|
+
|
|
67
|
+
| 操作 | 作用 |
|
|
68
|
+
| --- | --- |
|
|
69
|
+
| `/minimalist` | 打开设置(`/minimalist config` 也可以) |
|
|
70
|
+
| `/minimalist status` | 显示当前设置 |
|
|
71
|
+
| Ctrl+O | 展开或折叠工具输出 |
|
|
72
|
+
| Ctrl+T | 展开或折叠思考内容 |
|
|
73
|
+
|
|
74
|
+
设置会作用于已有的对话历史,并保存为全局设置。如果某个符号在你的终端里显示不正常,请选择 **Symbols → ASCII**。不需要 Nerd Font。
|
|
75
|
+
|
|
76
|
+
## 回到 Pi 的默认外观
|
|
77
|
+
|
|
78
|
+
关闭 **Compact tool rows** 即可恢复原生工具卡片。也可以选择 `off` 预设。
|
|
79
|
+
|
|
80
|
+
要完全禁用这个扩展,运行 `pi config`,禁用 pi-minimalist,然后重启 Pi。
|
|
81
|
+
|
|
82
|
+
## 兼容性
|
|
83
|
+
|
|
84
|
+
已在 Pi **1.0.0** 上测试。Pi 的更新可能影响渲染兼容性;请[反馈问题](https://github.com/EviHex/pi-minimalist/issues),并附上你的 Pi 版本、终端和一张截图。
|
|
85
|
+
|
|
86
|
+
[MIT 许可证](LICENSE)。
|
package/index.ts
CHANGED
|
@@ -22,7 +22,7 @@ import { getSettingsListTheme } from "@earendil-works/pi-coding-agent";
|
|
|
22
22
|
// keybindings and colours, as Pi's own `/settings`.
|
|
23
23
|
import { SettingsList } from "@earendil-works/pi-tui";
|
|
24
24
|
import { installBridges, sharedState } from "./src/bridge.ts";
|
|
25
|
-
import { type
|
|
25
|
+
import { type Config, type EditableSettings } from "./src/config.ts";
|
|
26
26
|
import { customSeed, loadSettings, saveBasicSettings } from "./src/config-file.ts";
|
|
27
27
|
import { argumentCompletions, createConfigScreen, summary } from "./src/config-ui.ts";
|
|
28
28
|
import { patchCore } from "./src/core-patch.ts";
|
|
@@ -75,6 +75,8 @@ export default function (pi: ExtensionAPI) {
|
|
|
75
75
|
theme: getSettingsListTheme(),
|
|
76
76
|
config,
|
|
77
77
|
onChange: (key, value) => persist(ctx, config, key, value),
|
|
78
|
+
toolNames: () => pi.getAllTools().map((tool) => tool.name),
|
|
79
|
+
onExcludeChange: (names) => persist(ctx, config, "excludeTools", names),
|
|
78
80
|
onClose: () => done(),
|
|
79
81
|
}),
|
|
80
82
|
);
|
|
@@ -84,17 +86,17 @@ export default function (pi: ExtensionAPI) {
|
|
|
84
86
|
|
|
85
87
|
type NotifyContext = { ui: { notify(message: string, type?: "info" | "warning" | "error"): void } };
|
|
86
88
|
|
|
87
|
-
function persist(
|
|
89
|
+
function persist<K extends keyof EditableSettings>(
|
|
88
90
|
ctx: NotifyContext,
|
|
89
91
|
config: Config,
|
|
90
|
-
key:
|
|
91
|
-
value:
|
|
92
|
+
key: K,
|
|
93
|
+
value: EditableSettings[K],
|
|
92
94
|
): void {
|
|
93
95
|
// The first switch to `custom` starts from the `lite` look (see customSeed).
|
|
94
96
|
const seed = key === "preset" && value === "custom" ? customSeed() : undefined;
|
|
95
|
-
const changes: Partial<Record<
|
|
96
|
-
const result = saveBasicSettings(changes as Partial<
|
|
97
|
-
for (const [k, v] of Object.entries(changes) as [
|
|
97
|
+
const changes: Partial<Record<keyof EditableSettings, unknown>> = { ...seed, [key]: value };
|
|
98
|
+
const result = saveBasicSettings(changes as Partial<EditableSettings>);
|
|
99
|
+
for (const [k, v] of Object.entries(changes) as [keyof EditableSettings, never][]) {
|
|
98
100
|
config.set(k, v);
|
|
99
101
|
// On success the file agrees, so it becomes the source of truth again.
|
|
100
102
|
if (result.ok) config.clearSessionOverride(k);
|
package/package.json
CHANGED
package/src/config-file.ts
CHANGED
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
DEFAULT_BASIC,
|
|
26
26
|
DEFAULTS,
|
|
27
27
|
DEFAULT_TOKENS,
|
|
28
|
+
EDITABLE_KEYS,
|
|
28
29
|
GLYPH_PRESETS,
|
|
29
30
|
FRESH_PRESET,
|
|
30
31
|
LOOK_KEYS,
|
|
@@ -32,7 +33,7 @@ import {
|
|
|
32
33
|
isFresh,
|
|
33
34
|
isPreset,
|
|
34
35
|
SETTINGS_KEY,
|
|
35
|
-
type
|
|
36
|
+
type EditableSettings,
|
|
36
37
|
type Glyphs,
|
|
37
38
|
type Settings,
|
|
38
39
|
type Tokens,
|
|
@@ -176,13 +177,14 @@ export type SaveResult =
|
|
|
176
177
|
/**
|
|
177
178
|
* Persist only the supplied editor-managed settings into the global agent file.
|
|
178
179
|
* A normal edit passes one key.
|
|
179
|
-
* Hand-written `glyphs`/`tokens
|
|
180
|
+
* Hand-written `glyphs`/`tokens` values survive untouched, and so does a hand-written
|
|
181
|
+
* `excludeTools` unless the tool picker is what changed it.
|
|
180
182
|
*
|
|
181
183
|
* REFUSES to write a file containing comments. `JSON.stringify` would silently
|
|
182
184
|
* delete them, and quietly destroying an annotated config is far worse than
|
|
183
185
|
* asking the user to edit one line by hand.
|
|
184
186
|
*/
|
|
185
|
-
export function saveBasicSettings(settings: Partial<
|
|
187
|
+
export function saveBasicSettings(settings: Partial<EditableSettings>, env = process.env): SaveResult {
|
|
186
188
|
const path = globalSettingsPath(env);
|
|
187
189
|
|
|
188
190
|
let raw = "";
|
|
@@ -208,7 +210,7 @@ export function saveBasicSettings(settings: Partial<BasicSettings>, env = proces
|
|
|
208
210
|
const merged: Json = { ...existing };
|
|
209
211
|
// The first write must pin the fresh-install preset, or the file would stop looking fresh and become `custom`.
|
|
210
212
|
if (isFresh(existing)) merged.preset = FRESH_PRESET;
|
|
211
|
-
for (const key of
|
|
213
|
+
for (const key of EDITABLE_KEYS) {
|
|
212
214
|
if (settings[key] !== undefined) merged[key] = settings[key];
|
|
213
215
|
}
|
|
214
216
|
|
package/src/config-ui.ts
CHANGED
|
@@ -84,8 +84,14 @@ type InputComponent = Component & { handleInput(data: string): void };
|
|
|
84
84
|
type SettingsListConstructor = new (...args: ConstructorParameters<typeof SettingsList>) => SettingsList;
|
|
85
85
|
type BasicValue = BasicSettings[BasicKey];
|
|
86
86
|
|
|
87
|
+
/** `custom` is the only preset whose look rows you can edit; say so where it is shown. */
|
|
88
|
+
const CUSTOM_LABEL = "custom (editable)";
|
|
89
|
+
const presetLabel = (preset: string) => (preset === "custom" ? CUSTOM_LABEL : preset);
|
|
90
|
+
/** Back from the displayed text to the stored preset name. */
|
|
91
|
+
const presetFromLabel = (text: string) => (text === CUSTOM_LABEL ? "custom" : text);
|
|
92
|
+
|
|
87
93
|
const CHOICES: Partial<Record<BasicKey, string[]>> = {
|
|
88
|
-
preset:
|
|
94
|
+
preset: PRESET_NAMES.map(presetLabel),
|
|
89
95
|
activitySummary: ["elapsed time", "tools used"],
|
|
90
96
|
glyphStyle: ["Unicode", "ASCII"],
|
|
91
97
|
};
|
|
@@ -99,10 +105,13 @@ export function items(settings: Settings, dim?: (text: string) => string): Setti
|
|
|
99
105
|
const value = displayValue(settings[key]);
|
|
100
106
|
// SettingsList has no disabled rows, so a locked row shows its dimmed value
|
|
101
107
|
// as its ONLY value: Enter "cycles" to the same text and nothing changes.
|
|
108
|
+
// The label is dimmed too: ordinary values are already `muted`, which is too
|
|
109
|
+
// close to the hint colour to tell a locked row apart, while ordinary labels
|
|
110
|
+
// are the default colour.
|
|
102
111
|
if (dim && isLook(key)) {
|
|
103
112
|
const shown = dim(value);
|
|
104
|
-
const hint = `Set by the '${settings.preset}' preset. Switch Preset to 'custom' to edit (your custom values are kept).`;
|
|
105
|
-
return { id: key, label, description: hint, currentValue: shown, values: [shown] };
|
|
113
|
+
const hint = `Set by the '${settings.preset}' preset. Switch Preset to 'custom (editable)' to edit (your custom values are kept).`;
|
|
114
|
+
return { id: key, label: dim(label), description: hint, currentValue: shown, values: [shown] };
|
|
106
115
|
}
|
|
107
116
|
return { id: key, label, description, currentValue: value, values: CHOICES[key] ?? ["on", "off"] };
|
|
108
117
|
},
|
|
@@ -114,9 +123,54 @@ export type ConfigScreenDeps = {
|
|
|
114
123
|
theme: SettingsListTheme;
|
|
115
124
|
config: Config;
|
|
116
125
|
onChange: (key: BasicKey, value: BasicValue) => void;
|
|
126
|
+
/** Names of every tool known right now; read each time the picker opens, so it is never stale. */
|
|
127
|
+
toolNames: () => string[];
|
|
128
|
+
/** Called with the new `excludeTools` after every toggle in the picker. */
|
|
129
|
+
onExcludeChange: (names: string[]) => void;
|
|
117
130
|
onClose: () => void;
|
|
118
131
|
};
|
|
119
132
|
|
|
133
|
+
const EXCLUDE_ID = "excludeTools";
|
|
134
|
+
const PICKER_ROWS = 12;
|
|
135
|
+
|
|
136
|
+
/** "none", the names when there are one or two, else a count. */
|
|
137
|
+
export function excludedSummary(names: string[]): string {
|
|
138
|
+
if (names.length === 0) return "none";
|
|
139
|
+
return names.length <= 2 ? names.join(", ") : `${names.length} tools`;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* One row per tool; Enter flips it between `compact` and `excluded`. It reuses
|
|
144
|
+
* SettingsList with its built-in search, so it has Pi's own keys and look and
|
|
145
|
+
* no list/filter code of ours. Names in `excludeTools` that no loaded tool
|
|
146
|
+
* carries (an extension not loaded this session) stay listed, or opening the
|
|
147
|
+
* picker would quietly forget them.
|
|
148
|
+
*/
|
|
149
|
+
function toolPicker(deps: ConfigScreenDeps, done: (summary: string) => void): Component {
|
|
150
|
+
const { SettingsList, theme, config, toolNames, onExcludeChange } = deps;
|
|
151
|
+
let excluded = [...config.get("excludeTools")];
|
|
152
|
+
const known = new Set(toolNames());
|
|
153
|
+
const names = [...new Set([...known, ...excluded])].sort((a, b) => a.localeCompare(b));
|
|
154
|
+
const rows: SettingItem[] = names.map((name) => ({
|
|
155
|
+
id: name,
|
|
156
|
+
label: name,
|
|
157
|
+
description: known.has(name) ? undefined : "Not loaded in this session; kept in your settings.",
|
|
158
|
+
currentValue: excluded.includes(name) ? "excluded" : "compact",
|
|
159
|
+
values: ["compact", "excluded"],
|
|
160
|
+
}));
|
|
161
|
+
return new SettingsList(
|
|
162
|
+
rows,
|
|
163
|
+
Math.min(PICKER_ROWS, Math.max(rows.length, 1)),
|
|
164
|
+
theme,
|
|
165
|
+
(name, value) => {
|
|
166
|
+
excluded = value === "excluded" ? [...excluded, name] : excluded.filter((n) => n !== name);
|
|
167
|
+
onExcludeChange(excluded);
|
|
168
|
+
},
|
|
169
|
+
() => done(excludedSummary(excluded)),
|
|
170
|
+
{ enableSearch: true },
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
120
174
|
/** Build a live screen; toggling prose folding immediately adds/removes its two child rows. */
|
|
121
175
|
export function createConfigScreen(deps: ConfigScreenDeps): InputComponent {
|
|
122
176
|
const { SettingsList, theme, config, onChange, onClose } = deps;
|
|
@@ -126,7 +180,16 @@ export function createConfigScreen(deps: ConfigScreenDeps): InputComponent {
|
|
|
126
180
|
const build = () => {
|
|
127
181
|
const preset = config.all().preset;
|
|
128
182
|
locked = preset !== "custom";
|
|
129
|
-
const rows =
|
|
183
|
+
const rows = [
|
|
184
|
+
...items(config.all(), locked ? theme.hint : undefined),
|
|
185
|
+
{
|
|
186
|
+
id: EXCLUDE_ID,
|
|
187
|
+
label: "Excluded tools",
|
|
188
|
+
description: "Tools drawn with their own card instead of a one-line row, e.g. subagent. Enter to pick; type to search.",
|
|
189
|
+
currentValue: excludedSummary(config.get("excludeTools")),
|
|
190
|
+
submenu: (_current: string, done: (selected?: string) => void) => toolPicker(deps, done),
|
|
191
|
+
},
|
|
192
|
+
];
|
|
130
193
|
return new SettingsList(
|
|
131
194
|
rows,
|
|
132
195
|
rows.length,
|
|
@@ -134,7 +197,8 @@ export function createConfigScreen(deps: ConfigScreenDeps): InputComponent {
|
|
|
134
197
|
(id, displayValue) => {
|
|
135
198
|
if (!isBasicKey(id)) return;
|
|
136
199
|
if (id === "preset") {
|
|
137
|
-
const
|
|
200
|
+
const picked = presetFromLabel(displayValue);
|
|
201
|
+
const value = isPreset(picked) ? picked : "custom";
|
|
138
202
|
config.set(id, value);
|
|
139
203
|
onChange(id, value);
|
|
140
204
|
list = build();
|
|
@@ -182,7 +246,7 @@ function isBasicKey(id: string): id is BasicKey {
|
|
|
182
246
|
}
|
|
183
247
|
|
|
184
248
|
function displayValue(value: BasicValue): string {
|
|
185
|
-
if (isPreset(value)) return value;
|
|
249
|
+
if (isPreset(value)) return presetLabel(value);
|
|
186
250
|
if (value === "elapsed") return "elapsed time";
|
|
187
251
|
if (value === "tools") return "tools used";
|
|
188
252
|
if (value === "unicode") return "Unicode";
|
|
@@ -211,6 +275,7 @@ export function summary(settings: Settings): string {
|
|
|
211
275
|
}),
|
|
212
276
|
"",
|
|
213
277
|
" /minimalist change these",
|
|
214
|
-
|
|
278
|
+
` Excluded tools ${excludedSummary(settings.excludeTools)}`,
|
|
279
|
+
" settings.json custom glyphs and colours",
|
|
215
280
|
].join("\n");
|
|
216
281
|
}
|
package/src/config.ts
CHANGED
|
@@ -125,7 +125,7 @@ export type BasicSettings = {
|
|
|
125
125
|
glyphStyle: GlyphStyle;
|
|
126
126
|
};
|
|
127
127
|
|
|
128
|
-
/** Settings
|
|
128
|
+
/** Settings the `/minimalist` rows do not cover; `excludeTools` has a picker, the rest need settings.json. */
|
|
129
129
|
export type AdvancedSettings = {
|
|
130
130
|
/** Tool names left to their own renderer. Everything else is compacted. */
|
|
131
131
|
excludeTools: string[];
|
|
@@ -161,10 +161,11 @@ export const PRESETS: Record<Exclude<Preset, "custom">, Record<LookKey, boolean>
|
|
|
161
161
|
};
|
|
162
162
|
|
|
163
163
|
export const DEFAULT_ADVANCED: AdvancedSettings = {
|
|
164
|
-
//
|
|
165
|
-
//
|
|
166
|
-
//
|
|
167
|
-
|
|
164
|
+
// Empty by default: every tool is compacted. A tool whose own renderer carries
|
|
165
|
+
// more than one line can show (e.g. `subagent`: run id, state, ctrl+o hint)
|
|
166
|
+
// is opted out BY NAME here, never by a "does this tool have its own renderer?"
|
|
167
|
+
// rule, which would silently exempt every third-party tool.
|
|
168
|
+
excludeTools: [],
|
|
168
169
|
glyphs: {},
|
|
169
170
|
tokens: {},
|
|
170
171
|
};
|
|
@@ -181,6 +182,10 @@ export const BASIC_KEYS = Object.keys(DEFAULT_BASIC) as (keyof BasicSettings)[];
|
|
|
181
182
|
|
|
182
183
|
export type BasicKey = keyof BasicSettings;
|
|
183
184
|
|
|
185
|
+
/** What `/minimalist` may write: the basic keys plus the tool picker's `excludeTools`. */
|
|
186
|
+
export type EditableSettings = BasicSettings & Pick<AdvancedSettings, "excludeTools">;
|
|
187
|
+
export const EDITABLE_KEYS = [...BASIC_KEYS, "excludeTools"] as (keyof EditableSettings)[];
|
|
188
|
+
|
|
184
189
|
// ---------------------------------------------------------------------------
|
|
185
190
|
// Live configuration
|
|
186
191
|
// ---------------------------------------------------------------------------
|
package/src/row.ts
CHANGED
|
@@ -197,11 +197,7 @@ export class Painter {
|
|
|
197
197
|
const glyphs = this.config.glyphs();
|
|
198
198
|
return counts
|
|
199
199
|
.map(({ name, count }) => {
|
|
200
|
-
|
|
201
|
-
// behave exactly like a tool, in which case it should look like one too.
|
|
202
|
-
const keepsThinkingHue =
|
|
203
|
-
name === "think" && color === tokens.label && !this.config.get("thinkingAsToolCall");
|
|
204
|
-
const token = keepsThinkingHue ? tokens.thinking : color;
|
|
200
|
+
const token = name === "think" && color === tokens.label ? tokens.thinking : color;
|
|
205
201
|
return `${this.theme.fg(token, name)} ${this.theme.fg(tokens.details, `${glyphs.count}${count}`)}`;
|
|
206
202
|
})
|
|
207
203
|
.join(this.theme.fg(tokens.details, ", "));
|
package/src/thinking.ts
CHANGED
|
@@ -49,7 +49,8 @@ export function createThinkingPreview(deps: ThinkingDeps): ThinkingPreview {
|
|
|
49
49
|
return new Painter(theme, config).labeled({
|
|
50
50
|
glyph: streaming ? glyphs.running : glyphs.done,
|
|
51
51
|
label: "think",
|
|
52
|
-
labelColor: tokens.
|
|
52
|
+
labelColor: tokens.thinking,
|
|
53
|
+
glyphColor: tokens.thinking,
|
|
53
54
|
details: text.replace(/\s+/g, " ").trim(),
|
|
54
55
|
});
|
|
55
56
|
};
|