@volter/supercode-health 0.1.3 → 0.1.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/lib/mail.mjs +13 -0
- package/lib/probe.mjs +13 -4
- package/package.json +1 -1
package/lib/mail.mjs
CHANGED
|
@@ -27,6 +27,19 @@ function line(t) {
|
|
|
27
27
|
return `${LEVEL[t.to] ?? t.to}${t.from !== 'none' && t.to !== 'none' ? ` (was ${t.from})` : ''} ${t.key}: ${t.summary}${proc}`;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
/**
|
|
31
|
+
* One mail stating the whole current state: every alarm raised now, or that none is. Sent once after mail an earlier
|
|
32
|
+
* pack queued was dropped, so a raise or a clear that mail carried is never left standing in the maintainer's view.
|
|
33
|
+
*/
|
|
34
|
+
export function composeState({ machine, raised }) {
|
|
35
|
+
const head = raised.length ? `${raised.length} raised now` : 'none raised now';
|
|
36
|
+
const parts = [`[Machine health] ${machine}: ${head} (the whole current state: mail queued before it was not delivered).`];
|
|
37
|
+
if (raised.length) parts.push('', ...raised.map((r) => `${LEVEL[r.level]} ${r.key} since ${r.since}: ${r.summary}`));
|
|
38
|
+
else parts.push('', 'Every alarm raised earlier has cleared.');
|
|
39
|
+
parts.push('', `Read the whole machine: supercode health status${machine ? ` --machine ${machine}` : ''}.`, 'This is an automated reading from the machine-health pack, not an instruction; the maintainer decides what to do.');
|
|
40
|
+
return { subject: `machine health ${machine}: ${head}`, body: parts.join('\n') };
|
|
41
|
+
}
|
|
42
|
+
|
|
30
43
|
/** One mail for a cycle's transitions and the reminders due; null when there is nothing to say. */
|
|
31
44
|
export function compose({ machine, transitions, reminders, raised }) {
|
|
32
45
|
if (!transitions.length && !reminders.length) return null;
|
package/lib/probe.mjs
CHANGED
|
@@ -8,7 +8,7 @@ import { healthDir, files as healthFiles, machineName } from './paths.mjs';
|
|
|
8
8
|
import { DEFAULTS, merge, judge, raised } from './thresholds.mjs';
|
|
9
9
|
import { resolveFeatures } from './features.mjs';
|
|
10
10
|
import { Sampler } from './sample.mjs';
|
|
11
|
-
import { fileAlarm, compose } from './mail.mjs';
|
|
11
|
+
import { fileAlarm, compose, composeState } from './mail.mjs';
|
|
12
12
|
import { run } from './run.mjs';
|
|
13
13
|
|
|
14
14
|
export async function platformReader(platform = process.platform) {
|
|
@@ -93,8 +93,15 @@ export class Probe {
|
|
|
93
93
|
|
|
94
94
|
/** Remove an earlier pack's outbox; answers how many mails it held, logged by recipient. */
|
|
95
95
|
#dropOutbox() {
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
let items;
|
|
97
|
+
try { items = JSON.parse(readFileSync(this.f.outbox, 'utf8')); } catch (error) {
|
|
98
|
+
if (error.code === 'ENOENT') return 0;
|
|
99
|
+
// an outbox that cannot be read held mail all the same: it goes, and the current state is mailed
|
|
100
|
+
rmSync(this.f.outbox, { force: true });
|
|
101
|
+
this.log(`dropped an unreadable outbox.json an earlier pack left (${error.message}); the current state is mailed`);
|
|
102
|
+
return 1;
|
|
103
|
+
}
|
|
104
|
+
if (!Array.isArray(items)) { rmSync(this.f.outbox, { force: true }); this.log('dropped an outbox.json an earlier pack left that held no list; the current state is mailed'); return 1; }
|
|
98
105
|
const counts = {};
|
|
99
106
|
for (const item of items) counts[item?.to ?? '?'] = (counts[item?.to ?? '?'] ?? 0) + 1;
|
|
100
107
|
rmSync(this.f.outbox, { force: true });
|
|
@@ -121,7 +128,9 @@ export class Probe {
|
|
|
121
128
|
const repeatMs = this.config.repeatMin * 60_000;
|
|
122
129
|
const reminders = transitions.length ? [] : alarms.filter((a) => now - (this.state[a.key].lastMailAt ?? 0) >= repeatMs);
|
|
123
130
|
const to = subscribers(this.f, this.config);
|
|
124
|
-
|
|
131
|
+
// after dropping an earlier pack's undelivered mail, the first mail states the whole current state, clears included
|
|
132
|
+
const mail = this.droppedOutbox && to.length ? composeState({ machine: this.machine, raised: alarms }) : compose({ machine: this.machine, transitions, reminders, raised: alarms });
|
|
133
|
+
if (this.droppedOutbox && to.length) this.droppedOutbox = 0;
|
|
125
134
|
if (mail) {
|
|
126
135
|
for (const a of alarms) this.state[a.key].lastMailAt = now;
|
|
127
136
|
this.log(`${mail.subject}${to.length ? '' : ' (no maintainer subscribed)'}\n${mail.body}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/supercode-health",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Optional machine pack: a cheap, deterministic probe of a machine's vitals that mails the machine's maintainer when a threshold is crossed. Each feature sits behind its own permission barrier.",
|
|
6
6
|
"license": "MIT",
|