pi-extended-agent 0.0.0-stage → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/README.md +370 -3
- package/bin/pi.mjs +3 -0
- package/dist/bin/command-policy.js +222 -0
- package/dist/bin/command-policy.js.map +1 -0
- package/dist/bin/main.js +44 -0
- package/dist/bin/main.js.map +1 -0
- package/dist/bin/model-interface.js +57 -0
- package/dist/bin/model-interface.js.map +1 -0
- package/dist/bin/runtime.js +84 -0
- package/dist/bin/runtime.js.map +1 -0
- package/dist/bin/update.js +217 -0
- package/dist/bin/update.js.map +1 -0
- package/dist/bin/verify-runtime.js +144 -0
- package/dist/bin/verify-runtime.js.map +1 -0
- package/dist/extensions/commands.js +65 -0
- package/dist/extensions/commands.js.map +1 -0
- package/dist/extensions/config.js +53 -0
- package/dist/extensions/config.js.map +1 -0
- package/dist/extensions/effort.js +65 -0
- package/dist/extensions/effort.js.map +1 -0
- package/dist/extensions/escape-exit.js +28 -0
- package/dist/extensions/escape-exit.js.map +1 -0
- package/dist/extensions/permissions.js +134 -0
- package/dist/extensions/permissions.js.map +1 -0
- package/dist/extensions/pi-interface.js +88 -0
- package/dist/extensions/pi-interface.js.map +1 -0
- package/dist/extensions/skills.js +59 -0
- package/dist/extensions/skills.js.map +1 -0
- package/dist/extensions/update-notice.js +18 -0
- package/dist/extensions/update-notice.js.map +1 -0
- package/dist/extensions/workspace.js +485 -0
- package/dist/extensions/workspace.js.map +1 -0
- package/dist/lib/activity.js +192 -0
- package/dist/lib/activity.js.map +1 -0
- package/dist/lib/command-policy.js +16 -0
- package/dist/lib/command-policy.js.map +1 -0
- package/dist/lib/config-preferences.js +3 -0
- package/dist/lib/config-preferences.js.map +1 -0
- package/dist/lib/config.js +27 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/context.js +112 -0
- package/dist/lib/context.js.map +1 -0
- package/dist/lib/errors.js +7 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/memory.js +87 -0
- package/dist/lib/memory.js.map +1 -0
- package/dist/lib/permissions.js +44 -0
- package/dist/lib/permissions.js.map +1 -0
- package/dist/lib/plan.js +81 -0
- package/dist/lib/plan.js.map +1 -0
- package/dist/lib/project-state.js +80 -0
- package/dist/lib/project-state.js.map +1 -0
- package/dist/lib/prompt.js +31 -0
- package/dist/lib/prompt.js.map +1 -0
- package/dist/lib/skills.js +269 -0
- package/dist/lib/skills.js.map +1 -0
- package/dist/lib/startup.js +12 -0
- package/dist/lib/startup.js.map +1 -0
- package/dist/lib/status.js +57 -0
- package/dist/lib/status.js.map +1 -0
- package/dist/lib/update-notice.js +49 -0
- package/dist/lib/update-notice.js.map +1 -0
- package/dist/lib/usage.js +111 -0
- package/dist/lib/usage.js.map +1 -0
- package/dist/lib/workspace-tools.js +15 -0
- package/dist/lib/workspace-tools.js.map +1 -0
- package/dist/ui/chat.js +63 -0
- package/dist/ui/chat.js.map +1 -0
- package/dist/ui/chrome.js +113 -0
- package/dist/ui/chrome.js.map +1 -0
- package/dist/ui/command-panel.js +104 -0
- package/dist/ui/command-panel.js.map +1 -0
- package/dist/ui/command-views.js +129 -0
- package/dist/ui/command-views.js.map +1 -0
- package/dist/ui/config-screen.js +84 -0
- package/dist/ui/config-screen.js.map +1 -0
- package/dist/ui/context-format.js +9 -0
- package/dist/ui/context-format.js.map +1 -0
- package/dist/ui/context-view.js +76 -0
- package/dist/ui/context-view.js.map +1 -0
- package/dist/ui/effort-screen.js +44 -0
- package/dist/ui/effort-screen.js.map +1 -0
- package/dist/ui/escape-exit.js +68 -0
- package/dist/ui/escape-exit.js.map +1 -0
- package/dist/ui/model-screen.js +62 -0
- package/dist/ui/model-screen.js.map +1 -0
- package/dist/ui/permissions-screen.js +68 -0
- package/dist/ui/permissions-screen.js.map +1 -0
- package/dist/ui/skills-screen.js +316 -0
- package/dist/ui/skills-screen.js.map +1 -0
- package/dist/ui/status-view.js +29 -0
- package/dist/ui/status-view.js.map +1 -0
- package/dist/ui/theme.js +36 -0
- package/dist/ui/theme.js.map +1 -0
- package/dist/ui/types.js +2 -0
- package/dist/ui/types.js.map +1 -0
- package/dist/ui/workspace-screen.js +67 -0
- package/dist/ui/workspace-screen.js.map +1 -0
- package/package.json +55 -6
- package/ui/pi-logo-light.svg +21 -0
- package/ui/pi-logo.svg +21 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.0.0
|
|
4
|
+
|
|
5
|
+
First release of Pi Extended Agent, bundling Pi 1.4.0.
|
|
6
|
+
|
|
7
|
+
- Shared terminal interface for configuration, models, effort, permissions, skills, usage, status, and context.
|
|
8
|
+
- Automatic project memory with a short MEMORY.md index, topic editing, and shared Git worktree storage.
|
|
9
|
+
- Persistent planning with a read-only tool barrier, explicit execution approval, and step tracking.
|
|
10
|
+
- Session, project, and global prompt additions that preserve Pi's native system prompt.
|
|
11
|
+
- Shift+Tab switches normal/plan modes; Shift+Left/Right adjusts supported reasoning effort.
|
|
12
|
+
- Per-action tool approval and read-only permissions, including nested tool calls.
|
|
13
|
+
- Managed engine updates with compatibility checks, rollback, and background update notices.
|
|
14
|
+
- Native Pi authentication, model discovery, session history, and automatic compaction.
|
|
15
|
+
- English Nextra documentation with static search and a GitHub Pages deployment workflow.
|
|
16
|
+
- Repository instructions in AGENTS.md and a documented npm release procedure.
|
|
17
|
+
- Reserved memory index identifier to prevent note loss on case-insensitive filesystems.
|
package/README.md
CHANGED
|
@@ -1,3 +1,370 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://pi.dev">
|
|
3
|
+
<picture>
|
|
4
|
+
<source media="(prefers-color-scheme: dark)" srcset="ui/pi-logo.svg">
|
|
5
|
+
<img src="ui/pi-logo-light.svg" alt="Pi logo" width="128" height="128">
|
|
6
|
+
</picture>
|
|
7
|
+
</a>
|
|
8
|
+
</p>
|
|
9
|
+
|
|
10
|
+
<h1 align="center">Pi Extended Agent</h1>
|
|
11
|
+
|
|
12
|
+
<p align="center">
|
|
13
|
+
A personal Pi setup with a quiet terminal interface.<br>
|
|
14
|
+
One package. The <code>pi</code> command. Managed engine updates.
|
|
15
|
+
</p>
|
|
16
|
+
|
|
17
|
+
<p align="center">
|
|
18
|
+
<a href="https://svjszn.github.io/pi-extended-agent/">Documentation</a> /
|
|
19
|
+
<a href="#installation">Installation</a> /
|
|
20
|
+
<a href="#already-have-pi">Existing Pi users</a> /
|
|
21
|
+
<a href="#updates">Updates</a> /
|
|
22
|
+
<a href="#development">Development</a> /
|
|
23
|
+
<a href="#contributing">Contributing</a>
|
|
24
|
+
</p>
|
|
25
|
+
|
|
26
|
+
## At a glance
|
|
27
|
+
|
|
28
|
+
| Component | Version / default |
|
|
29
|
+
| :--- | :--- |
|
|
30
|
+
| Package | `pi-extended-agent` · `1.0.0` |
|
|
31
|
+
| Bundled Pi fallback | `1.4.0` |
|
|
32
|
+
| Managed engine | Updated separately with `pi update` |
|
|
33
|
+
| Startup model | Selected by the active Pi engine from its settings and catalog |
|
|
34
|
+
| Node.js | `>=22.19.0` |
|
|
35
|
+
|
|
36
|
+
Pi provides the agent loop, tools, authentication, and sessions. This package provides the CLI entry point, interface extensions, and engine updater. Pi is installed automatically; users do not install it separately.
|
|
37
|
+
|
|
38
|
+
```text
|
|
39
|
+
██████ pi coding agent v1.4.0
|
|
40
|
+
██ ██ Your model with medium effort
|
|
41
|
+
████ ██ ~/project
|
|
42
|
+
██ ██
|
|
43
|
+
|
|
44
|
+
...conversation...
|
|
45
|
+
|
|
46
|
+
────────────────────────────────────────────────────────────
|
|
47
|
+
>
|
|
48
|
+
────────────────────────────────────────────────────────────
|
|
49
|
+
auto mode
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The header shows the actual engine version, model, effort, and current working directory. Short conversations sit above the input; the footer shows the permissions mode at the left: `auto mode` for full access, `ask mode` for approvals, or `read only`.
|
|
53
|
+
|
|
54
|
+
The terminal tab is titled **Pi Coding Agent**. Chat messages and input align with the logo's two-column inset. User messages have a subtle dark gray background with light text; assistant replies keep the terminal background. Below the input, **auto mode** appears on the left and current context usage on the right, for example `~24k / 200k · 12% context`. Narrow terminals show a shorter indicator.
|
|
55
|
+
|
|
56
|
+
## Installation
|
|
57
|
+
|
|
58
|
+
You need **Node.js 22.19.0 or newer** and npm. On Windows, Git for Windows supplies the Bash shell used by Pi's default shell tool. Existing Pi users should read the migration instructions below first.
|
|
59
|
+
|
|
60
|
+
### From npm
|
|
61
|
+
|
|
62
|
+
Install the package and start the agent:
|
|
63
|
+
|
|
64
|
+
```sh
|
|
65
|
+
npm install -g --ignore-scripts pi-extended-agent
|
|
66
|
+
pi
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The package also provides `pi-extended-agent` as an alternative command. Both launch the same agent.
|
|
70
|
+
|
|
71
|
+
### From source
|
|
72
|
+
|
|
73
|
+
```sh
|
|
74
|
+
git clone https://github.com/svjszn/pi-extended-agent.git agent
|
|
75
|
+
cd agent
|
|
76
|
+
npm ci --ignore-scripts
|
|
77
|
+
npm run build
|
|
78
|
+
npm link --force --ignore-scripts
|
|
79
|
+
pi
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**`npm ci` installs the bundled Pi dependency. `npm link` connects the global commands to this checkout.** Keep the checkout in place while using the link. To run without linking: `npm run pi`.
|
|
83
|
+
|
|
84
|
+
### Already have Pi?
|
|
85
|
+
|
|
86
|
+
Upstream Pi and this package both provide a command named `pi`. npm may reject the new installation with `EEXIST` rather than replace the existing command.
|
|
87
|
+
|
|
88
|
+
The recommended migration for an npm-installed upstream Pi is:
|
|
89
|
+
|
|
90
|
+
```sh
|
|
91
|
+
npm uninstall -g @earendil-works/pi-coding-agent
|
|
92
|
+
npm install -g --ignore-scripts pi-extended-agent
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
For a linked source checkout, replace the second command with `npm link --force --ignore-scripts` from that checkout, or install a locally packed `.tgz` file.
|
|
96
|
+
|
|
97
|
+
If you linked an early checkout under the old name `local-coding-agent`, run `npm unlink -g local-coding-agent` before linking this renamed package.
|
|
98
|
+
|
|
99
|
+
**Your existing `~/.pi/agent/` profile is preserved**, including sign-in, personal settings, and sessions. The upstream package is removed; its user data is not.
|
|
100
|
+
|
|
101
|
+
An explicit takeover is also possible with `npm install -g --force --ignore-scripts pi-extended-agent`, but it leaves the upstream package installed. Reinstalling that upstream package later can claim `pi` again. Removing it first avoids that ambiguity.
|
|
102
|
+
|
|
103
|
+
For a standalone Pi installation or a different npm prefix, inspect the shell's command resolution instead of deleting executables manually:
|
|
104
|
+
|
|
105
|
+
```powershell
|
|
106
|
+
# PowerShell
|
|
107
|
+
Get-Command pi -All
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
```sh
|
|
111
|
+
# Bash / Zsh
|
|
112
|
+
type -a pi
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
If another installation appears earlier on PATH, launch `pi-extended-agent` directly while fixing PATH or removing the old installation through its own package manager.
|
|
116
|
+
|
|
117
|
+
### Sign in and verify
|
|
118
|
+
|
|
119
|
+
Run `pi` from the project you want to work on. Inside Pi:
|
|
120
|
+
|
|
121
|
+
1. Enter `/login`, select ChatGPT/Codex, and complete the browser sign-in if needed. Existing standard-profile credentials are reused.
|
|
122
|
+
2. Enter `/status` to check the active Pi version, selected model, and authentication status. `/config info` shows configuration paths.
|
|
123
|
+
|
|
124
|
+
If the selected provider has no configured authentication, startup shows a warning and the header keeps a `/login PROVIDER` hint. The hint disappears after sign-in. This checks local configuration only; it does not verify token validity with the provider.
|
|
125
|
+
|
|
126
|
+
Each computer needs its own sign-in. The standard profile is `~/.pi/agent/`, normally `C:\Users\YOUR_NAME\.pi\agent\` on Windows. `PI_CODING_AGENT_DIR` remains available for an explicitly chosen alternative profile.
|
|
127
|
+
|
|
128
|
+
## Updates
|
|
129
|
+
|
|
130
|
+
### Update the internal Pi engine
|
|
131
|
+
|
|
132
|
+
```sh
|
|
133
|
+
pi update
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
The launcher checks the latest upstream release through npm, installs it into a separate managed version directory, and checks our extension loading, terminal layout, and Escape handling. The version check uses your npm registry, proxy, and certificate settings, with a 30-second request timeout and one retry. These compatibility checks do not call a model. Only after they pass does it switch the active engine. A failed download, installation, or compatibility check leaves the previous engine selected.
|
|
137
|
+
|
|
138
|
+
**Engine updates do not install a global upstream Pi package, change the global command, edit this repository, or touch your credentials.** Restart Pi after a successful update.
|
|
139
|
+
|
|
140
|
+
| Command | Behavior |
|
|
141
|
+
| :--- | :--- |
|
|
142
|
+
| `pi update` | Install the latest Pi release and activate it if compatibility checks pass |
|
|
143
|
+
| `pi update --check` | Show the active and latest engine versions |
|
|
144
|
+
| `pi update --to 1.4.0` | Install a specific engine version |
|
|
145
|
+
| `pi update --offline` | Check and activate the newest complete cached engine |
|
|
146
|
+
| `pi update --rollback` | Restore the previous engine, or the bundled fallback |
|
|
147
|
+
| `pi update --all` | Update the engine, then configured extension packages |
|
|
148
|
+
| `pi update --models` | Refresh model catalogs through Pi |
|
|
149
|
+
| `pi update --extensions` | Update configured extension packages through Pi |
|
|
150
|
+
|
|
151
|
+
The managed engine lives under `~/.pi/pi-extended-agent/`, separately from the authentication profile. Version directories remain available for rollback. `active.json` selects the active release. The bundled dependency is used until an updated engine is activated.
|
|
152
|
+
|
|
153
|
+
At interactive startup, this package checks npm in the background and shows `Pi VERSION is available … Run pi update` when a newer engine exists. Successful checks are cached for 12 hours under the managed runtime directory. The check uses your npm registry settings, has a short timeout, and never blocks the editor. Offline mode (`PI_OFFLINE`) skips it; network failures stay quiet. Print and RPC sessions do not check. Updates are installed only when you run `pi update`.
|
|
154
|
+
|
|
155
|
+
For testing or custom storage, set `PI_EXTENDED_RUNTIME_DIR`. The launcher disables upstream self-update notices because updates belong to this package's updater; the notification above points to our managed update command. It does not automatically switch engines at startup.
|
|
156
|
+
|
|
157
|
+
### Update Pi Extended Agent itself
|
|
158
|
+
|
|
159
|
+
```sh
|
|
160
|
+
npm install -g --ignore-scripts pi-extended-agent@latest
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
For a linked source checkout:
|
|
164
|
+
|
|
165
|
+
```sh
|
|
166
|
+
git pull
|
|
167
|
+
npm ci --ignore-scripts
|
|
168
|
+
npm run build
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Restart Pi afterward. Source edits do not require relinking. If you move the checkout or change the CLI entry points, run `npm link --force --ignore-scripts` again.
|
|
172
|
+
|
|
173
|
+
## Daily use
|
|
174
|
+
|
|
175
|
+
### Commands
|
|
176
|
+
|
|
177
|
+
| Command | Shows |
|
|
178
|
+
| :--- | :--- |
|
|
179
|
+
| `/usage` | Active provider, available account usage limits, and local reset times |
|
|
180
|
+
| `/stats` | Annual activity calendar and local history statistics |
|
|
181
|
+
| `/status` | Pi version, session ID, login method, active model, MCP servers, and tools |
|
|
182
|
+
| `/config` | Configuration overview with an integrated Preferences tab |
|
|
183
|
+
| `/context` | Context window map, estimated breakdown, loaded instructions, skills, and active tools |
|
|
184
|
+
| `/effort [level]` | Choose reasoning effort or set a supported level directly |
|
|
185
|
+
| `/permissions [mode]` | Choose full access, per-action approval, or read-only agent tools |
|
|
186
|
+
| `/memory` | Inspect, edit, delete, and toggle automatic project memory |
|
|
187
|
+
| `/plan [goal]` | Research a task, edit its plan, and explicitly approve execution |
|
|
188
|
+
| `/prompt [scope]` | View the native system prompt and edit session, project, or global additions |
|
|
189
|
+
| `/model [query]` | Search and select a model in the shared full-screen interface |
|
|
190
|
+
| `/skills [query]` | Installed skills, skills.sh search, preview, and installation |
|
|
191
|
+
|
|
192
|
+
The commands open full terminal screens below the Pi header, aligned to its two-column inset. They have no enclosing border. Read-only screens show `esc to close` in the input row; `/skills` uses that row for search and filtering. Usage bars show the remaining allowance; configuration values align in columns. The shared white and gray palette lives in `ui/theme.ts`, ready for a future `/theme` command. Press **Escape** or **Enter** to close a read-only screen. Scroll with **↑/↓**, **Page Up/Down**, **Home/End**, or the mouse wheel. Opening a viewer does not call a model. Starting `/plan <goal>` or choosing Execute sends the corresponding task to the agent.
|
|
193
|
+
|
|
194
|
+
`/usage` names the active provider. It has account-usage readers for ChatGPT OAuth (`openai-codex`) and Claude OAuth (`anthropic`), using credentials resolved by Pi. It does not import credentials from a separate Claude Code installation. The Claude reader has fixture coverage; it has not been verified with a live Claude account. These account backends are not public API contracts, and availability depends on account access and OAuth scopes. Limits are fetched only when the screen opens; remaining allowances are never estimated from local token counts. API keys, unsupported providers, missing data, and network errors show an explicit unavailable state. Credentials and usage responses are not copied or stored.
|
|
195
|
+
|
|
196
|
+
`/stats` shows an annual calendar above two columns of statistics, with **All time / Last 7 days / Last 30 days** filters. Switch filters with **Tab / Shift+Tab** or **←/→**. Filters affect the statistics; the calendar always covers the latest year and crops to recent weeks in a narrow terminal. Intensity follows recorded daily tokens, with prompt counts as a fallback when token data is absent.
|
|
197
|
+
|
|
198
|
+
Statistics come from the active profile's local sessions, including the current session and a custom session directory. They include favorite model (by assistant response count), recorded tokens, session count, active days, most active day, and streaks. Session length is the span between its first and last recorded messages, including idle gaps. Token totals include reported tool, compaction, and summary usage; reasoning tokens are not added twice. Forked entries count once. Statistics cover all recorded history or the selected period, while the calendar uses local dates for the latest 365 days. Activity on other computers or in the Codex app is not included.
|
|
199
|
+
|
|
200
|
+
`/config` opens the original Configuration overview, with Current session, Saved preferences, and Files in aligned columns. Press Tab to switch to the integrated Preferences tab in the same full-screen panel, keeping the header, footer, inset, and white/gray palette. Preferences include all settings previously available as `/settings`: themes, model defaults, effort defaults, transport, compaction, image handling, terminal behavior, and warnings. Use arrow keys to navigate, Enter to edit, and type to filter. Escape backs out of a submenu, returns to the overview, then closes the screen. Tab switches between the overview and preferences. Native save callbacks apply settings to the session; changing TUI mode briefly closes and reopens the panel so Pi can switch renderers safely. `/config info` remains an alias for the overview. Project preferences respect Pi's trust decision, and credentials are excluded. In print/RPC mode, `/config` shows the read-only overview.
|
|
201
|
+
|
|
202
|
+
The command menu omits `/settings`, `/tree`, `/thinking`, `/scoped-models`, `/import`, `/export`, `/share`, `/bug`, `/copy`, `/session`, `/changelog`, `/hotkeys`, `/fork`, `/clone`, `/trust`, `/about-agent`, `/llama`, and `/mcp`. These commands are also rejected when entered manually. Use `/config` for preferences, `/effort` for session reasoning effort, and `/status` for engine and session information. The runtime adapter applies to both bundled and managed engines and is checked before engine updates activate. It does not modify upstream package files.
|
|
203
|
+
|
|
204
|
+
`/status` shows the active Pi engine version, session ID, provider login method, model, MCP servers, and active tool names. The model appears with MCP and tools, and shows only its model ID. Login reflects configured credentials without resolving or refreshing them. MCP metadata combines the engine's configuration reader with extension registrations and tool namespaces; project settings respect Pi's trust decision. Registered tools do not prove a live connection. Engines without a native MCP configuration reader show the servers inferred from registered tools and extensions.
|
|
205
|
+
|
|
206
|
+
`/effort` opens a selector containing only levels supported by the current model, as reported by Pi's `getSupportedThinkingLevels(model)`. Choose with **↑/↓** or **Tab / Shift+Tab**, apply with **Enter**, or cancel with **Escape**. `/effort high` sets a level directly; argument completion follows the selected model. Changes apply to the current session through Pi's native thinking-level API. The current level comes from `pi.getThinkingLevel()` and appears right-aligned on a separate line above the input. It stays synchronized with native shortcuts and model changes. The label is hidden when the terminal is too narrow to fit its name.
|
|
207
|
+
|
|
208
|
+
`/model` uses the same header, two-column inset, borderless body, monochrome palette, and input dock as the other command screens. Search stays in the input row; the current model uses `●` and the highlighted row is bold. Native model discovery, scoped-model switching with Tab, selection with Enter, and saving the default with Ctrl+S retain Pi's behavior. Escape cancels the selector and its background catalog refresh. Model-screen compatibility is checked before activating an engine update.
|
|
209
|
+
|
|
210
|
+
### Agent permissions
|
|
211
|
+
|
|
212
|
+
Open `/permissions` to choose a mode in the shared white/gray full-screen interface, or set it directly:
|
|
213
|
+
|
|
214
|
+
```text
|
|
215
|
+
/permissions full
|
|
216
|
+
/permissions ask
|
|
217
|
+
/permissions read-only
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
- **Full access** preserves the previous behavior: tools execute without this package's approval prompts. It is the default for new sessions.
|
|
221
|
+
- **Ask before actions** allows Pi's built-in `read`, `find`, `grep`, and `ls` without prompting. File changes, shell commands, and other tools (including MCP and nested tools) require approval for each call. TUI approval screens show the complete tool input with scrolling, start on Deny, and support Allow once. RPC uses Pi's confirmation request; a client must respond. Without an interactive UI, calls requiring approval are denied.
|
|
222
|
+
- **Read only** permits those four built-in reading/search tools. Write, edit, Bash, PowerShell, and external tools are blocked. External tools' read-only hints do not grant permission. Our own memory reads and plan updates are also allowed: they only access the app's project notebook. Memory saves and deletes follow the normal permissions policy.
|
|
223
|
+
|
|
224
|
+
The selection is saved as session metadata and restored on resume or reload. It applies to subsequent tool calls; it does not stop a tool already running. Pending approval dialogs are cancelled when the mode changes or the session shuts down. The footer reflects the selected mode. These controls govern agent tool calls, including calls through other tools; they are not an operating-system sandbox or a project-directory boundary. Explicit user shell commands (`!` / `!!`), command actions such as installing skills, and extensions' direct code execution keep their existing behavior. Project trust remains separate.
|
|
225
|
+
|
|
226
|
+
### Automatic project memory
|
|
227
|
+
|
|
228
|
+
Automatic memory is enabled by default. During normal work the agent can save useful preferences, corrections, environment facts, and project decisions through `project_memory`. It does not run a separate model request or an extraction pass after each message. Source-control history, transient progress, and credentials do not belong in memory. Common credential patterns are rejected when saving.
|
|
229
|
+
|
|
230
|
+
`/memory` opens the project notebook. **Tab** changes topics; **e** edits the selected topic, **n** creates one, **d** deletes it after confirmation, and **t** toggles automatic memory. Document editors use **Enter** for newlines, **Ctrl+S** to save, and **Escape** to discard changes. Direct commands include `/memory on`, `/memory off`, `/memory read TOPIC`, `/memory edit TOPIC`, `/memory add`, and `/memory delete TOPIC`. Disabling memory preserves notes but stops loading and agent access until re-enabled.
|
|
231
|
+
|
|
232
|
+
Notes live under the active profile's `pi-extended/projects/PROJECT_KEY/memory/`. Git worktrees of the same repository share a notebook; separate repositories are isolated. Outside Git, the canonical working directory identifies the project. The short `MEMORY.md` index contains at most 32 summaries (160 bytes each); each topic has up to 12 KB of details read by the model only on demand. The notebook stays outside the source tree and persists across sessions. These local files are sent to the selected model when loaded into context.
|
|
233
|
+
|
|
234
|
+
### Plan before executing
|
|
235
|
+
|
|
236
|
+
**Shift+Tab** in the chat input switches between normal mode (`auto mode` with Full access) and `plan mode`. Switching out pauses and preserves the plan; switching back restores the draft. It keeps your input text, effort, and permission choice. It does not start execution. Finish the current run and queued messages before switching. **Shift+Left/Right** decreases/increases reasoning effort through the current model's supported levels, stopping at the lowest/highest level; `/effort` also remains available. Inside command screens, Shift+Tab keeps its usual navigation behavior.
|
|
237
|
+
|
|
238
|
+
Use `/plan <goal>` to start research, or open `/plan` and press **s** to enable planning before describing the task. The agent saves the goal, steps, affected areas, and checks with `update_plan`. The footer shows `plan mode`. A tool hook allows only built-in reading/search tools, memory reads, and our internal plan updates. Available built-in `find`, `grep`, and `ls` tools are temporarily activated so research works without shell access; the previous selection is restored on execution or cancellation. Changes, external tools, nested mutation calls, and shell commands are blocked even under Full access. Interactive/RPC user shell commands are also blocked while planning.
|
|
239
|
+
|
|
240
|
+
Review the result with `/plan`, edit with **e** or `/plan edit`, and explicitly choose **x** or `/plan execute` to start implementation. Only a user command can approve execution. The existing `/permissions` mode stays in force; executing a plan never grants Full access. `/plan cancel` leaves planning without starting work. Plans are saved per session in the profile, survive compaction, and restore when that session is resumed or reloaded. During execution the agent tracks pending, in-progress, and completed steps; changing the approved scope requires another edit and approval.
|
|
241
|
+
|
|
242
|
+
### System prompt additions
|
|
243
|
+
|
|
244
|
+
`/prompt` shows a preview for the next run, the native Pi prompt, and **session**, **project**, and **global** additions. Use **Tab** to choose a section, **e** to edit additions, or **d** to clear them after confirmation. Native Pi instructions remain intact. `/prompt session`, `/prompt project`, and `/prompt global` open the corresponding editor directly; `/prompt project Use npm for this repository.` saves text without opening an editor.
|
|
245
|
+
|
|
246
|
+
Global and project additions live in the active profile; session additions are stored in Pi session metadata. Additions are limited to 12 KB per scope and apply on the next run, in global → project → session order. Other extensions can add their own instructions at run start. Pi's existing system-prompt files, instruction discovery, and automatic compaction remain in use; this package does not replace them.
|
|
247
|
+
|
|
248
|
+
### Inspect context
|
|
249
|
+
|
|
250
|
+
`/context` shows a white and gray map of the active model's context window, followed by estimates for the system prompt, tool definitions, loaded instructions, skill descriptions, messages, and tool results. Free space and the configured compaction buffer appear separately. The screen also lists instruction paths, skill names, active tool names, and compaction settings. It reads in-memory session data without making a model request or adding content to the conversation.
|
|
251
|
+
|
|
252
|
+
The total follows Pi's current-window estimate, based on its latest valid assistant usage and estimates for newer messages. Before the first response, the indicator also estimates the prompt and active tool schemas. These are not cumulative billed tokens. `~` marks estimated values. Categories use Pi's character-based heuristic and reconcile to the total; unclassified differences appear as **Other context**. Individual source lists show raw estimates. Provider formatting, images, and extension hooks can affect final request sizes.
|
|
253
|
+
|
|
254
|
+
Compacted history and inactive branches are excluded. After compaction, Pi may report an unknown total until the next response; the footer shows `—` instead of retaining the previous usage. The indicator refreshes on session, model, message, and compaction events, without recounting tokens on every terminal frame. Use Pi's native `/compact` to summarize the current session or `/new` to begin a fresh one.
|
|
255
|
+
|
|
256
|
+
### Find and install skills
|
|
257
|
+
|
|
258
|
+
Open `/skills` for **Installed** and **Search** tabs, or enter `/skills react` to search immediately. The installed list comes from skills already loaded by Pi, including shared folders, configured paths, and packages. Type to filter it. In Search, type at least two characters to search [skills.sh](https://skills.sh/). A filled circle **●** marks a skill available in the current session; an empty circle **○** marks one that is not loaded. Results also show the source repository and install count. Descriptions appear when the catalog supplies them; the preview reads the description and full `SKILL.md` from GitHub.
|
|
259
|
+
|
|
260
|
+
- **Tab / Shift+Tab** switches tabs; **↑/↓** selects a skill; **Enter** opens its preview.
|
|
261
|
+
- In a new skill's preview, **Tab / ←/→** chooses **This project** or **All projects**, then **Enter** installs.
|
|
262
|
+
- **Page Up/Down** and **↑/↓** scroll the preview; **Escape** goes back, closes the manager, or cancels an active download.
|
|
263
|
+
- After installation, **Enter** returns to the chat and reloads Pi's skills without restarting the process.
|
|
264
|
+
|
|
265
|
+
Project skills go to `.pi/skills/`; global skills go to the active profile's `skills/` folder (`~/.pi/agent/skills/` by default). Project installation requires Pi's existing trust decision; choose a global installation or reopen Pi and approve the project when prompted. `--no-skills` and Pi's resource-discovery settings continue to apply.
|
|
266
|
+
|
|
267
|
+
The first version supports public GitHub skills from the catalog. Preview and installation use one pinned commit. The selected skill's directory is downloaded with its references, scripts, and assets, and each file is verified against its Git blob hash. Installation does not run scripts or install the skill's dependencies. Existing directories are never replaced. A failed or cancelled download is cleaned up before activation. Each installed folder includes `.pi-extended-source.json` with its source revision for future management.
|
|
268
|
+
|
|
269
|
+
Large repositories, symlinks, submodules, conflicting filenames, and skills over 200 files, 2 MiB per file, or 25 MiB total are not supported in this first version. Search uses the same public catalog endpoint as the Skills CLI; GitHub's unauthenticated request limits also apply to previews. No model-provider credentials are sent to either service. `/skills` in print/RPC mode is read-only: it lists or searches, without installing.
|
|
270
|
+
|
|
271
|
+
Use `/model` to switch models and `/effort` to choose reasoning effort. Model selection follows the active Pi engine's settings and catalog, including its provider defaults. This package does not inject a fixed model ID, so engine updates can change the provider default without leaving an obsolete CLI override. Explicit CLI model/provider choices, `--models`, and resumed sessions keep Pi's native behavior. Choosing a custom model ID explicitly remains supported by Pi. Before sign-in, Pi may have no model selected; the header shows a `/login` hint.
|
|
272
|
+
|
|
273
|
+
Press **Escape** to exit when the input is empty and Pi is idle. During work, in menus, and in autocomplete, Escape keeps its normal cancellation behavior. An unsent draft prevents Escape from exiting. **Ctrl+D** remains available.
|
|
274
|
+
|
|
275
|
+
```sh
|
|
276
|
+
pi --continue
|
|
277
|
+
pi --model openai-codex/gpt-6-astra
|
|
278
|
+
pi --thinking medium
|
|
279
|
+
pi --tui-mode regular
|
|
280
|
+
pi --no-extensions
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
## Development
|
|
284
|
+
|
|
285
|
+
| File | Responsibility |
|
|
286
|
+
| :--- | :--- |
|
|
287
|
+
| [`bin/pi.mjs`](bin/pi.mjs) | Stable npm entry point for installed and linked commands |
|
|
288
|
+
| [`bin/main.ts`](bin/main.ts) | Own the commands and launch the active Pi engine |
|
|
289
|
+
| [`bin/runtime.ts`](bin/runtime.ts) | Resolve bundled and managed engine versions |
|
|
290
|
+
| [`bin/update.ts`](bin/update.ts) | Install, activate, and roll back engines |
|
|
291
|
+
| [`bin/verify-runtime.ts`](bin/verify-runtime.ts) | Check candidate engine compatibility |
|
|
292
|
+
| [`extensions/`](extensions/) | Register commands, UI, and keyboard behavior |
|
|
293
|
+
| [`lib/`](lib/) | Read account usage, local activity, and selected configuration |
|
|
294
|
+
| [`ui/chrome.ts`](ui/chrome.ts) | Render the header, footer, and spacing |
|
|
295
|
+
| [`ui/escape-exit.ts`](ui/escape-exit.ts) | Preserve native behavior around Escape |
|
|
296
|
+
| [`ui/pi-logo.svg`](ui/pi-logo.svg) | Reference Pi logo geometry |
|
|
297
|
+
| [`test/`](test/) | Check UI, startup, and update behavior |
|
|
298
|
+
|
|
299
|
+
Source code uses TypeScript with `strict` enabled. Plain `npm ci` builds it through `prepare`; when using `npm ci --ignore-scripts`, run `npm run build` explicitly. Compilation writes JavaScript to `dist/`, which is ignored by Git and included in the npm package. Extensions load from `dist/extensions/`; installed users do not need TypeScript or a build step. Keep TypeScript paths in `tsconfig.json` aligned with the bundled Pi dependency; updated engines resolve their own modules at runtime.
|
|
300
|
+
|
|
301
|
+
After editing source files, run `npm run build` before restarting a directly linked `pi`. `npm run pi`, `npm start`, and `npm test` build automatically. For continuous compilation in another terminal, use `npm run build -- --watch`. Tests exercise the compiled JavaScript that ships to users. `npm pack` builds before creating an archive.
|
|
302
|
+
|
|
303
|
+
The startup resource listing is hidden; skills and extensions still load normally. UI integration relies on some Pi component structure, so engine updates are checked before activation.
|
|
304
|
+
|
|
305
|
+
```sh
|
|
306
|
+
npm run check
|
|
307
|
+
npm run build
|
|
308
|
+
npm test
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
Before publishing a release, run `npm run release:check`. It runs type checking and tests, packs the exact npm artifact, installs it into an isolated global prefix, and checks the installed CLI and extensions with an empty profile. The archive is saved under `.local/releases/`. This check never publishes or changes your normal global installation. Windows is the currently verified platform; Linux/macOS need their own runs before claiming support.
|
|
312
|
+
|
|
313
|
+
Repository instructions live in [AGENTS.md](AGENTS.md). The English documentation
|
|
314
|
+
site lives in `docs/` as an independent Nextra project. Run `npm ci --prefix docs`
|
|
315
|
+
and `npm run dev --prefix docs` to work on it. Production builds export static
|
|
316
|
+
pages and a search index; the Documentation workflow deploys them to GitHub
|
|
317
|
+
Pages. See [RELEASING.md](RELEASING.md) for verification and publication steps.
|
|
318
|
+
|
|
319
|
+
To check credentials and make one short model request:
|
|
320
|
+
|
|
321
|
+
```sh
|
|
322
|
+
npm run pi -- auth check --provider openai-codex --no-refresh --json
|
|
323
|
+
npm run smoke
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
The auth check should report `"status":"ready"`. The smoke request runs without tools or session storage and should return `PI_OK`. To use another model: `npm run smoke -- --model MODEL_ID`.
|
|
327
|
+
|
|
328
|
+
## Contributing
|
|
329
|
+
|
|
330
|
+
Bug reports, fixes, documentation improvements, and interface refinements are
|
|
331
|
+
welcome. For a larger feature, you can open an
|
|
332
|
+
[issue](https://github.com/svjszn/pi-extended-agent/issues) to discuss the approach.
|
|
333
|
+
|
|
334
|
+
Fork the repository, create a branch for your change, and follow the setup in
|
|
335
|
+
[Development](#development). Keep pull requests focused and explain the problem,
|
|
336
|
+
the resulting behavior, and how you checked it.
|
|
337
|
+
|
|
338
|
+
For agent code changes, run:
|
|
339
|
+
|
|
340
|
+
```sh
|
|
341
|
+
npm run check
|
|
342
|
+
npm test
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
For documentation changes, install the docs dependencies and build the site:
|
|
346
|
+
|
|
347
|
+
```sh
|
|
348
|
+
npm ci --prefix docs
|
|
349
|
+
npm run build --prefix docs
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
Add regression coverage for behavior fixes and include screenshots for interface
|
|
353
|
+
changes when possible. Keep generated files, local profiles, and credentials out
|
|
354
|
+
of commits. Read [AGENTS.md](AGENTS.md) for repository conventions and the
|
|
355
|
+
[contributing guide](https://svjszn.github.io/pi-extended-agent/contributing/)
|
|
356
|
+
for the full workflow.
|
|
357
|
+
|
|
358
|
+
## Troubleshooting
|
|
359
|
+
|
|
360
|
+
**The original Pi interface opens or `/effort` is missing.** A different installation owns `pi`. Check PATH as shown above. Remove the old npm-installed Pi, then reinstall or relink this package. The unique `pi-extended-agent` command can also launch our package directly.
|
|
361
|
+
|
|
362
|
+
**An engine update fails.** The previous engine stays selected. Check the error, fix connectivity or npm access, and retry. If the version check times out, `pi update --to VERSION` skips that lookup and installs an exact version (installation still needs npm access or cached packages). Use `pi update --rollback` to select the previous version after a successful update.
|
|
363
|
+
|
|
364
|
+
**The updater reports a lock.** Another update may be running. If the updater was interrupted and no update process remains, remove the reported `update.lock` file and retry.
|
|
365
|
+
|
|
366
|
+
**Authentication is missing.** Check `PI_CODING_AGENT_DIR` and use `/login` on this computer. Early local experiments used `.local/pi/`; the current package does not select that directory automatically.
|
|
367
|
+
|
|
368
|
+
---
|
|
369
|
+
|
|
370
|
+
Built on [Pi](https://pi.dev) by Earendil and contributors. Uses the official pixel mark in a terminal-friendly form.
|
package/bin/pi.mjs
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { pathToFileURL } from "node:url";
|
|
4
|
+
import { commandName, removedCommand, removedCommandMessage } from "../lib/command-policy.js";
|
|
5
|
+
import { CONFIG_PREFERENCES } from "../lib/config-preferences.js";
|
|
6
|
+
import { createRequire } from "node:module";
|
|
7
|
+
import { installModelInterface } from "./model-interface.js";
|
|
8
|
+
const installed = new WeakSet();
|
|
9
|
+
/** Runtime-only adapters: never edit upstream files or duplicate its settings callbacks. */
|
|
10
|
+
export function installCommandPolicy(api) {
|
|
11
|
+
const ui = api.InteractiveMode?.prototype;
|
|
12
|
+
const runner = api.ExtensionRunner?.prototype;
|
|
13
|
+
const session = api.AgentSession?.prototype;
|
|
14
|
+
for (const method of [ui?.createBaseAutocompleteProvider, ui?.setupEditorSubmitHandler, ui?.showSettingsSelector, ui?.createExtensionUIContext,
|
|
15
|
+
runner?.getRegisteredCommands, runner?.getCommand, session?.prompt]) {
|
|
16
|
+
if (typeof method !== "function")
|
|
17
|
+
throw new Error("This Pi engine does not support the command-menu adapter.");
|
|
18
|
+
}
|
|
19
|
+
if (installed.has(ui))
|
|
20
|
+
return;
|
|
21
|
+
const autocomplete = ui.createBaseAutocompleteProvider;
|
|
22
|
+
ui.createBaseAutocompleteProvider = function () {
|
|
23
|
+
const provider = autocomplete.call(this);
|
|
24
|
+
if (!Array.isArray(provider.commands))
|
|
25
|
+
throw new Error("Pi command autocomplete has changed.");
|
|
26
|
+
provider.commands = provider.commands.filter((command) => !removedCommand(command.name));
|
|
27
|
+
return provider;
|
|
28
|
+
};
|
|
29
|
+
const setupSubmit = ui.setupEditorSubmitHandler;
|
|
30
|
+
ui.setupEditorSubmitHandler = function () {
|
|
31
|
+
setupSubmit.call(this);
|
|
32
|
+
const submit = this.defaultEditor.onSubmit;
|
|
33
|
+
if (!submit)
|
|
34
|
+
throw new Error("Pi command submission has changed.");
|
|
35
|
+
this.defaultEditor.onSubmit = (text) => {
|
|
36
|
+
const name = commandName(text);
|
|
37
|
+
if (name && removedCommand(name)) {
|
|
38
|
+
this.editor.setText("");
|
|
39
|
+
this.showStatus(removedCommandMessage(name));
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
return submit(text);
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
const commands = runner.getRegisteredCommands;
|
|
46
|
+
runner.getRegisteredCommands = function () {
|
|
47
|
+
return commands.call(this).filter((command) => !removedCommand(command.name)
|
|
48
|
+
&& !removedCommand(command.invocationName ?? command.name));
|
|
49
|
+
};
|
|
50
|
+
const getCommand = runner.getCommand;
|
|
51
|
+
runner.getCommand = function (name) {
|
|
52
|
+
if (removedCommand(name))
|
|
53
|
+
return undefined;
|
|
54
|
+
const command = getCommand.call(this, name);
|
|
55
|
+
return command && !removedCommand(command.name) ? command : undefined;
|
|
56
|
+
};
|
|
57
|
+
const prompt = session.prompt;
|
|
58
|
+
session.prompt = function (text, options) {
|
|
59
|
+
const name = commandName(text);
|
|
60
|
+
if (name && removedCommand(name))
|
|
61
|
+
return Promise.reject(new Error(removedCommandMessage(name)));
|
|
62
|
+
return prompt.call(this, text, options);
|
|
63
|
+
};
|
|
64
|
+
const createUI = ui.createExtensionUIContext;
|
|
65
|
+
ui.createExtensionUIContext = function () {
|
|
66
|
+
const context = createUI.call(this);
|
|
67
|
+
context[CONFIG_PREFERENCES] = () => captureConfigPreferences(this);
|
|
68
|
+
return context;
|
|
69
|
+
};
|
|
70
|
+
installed.add(ui);
|
|
71
|
+
}
|
|
72
|
+
/** Reuse every native item and save callback, without mounting the native menu. */
|
|
73
|
+
export function captureConfigPreferences(host) {
|
|
74
|
+
let list, cancelled = false, pending;
|
|
75
|
+
const originalSelector = host.showSelector;
|
|
76
|
+
try {
|
|
77
|
+
host.showSelector = (create) => { list = create(() => { cancelled = true; }).component.getSettingsList(); };
|
|
78
|
+
host.showSettingsSelector();
|
|
79
|
+
}
|
|
80
|
+
finally {
|
|
81
|
+
host.showSelector = originalSelector;
|
|
82
|
+
}
|
|
83
|
+
if (!list || typeof list.render !== "function" || typeof list.onChange !== "function") {
|
|
84
|
+
throw new Error("Pi preferences are incompatible with the configuration screen.");
|
|
85
|
+
}
|
|
86
|
+
const settings = list;
|
|
87
|
+
const change = settings.onChange;
|
|
88
|
+
settings.onChange = (id, value) => {
|
|
89
|
+
// Changing renderers requires the overlay to close before invoking Pi's callback.
|
|
90
|
+
if (id === "tui-mode")
|
|
91
|
+
pending = () => change(id, value);
|
|
92
|
+
else
|
|
93
|
+
change(id, value);
|
|
94
|
+
};
|
|
95
|
+
return {
|
|
96
|
+
get cancelled() { return cancelled; },
|
|
97
|
+
get hasPendingChange() { return Boolean(pending); },
|
|
98
|
+
applyPendingChange() { const apply = pending; pending = undefined; apply?.(); },
|
|
99
|
+
handleInput: (data) => settings.handleInput(data),
|
|
100
|
+
render(width, rows, theme) {
|
|
101
|
+
settings.maxVisible = Math.max(1, rows - 7);
|
|
102
|
+
settings.theme = {
|
|
103
|
+
label: (text, selected) => theme.fg(selected ? "primary" : "muted", text),
|
|
104
|
+
value: (text) => theme.fg("text", text), description: (text) => theme.fg("dim", text),
|
|
105
|
+
cursor: theme.fg("primary", "› "), hint: (text) => theme.fg("dim", text),
|
|
106
|
+
};
|
|
107
|
+
// Native menus assume a minimum label width; the shared panel clips tiny terminals.
|
|
108
|
+
const lines = settings.render(Math.max(40, width));
|
|
109
|
+
// Submenus obtain their own native theme. Keep them monochrome as well.
|
|
110
|
+
return settings.submenuComponent
|
|
111
|
+
? lines.map((line) => theme.fg("text", line.replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, "")))
|
|
112
|
+
: lines;
|
|
113
|
+
},
|
|
114
|
+
dispose() {
|
|
115
|
+
// Cancel nested theme previews before leaving the preferences tab.
|
|
116
|
+
for (let i = 0; settings.submenuComponent && i < 10; i++)
|
|
117
|
+
settings.handleInput("\x1b");
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
export async function prepareRuntimeCommands(runtime) {
|
|
122
|
+
// The executable and bundle index share classes. Patching dist/index.js alone
|
|
123
|
+
// would leave the actual bundled CLI's menu and submit handler unchanged.
|
|
124
|
+
const bundle = join(runtime.packageDir, "dist", "bundle", "index.js");
|
|
125
|
+
if (!existsSync(bundle))
|
|
126
|
+
throw new Error("Pi engine is missing its bundled command API.");
|
|
127
|
+
const api = await import(pathToFileURL(bundle).href);
|
|
128
|
+
installCommandPolicy(api);
|
|
129
|
+
const require = createRequire(pathToFileURL(runtime.entry));
|
|
130
|
+
const measure = await import(pathToFileURL(require.resolve("@earendil-works/pi-tui")).href);
|
|
131
|
+
installModelInterface(api, measure, runtime.version);
|
|
132
|
+
return api;
|
|
133
|
+
}
|
|
134
|
+
/** Probe private adapter surfaces without creating a session or accessing a profile. */
|
|
135
|
+
export async function verifyCommandPolicy(api) {
|
|
136
|
+
const host = Object.create(api.InteractiveMode.prototype);
|
|
137
|
+
Object.defineProperties(host, {
|
|
138
|
+
session: { configurable: true, value: { scopedModels: [], promptTemplates: [],
|
|
139
|
+
extensionRunner: { getRegisteredCommands: () => [{ name: "config", invocationName: "config" }] },
|
|
140
|
+
resourceLoader: { getSkills: () => ({ skills: [] }) } } },
|
|
141
|
+
sessionManager: { value: { getCwd: () => process.cwd() } },
|
|
142
|
+
settingsManager: { configurable: true, value: { getEnableSkillCommands: () => false } },
|
|
143
|
+
skillCommands: { value: new Map() },
|
|
144
|
+
});
|
|
145
|
+
const provider = host.createBaseAutocompleteProvider();
|
|
146
|
+
if (provider.commands.some((command) => removedCommand(command.name))
|
|
147
|
+
|| !provider.commands.some((command) => command.name === "config")
|
|
148
|
+
|| !provider.commands.some((command) => command.name === "model")) {
|
|
149
|
+
throw new Error("Pi command-menu filtering is incompatible.");
|
|
150
|
+
}
|
|
151
|
+
let settingsOpened = false, removedNotice = false, submitted = "";
|
|
152
|
+
host.defaultEditor = {};
|
|
153
|
+
host.editor = { setText() { } };
|
|
154
|
+
host.showStatus = () => { removedNotice = true; };
|
|
155
|
+
host.showSettingsSelector = () => { settingsOpened = true; };
|
|
156
|
+
host.setupEditorSubmitHandler();
|
|
157
|
+
await host.defaultEditor.onSubmit("/settings");
|
|
158
|
+
if (!removedNotice || settingsOpened)
|
|
159
|
+
throw new Error("Pi still executes removed commands.");
|
|
160
|
+
// /config must reach our extension rather than mount the native settings menu.
|
|
161
|
+
Object.assign(host, { flushPendingBashComponents() { }, onInputCallback: (text) => { submitted = text; } });
|
|
162
|
+
await host.defaultEditor.onSubmit("/config");
|
|
163
|
+
if (settingsOpened || submitted !== "/config")
|
|
164
|
+
throw new Error("Pi bypasses the custom configuration screen.");
|
|
165
|
+
// Probe the settings-data bridge as well as command submission. Native data
|
|
166
|
+
// and callbacks can change even when the old menu method still exists.
|
|
167
|
+
api.initTheme("dark", false);
|
|
168
|
+
const engineSettings = api.SettingsManager.inMemory();
|
|
169
|
+
Object.defineProperty(host, "settingsManager", { value: engineSettings });
|
|
170
|
+
Object.defineProperty(host, "session", { configurable: true, value: {
|
|
171
|
+
settingsManager: engineSettings, autoCompactionEnabled: true,
|
|
172
|
+
modelRuntime: { getAvailableSnapshot: () => [] }, steeringMode: "all", followUpMode: "all",
|
|
173
|
+
} });
|
|
174
|
+
Object.assign(host, {
|
|
175
|
+
showSettingsSelector: api.InteractiveMode.prototype.showSettingsSelector,
|
|
176
|
+
themeController: { getThemeSelection: () => "dark", getTerminalTheme: () => "dark" },
|
|
177
|
+
ui: { mode: "fullscreen" }, chatContainer: { children: [] },
|
|
178
|
+
});
|
|
179
|
+
const preferences = captureConfigPreferences(host);
|
|
180
|
+
try {
|
|
181
|
+
if (!preferences.render(80, 24, { fg: (_role, text) => text, bold: (text) => text }).length) {
|
|
182
|
+
throw new Error("Pi configuration preferences are empty.");
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
finally {
|
|
186
|
+
preferences.dispose();
|
|
187
|
+
}
|
|
188
|
+
// Verify the controller fields consumed by our model renderer against the
|
|
189
|
+
// candidate executable, without authentication or a catalog network request.
|
|
190
|
+
const model = { provider: "compat", id: "compat-model", name: "Compatibility model" };
|
|
191
|
+
Object.defineProperty(host, "session", { value: {
|
|
192
|
+
model, thinkingLevel: "medium", settingsManager: engineSettings, scopedModels: [],
|
|
193
|
+
modelRuntime: { getAvailableSnapshot: () => [model], getModel: () => model, getError: () => undefined,
|
|
194
|
+
refresh: async () => ({ errors: new Map(), aborted: false }) },
|
|
195
|
+
} });
|
|
196
|
+
const tui = { children: [], terminal: { rows: 24, columns: 80 }, requestRender() { } };
|
|
197
|
+
let modelScreen;
|
|
198
|
+
Object.assign(host, {
|
|
199
|
+
ui: tui, footerContainer: { render: () => [] },
|
|
200
|
+
showError: (message) => { throw new Error(message); },
|
|
201
|
+
createExtensionUIContext: () => ({ custom: (create) => {
|
|
202
|
+
modelScreen = Promise.resolve().then(async () => {
|
|
203
|
+
const panel = create(tui, {}, {}, () => panel.dispose());
|
|
204
|
+
try {
|
|
205
|
+
await panel.ready;
|
|
206
|
+
if (!panel.render(80).some((line) => line.includes("compat-model")))
|
|
207
|
+
throw new Error("Pi model selection has changed.");
|
|
208
|
+
panel.handleInput("\x1b");
|
|
209
|
+
}
|
|
210
|
+
finally {
|
|
211
|
+
panel.dispose();
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
return modelScreen;
|
|
215
|
+
} }),
|
|
216
|
+
});
|
|
217
|
+
host.showModelSelector("compat-model");
|
|
218
|
+
if (!modelScreen)
|
|
219
|
+
throw new Error("Pi bypasses the styled model screen.");
|
|
220
|
+
await modelScreen;
|
|
221
|
+
}
|
|
222
|
+
//# sourceMappingURL=command-policy.js.map
|