osdy-pi 0.1.8 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +209 -161
- package/bin/osdy-pi.mjs +127 -0
- package/extensions/osdy-pi/account-profiles.test.ts +517 -0
- package/extensions/osdy-pi/account-profiles.ts +581 -0
- package/extensions/osdy-pi/animation.ts +47 -5
- package/extensions/osdy-pi/constants.ts +282 -103
- package/extensions/osdy-pi/diff-panel.ts +78 -24
- package/extensions/osdy-pi/editor-settings.test.ts +163 -0
- package/extensions/osdy-pi/editor-settings.ts +112 -0
- package/extensions/osdy-pi/metrics.ts +8 -135
- package/extensions/osdy-pi/plugin-events.ts +26 -0
- package/extensions/osdy-pi/profile-label.ts +29 -0
- package/extensions/osdy-pi/runtime-helpers.test.ts +26 -0
- package/extensions/osdy-pi/runtime-helpers.ts +87 -44
- package/extensions/osdy-pi/runtime.test.ts +62 -0
- package/extensions/osdy-pi/runtime.ts +256 -64
- package/extensions/osdy-pi/types.ts +33 -10
- package/extensions/osdy-pi/ui.test.ts +51 -0
- package/extensions/osdy-pi/ui.ts +298 -114
- package/extensions/osdy-pi/utils.ts +43 -1
- package/extensions/osdy-pi/working-tree.ts +25 -6
- package/package.json +22 -5
- package/scripts/osdy-pi-account-profiles.mjs +501 -0
- package/themes/osdy-pi-catppuccin-frappe.json +94 -0
- package/themes/osdy-pi-catppuccin-latte.json +94 -0
- package/themes/osdy-pi-catppuccin-macchiato.json +94 -0
- package/themes/osdy-pi-catppuccin-mocha.json +94 -0
- package/themes/osdy-pi-dark.json +0 -6
- package/themes/osdy-pi-dracula.json +83 -0
- package/themes/osdy-pi-kanagawa-dragon.json +91 -0
- package/themes/osdy-pi-kanagawa-lotus.json +92 -0
- package/themes/osdy-pi-kanagawa-wave.json +91 -0
- package/themes/osdy-pi-lucent-orange.json +80 -0
- package/themes/osdy-pi-matrix.json +83 -0
- package/themes/osdy-pi-new.json +91 -0
- package/themes/osdy-pi-sexy.json +84 -0
- package/themes/osdy-pi-tokyo-night.json +83 -0
- package/themes/osdy-pi-light.json +0 -84
- package/themes/osdy-pi-simple.json +0 -83
package/README.md
CHANGED
|
@@ -1,184 +1,238 @@
|
|
|
1
|
-
# Osdy Pi
|
|
1
|
+
# Osdy Pi — a themed, responsive Pi workspace
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Osdy Pi gives [Pi](https://github.com/earendil-works/pi) a themed, responsive terminal presentation with a header, editor, working indicator, and Git view. Visit the [Osdy landing page](https://landing-osdy.vercel.app/).
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
<img width="1857" height="847" alt="Osdy Pi interface" src="https://github.com/user-attachments/assets/028eeb14-3f43-4f1c-9603-0c55a8d2856d" />
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Quick start
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
- **Dark theme:** `osdy-pi-dark`, enabled by default when the package starts.
|
|
12
|
-
- **Light theme:** `osdy-pi-light`, with the same Osdy palette adapted for light terminals.
|
|
13
|
-
- **Simple theme:** `osdy-pi-simple`, a blue/red/slate console theme for the full Pi interface.
|
|
14
|
-
- **Custom header:** two selectable header styles with responsive status metadata: `osdy-theme` (default) and `classic`.
|
|
15
|
-
- **Custom editor:** full-width framed input area with model, thinking, token, cost, and context status.
|
|
16
|
-
- **Custom working indicator:** a dedicated working widget/spinner appears above the text box, outside the editor frame.
|
|
17
|
-
- **Clean layout:** the built-in working row is hidden while Osdy Pi is enabled to avoid duplicated UI.
|
|
18
|
-
- **Optional audio notifications:** configurable `.mp3`/`.wav` files for `completion`, `error`, `permission`, and `question` events on macOS and Windows.
|
|
19
|
-
|
|
20
|
-
<img width="1280" height="433" alt="image" src="https://github.com/user-attachments/assets/20c7624d-9ad8-4494-97fb-6b6d81aaf328" />
|
|
21
|
-
|
|
22
|
-
## Install in Pi
|
|
23
|
-
|
|
24
|
-
Install the published package from npm:
|
|
9
|
+
Install from npm:
|
|
25
10
|
|
|
26
11
|
```bash
|
|
27
12
|
pi install npm:osdy-pi
|
|
28
13
|
```
|
|
29
14
|
|
|
30
|
-
|
|
15
|
+
Or install directly from GitHub:
|
|
31
16
|
|
|
32
17
|
```bash
|
|
33
18
|
pi install git:github.com/OsdyOrtiz/Osdy-Pi
|
|
34
19
|
```
|
|
35
20
|
|
|
36
|
-
|
|
21
|
+
Start Pi normally:
|
|
37
22
|
|
|
38
23
|
```bash
|
|
39
24
|
pi
|
|
40
25
|
```
|
|
41
26
|
|
|
42
|
-
Osdy Pi
|
|
27
|
+
`pi install` installs Osdy Pi's extension resources. When you later run plain `pi`, a valid Osdy default account automatically hands off once to the bundled launcher and resumes the saved session under that profile. With no default, Pi remains unmanaged; run `/osdy-account` to create a profile and establish a default. On session start, Osdy Pi enables its UI when a UI is available and preserves your selected Pi theme.
|
|
43
28
|
|
|
44
|
-
##
|
|
29
|
+
## OpenAI account profiles
|
|
45
30
|
|
|
46
|
-
|
|
31
|
+
Osdy Pi can keep multiple ChatGPT Plus/Pro accounts authenticated and let you choose which one starts Pi. `personal` and `work` are only examples—you can create as many named profiles as you need.
|
|
47
32
|
|
|
48
|
-
|
|
49
|
-
|
|
33
|
+
### Create and use profiles
|
|
34
|
+
|
|
35
|
+
**In Pi, run `/osdy-account`** to open the complete account manager:
|
|
36
|
+
|
|
37
|
+
| Action | Behavior |
|
|
38
|
+
| --- | --- |
|
|
39
|
+
| **Switch** | Restarts Pi safely with another profile, resumes the current saved session, and makes that profile the default. |
|
|
40
|
+
| **Add** | Creates an isolated profile without restarting or changing the default. Select it with **Switch**, then run `/login`. |
|
|
41
|
+
| **Default** | Shows, changes, or clears the profile used by future plain installed `pi` and `npm run pi:dev` launches. It does not switch the current process. |
|
|
42
|
+
| **Rename** | Renames an inactive profile. The default follows the new name when applicable. |
|
|
43
|
+
| **Remove** | Permanently deletes an inactive profile after exact-name confirmation. Removing the default requires a replacement. |
|
|
44
|
+
| **Account info** | Shows the available profiles and marks the active and default profiles without reading credentials. |
|
|
45
|
+
|
|
46
|
+
Pi does not expose a supported API for extensions to invoke its OAuth login dialog. After switching to a newly created profile, run Pi's native `/login` and choose **ChatGPT Plus/Pro (Codex)**. This is the only step that remains a separate Pi command; it does not require leaving Pi or opening another terminal.
|
|
47
|
+
|
|
48
|
+
Terminal commands remain available as recovery and automation alternatives:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# Create a profile without launching or changing the default.
|
|
52
|
+
osdy-pi account create personal
|
|
53
|
+
|
|
54
|
+
# Legacy recovery flow: create a profile and open Pi for /login.
|
|
55
|
+
osdy-pi account add work
|
|
56
|
+
|
|
57
|
+
# List profiles, choose the default, or launch one now.
|
|
58
|
+
osdy-pi account list
|
|
59
|
+
osdy-pi account default personal
|
|
60
|
+
osdy-pi account default
|
|
61
|
+
osdy-pi account use personal
|
|
62
|
+
|
|
63
|
+
# Rename a profile, or permanently remove an inactive profile.
|
|
64
|
+
osdy-pi account rename work consulting
|
|
65
|
+
osdy-pi account remove consulting --confirm consulting
|
|
66
|
+
|
|
67
|
+
# Removing the default requires an existing replacement.
|
|
68
|
+
osdy-pi account remove personal --confirm personal --replacement work
|
|
69
|
+
|
|
70
|
+
# Remove the preference without removing any profile.
|
|
71
|
+
osdy-pi account default --clear
|
|
50
72
|
```
|
|
51
73
|
|
|
52
|
-
|
|
74
|
+
Profile names accept lowercase letters, numbers, and hyphens, up to 63 characters. Spaces, paths, uppercase letters, and the reserved names `default`, `profiles`, and `auth.json` are rejected. `account add` opens a profile for login but does not change the default.
|
|
75
|
+
|
|
76
|
+
### See and switch the active account
|
|
77
|
+
|
|
78
|
+
When Pi was launched through a profile, Osdy Pi shows its profile name in the editor:
|
|
79
|
+
|
|
80
|
+
- **Simple/native editor:** beside the model, for example `gpt-5.6-sol · personal · think high`.
|
|
81
|
+
- **Extended/framed editor:** `personal` replaces the `Osdy-Pi` title.
|
|
82
|
+
- **No managed profile:** the existing model line and `Osdy-Pi` title remain unchanged.
|
|
83
|
+
|
|
84
|
+
`account use <name>` saves that existing profile as the default before it starts Pi. Inside Pi, `/osdy-account` does the same after you select another profile. Osdy Pi waits for active work to finish, starts the replacement Pi with the current saved session, confirms that the new Pi process started, and only then closes the previous process. This is a controlled restart, not an in-process credential swap.
|
|
85
|
+
|
|
86
|
+
To resume a specific session directly from the terminal:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
osdy-pi account use work -- --session /absolute/path/to/session.jsonl
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
> **Privacy:** only Pi's managed `auth.json` is isolated per profile. Session history, settings, installed packages, and extension resources are shared, so every profile can access that local state. Osdy Pi never reads, copies, prints, or passes OAuth credentials. It keeps Pi's canonical `openai-codex` provider and delegates authentication to Pi's built-in `/login` flow.
|
|
93
|
+
|
|
94
|
+
### Rename and permanently remove profiles
|
|
95
|
+
|
|
96
|
+
Use `osdy-pi account rename <old> <new>` to rename an existing inactive profile. If it was the default, its default selection follows the new name.
|
|
97
|
+
|
|
98
|
+
Use `osdy-pi account remove <name> --confirm <name>` for a non-default profile. This permanently deletes its isolated profile directory. Removing the default additionally requires `--replacement <other>`; the existing, different replacement becomes the default before deletion. A replacement is rejected for non-default removal.
|
|
99
|
+
|
|
100
|
+
Before rename or removal, close this Pi process when it uses the target and **manually close every other Pi process using that target profile**. Osdy Pi does not scan or stop other processes. Inside Pi, use `/osdy-account` (or `/osdy-account rename` / `remove`); the guided flow shows the active profile but refuses changes to it until you Switch first, asks for a new default when needed, and requires typing the exact profile name. Cancellation changes nothing. Do not start two Pi processes with the same `--session` path.
|
|
101
|
+
|
|
102
|
+
## What ships
|
|
103
|
+
|
|
104
|
+
| Area | Included behavior |
|
|
105
|
+
| --- | --- |
|
|
106
|
+
| Themes | 14 built-in themes, including Osdy, Kanagawa, Dracula, Catppuccin, Matrix, and Lucent Orange palettes |
|
|
107
|
+
| Header | Selectable `osdy-theme` and `classic` header/mascot styles |
|
|
108
|
+
| Input | Responsive auto editor by default, with selectable simple Pi-native or extended framed modes |
|
|
109
|
+
| Status | Custom working spinner, responsive footer metrics, and dynamic extension statuses |
|
|
110
|
+
| Git | Working-tree summary and a centered, filterable diff panel |
|
|
111
|
+
| Audio | Optional event sounds on macOS and Windows |
|
|
112
|
+
|
|
113
|
+
<img width="1280" height="433" alt="Osdy Pi header and editor" src="https://github.com/user-attachments/assets/20c7624d-9ad8-4494-97fb-6b6d81aaf328" />
|
|
114
|
+
|
|
115
|
+
## Appearance
|
|
116
|
+
|
|
117
|
+
### Themes
|
|
118
|
+
|
|
119
|
+
| Theme | Use |
|
|
120
|
+
| --- | --- |
|
|
121
|
+
| `osdy-pi-new` | Landing palette: cyan, violet, silver, and navy. |
|
|
122
|
+
| `osdy-pi-dark` | Dark alternative. |
|
|
123
|
+
| `osdy-pi-sexy` | Gentleman neon pink palette. |
|
|
124
|
+
| `osdy-pi-tokyo-night` | Tokyo Night dark palette. |
|
|
125
|
+
| `osdy-pi-kanagawa-wave` | Kanagawa Wave dark palette. |
|
|
126
|
+
| `osdy-pi-kanagawa-dragon` | Kanagawa Dragon dark palette. |
|
|
127
|
+
| `osdy-pi-kanagawa-lotus` | Kanagawa Lotus light palette. |
|
|
128
|
+
| `osdy-pi-dracula` | Dracula Classic dark palette. |
|
|
129
|
+
| `osdy-pi-catppuccin-latte` | Catppuccin Latte light palette. |
|
|
130
|
+
| `osdy-pi-catppuccin-frappe` | Catppuccin Frappé dark palette. |
|
|
131
|
+
| `osdy-pi-catppuccin-macchiato` | Catppuccin Macchiato dark palette. |
|
|
132
|
+
| `osdy-pi-catppuccin-mocha` | Catppuccin Mocha dark palette. |
|
|
133
|
+
| `osdy-pi-matrix` | OpenCode Matrix dark palette. |
|
|
134
|
+
| `osdy-pi-lucent-orange` | Lucent Orange dark palette with terminal-background passthrough. |
|
|
135
|
+
|
|
136
|
+
Osdy Pi preserves your selected Pi theme when it enables, reapplies, or disables its UI. Choose any theme in Pi:
|
|
53
137
|
|
|
54
138
|
```text
|
|
55
|
-
|
|
56
|
-
osdy-pi-light
|
|
57
|
-
osdy-pi-simple
|
|
139
|
+
/settings
|
|
58
140
|
```
|
|
59
141
|
|
|
60
|
-
|
|
142
|
+
Or set the theme in Pi's `settings.json`:
|
|
61
143
|
|
|
62
144
|
```json
|
|
63
145
|
{
|
|
64
|
-
"theme": "osdy-pi-
|
|
146
|
+
"theme": "osdy-pi-sexy"
|
|
65
147
|
}
|
|
66
148
|
```
|
|
67
149
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
## Commands
|
|
150
|
+
### Header, mascot, and animation
|
|
71
151
|
|
|
72
|
-
|
|
152
|
+
`osdy-theme` is the default header style; `classic` is the alternative. In normal mode, both styles render their full selected header and mascot. The header animation and mascot edge glow resolve through the active theme, so each installed palette supplies its own accents. Use `/osdy-pi osdy-theme` or `/osdy-pi classic`, or their direct aliases `/osdy-pi-osdy-theme` and `/osdy-pi-classic`.
|
|
73
153
|
|
|
74
|
-
|
|
75
|
-
/osdy-pi enable
|
|
76
|
-
/osdy-pi disable
|
|
77
|
-
/osdy-pi status
|
|
78
|
-
/osdy-pi sound setup
|
|
79
|
-
/osdy-pi working-tree on
|
|
80
|
-
/osdy-pi working-tree off
|
|
81
|
-
/osdy-pi working-tree toggle
|
|
82
|
-
/osdy-pi working-tree status
|
|
83
|
-
/osdy-pi working-tree position top
|
|
84
|
-
/osdy-pi working-tree position bottom
|
|
85
|
-
/osdy-pi diff
|
|
86
|
-
/osdy-pi osdy-theme
|
|
87
|
-
/osdy-pi classic
|
|
88
|
-
/osdy-pi-osdy-theme
|
|
89
|
-
/osdy-pi-classic
|
|
90
|
-
```
|
|
154
|
+
Animation is enabled by default with an intro animation. Configure it through `OSDY_PI_ANIMATION`:
|
|
91
155
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
- `working-tree position top|bottom` moves the summary widget above or below the editor.
|
|
98
|
-
- `diff` opens a wizard-style in-app diff viewer to inspect the current per-file diff without leaving Pi.
|
|
99
|
-
- `osdy-theme` is the default OsdyTheme header with pink, cyan, and purple styling, plus the mascot glow on the right edge.
|
|
100
|
-
- `classic` keeps the previous classic header shape with the shared mascot.
|
|
101
|
-
- `/osdy-pi-osdy-theme` and `/osdy-pi-classic` are direct aliases.
|
|
156
|
+
| Value | Result |
|
|
157
|
+
| --- | --- |
|
|
158
|
+
| `0`, `off` | Static art |
|
|
159
|
+
| `1`, `on`, `continuous` | Continuous animation |
|
|
160
|
+
| `intro` | Intro animation, then static art |
|
|
102
161
|
|
|
103
|
-
|
|
162
|
+
### Responsive layout
|
|
104
163
|
|
|
105
|
-
|
|
164
|
+
| Terminal mode | Header and mascot | Editor and Git | Footer |
|
|
165
|
+
| --- | --- | --- | --- |
|
|
166
|
+
| Normal | Full selected header and mascot side by side | Auto mode shows the framed editor by default; simple selects Pi's native editor and extended selects the framed editor; Git summary when enabled | Native editor: model/thinking, usage, path/branch, then statuses; framed editor: path/branch then statuses |
|
|
167
|
+
| Compact (72+ columns) | Proportionally scaled mascot above a readable header, reduced only when needed | Selected editor mode and Git behavior | Same editor-aware footer behavior as normal/small modes |
|
|
168
|
+
| Small (<72 columns) | Mascot only; art and tone map scale proportionally | Pi native editor for every editor mode; Git summary hidden | Model + styled thinking level, usage, path/branch, then dynamic extension statuses (except Pi Lens) |
|
|
106
169
|
|
|
107
|
-
|
|
170
|
+
Small and compact modes trim only fully empty mascot-art and tone-map margins before applying one proportional width-and-height scale; mascot width starts near four-fifths of the available width. The header moves below the mascot as soon as side-by-side width would force the mascot into an additional width-limited reduction. Compact headers retain their source art when it fits and reduce proportionally only when a width or row bound requires it. Compact headers and mascots share a bounded terminal-row budget, so the header is omitted rather than collapsed into an unreadable one-row logo when there is not enough vertical space. The small-mode footer places the model and styled bare thinking level above usage, path/branch, and dynamic extension statuses. Pi Lens's footer status is hidden in small mode, but Pi Lens continues running. Usage includes input/output/cache-read/cache-write tokens, cost, and context. Extension statuses are supplied dynamically by Pi/extensions and may include Osdy Pi, MCP, or LSP; they are not hardcoded.
|
|
108
171
|
|
|
109
|
-
|
|
172
|
+
The editor mode and working-tree visibility preference persist globally across Pi reloads and sessions, shared by all projects. They are saved in `$PI_CODING_AGENT_DIR/extensions/osdy-pi/settings.json`, or `~/.pi/agent/extensions/osdy-pi/settings.json` when `PI_CODING_AGENT_DIR` is unset. The selected editor mode and working-tree placement are restored when the terminal moves normal → small → normal.
|
|
110
173
|
|
|
111
|
-
|
|
112
|
-
- previews the top changed files;
|
|
113
|
-
- refreshes automatically when Pi finishes mutating tools such as `edit`, `write`, `ast_grep_replace`, or `bash`;
|
|
114
|
-
- is intentionally scoped to changes observed during Pi-driven work for now.
|
|
115
|
-
|
|
116
|
-
Use these commands to control it:
|
|
174
|
+
## Commands
|
|
117
175
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
176
|
+
| Group | Command |
|
|
177
|
+
| --- | --- |
|
|
178
|
+
| Main | `/osdy-pi` |
|
|
179
|
+
| Main | `/osdy-pi enable\|disable\|status` |
|
|
180
|
+
| Accounts | `/osdy-account` |
|
|
181
|
+
| Header | `/osdy-pi osdy-theme\|classic` |
|
|
182
|
+
| Editor | `/osdy-pi editor auto\|extended\|simple\|on\|off\|toggle\|status` |
|
|
183
|
+
| Working tree | `/osdy-pi working-tree on\|off\|toggle\|status` |
|
|
184
|
+
| Working tree | `/osdy-pi working-tree position top\|bottom\|status` |
|
|
185
|
+
| Audio | `/osdy-pi sound setup` |
|
|
186
|
+
| Diff | `/osdy-pi diff` |
|
|
187
|
+
| Alias | `/osdy-pi-osdy-theme` |
|
|
188
|
+
| Alias | `/osdy-pi-classic` |
|
|
127
189
|
|
|
128
|
-
|
|
190
|
+
`/osdy-pi` reports status. `enable` applies the Osdy Pi UI without changing the selected Pi theme; `disable` restores Pi's built-in header, editor, footer, and working row while preserving that theme. The editor mode, working-tree visibility, and sound configuration persist globally; other UI toggles are current-session desired state.
|
|
129
191
|
|
|
130
|
-
|
|
131
|
-
2. open its patch in a second centered view
|
|
132
|
-
3. return with `esc` / `backspace` or close with `q`
|
|
192
|
+
## Editor and working indicator
|
|
133
193
|
|
|
134
|
-
|
|
194
|
+
The default `auto` editor mode preserves the responsive behavior: it uses the framed editor when space permits and Pi's native editor on small terminals. Select `simple` for Pi's native editor at every width, or `extended` to request the framed editor explicitly: `/osdy-pi editor auto|extended|simple`. Small terminals always use Pi's native editor, including when `extended` is selected. The legacy commands remain compatible where feasible: `on` maps to `extended`, `off` maps to `simple`, and `toggle` switches between extended and simple.
|
|
135
195
|
|
|
136
|
-
-
|
|
137
|
-
- patch view: `PgUp` / `PgDn`
|
|
138
|
-
- back: `esc` / `backspace` or `←`
|
|
139
|
-
- close: `q`
|
|
196
|
+
In auto or extended mode at a non-small width, the framed editor shows the model and thinking level in its title and session usage in its footer. For an account-profile launch, the left title shows the active profile name instead of `Osdy-Pi`. When the native editor is effective (simple mode or any small terminal), the Osdy footer instead shows model, active profile when present, thinking, and usage rows before its path/branch and status rows. It uses the currently active Pi/Osdy theme palette; no separate editor theme selector exists. Usage covers input, output, cache read, cache write when present, cost, and context. If Pi supports autocomplete, the editor uses Pi's native autocomplete rendering while the completion UI is visible.
|
|
140
197
|
|
|
141
|
-
|
|
198
|
+
A custom spinner appears above the editor while work is active. Osdy Pi hides Pi's built-in working row while enabled to avoid a duplicate indicator.
|
|
142
199
|
|
|
143
|
-
|
|
200
|
+
## Working tree and diff
|
|
144
201
|
|
|
145
|
-
-
|
|
146
|
-
- `error`: a real tool execution failure occurs during the flow.
|
|
147
|
-
- `permission`: reserved for future explicit Pi approval hooks, dormant by default today.
|
|
148
|
-
- `question`: reserved for future explicit Pi question hooks, dormant by default today.
|
|
202
|
+
The working-tree summary is enabled by default. It reads the repository state at session start, including existing changes, and reports staged, unstaged, and untracked counts with total `+/-` changes. It also has clean and unavailable states. After successful `edit`, `write`, `ast_grep_replace`, or `bash` tool execution, it refreshes.
|
|
149
203
|
|
|
150
|
-
|
|
204
|
+
Use `working-tree position top` or `bottom` to place the summary above or below the editor. The widget supplies trailing blank space and adds leading separation when it is below the editor or the spinner is active, keeping the surrounding layout readable without promising a fixed number of blank lines in every state.
|
|
151
205
|
|
|
152
|
-
-
|
|
153
|
-
- Windows
|
|
206
|
+
`/osdy-pi diff` opens a centered diff panel. Type to filter paths, then inspect staged, unstaged, or untracked patches for a file.
|
|
154
207
|
|
|
155
|
-
|
|
208
|
+
| Action | Controls |
|
|
209
|
+
| --- | --- |
|
|
210
|
+
| Move selection | Arrow keys or `j` / `k` |
|
|
211
|
+
| Open a patch | `enter`, `right`, `space`, or `l` |
|
|
212
|
+
| Scroll a patch | `PgUp` / `PgDn` (or `space` forward) |
|
|
213
|
+
| Go back | `esc`, `backspace`, `left`, or `h` |
|
|
214
|
+
| Close | `q` or `ctrl+c` |
|
|
156
215
|
|
|
157
|
-
|
|
216
|
+
## Audio notifications
|
|
158
217
|
|
|
159
|
-
|
|
218
|
+
Osdy Pi can play readable `.mp3` or `.wav` files on macOS and Windows. Other platforms safely skip playback.
|
|
160
219
|
|
|
161
|
-
|
|
220
|
+
| Event | Current meaning |
|
|
221
|
+
| --- | --- |
|
|
222
|
+
| `completion` | An agent run ends. |
|
|
223
|
+
| `error` | The first failed tool execution in an agent run. |
|
|
224
|
+
| `permission` | Hook is available but dormant until an explicit Pi approval integration uses it. |
|
|
225
|
+
| `question` | Hook is available but dormant until an explicit Pi question integration uses it. |
|
|
162
226
|
|
|
163
|
-
|
|
227
|
+
Run the guided wizard:
|
|
164
228
|
|
|
165
229
|
```text
|
|
166
230
|
/osdy-pi sound setup
|
|
167
231
|
```
|
|
168
232
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
- walks through `completion`, `error`, `permission`, and `question`;
|
|
172
|
-
- lets you keep, replace, clear, or skip each event;
|
|
173
|
-
- validates every selected path before save;
|
|
174
|
-
- blocks save if any selected file is missing, unreadable, not a regular file, or not `.mp3`/`.wav`;
|
|
175
|
-
- stores accepted settings globally at `~/.pi/agent/extensions/osdy-pi/audio-notifications.json` (or `$PI_CODING_AGENT_DIR/extensions/osdy-pi/audio-notifications.json` when that env var is set).
|
|
176
|
-
|
|
177
|
-
Saved global sound paths apply across restarts and projects that use Osdy Pi.
|
|
233
|
+
It configures `completion`, `error`, `permission`, and `question`; validates selected readable audio files; and saves global settings to `~/.pi/agent/extensions/osdy-pi/audio-notifications.json`, or `$PI_CODING_AGENT_DIR/extensions/osdy-pi/audio-notifications.json` when `PI_CODING_AGENT_DIR` is set.
|
|
178
234
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
You can still pass sound paths as Pi flags when starting the session:
|
|
235
|
+
Startup flags can override a saved path per event:
|
|
182
236
|
|
|
183
237
|
```bash
|
|
184
238
|
pi \
|
|
@@ -188,63 +242,49 @@ pi \
|
|
|
188
242
|
--osdy-pi-sound-question /absolute/path/question.wav
|
|
189
243
|
```
|
|
190
244
|
|
|
191
|
-
Precedence is
|
|
245
|
+
Precedence is startup flag, then saved global setting, then unconfigured. Empty flags do not override saved settings; relative startup paths resolve from the current working directory, while the wizard saves normalized absolute paths. Missing, unreadable, or unsupported files are skipped safely.
|
|
246
|
+
|
|
247
|
+
## Local install and development
|
|
192
248
|
|
|
193
|
-
|
|
194
|
-
2. saved global Osdy Pi setting
|
|
195
|
-
3. unconfigured
|
|
249
|
+
For the normal in-Pi development flow, no global `osdy-pi` link is required:
|
|
196
250
|
|
|
197
|
-
|
|
251
|
+
1. Start the local extension:
|
|
198
252
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
- `~` expands to your home directory.
|
|
203
|
-
- Invalid, unreadable, or unsupported files are skipped at playback time without changing existing UI behavior.
|
|
204
|
-
- If a file was valid when saved but later disappears or becomes unreadable, Osdy Pi fails safely and skips playback for that event.
|
|
205
|
-
- Audio notifications and sound setup are additive only, they do not change the current header, editor, footer, working indicator, theme, or commands.
|
|
253
|
+
```bash
|
|
254
|
+
npm run pi:dev
|
|
255
|
+
```
|
|
206
256
|
|
|
207
|
-
|
|
257
|
+
2. Inside Pi, run `/osdy-account`.
|
|
258
|
+
3. Choose **Add**, enter a profile name, then choose **Switch** and select it.
|
|
259
|
+
4. After the managed restart, run `/login` and choose **ChatGPT Plus/Pro (Codex)**.
|
|
260
|
+
5. From then on, `npm run pi:dev` starts the default profile automatically. Use `/osdy-account` for every profile-management action.
|
|
208
261
|
|
|
209
|
-
|
|
262
|
+
The terminal interface remains available for recovery and automated testing:
|
|
210
263
|
|
|
211
264
|
```bash
|
|
212
|
-
npm run pi:dev
|
|
265
|
+
npm run pi:dev -- account create personal
|
|
266
|
+
npm run pi:dev -- account list
|
|
267
|
+
npm run pi:dev -- account use personal
|
|
268
|
+
npm run pi:dev -- account default personal
|
|
269
|
+
npm run pi:dev -- account rename personal private
|
|
270
|
+
npm run pi:dev -- account remove private --confirm private
|
|
213
271
|
```
|
|
214
272
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
You can still launch it manually if needed:
|
|
273
|
+
`npm run pi:dev` launches `pi -e <absolute repository root>` with `PI_CODING_AGENT_DIR=<absolute repository root>/.pi-dev` when no default is set. If its `.pi-dev` metadata names a valid profile, it routes through this checkout's local launcher and starts that profile while retaining `-e <absolute repository root>`. The development `.pi-dev` profile store and the installed Pi profile store are separate. For an installed package, plain `pi` loads extension resources; at startup Osdy Pi hands off through its bundled launcher when the installed store has a valid default, while no default leaves ordinary unmanaged Pi running. Account commands use this checkout's local launcher, so no global `osdy-pi` link is needed. The development extension root is inherited by profile launches, keeping the local extension loaded after an `/osdy-account` handoff. The manual equivalent is:
|
|
218
274
|
|
|
219
275
|
```bash
|
|
220
|
-
PI_CODING_AGENT_DIR="$PWD/.pi-dev" pi -e
|
|
276
|
+
PI_CODING_AGENT_DIR="$PWD/.pi-dev" OSDY_PI_DEV_EXTENSION_ROOT="$PWD" pi -e "$PWD"
|
|
221
277
|
```
|
|
222
278
|
|
|
223
|
-
|
|
279
|
+
Install a local checkout into Pi with:
|
|
224
280
|
|
|
225
281
|
```bash
|
|
226
282
|
pi install /absolute/path/to/Osdy-Pi
|
|
227
283
|
```
|
|
228
284
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
## Package contents
|
|
232
|
-
|
|
233
|
-
```text
|
|
234
|
-
themes/osdy-pi-dark.json
|
|
235
|
-
themes/osdy-pi-light.json
|
|
236
|
-
themes/osdy-pi-simple.json
|
|
237
|
-
extensions/osdy-pi.ts
|
|
238
|
-
extensions/osdy-pi/
|
|
239
|
-
```
|
|
285
|
+
After changing a local extension, run `/reload` or restart Pi.
|
|
240
286
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
The Pi manifest is declared in `package.json` through `pi.themes` and `pi.extensions`, so Pi can discover the themes and extension after installation.
|
|
244
|
-
|
|
245
|
-
## Development
|
|
246
|
-
|
|
247
|
-
If you are working on the package locally, you can run:
|
|
287
|
+
For package checks and local development:
|
|
248
288
|
|
|
249
289
|
```bash
|
|
250
290
|
npm run typecheck
|
|
@@ -252,16 +292,24 @@ npm run lint
|
|
|
252
292
|
npm run pi:dev
|
|
253
293
|
```
|
|
254
294
|
|
|
255
|
-
|
|
295
|
+

|
|
296
|
+
|
|
297
|
+
## Limits and troubleshooting
|
|
298
|
+
|
|
299
|
+
- The custom UI requires a Pi session with a UI; otherwise it does not mount.
|
|
300
|
+
- A compact terminal stacks a scaled mascot over a source-size header when it fits, reducing the header only when needed; below 72 columns it switches to mascot-only, native editor, and no Git summary until space returns.
|
|
301
|
+
- The Git summary reports unavailable when Git commands cannot read a working tree.
|
|
302
|
+
- Diff patches depend on readable repository files; a file whose patch cannot load shows the reported error in the panel.
|
|
303
|
+
- Audio playback is limited to macOS and Windows and to readable `.mp3`/`.wav` files.
|
|
256
304
|
|
|
257
|
-
|
|
305
|
+
## Disable, uninstall, and license
|
|
306
|
+
|
|
307
|
+
Temporarily turn off the custom UI:
|
|
258
308
|
|
|
259
309
|
```text
|
|
260
310
|
/osdy-pi disable
|
|
261
311
|
```
|
|
262
312
|
|
|
263
|
-
To remove the package
|
|
264
|
-
|
|
265
|
-
## License
|
|
313
|
+
To remove the package, use Pi's package-management command for installed packages.
|
|
266
314
|
|
|
267
315
|
MIT
|
package/bin/osdy-pi.mjs
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
3
|
+
import {
|
|
4
|
+
clearDefaultAccount,
|
|
5
|
+
ensureProfileLayout,
|
|
6
|
+
getSharedAgentDir,
|
|
7
|
+
listProfiles,
|
|
8
|
+
parseAccountCommand,
|
|
9
|
+
planDefaultLaunch,
|
|
10
|
+
planPiLaunch,
|
|
11
|
+
readDefaultAccount,
|
|
12
|
+
removeProfile,
|
|
13
|
+
renameProfile,
|
|
14
|
+
setDefaultAccount,
|
|
15
|
+
validateExistingProfile,
|
|
16
|
+
} from "../scripts/osdy-pi-account-profiles.mjs";
|
|
17
|
+
|
|
18
|
+
function writeStdout(message) {
|
|
19
|
+
process.stdout.write(`${message}\n`);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function writeStderr(message) {
|
|
23
|
+
process.stderr.write(`${message}\n`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function printUsage() {
|
|
27
|
+
writeStderr(
|
|
28
|
+
"Usage: osdy-pi account list | create <name> | add <name> | rename <old> <new> | remove <name> --confirm <name> [--replacement <other>] | use <name> [-- <pi args...] | default [<name> | --clear]",
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function boundedMessage(error) {
|
|
33
|
+
const message =
|
|
34
|
+
error instanceof Error ? error.message : "Unable to manage Osdy Pi accounts.";
|
|
35
|
+
return message.slice(0, 240);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function sendLauncherMessage(message) {
|
|
39
|
+
if (typeof process.send === "function") process.send(message);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function reportLauncherFailure(error) {
|
|
43
|
+
const message = boundedMessage(error);
|
|
44
|
+
sendLauncherMessage({ type: "osdy-pi-error", message });
|
|
45
|
+
writeStderr(message);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function startPi(plan) {
|
|
49
|
+
const child = spawn(plan.command, plan.args, {
|
|
50
|
+
stdio: "inherit",
|
|
51
|
+
env: { ...process.env, ...plan.env },
|
|
52
|
+
});
|
|
53
|
+
child.once("spawn", () => {
|
|
54
|
+
sendLauncherMessage({ type: "osdy-pi-ready" });
|
|
55
|
+
});
|
|
56
|
+
child.on("error", (error) => {
|
|
57
|
+
reportLauncherFailure(new Error(`Failed to start Pi: ${error.message}`));
|
|
58
|
+
process.exitCode = 1;
|
|
59
|
+
});
|
|
60
|
+
child.on("exit", (code, signal) => {
|
|
61
|
+
if (signal) process.kill(process.pid, signal);
|
|
62
|
+
else process.exitCode = code ?? 1;
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
const args = process.argv.slice(2);
|
|
68
|
+
const sharedAgentDir = getSharedAgentDir();
|
|
69
|
+
if (args.length === 0) {
|
|
70
|
+
const result = await planDefaultLaunch(sharedAgentDir);
|
|
71
|
+
if (result.defaultAccount.status === "invalid")
|
|
72
|
+
writeStderr("Ignoring invalid Osdy Pi default account metadata.");
|
|
73
|
+
startPi(result.plan);
|
|
74
|
+
} else {
|
|
75
|
+
const command = parseAccountCommand(args);
|
|
76
|
+
if (command.action === "list") {
|
|
77
|
+
const profiles = await listProfiles(sharedAgentDir);
|
|
78
|
+
if (profiles.length === 0)
|
|
79
|
+
writeStdout(
|
|
80
|
+
"No Osdy Pi accounts. Add one with: osdy-pi account add <name>",
|
|
81
|
+
);
|
|
82
|
+
else writeStdout(profiles.join("\n"));
|
|
83
|
+
} else if (command.action === "default") {
|
|
84
|
+
if (command.operation === "query") {
|
|
85
|
+
const account = await readDefaultAccount(sharedAgentDir);
|
|
86
|
+
if (account.status === "valid") writeStdout(account.profile);
|
|
87
|
+
else if (account.status === "unset") writeStdout("No default account.");
|
|
88
|
+
else
|
|
89
|
+
writeStdout("Default account metadata is invalid; no account selected.");
|
|
90
|
+
} else if (command.operation === "clear") {
|
|
91
|
+
await clearDefaultAccount(sharedAgentDir);
|
|
92
|
+
writeStdout("Default account cleared.");
|
|
93
|
+
} else {
|
|
94
|
+
await setDefaultAccount(sharedAgentDir, command.name);
|
|
95
|
+
writeStdout(`Default account set to ${command.name}.`);
|
|
96
|
+
}
|
|
97
|
+
} else if (command.action === "create") {
|
|
98
|
+
await ensureProfileLayout(sharedAgentDir, command.name);
|
|
99
|
+
writeStdout(
|
|
100
|
+
"Account profile created. Use /osdy-account Switch, then run /login and select ChatGPT Plus/Pro (Codex).",
|
|
101
|
+
);
|
|
102
|
+
} else if (command.action === "add") {
|
|
103
|
+
await ensureProfileLayout(sharedAgentDir, command.name);
|
|
104
|
+
writeStdout(
|
|
105
|
+
"Account profile is ready. In Pi, run /login and select ChatGPT Plus/Pro (Codex).",
|
|
106
|
+
);
|
|
107
|
+
startPi(planPiLaunch(sharedAgentDir, command.name));
|
|
108
|
+
} else if (command.action === "rename") {
|
|
109
|
+
await renameProfile(sharedAgentDir, command.oldName, command.newName);
|
|
110
|
+
writeStdout(`Account profile renamed to ${command.newName}.`);
|
|
111
|
+
} else if (command.action === "remove") {
|
|
112
|
+
await removeProfile(sharedAgentDir, command.name, {
|
|
113
|
+
confirmation: command.name,
|
|
114
|
+
replacement: command.replacement,
|
|
115
|
+
});
|
|
116
|
+
writeStdout(`Account profile ${command.name} permanently removed.`);
|
|
117
|
+
} else {
|
|
118
|
+
await validateExistingProfile(sharedAgentDir, command.name);
|
|
119
|
+
await setDefaultAccount(sharedAgentDir, command.name);
|
|
120
|
+
startPi(planPiLaunch(sharedAgentDir, command.name, command.piArgs));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
} catch (error) {
|
|
124
|
+
reportLauncherFailure(error);
|
|
125
|
+
printUsage();
|
|
126
|
+
process.exitCode = 1;
|
|
127
|
+
}
|