pinglet-cli 0.6.1 → 0.6.2
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/dist/commands/statusline.js +4 -0
- package/dist/notifications.js +33 -5
- package/package.json +1 -1
|
@@ -102,6 +102,10 @@ function rotateSpinner(state, now) {
|
|
|
102
102
|
visibleMs: prev.visibleMs,
|
|
103
103
|
});
|
|
104
104
|
prev.visibleMs = 0; // A failed replacement must not account this interval twice.
|
|
105
|
+
// The event is already on disk. Persist the reset now: if arming below throws
|
|
106
|
+
// (e.g. settings.json is temporarily unparseable) the tick ends before the
|
|
107
|
+
// final saveState and the next tick would settle the same interval again.
|
|
108
|
+
(0, cache_1.saveState)(state);
|
|
105
109
|
}
|
|
106
110
|
const message = (0, picker_1.pickMessage)((0, cache_1.loadFeedMessages)(), state);
|
|
107
111
|
if (!message) {
|
package/dist/notifications.js
CHANGED
|
@@ -82,17 +82,45 @@ function enqueueNotification(args) {
|
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
|
-
|
|
85
|
+
const MAX_NOTIFICATION_AGE_MS = 60 * 60_000;
|
|
86
|
+
/** Caller holds the short state lock. Failed work stays on disk for retry.
|
|
87
|
+
* One unreadable or stale file must never stop the hook: unparseable files are
|
|
88
|
+
* discarded (their notification cannot be recovered), a turn-complete notice
|
|
89
|
+
* older than an hour is useless and discarded, and a delivery failure keeps
|
|
90
|
+
* its file for the next drain without affecting the other files.
|
|
91
|
+
*/
|
|
86
92
|
function drainNotifications() {
|
|
87
93
|
if (!fs.existsSync(config_1.CONFIG_PATH))
|
|
88
94
|
return;
|
|
89
95
|
const config = (0, config_1.loadConfig)();
|
|
90
96
|
for (const name of fs.readdirSync(config_1.PINGLET_DIR).filter(name => name.startsWith(PREFIX) && name.endsWith(".json"))) {
|
|
91
97
|
const file = path.join(config_1.PINGLET_DIR, name);
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
98
|
+
let event = null;
|
|
99
|
+
let stale = false;
|
|
100
|
+
try {
|
|
101
|
+
stale = Date.now() - fs.statSync(file).mtimeMs > MAX_NOTIFICATION_AGE_MS;
|
|
102
|
+
const parsed = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
103
|
+
if (parsed && typeof parsed === "object" && typeof parsed.type === "string")
|
|
104
|
+
event = parsed;
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
if ((0, storage_1.isMissing)(error))
|
|
108
|
+
continue; // Removed concurrently (purge/uninstall).
|
|
109
|
+
}
|
|
110
|
+
if (event && !stale && config.adapters.codex?.installedAt === event.installedAt && config.apiBaseUrl === event.apiBaseUrl) {
|
|
111
|
+
try {
|
|
112
|
+
(0, notify_1.runNotify)([JSON.stringify({ type: event.type })], "evt_" + name.slice(PREFIX.length, -5));
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
continue; // Keep the file; the same eventId is reused on retry.
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
try {
|
|
119
|
+
fs.unlinkSync(file);
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
if (!(0, storage_1.isMissing)(error))
|
|
123
|
+
throw error;
|
|
95
124
|
}
|
|
96
|
-
fs.unlinkSync(file); // Stale installation notifications must not survive reinstall.
|
|
97
125
|
}
|
|
98
126
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pinglet-cli",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"description": "Short messages from other developers shown in your Claude Code spinner while the AI thinks — zero tokens, never reads your code. Claude Code / Codex integration",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|