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.
Files changed (39) hide show
  1. package/README.md +209 -161
  2. package/bin/osdy-pi.mjs +127 -0
  3. package/extensions/osdy-pi/account-profiles.test.ts +517 -0
  4. package/extensions/osdy-pi/account-profiles.ts +581 -0
  5. package/extensions/osdy-pi/animation.ts +47 -5
  6. package/extensions/osdy-pi/constants.ts +282 -103
  7. package/extensions/osdy-pi/diff-panel.ts +78 -24
  8. package/extensions/osdy-pi/editor-settings.test.ts +163 -0
  9. package/extensions/osdy-pi/editor-settings.ts +112 -0
  10. package/extensions/osdy-pi/metrics.ts +8 -135
  11. package/extensions/osdy-pi/plugin-events.ts +26 -0
  12. package/extensions/osdy-pi/profile-label.ts +29 -0
  13. package/extensions/osdy-pi/runtime-helpers.test.ts +26 -0
  14. package/extensions/osdy-pi/runtime-helpers.ts +87 -44
  15. package/extensions/osdy-pi/runtime.test.ts +62 -0
  16. package/extensions/osdy-pi/runtime.ts +256 -64
  17. package/extensions/osdy-pi/types.ts +33 -10
  18. package/extensions/osdy-pi/ui.test.ts +51 -0
  19. package/extensions/osdy-pi/ui.ts +298 -114
  20. package/extensions/osdy-pi/utils.ts +43 -1
  21. package/extensions/osdy-pi/working-tree.ts +25 -6
  22. package/package.json +22 -5
  23. package/scripts/osdy-pi-account-profiles.mjs +501 -0
  24. package/themes/osdy-pi-catppuccin-frappe.json +94 -0
  25. package/themes/osdy-pi-catppuccin-latte.json +94 -0
  26. package/themes/osdy-pi-catppuccin-macchiato.json +94 -0
  27. package/themes/osdy-pi-catppuccin-mocha.json +94 -0
  28. package/themes/osdy-pi-dark.json +0 -6
  29. package/themes/osdy-pi-dracula.json +83 -0
  30. package/themes/osdy-pi-kanagawa-dragon.json +91 -0
  31. package/themes/osdy-pi-kanagawa-lotus.json +92 -0
  32. package/themes/osdy-pi-kanagawa-wave.json +91 -0
  33. package/themes/osdy-pi-lucent-orange.json +80 -0
  34. package/themes/osdy-pi-matrix.json +83 -0
  35. package/themes/osdy-pi-new.json +91 -0
  36. package/themes/osdy-pi-sexy.json +84 -0
  37. package/themes/osdy-pi-tokyo-night.json +83 -0
  38. package/themes/osdy-pi-light.json +0 -84
  39. 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
