@cad0p/pi-usage 0.11.3 → 0.11.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/README.md +274 -12
- package/bin/piquota.js +49 -4
- package/extensions/quota-panel.ts +188 -31
- package/omarchy/cad0p.pi-usage/Agent.qml +33 -0
- package/omarchy/cad0p.pi-usage/Main.qml +333 -0
- package/omarchy/cad0p.pi-usage/Panel.qml +136 -0
- package/omarchy/cad0p.pi-usage/README.md +40 -0
- package/omarchy/cad0p.pi-usage/UsageContent.qml +1001 -0
- package/omarchy/cad0p.pi-usage/UsageLogic.js +603 -0
- package/omarchy/cad0p.pi-usage/assets/antigravity.svg +3 -0
- package/omarchy/cad0p.pi-usage/assets/claude.svg +1 -0
- package/omarchy/cad0p.pi-usage/assets/codex-light.svg +1 -0
- package/omarchy/cad0p.pi-usage/assets/codex.svg +1 -0
- package/omarchy/cad0p.pi-usage/assets/fireworks.svg +7 -0
- package/omarchy/cad0p.pi-usage/assets/github-actions.svg +3 -0
- package/omarchy/cad0p.pi-usage/assets/opencode-go.svg +3 -0
- package/omarchy/cad0p.pi-usage/manifest.json +56 -0
- package/package.json +2 -1
- package/src/auth/pi-auth.js +3 -0
- package/src/cli/args.js +5 -0
- package/src/cli/commands/stats.js +76 -0
- package/src/engine.js +44 -0
- package/src/local/history.js +1160 -0
- package/src/local/pi-sessions.js +1511 -0
- package/src/omarchy/publish.js +1 -65
- package/src/omarchy/record.js +82 -7
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import QtQuick
|
|
2
|
+
import Quickshell
|
|
3
|
+
import Quickshell.Io
|
|
4
|
+
import qs.Commons
|
|
5
|
+
import qs.Ui
|
|
6
|
+
import "UsageLogic.js" as Logic
|
|
7
|
+
|
|
8
|
+
// AI Usage: one bar icon and one popup for every AI subscription that has a
|
|
9
|
+
// usage record, each provider a collapsible section of a single scrolling
|
|
10
|
+
// list. Derived from Omarchy's built-in Agents panel (plugins/agents, MIT, by
|
|
11
|
+
// Omarchy): the same records, rows and type, with the tab switch replaced by
|
|
12
|
+
// sections and multi-account providers drawn account by account.
|
|
13
|
+
Panel {
|
|
14
|
+
id: root
|
|
15
|
+
moduleName: "cad0p.pi-usage"
|
|
16
|
+
ipcTarget: "cad0p.pi-usage"
|
|
17
|
+
manageIpc: false
|
|
18
|
+
|
|
19
|
+
readonly property color foreground: bar ? bar.foreground : Color.foreground
|
|
20
|
+
readonly property color urgent: bar ? bar.urgent : Color.urgent
|
|
21
|
+
readonly property string fontFamily: bar ? bar.fontFamily : Style.font.family
|
|
22
|
+
readonly property string glyph: ""
|
|
23
|
+
|
|
24
|
+
readonly property var providers: usage.providers
|
|
25
|
+
|
|
26
|
+
// The icon lights up when any headline window is at 90% or a prepaid
|
|
27
|
+
// balance is down to its last 10%, the built-in's alarm thresholds.
|
|
28
|
+
readonly property bool alarming: {
|
|
29
|
+
for (var i = 0; i < providers.length; i++) {
|
|
30
|
+
var h = Logic.headline(providers[i])
|
|
31
|
+
if ((h && h.percent >= 0.9) || Logic.balanceAlarming(providers[i].balance)) return true
|
|
32
|
+
}
|
|
33
|
+
return false
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Countdowns and "updated" read this instead of Date.now() so the panel
|
|
37
|
+
// keeps telling the truth while it sits open.
|
|
38
|
+
property double nowMs: Date.now()
|
|
39
|
+
|
|
40
|
+
function refreshNow() { usage.refreshAll() }
|
|
41
|
+
|
|
42
|
+
function launchAgent() {
|
|
43
|
+
if (root.bar) root.bar.run("omarchy-agent --pick")
|
|
44
|
+
root.close()
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Nothing to report, nothing in the bar, as with the built-in widget.
|
|
48
|
+
visible: Logic.pluginVisible(providers)
|
|
49
|
+
implicitWidth: button.implicitWidth
|
|
50
|
+
implicitHeight: button.implicitHeight
|
|
51
|
+
|
|
52
|
+
onOpenedChanged: if (opened) {
|
|
53
|
+
nowMs = Date.now()
|
|
54
|
+
content.resetView()
|
|
55
|
+
usage.refreshOnOpen()
|
|
56
|
+
Qt.callLater(function() { keyCatcher.forceActiveFocus() })
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
Main {
|
|
60
|
+
id: usage
|
|
61
|
+
settings: root.settings
|
|
62
|
+
bar: root.bar
|
|
63
|
+
pluginDir: Qt.resolvedUrl(".")
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
Timer {
|
|
67
|
+
interval: 30000
|
|
68
|
+
running: root.opened
|
|
69
|
+
repeat: true
|
|
70
|
+
onTriggered: root.nowMs = Date.now()
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
IpcHandler {
|
|
74
|
+
target: root.ipcTarget
|
|
75
|
+
function open(): void { root.open() }
|
|
76
|
+
function close(): void { root.close() }
|
|
77
|
+
function show(): void { root.open() }
|
|
78
|
+
function hide(): void { root.close() }
|
|
79
|
+
function toggle(): void { root.toggle() }
|
|
80
|
+
function refresh(): string { root.refreshNow(); return "ok" }
|
|
81
|
+
function expand(id: string): string { usage.setExpanded(id, true); return "ok" }
|
|
82
|
+
function collapse(id: string): string { usage.setExpanded(id, false); return "ok" }
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
BarIconButton {
|
|
86
|
+
id: button
|
|
87
|
+
anchors.fill: parent
|
|
88
|
+
bar: root.bar
|
|
89
|
+
text: root.glyph
|
|
90
|
+
active: root.alarming
|
|
91
|
+
onPressed: function(buttonCode) {
|
|
92
|
+
if (buttonCode === Qt.RightButton) root.launchAgent()
|
|
93
|
+
else if (buttonCode === Qt.MiddleButton) root.refreshNow()
|
|
94
|
+
else root.toggle()
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
KeyboardPanel {
|
|
99
|
+
id: panel
|
|
100
|
+
anchorItem: button
|
|
101
|
+
owner: root
|
|
102
|
+
bar: root.bar
|
|
103
|
+
open: root.opened
|
|
104
|
+
focusTarget: keyCatcher
|
|
105
|
+
contentWidth: panel.fittedContentWidth(Style.space(380))
|
|
106
|
+
contentHeight: panel.fittedContentHeight(content.contentImplicitHeight, Style.space(640))
|
|
107
|
+
|
|
108
|
+
PanelKeyCatcher {
|
|
109
|
+
id: keyCatcher
|
|
110
|
+
anchors.fill: parent
|
|
111
|
+
|
|
112
|
+
// j/k or arrows walk the section headers (paging through an open one
|
|
113
|
+
// taller than the panel), Enter/Space fold or unfold, l/h unfold and
|
|
114
|
+
// fold, r refreshes, Tab moves to the neighboring bar panel.
|
|
115
|
+
onMoveRequested: function(dx, dy) {
|
|
116
|
+
if (dy !== 0) content.moveCursor(dy)
|
|
117
|
+
if (dx !== 0) content.setCursorExpanded(dx > 0)
|
|
118
|
+
}
|
|
119
|
+
onActivateRequested: content.toggleCursor()
|
|
120
|
+
onCloseRequested: root.close()
|
|
121
|
+
onTabRequested: function(direction) { root.switchPanel(direction) }
|
|
122
|
+
onTextKey: function(t) { if (t === "r" || t === "R") root.refreshNow() }
|
|
123
|
+
|
|
124
|
+
UsageContent {
|
|
125
|
+
id: content
|
|
126
|
+
anchors.fill: parent
|
|
127
|
+
usage: usage
|
|
128
|
+
foreground: root.foreground
|
|
129
|
+
urgent: root.urgent
|
|
130
|
+
fontFamily: root.fontFamily
|
|
131
|
+
nowMs: root.nowMs
|
|
132
|
+
fallbackGlyph: root.glyph
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# AI Usage (`cad0p.pi-usage`)
|
|
2
|
+
|
|
3
|
+
One Omarchy bar icon and one scrolling panel for every AI subscription that has
|
|
4
|
+
a usage record in `${XDG_STATE_HOME:-~/.local/state}/omarchy/agents/usage/`:
|
|
5
|
+
pi-usage's `pi-*.json` and Omarchy's own `claude`, `codex` and `fireworks`
|
|
6
|
+
records alike. Every provider is a collapsible section instead of a tab; a
|
|
7
|
+
multi-account provider shows every window of every account.
|
|
8
|
+
|
|
9
|
+
The plugin does **not** support the built-in Agents widget's synced cross-device
|
|
10
|
+
aggregation (`syncMode`, `syncDir`, `syncFileName`, `syncDeviceId`). Users who
|
|
11
|
+
rely on synced aggregation should keep the built-in widget; this plugin is not a
|
|
12
|
+
full replacement for it.
|
|
13
|
+
|
|
14
|
+
Omarchy's own collectors follow the `omarchyCollectors` setting: `Off` never
|
|
15
|
+
runs them, `Auto` only while the built-in Agents widget is off the bar — the
|
|
16
|
+
`retryAdvised` retry included.
|
|
17
|
+
|
|
18
|
+
Part of [`@cad0p/pi-usage`](../../README.md#the-ai-usage-bar-plugin), which
|
|
19
|
+
documents installation, keys, settings and IPC. Install with
|
|
20
|
+
`./install.sh --omarchy-plugin`, then `omarchy plugin enable cad0p.pi-usage`.
|
|
21
|
+
|
|
22
|
+
The installer links the plugin directory; Omarchy loads that symlink, but
|
|
23
|
+
`omarchy plugin validate` rejects symlinked plugin folders. Validate the real
|
|
24
|
+
package path instead, for example
|
|
25
|
+
`omarchy plugin validate ~/.pi/agent/npm/node_modules/@cad0p/pi-usage/omarchy/cad0p.pi-usage`,
|
|
26
|
+
or validate the directory in a source checkout—not the
|
|
27
|
+
`~/.config/omarchy/plugins/cad0p.pi-usage` link.
|
|
28
|
+
|
|
29
|
+
| File | Role |
|
|
30
|
+
|---|---|
|
|
31
|
+
| `Panel.qml` | Bar button, popup, keyboard and IPC (`omarchy-shell cad0p.pi-usage …`) |
|
|
32
|
+
| `UsageContent.qml` | The scrolling list of provider sections and their rows |
|
|
33
|
+
| `Main.qml` | Record discovery and watching, expansion state, refresh |
|
|
34
|
+
| `Agent.qml` | Per-record file watcher |
|
|
35
|
+
| `UsageLogic.js` | Pure logic (headline, ordering, formatting), tested with `node --test` |
|
|
36
|
+
| `assets/` | Provider marks, `<family>.svg` with a `-light` twin where needed |
|
|
37
|
+
|
|
38
|
+
Derived from Omarchy's built-in Agents plugin (`shell/plugins/agents`, MIT,
|
|
39
|
+
by Omarchy): its record contract, rows, meters, type scale and the Claude,
|
|
40
|
+
Codex and Fireworks marks. MIT, like the package.
|