pi-chassis 0.0.0-stage → 0.7.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/CHANGELOG.md +118 -0
- package/LICENSE +21 -0
- package/README.md +51 -2
- package/THIRD_PARTY_NOTICES +30 -0
- package/dist/chassis/alert.d.ts +50 -0
- package/dist/chassis/alert.js +107 -0
- package/dist/chassis/api.d.ts +411 -0
- package/dist/chassis/api.js +676 -0
- package/dist/chassis/bash-output.d.ts +89 -0
- package/dist/chassis/bash-output.js +157 -0
- package/dist/chassis/brand.d.ts +99 -0
- package/dist/chassis/brand.js +79 -0
- package/dist/chassis/client.d.ts +87 -0
- package/dist/chassis/client.js +271 -0
- package/dist/chassis/commands.d.ts +60 -0
- package/dist/chassis/commands.js +211 -0
- package/dist/chassis/editor.d.ts +70 -0
- package/dist/chassis/editor.js +213 -0
- package/dist/chassis/footer.d.ts +14 -0
- package/dist/chassis/footer.js +136 -0
- package/dist/chassis/header.d.ts +12 -0
- package/dist/chassis/header.js +38 -0
- package/dist/chassis/home.d.ts +48 -0
- package/dist/chassis/home.js +184 -0
- package/dist/chassis/icons.d.ts +203 -0
- package/dist/chassis/icons.js +190 -0
- package/dist/chassis/index.d.ts +21 -0
- package/dist/chassis/index.js +582 -0
- package/dist/chassis/layout.d.ts +40 -0
- package/dist/chassis/layout.js +264 -0
- package/dist/chassis/message-modes.d.ts +21 -0
- package/dist/chassis/message-modes.js +49 -0
- package/dist/chassis/messages.d.ts +75 -0
- package/dist/chassis/messages.js +392 -0
- package/dist/chassis/modes.d.ts +21 -0
- package/dist/chassis/modes.js +99 -0
- package/dist/chassis/palette.d.ts +84 -0
- package/dist/chassis/palette.js +235 -0
- package/dist/chassis/peek.d.ts +61 -0
- package/dist/chassis/peek.js +156 -0
- package/dist/chassis/prompt-row.d.ts +42 -0
- package/dist/chassis/prompt-row.js +68 -0
- package/dist/chassis/provider-view.d.ts +34 -0
- package/dist/chassis/provider-view.js +107 -0
- package/dist/chassis/provider.d.ts +69 -0
- package/dist/chassis/provider.js +73 -0
- package/dist/chassis/readonly-command.d.ts +19 -0
- package/dist/chassis/readonly-command.js +454 -0
- package/dist/chassis/sanitize.d.ts +42 -0
- package/dist/chassis/sanitize.js +103 -0
- package/dist/chassis/session-info.d.ts +39 -0
- package/dist/chassis/session-info.js +107 -0
- package/dist/chassis/sidebar.d.ts +48 -0
- package/dist/chassis/sidebar.js +273 -0
- package/dist/chassis/state.d.ts +38 -0
- package/dist/chassis/state.js +19 -0
- package/dist/chassis/telemetry.d.ts +60 -0
- package/dist/chassis/telemetry.js +191 -0
- package/dist/chassis/tools.d.ts +112 -0
- package/dist/chassis/tools.js +588 -0
- package/dist/chassis/version.d.ts +2 -0
- package/dist/chassis/version.js +20 -0
- package/dist/diff/git-diff.d.ts +71 -0
- package/dist/diff/git-diff.js +325 -0
- package/dist/diff/host.d.ts +34 -0
- package/dist/diff/host.js +50 -0
- package/dist/diff/index.d.ts +13 -0
- package/dist/diff/index.js +86 -0
- package/dist/diff/render.d.ts +67 -0
- package/dist/diff/render.js +196 -0
- package/dist/diff/types.d.ts +60 -0
- package/dist/diff/types.js +4 -0
- package/dist/diff/view.d.ts +118 -0
- package/dist/diff/view.js +528 -0
- package/dist/git/flows.d.ts +92 -0
- package/dist/git/flows.js +415 -0
- package/dist/git/forge.d.ts +26 -0
- package/dist/git/forge.js +41 -0
- package/dist/git/index.d.ts +20 -0
- package/dist/git/index.js +121 -0
- package/dist/git/repo.d.ts +64 -0
- package/dist/git/repo.js +186 -0
- package/dist/git/run.d.ts +38 -0
- package/dist/git/run.js +127 -0
- package/dist/git/settings.d.ts +8 -0
- package/dist/git/settings.js +38 -0
- package/dist/git/text.d.ts +51 -0
- package/dist/git/text.js +109 -0
- package/dist/widgets/container/detect.d.ts +23 -0
- package/dist/widgets/container/detect.js +67 -0
- package/dist/widgets/container/index.d.ts +9 -0
- package/dist/widgets/container/index.js +26 -0
- package/dist/widgets/mcp/index.d.ts +13 -0
- package/dist/widgets/mcp/index.js +50 -0
- package/dist/widgets/mcp/status.d.ts +50 -0
- package/dist/widgets/mcp/status.js +70 -0
- package/dist/widgets/session-todos/index.d.ts +12 -0
- package/dist/widgets/session-todos/index.js +52 -0
- package/dist/widgets/subagents/index.d.ts +16 -0
- package/dist/widgets/subagents/index.js +173 -0
- package/dist/widgets/subagents/status.d.ts +61 -0
- package/dist/widgets/subagents/status.js +198 -0
- package/dist/widgets/todo/index.d.ts +13 -0
- package/dist/widgets/todo/index.js +65 -0
- package/dist/widgets/todo/parse.d.ts +29 -0
- package/dist/widgets/todo/parse.js +122 -0
- package/docs/branding.md +25 -0
- package/docs/development.md +22 -0
- package/docs/diff-api.md +18 -0
- package/docs/git.md +23 -0
- package/docs/internals.md +13 -0
- package/docs/provider-status.md +23 -0
- package/docs/status-widgets.md +157 -0
- package/docs/tool-rows.md +50 -0
- package/docs/usage.md +62 -0
- package/docs/widgets.md +113 -0
- package/extensions/chassis/alert.ts +127 -0
- package/extensions/chassis/api.ts +967 -0
- package/extensions/chassis/bash-output.ts +186 -0
- package/extensions/chassis/brand.ts +151 -0
- package/extensions/chassis/client.ts +284 -0
- package/extensions/chassis/commands.ts +244 -0
- package/extensions/chassis/editor.ts +253 -0
- package/extensions/chassis/footer.ts +131 -0
- package/extensions/chassis/header.ts +43 -0
- package/extensions/chassis/home.ts +186 -0
- package/extensions/chassis/icons.ts +220 -0
- package/extensions/chassis/index.ts +605 -0
- package/extensions/chassis/layout.ts +298 -0
- package/extensions/chassis/message-modes.ts +48 -0
- package/extensions/chassis/messages.ts +403 -0
- package/extensions/chassis/modes.ts +108 -0
- package/extensions/chassis/palette.ts +258 -0
- package/extensions/chassis/peek.ts +167 -0
- package/extensions/chassis/prompt-row.ts +86 -0
- package/extensions/chassis/provider-view.ts +118 -0
- package/extensions/chassis/provider.ts +115 -0
- package/extensions/chassis/readonly-command.ts +440 -0
- package/extensions/chassis/sanitize.ts +108 -0
- package/extensions/chassis/session-info.ts +127 -0
- package/extensions/chassis/sidebar.ts +285 -0
- package/extensions/chassis/state.ts +50 -0
- package/extensions/chassis/telemetry.ts +222 -0
- package/extensions/chassis/tools.ts +618 -0
- package/extensions/chassis/version.ts +20 -0
- package/extensions/diff/git-diff.ts +365 -0
- package/extensions/diff/host.ts +58 -0
- package/extensions/diff/index.ts +101 -0
- package/extensions/diff/render.ts +217 -0
- package/extensions/diff/types.ts +67 -0
- package/extensions/diff/view.ts +523 -0
- package/extensions/git/flows.ts +485 -0
- package/extensions/git/forge.ts +54 -0
- package/extensions/git/index.ts +117 -0
- package/extensions/git/repo.ts +200 -0
- package/extensions/git/run.ts +143 -0
- package/extensions/git/settings.ts +38 -0
- package/extensions/git/text.ts +133 -0
- package/extensions/widgets/container/detect.ts +81 -0
- package/extensions/widgets/container/index.ts +29 -0
- package/extensions/widgets/mcp/index.ts +53 -0
- package/extensions/widgets/mcp/status.ts +94 -0
- package/extensions/widgets/session-todos/index.ts +55 -0
- package/extensions/widgets/subagents/index.ts +170 -0
- package/extensions/widgets/subagents/status.ts +237 -0
- package/extensions/widgets/todo/index.ts +66 -0
- package/extensions/widgets/todo/parse.ts +119 -0
- package/package.json +91 -4
- package/scripts/link-pi.mjs +76 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to pi-chassis (published under an earlier name up to 0.3.0) are listed here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html); see [Versioning](README.md#versioning) for what counts as a breaking change here.
|
|
4
|
+
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
## [0.7.1] - 2026-10-23
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- README: the install commands no longer pin a version or a tag, and the advice to pin is gone.
|
|
12
|
+
|
|
13
|
+
## [0.7.0] - 2026-10-23
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- **Breaking:** the shared `globalThis` keys are now `Symbol.for("pi-chassis/<name>")`: `registry`, `pending`, `pendingToolRows`, `brand`, `icons`, `providers`, `diff`, `original-root` and `original-render`. The plain message types set is now `globalThis[Symbol.for("pi-chassis/plainMessageTypes")]`. A package that talks to chassis through globals must update the keys.
|
|
18
|
+
- **Breaking:** the session entry types are now `chassis-mode`, `chassis-plan-context` and `chassis-git`. Sessions written with the old names no longer restore their mode or their git reports.
|
|
19
|
+
|
|
20
|
+
### Removed
|
|
21
|
+
|
|
22
|
+
- **Breaking:** the fallbacks for the old environment variables, the migration of the old settings file, the old command aliases and the compatibility package for the old name.
|
|
23
|
+
|
|
24
|
+
## [0.6.1] - 2026-10-21
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
|
|
28
|
+
- Documentation only: the 0.6.0 changelog entry and `docs/status-widgets.md` no longer name the package the AWS widget moved to. No code change.
|
|
29
|
+
|
|
30
|
+
## [0.6.0] - 2026-10-15
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
|
|
34
|
+
- `docs/status-widgets.md`: recipes for building a status widget from what you already have, an environment variable, a file another tool keeps current, a count with detail lines, a linked line, another extension's `setStatus` line, and a value that needs a command (run from a palette action, never on a timer). Each recipe was type-checked against the real API and run through the sidebar renderer. It also lists the rules that keep a status widget safe.
|
|
35
|
+
|
|
36
|
+
### Removed
|
|
37
|
+
|
|
38
|
+
- **Breaking:** the built-in AWS widget is gone. It moved to a separate package. Anything that relied on it must change:
|
|
39
|
+
- The sidebar and footer no longer show an AWS row unless a package supplies one.
|
|
40
|
+
- The `pi-chassis/aws` export is removed. `registerCredentialProcessResolver`, `resolveAwsContext`, `resolveRegion`, `parseAwsConfig`, `accountFromAccessKeyId`, `roleTone`, `awsExpiresIn`, `formatRemaining`, `formatAwsStatus`, `EXPIRY_SOON_MS`, `SESSION_EXPIRY_VAR` and the types `AwsContext`, `CredentialProcessCall`, `CredentialProcessResult` and `CredentialProcessResolver` have no replacement in pi-chassis. The shared registry key for credential process resolvers is no longer read.
|
|
41
|
+
- `/widgets disable aws` and an `aws` entry in `disabledWidgets` do nothing now. The entry is harmless.
|
|
42
|
+
- The event `aws-status:refresh` and the variable `PI_AWS_SESSION_EXPIRATION` are no longer read by pi-chassis. A package that registers its own `aws` widget keeps using them.
|
|
43
|
+
- The icon table loses `widgetAws` and `widgetAwsFooter`.
|
|
44
|
+
- To get the same row, write one with the recipes in `docs/status-widgets.md`.
|
|
45
|
+
|
|
46
|
+
### Changed
|
|
47
|
+
|
|
48
|
+
- `docs/widgets.md` now says where `onDetailClick` works: only in fullscreen mode with the split sidebar. In regular mode, and in the pop-up sidebar that stands in for the split one, clicks do not reach the widget, so anything the user must reach by clicking needs a second way, such as a palette action.
|
|
49
|
+
|
|
50
|
+
## [0.5.1] - 2026-10-14
|
|
51
|
+
|
|
52
|
+
### Changed
|
|
53
|
+
|
|
54
|
+
- The README is now a short overview with links, and the detail lives in `docs/` (usage, git workflows, widgets, tool rows, the diff view API, branding, provider status, how the sidebar works, development). `docs/` is part of the published package, so the docs match the installed version. The README sections that other packages refer to by name moved: "Adding a widget" and "Adding a widget without depending on pi-chassis" are in `docs/widgets.md`, "Tool rows for your extension's tools" is in `docs/tool-rows.md`.
|
|
55
|
+
|
|
56
|
+
## [0.5.0] - 2026-10-14
|
|
57
|
+
|
|
58
|
+
### Added
|
|
59
|
+
|
|
60
|
+
- Detail lines can hold links. A `detail` line may be a list of pieces, each a string or a `{ text, url }` link (the new `DetailLine` and `DetailLink` types, exported from `pi-chassis/client` and `pi-chassis/api`). chassis builds the link itself, and only from a plain https URL (no user name, whitespace or control characters, at most 2048 characters). It shows the label alone when the terminal cannot show links, when the URL is refused, or when the label is empty once cleaned. Text is still stripped of every escape sequence, so a link written into a string, or one that arrives inside a ticket summary or an incident title, never becomes a link. Until now a widget could not show a link in the sidebar at all, because chassis strips escape sequences from widget text.
|
|
61
|
+
|
|
62
|
+
## [0.4.0] - 2026-10-14
|
|
63
|
+
|
|
64
|
+
### Changed
|
|
65
|
+
|
|
66
|
+
- **Breaking:** the package is now named **pi-chassis**. Install `npm:pi-chassis` and import `pi-chassis/client` (and the other exports). The commands are `/chassis` and `/chassis-resume-last`, the settings file is `~/.pi/agent/chassis.json`, the environment variables are `PI_CHASSIS_ICONS` and `PI_CHASSIS_STATE`, and the brand line reads `chassis X.Y.Z`.
|
|
67
|
+
- **Breaking:** requires pi 1.2 (`>=1.2.0 <1.3.0`). pi 1.1.0 no longer installs cleanly. The sidebar layout, prompt bars and thinking peek were checked against pi 1.2.0. Plan mode's read-only reminder now also reaches runs another extension starts with a custom message, which pi 1.2 passes through `before_agent_start`.
|
|
68
|
+
|
|
69
|
+
## [0.3.0] - 2026-10-08
|
|
70
|
+
|
|
71
|
+
### Added
|
|
72
|
+
|
|
73
|
+
- Tool rows for other extensions' tools: `registerToolRows(specs)` in `pi-chassis/client` (and `registerToolRows` plus `toolRowsVersion` on the shared registry on `globalThis` for a package that does not depend on pi-chassis) has chassis draw a tool's calls as one-line rows with an icon, title, description, outcome and an expanded view. Specs are `ToolRowSpec` (`icon`, `title`, `describe`, `summarize`, `expand`), exported as types from `pi-chassis/client`. Everything a spec returns is sanitized, a spec that throws falls back to the tool's own renderer, registration works in any load order and returns a function that removes it, and chassis's rows for pi's built-in tools cannot be overridden. `registerToolRows(specs, { id })` takes an optional owner id: registering again with the same id replaces that registrant's earlier rows, so a package that registers on every `session_start` or after /reload does not pile up groups. Entries need a string `title` and function `describe` and `summarize` (and `expand`, if given) or they are skipped. A spec that throws while a call's arguments or output are still arriving is retried on the next frame; one that fails on three finished calls is skipped for new calls, which then use the tool's own renderers and shell. This is a new capability, not a change to `apiVersion`: check `toolRowsVersion`.
|
|
74
|
+
- `register(pi, spec, ctx?)` on the registry, and `registerWidget(pi, spec, ctx?)` in `pi-chassis/client`, take an optional `ctx`. A widget registered from inside a `session_start` handler passes the handler's `ctx` so its first `update` and its timer start at once.
|
|
75
|
+
- README: how a package without a dependency on pi-chassis registers a widget (including a sidebar section whose detail lines open the full text on click) and tool rows through `globalThis` alone.
|
|
76
|
+
|
|
77
|
+
### Removed
|
|
78
|
+
|
|
79
|
+
- **Breaking for the old memory extension's users:** chassis no longer draws the `memory_write`, `memory_update`, `memory_forget` and `memory_search` tools with its own rows, and no longer treats the `memory-recall` message type as a plain row. A memory extension now registers its own rows (`registerToolRows`) and its message type (the shared plain message types set); until it does, those tools use pi's default rendering and `memory-recall` notices get chassis's panel and bar. The `toolMemory` icon is removed from `pi-chassis/icons`.
|
|
80
|
+
|
|
81
|
+
## [0.2.1] - 2026-10-08
|
|
82
|
+
|
|
83
|
+
### Changed
|
|
84
|
+
|
|
85
|
+
- pi-chassis describes itself as a workbench for pi (an interface, git workflows and a widget platform) instead of an OpenCode-style TUI, in the README and the npm description. OpenCode is credited as the inspiration for the interface.
|
|
86
|
+
|
|
87
|
+
## [0.2.0] - 2026-10-08
|
|
88
|
+
|
|
89
|
+
### Changed
|
|
90
|
+
|
|
91
|
+
- **Breaking:** the package exports (`pi-chassis/client`, `api`, `brand`, `icons`, `provider`, `aws`) now resolve to compiled JavaScript in `dist/` with type declarations, instead of the `.ts` sources. A package that depends on pi-chassis can now import it from plain `node --test` and type-check it with `tsc`; before, Node refused to strip types from files under `node_modules`. Deep imports of `pi-chassis/extensions/...` paths are not part of the API and may stop working. pi still loads chassis's own extensions from the `.ts` sources, so nothing changes for users of the TUI.
|
|
92
|
+
|
|
93
|
+
## [0.1.1] - 2026-10-08
|
|
94
|
+
|
|
95
|
+
### Security
|
|
96
|
+
|
|
97
|
+
- Releases are published by CI with npm trusted publishing (OIDC) and carry a provenance attestation. No npm token is stored in the repository.
|
|
98
|
+
|
|
99
|
+
## [0.1.0] - 2026-10-08
|
|
100
|
+
|
|
101
|
+
First public release.
|
|
102
|
+
|
|
103
|
+
### Added
|
|
104
|
+
|
|
105
|
+
- OpenCode-style TUI for pi: home screen, right sidebar, one-line footer, prompt row with the mode and model, `ctrl+x` leader keys and a `ctrl+p` command palette.
|
|
106
|
+
- Build and Plan modes. Plan mode turns off edit and write and limits bash to a read-only allow-list (a guardrail, not a sandbox).
|
|
107
|
+
- Tool rows for pi's built-in tools, drawn through `pi.registerToolRenderer`, with live bash output, expandable results, diffs for edit and numbered lines for write.
|
|
108
|
+
- Thinking peek, turn telemetry and a finish alert (terminal bell and window title mark).
|
|
109
|
+
- Git diff view (`/diff`): changes and branch views, hunks, mouse support, and an API for other extensions (`openDiff`, `openChanges`, `addDiffAction`).
|
|
110
|
+
- Git commands: `/commit` (drafts the message from the diff), `/push`, `/merge`, `/pr` (drafts the title and description, opens it with `gh` or `glab`) and `/git`. Each reports its outcome and a fresh repository status to the model on its next turn.
|
|
111
|
+
- Widget API (`pi-chassis/client`) for status rows and sidebar sections, with built-in widgets for containers, AWS, MCP, TODO.md, session todos and subagents.
|
|
112
|
+
- Replaceable brand layer (`pi-chassis/brand`): name, mark, colours, startup art and surface shades.
|
|
113
|
+
- Plain and Nerd Font icon sets (`/chassis icons`).
|
|
114
|
+
- Sanitizing of untrusted text (file contents, tool output, git and forge output, session names, widget text) before it reaches the terminal.
|
|
115
|
+
|
|
116
|
+
[Unreleased]: https://github.com/one24-ai/pi-chassis/compare/v0.7.1...HEAD
|
|
117
|
+
[0.7.1]: https://github.com/one24-ai/pi-chassis/compare/v0.7.0...v0.7.1
|
|
118
|
+
[0.7.0]: https://github.com/one24-ai/pi-chassis/releases/tag/v0.7.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Zach Koncir
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,52 @@
|
|
|
1
|
-
#
|
|
1
|
+
# pi-chassis
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A workbench for [pi](https://pi.dev): a sidebar, a home screen, Build and Plan modes, a git diff view, git commands that draft commit messages and pull requests, and a small API for widgets, tool rows and branding. The brand (name, mark, colours, startup art) is a replaceable layer: see [Branding](docs/branding.md).
|
|
4
|
+
|
|
5
|
+
Requires pi 1.2 and Node.js 22.19 or later.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pi install npm:pi-chassis # from npm, the latest release
|
|
11
|
+
pi install git:github.com/one24-ai/pi-chassis # from git, the main branch
|
|
12
|
+
pi install /path/to/pi-chassis # a local checkout
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
`pi update` moves to the latest release; the [changelog](CHANGELOG.md) says what changed.
|
|
16
|
+
|
|
17
|
+
pi-chassis replaces pi's header, footer and editor, so it does not combine with another package that replaces any of them (pi-open-tui is one): keep only one such package in `packages`.
|
|
18
|
+
|
|
19
|
+
## Documentation
|
|
20
|
+
|
|
21
|
+
Using it:
|
|
22
|
+
|
|
23
|
+
- [Using pi-chassis](docs/usage.md): the features in detail, keys, subagents, icons and themes
|
|
24
|
+
- [Git workflows](docs/git.md): `/commit`, `/push`, `/merge`, `/pr`, `/git` and the diff view
|
|
25
|
+
|
|
26
|
+
Building on it:
|
|
27
|
+
|
|
28
|
+
- [Adding a widget](docs/widgets.md), with or without a dependency on pi-chassis
|
|
29
|
+
- [Status widgets from what you already have](docs/status-widgets.md): recipes for an environment variable, a file, a count, a link and a palette action
|
|
30
|
+
- [Tool rows for your extension's tools](docs/tool-rows.md)
|
|
31
|
+
- [Diff view API](docs/diff-api.md)
|
|
32
|
+
- [Branding](docs/branding.md)
|
|
33
|
+
- [Provider status](docs/provider-status.md)
|
|
34
|
+
|
|
35
|
+
Working on pi-chassis:
|
|
36
|
+
|
|
37
|
+
- [How the sidebar works](docs/internals.md)
|
|
38
|
+
- [Development](docs/development.md) and [RELEASING.md](RELEASING.md)
|
|
39
|
+
|
|
40
|
+
## Versioning
|
|
41
|
+
|
|
42
|
+
pi-chassis follows [Semantic Versioning](https://semver.org). The public API is:
|
|
43
|
+
|
|
44
|
+
- the exports in `package.json` (`pi-chassis/client`, `api`, `brand`, `icons`, `provider`) and the types they export,
|
|
45
|
+
- the slash commands, their arguments and the `ctrl+x` and `ctrl+p` keys,
|
|
46
|
+
- the settings it stores in `~/.pi/agent/chassis.json`.
|
|
47
|
+
|
|
48
|
+
A change that breaks one of those is a major version, a new feature is a minor version, and a fix is a patch. Before 1.0.0, a breaking change bumps the minor version instead (0.1 to 0.2). Each release supports one pi minor version, declared in `peerDependencies`; supporting a new pi minor is a minor release of pi-chassis. Every change is listed in [CHANGELOG.md](CHANGELOG.md); how a release is cut is in [RELEASING.md](RELEASING.md).
|
|
49
|
+
|
|
50
|
+
## Credits
|
|
51
|
+
|
|
52
|
+
The interface is inspired by [OpenCode](https://opencode.ai). The thinking peek and turn telemetry are adapted from [pi-open-tui](https://github.com/OldSuns/pi-open-tui). The plan-mode bash allowlist started from pi's plan-mode example. See `THIRD_PARTY_NOTICES`.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
pi-chassis includes code adapted from the following projects.
|
|
2
|
+
|
|
3
|
+
== pi-open-tui (extensions/chassis/peek.ts, extensions/chassis/telemetry.ts) ==
|
|
4
|
+
https://github.com/OldSuns/pi-open-tui
|
|
5
|
+
|
|
6
|
+
MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 pi-open-tui contributors
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
== pi-coding-agent plan-mode example (extensions/chassis/readonly-command.ts, the first version of the bash allow-list) ==
|
|
29
|
+
https://github.com/earendil-works/pi
|
|
30
|
+
License: MIT
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finish alert: when a long run ends, or a run that has been going for a while stops to ask you
|
|
3
|
+
* something, ring the terminal bell and put a mark in the window title, so you notice from another
|
|
4
|
+
* window or tab.
|
|
5
|
+
*
|
|
6
|
+
* It uses only two terminal standards and no OS commands: BEL (0x07) and the OSC 0 title. What the
|
|
7
|
+
* terminal does with them is its own setting (a taskbar flash, a tab badge, a sound, or nothing).
|
|
8
|
+
* Runs shorter than the threshold stay quiet, and `/chassis alert off` switches it off.
|
|
9
|
+
*
|
|
10
|
+
* The setting lives in the same state file as the disabled widgets (`alert`: `{ enabled, seconds }`).
|
|
11
|
+
*/
|
|
12
|
+
export declare const DEFAULT_ALERT_SECONDS = 30;
|
|
13
|
+
export interface AlertSettings {
|
|
14
|
+
enabled: boolean;
|
|
15
|
+
/** Runs shorter than this stay quiet. */
|
|
16
|
+
seconds: number;
|
|
17
|
+
}
|
|
18
|
+
export declare function defaultAlert(): AlertSettings;
|
|
19
|
+
/** Settings from the state file; anything missing or malformed falls back to the default. */
|
|
20
|
+
export declare function loadAlert(path?: string): AlertSettings;
|
|
21
|
+
/** Save into the state file, keeping its other keys. Best effort, like the widget list. */
|
|
22
|
+
export declare function saveAlert(s: AlertSettings, path?: string): void;
|
|
23
|
+
/** Why the agent stopped. */
|
|
24
|
+
export type AlertReason = "finished" | "failed" | "waiting";
|
|
25
|
+
/**
|
|
26
|
+
* Whether to alert: on, and the run has lasted the threshold. A shorter run is one you are
|
|
27
|
+
* watching. This holds for a finish, a failure and a stop that waits for you alike.
|
|
28
|
+
*/
|
|
29
|
+
export declare function shouldAlert(s: AlertSettings, durationMs: number | undefined): boolean;
|
|
30
|
+
/** The mark put in front of the title. */
|
|
31
|
+
export declare const TITLE_MARK: Record<AlertReason, string>;
|
|
32
|
+
/** Title while alerting: the mark in front of pi's own title. */
|
|
33
|
+
export declare function alertTitle(reason: AlertReason, title: string): string;
|
|
34
|
+
export interface AlertOutput {
|
|
35
|
+
/** Raw write to the terminal. */
|
|
36
|
+
write(data: string): void;
|
|
37
|
+
setTitle(title: string): void;
|
|
38
|
+
}
|
|
39
|
+
/** Ring the bell and mark the title. */
|
|
40
|
+
export declare function alert(out: AlertOutput, reason: AlertReason, title: string): void;
|
|
41
|
+
/**
|
|
42
|
+
* How a run ended, from the last assistant message's stop reason in an agent_end message list. An
|
|
43
|
+
* abort means you pressed esc, so you are there and nothing should ring.
|
|
44
|
+
*/
|
|
45
|
+
export declare function runOutcome(messages: readonly unknown[] | undefined): "finished" | "failed" | "aborted";
|
|
46
|
+
/** The title pi itself sets when there is no session name: "π - <folder>". Used to clear the mark. */
|
|
47
|
+
export declare function plainTitle(cwd: string, sessionName?: string): string;
|
|
48
|
+
/** "off", "on", or a number of seconds ("30", "30s", "2m"); undefined when it is none of these. */
|
|
49
|
+
export declare function parseAlertArg(arg: string): Partial<AlertSettings> | undefined;
|
|
50
|
+
export declare function describeAlert(s: AlertSettings): string;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finish alert: when a long run ends, or a run that has been going for a while stops to ask you
|
|
3
|
+
* something, ring the terminal bell and put a mark in the window title, so you notice from another
|
|
4
|
+
* window or tab.
|
|
5
|
+
*
|
|
6
|
+
* It uses only two terminal standards and no OS commands: BEL (0x07) and the OSC 0 title. What the
|
|
7
|
+
* terminal does with them is its own setting (a taskbar flash, a tab badge, a sound, or nothing).
|
|
8
|
+
* Runs shorter than the threshold stay quiet, and `/chassis alert off` switches it off.
|
|
9
|
+
*
|
|
10
|
+
* The setting lives in the same state file as the disabled widgets (`alert`: `{ enabled, seconds }`).
|
|
11
|
+
*/
|
|
12
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
13
|
+
import { dirname } from "node:path";
|
|
14
|
+
import { statePath } from "./api.js";
|
|
15
|
+
export const DEFAULT_ALERT_SECONDS = 30;
|
|
16
|
+
const MAX_SECONDS = 24 * 60 * 60;
|
|
17
|
+
const BEL = "\x07";
|
|
18
|
+
export function defaultAlert() {
|
|
19
|
+
return { enabled: true, seconds: DEFAULT_ALERT_SECONDS };
|
|
20
|
+
}
|
|
21
|
+
/** Settings from the state file; anything missing or malformed falls back to the default. */
|
|
22
|
+
export function loadAlert(path = statePath()) {
|
|
23
|
+
const out = defaultAlert();
|
|
24
|
+
try {
|
|
25
|
+
const a = JSON.parse(readFileSync(path, "utf8"))?.alert;
|
|
26
|
+
if (typeof a?.enabled === "boolean")
|
|
27
|
+
out.enabled = a.enabled;
|
|
28
|
+
if (typeof a?.seconds === "number" && Number.isFinite(a.seconds) && a.seconds >= 0 && a.seconds <= MAX_SECONDS)
|
|
29
|
+
out.seconds = a.seconds;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
// no file yet, or unreadable: defaults
|
|
33
|
+
}
|
|
34
|
+
return out;
|
|
35
|
+
}
|
|
36
|
+
/** Save into the state file, keeping its other keys. Best effort, like the widget list. */
|
|
37
|
+
export function saveAlert(s, path = statePath()) {
|
|
38
|
+
try {
|
|
39
|
+
let data = {};
|
|
40
|
+
if (existsSync(path)) {
|
|
41
|
+
try {
|
|
42
|
+
data = JSON.parse(readFileSync(path, "utf8")) ?? {};
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
data = {};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
data.alert = { enabled: s.enabled, seconds: s.seconds };
|
|
49
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
50
|
+
writeFileSync(path, `${JSON.stringify(data, null, 2)}\n`);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// the in-memory setting still applies for this run
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Whether to alert: on, and the run has lasted the threshold. A shorter run is one you are
|
|
58
|
+
* watching. This holds for a finish, a failure and a stop that waits for you alike.
|
|
59
|
+
*/
|
|
60
|
+
export function shouldAlert(s, durationMs) {
|
|
61
|
+
return s.enabled && durationMs !== undefined && durationMs >= s.seconds * 1000;
|
|
62
|
+
}
|
|
63
|
+
/** The mark put in front of the title. */
|
|
64
|
+
export const TITLE_MARK = { finished: "✓", failed: "✗", waiting: "?" };
|
|
65
|
+
/** Title while alerting: the mark in front of pi's own title. */
|
|
66
|
+
export function alertTitle(reason, title) {
|
|
67
|
+
return `${TITLE_MARK[reason]} ${title}`;
|
|
68
|
+
}
|
|
69
|
+
/** Ring the bell and mark the title. */
|
|
70
|
+
export function alert(out, reason, title) {
|
|
71
|
+
out.write(BEL);
|
|
72
|
+
out.setTitle(alertTitle(reason, title));
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* How a run ended, from the last assistant message's stop reason in an agent_end message list. An
|
|
76
|
+
* abort means you pressed esc, so you are there and nothing should ring.
|
|
77
|
+
*/
|
|
78
|
+
export function runOutcome(messages) {
|
|
79
|
+
for (let i = (messages?.length ?? 0) - 1; i >= 0; i--) {
|
|
80
|
+
const m = messages[i];
|
|
81
|
+
if (m?.role !== "assistant")
|
|
82
|
+
continue;
|
|
83
|
+
return m.stopReason === "error" ? "failed" : m.stopReason === "aborted" ? "aborted" : "finished";
|
|
84
|
+
}
|
|
85
|
+
return "finished";
|
|
86
|
+
}
|
|
87
|
+
/** The title pi itself sets when there is no session name: "π - <folder>". Used to clear the mark. */
|
|
88
|
+
export function plainTitle(cwd, sessionName) {
|
|
89
|
+
const folder = cwd.split(/[\\/]/).filter(Boolean).pop() ?? cwd;
|
|
90
|
+
return sessionName ? `π - ${sessionName} - ${folder}` : `π - ${folder}`;
|
|
91
|
+
}
|
|
92
|
+
/** "off", "on", or a number of seconds ("30", "30s", "2m"); undefined when it is none of these. */
|
|
93
|
+
export function parseAlertArg(arg) {
|
|
94
|
+
const a = arg.trim().toLowerCase();
|
|
95
|
+
if (a === "on")
|
|
96
|
+
return { enabled: true };
|
|
97
|
+
if (a === "off")
|
|
98
|
+
return { enabled: false };
|
|
99
|
+
const m = a.match(/^(\d+(?:\.\d+)?)\s*(s|m)?$/);
|
|
100
|
+
if (!m)
|
|
101
|
+
return undefined;
|
|
102
|
+
const seconds = Number(m[1]) * (m[2] === "m" ? 60 : 1);
|
|
103
|
+
return seconds <= MAX_SECONDS ? { enabled: true, seconds } : undefined;
|
|
104
|
+
}
|
|
105
|
+
export function describeAlert(s) {
|
|
106
|
+
return s.enabled ? `finish alert on (runs over ${s.seconds}s)` : "finish alert off";
|
|
107
|
+
}
|