@groundnuty/macf 0.2.37 → 0.2.39
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/.build-info.json +2 -2
- package/dist/cli/claude-sh.d.ts.map +1 -1
- package/dist/cli/claude-sh.js +13 -0
- package/dist/cli/claude-sh.js.map +1 -1
- package/dist/cli/commands/certs.d.ts.map +1 -1
- package/dist/cli/commands/certs.js +6 -2
- package/dist/cli/commands/certs.js.map +1 -1
- package/dist/cli/commands/doctor.d.ts +102 -3
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/doctor.js +349 -55
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/fleet-doctor-inject.d.ts +52 -0
- package/dist/cli/commands/fleet-doctor-inject.d.ts.map +1 -0
- package/dist/cli/commands/fleet-doctor-inject.js +100 -0
- package/dist/cli/commands/fleet-doctor-inject.js.map +1 -0
- package/dist/cli/commands/fleet-doctor.d.ts +236 -0
- package/dist/cli/commands/fleet-doctor.d.ts.map +1 -0
- package/dist/cli/commands/fleet-doctor.js +481 -0
- package/dist/cli/commands/fleet-doctor.js.map +1 -0
- package/dist/cli/commands/fleet.d.ts +83 -0
- package/dist/cli/commands/fleet.d.ts.map +1 -0
- package/dist/cli/commands/fleet.js +225 -0
- package/dist/cli/commands/fleet.js.map +1 -0
- package/dist/cli/commands/init.d.ts +24 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +79 -8
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/migrate.d.ts +1 -0
- package/dist/cli/commands/migrate.d.ts.map +1 -1
- package/dist/cli/commands/ps.d.ts +17 -0
- package/dist/cli/commands/ps.d.ts.map +1 -0
- package/dist/cli/commands/ps.js +69 -0
- package/dist/cli/commands/ps.js.map +1 -0
- package/dist/cli/commands/registry-prune.d.ts +81 -0
- package/dist/cli/commands/registry-prune.d.ts.map +1 -0
- package/dist/cli/commands/registry-prune.js +163 -0
- package/dist/cli/commands/registry-prune.js.map +1 -0
- package/dist/cli/commands/restart-self.d.ts +111 -0
- package/dist/cli/commands/restart-self.d.ts.map +1 -0
- package/dist/cli/commands/restart-self.js +312 -0
- package/dist/cli/commands/restart-self.js.map +1 -0
- package/dist/cli/commands/routing-doctor-gh.d.ts +29 -0
- package/dist/cli/commands/routing-doctor-gh.d.ts.map +1 -0
- package/dist/cli/commands/routing-doctor-gh.js +103 -0
- package/dist/cli/commands/routing-doctor-gh.js.map +1 -0
- package/dist/cli/commands/routing-doctor.d.ts +183 -0
- package/dist/cli/commands/routing-doctor.d.ts.map +1 -0
- package/dist/cli/commands/routing-doctor.js +504 -0
- package/dist/cli/commands/routing-doctor.js.map +1 -0
- package/dist/cli/commands/update.d.ts.map +1 -1
- package/dist/cli/commands/update.js +9 -0
- package/dist/cli/commands/update.js.map +1 -1
- package/dist/cli/config.d.ts +2 -0
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/config.js +16 -0
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/env-files.d.ts.map +1 -1
- package/dist/cli/env-files.js +11 -0
- package/dist/cli/env-files.js.map +1 -1
- package/dist/cli/host-prelude.d.ts +50 -0
- package/dist/cli/host-prelude.d.ts.map +1 -0
- package/dist/cli/host-prelude.js +256 -0
- package/dist/cli/host-prelude.js.map +1 -0
- package/dist/cli/index.js +122 -5
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/proc-scan.d.ts +81 -0
- package/dist/cli/proc-scan.d.ts.map +1 -0
- package/dist/cli/proc-scan.js +172 -0
- package/dist/cli/proc-scan.js.map +1 -0
- package/dist/cli/role-settings-model.d.ts +70 -0
- package/dist/cli/role-settings-model.d.ts.map +1 -0
- package/dist/cli/role-settings-model.js +90 -0
- package/dist/cli/role-settings-model.js.map +1 -0
- package/dist/cli/settings-writer.d.ts +27 -0
- package/dist/cli/settings-writer.d.ts.map +1 -1
- package/dist/cli/settings-writer.js +144 -2
- package/dist/cli/settings-writer.js.map +1 -1
- package/package.json +2 -2
- package/plugin/rules/coordination.md +10 -0
- package/plugin/rules/silent-fallback-hazards.md +19 -4
- package/scripts/check-gh-attribution.sh +34 -10
- package/scripts/emit-turn-receipt.sh +44 -4
|
@@ -0,0 +1,481 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `macf fleet doctor` — NON-INVASIVE mesh-interconnect test (DR-030 phase-1
|
|
3
|
+
* increment 1d, macf#568).
|
|
4
|
+
*
|
|
5
|
+
* For the current project's registry, run a two-tier delivery ladder per agent:
|
|
6
|
+
*
|
|
7
|
+
* 1. REACHABLE — the agent's registry `host:port` answers an mTLS `/health`
|
|
8
|
+
* ping (reuses `pingAgentHealth`, the same probe `macf fleet status` uses).
|
|
9
|
+
* 2. ACCEPTED — an mTLS `/notify` POST carrying a DIAGNOSTIC payload is ACK'd
|
|
10
|
+
* by the server's receive path. The diagnostic body short-circuits to an
|
|
11
|
+
* ACK BEFORE any MCP push, and the ACK echoes back the correlation token we
|
|
12
|
+
* sent. "Accepted" is green iff HTTP 200 AND `ack === true` AND the echoed
|
|
13
|
+
* `correlation_token` matches what we sent (the echo proves a real
|
|
14
|
+
* round-trip, not a coincidental 200).
|
|
15
|
+
*
|
|
16
|
+
* HONESTY (DR-030 §3, rendered LOUDLY in the output legend): the default NON-
|
|
17
|
+
* invasive checks prove the protocol REACHES THE SERVER (mTLS auth + body parse)
|
|
18
|
+
* ONLY — they do NOT prove DELIVERY TO THE AGENT (the MCP-push → agent-reads gap
|
|
19
|
+
* is not exercised). Real deliver→process proof needs `--inject` (the INVASIVE
|
|
20
|
+
* Processed-now tier in this file — routes a real marker-bearing prompt + wakes
|
|
21
|
+
* each agent + matches the echoed run_id off `/health.last_processed`);
|
|
22
|
+
* routing-plane delivery needs an e2e run.
|
|
23
|
+
*
|
|
24
|
+
* Reuses `macf fleet status`'s plumbing: the registry list
|
|
25
|
+
* (`createRegistryFromConfig`), the mTLS `/health` probe (`pingAgentHealth`),
|
|
26
|
+
* the CA-cert read (`createClientFromConfig`), and the `formatTable` renderer
|
|
27
|
+
* (shared with `macf ps` / `macf fleet status`). The diagnostic POST mirrors
|
|
28
|
+
* `pingAgentHealth`'s mTLS request shape. Registry + both mTLS calls are
|
|
29
|
+
* injectable (`FleetDoctorDeps`) so tests run fully offline.
|
|
30
|
+
*/
|
|
31
|
+
import { randomUUID } from 'node:crypto';
|
|
32
|
+
import { request } from 'node:https';
|
|
33
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
34
|
+
import { readAgentConfig, tokenSourceFromConfig, agentCertPath, agentKeyPath, } from '../config.js';
|
|
35
|
+
import { createClientFromConfig } from '../registry-helper.js';
|
|
36
|
+
import { createRegistryFromConfig, generateToken, pingAgentHealth, toVariableSegment, } from '@groundnuty/macf-core';
|
|
37
|
+
import { formatTable } from './ps.js';
|
|
38
|
+
import { postInjectNotify, pollLastProcessedToken, } from './fleet-doctor-inject.js';
|
|
39
|
+
const DEFAULT_TIMEOUT_MS = 5000;
|
|
40
|
+
const DEFAULT_INJECT_MAX_POLLS = 7;
|
|
41
|
+
const DEFAULT_INJECT_POLL_INTERVAL_MS = 4000;
|
|
42
|
+
/** Default digits-only run id: epoch-ms + 6 random digits → unique, `[0-9]+`. */
|
|
43
|
+
export function defaultRunId() {
|
|
44
|
+
return `${Date.now()}${Math.floor(Math.random() * 1_000_000)}`;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Sanitize a registry name into a marker-legal agent slug. The
|
|
48
|
+
* `emit-turn-receipt.sh` grep is `\[macf-route:[0-9]+:[a-z0-9-]+\]`, so an
|
|
49
|
+
* UNsanitized label with an underscore/uppercase would fail the whole-marker
|
|
50
|
+
* match → no receipt written → a false UNCONFIRMED. Lowercase + map any
|
|
51
|
+
* out-of-class char to `-`; fall back to `agent` if the result is empty.
|
|
52
|
+
*/
|
|
53
|
+
export function sanitizeMarkerAgent(name) {
|
|
54
|
+
const slug = name.toLowerCase().replace(/[^a-z0-9-]/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '');
|
|
55
|
+
return slug === '' ? 'agent' : slug;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Accepted = HTTP 200 AND `ack === true` AND the echoed `correlation_token`
|
|
59
|
+
* matches what we sent. The token echo is the load-bearing check — it proves
|
|
60
|
+
* the 200 is a real round-trip of OUR request, not a coincidental success.
|
|
61
|
+
*/
|
|
62
|
+
export function isAccepted(sentToken, ack) {
|
|
63
|
+
return ack.status === 200 && ack.body?.ack === true && ack.body?.correlation_token === sentToken;
|
|
64
|
+
}
|
|
65
|
+
/** Human-readable reason the Accepted tier failed (used in `--json`/diagnostics). */
|
|
66
|
+
export function acceptFailureReason(sentToken, ack) {
|
|
67
|
+
if (ack.error)
|
|
68
|
+
return ack.error;
|
|
69
|
+
if (ack.status === null)
|
|
70
|
+
return 'no response';
|
|
71
|
+
if (ack.status !== 200)
|
|
72
|
+
return `http ${ack.status}`;
|
|
73
|
+
if (ack.body?.ack !== true)
|
|
74
|
+
return 'ack not true';
|
|
75
|
+
if (ack.body?.correlation_token !== sentToken)
|
|
76
|
+
return 'correlation_token mismatch';
|
|
77
|
+
return 'unknown';
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Run the Processed-now (`--inject`) tier for ONE reachable agent: route a real
|
|
81
|
+
* marker-bearing mention, then poll `/health.last_processed.correlation_token`
|
|
82
|
+
* for our `run_id`. Returns the tri-state outcome + diagnostics. PURE w.r.t.
|
|
83
|
+
* `inject.post`/`inject.poll`/`inject.sleep` — tests inject fakes (and a no-op
|
|
84
|
+
* sleep) so nothing hits the network and there are no real waits.
|
|
85
|
+
*/
|
|
86
|
+
export async function runProcessedInject(peer, ackAgent, inject) {
|
|
87
|
+
const { host, port } = peer.info;
|
|
88
|
+
const runId = (inject.genRunId ?? defaultRunId)();
|
|
89
|
+
const markerAgent = sanitizeMarkerAgent(ackAgent ?? peer.name);
|
|
90
|
+
const post = await inject.post(host, port, runId, markerAgent);
|
|
91
|
+
if (!post.delivered) {
|
|
92
|
+
return { processedInject: false, injectRunId: runId, injectError: post.error ?? 'inject POST not delivered' };
|
|
93
|
+
}
|
|
94
|
+
const maxPolls = inject.maxPolls ?? DEFAULT_INJECT_MAX_POLLS;
|
|
95
|
+
const intervalMs = inject.pollIntervalMs ?? DEFAULT_INJECT_POLL_INTERVAL_MS;
|
|
96
|
+
const sleep = inject.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
97
|
+
for (let i = 0; i < maxPolls; i++) {
|
|
98
|
+
const token = await inject.poll(host, port);
|
|
99
|
+
if (token === runId)
|
|
100
|
+
return { processedInject: true, injectRunId: runId };
|
|
101
|
+
if (i < maxPolls - 1)
|
|
102
|
+
await sleep(intervalMs);
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
processedInject: false,
|
|
106
|
+
injectRunId: runId,
|
|
107
|
+
injectError: `processing unconfirmed within ~${Math.round(((maxPolls - 1) * intervalMs) / 1000)}s`,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Run the ladder per peer: probe `/health`, then (only if reachable) POST the
|
|
112
|
+
* diagnostic `/notify`. When `inject` is supplied (`--inject`), ALSO run the
|
|
113
|
+
* INVASIVE Processed-now tier on each reachable agent (routes a real prompt +
|
|
114
|
+
* wakes the agent). PURE w.r.t. `probe`/`diagnose`/`genToken`/`inject` — tests
|
|
115
|
+
* inject fakes so nothing hits the network.
|
|
116
|
+
*/
|
|
117
|
+
export async function gatherFleetDoctor(peers, probe, diagnose, genToken = randomUUID, inject) {
|
|
118
|
+
const out = [];
|
|
119
|
+
for (const peer of peers) {
|
|
120
|
+
const { host, port } = peer.info;
|
|
121
|
+
const health = await probe(host, port);
|
|
122
|
+
if (health === null) {
|
|
123
|
+
// Tier 1 failed → ladder stops; Accepted + Processed are N/A (not attempted).
|
|
124
|
+
out.push({
|
|
125
|
+
name: peer.name,
|
|
126
|
+
host,
|
|
127
|
+
port,
|
|
128
|
+
reachable: false,
|
|
129
|
+
accepted: null,
|
|
130
|
+
processedInject: inject ? null : undefined,
|
|
131
|
+
});
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
const token = genToken();
|
|
135
|
+
const ack = await diagnose(host, port, token);
|
|
136
|
+
const accepted = isAccepted(token, ack);
|
|
137
|
+
const ackAgent = ack.body?.agent;
|
|
138
|
+
const proc = inject ? await runProcessedInject(peer, ackAgent, inject) : undefined;
|
|
139
|
+
out.push({
|
|
140
|
+
name: peer.name,
|
|
141
|
+
host,
|
|
142
|
+
port,
|
|
143
|
+
reachable: true,
|
|
144
|
+
accepted,
|
|
145
|
+
ackAgent,
|
|
146
|
+
instanceId: ack.body?.instance_id,
|
|
147
|
+
acceptError: accepted ? undefined : acceptFailureReason(token, ack),
|
|
148
|
+
processedInject: proc ? proc.processedInject : undefined,
|
|
149
|
+
injectRunId: proc?.injectRunId,
|
|
150
|
+
injectError: proc?.injectError,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
return out;
|
|
154
|
+
}
|
|
155
|
+
const HEADERS = ['NAME', 'HOST:PORT', 'REACHABLE', 'ACCEPTED'];
|
|
156
|
+
const HEADERS_INJECT = [...HEADERS, 'PROCESSED'];
|
|
157
|
+
/** ✓ / ✗ for a boolean reachability flag. */
|
|
158
|
+
export function reachableGlyph(reachable) {
|
|
159
|
+
return reachable ? '✓' : '✗';
|
|
160
|
+
}
|
|
161
|
+
/** ✓ / ✗ / — for the tri-state Accepted (null = not attempted). */
|
|
162
|
+
export function acceptedGlyph(accepted) {
|
|
163
|
+
if (accepted === null)
|
|
164
|
+
return '—';
|
|
165
|
+
return accepted ? '✓' : '✗';
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Processed glyph (inject tier). ✓ = run_id echoed (processed end-to-end);
|
|
169
|
+
* `?` = UNCONFIRMED within the window (delivered but not echoed — possibly a
|
|
170
|
+
* busy agent, NOT necessarily a gap — deliberately NOT `✗`); `—` = not
|
|
171
|
+
* attempted (unreachable / inject off).
|
|
172
|
+
*/
|
|
173
|
+
export function processedGlyph(processed) {
|
|
174
|
+
if (processed === true)
|
|
175
|
+
return '✓';
|
|
176
|
+
if (processed === false)
|
|
177
|
+
return '?';
|
|
178
|
+
return '—';
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Build one display row per agent (pure — exported for tests). When `inject`
|
|
182
|
+
* is true, append the PROCESSED column.
|
|
183
|
+
*/
|
|
184
|
+
export function buildDoctorRows(results, inject = false) {
|
|
185
|
+
return results.map((r) => {
|
|
186
|
+
const base = [r.name, `${r.host}:${r.port}`, reachableGlyph(r.reachable), acceptedGlyph(r.accepted)];
|
|
187
|
+
return inject ? [...base, processedGlyph(r.processedInject)] : base;
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
/** Full rendered table (pure — exported for tests). */
|
|
191
|
+
export function formatDoctorTable(results, inject = false) {
|
|
192
|
+
return formatTable(inject ? HEADERS_INJECT : HEADERS, buildDoctorRows(results, inject));
|
|
193
|
+
}
|
|
194
|
+
/** Reachable AND Accepted both green. */
|
|
195
|
+
function isFullyOk(r) {
|
|
196
|
+
return r.reachable && r.accepted === true;
|
|
197
|
+
}
|
|
198
|
+
export function meshVerdict(results) {
|
|
199
|
+
if (results.length === 0)
|
|
200
|
+
return 'EMPTY';
|
|
201
|
+
return results.every(isFullyOk) ? 'HEALTHY' : 'DEGRADED';
|
|
202
|
+
}
|
|
203
|
+
/** `3/4 agents reachable + accepting; mesh interconnect: DEGRADED`. */
|
|
204
|
+
export function summaryLine(results) {
|
|
205
|
+
const total = results.length;
|
|
206
|
+
const ok = results.filter(isFullyOk).length;
|
|
207
|
+
return `${ok}/${total} agents reachable + accepting; mesh interconnect: ${meshVerdict(results)}`;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* The honesty footnote — non-invasive checks prove protocol-to-server ONLY.
|
|
211
|
+
* Kept as a single block so it renders identically in the table output and is
|
|
212
|
+
* carried verbatim in the `--json` `disclaimer` field.
|
|
213
|
+
*/
|
|
214
|
+
export const HONESTY_LEGEND = [
|
|
215
|
+
'Legend: REACHABLE = mTLS /health answered. ACCEPTED = diagnostic /notify ACK (HTTP 200 + ack + token echo).',
|
|
216
|
+
'NOTE: these non-invasive checks prove the protocol REACHES THE SERVER (mTLS auth + parse) ONLY —',
|
|
217
|
+
' NOT delivery to the agent (the MCP-push → agent-reads gap is not exercised). Actual mesh',
|
|
218
|
+
' delivery needs `macf fleet doctor --inject` (INVASIVE — wakes each agent); routing-plane',
|
|
219
|
+
' delivery needs an e2e run.',
|
|
220
|
+
].join('\n');
|
|
221
|
+
const HONESTY_DISCLAIMER = 'Non-invasive checks prove protocol-to-server (mTLS auth + parse) ONLY, NOT delivery to the ' +
|
|
222
|
+
'agent (MCP-push → agent-reads gap). Mesh delivery needs --inject (later increment); ' +
|
|
223
|
+
'routing-plane delivery needs e2e.';
|
|
224
|
+
/**
|
|
225
|
+
* The `--inject` Processed-tier legend. INVASIVE: it routes a real probe to each
|
|
226
|
+
* reachable agent + costs it a turn. A `?` (UNCONFIRMED) is NOT "deaf" — a busy
|
|
227
|
+
* agent mid-long-turn legitimately won't process the probe within the window.
|
|
228
|
+
*/
|
|
229
|
+
export const INJECT_LEGEND = [
|
|
230
|
+
'Legend (--inject): PROCESSED ✓ = the probe run_id echoed back via /health.last_processed —',
|
|
231
|
+
' the FULL chain proven (deliver → MCP push → agent read it as a TURN → local turn-receipt',
|
|
232
|
+
' → /health surfaced it). ? = UNCONFIRMED within the window (delivered, but no echo yet —',
|
|
233
|
+
' a busy agent mid-long-turn legitimately may not have processed it; NOT proof of a gap).',
|
|
234
|
+
' — = not attempted (agent unreachable).',
|
|
235
|
+
'INVASIVE: --inject routes a REAL /notify to each reachable agent, WAKING each + costing it a turn.',
|
|
236
|
+
' It is the IDLE-agent fallback; for a busy/active agent prefer the passive last_processed self-report.',
|
|
237
|
+
].join('\n');
|
|
238
|
+
/** `2/3 reachable agents processed an injected probe (1 unconfirmed — possibly busy)`. */
|
|
239
|
+
export function injectSummaryLine(results) {
|
|
240
|
+
const attempted = results.filter((r) => r.processedInject !== null && r.processedInject !== undefined);
|
|
241
|
+
const processed = attempted.filter((r) => r.processedInject === true).length;
|
|
242
|
+
const unconfirmed = attempted.length - processed;
|
|
243
|
+
const tail = unconfirmed > 0 ? ` (${unconfirmed} unconfirmed — possibly busy, NOT necessarily a gap)` : '';
|
|
244
|
+
return `${processed}/${attempted.length} reachable agents processed an injected probe${tail}`;
|
|
245
|
+
}
|
|
246
|
+
/** Count of reachable agents an `--inject` run will WAKE (for the up-front warning). */
|
|
247
|
+
export function injectableCount(results) {
|
|
248
|
+
return results.filter((r) => r.reachable).length;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Structured `--json` shape for automation. THIS IS THE INPUT CONTRACT the
|
|
252
|
+
* DR-031 watchdog consumes — keep it clean + stable. `accepted` is tri-state
|
|
253
|
+
* (`true`/`false`/`null`); `summary.verdict` is the machine-readable health.
|
|
254
|
+
*
|
|
255
|
+
* `schema_version` is the HARD version contract (DR-006 watchdog request,
|
|
256
|
+
* macf-devops-toolkit#115): a consumer asserts `schema_version === <known>`
|
|
257
|
+
* and refuses an unknown value, so it fails LOUD on ANY breaking change —
|
|
258
|
+
* not just a renamed key (which a presence-check catches) but a same-name
|
|
259
|
+
* SEMANTIC change (e.g. `accepted` going tri-state-bool → string-enum) that
|
|
260
|
+
* would otherwise parse clean and silently misread (the Instance-13-adjacent
|
|
261
|
+
* silent-fallback at the supervisor's own input). BUMP this on any breaking
|
|
262
|
+
* change (rename / removal / semantic shift); additive-optional fields do NOT
|
|
263
|
+
* bump it.
|
|
264
|
+
*/
|
|
265
|
+
export const FLEET_DOCTOR_JSON_SCHEMA_VERSION = 1;
|
|
266
|
+
/**
|
|
267
|
+
* `--inject` ADDS `processed_inject` (+ `inject_run_id` / `inject_error` /
|
|
268
|
+
* top-level `inject`) WITHOUT a `schema_version` bump. Per the documented policy
|
|
269
|
+
* above, additive-OPTIONAL fields do NOT bump the version (a bump is reserved
|
|
270
|
+
* for rename / removal / a same-name SEMANTIC shift). `processed_inject` is
|
|
271
|
+
* present ONLY when `--inject` ran (`opts.inject`); a watchdog that pins
|
|
272
|
+
* `schema_version === 1` keeps parsing clean and simply ignores the new key —
|
|
273
|
+
* exactly the additive-tolerance the version contract is built for.
|
|
274
|
+
*/
|
|
275
|
+
export function fleetDoctorToJson(results, project, opts = {}) {
|
|
276
|
+
return {
|
|
277
|
+
schema_version: FLEET_DOCTOR_JSON_SCHEMA_VERSION,
|
|
278
|
+
project: project ?? null,
|
|
279
|
+
...(opts.inject
|
|
280
|
+
? {
|
|
281
|
+
// Surfaced ONLY in inject mode so a consumer never misreads a
|
|
282
|
+
// mode-off run as "0 processed". Loudly flags the invasive nature.
|
|
283
|
+
inject: {
|
|
284
|
+
invasive: true,
|
|
285
|
+
woke: injectableCount(results),
|
|
286
|
+
processed: results.filter((r) => r.processedInject === true).length,
|
|
287
|
+
},
|
|
288
|
+
}
|
|
289
|
+
: {}),
|
|
290
|
+
summary: {
|
|
291
|
+
total: results.length,
|
|
292
|
+
reachable: results.filter((r) => r.reachable).length,
|
|
293
|
+
accepting: results.filter(isFullyOk).length,
|
|
294
|
+
verdict: meshVerdict(results),
|
|
295
|
+
},
|
|
296
|
+
agents: results.map((r) => ({
|
|
297
|
+
name: r.name,
|
|
298
|
+
host: r.host,
|
|
299
|
+
port: r.port,
|
|
300
|
+
reachable: r.reachable,
|
|
301
|
+
accepted: r.accepted,
|
|
302
|
+
ack_agent: r.ackAgent ?? null,
|
|
303
|
+
instance_id: r.instanceId ?? null,
|
|
304
|
+
accept_error: r.acceptError ?? null,
|
|
305
|
+
// Additive-optional (no schema bump): tri-state true/false/null, present
|
|
306
|
+
// only under --inject. null = not attempted (unreachable).
|
|
307
|
+
...(opts.inject
|
|
308
|
+
? {
|
|
309
|
+
processed_inject: r.processedInject ?? null,
|
|
310
|
+
inject_run_id: r.injectRunId ?? null,
|
|
311
|
+
inject_error: r.injectError ?? null,
|
|
312
|
+
}
|
|
313
|
+
: {}),
|
|
314
|
+
})),
|
|
315
|
+
disclaimer: HONESTY_DISCLAIMER,
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* The real mTLS diagnostic POST. Mirrors `pingAgentHealth`'s request shape
|
|
320
|
+
* (same CA + client cert/key, `rejectUnauthorized`, timeout) but POSTs the
|
|
321
|
+
* diagnostic body to `/notify`. Resolves with a `DiagnosticAck` describing the
|
|
322
|
+
* outcome; never throws (failures become `{ status: null, error }`).
|
|
323
|
+
*/
|
|
324
|
+
export async function postDiagnosticNotify(config) {
|
|
325
|
+
const { host, port, caCertPem, certPath, keyPath, correlationToken, timeoutMs = DEFAULT_TIMEOUT_MS, } = config;
|
|
326
|
+
if (!existsSync(certPath) || !existsSync(keyPath)) {
|
|
327
|
+
return { status: null, body: null, error: 'client cert/key missing' };
|
|
328
|
+
}
|
|
329
|
+
const payload = JSON.stringify({
|
|
330
|
+
type: 'mention',
|
|
331
|
+
diagnostic: true,
|
|
332
|
+
correlation_token: correlationToken,
|
|
333
|
+
});
|
|
334
|
+
return new Promise((resolve) => {
|
|
335
|
+
const req = request({
|
|
336
|
+
hostname: host,
|
|
337
|
+
port,
|
|
338
|
+
method: 'POST',
|
|
339
|
+
path: '/notify',
|
|
340
|
+
ca: Buffer.from(caCertPem),
|
|
341
|
+
cert: readFileSync(certPath),
|
|
342
|
+
key: readFileSync(keyPath),
|
|
343
|
+
rejectUnauthorized: true,
|
|
344
|
+
timeout: timeoutMs,
|
|
345
|
+
headers: {
|
|
346
|
+
'content-type': 'application/json',
|
|
347
|
+
'content-length': Buffer.byteLength(payload),
|
|
348
|
+
},
|
|
349
|
+
}, (res) => {
|
|
350
|
+
const chunks = [];
|
|
351
|
+
res.on('data', (chunk) => chunks.push(chunk));
|
|
352
|
+
res.on('end', () => {
|
|
353
|
+
const status = res.statusCode ?? null;
|
|
354
|
+
let body;
|
|
355
|
+
try {
|
|
356
|
+
body = JSON.parse(Buffer.concat(chunks).toString('utf-8'));
|
|
357
|
+
}
|
|
358
|
+
catch {
|
|
359
|
+
body = null;
|
|
360
|
+
}
|
|
361
|
+
resolve({ status, body, error: body ? undefined : 'non-JSON response' });
|
|
362
|
+
});
|
|
363
|
+
});
|
|
364
|
+
req.on('error', (e) => resolve({ status: null, body: null, error: e.message }));
|
|
365
|
+
req.on('timeout', () => {
|
|
366
|
+
req.destroy();
|
|
367
|
+
resolve({ status: null, body: null, error: 'timeout' });
|
|
368
|
+
});
|
|
369
|
+
req.write(payload);
|
|
370
|
+
req.end();
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
/** Wire the registry + both mTLS calls from a project's config. */
|
|
374
|
+
async function resolveDepsFromRegistry(projectDir) {
|
|
375
|
+
const config = readAgentConfig(projectDir);
|
|
376
|
+
if (!config) {
|
|
377
|
+
console.error('No macf-agent.json found. Run `macf init` first.');
|
|
378
|
+
return { ok: false, code: 1 };
|
|
379
|
+
}
|
|
380
|
+
const token = await generateToken(tokenSourceFromConfig(projectDir, config));
|
|
381
|
+
const registry = createRegistryFromConfig(config.registry, config.project, token);
|
|
382
|
+
const client = createClientFromConfig(config.registry, token);
|
|
383
|
+
const caCertPem = await client.readVariable(`${toVariableSegment(config.project)}_CA_CERT`);
|
|
384
|
+
if (!caCertPem) {
|
|
385
|
+
console.error('CA certificate not found in registry. Run `macf certs init` first.');
|
|
386
|
+
return { ok: false, code: 1 };
|
|
387
|
+
}
|
|
388
|
+
const certPath = agentCertPath(projectDir);
|
|
389
|
+
const keyPath = agentKeyPath(projectDir);
|
|
390
|
+
return {
|
|
391
|
+
ok: true,
|
|
392
|
+
deps: {
|
|
393
|
+
project: config.project,
|
|
394
|
+
listPeers: () => registry.list(''),
|
|
395
|
+
probe: (host, port) => pingAgentHealth({ host, port, caCertPem, certPath, keyPath }),
|
|
396
|
+
diagnose: (host, port, correlationToken) => postDiagnosticNotify({ host, port, caCertPem, certPath, keyPath, correlationToken }),
|
|
397
|
+
injectPost: (host, port, runId, markerAgent) => postInjectNotify({ host, port, caCertPem, certPath, keyPath, runId, markerAgent }),
|
|
398
|
+
injectPoll: (host, port) => pollLastProcessedToken({ host, port, caCertPem, certPath, keyPath }),
|
|
399
|
+
},
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Build the `FleetInjectConfig` from deps + options when `--inject` is on.
|
|
404
|
+
* Returns `undefined` when inject is off OR the deps lack the inject seams
|
|
405
|
+
* (defensive — production always wires them). A `~4s` poll interval; the
|
|
406
|
+
* timeout-seconds budget derives `maxPolls`.
|
|
407
|
+
*/
|
|
408
|
+
function buildInjectConfig(deps, opts) {
|
|
409
|
+
if (!opts.inject)
|
|
410
|
+
return undefined;
|
|
411
|
+
if (!deps.injectPost || !deps.injectPoll)
|
|
412
|
+
return undefined;
|
|
413
|
+
const intervalMs = DEFAULT_INJECT_POLL_INTERVAL_MS;
|
|
414
|
+
const budgetSec = opts.injectTimeoutSec ?? 24;
|
|
415
|
+
// maxPolls so that (maxPolls-1)*interval ≈ budget; floor at 2 polls.
|
|
416
|
+
const maxPolls = Math.max(2, Math.round((budgetSec * 1000) / intervalMs) + 1);
|
|
417
|
+
return {
|
|
418
|
+
post: deps.injectPost,
|
|
419
|
+
poll: deps.injectPoll,
|
|
420
|
+
genRunId: deps.injectGenRunId,
|
|
421
|
+
sleep: deps.injectSleep,
|
|
422
|
+
maxPolls,
|
|
423
|
+
pollIntervalMs: intervalMs,
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* `macf fleet doctor` entry point. Returns the shell exit code — 1 when the
|
|
428
|
+
* mesh is DEGRADED (any agent unreachable or not-accepting), 0 when HEALTHY or
|
|
429
|
+
* when no agents are registered (matching the `macf doctor` "non-zero on
|
|
430
|
+
* problem" convention). The `--json` body still prints to stdout regardless of
|
|
431
|
+
* exit code; the watchdog reads `summary.verdict` from it. `deps` is injected
|
|
432
|
+
* by tests; production resolves it from the project's registry config.
|
|
433
|
+
*/
|
|
434
|
+
export async function runFleetDoctor(projectDir, opts = {}, deps) {
|
|
435
|
+
let resolved = deps;
|
|
436
|
+
if (!resolved) {
|
|
437
|
+
const r = await resolveDepsFromRegistry(projectDir);
|
|
438
|
+
if (!r.ok)
|
|
439
|
+
return r.code;
|
|
440
|
+
resolved = r.deps;
|
|
441
|
+
}
|
|
442
|
+
const inject = buildInjectConfig(resolved, opts);
|
|
443
|
+
const peers = await resolved.listPeers();
|
|
444
|
+
// Loud up-front INVASIVE warning (DR-030 §3) to stderr BEFORE we route any
|
|
445
|
+
// real probe. Skipped under --json (machine consumer) + when no agents exist.
|
|
446
|
+
// The exact reachable count is reported post-gather (we'd otherwise double-
|
|
447
|
+
// probe every agent just to count).
|
|
448
|
+
if (inject && !opts.json && peers.length > 0) {
|
|
449
|
+
console.error(`⚠️ --inject is INVASIVE: it routes a REAL /notify to each REACHABLE agent ` +
|
|
450
|
+
`(up to ${String(peers.length)} registered), WAKING it + costing it a turn. ` +
|
|
451
|
+
`IDLE-agent fallback — prefer the passive last_processed self-report for a busy agent.`);
|
|
452
|
+
}
|
|
453
|
+
const results = await gatherFleetDoctor(peers, resolved.probe, resolved.diagnose, resolved.genToken, inject);
|
|
454
|
+
if (opts.json) {
|
|
455
|
+
console.log(JSON.stringify(fleetDoctorToJson(results, resolved.project, { inject: !!inject }), null, 2));
|
|
456
|
+
return meshVerdict(results) === 'DEGRADED' ? 1 : 0;
|
|
457
|
+
}
|
|
458
|
+
const header = `macf fleet doctor${resolved.project ? ` — ${resolved.project}` : ''}`;
|
|
459
|
+
if (results.length === 0) {
|
|
460
|
+
console.log(`${header}\n\nNo agents registered in the registry.`);
|
|
461
|
+
return 0;
|
|
462
|
+
}
|
|
463
|
+
console.log(`${header}\n`);
|
|
464
|
+
console.log(formatDoctorTable(results, !!inject));
|
|
465
|
+
console.log('');
|
|
466
|
+
console.log(summaryLine(results));
|
|
467
|
+
if (inject) {
|
|
468
|
+
console.log(`--inject routed a REAL probe to ${String(injectableCount(results))} reachable agent(s), waking each.`);
|
|
469
|
+
console.log(injectSummaryLine(results));
|
|
470
|
+
}
|
|
471
|
+
console.log('');
|
|
472
|
+
console.log(HONESTY_LEGEND);
|
|
473
|
+
if (inject) {
|
|
474
|
+
console.log('');
|
|
475
|
+
console.log(INJECT_LEGEND);
|
|
476
|
+
}
|
|
477
|
+
// The Processed tier does NOT fold into the verdict/exit code: an UNCONFIRMED
|
|
478
|
+
// is "possibly busy," not "broken." Exit stays driven by Reachable+Accepted.
|
|
479
|
+
return meshVerdict(results) === 'DEGRADED' ? 1 : 0;
|
|
480
|
+
}
|
|
481
|
+
//# sourceMappingURL=fleet-doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fleet-doctor.js","sourceRoot":"","sources":["../../../src/cli/commands/fleet-doctor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { AgentInfo, HealthResponse } from '@groundnuty/macf-core';
|
|
2
|
+
/**
|
|
3
|
+
* DR-030 sibling-increment `/health.state` object self-report — read
|
|
4
|
+
* DEFENSIVELY (NOT yet in the `HealthResponse` type). All fields optional; the
|
|
5
|
+
* field may also arrive as a plain `"idle"|"busy"` string (DR-030 §5).
|
|
6
|
+
*/
|
|
7
|
+
export interface AgentRunState {
|
|
8
|
+
readonly status?: string;
|
|
9
|
+
readonly turn_number?: number;
|
|
10
|
+
readonly elapsed_ms?: number;
|
|
11
|
+
}
|
|
12
|
+
/** DR-030 sibling-increment `/health.otel` self-report — read DEFENSIVELY. */
|
|
13
|
+
export interface AgentOtelReport {
|
|
14
|
+
readonly endpoint_reachable?: boolean;
|
|
15
|
+
}
|
|
16
|
+
/** One agent's roster + reachability + raw self-report body. */
|
|
17
|
+
export interface FleetAgentStatus {
|
|
18
|
+
readonly name: string;
|
|
19
|
+
readonly host: string;
|
|
20
|
+
readonly port: number;
|
|
21
|
+
readonly online: boolean;
|
|
22
|
+
/** Raw `/health` body (incl. any defensively-read `state`/`otel`), or null when offline. */
|
|
23
|
+
readonly health: HealthResponse | null;
|
|
24
|
+
}
|
|
25
|
+
/** Probe a single endpoint's `/health`; null on any failure. Injectable for tests. */
|
|
26
|
+
export type FleetProbeFn = (host: string, port: number) => Promise<HealthResponse | null>;
|
|
27
|
+
/**
|
|
28
|
+
* Probe every peer once and collect roster + reachability + raw body. PURE
|
|
29
|
+
* w.r.t. `probe` — tests inject a fake so nothing hits the network.
|
|
30
|
+
*/
|
|
31
|
+
export declare function gatherFleetStatus(peers: readonly {
|
|
32
|
+
readonly name: string;
|
|
33
|
+
readonly info: AgentInfo;
|
|
34
|
+
}[], probe: FleetProbeFn): Promise<readonly FleetAgentStatus[]>;
|
|
35
|
+
/** Human-readable elapsed from whole seconds: `45s` / `18m` / `2h5m`. */
|
|
36
|
+
export declare function formatUptime(seconds: number): string;
|
|
37
|
+
/** Whole days from `now` (ms) until an ISO timestamp; negative when past. */
|
|
38
|
+
export declare function daysUntil(isoDate: string, now: number): number;
|
|
39
|
+
/**
|
|
40
|
+
* Render `cert_expiry` with a severity marker: crit (`✗`) when <7d / already
|
|
41
|
+
* expired, warn (`⚠`) when <30d. An expired leaf = silent off-channels
|
|
42
|
+
* (DR-030 §5), so it earns the loudest marker.
|
|
43
|
+
*/
|
|
44
|
+
export declare function formatCertExpiry(certExpiry: string | null | undefined, now: number): string;
|
|
45
|
+
/**
|
|
46
|
+
* Render the `state` self-report. Tolerates the field being absent, a plain
|
|
47
|
+
* `"idle"|"busy"` string (DR-030 §5), or a `{ status, turn_number, elapsed_ms }`
|
|
48
|
+
* object (rendered like `busy 18m on turn 7`).
|
|
49
|
+
*/
|
|
50
|
+
export declare function formatRunState(raw: unknown): string;
|
|
51
|
+
/** Render the `otel` self-report's `endpoint_reachable` flag. */
|
|
52
|
+
export declare function formatOtel(raw: unknown): string;
|
|
53
|
+
/** Build one display row per agent (pure — exported for tests). */
|
|
54
|
+
export declare function buildFleetRows(statuses: readonly FleetAgentStatus[], now: number): readonly (readonly string[])[];
|
|
55
|
+
/** Full rendered table for a fleet status list (pure — exported for tests). */
|
|
56
|
+
export declare function formatFleetTable(statuses: readonly FleetAgentStatus[], now: number): string;
|
|
57
|
+
/**
|
|
58
|
+
* Structured `--json` shape for automation. Carries the RAW `/health` body so
|
|
59
|
+
* any present `state`/`otel`/future fields pass through untouched.
|
|
60
|
+
*/
|
|
61
|
+
export declare function fleetStatusToJson(statuses: readonly FleetAgentStatus[]): unknown;
|
|
62
|
+
/** Options for `runFleetStatus`. */
|
|
63
|
+
export interface RunFleetStatusOptions {
|
|
64
|
+
/** Emit the structured data as JSON instead of a table. */
|
|
65
|
+
readonly json?: boolean;
|
|
66
|
+
/** Clock for cert-expiry math (defaults to `Date.now()`; injected in tests). */
|
|
67
|
+
readonly now?: number;
|
|
68
|
+
}
|
|
69
|
+
/** Injectable seam so tests drive the command without touching the registry/network. */
|
|
70
|
+
export interface FleetStatusDeps {
|
|
71
|
+
readonly listPeers: () => Promise<readonly {
|
|
72
|
+
readonly name: string;
|
|
73
|
+
readonly info: AgentInfo;
|
|
74
|
+
}[]>;
|
|
75
|
+
readonly probe: FleetProbeFn;
|
|
76
|
+
readonly project?: string;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* `macf fleet status` entry point. Returns the shell exit code. `deps` is
|
|
80
|
+
* injected by tests; production resolves it from the project's registry config.
|
|
81
|
+
*/
|
|
82
|
+
export declare function runFleetStatus(projectDir: string, opts?: RunFleetStatusOptions, deps?: FleetStatusDeps): Promise<number>;
|
|
83
|
+
//# sourceMappingURL=fleet.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fleet.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/fleet.ts"],"names":[],"mappings":"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"}
|