- <img width="1857" height="847" alt="image" src="https://github.com/user-attachments/assets/028eeb14-3f43-4f1c-9603-0c55a8d2856d" />
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
- Theme package for [Pi](https://github.com/earendil-works/pi) with the Osdy terminal style: neon pink/purple colors, a custom ASCII header, and a framed editor experience.
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
- Visit the Osdy landing page: [landing-osdy.vercel.app](https://landing-osdy.vercel.app/).
7
+ ## Quick start
8
8
 
9
- ## What you get
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
- You can also install it directly from GitHub:
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
- Then start Pi normally:
21
+ Start Pi normally:
37
22
 
38
23
  ```bash
39
24
  pi
40
25
  ```
41
26
 
42
- Osdy Pi enables the `osdy-pi-dark` theme and custom UI automatically on `session_start`.
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
- ## Choose the theme manually
29
+ ## OpenAI account profiles
45
30
 
46
- If you only want to switch themes, open Pi settings:
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
- ```text
49
- /settings
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
- Then select one of these theme names:
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
- osdy-pi-dark
56
- osdy-pi-light
57
- osdy-pi-simple
139
+ /settings
58
140
  ```
59
141
 
60
- You can also set it in your Pi `settings.json`:
142
+ Or set the theme in Pi's `settings.json`:
61
143
 
62
144
  ```json
63
145
  {
64
- "theme": "osdy-pi-dark"
146
+ "theme": "osdy-pi-sexy"
65
147
  }
66
148
  ```
67
149
 
68
- Use `osdy-pi-light` if you prefer the light version, or `osdy-pi-simple` if you want the blue/red/slate palette across the whole console.
69
-
70
- ## Commands
150
+ ### Header, mascot, and animation
71
151
 
72
- Osdy Pi includes a small command group:
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
- ```text
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
- - `enable` applies the dark Osdy theme, custom header, custom editor, and clean layout.
93
- - `disable` restores Pi's built-in header, editor, footer, and working visibility, then switches back to the previous theme or `dark`.
94
- - `status` shows whether the Osdy Pi UI is currently enabled, including the active style.
95
- - `sound setup` opens the guided global sound-setup wizard for audio notifications.
96
- - `working-tree on|off|toggle|status` controls the persistent git working-tree summary widget.
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
- After changing a local extension, run `/reload` or restart Pi so the updated commands are registered.
162
+ ### Responsive layout
104
163
 
105
- ### Working tree widget
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
- Osdy Pi can show a persistent git working-tree summary above or below the editor.
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
- Current behavior:
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
- - shows file count, `+/-` totals, and staged/unstaged/new counts;
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
- ```text
119
- /osdy-pi working-tree on
120
- /osdy-pi working-tree off
121
- /osdy-pi working-tree toggle
122
- /osdy-pi working-tree status
123
- /osdy-pi working-tree position top
124
- /osdy-pi working-tree position bottom
125
- /osdy-pi diff
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
- The `/osdy-pi diff` viewer now behaves like a simple wizard and opens with a wider centered modal by default:
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
- 1. select a changed file in a centered modal
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
- Controls:
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
- - selector: `↑` / `↓` or `j` / `k`, then `enter` or `→`
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
- ## Audio notifications
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
- Osdy Pi can play your own sound files for these product-level events:
200
+ ## Working tree and diff
144
201
 
145
- - `completion`: the full orchestrator flow finishes and Pi returns control to input.
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
- Initial audio playback support is implemented for:
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
- - macOS
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
- Unsupported platforms fall back safely without crashing Osdy Pi.
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
- ### Supported files
216
+ ## Audio notifications
158
217
 
159
- Only readable `.mp3` and `.wav` files are accepted.
218
+ Osdy Pi can play readable `.mp3` or `.wav` files on macOS and Windows. Other platforms safely skip playback.
160
219
 
161
- ### Configure sounds
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
- The preferred setup path is the guided Osdy Pi wizard:
227
+ Run the guided wizard:
164
228
 
165
229
  ```text
166
230
  /osdy-pi sound setup
167
231
  ```
168
232
 
169
- The wizard:
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
- ### Startup flags still work
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 per event:
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
- 1. startup flag
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
- Notes:
251
+ 1. Start the local extension:
198
252
 
199
- - Empty or omitted flags mean that event does not override the saved global setting.
200
- - Relative startup-flag paths resolve from the current working directory.
201
- - The setup wizard saves normalized absolute paths for global settings.
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
- ## Local install
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
- If you cloned this repository and want to test it locally without colliding with an already installed global `osdy-pi`, use the isolated dev launcher:
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
- This command runs `pi -e .` with `PI_CODING_AGENT_DIR=.pi-dev`, so it uses a separate local Pi config/package/extensions directory and does not load your global installed `osdy-pi` package.
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
- To install it from a local path:
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
- ![Osdy Pi preview](https://raw.githubusercontent.com/OsdyOrtiz/Osdy-Pi/main/mapche1.png)
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
- `extensions/osdy-pi.ts` is the package entrypoint. The implementation lives in the modular `extensions/osdy-pi/` folder (runtime, UI, metrics, working controller, animation, border, and formatting helpers).
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
- ## Uninstall or turn off
295
+ ![Osdy Pi preview](https://raw.githubusercontent.com/OsdyOrtiz/Osdy-Pi/main/mapche1.png)
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
- To temporarily turn off the custom UI inside Pi:
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 completely, use Pi's package management command for installed packages.
264
-
265
- ## License
313
+ To remove the package, use Pi's package-management command for installed packages.
266
314
 
267
315
  MIT
@@ -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
+ }