pi-observability 1.0.0 → 1.3.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/.oxfmtrc.json +3 -0
- package/.oxlintrc.json +15 -0
- package/.zed/settings.json +222 -0
- package/DEVELOPMENT.md +243 -0
- package/README.md +66 -25
- package/demo-preview.gif +0 -0
- package/diff.png +0 -0
- package/extensions/lib/footer-engine/format.ts +67 -0
- package/extensions/lib/footer-engine/index.ts +55 -0
- package/extensions/lib/footer-engine/layout.ts +47 -0
- package/extensions/lib/footer-engine/segments.ts +94 -0
- package/extensions/lib/footer-engine/types.ts +53 -0
- package/extensions/lib/settings/domain.ts +161 -0
- package/extensions/lib/settings/index.ts +32 -0
- package/extensions/lib/settings/manager.ts +58 -0
- package/extensions/lib/settings/metadata.ts +114 -0
- package/extensions/lib/settings/storage.ts +38 -0
- package/extensions/lib/settings/tui.ts +44 -0
- package/extensions/lib/settings/types.ts +40 -0
- package/extensions/lib/storage/file-backend.ts +62 -0
- package/extensions/lib/storage/index.ts +33 -0
- package/extensions/lib/storage/json-store.ts +32 -0
- package/extensions/lib/storage/jsonl-store.ts +29 -0
- package/extensions/lib/storage/memory-backend.ts +37 -0
- package/extensions/lib/storage/types.ts +23 -0
- package/extensions/observability.ts +646 -428
- package/output.mp4 +0 -0
- package/package.json +37 -21
- package/tsconfig.json +12 -12
package/.oxfmtrc.json
ADDED
package/.oxlintrc.json
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
{
|
|
2
|
+
"lsp": {
|
|
3
|
+
"oxlint": {
|
|
4
|
+
"initialization_options": {
|
|
5
|
+
"settings": {
|
|
6
|
+
"configPath": "./.oxlintrc.json",
|
|
7
|
+
"run": "onType",
|
|
8
|
+
"disableNestedConfig": false,
|
|
9
|
+
"fixKind": "safe_fix",
|
|
10
|
+
"typeAware": true,
|
|
11
|
+
"unusedDisableDirectives": "deny"
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"oxfmt": {
|
|
16
|
+
"initialization_options": {
|
|
17
|
+
"settings": {
|
|
18
|
+
"configPath": "./vite.config.ts",
|
|
19
|
+
"run": "onSave"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"languages": {
|
|
25
|
+
"CSS": {
|
|
26
|
+
"format_on_save": "on",
|
|
27
|
+
"prettier": {
|
|
28
|
+
"allowed": false
|
|
29
|
+
},
|
|
30
|
+
"formatter": [
|
|
31
|
+
{
|
|
32
|
+
"language_server": {
|
|
33
|
+
"name": "oxfmt"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
"HTML": {
|
|
39
|
+
"format_on_save": "on",
|
|
40
|
+
"prettier": {
|
|
41
|
+
"allowed": false
|
|
42
|
+
},
|
|
43
|
+
"formatter": [
|
|
44
|
+
{
|
|
45
|
+
"language_server": {
|
|
46
|
+
"name": "oxfmt"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
"JavaScript": {
|
|
52
|
+
"format_on_save": "on",
|
|
53
|
+
"prettier": {
|
|
54
|
+
"allowed": false
|
|
55
|
+
},
|
|
56
|
+
"formatter": [
|
|
57
|
+
{
|
|
58
|
+
"language_server": {
|
|
59
|
+
"name": "oxfmt"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
],
|
|
63
|
+
"code_action": "source.fixAll.oxc"
|
|
64
|
+
},
|
|
65
|
+
"JSX": {
|
|
66
|
+
"format_on_save": "on",
|
|
67
|
+
"prettier": {
|
|
68
|
+
"allowed": false
|
|
69
|
+
},
|
|
70
|
+
"formatter": [
|
|
71
|
+
{
|
|
72
|
+
"language_server": {
|
|
73
|
+
"name": "oxfmt"
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
]
|
|
77
|
+
},
|
|
78
|
+
"JSON": {
|
|
79
|
+
"format_on_save": "on",
|
|
80
|
+
"prettier": {
|
|
81
|
+
"allowed": false
|
|
82
|
+
},
|
|
83
|
+
"formatter": [
|
|
84
|
+
{
|
|
85
|
+
"language_server": {
|
|
86
|
+
"name": "oxfmt"
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
]
|
|
90
|
+
},
|
|
91
|
+
"JSON5": {
|
|
92
|
+
"format_on_save": "on",
|
|
93
|
+
"prettier": {
|
|
94
|
+
"allowed": false
|
|
95
|
+
},
|
|
96
|
+
"formatter": [
|
|
97
|
+
{
|
|
98
|
+
"language_server": {
|
|
99
|
+
"name": "oxfmt"
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
]
|
|
103
|
+
},
|
|
104
|
+
"JSONC": {
|
|
105
|
+
"format_on_save": "on",
|
|
106
|
+
"prettier": {
|
|
107
|
+
"allowed": false
|
|
108
|
+
},
|
|
109
|
+
"formatter": [
|
|
110
|
+
{
|
|
111
|
+
"language_server": {
|
|
112
|
+
"name": "oxfmt"
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
]
|
|
116
|
+
},
|
|
117
|
+
"Less": {
|
|
118
|
+
"format_on_save": "on",
|
|
119
|
+
"prettier": {
|
|
120
|
+
"allowed": false
|
|
121
|
+
},
|
|
122
|
+
"formatter": [
|
|
123
|
+
{
|
|
124
|
+
"language_server": {
|
|
125
|
+
"name": "oxfmt"
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
]
|
|
129
|
+
},
|
|
130
|
+
"Markdown": {
|
|
131
|
+
"format_on_save": "on",
|
|
132
|
+
"prettier": {
|
|
133
|
+
"allowed": false
|
|
134
|
+
},
|
|
135
|
+
"formatter": [
|
|
136
|
+
{
|
|
137
|
+
"language_server": {
|
|
138
|
+
"name": "oxfmt"
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
]
|
|
142
|
+
},
|
|
143
|
+
"MDX": {
|
|
144
|
+
"format_on_save": "on",
|
|
145
|
+
"prettier": {
|
|
146
|
+
"allowed": false
|
|
147
|
+
},
|
|
148
|
+
"formatter": [
|
|
149
|
+
{
|
|
150
|
+
"language_server": {
|
|
151
|
+
"name": "oxfmt"
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
]
|
|
155
|
+
},
|
|
156
|
+
"SCSS": {
|
|
157
|
+
"format_on_save": "on",
|
|
158
|
+
"prettier": {
|
|
159
|
+
"allowed": false
|
|
160
|
+
},
|
|
161
|
+
"formatter": [
|
|
162
|
+
{
|
|
163
|
+
"language_server": {
|
|
164
|
+
"name": "oxfmt"
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
]
|
|
168
|
+
},
|
|
169
|
+
"TypeScript": {
|
|
170
|
+
"format_on_save": "on",
|
|
171
|
+
"prettier": {
|
|
172
|
+
"allowed": false
|
|
173
|
+
},
|
|
174
|
+
"formatter": [
|
|
175
|
+
{
|
|
176
|
+
"language_server": {
|
|
177
|
+
"name": "oxfmt"
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
]
|
|
181
|
+
},
|
|
182
|
+
"TSX": {
|
|
183
|
+
"format_on_save": "on",
|
|
184
|
+
"prettier": {
|
|
185
|
+
"allowed": false
|
|
186
|
+
},
|
|
187
|
+
"formatter": [
|
|
188
|
+
{
|
|
189
|
+
"language_server": {
|
|
190
|
+
"name": "oxfmt"
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
]
|
|
194
|
+
},
|
|
195
|
+
"Vue.js": {
|
|
196
|
+
"format_on_save": "on",
|
|
197
|
+
"prettier": {
|
|
198
|
+
"allowed": false
|
|
199
|
+
},
|
|
200
|
+
"formatter": [
|
|
201
|
+
{
|
|
202
|
+
"language_server": {
|
|
203
|
+
"name": "oxfmt"
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
]
|
|
207
|
+
},
|
|
208
|
+
"YAML": {
|
|
209
|
+
"format_on_save": "on",
|
|
210
|
+
"prettier": {
|
|
211
|
+
"allowed": false
|
|
212
|
+
},
|
|
213
|
+
"formatter": [
|
|
214
|
+
{
|
|
215
|
+
"language_server": {
|
|
216
|
+
"name": "oxfmt"
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
]
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
package/DEVELOPMENT.md
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
# Development Workflow
|
|
2
|
+
|
|
3
|
+
This guide covers how to develop, test, and publish the `pi-observability` extension.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Project Structure](#project-structure)
|
|
8
|
+
- [Local Development](#local-development)
|
|
9
|
+
- [Testing Changes](#testing-changes)
|
|
10
|
+
- [Publishing](#publishing)
|
|
11
|
+
- [Versioning](#versioning)
|
|
12
|
+
- [Troubleshooting](#troubleshooting)
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Project Structure
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
pi-observability/
|
|
20
|
+
├── extensions/
|
|
21
|
+
│ └── observability.ts # Main extension entry point
|
|
22
|
+
├── package.json # Package manifest + pi config
|
|
23
|
+
├── tsconfig.json # TypeScript config
|
|
24
|
+
├── README.md # User-facing docs
|
|
25
|
+
├── DEVELOPMENT.md # This file
|
|
26
|
+
└── LICENSE
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The `pi` key in `package.json` declares what pi loads:
|
|
30
|
+
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"pi": {
|
|
34
|
+
"extensions": ["./extensions/observability.ts"]
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Local Development
|
|
42
|
+
|
|
43
|
+
### 1. Clone and install
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
git clone https://github.com/imran-vz/pi-observability.git
|
|
47
|
+
cd pi-observability
|
|
48
|
+
npm install
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 2. Link for live testing
|
|
52
|
+
|
|
53
|
+
The fastest way to iterate is to **symlink** the extension into pi's auto-discovery directory. This lets you edit the source file and hot-reload with `/reload`.
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npm run dev:link
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
This creates a symlink:
|
|
60
|
+
```
|
|
61
|
+
~/.pi/agent/extensions/observability.ts → ./extensions/observability.ts
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
> **Important:** If you previously had a copy (not symlink) at `~/.pi/agent/extensions/observability.ts`, this script removes it first.
|
|
65
|
+
|
|
66
|
+
### 3. Start pi and test
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
pi
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Make edits to `extensions/observability.ts`, then in pi run:
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
/reload
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The extension reloads instantly. No need to restart pi.
|
|
79
|
+
|
|
80
|
+
### 4. Unlink when done
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
npm run dev:unlink
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
This removes the symlink. To continue using the published version, reinstall:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
pi install npm:pi-observability
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Alternative: `-e` flag (quick tests)
|
|
93
|
+
|
|
94
|
+
For one-off testing without linking:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
pi -e ./extensions/observability.ts
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
This loads the extension for that session only. Good for testing on a clean slate.
|
|
101
|
+
|
|
102
|
+
### Alternative: Local path in settings
|
|
103
|
+
|
|
104
|
+
Add to `~/.pi/agent/settings.json`:
|
|
105
|
+
|
|
106
|
+
```json
|
|
107
|
+
{
|
|
108
|
+
"extensions": ["/absolute/path/to/pi-observability/extensions/observability.ts"]
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Testing Changes
|
|
115
|
+
|
|
116
|
+
Before publishing, verify:
|
|
117
|
+
|
|
118
|
+
1. **Type check:**
|
|
119
|
+
```bash
|
|
120
|
+
npm run typecheck
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
2. **Load in pi:**
|
|
124
|
+
```bash
|
|
125
|
+
npm run dev:link
|
|
126
|
+
pi
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
3. **Test all commands:**
|
|
130
|
+
- `/obs` — Dashboard prints correctly
|
|
131
|
+
- `/obs-toggle` — Footer toggles on/off
|
|
132
|
+
- Footer updates during streaming
|
|
133
|
+
- History persists across sessions
|
|
134
|
+
|
|
135
|
+
4. **Test edge cases:**
|
|
136
|
+
- Non-git directories (diff stats should show 0)
|
|
137
|
+
- Very long paths (truncation works)
|
|
138
|
+
- Context window exceeded (usage display)
|
|
139
|
+
- Multiple models in one session
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Publishing
|
|
144
|
+
|
|
145
|
+
### Prerequisites
|
|
146
|
+
|
|
147
|
+
- Logged into npm: `npm login`
|
|
148
|
+
- Write access to the GitHub repo
|
|
149
|
+
- Clean working tree: `git status`
|
|
150
|
+
|
|
151
|
+
### Release workflow
|
|
152
|
+
|
|
153
|
+
**Patch release** (bug fixes):
|
|
154
|
+
```bash
|
|
155
|
+
npm run version:patch # bumps 1.0.0 → 1.0.1, tags, pushes
|
|
156
|
+
npm run publish:pkg # publishes to npm
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Minor release** (new features):
|
|
160
|
+
```bash
|
|
161
|
+
npm run version:minor # bumps 1.0.0 → 1.1.0
|
|
162
|
+
npm run publish:pkg
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
**Major release** (breaking changes):
|
|
166
|
+
```bash
|
|
167
|
+
npm run version:major # bumps 1.0.0 → 2.0.0
|
|
168
|
+
npm run publish:pkg
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### What `npm version` does
|
|
172
|
+
|
|
173
|
+
1. Updates `version` in `package.json`
|
|
174
|
+
2. Creates a git commit: `1.0.1`
|
|
175
|
+
3. Creates a git tag: `v1.0.1`
|
|
176
|
+
4. Pushes commit + tag to origin
|
|
177
|
+
|
|
178
|
+
### After publishing
|
|
179
|
+
|
|
180
|
+
Users update with:
|
|
181
|
+
```bash
|
|
182
|
+
pi update
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Or reinstall to get the latest:
|
|
186
|
+
```bash
|
|
187
|
+
pi remove npm:pi-observability
|
|
188
|
+
pi install npm:pi-observability
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Versioning
|
|
194
|
+
|
|
195
|
+
We follow [SemVer](https://semver.org/):
|
|
196
|
+
|
|
197
|
+
| Version change | When to use |
|
|
198
|
+
|----------------|-------------|
|
|
199
|
+
| **Patch** `1.0.0 → 1.0.1` | Bug fixes, typo corrections, performance improvements |
|
|
200
|
+
| **Minor** `1.0.0 → 1.1.0` | New commands, new footer features, new metrics |
|
|
201
|
+
| **Major** `1.0.0 → 2.0.0` | Breaking changes (command renames, removed features) |
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## Troubleshooting
|
|
206
|
+
|
|
207
|
+
### Extension not loading after `/reload`
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
# Check the symlink points to the right place
|
|
211
|
+
ls -la ~/.pi/agent/extensions/observability.ts
|
|
212
|
+
|
|
213
|
+
# If it's a copy instead of a symlink, remove and re-link
|
|
214
|
+
rm ~/.pi/agent/extensions/observability.ts
|
|
215
|
+
npm run dev:link
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Type errors from pi packages
|
|
219
|
+
|
|
220
|
+
Pi bundles its core packages at runtime. The `devDependencies` are only for IDE support. If TypeScript complains about missing modules during `npm run typecheck`, make sure you've run:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
npm install
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Published version not updating for users
|
|
227
|
+
|
|
228
|
+
npm has a TTL on package metadata. Users may need:
|
|
229
|
+
```bash
|
|
230
|
+
pi remove npm:pi-observability
|
|
231
|
+
pi install npm:pi-observability
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Or wait a few minutes and run `pi update`.
|
|
235
|
+
|
|
236
|
+
### Conflicts with local copy
|
|
237
|
+
|
|
238
|
+
If you have both the npm-installed version and a local symlink, pi may load both. Unlink during published-version testing:
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
npm run dev:unlink
|
|
242
|
+
pi
|
|
243
|
+
```
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 🔭 pi-observability
|
|
2
2
|
|
|
3
|
-
A [pi](https://github.com/mariozechner/pi) extension that replaces the default footer with a live observability bar
|
|
3
|
+
A [pi](https://github.com/mariozechner/pi) extension that replaces the default footer with a live observability bar, provides a full dashboard command, and prints a TPS summary after each agent run.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
@@ -8,19 +8,69 @@ A [pi](https://github.com/mariozechner/pi) extension that replaces the default f
|
|
|
8
8
|
- Session input/output tokens & estimated cost
|
|
9
9
|
- Live TPS (tokens per second) during streaming
|
|
10
10
|
- Session runtime
|
|
11
|
-
- Current model & git branch
|
|
11
|
+
- Current model, thinking level, fast mode & git branch
|
|
12
12
|
- Git diff stats (added/removed lines)
|
|
13
13
|
- Context usage (current / max)
|
|
14
|
+
- **Thinking level colors match pi's input field** — off/low/medium/high use the same theme colors as the editor border
|
|
15
|
+
- **Rainbow mode** — `xhigh` and `max` thinking levels render the model indicator in cycling rainbow colors
|
|
14
16
|
|
|
15
|
-
- **`/obs` command** —
|
|
17
|
+
- **`/obs` command** — Full-screen TUI dashboard with per-turn breakdowns and last 10 session history. Renders through pi's native TUI (no console spam), with theme-aware borders and dynamic terminal width.
|
|
18
|
+
|
|
19
|
+
- **End-of-run TPS notification** — Prints the legacy TPS summary after each agent run: output TPS, input/output tokens, cache read/write tokens, total tokens, and elapsed time.
|
|
16
20
|
|
|
17
21
|
- **`/obs-toggle` command** — Toggle the live footer on/off
|
|
18
22
|
|
|
19
23
|
## Preview
|
|
20
24
|
|
|
25
|
+
### Screed recording
|
|
26
|
+
|
|
27
|
+
> GitHub does not render inline MP4 players in `README.md`, so here's a short animated preview. Click it to open the full recording.
|
|
28
|
+
|
|
29
|
+
[](./output.mp4)
|
|
30
|
+
|
|
31
|
+
[Open the full screed recording (MP4)](./output.mp4)
|
|
32
|
+
|
|
33
|
+
### Footer
|
|
34
|
+
|
|
35
|
+
Compact single-line layout that falls back to two lines when the terminal is narrow:
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
gpt-5.5:high ▸ ⏱ 12:34 ▸ 📁 my-app ▸ main +42 -7 ▸ ctx 4.2k/200k ▸ ↑1.2k ↓3.4k ▸ ⚡45.2 ▸ $0.0042
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
With `xhigh` or `max` thinking, the model name renders in rainbow:
|
|
42
|
+
|
|
21
43
|
```
|
|
22
|
-
|
|
23
|
-
|
|
44
|
+
gpt-5.5:xhigh ▸ ⏱ 12:34 ▸ 📁 my-app ▸ ↑1.2k ↓3.4k ▸ ⚡45.2 ▸ $0.0042
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Git diff in the status bar
|
|
48
|
+
|
|
49
|
+

|
|
50
|
+
|
|
51
|
+
### Dashboard (`/obs`)
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
┌──────────────────────────────────────────┐
|
|
55
|
+
│ Agent Observability Dashboard │
|
|
56
|
+
├──────────────────────────────────────────┤
|
|
57
|
+
│ Runtime: 12:34 Dir: ~/projects/my-app │
|
|
58
|
+
│ Branch: main Model: claude-sonnet-4 │
|
|
59
|
+
├──────────────────────────────────────────┤
|
|
60
|
+
│ Tokens: ↑1.2k ↓3.4k │
|
|
61
|
+
│ Cost: $0.004200 │
|
|
62
|
+
└──────────────────────────────────────────┘
|
|
63
|
+
|
|
64
|
+
TURNS (2)
|
|
65
|
+
# Input Output Time TPS Cost Model
|
|
66
|
+
─────────────────────────────────────────────────
|
|
67
|
+
1 ↑450 ↓1200 0:45 26.7 $0.00 claude-sonnet-4
|
|
68
|
+
2 ↑320 ↓900 0:32 28.1 $0.00 claude-sonnet-4
|
|
69
|
+
|
|
70
|
+
LAST 10 SESSIONS
|
|
71
|
+
When Duration Turns Input Output Cost
|
|
72
|
+
───────────────────────────────────────────────────────────
|
|
73
|
+
Apr 18, 04:19 PM 9:05 10 ↑110k ↓9.9k $0.00
|
|
24
74
|
```
|
|
25
75
|
|
|
26
76
|
## Install
|
|
@@ -39,34 +89,25 @@ pi install git:github.com/imran-vz/pi-observability
|
|
|
39
89
|
|
|
40
90
|
### Manual
|
|
41
91
|
|
|
42
|
-
Copy `extensions
|
|
92
|
+
Copy the entire `extensions/` directory to `~/.pi/agent/extensions/` (or `.pi/extensions/` for project-local):
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
cp -r extensions/* ~/.pi/agent/extensions/
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
> **Note:** This extension is split into multiple files (`observability.ts` + `lib/`). Copying only the main file will break imports.
|
|
43
99
|
|
|
44
100
|
## Commands
|
|
45
101
|
|
|
46
102
|
| Command | Description |
|
|
47
103
|
|---------|-------------|
|
|
48
|
-
| `/obs` |
|
|
104
|
+
| `/obs` | Open full observability dashboard in TUI overlay |
|
|
49
105
|
| `/obs-toggle` | Toggle the observability footer on/off |
|
|
106
|
+
| `/obs-toggle-path` | Toggle between folder name and full path in footer |
|
|
50
107
|
|
|
51
|
-
##
|
|
108
|
+
## Migration from TPS
|
|
52
109
|
|
|
53
|
-
|
|
54
|
-
╔══════════════════════════════════════════════════════════════╗
|
|
55
|
-
║ 🕵️ Agent Observability Dashboard ║
|
|
56
|
-
╠══════════════════════════════════════════════════════════════╣
|
|
57
|
-
║ Runtime: 12:34 ║
|
|
58
|
-
║ Dir: ~/projects/my-app ║
|
|
59
|
-
║ Branch: main ║
|
|
60
|
-
║ Model: claude-sonnet-4 ║
|
|
61
|
-
╠══════════════════════════════════════════════════════════════╣
|
|
62
|
-
║ Tokens: ↑1.2k ↓3.4k ║
|
|
63
|
-
║ Cost: $0.004200 ║
|
|
64
|
-
╠══════════════════════════════════════════════════════════════╣
|
|
65
|
-
║ Turns: ║
|
|
66
|
-
║ #1 ↑450 ↓1200 0:45 26.7/s $0.0015 claude-sonne ║
|
|
67
|
-
║ #2 ↑320 ↓900 0:32 28.1/s $0.0012 claude-sonne ║
|
|
68
|
-
╚══════════════════════════════════════════════════════════════╝
|
|
69
|
-
```
|
|
110
|
+
The standalone TPS extension is no longer required. pi-observability now includes its end-of-run TPS notification, so remove `~/.pi/agent/extensions/tps.ts` if it is installed to avoid duplicate notifications.
|
|
70
111
|
|
|
71
112
|
## Requirements
|
|
72
113
|
|
package/demo-preview.gif
ADDED
|
Binary file
|
package/diff.png
ADDED
|
Binary file
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import type { ThemeColor } from "@mariozechner/pi-coding-agent";
|
|
3
|
+
|
|
4
|
+
export function fmtDuration(ms: number): string {
|
|
5
|
+
if (!Number.isFinite(ms) || ms < 0) ms = 0;
|
|
6
|
+
const s = Math.floor(ms / 1000);
|
|
7
|
+
const h = Math.floor(s / 3600);
|
|
8
|
+
const m = Math.floor((s % 3600) / 60);
|
|
9
|
+
const sec = s % 60;
|
|
10
|
+
if (h > 0) return `${h}:${m.toString().padStart(2, "0")}:${sec.toString().padStart(2, "0")}`;
|
|
11
|
+
return `${m}:${sec.toString().padStart(2, "0")}`;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function fmtTokens(n: number): string {
|
|
15
|
+
if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(2)}M`;
|
|
16
|
+
if (n >= 1_000) return `${(n / 1_000).toFixed(1)}k`;
|
|
17
|
+
return `${n}`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function shortenPath(p: string): string {
|
|
21
|
+
const home = homedir();
|
|
22
|
+
if (home && p.startsWith(home)) return p.replace(home, "~");
|
|
23
|
+
return p;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function thinkingColor(level: string): ThemeColor {
|
|
27
|
+
switch (level) {
|
|
28
|
+
case "off":
|
|
29
|
+
return "thinkingOff";
|
|
30
|
+
case "minimal":
|
|
31
|
+
return "thinkingMinimal";
|
|
32
|
+
case "low":
|
|
33
|
+
return "thinkingLow";
|
|
34
|
+
case "medium":
|
|
35
|
+
return "thinkingMedium";
|
|
36
|
+
case "high":
|
|
37
|
+
return "thinkingHigh";
|
|
38
|
+
case "xhigh":
|
|
39
|
+
return "thinkingXhigh";
|
|
40
|
+
default:
|
|
41
|
+
return "thinkingOff";
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function contextUsageColor(pct: number, expert: number, warning: number): ThemeColor {
|
|
46
|
+
if (pct <= expert) return "success";
|
|
47
|
+
if (pct <= warning) return "warning";
|
|
48
|
+
return "error";
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function rainbowText(text: string): string {
|
|
52
|
+
const colors = [
|
|
53
|
+
"\x1b[38;2;255;0;0m", // red
|
|
54
|
+
"\x1b[38;2;255;127;0m", // orange
|
|
55
|
+
"\x1b[38;2;255;255;0m", // yellow
|
|
56
|
+
"\x1b[38;2;0;255;0m", // green
|
|
57
|
+
"\x1b[38;2;0;255;255m", // cyan
|
|
58
|
+
"\x1b[38;2;0;0;255m", // blue
|
|
59
|
+
"\x1b[38;2;255;0;255m", // magenta
|
|
60
|
+
];
|
|
61
|
+
let result = "";
|
|
62
|
+
for (let i = 0; i < text.length; i++) {
|
|
63
|
+
result += colors[i % colors.length] + text[i];
|
|
64
|
+
}
|
|
65
|
+
result += "\x1b[0m";
|
|
66
|
+
return result;
|
|
67
|
+
}
|