@agimon-ai/doompi-ui 0.0.1-alpha.9 → 0.0.1-alpha.90
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 +89 -19
- package/dist/apiContracts.cjs +17 -0
- package/dist/apiContracts.cjs.map +1 -0
- package/dist/apiContracts.d.mts +53 -0
- package/dist/apiContracts.d.mts.map +1 -0
- package/dist/apiContracts.mjs +13 -0
- package/dist/apiContracts.mjs.map +1 -0
- package/dist/config.cjs +62 -2
- package/dist/config.d.mts +2 -5
- package/dist/config.mjs +2 -2
- package/dist/configOverlay-Bov-Zcdz.cjs +0 -0
- package/dist/configOverlay-Bov-Zcdz.cjs.map +1 -0
- package/dist/configOverlay-CCbWicvH.mjs +0 -0
- package/dist/configOverlay-CCbWicvH.mjs.map +1 -0
- package/dist/configOverlay.cjs +4 -0
- package/dist/{components/configOverlay.d.mts → configOverlay.d.mts} +0 -0
- package/dist/configOverlay.d.mts.map +1 -0
- package/dist/configOverlay.mjs +2 -0
- package/dist/diffRender-D7zqA45E.mjs +102 -0
- package/dist/diffRender-D7zqA45E.mjs.map +1 -0
- package/dist/diffRender-D8yINsb1.cjs +119 -0
- package/dist/diffRender-D8yINsb1.cjs.map +1 -0
- package/dist/{components/doomEditor.d.mts → doomEditor-Dvzxbz3r.d.mts} +11 -7
- package/dist/doomEditor-Dvzxbz3r.d.mts.map +1 -0
- package/dist/doomEditor-KbMpb-b3.mjs +274 -0
- package/dist/doomEditor-KbMpb-b3.mjs.map +1 -0
- package/dist/doomEditor-woICKPEH.cjs +279 -0
- package/dist/doomEditor-woICKPEH.cjs.map +1 -0
- package/dist/doomEditor.cjs +3 -0
- package/dist/doomEditor.d.mts +2 -0
- package/dist/doomEditor.mjs +2 -0
- package/dist/doomFooter-D7cSjz9I.mjs +126 -0
- package/dist/doomFooter-D7cSjz9I.mjs.map +1 -0
- package/dist/{components/doomFooter.d.cts → doomFooter-SkOvq3Pf.d.mts} +20 -7
- package/dist/doomFooter-SkOvq3Pf.d.mts.map +1 -0
- package/dist/doomFooter-qNPW5h37.cjs +133 -0
- package/dist/doomFooter-qNPW5h37.cjs.map +1 -0
- package/dist/doomFooter.cjs +3 -0
- package/dist/doomFooter.d.mts +2 -0
- package/dist/doomFooter.mjs +2 -0
- package/dist/doomHeader-D0N0VUF9.cjs +207 -0
- package/dist/doomHeader-D0N0VUF9.cjs.map +1 -0
- package/dist/{components/doomHeader.d.cts → doomHeader-DimAnEv5.d.mts} +5 -5
- package/dist/doomHeader-DimAnEv5.d.mts.map +1 -0
- package/dist/doomHeader-mG3_M_7C.mjs +200 -0
- package/dist/doomHeader-mG3_M_7C.mjs.map +1 -0
- package/dist/doomHeader.cjs +3 -0
- package/dist/doomHeader.d.mts +2 -0
- package/dist/doomHeader.mjs +2 -0
- package/dist/{components/doomOverlay.d.mts → doomOverlay-BXVz35qt.d.mts} +12 -7
- package/dist/doomOverlay-BXVz35qt.d.mts.map +1 -0
- package/dist/doomOverlay-DYucstPB.cjs +185 -0
- package/dist/doomOverlay-DYucstPB.cjs.map +1 -0
- package/dist/doomOverlay-Onfi701y.mjs +162 -0
- package/dist/doomOverlay-Onfi701y.mjs.map +1 -0
- package/dist/doomOverlay.cjs +6 -0
- package/dist/doomOverlay.d.mts +2 -0
- package/dist/doomOverlay.mjs +2 -0
- package/dist/extensionName.cjs +6 -2
- package/dist/extensionName.d.mts +14 -5
- package/dist/extensionName.d.mts.map +1 -1
- package/dist/extensionName.mjs +2 -2
- package/dist/extensionSource-B87Grvo1.mjs +93 -0
- package/dist/extensionSource-B87Grvo1.mjs.map +1 -0
- package/dist/extensionSource-DtiJSajb.cjs +119 -0
- package/dist/extensionSource-DtiJSajb.cjs.map +1 -0
- package/dist/extensions/mcp-ui.mjs +46 -0
- package/dist/extensions/mcp-ui.mjs.map +1 -0
- package/dist/extensions/mcp.cjs +75 -0
- package/dist/extensions/mcp.cjs.map +1 -0
- package/dist/extensions/mcp.d.mts +5 -0
- package/dist/extensions/mcp.d.mts.map +1 -0
- package/dist/extensions/mcp.mjs +70 -0
- package/dist/extensions/mcp.mjs.map +1 -0
- package/dist/extensions/pi.cjs +778 -1
- package/dist/extensions/pi.cjs.map +1 -1
- package/dist/extensions/pi.d.mts +7 -2
- package/dist/extensions/pi.d.mts.map +1 -0
- package/dist/extensions/pi.mjs +771 -1
- package/dist/extensions/pi.mjs.map +1 -1
- package/dist/extensions/server.cjs +68 -0
- package/dist/extensions/server.cjs.map +1 -0
- package/dist/extensions/server.d.mts +5 -0
- package/dist/extensions/server.d.mts.map +1 -0
- package/dist/extensions/server.mjs +63 -0
- package/dist/extensions/server.mjs.map +1 -0
- package/dist/extensions/web.mjs +332 -0
- package/dist/extensions/web.mjs.map +1 -0
- package/dist/footer.cjs +26 -2
- package/dist/footer.d.mts +2 -5
- package/dist/footer.mjs +2 -2
- package/dist/harnessMetadata-ClCqMmsE.mjs +25 -0
- package/dist/harnessMetadata-ClCqMmsE.mjs.map +1 -0
- package/dist/{harnessMetadata.d.cts → harnessMetadata-CzsdGAxL.d.mts} +3 -3
- package/dist/harnessMetadata-CzsdGAxL.d.mts.map +1 -0
- package/dist/harnessMetadata-il7ns7Vq.cjs +30 -0
- package/dist/harnessMetadata-il7ns7Vq.cjs.map +1 -0
- package/dist/harnessMetadata.cjs +3 -2
- package/dist/harnessMetadata.d.mts +2 -21
- package/dist/harnessMetadata.mjs +2 -2
- package/dist/hashlineRendering.cjs +123 -0
- package/dist/hashlineRendering.cjs.map +1 -0
- package/dist/hashlineRendering.d.mts +20 -0
- package/dist/hashlineRendering.d.mts.map +1 -0
- package/dist/hashlineRendering.mjs +118 -0
- package/dist/hashlineRendering.mjs.map +1 -0
- package/dist/{leaderRegistry.d.cts → index-BvkZav1G.d.mts} +8 -7
- package/dist/index-BvkZav1G.d.mts.map +1 -0
- package/dist/{logSinkTelemetry.d.cts → index-DoRvCo76.d.mts} +9 -8
- package/dist/index-DoRvCo76.d.mts.map +1 -0
- package/dist/index.cjs +51 -1
- package/dist/index.d.mts +15 -25
- package/dist/index.mjs +12 -1
- package/dist/leader.cjs +0 -1
- package/dist/leader.d.mts +2 -2
- package/dist/leader.mjs +1 -1
- package/dist/{components/leaderHints.d.cts → leaderHints-BwZHg3Zt.d.mts} +20 -7
- package/dist/leaderHints-BwZHg3Zt.d.mts.map +1 -0
- package/dist/leaderHints-CYJqHmaj.cjs +216 -0
- package/dist/leaderHints-CYJqHmaj.cjs.map +1 -0
- package/dist/leaderHints-sCok2wGh.mjs +205 -0
- package/dist/leaderHints-sCok2wGh.mjs.map +1 -0
- package/dist/leaderHints.cjs +4 -0
- package/dist/leaderHints.d.mts +2 -0
- package/dist/leaderHints.mjs +2 -0
- package/dist/leaderRegistry-DKTjYB4q.cjs +519 -0
- package/dist/leaderRegistry-DKTjYB4q.cjs.map +1 -0
- package/dist/leaderRegistry-DXYQNR_c.mjs +514 -0
- package/dist/leaderRegistry-DXYQNR_c.mjs.map +1 -0
- package/dist/leaderRegistry.cjs +3 -2
- package/dist/leaderRegistry.d.mts +2 -58
- package/dist/leaderRegistry.mjs +2 -2
- package/dist/logSinkTelemetry.cjs +4 -2
- package/dist/logSinkTelemetry.d.mts +2 -29
- package/dist/logSinkTelemetry.mjs +2 -2
- package/dist/matrixPicker.cjs +150 -0
- package/dist/matrixPicker.cjs.map +1 -0
- package/dist/matrixPicker.d.mts +54 -0
- package/dist/matrixPicker.d.mts.map +1 -0
- package/dist/matrixPicker.mjs +146 -0
- package/dist/matrixPicker.mjs.map +1 -0
- package/dist/rendering-AfmSPYnd.mjs +65 -0
- package/dist/rendering-AfmSPYnd.mjs.map +1 -0
- package/dist/rendering-D_d6wdrK.cjs +106 -0
- package/dist/rendering-D_d6wdrK.cjs.map +1 -0
- package/dist/rendering.cjs +13 -2
- package/dist/rendering.d.mts +25 -8
- package/dist/rendering.d.mts.map +1 -1
- package/dist/rendering.mjs +3 -2
- package/dist/rolldown-runtime-VH7oDXx4.cjs +28 -0
- package/dist/skills.cjs +38 -1
- package/dist/skills.d.mts +2 -1
- package/dist/skills.mjs +2 -1
- package/dist/telemetry-CjLBjfN8.cjs +47 -0
- package/dist/{logSinkTelemetry.cjs.map → telemetry-CjLBjfN8.cjs.map} +1 -1
- package/dist/telemetry-ioWp8s-g.mjs +36 -0
- package/dist/{logSinkTelemetry.mjs.map → telemetry-ioWp8s-g.mjs.map} +1 -1
- package/dist/theme-CRP66cUO.d.mts +103 -0
- package/dist/theme-CRP66cUO.d.mts.map +1 -0
- package/dist/theme-DOBo1P0E.mjs +134 -0
- package/dist/theme-DOBo1P0E.mjs.map +1 -0
- package/dist/theme-YHJrFjof.cjs +166 -0
- package/dist/theme-YHJrFjof.cjs.map +1 -0
- package/dist/theme.cjs +7 -2
- package/dist/theme.d.mts +2 -95
- package/dist/theme.mjs +2 -2
- package/dist/toolChrome-BJUD8oJY.mjs +93 -0
- package/dist/toolChrome-BJUD8oJY.mjs.map +1 -0
- package/dist/toolChrome-Dktxk1id.d.mts +44 -0
- package/dist/toolChrome-Dktxk1id.d.mts.map +1 -0
- package/dist/toolChrome-f6IcTk57.cjs +134 -0
- package/dist/toolChrome-f6IcTk57.cjs.map +1 -0
- package/dist/toolChrome.cjs +9 -0
- package/dist/toolChrome.d.mts +2 -0
- package/dist/toolChrome.mjs +2 -0
- package/dist/toolInventory.cjs +20 -2
- package/dist/toolInventory.d.mts +2 -40
- package/dist/toolInventory.mjs +2 -2
- package/dist/toolsOverlay-BiiEtX5a.cjs +235 -0
- package/dist/toolsOverlay-BiiEtX5a.cjs.map +1 -0
- package/dist/toolsOverlay-DQ8eXvL0.mjs +224 -0
- package/dist/toolsOverlay-DQ8eXvL0.mjs.map +1 -0
- package/dist/toolsOverlay.cjs +4 -0
- package/dist/{components/toolsOverlay.d.mts → toolsOverlay.d.mts} +5 -6
- package/dist/toolsOverlay.d.mts.map +1 -0
- package/dist/toolsOverlay.mjs +2 -0
- package/dist/ui-ByJgBTSD.mjs +18 -0
- package/dist/ui-ByJgBTSD.mjs.map +1 -0
- package/dist/ui-DqBCupXE.cjs +89 -0
- package/dist/ui-DqBCupXE.cjs.map +1 -0
- package/dist/uiState-CQoAIdwc.d.mts +40 -0
- package/dist/uiState-CQoAIdwc.d.mts.map +1 -0
- package/dist/uiState-G_Pso-5i.mjs +57 -0
- package/dist/uiState-G_Pso-5i.mjs.map +1 -0
- package/dist/uiState-rUwgKslb.cjs +68 -0
- package/dist/uiState-rUwgKslb.cjs.map +1 -0
- package/dist/uiState.cjs +4 -2
- package/dist/uiState.d.mts +2 -37
- package/dist/uiState.mjs +2 -2
- package/package.json +152 -61
- package/themes/doom-pi-dark.json +32 -30
- package/dist/_virtual/_rolldown/runtime.cjs +0 -1
- package/dist/_virtual/_rolldown/runtime.mjs +0 -1
- package/dist/components/configOverlay.cjs +0 -0
- package/dist/components/configOverlay.cjs.map +0 -1
- package/dist/components/configOverlay.d.cts +0 -0
- package/dist/components/configOverlay.d.cts.map +0 -1
- package/dist/components/configOverlay.d.mts.map +0 -1
- package/dist/components/configOverlay.mjs +0 -0
- package/dist/components/configOverlay.mjs.map +0 -1
- package/dist/components/doomEditor.cjs +0 -2
- package/dist/components/doomEditor.cjs.map +0 -1
- package/dist/components/doomEditor.d.cts +0 -59
- package/dist/components/doomEditor.d.cts.map +0 -1
- package/dist/components/doomEditor.d.mts.map +0 -1
- package/dist/components/doomEditor.mjs +0 -2
- package/dist/components/doomEditor.mjs.map +0 -1
- package/dist/components/doomFooter.cjs +0 -2
- package/dist/components/doomFooter.cjs.map +0 -1
- package/dist/components/doomFooter.d.cts.map +0 -1
- package/dist/components/doomFooter.d.mts +0 -32
- package/dist/components/doomFooter.d.mts.map +0 -1
- package/dist/components/doomFooter.mjs +0 -2
- package/dist/components/doomFooter.mjs.map +0 -1
- package/dist/components/doomHeader.cjs +0 -2
- package/dist/components/doomHeader.cjs.map +0 -1
- package/dist/components/doomHeader.d.cts.map +0 -1
- package/dist/components/doomHeader.d.mts +0 -34
- package/dist/components/doomHeader.d.mts.map +0 -1
- package/dist/components/doomHeader.mjs +0 -2
- package/dist/components/doomHeader.mjs.map +0 -1
- package/dist/components/doomOverlay.cjs +0 -2
- package/dist/components/doomOverlay.cjs.map +0 -1
- package/dist/components/doomOverlay.d.cts +0 -79
- package/dist/components/doomOverlay.d.cts.map +0 -1
- package/dist/components/doomOverlay.d.mts.map +0 -1
- package/dist/components/doomOverlay.mjs +0 -2
- package/dist/components/doomOverlay.mjs.map +0 -1
- package/dist/components/leaderHints.cjs +0 -2
- package/dist/components/leaderHints.cjs.map +0 -1
- package/dist/components/leaderHints.d.cts.map +0 -1
- package/dist/components/leaderHints.d.mts +0 -37
- package/dist/components/leaderHints.d.mts.map +0 -1
- package/dist/components/leaderHints.mjs +0 -2
- package/dist/components/leaderHints.mjs.map +0 -1
- package/dist/components/toolsOverlay.cjs +0 -2
- package/dist/components/toolsOverlay.cjs.map +0 -1
- package/dist/components/toolsOverlay.d.cts +0 -29
- package/dist/components/toolsOverlay.d.cts.map +0 -1
- package/dist/components/toolsOverlay.d.mts.map +0 -1
- package/dist/components/toolsOverlay.mjs +0 -2
- package/dist/components/toolsOverlay.mjs.map +0 -1
- package/dist/config.cjs.map +0 -1
- package/dist/config.d.cts +0 -5
- package/dist/config.d.cts.map +0 -1
- package/dist/config.d.mts.map +0 -1
- package/dist/config.mjs.map +0 -1
- package/dist/extension.cjs +0 -2
- package/dist/extension.cjs.map +0 -1
- package/dist/extension.d.cts +0 -7
- package/dist/extension.d.cts.map +0 -1
- package/dist/extension.d.mts +0 -7
- package/dist/extension.d.mts.map +0 -1
- package/dist/extension.mjs +0 -2
- package/dist/extension.mjs.map +0 -1
- package/dist/extensionName.cjs.map +0 -1
- package/dist/extensionName.d.cts +0 -16
- package/dist/extensionName.d.cts.map +0 -1
- package/dist/extensionName.mjs.map +0 -1
- package/dist/extensions/pi.d.cts +0 -2
- package/dist/footer.cjs.map +0 -1
- package/dist/footer.d.cts +0 -5
- package/dist/footer.d.cts.map +0 -1
- package/dist/footer.d.mts.map +0 -1
- package/dist/footer.mjs.map +0 -1
- package/dist/harnessMetadata.cjs.map +0 -1
- package/dist/harnessMetadata.d.cts.map +0 -1
- package/dist/harnessMetadata.d.mts.map +0 -1
- package/dist/harnessMetadata.mjs.map +0 -1
- package/dist/index.d.cts +0 -25
- package/dist/leader.d.cts +0 -2
- package/dist/leaderRegistry.cjs.map +0 -1
- package/dist/leaderRegistry.d.cts.map +0 -1
- package/dist/leaderRegistry.d.mts.map +0 -1
- package/dist/leaderRegistry.mjs.map +0 -1
- package/dist/logSinkTelemetry.d.cts.map +0 -1
- package/dist/logSinkTelemetry.d.mts.map +0 -1
- package/dist/mode.cjs +0 -2
- package/dist/mode.cjs.map +0 -1
- package/dist/mode.d.cts +0 -5
- package/dist/mode.d.cts.map +0 -1
- package/dist/mode.d.mts +0 -5
- package/dist/mode.d.mts.map +0 -1
- package/dist/mode.mjs +0 -2
- package/dist/mode.mjs.map +0 -1
- package/dist/rendering.cjs.map +0 -1
- package/dist/rendering.d.cts +0 -11
- package/dist/rendering.d.cts.map +0 -1
- package/dist/rendering.mjs.map +0 -1
- package/dist/skills.d.cts +0 -1
- package/dist/theme.cjs.map +0 -1
- package/dist/theme.d.cts +0 -95
- package/dist/theme.d.cts.map +0 -1
- package/dist/theme.d.mts.map +0 -1
- package/dist/theme.mjs.map +0 -1
- package/dist/toolInventory.cjs.map +0 -1
- package/dist/toolInventory.d.cts +0 -40
- package/dist/toolInventory.d.cts.map +0 -1
- package/dist/toolInventory.d.mts.map +0 -1
- package/dist/toolInventory.mjs.map +0 -1
- package/dist/uiState.cjs.map +0 -1
- package/dist/uiState.d.cts +0 -37
- package/dist/uiState.d.cts.map +0 -1
- package/dist/uiState.d.mts.map +0 -1
- package/dist/uiState.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -1,40 +1,110 @@
|
|
|
1
1
|
# @agimon-ai/doompi-ui
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
DoomPi's shared terminal interface, Leader Space host, theme, overlays, and UI registries.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
to a keystroke.
|
|
5
|
+
The [DoomPi distribution](https://www.npmjs.com/package/@agimon-ai/doompi) loads this package as
|
|
6
|
+
core. Extension authors can depend on its public contracts without adopting the full distribution.
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
> **Alpha:** UI and contribution contracts may change between releases.
|
|
9
|
+
|
|
10
|
+
## Requirements
|
|
11
|
+
|
|
12
|
+
- Node.js 22.19.0 or newer
|
|
13
|
+
- Pi 0.85.0
|
|
14
|
+
- Pi TUI 0.85.0
|
|
12
15
|
|
|
13
16
|
## Install
|
|
14
17
|
|
|
18
|
+
To load the UI directly in Pi:
|
|
19
|
+
|
|
15
20
|
```bash
|
|
16
|
-
|
|
21
|
+
pi install npm:@agimon-ai/doompi-ui
|
|
17
22
|
```
|
|
18
23
|
|
|
19
|
-
|
|
24
|
+
DoomPi users should not add it to a layer; the distribution loads it before layer contributions.
|
|
25
|
+
|
|
26
|
+
## Commands and keys
|
|
27
|
+
|
|
28
|
+
| Input | Behavior |
|
|
29
|
+
| ------------ | ---------------------------------------------------------------------------------- |
|
|
30
|
+
| `Ctrl+Space` | Opens Leader Space from anywhere in the editor |
|
|
31
|
+
| `SPC` | Opens Leader Space only when the current draft is empty; otherwise inserts a space |
|
|
32
|
+
| `/tools` | Opens the current tool and MCP inventory |
|
|
33
|
+
| `/config` | Opens settings contributed by active extensions |
|
|
34
|
+
|
|
35
|
+
The registry rejects or diagnoses conflicting Leader contributions instead of silently replacing
|
|
36
|
+
an existing binding. Diagnostics are recorded through telemetry and shown as TUI warnings when a
|
|
37
|
+
UI is attached.
|
|
38
|
+
|
|
39
|
+
## Contribute to Leader Space
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { DOOM_UI_HUB_SERVICE, requireDoomUiHub } from '@agimon-ai/doompi-core/uiHub';
|
|
43
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
44
|
+
|
|
45
|
+
export function reviewPlugin(ctx: Context): void {
|
|
46
|
+
ctx.inject([DOOM_UI_HUB_SERVICE], (uiContext) => {
|
|
47
|
+
const contribution = requireDoomUiHub(uiContext).registerLeader({
|
|
48
|
+
source: '@example/review-extension',
|
|
49
|
+
bindings: [
|
|
50
|
+
{
|
|
51
|
+
id: 'review.open',
|
|
52
|
+
path: [{ key: 'r', label: 'review', detail: 'open review tools' }],
|
|
53
|
+
command: { name: 'review' },
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
});
|
|
57
|
+
return () => contribution.dispose();
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Mount this plugin beneath the shared Doom Cordis host. Cordis retracts the registration when either
|
|
63
|
+
the contributor or UI provider disappears, so reloads cannot retain stale bindings.
|
|
64
|
+
|
|
65
|
+
## TUI and headless sessions
|
|
66
|
+
|
|
67
|
+
The editor, header, footer, overlays, Leader menu, and notifications require an interactive TUI.
|
|
68
|
+
The underlying typed contribution registries can still be installed and queried in headless
|
|
69
|
+
sessions, but UI-only commands have no panel to render. Provide a tool, RPC, or CLI route when a
|
|
70
|
+
capability must also work headlessly.
|
|
20
71
|
|
|
21
|
-
|
|
22
|
-
`.doom/modes.yaml`: making it optional would only create broken configurations.
|
|
72
|
+
## Extension lifecycle
|
|
23
73
|
|
|
24
|
-
|
|
74
|
+
`src/extensions/pi.ts` declares the Pi plugin, and `src/extensions/server.ts` declares the session inventory plugin. The browser entry is `src/extensions/web.ts`. Public modules stay flat under `src/exports`; Component exports use flat kebab-case subpaths such as `@agimon-ai/doompi-ui/doomOverlay` and `@agimon-ai/doompi-ui/matrixPicker`.
|
|
25
75
|
|
|
26
|
-
|
|
76
|
+
The Pi helper installs the UI hub service before commands, native event handlers, and tool declarations. Optional minor-mode catalog bindings follow their provider lifetime. `onStop` clears the shell and shuts down telemetry; idempotent `onDispose` also handles registration failure. The TUI runtime owns presentation callbacks, `models/uiState.ts` owns state, and each service has its own `services/<name>/index.ts` entry.
|
|
27
77
|
|
|
28
|
-
|
|
78
|
+
Native builtin tools use `definePiTool` to retain their schema and renderer detail types. Composed sessions install their renderers directly; standalone sessions install each replacement only after its override claim is granted.
|
|
29
79
|
|
|
30
|
-
##
|
|
80
|
+
## Theme
|
|
31
81
|
|
|
32
|
-
|
|
33
|
-
|
|
82
|
+
The package publishes `@agimon-ai/doompi-ui/themes/doom-pi-dark.json`. DoomPi synchronizes that
|
|
83
|
+
resource and selects it by default. Set `DOOMPI_THEME` to select another available Pi theme for the
|
|
84
|
+
UI extension.
|
|
34
85
|
|
|
35
|
-
##
|
|
86
|
+
## Public API
|
|
87
|
+
|
|
88
|
+
Declared exports cover UI state, rendering, tool chrome, header/footer/editor components,
|
|
89
|
+
configuration and tools overlays, telemetry integration, and theme helpers. Contribution schemas
|
|
90
|
+
and the direct UI hub service live in extension contracts. Use these exports rather than importing
|
|
91
|
+
generated `dist` paths.
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
import { DOOM_UI_HUB_SERVICE } from '@agimon-ai/doompi-core/uiHub';
|
|
95
|
+
import { DEFAULT_THEME_NAME } from '@agimon-ai/doompi-ui/theme';
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Development
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
pnpm build
|
|
102
|
+
pnpm typecheck
|
|
103
|
+
pnpm test
|
|
104
|
+
pnpm lint
|
|
105
|
+
```
|
|
36
106
|
|
|
37
|
-
|
|
107
|
+
Maintained by [Agimon](https://agimon.ai/about).
|
|
38
108
|
|
|
39
109
|
## License
|
|
40
110
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Object.defineProperties(exports, {
|
|
2
|
+
__esModule: { value: true },
|
|
3
|
+
[Symbol.toStringTag]: { value: "Module" }
|
|
4
|
+
});
|
|
5
|
+
//#region src/schemas/apiContracts.ts
|
|
6
|
+
/** This facet contributes agent tools, commands or lifecycle only, with no separate HTTP or socket surface. */
|
|
7
|
+
const apiContracts = (0, require("@agimon-ai/doompi-core/apiContracts").defineApiContract)({
|
|
8
|
+
version: 1,
|
|
9
|
+
http: [],
|
|
10
|
+
sockets: [],
|
|
11
|
+
dynamic: []
|
|
12
|
+
});
|
|
13
|
+
//#endregion
|
|
14
|
+
exports.apiContracts = apiContracts;
|
|
15
|
+
exports.default = apiContracts;
|
|
16
|
+
|
|
17
|
+
//# sourceMappingURL=apiContracts.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiContracts.cjs","names":["defineApiContract"],"sources":["../src/schemas/apiContracts.ts"],"sourcesContent":["import { defineApiContract } from '@agimon-ai/doompi-core/apiContracts';\n\n/** This facet contributes agent tools, commands or lifecycle only, with no separate HTTP or socket surface. */\nexport const apiContracts = defineApiContract({ version: 1, http: [], sockets: [], dynamic: [] });\nexport default apiContracts;\n"],"mappings":";;;;;;AAGA,MAAa,gBAAA,gDAAeA,CAAAA,CAAAA,kBAAAA,CAAkB;CAAE,SAAS;CAAG,MAAM,CAAC;CAAG,SAAS,CAAC;CAAG,SAAS,CAAC;AAAE,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
//#region src/schemas/apiContracts.d.ts
|
|
2
|
+
/** This facet contributes agent tools, commands or lifecycle only, with no separate HTTP or socket surface. */
|
|
3
|
+
export declare const apiContracts: {
|
|
4
|
+
version: 1;
|
|
5
|
+
protocols?: Record<string, string> | undefined;
|
|
6
|
+
schemas?: Record<string, boolean | object> | undefined;
|
|
7
|
+
http: {
|
|
8
|
+
id: string;
|
|
9
|
+
scope: "global" | "session" | "workspace";
|
|
10
|
+
basePath?: string | undefined;
|
|
11
|
+
path: string;
|
|
12
|
+
method: "DELETE" | "GET" | "HEAD" | "OPTIONS" | "PATCH" | "POST" | "PUT";
|
|
13
|
+
description: string;
|
|
14
|
+
availability?: string | undefined;
|
|
15
|
+
authentication: "device" | "none" | "owner";
|
|
16
|
+
parameters?: {
|
|
17
|
+
name: string;
|
|
18
|
+
in: "header" | "path" | "query";
|
|
19
|
+
required: boolean;
|
|
20
|
+
schema: boolean | object;
|
|
21
|
+
}[] | undefined;
|
|
22
|
+
body?: {
|
|
23
|
+
contentType: string;
|
|
24
|
+
contentTypes?: string[] | undefined;
|
|
25
|
+
required: boolean;
|
|
26
|
+
schema: boolean | object;
|
|
27
|
+
} | undefined;
|
|
28
|
+
responses: Record<string, {
|
|
29
|
+
description: string;
|
|
30
|
+
contentType?: string | undefined;
|
|
31
|
+
schema?: boolean | object | undefined;
|
|
32
|
+
events?: Record<string, boolean | object> | undefined;
|
|
33
|
+
}>;
|
|
34
|
+
}[];
|
|
35
|
+
sockets: {
|
|
36
|
+
id: string;
|
|
37
|
+
scope: "global" | "session" | "workspace";
|
|
38
|
+
description: string;
|
|
39
|
+
availability?: string | undefined;
|
|
40
|
+
service: string;
|
|
41
|
+
member: string;
|
|
42
|
+
direction: "client-to-server" | "server-to-client";
|
|
43
|
+
kind: "channel" | "method" | "state";
|
|
44
|
+
input: boolean | object;
|
|
45
|
+
output?: boolean | object | undefined;
|
|
46
|
+
errors?: boolean | object | undefined;
|
|
47
|
+
}[];
|
|
48
|
+
dynamic: string[];
|
|
49
|
+
gaps?: string[] | undefined;
|
|
50
|
+
};
|
|
51
|
+
//#endregion
|
|
52
|
+
export { apiContracts as default };
|
|
53
|
+
//# sourceMappingURL=apiContracts.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiContracts.d.mts","names":[],"sources":["../src/schemas/apiContracts.ts"],"mappings":";;qBAGa"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { defineApiContract } from "@agimon-ai/doompi-core/apiContracts";
|
|
2
|
+
//#region src/schemas/apiContracts.ts
|
|
3
|
+
/** This facet contributes agent tools, commands or lifecycle only, with no separate HTTP or socket surface. */
|
|
4
|
+
const apiContracts = defineApiContract({
|
|
5
|
+
version: 1,
|
|
6
|
+
http: [],
|
|
7
|
+
sockets: [],
|
|
8
|
+
dynamic: []
|
|
9
|
+
});
|
|
10
|
+
//#endregion
|
|
11
|
+
export { apiContracts, apiContracts as default };
|
|
12
|
+
|
|
13
|
+
//# sourceMappingURL=apiContracts.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiContracts.mjs","names":[],"sources":["../src/schemas/apiContracts.ts"],"sourcesContent":["import { defineApiContract } from '@agimon-ai/doompi-core/apiContracts';\n\n/** This facet contributes agent tools, commands or lifecycle only, with no separate HTTP or socket surface. */\nexport const apiContracts = defineApiContract({ version: 1, http: [], sockets: [], dynamic: [] });\nexport default apiContracts;\n"],"mappings":";;;AAGA,MAAa,eAAe,kBAAkB;CAAE,SAAS;CAAG,MAAM,CAAC;CAAG,SAAS,CAAC;CAAG,SAAS,CAAC;AAAE,CAAC"}
|
package/dist/config.cjs
CHANGED
|
@@ -1,2 +1,62 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value
|
|
2
|
-
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
let _agimon_ai_doompi_core_config = require("@agimon-ai/doompi-core/config");
|
|
3
|
+
Object.defineProperty(exports, "CONFIG_ACTION", {
|
|
4
|
+
enumerable: true,
|
|
5
|
+
get: function() {
|
|
6
|
+
return _agimon_ai_doompi_core_config.CONFIG_ACTION;
|
|
7
|
+
}
|
|
8
|
+
});
|
|
9
|
+
Object.defineProperty(exports, "ConfigActionSchema", {
|
|
10
|
+
enumerable: true,
|
|
11
|
+
get: function() {
|
|
12
|
+
return _agimon_ai_doompi_core_config.ConfigActionSchema;
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
Object.defineProperty(exports, "ConfigChoiceSchema", {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
get: function() {
|
|
18
|
+
return _agimon_ai_doompi_core_config.ConfigChoiceSchema;
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
Object.defineProperty(exports, "ConfigFieldKindSchema", {
|
|
22
|
+
enumerable: true,
|
|
23
|
+
get: function() {
|
|
24
|
+
return _agimon_ai_doompi_core_config.ConfigFieldKindSchema;
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
Object.defineProperty(exports, "ConfigFieldSchema", {
|
|
28
|
+
enumerable: true,
|
|
29
|
+
get: function() {
|
|
30
|
+
return _agimon_ai_doompi_core_config.ConfigFieldSchema;
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
Object.defineProperty(exports, "ConfigProgressSchema", {
|
|
34
|
+
enumerable: true,
|
|
35
|
+
get: function() {
|
|
36
|
+
return _agimon_ai_doompi_core_config.ConfigProgressSchema;
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
Object.defineProperty(exports, "ConfigSectionSchema", {
|
|
40
|
+
enumerable: true,
|
|
41
|
+
get: function() {
|
|
42
|
+
return _agimon_ai_doompi_core_config.ConfigSectionSchema;
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
Object.defineProperty(exports, "ConfigSourceSchema", {
|
|
46
|
+
enumerable: true,
|
|
47
|
+
get: function() {
|
|
48
|
+
return _agimon_ai_doompi_core_config.ConfigSourceSchema;
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
Object.defineProperty(exports, "ConfigStatusSchema", {
|
|
52
|
+
enumerable: true,
|
|
53
|
+
get: function() {
|
|
54
|
+
return _agimon_ai_doompi_core_config.ConfigStatusSchema;
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
Object.defineProperty(exports, "ConfigStepSchema", {
|
|
58
|
+
enumerable: true,
|
|
59
|
+
get: function() {
|
|
60
|
+
return _agimon_ai_doompi_core_config.ConfigStepSchema;
|
|
61
|
+
}
|
|
62
|
+
});
|
package/dist/config.d.mts
CHANGED
|
@@ -1,5 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
//#endregion
|
|
4
|
-
export { import__agimon_ai_doompi_extension_contracts_config as config_d_exports };
|
|
5
|
-
//# sourceMappingURL=config.d.mts.map
|
|
1
|
+
import { CONFIG_ACTION, ConfigAction, ConfigActionSchema, ConfigChoice, ConfigChoiceSchema, ConfigField, ConfigFieldKind, ConfigFieldKindSchema, ConfigFieldSchema, ConfigProgress, ConfigProgressSchema, ConfigSection, ConfigSectionSchema, ConfigSnapshot, ConfigSourceRef, ConfigSourceSchema, ConfigStatus, ConfigStatusSchema, ConfigStep, ConfigStepSchema, DoomConfigActionInput, DoomConfigContributionHandle, DoomConfigContributionOptions, DoomConfigInvocation, DoomConfigSectionView, DoomExtensionContext } from "@agimon-ai/doompi-core/config";
|
|
2
|
+
export { CONFIG_ACTION, type ConfigAction, ConfigActionSchema, type ConfigChoice, ConfigChoiceSchema, type ConfigField, type ConfigFieldKind, ConfigFieldKindSchema, ConfigFieldSchema, type ConfigProgress, ConfigProgressSchema, type ConfigSection, ConfigSectionSchema, type ConfigSnapshot, type ConfigSourceRef, ConfigSourceSchema, type ConfigStatus, ConfigStatusSchema, type ConfigStep, ConfigStepSchema, type DoomConfigActionInput, type DoomConfigContributionHandle, type DoomConfigContributionOptions, type DoomConfigInvocation, type DoomConfigSectionView, type DoomExtensionContext };
|
package/dist/config.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{
|
|
2
|
-
|
|
1
|
+
import { CONFIG_ACTION, ConfigActionSchema, ConfigChoiceSchema, ConfigFieldKindSchema, ConfigFieldSchema, ConfigProgressSchema, ConfigSectionSchema, ConfigSourceSchema, ConfigStatusSchema, ConfigStepSchema } from "@agimon-ai/doompi-core/config";
|
|
2
|
+
export { CONFIG_ACTION, ConfigActionSchema, ConfigChoiceSchema, ConfigFieldKindSchema, ConfigFieldSchema, ConfigProgressSchema, ConfigSectionSchema, ConfigSourceSchema, ConfigStatusSchema, ConfigStepSchema };
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"configOverlay-Bov-Zcdz.cjs","names":["fitStyledLine","visibleWidth","DoomOverlay","matchesKey","DOOM_OVERLAY_ACCENT","truncateToWidth","DOOM_FULLSCREEN_UI_OPTIONS"],"sources":["../src/tui/configOverlay.ts"],"sourcesContent":["/**\n * Configuration panel: the `SPC e c` overlay.\n *\n * Sections on the left, one per contributing extension, and that section's\n * fields on the right. The panel owns navigation and text entry; every value it\n * shows was published by an extension, and every change it makes is a request\n * back to whichever extension owns the field. Nothing here knows what a voice\n * model or an editor command is.\n *\n * It subscribes to the registry rather than snapshotting at open time, unlike\n * the tools browser next door, because a contributor can be doing long work\n * (fetching a model, running an installer) and the panel is where that progress\n * is meant to appear.\n *\n * There is no local echo of an edit. A typed value is sent and the field stays\n * pending until its owner republishes, so a rejected value comes back with the\n * reason attached instead of the panel showing a value that was never written.\n */\n\nimport type { ConfigChoice, ConfigField } from '@agimon-ai/doompi-core/config';\nimport type { DoomConfigSectionView } from '@agimon-ai/doompi-core/config';\nimport type { ExtensionContext, Theme } from '@earendil-works/pi-coding-agent';\nimport { matchesKey, truncateToWidth, visibleWidth } from '@earendil-works/pi-tui';\n\nimport {\n DOOM_FULLSCREEN_UI_OPTIONS,\n DOOM_OVERLAY_ACCENT,\n DoomOverlay,\n type DoomOverlayChrome,\n type DoomOverlayTui,\n} from './doomOverlay';\nimport { fitStyledLine } from './rendering';\n\ntype Pane = 'sections' | 'fields';\ntype Mode = 'browse' | 'edit' | 'choices';\n\nconst TITLE = 'CONFIG';\nconst BREADCRUMB = 'SPC › e / c · config';\nconst ACTION_SET = 'set';\nconst ACTION_CLEAR = 'clear';\nconst ACTION_ABORT = 'abort';\nconst DEFAULT_CHOICE_ACTION = 'select';\n\nconst KEY_BACKSPACE = '\\x7f';\nconst KEY_ENTER = '\\r';\nconst KEY_NEWLINE = '\\n';\nconst KEY_TAB = '\\t';\nconst FIRST_PRINTABLE_CODE_POINT = 0x20;\nconst DELETE_CODE_POINT = 0x7f;\n\nconst MIN_WIDTH = 48;\nconst SECTION_PANE_RATIO = 1 / 3;\nconst PANE_GUTTER = 1;\nconst MIN_PANE_WIDTH = 18;\nconst ELLIPSIS = '…';\nconst LABEL_COLUMN = 18;\nconst INDENT = ' ';\nconst EMPTY_MESSAGE = 'No extension has contributed settings to this session.';\nconst NO_FIELDS_MESSAGE = 'This section has no fields.';\nconst UNSET_PLACEHOLDER = 'not set';\nconst SECTION_HEADING = 'SECTIONS';\nconst HELP_BADGE = ' HELP ';\n/**\n * Every field here is published by a package, so the panel cannot explain what\n * any one of them means. Help mode can: it loads the owning package's docs into\n * the session, and the agent reads them and answers from there.\n */\nconst HELP_HINT = 'Not sure what a setting does? SPC h e loads package Help, then ask the agent about it.';\n/** Body rows below which the banner is dropped: a field outranks a pointer to the docs. */\nconst HELP_BANNER_MIN_ROWS = 10;\nconst PROGRESS_WIDTH = 24;\nconst ACTION_INPUT = 'input';\ntype ThemeColor = Parameters<Theme['fg']>[0];\nconst STEP_MARKERS: Readonly<Record<string, readonly [string, ThemeColor]>> = {\n pending: ['·', 'dim'],\n satisfied: ['✓', 'dim'],\n running: ['▸', 'accent'],\n done: ['✓', 'success'],\n failed: ['✗', 'error'],\n};\nconst PROGRESS_FULL = '█';\nconst PROGRESS_EMPTY = '░';\n\n/**\n * Keystrokes that carry no text: escape sequences, control keys, delete.\n * Indexed rather than iterated so surrogate pairs stay intact; both halves sit\n * far above the control range, so no emoji is ever mistaken for one.\n */\nfunction isControlInput(data: string): boolean {\n for (let index = 0; index < data.length; index++) {\n const code = data.charCodeAt(index);\n if (code < FIRST_PRINTABLE_CODE_POINT || code === DELETE_CODE_POINT) return true;\n }\n return false;\n}\n\nfunction fitRow(text: string, width: number): string {\n return fitStyledLine(text, width, ELLIPSIS);\n}\n\nfunction rightAligned(left: string, right: string, width: number): string {\n const rightWidth = visibleWidth(right);\n const leftWidth = Math.max(0, width - rightWidth - 1);\n return fitRow(left, leftWidth) + ' '.repeat(Math.max(1, width - leftWidth - rightWidth)) + fitRow(right, rightWidth);\n}\n\nfunction wrap(text: string, width: number): string[] {\n if (width <= 0) return [];\n const lines: string[] = [];\n let current = '';\n for (const word of text.split(/\\s+/).filter(Boolean)) {\n if (current.length === 0) current = word;\n else if (current.length + 1 + word.length <= width) current += ` ${word}`;\n else {\n lines.push(current);\n current = word;\n }\n }\n if (current.length > 0) lines.push(current);\n return lines;\n}\n\nfunction isSelectable(field: ConfigField): boolean {\n return field.kind !== 'info';\n}\n\nexport class ConfigOverlayComponent extends DoomOverlay {\n private readonly registry: DoomConfigStoreView;\n private readonly done: (result: undefined) => void;\n private readonly unsubscribe: () => void;\n private sections: readonly DoomConfigSectionView[];\n private pane: Pane = 'sections';\n private mode: Mode = 'browse';\n private sectionIndex = 0;\n private fieldIndex = 0;\n private choiceIndex = 0;\n private draft = '';\n /** Fields awaiting a reply, keyed by source, section, and field. */\n private readonly pending = new Set<string>();\n private bodyHeight = 1;\n\n constructor(tui: DoomOverlayTui, theme: Theme, registry: DoomConfigStoreView, done: (result: undefined) => void) {\n super(tui, theme);\n this.registry = registry;\n this.done = done;\n this.sections = registry.getSections();\n this.fieldIndex = this.firstSelectableField();\n this.unsubscribe = registry.subscribe(() => this.onSectionsChanged());\n }\n\n /** Info fields are labels, so the cursor never starts on one. */\n private firstSelectableField(): number {\n const index = this.currentFields().findIndex(isSelectable);\n return index < 0 ? 0 : index;\n }\n\n dispose(): void {\n this.unsubscribe();\n }\n\n private onSectionsChanged(): void {\n this.sections = this.registry.getSections();\n // Any republish from an owner is its answer, so nothing stays pending past it.\n this.pending.clear();\n this.sectionIndex = Math.min(this.sectionIndex, Math.max(0, this.sections.length - 1));\n const fields = this.currentFields();\n this.fieldIndex = Math.min(this.fieldIndex, Math.max(0, fields.length - 1));\n if (!isSelectable(fields[this.fieldIndex] ?? { kind: 'info' })) this.fieldIndex = this.firstSelectableField();\n const field = this.currentField();\n // A field that grew an error keeps the draft so the typed value is not lost,\n // and an answer being typed survives the republish each output chunk causes.\n if (this.mode === 'edit' && !field?.statusText && !field?.awaitingInput) this.mode = 'browse';\n this.tui.requestRender();\n }\n\n private currentSection(): DoomConfigSectionView | undefined {\n return this.sections[this.sectionIndex];\n }\n\n private currentFields(): readonly ConfigField[] {\n return this.currentSection()?.fields ?? [];\n }\n\n private currentField(): ConfigField | undefined {\n return this.currentFields()[this.fieldIndex];\n }\n\n private currentChoices(): readonly ConfigChoice[] {\n return this.currentField()?.choices ?? [];\n }\n\n private pendingKey(field: ConfigField): string {\n return `${this.currentSection()?.source ?? ''}\u0000${this.currentSection()?.id ?? ''}\u0000${field.id}`;\n }\n\n private invoke(action: string, value?: string): void {\n const section = this.currentSection();\n const field = this.currentField();\n if (!section || !field) return;\n this.pending.add(this.pendingKey(field));\n this.registry.invoke({\n source: section.source,\n sectionId: section.id,\n fieldId: field.id,\n action,\n ...(value === undefined ? {} : { value }),\n });\n this.tui.requestRender();\n }\n\n private moveSection(delta: number): void {\n if (this.sections.length === 0) return;\n const next = Math.max(0, Math.min(this.sectionIndex + delta, this.sections.length - 1));\n if (next === this.sectionIndex) return;\n this.sectionIndex = next;\n this.fieldIndex = this.firstSelectableField();\n this.tui.requestRender();\n }\n\n /** Info fields are labels, so the cursor steps over them to the next control. */\n private moveField(delta: number): void {\n const fields = this.currentFields();\n const step = delta < 0 ? -1 : 1;\n let next = this.fieldIndex + step;\n while (next >= 0 && next < fields.length && !isSelectable(fields[next] as ConfigField)) next += step;\n if (next < 0 || next >= fields.length) return;\n this.fieldIndex = next;\n this.tui.requestRender();\n }\n\n private moveChoice(delta: number): void {\n const choices = this.currentChoices();\n if (choices.length === 0) return;\n const next = Math.max(0, Math.min(this.choiceIndex + delta, choices.length - 1));\n if (next === this.choiceIndex) return;\n this.choiceIndex = next;\n this.tui.requestRender();\n }\n\n handleInput(data: string): void {\n if (this.mode === 'edit') {\n this.handleEditInput(data);\n return;\n }\n if (this.mode === 'choices') {\n this.handleChoiceInput(data);\n return;\n }\n this.handleBrowseInput(data);\n }\n\n private handleBrowseInput(data: string): void {\n const field = this.currentField();\n if (matchesKey(data, 'ctrl+c')) {\n if (field?.busy) this.invoke(ACTION_ABORT);\n else this.done(undefined);\n return;\n }\n if (matchesKey(data, 'escape') || data === 'q') {\n // Escape backs out of the fields pane before it closes the panel.\n if (this.pane === 'fields') {\n this.pane = 'sections';\n this.tui.requestRender();\n return;\n }\n this.done(undefined);\n return;\n }\n if (data === KEY_TAB) {\n this.pane = this.pane === 'sections' ? 'fields' : 'sections';\n this.tui.requestRender();\n return;\n }\n if (matchesKey(data, 'up') || data === 'k') {\n if (this.pane === 'sections') this.moveSection(-1);\n else this.moveField(-1);\n return;\n }\n if (matchesKey(data, 'down') || data === 'j') {\n if (this.pane === 'sections') this.moveSection(1);\n else this.moveField(1);\n return;\n }\n // While a field offers its own keys, those win: a pending confirmation is\n // answered before anything else can be typed.\n const offered = field?.actions?.find((action) => action.key === data);\n if (this.pane === 'fields' && offered) {\n this.invoke(offered.action);\n return;\n }\n // Answering a waiting command beats every other reading of `i`, and it is\n // the only thing that will make progress while one is blocked on a prompt.\n if (this.pane === 'fields' && field?.awaitingInput && data === 'i') {\n this.draft = '';\n this.mode = 'edit';\n this.tui.requestRender();\n return;\n }\n if (matchesKey(data, 'enter') || data === KEY_ENTER || data === KEY_NEWLINE) {\n this.activate();\n return;\n }\n if (this.pane === 'fields' && data === 'd' && field && isSelectable(field)) this.invoke(ACTION_CLEAR);\n }\n\n private activate(): void {\n if (this.pane === 'sections') {\n this.pane = 'fields';\n this.tui.requestRender();\n return;\n }\n const field = this.currentField();\n if (!field || field.busy || !isSelectable(field)) return;\n // `enum` and `choice` differ only in how many entries they carry, so both\n // open the same list with the cursor on whatever is currently set.\n if (field.kind === 'choice' || field.kind === 'enum') {\n this.choiceIndex = Math.max(\n 0,\n this.currentChoices().findIndex((choice) => choice.id === field.value),\n );\n this.mode = 'choices';\n this.tui.requestRender();\n return;\n }\n this.draft = field.value ?? '';\n this.mode = 'edit';\n this.tui.requestRender();\n }\n\n private handleEditInput(data: string): void {\n if (matchesKey(data, 'escape')) {\n this.mode = 'browse';\n this.draft = '';\n this.tui.requestRender();\n return;\n }\n if (data === KEY_ENTER || data === KEY_NEWLINE) {\n const value = this.draft.trim();\n // Answering a prompt is a different write from setting a field, and an\n // empty answer is meaningful there: it accepts the command's default.\n if (this.currentField()?.awaitingInput) {\n this.mode = 'browse';\n this.invoke(ACTION_INPUT, value.length === 0 ? undefined : value);\n this.draft = '';\n return;\n }\n // The parser rejects blank values, so clearing a key means removing it.\n this.invoke(value.length === 0 ? ACTION_CLEAR : ACTION_SET, value.length === 0 ? undefined : value);\n return;\n }\n if (data === KEY_BACKSPACE) this.draft = this.draft.slice(0, -1);\n else if (!isControlInput(data)) this.draft += data;\n this.tui.requestRender();\n }\n\n private handleChoiceInput(data: string): void {\n if (matchesKey(data, 'escape')) {\n this.mode = 'browse';\n this.tui.requestRender();\n return;\n }\n if (matchesKey(data, 'up') || data === 'k') {\n this.moveChoice(-1);\n return;\n }\n if (matchesKey(data, 'down') || data === 'j') {\n this.moveChoice(1);\n return;\n }\n if (matchesKey(data, 'enter') || data === KEY_ENTER || data === KEY_NEWLINE) {\n const choice = this.currentChoices()[this.choiceIndex];\n if (!choice) return;\n this.mode = 'browse';\n // The entry names what enter does to it, which is what lets one list hold\n // both an installed thing to select and an absent one to fetch.\n this.invoke(choice.action ?? DEFAULT_CHOICE_ACTION, choice.id);\n }\n }\n\n private sectionLines(width: number): string[] {\n const lines = [this.theme.bold(SECTION_HEADING), ''];\n if (this.sections.length === 0) {\n lines.push(...wrap(EMPTY_MESSAGE, width).map((line) => this.theme.fg('dim', line)));\n return lines;\n }\n for (const [index, section] of this.sections.entries()) {\n const active = index === this.sectionIndex;\n const title = rightAligned(\n active ? this.theme.bold(section.title) : this.theme.fg('text', section.title),\n this.theme.fg(section.noticeLevel === 'error' ? 'error' : 'dim', section.detail ?? ''),\n width,\n );\n lines.push(active && this.pane === 'sections' ? this.theme.bg('selectedBg', fitRow(title, width)) : title);\n lines.push(this.theme.fg('dim', fitRow(`${INDENT}${section.source}`, width)));\n }\n return lines;\n }\n\n /**\n * The whole plan, not just the running step.\n *\n * Seeing that a package manager already finished and a download is now\n * underway is what makes a long install legible; a lone \"step 3 of 6\" is not.\n */\n private stepLines(field: ConfigField, width: number): string[] {\n const inner = Math.max(1, width - INDENT.length);\n return (field.steps ?? []).map((step) => {\n const [glyph, color] = STEP_MARKERS[step.state];\n const label = step.state === 'pending' ? this.theme.fg('dim', step.label) : step.label;\n const row = rightAligned(\n `${this.theme.fg(color, glyph)} ${label}`,\n this.theme.fg('dim', step.detail ?? ''),\n inner,\n );\n return `${INDENT}${row}`;\n });\n }\n\n /** The tail of the running command, so a prompt it printed is visible. */\n private outputLines(field: ConfigField, width: number): string[] {\n const inner = Math.max(1, width - INDENT.length);\n return (field.output ?? []).map((line) => `${INDENT}${this.theme.fg('dim', fitRow(line, inner))}`);\n }\n\n private progressBar(ratio: number | undefined, width: number): string {\n if (ratio === undefined) return '';\n const filled = Math.max(0, Math.min(PROGRESS_WIDTH, Math.round(ratio * PROGRESS_WIDTH)));\n const bar = PROGRESS_FULL.repeat(filled) + PROGRESS_EMPTY.repeat(PROGRESS_WIDTH - filled);\n return fitRow(`${bar} ${Math.round(ratio * 100)}%`, width);\n }\n\n private fieldLines(width: number): string[] {\n const section = this.currentSection();\n if (!section) return [this.theme.fg('dim', EMPTY_MESSAGE)];\n const lines = [this.theme.bold(section.title), ''];\n if (section.notice) {\n lines.push(\n ...wrap(section.notice, width).map((line) =>\n this.theme.fg(section.noticeLevel === 'error' ? 'error' : 'dim', line),\n ),\n );\n lines.push('');\n }\n if (section.fields.length === 0) {\n lines.push(this.theme.fg('dim', NO_FIELDS_MESSAGE));\n return lines;\n }\n\n const valueWidth = Math.max(1, width - LABEL_COLUMN);\n for (const [index, field] of section.fields.entries()) {\n const active = index === this.fieldIndex && this.pane === 'fields';\n const editing = active && this.mode === 'edit';\n const isPending = this.pending.has(this.pendingKey(field));\n const shown = editing ? `${this.draft}█` : (field.value ?? field.placeholder ?? UNSET_PLACEHOLDER);\n const tone = editing || field.value ? 'text' : 'dim';\n const value = this.theme.fg(isPending || field.busy ? 'dim' : tone, shown);\n const status = field.statusText ?? (isPending ? '' : '');\n const row = `${this.theme.fg('dim', fitRow(field.label, LABEL_COLUMN))}${\n status\n ? rightAligned(value, this.theme.fg(field.status === 'blocked' ? 'error' : 'dim', status), valueWidth)\n : fitRow(value, valueWidth)\n }`;\n lines.push(active ? this.theme.bg('selectedBg', fitRow(row, width)) : row);\n lines.push(...this.stepLines(field, width));\n if (field.busy && field.progress) {\n lines.push(this.theme.fg('dim', fitRow(`${INDENT}${field.progress.label}`, width)));\n const bar = this.progressBar(field.progress.ratio, valueWidth);\n if (bar) lines.push(`${INDENT}${this.theme.fg('accent', bar)}`);\n }\n lines.push(...this.outputLines(field, width));\n if (active && field.awaitingInput) {\n // The command is asking something. Answering is the only useful action,\n // so the line is offered without having to enter a mode first.\n const prompt = this.mode === 'edit' ? `${this.draft}█` : 'press i to answer';\n lines.push(\n `${INDENT}${this.theme.fg('warning', fitRow(`waiting for input ${prompt}`, width - INDENT.length))}`,\n );\n }\n if (!active) continue;\n if (field.detail) {\n lines.push(\n ...wrap(field.detail, Math.max(1, width - LABEL_COLUMN)).map(\n (line) => `${' '.repeat(LABEL_COLUMN)}${this.theme.fg('dim', line)}`,\n ),\n );\n }\n if (field.keyPath) lines.push(`${' '.repeat(LABEL_COLUMN)}${this.theme.fg('accent', field.keyPath)}`);\n if (field.actions && field.actions.length > 0) lines.push(`${' '.repeat(LABEL_COLUMN)}${this.hintLine()}`);\n }\n return lines;\n }\n\n private choiceLines(width: number): string[] {\n const field = this.currentField();\n const choices = this.currentChoices();\n const lines = [this.theme.bold(field?.label ?? ''), ''];\n if (choices.length === 0) {\n lines.push(this.theme.fg('dim', NO_FIELDS_MESSAGE));\n return lines;\n }\n const budget = Math.max(1, this.bodyHeight - lines.length);\n const selected = Math.max(0, Math.min(this.choiceIndex, choices.length - 1));\n const start = Math.max(0, Math.min(selected - budget + 1, Math.max(0, choices.length - budget)));\n let lastGroup: string | undefined;\n for (const [offset, choice] of choices.slice(start, start + budget).entries()) {\n if (choice.group && choice.group !== lastGroup) {\n lastGroup = choice.group;\n lines.push(this.theme.fg('accent', fitRow(choice.group, width)));\n }\n const status = choice.statusText ?? choice.status ?? '';\n const row = rightAligned(\n `${INDENT}${choice.label}${choice.detail ? this.theme.fg('dim', ` ${choice.detail}`) : ''}`,\n this.theme.fg(choice.status === 'blocked' ? 'error' : 'dim', status),\n width,\n );\n lines.push(start + offset === selected ? this.theme.bg('selectedBg', fitRow(row, width)) : row);\n }\n return lines;\n }\n\n private hints(): readonly (readonly [string, string])[] {\n if (this.mode === 'edit') {\n return [\n ['⌫', 'delete'],\n ['enter', this.currentField()?.awaitingInput ? 'send' : 'save'],\n ['esc', 'cancel'],\n ];\n }\n if (this.mode === 'choices') {\n const choice = this.currentChoices()[this.choiceIndex];\n // The hint names what enter does to the entry under the cursor, because on\n // this list that differs row by row.\n return [\n ['↑↓', 'move'],\n ['enter', choice?.action ?? DEFAULT_CHOICE_ACTION],\n ['esc', 'back'],\n ];\n }\n const field = this.currentField();\n if (field?.awaitingInput) {\n return [\n ['i', 'answer'],\n ['ctrl+c', 'abort'],\n ['esc', 'close, keeps running'],\n ];\n }\n if (field?.busy) {\n return [\n ['ctrl+c', 'abort'],\n ['esc', 'close, keeps running'],\n ];\n }\n const offered = (field?.actions ?? []).map((action) => [action.key, action.label] as const);\n return [\n ['↑↓', 'move'],\n ['tab', 'pane'],\n ['enter', this.pane === 'sections' ? 'fields' : 'edit'],\n ...offered,\n ...(this.pane === 'fields' && offered.length === 0 ? ([['d', 'clear']] as const) : []),\n ['esc', this.pane === 'fields' ? 'back' : 'close'],\n ];\n }\n\n private hintLine(): string {\n return this.hints()\n .map(\n ([key, label]) =>\n `${this.theme.bg('selectedBg', this.theme.fg('text', ` ${key} `))}${this.theme.fg('dim', ` ${label}`)}`,\n )\n .join(this.theme.fg('dim', ' '));\n }\n\n protected getChrome(): DoomOverlayChrome {\n const section = this.currentSection();\n const field = this.currentField();\n const breadcrumb =\n this.mode === 'choices' && section && field ? `${BREADCRUMB} › ${section.title} / ${field.label}` : BREADCRUMB;\n return {\n title: TITLE,\n accent: DOOM_OVERLAY_ACCENT,\n breadcrumb,\n headerRight: `${this.sections.length} sections · ${this.sections.length === 0 ? 'none' : (section?.source ?? '')}`,\n footer: this.hintLine(),\n };\n }\n\n /**\n * The one line the panel says in its own voice, kept at the bottom where it\n * does not push a section's fields around. Dropped entirely when the body is\n * too short to spare the rows: a field the user came here to change outranks\n * a pointer to the docs.\n */\n private helpBanner(width: number): string[] {\n const badge = this.theme.inverse(this.theme.bold(this.theme.fg('accent', HELP_BADGE)));\n return ['', fitRow(`${badge} ${this.theme.fg('dim', HELP_HINT)}`, width)];\n }\n\n protected renderBody(width: number, height: number): string[] {\n const banner = height >= HELP_BANNER_MIN_ROWS ? this.helpBanner(width) : [];\n const bodyHeight = Math.max(0, height - banner.length);\n this.bodyHeight = bodyHeight;\n const right = this.mode === 'choices' ? this.choiceLines.bind(this) : this.fieldLines.bind(this);\n if (width < MIN_WIDTH) return [...this.renderStacked(width, bodyHeight, right), ...banner];\n\n const leftWidth = Math.max(MIN_PANE_WIDTH, Math.floor((width - 1) * SECTION_PANE_RATIO));\n const rightWidth = Math.max(1, width - leftWidth - 1);\n const leftContent = Math.max(1, leftWidth - PANE_GUTTER);\n const rightContent = Math.max(1, rightWidth - PANE_GUTTER);\n const left = this.sectionLines(leftContent);\n const rightLines = right(rightContent);\n\n const divider = this.theme.fg('borderMuted', '│');\n const rows = Array.from({ length: bodyHeight }, (_, index) => {\n const row = `${fitRow(left[index] ?? '', leftContent)} ${divider} ${fitRow(rightLines[index] ?? '', rightContent)}`;\n return truncateToWidth(row, width, ELLIPSIS);\n });\n return [...rows, ...banner];\n }\n\n private renderStacked(width: number, height: number, right: (width: number) => string[]): string[] {\n const topHeight = Math.max(1, Math.floor((height - 1) / 2));\n const bottomHeight = Math.max(0, height - topHeight - 1);\n this.bodyHeight = topHeight;\n const top = this.sectionLines(width);\n const bottom = right(width);\n return [\n ...top.slice(0, topHeight),\n ...Array.from({ length: Math.max(0, topHeight - top.length) }, () => ''),\n this.theme.fg('borderMuted', '─'.repeat(width)),\n ...bottom.slice(0, bottomHeight),\n ];\n }\n}\n\nexport interface DoomConfigStoreView {\n getSections(): DoomConfigSectionView[];\n invoke(invocation: { source: string; sectionId: string; fieldId: string; action: string; value?: string }): void;\n subscribe(listener: () => void): () => void;\n}\n\nexport async function openConfigOverlay(ctx: ExtensionContext, registry: DoomConfigStoreView): Promise<void> {\n await ctx.ui.custom<undefined>(\n (tui, theme, _keybindings, done) => new ConfigOverlayComponent(tui, theme, registry, done),\n DOOM_FULLSCREEN_UI_OPTIONS,\n );\n}\n"],"mappings":"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"}
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"configOverlay-CCbWicvH.mjs","names":[],"sources":["../src/tui/configOverlay.ts"],"sourcesContent":["/**\n * Configuration panel: the `SPC e c` overlay.\n *\n * Sections on the left, one per contributing extension, and that section's\n * fields on the right. The panel owns navigation and text entry; every value it\n * shows was published by an extension, and every change it makes is a request\n * back to whichever extension owns the field. Nothing here knows what a voice\n * model or an editor command is.\n *\n * It subscribes to the registry rather than snapshotting at open time, unlike\n * the tools browser next door, because a contributor can be doing long work\n * (fetching a model, running an installer) and the panel is where that progress\n * is meant to appear.\n *\n * There is no local echo of an edit. A typed value is sent and the field stays\n * pending until its owner republishes, so a rejected value comes back with the\n * reason attached instead of the panel showing a value that was never written.\n */\n\nimport type { ConfigChoice, ConfigField } from '@agimon-ai/doompi-core/config';\nimport type { DoomConfigSectionView } from '@agimon-ai/doompi-core/config';\nimport type { ExtensionContext, Theme } from '@earendil-works/pi-coding-agent';\nimport { matchesKey, truncateToWidth, visibleWidth } from '@earendil-works/pi-tui';\n\nimport {\n DOOM_FULLSCREEN_UI_OPTIONS,\n DOOM_OVERLAY_ACCENT,\n DoomOverlay,\n type DoomOverlayChrome,\n type DoomOverlayTui,\n} from './doomOverlay';\nimport { fitStyledLine } from './rendering';\n\ntype Pane = 'sections' | 'fields';\ntype Mode = 'browse' | 'edit' | 'choices';\n\nconst TITLE = 'CONFIG';\nconst BREADCRUMB = 'SPC › e / c · config';\nconst ACTION_SET = 'set';\nconst ACTION_CLEAR = 'clear';\nconst ACTION_ABORT = 'abort';\nconst DEFAULT_CHOICE_ACTION = 'select';\n\nconst KEY_BACKSPACE = '\\x7f';\nconst KEY_ENTER = '\\r';\nconst KEY_NEWLINE = '\\n';\nconst KEY_TAB = '\\t';\nconst FIRST_PRINTABLE_CODE_POINT = 0x20;\nconst DELETE_CODE_POINT = 0x7f;\n\nconst MIN_WIDTH = 48;\nconst SECTION_PANE_RATIO = 1 / 3;\nconst PANE_GUTTER = 1;\nconst MIN_PANE_WIDTH = 18;\nconst ELLIPSIS = '…';\nconst LABEL_COLUMN = 18;\nconst INDENT = ' ';\nconst EMPTY_MESSAGE = 'No extension has contributed settings to this session.';\nconst NO_FIELDS_MESSAGE = 'This section has no fields.';\nconst UNSET_PLACEHOLDER = 'not set';\nconst SECTION_HEADING = 'SECTIONS';\nconst HELP_BADGE = ' HELP ';\n/**\n * Every field here is published by a package, so the panel cannot explain what\n * any one of them means. Help mode can: it loads the owning package's docs into\n * the session, and the agent reads them and answers from there.\n */\nconst HELP_HINT = 'Not sure what a setting does? SPC h e loads package Help, then ask the agent about it.';\n/** Body rows below which the banner is dropped: a field outranks a pointer to the docs. */\nconst HELP_BANNER_MIN_ROWS = 10;\nconst PROGRESS_WIDTH = 24;\nconst ACTION_INPUT = 'input';\ntype ThemeColor = Parameters<Theme['fg']>[0];\nconst STEP_MARKERS: Readonly<Record<string, readonly [string, ThemeColor]>> = {\n pending: ['·', 'dim'],\n satisfied: ['✓', 'dim'],\n running: ['▸', 'accent'],\n done: ['✓', 'success'],\n failed: ['✗', 'error'],\n};\nconst PROGRESS_FULL = '█';\nconst PROGRESS_EMPTY = '░';\n\n/**\n * Keystrokes that carry no text: escape sequences, control keys, delete.\n * Indexed rather than iterated so surrogate pairs stay intact; both halves sit\n * far above the control range, so no emoji is ever mistaken for one.\n */\nfunction isControlInput(data: string): boolean {\n for (let index = 0; index < data.length; index++) {\n const code = data.charCodeAt(index);\n if (code < FIRST_PRINTABLE_CODE_POINT || code === DELETE_CODE_POINT) return true;\n }\n return false;\n}\n\nfunction fitRow(text: string, width: number): string {\n return fitStyledLine(text, width, ELLIPSIS);\n}\n\nfunction rightAligned(left: string, right: string, width: number): string {\n const rightWidth = visibleWidth(right);\n const leftWidth = Math.max(0, width - rightWidth - 1);\n return fitRow(left, leftWidth) + ' '.repeat(Math.max(1, width - leftWidth - rightWidth)) + fitRow(right, rightWidth);\n}\n\nfunction wrap(text: string, width: number): string[] {\n if (width <= 0) return [];\n const lines: string[] = [];\n let current = '';\n for (const word of text.split(/\\s+/).filter(Boolean)) {\n if (current.length === 0) current = word;\n else if (current.length + 1 + word.length <= width) current += ` ${word}`;\n else {\n lines.push(current);\n current = word;\n }\n }\n if (current.length > 0) lines.push(current);\n return lines;\n}\n\nfunction isSelectable(field: ConfigField): boolean {\n return field.kind !== 'info';\n}\n\nexport class ConfigOverlayComponent extends DoomOverlay {\n private readonly registry: DoomConfigStoreView;\n private readonly done: (result: undefined) => void;\n private readonly unsubscribe: () => void;\n private sections: readonly DoomConfigSectionView[];\n private pane: Pane = 'sections';\n private mode: Mode = 'browse';\n private sectionIndex = 0;\n private fieldIndex = 0;\n private choiceIndex = 0;\n private draft = '';\n /** Fields awaiting a reply, keyed by source, section, and field. */\n private readonly pending = new Set<string>();\n private bodyHeight = 1;\n\n constructor(tui: DoomOverlayTui, theme: Theme, registry: DoomConfigStoreView, done: (result: undefined) => void) {\n super(tui, theme);\n this.registry = registry;\n this.done = done;\n this.sections = registry.getSections();\n this.fieldIndex = this.firstSelectableField();\n this.unsubscribe = registry.subscribe(() => this.onSectionsChanged());\n }\n\n /** Info fields are labels, so the cursor never starts on one. */\n private firstSelectableField(): number {\n const index = this.currentFields().findIndex(isSelectable);\n return index < 0 ? 0 : index;\n }\n\n dispose(): void {\n this.unsubscribe();\n }\n\n private onSectionsChanged(): void {\n this.sections = this.registry.getSections();\n // Any republish from an owner is its answer, so nothing stays pending past it.\n this.pending.clear();\n this.sectionIndex = Math.min(this.sectionIndex, Math.max(0, this.sections.length - 1));\n const fields = this.currentFields();\n this.fieldIndex = Math.min(this.fieldIndex, Math.max(0, fields.length - 1));\n if (!isSelectable(fields[this.fieldIndex] ?? { kind: 'info' })) this.fieldIndex = this.firstSelectableField();\n const field = this.currentField();\n // A field that grew an error keeps the draft so the typed value is not lost,\n // and an answer being typed survives the republish each output chunk causes.\n if (this.mode === 'edit' && !field?.statusText && !field?.awaitingInput) this.mode = 'browse';\n this.tui.requestRender();\n }\n\n private currentSection(): DoomConfigSectionView | undefined {\n return this.sections[this.sectionIndex];\n }\n\n private currentFields(): readonly ConfigField[] {\n return this.currentSection()?.fields ?? [];\n }\n\n private currentField(): ConfigField | undefined {\n return this.currentFields()[this.fieldIndex];\n }\n\n private currentChoices(): readonly ConfigChoice[] {\n return this.currentField()?.choices ?? [];\n }\n\n private pendingKey(field: ConfigField): string {\n return `${this.currentSection()?.source ?? ''}\u0000${this.currentSection()?.id ?? ''}\u0000${field.id}`;\n }\n\n private invoke(action: string, value?: string): void {\n const section = this.currentSection();\n const field = this.currentField();\n if (!section || !field) return;\n this.pending.add(this.pendingKey(field));\n this.registry.invoke({\n source: section.source,\n sectionId: section.id,\n fieldId: field.id,\n action,\n ...(value === undefined ? {} : { value }),\n });\n this.tui.requestRender();\n }\n\n private moveSection(delta: number): void {\n if (this.sections.length === 0) return;\n const next = Math.max(0, Math.min(this.sectionIndex + delta, this.sections.length - 1));\n if (next === this.sectionIndex) return;\n this.sectionIndex = next;\n this.fieldIndex = this.firstSelectableField();\n this.tui.requestRender();\n }\n\n /** Info fields are labels, so the cursor steps over them to the next control. */\n private moveField(delta: number): void {\n const fields = this.currentFields();\n const step = delta < 0 ? -1 : 1;\n let next = this.fieldIndex + step;\n while (next >= 0 && next < fields.length && !isSelectable(fields[next] as ConfigField)) next += step;\n if (next < 0 || next >= fields.length) return;\n this.fieldIndex = next;\n this.tui.requestRender();\n }\n\n private moveChoice(delta: number): void {\n const choices = this.currentChoices();\n if (choices.length === 0) return;\n const next = Math.max(0, Math.min(this.choiceIndex + delta, choices.length - 1));\n if (next === this.choiceIndex) return;\n this.choiceIndex = next;\n this.tui.requestRender();\n }\n\n handleInput(data: string): void {\n if (this.mode === 'edit') {\n this.handleEditInput(data);\n return;\n }\n if (this.mode === 'choices') {\n this.handleChoiceInput(data);\n return;\n }\n this.handleBrowseInput(data);\n }\n\n private handleBrowseInput(data: string): void {\n const field = this.currentField();\n if (matchesKey(data, 'ctrl+c')) {\n if (field?.busy) this.invoke(ACTION_ABORT);\n else this.done(undefined);\n return;\n }\n if (matchesKey(data, 'escape') || data === 'q') {\n // Escape backs out of the fields pane before it closes the panel.\n if (this.pane === 'fields') {\n this.pane = 'sections';\n this.tui.requestRender();\n return;\n }\n this.done(undefined);\n return;\n }\n if (data === KEY_TAB) {\n this.pane = this.pane === 'sections' ? 'fields' : 'sections';\n this.tui.requestRender();\n return;\n }\n if (matchesKey(data, 'up') || data === 'k') {\n if (this.pane === 'sections') this.moveSection(-1);\n else this.moveField(-1);\n return;\n }\n if (matchesKey(data, 'down') || data === 'j') {\n if (this.pane === 'sections') this.moveSection(1);\n else this.moveField(1);\n return;\n }\n // While a field offers its own keys, those win: a pending confirmation is\n // answered before anything else can be typed.\n const offered = field?.actions?.find((action) => action.key === data);\n if (this.pane === 'fields' && offered) {\n this.invoke(offered.action);\n return;\n }\n // Answering a waiting command beats every other reading of `i`, and it is\n // the only thing that will make progress while one is blocked on a prompt.\n if (this.pane === 'fields' && field?.awaitingInput && data === 'i') {\n this.draft = '';\n this.mode = 'edit';\n this.tui.requestRender();\n return;\n }\n if (matchesKey(data, 'enter') || data === KEY_ENTER || data === KEY_NEWLINE) {\n this.activate();\n return;\n }\n if (this.pane === 'fields' && data === 'd' && field && isSelectable(field)) this.invoke(ACTION_CLEAR);\n }\n\n private activate(): void {\n if (this.pane === 'sections') {\n this.pane = 'fields';\n this.tui.requestRender();\n return;\n }\n const field = this.currentField();\n if (!field || field.busy || !isSelectable(field)) return;\n // `enum` and `choice` differ only in how many entries they carry, so both\n // open the same list with the cursor on whatever is currently set.\n if (field.kind === 'choice' || field.kind === 'enum') {\n this.choiceIndex = Math.max(\n 0,\n this.currentChoices().findIndex((choice) => choice.id === field.value),\n );\n this.mode = 'choices';\n this.tui.requestRender();\n return;\n }\n this.draft = field.value ?? '';\n this.mode = 'edit';\n this.tui.requestRender();\n }\n\n private handleEditInput(data: string): void {\n if (matchesKey(data, 'escape')) {\n this.mode = 'browse';\n this.draft = '';\n this.tui.requestRender();\n return;\n }\n if (data === KEY_ENTER || data === KEY_NEWLINE) {\n const value = this.draft.trim();\n // Answering a prompt is a different write from setting a field, and an\n // empty answer is meaningful there: it accepts the command's default.\n if (this.currentField()?.awaitingInput) {\n this.mode = 'browse';\n this.invoke(ACTION_INPUT, value.length === 0 ? undefined : value);\n this.draft = '';\n return;\n }\n // The parser rejects blank values, so clearing a key means removing it.\n this.invoke(value.length === 0 ? ACTION_CLEAR : ACTION_SET, value.length === 0 ? undefined : value);\n return;\n }\n if (data === KEY_BACKSPACE) this.draft = this.draft.slice(0, -1);\n else if (!isControlInput(data)) this.draft += data;\n this.tui.requestRender();\n }\n\n private handleChoiceInput(data: string): void {\n if (matchesKey(data, 'escape')) {\n this.mode = 'browse';\n this.tui.requestRender();\n return;\n }\n if (matchesKey(data, 'up') || data === 'k') {\n this.moveChoice(-1);\n return;\n }\n if (matchesKey(data, 'down') || data === 'j') {\n this.moveChoice(1);\n return;\n }\n if (matchesKey(data, 'enter') || data === KEY_ENTER || data === KEY_NEWLINE) {\n const choice = this.currentChoices()[this.choiceIndex];\n if (!choice) return;\n this.mode = 'browse';\n // The entry names what enter does to it, which is what lets one list hold\n // both an installed thing to select and an absent one to fetch.\n this.invoke(choice.action ?? DEFAULT_CHOICE_ACTION, choice.id);\n }\n }\n\n private sectionLines(width: number): string[] {\n const lines = [this.theme.bold(SECTION_HEADING), ''];\n if (this.sections.length === 0) {\n lines.push(...wrap(EMPTY_MESSAGE, width).map((line) => this.theme.fg('dim', line)));\n return lines;\n }\n for (const [index, section] of this.sections.entries()) {\n const active = index === this.sectionIndex;\n const title = rightAligned(\n active ? this.theme.bold(section.title) : this.theme.fg('text', section.title),\n this.theme.fg(section.noticeLevel === 'error' ? 'error' : 'dim', section.detail ?? ''),\n width,\n );\n lines.push(active && this.pane === 'sections' ? this.theme.bg('selectedBg', fitRow(title, width)) : title);\n lines.push(this.theme.fg('dim', fitRow(`${INDENT}${section.source}`, width)));\n }\n return lines;\n }\n\n /**\n * The whole plan, not just the running step.\n *\n * Seeing that a package manager already finished and a download is now\n * underway is what makes a long install legible; a lone \"step 3 of 6\" is not.\n */\n private stepLines(field: ConfigField, width: number): string[] {\n const inner = Math.max(1, width - INDENT.length);\n return (field.steps ?? []).map((step) => {\n const [glyph, color] = STEP_MARKERS[step.state];\n const label = step.state === 'pending' ? this.theme.fg('dim', step.label) : step.label;\n const row = rightAligned(\n `${this.theme.fg(color, glyph)} ${label}`,\n this.theme.fg('dim', step.detail ?? ''),\n inner,\n );\n return `${INDENT}${row}`;\n });\n }\n\n /** The tail of the running command, so a prompt it printed is visible. */\n private outputLines(field: ConfigField, width: number): string[] {\n const inner = Math.max(1, width - INDENT.length);\n return (field.output ?? []).map((line) => `${INDENT}${this.theme.fg('dim', fitRow(line, inner))}`);\n }\n\n private progressBar(ratio: number | undefined, width: number): string {\n if (ratio === undefined) return '';\n const filled = Math.max(0, Math.min(PROGRESS_WIDTH, Math.round(ratio * PROGRESS_WIDTH)));\n const bar = PROGRESS_FULL.repeat(filled) + PROGRESS_EMPTY.repeat(PROGRESS_WIDTH - filled);\n return fitRow(`${bar} ${Math.round(ratio * 100)}%`, width);\n }\n\n private fieldLines(width: number): string[] {\n const section = this.currentSection();\n if (!section) return [this.theme.fg('dim', EMPTY_MESSAGE)];\n const lines = [this.theme.bold(section.title), ''];\n if (section.notice) {\n lines.push(\n ...wrap(section.notice, width).map((line) =>\n this.theme.fg(section.noticeLevel === 'error' ? 'error' : 'dim', line),\n ),\n );\n lines.push('');\n }\n if (section.fields.length === 0) {\n lines.push(this.theme.fg('dim', NO_FIELDS_MESSAGE));\n return lines;\n }\n\n const valueWidth = Math.max(1, width - LABEL_COLUMN);\n for (const [index, field] of section.fields.entries()) {\n const active = index === this.fieldIndex && this.pane === 'fields';\n const editing = active && this.mode === 'edit';\n const isPending = this.pending.has(this.pendingKey(field));\n const shown = editing ? `${this.draft}█` : (field.value ?? field.placeholder ?? UNSET_PLACEHOLDER);\n const tone = editing || field.value ? 'text' : 'dim';\n const value = this.theme.fg(isPending || field.busy ? 'dim' : tone, shown);\n const status = field.statusText ?? (isPending ? '' : '');\n const row = `${this.theme.fg('dim', fitRow(field.label, LABEL_COLUMN))}${\n status\n ? rightAligned(value, this.theme.fg(field.status === 'blocked' ? 'error' : 'dim', status), valueWidth)\n : fitRow(value, valueWidth)\n }`;\n lines.push(active ? this.theme.bg('selectedBg', fitRow(row, width)) : row);\n lines.push(...this.stepLines(field, width));\n if (field.busy && field.progress) {\n lines.push(this.theme.fg('dim', fitRow(`${INDENT}${field.progress.label}`, width)));\n const bar = this.progressBar(field.progress.ratio, valueWidth);\n if (bar) lines.push(`${INDENT}${this.theme.fg('accent', bar)}`);\n }\n lines.push(...this.outputLines(field, width));\n if (active && field.awaitingInput) {\n // The command is asking something. Answering is the only useful action,\n // so the line is offered without having to enter a mode first.\n const prompt = this.mode === 'edit' ? `${this.draft}█` : 'press i to answer';\n lines.push(\n `${INDENT}${this.theme.fg('warning', fitRow(`waiting for input ${prompt}`, width - INDENT.length))}`,\n );\n }\n if (!active) continue;\n if (field.detail) {\n lines.push(\n ...wrap(field.detail, Math.max(1, width - LABEL_COLUMN)).map(\n (line) => `${' '.repeat(LABEL_COLUMN)}${this.theme.fg('dim', line)}`,\n ),\n );\n }\n if (field.keyPath) lines.push(`${' '.repeat(LABEL_COLUMN)}${this.theme.fg('accent', field.keyPath)}`);\n if (field.actions && field.actions.length > 0) lines.push(`${' '.repeat(LABEL_COLUMN)}${this.hintLine()}`);\n }\n return lines;\n }\n\n private choiceLines(width: number): string[] {\n const field = this.currentField();\n const choices = this.currentChoices();\n const lines = [this.theme.bold(field?.label ?? ''), ''];\n if (choices.length === 0) {\n lines.push(this.theme.fg('dim', NO_FIELDS_MESSAGE));\n return lines;\n }\n const budget = Math.max(1, this.bodyHeight - lines.length);\n const selected = Math.max(0, Math.min(this.choiceIndex, choices.length - 1));\n const start = Math.max(0, Math.min(selected - budget + 1, Math.max(0, choices.length - budget)));\n let lastGroup: string | undefined;\n for (const [offset, choice] of choices.slice(start, start + budget).entries()) {\n if (choice.group && choice.group !== lastGroup) {\n lastGroup = choice.group;\n lines.push(this.theme.fg('accent', fitRow(choice.group, width)));\n }\n const status = choice.statusText ?? choice.status ?? '';\n const row = rightAligned(\n `${INDENT}${choice.label}${choice.detail ? this.theme.fg('dim', ` ${choice.detail}`) : ''}`,\n this.theme.fg(choice.status === 'blocked' ? 'error' : 'dim', status),\n width,\n );\n lines.push(start + offset === selected ? this.theme.bg('selectedBg', fitRow(row, width)) : row);\n }\n return lines;\n }\n\n private hints(): readonly (readonly [string, string])[] {\n if (this.mode === 'edit') {\n return [\n ['⌫', 'delete'],\n ['enter', this.currentField()?.awaitingInput ? 'send' : 'save'],\n ['esc', 'cancel'],\n ];\n }\n if (this.mode === 'choices') {\n const choice = this.currentChoices()[this.choiceIndex];\n // The hint names what enter does to the entry under the cursor, because on\n // this list that differs row by row.\n return [\n ['↑↓', 'move'],\n ['enter', choice?.action ?? DEFAULT_CHOICE_ACTION],\n ['esc', 'back'],\n ];\n }\n const field = this.currentField();\n if (field?.awaitingInput) {\n return [\n ['i', 'answer'],\n ['ctrl+c', 'abort'],\n ['esc', 'close, keeps running'],\n ];\n }\n if (field?.busy) {\n return [\n ['ctrl+c', 'abort'],\n ['esc', 'close, keeps running'],\n ];\n }\n const offered = (field?.actions ?? []).map((action) => [action.key, action.label] as const);\n return [\n ['↑↓', 'move'],\n ['tab', 'pane'],\n ['enter', this.pane === 'sections' ? 'fields' : 'edit'],\n ...offered,\n ...(this.pane === 'fields' && offered.length === 0 ? ([['d', 'clear']] as const) : []),\n ['esc', this.pane === 'fields' ? 'back' : 'close'],\n ];\n }\n\n private hintLine(): string {\n return this.hints()\n .map(\n ([key, label]) =>\n `${this.theme.bg('selectedBg', this.theme.fg('text', ` ${key} `))}${this.theme.fg('dim', ` ${label}`)}`,\n )\n .join(this.theme.fg('dim', ' '));\n }\n\n protected getChrome(): DoomOverlayChrome {\n const section = this.currentSection();\n const field = this.currentField();\n const breadcrumb =\n this.mode === 'choices' && section && field ? `${BREADCRUMB} › ${section.title} / ${field.label}` : BREADCRUMB;\n return {\n title: TITLE,\n accent: DOOM_OVERLAY_ACCENT,\n breadcrumb,\n headerRight: `${this.sections.length} sections · ${this.sections.length === 0 ? 'none' : (section?.source ?? '')}`,\n footer: this.hintLine(),\n };\n }\n\n /**\n * The one line the panel says in its own voice, kept at the bottom where it\n * does not push a section's fields around. Dropped entirely when the body is\n * too short to spare the rows: a field the user came here to change outranks\n * a pointer to the docs.\n */\n private helpBanner(width: number): string[] {\n const badge = this.theme.inverse(this.theme.bold(this.theme.fg('accent', HELP_BADGE)));\n return ['', fitRow(`${badge} ${this.theme.fg('dim', HELP_HINT)}`, width)];\n }\n\n protected renderBody(width: number, height: number): string[] {\n const banner = height >= HELP_BANNER_MIN_ROWS ? this.helpBanner(width) : [];\n const bodyHeight = Math.max(0, height - banner.length);\n this.bodyHeight = bodyHeight;\n const right = this.mode === 'choices' ? this.choiceLines.bind(this) : this.fieldLines.bind(this);\n if (width < MIN_WIDTH) return [...this.renderStacked(width, bodyHeight, right), ...banner];\n\n const leftWidth = Math.max(MIN_PANE_WIDTH, Math.floor((width - 1) * SECTION_PANE_RATIO));\n const rightWidth = Math.max(1, width - leftWidth - 1);\n const leftContent = Math.max(1, leftWidth - PANE_GUTTER);\n const rightContent = Math.max(1, rightWidth - PANE_GUTTER);\n const left = this.sectionLines(leftContent);\n const rightLines = right(rightContent);\n\n const divider = this.theme.fg('borderMuted', '│');\n const rows = Array.from({ length: bodyHeight }, (_, index) => {\n const row = `${fitRow(left[index] ?? '', leftContent)} ${divider} ${fitRow(rightLines[index] ?? '', rightContent)}`;\n return truncateToWidth(row, width, ELLIPSIS);\n });\n return [...rows, ...banner];\n }\n\n private renderStacked(width: number, height: number, right: (width: number) => string[]): string[] {\n const topHeight = Math.max(1, Math.floor((height - 1) / 2));\n const bottomHeight = Math.max(0, height - topHeight - 1);\n this.bodyHeight = topHeight;\n const top = this.sectionLines(width);\n const bottom = right(width);\n return [\n ...top.slice(0, topHeight),\n ...Array.from({ length: Math.max(0, topHeight - top.length) }, () => ''),\n this.theme.fg('borderMuted', '─'.repeat(width)),\n ...bottom.slice(0, bottomHeight),\n ];\n }\n}\n\nexport interface DoomConfigStoreView {\n getSections(): DoomConfigSectionView[];\n invoke(invocation: { source: string; sectionId: string; fieldId: string; action: string; value?: string }): void;\n subscribe(listener: () => void): () => void;\n}\n\nexport async function openConfigOverlay(ctx: ExtensionContext, registry: DoomConfigStoreView): Promise<void> {\n await ctx.ui.custom<undefined>(\n (tui, theme, _keybindings, done) => new ConfigOverlayComponent(tui, theme, registry, done),\n DOOM_FULLSCREEN_UI_OPTIONS,\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_configOverlay = require("./configOverlay-Bov-Zcdz.cjs");
|
|
3
|
+
exports.ConfigOverlayComponent = require_configOverlay.ConfigOverlayComponent;
|
|
4
|
+
exports.openConfigOverlay = require_configOverlay.openConfigOverlay;
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"configOverlay.d.mts","names":[],"sources":["../src/tui/configOverlay.ts"],"mappings":";;;;qBA8Ha,+BAA+B;mBACzB;mBACA;mBACA;UACT;UACA;UACA;UACA;UACA;UACA;UACA;;mBAES;UACT;EAER,YAAY,KAAK,gBAAgB,OAAO,OAAO,UAAU,qBAAqB,OAAO;;UAU7E;EAKR;UAIQ;UAeA;UAIA;UAIA;UAIA;UAIA;UAIA;UAeA;;UAUA;UAUA;EASR,YAAY;UAYJ;UAsDA;UAwBA;UA0BA;UAwBA;;;;;;;UAyBA;;UAeA;UAKA;UAOA;UA6DA;UA4BA;UA2CA;YASE,aAAa;;;;;;;UAoBf;YAKE,WAAW,eAAe;UAsB5B;;UAeO;EACf,eAAe;EACf,OAAO;IAAc;IAAgB;IAAmB;IAAiB;IAAgB;;EACzF,UAAU;;wBAGU,kBAAkB,KAAK,kBAAkB,UAAU,sBAAsB"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { r as fitStyledLine } from "./rendering-AfmSPYnd.mjs";
|
|
2
|
+
import { highlightCode } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
//#region src/tui/codeGutter.ts
|
|
4
|
+
/** Doom Emacs recesses `line-number` and brightens `line-number-current-line`. */
|
|
5
|
+
const CONTEXT_LINE_NUMBER_COLOR = "dim";
|
|
6
|
+
const CHANGED_LINE_NUMBER_COLOR = "muted";
|
|
7
|
+
/** Right-align every number in a block so the code column never goes ragged. */
|
|
8
|
+
function gutterWidth(highestLineNumber) {
|
|
9
|
+
return String(Math.max(1, highestLineNumber)).length;
|
|
10
|
+
}
|
|
11
|
+
/** Recessive right-aligned line number; blank numbers keep the column reserved. */
|
|
12
|
+
function renderLineNumber(value, width, theme, changed = false) {
|
|
13
|
+
const color = changed ? CHANGED_LINE_NUMBER_COLOR : CONTEXT_LINE_NUMBER_COLOR;
|
|
14
|
+
return theme.fg(color, String(value).padStart(width, " "));
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
//#region src/tui/diffRender.ts
|
|
18
|
+
/** Pi emits `+12 text`, `-12 text`, ` 12 text`, and a blank-numbered ` ... ` elision between hunks. */
|
|
19
|
+
const DIFF_ROW_PATTERN = /^([+\- ])( *\d*) (.*)$/u;
|
|
20
|
+
const TAB_REPLACEMENT = " ";
|
|
21
|
+
const CONTEXT_MARKER = " ";
|
|
22
|
+
/**
|
|
23
|
+
* Doom Emacs carries a diff on the background and leaves the foreground to
|
|
24
|
+
* syntax highlighting, the way Magit's `magit-diff-added`/`-removed` faces do.
|
|
25
|
+
* The theme's success and error backgrounds are its green- and red-tinted
|
|
26
|
+
* washes, so any theme yields a readable added/removed pair.
|
|
27
|
+
*/
|
|
28
|
+
const ROW_BACKGROUND = {
|
|
29
|
+
"+": "toolSuccessBg",
|
|
30
|
+
"-": "toolErrorBg"
|
|
31
|
+
};
|
|
32
|
+
const MARKER_COLOR = {
|
|
33
|
+
"+": "toolDiffAdded",
|
|
34
|
+
"-": "toolDiffRemoved"
|
|
35
|
+
};
|
|
36
|
+
function isChangedMarker(marker) {
|
|
37
|
+
return marker !== CONTEXT_MARKER;
|
|
38
|
+
}
|
|
39
|
+
function toDiffMarker(value) {
|
|
40
|
+
return value === "+" || value === "-" ? value : CONTEXT_MARKER;
|
|
41
|
+
}
|
|
42
|
+
function parseDiffRows(diff) {
|
|
43
|
+
return diff.split("\n").map((line) => {
|
|
44
|
+
const expanded = line.replaceAll(" ", TAB_REPLACEMENT);
|
|
45
|
+
const match = DIFF_ROW_PATTERN.exec(expanded);
|
|
46
|
+
if (!match) return {
|
|
47
|
+
marker: CONTEXT_MARKER,
|
|
48
|
+
lineNumber: "",
|
|
49
|
+
content: expanded
|
|
50
|
+
};
|
|
51
|
+
return {
|
|
52
|
+
marker: toDiffMarker(match[1]),
|
|
53
|
+
lineNumber: match[2].trim(),
|
|
54
|
+
content: match[3]
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Highlight the diff as one block so multi-line constructs keep their context.
|
|
60
|
+
* Interleaved removals make the block imperfect source, which the highlighter
|
|
61
|
+
* tolerates; a line count mismatch falls back to flat diff coloring.
|
|
62
|
+
*/
|
|
63
|
+
function decorateRows(rows, language, theme, highlight) {
|
|
64
|
+
if (language !== void 0) {
|
|
65
|
+
const highlighted = highlight(rows.map((row) => row.content).join("\n"), language);
|
|
66
|
+
if (highlighted.length === rows.length) return highlighted;
|
|
67
|
+
}
|
|
68
|
+
return rows.map((row) => theme.fg(isChangedMarker(row.marker) ? "toolOutput" : "toolDiffContext", row.content));
|
|
69
|
+
}
|
|
70
|
+
/** A width-aware diff whose added and removed rows carry a full-width color band. */
|
|
71
|
+
var DoomDiff = class {
|
|
72
|
+
rows;
|
|
73
|
+
contents;
|
|
74
|
+
theme;
|
|
75
|
+
gutter;
|
|
76
|
+
constructor(rows, contents, theme) {
|
|
77
|
+
this.rows = rows;
|
|
78
|
+
this.contents = contents;
|
|
79
|
+
this.theme = theme;
|
|
80
|
+
this.gutter = rows.reduce((widest, row) => Math.max(widest, row.lineNumber.length), 1);
|
|
81
|
+
}
|
|
82
|
+
render(width) {
|
|
83
|
+
if (width <= 0) return [];
|
|
84
|
+
return this.rows.map((row, index) => this.renderRow(row, this.contents[index] ?? row.content, width));
|
|
85
|
+
}
|
|
86
|
+
invalidate() {}
|
|
87
|
+
renderRow({ marker, lineNumber }, content, width) {
|
|
88
|
+
const number = renderLineNumber(lineNumber, this.gutter, this.theme, isChangedMarker(marker));
|
|
89
|
+
if (!isChangedMarker(marker)) return fitStyledLine(`${number} ${CONTEXT_MARKER}${content}`, width);
|
|
90
|
+
const band = fitStyledLine(`${number} ${this.theme.fg(MARKER_COLOR[marker], marker)}${content}`, width);
|
|
91
|
+
return this.theme.bg(ROW_BACKGROUND[marker], band);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
/** Render Pi's display diff with Doom's background-banded added and removed rows. */
|
|
95
|
+
function renderDoomDiff(diff, theme, language, highlight = highlightCode) {
|
|
96
|
+
const rows = parseDiffRows(diff);
|
|
97
|
+
return new DoomDiff(rows, decorateRows(rows, language, theme, highlight), theme);
|
|
98
|
+
}
|
|
99
|
+
//#endregion
|
|
100
|
+
export { gutterWidth as n, renderLineNumber as r, renderDoomDiff as t };
|
|
101
|
+
|
|
102
|
+
//# sourceMappingURL=diffRender-D7zqA45E.mjs.map
|