@shardworks/nexus 0.1.270 → 0.1.272
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/README.md +15 -1
- package/dist/commands/clock.d.ts +225 -0
- package/dist/commands/clock.d.ts.map +1 -0
- package/dist/commands/clock.js +652 -0
- package/dist/commands/clock.js.map +1 -0
- package/dist/commands/index.d.ts +14 -0
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +18 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/signal.d.ts +41 -0
- package/dist/commands/signal.d.ts.map +1 -0
- package/dist/commands/signal.js +85 -0
- package/dist/commands/signal.js.map +1 -0
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +59 -40
- package/dist/commands/start.js.map +1 -1
- package/dist/commands/stop.d.ts.map +1 -1
- package/dist/commands/stop.js +1 -41
- package/dist/commands/stop.js.map +1 -1
- package/dist/program.d.ts.map +1 -1
- package/dist/program.js +17 -2
- package/dist/program.js.map +1 -1
- package/dist/started-guild.d.ts +41 -0
- package/dist/started-guild.d.ts.map +1 -0
- package/dist/started-guild.js +47 -0
- package/dist/started-guild.js.map +1 -0
- package/package.json +5 -4
|
@@ -0,0 +1,652 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* nsg clock — operator-facing Clockworks CLI.
|
|
3
|
+
*
|
|
4
|
+
* Three subcommands under `nsg clock` that compose on top of
|
|
5
|
+
* `ClockworksApi.processEvents` and a direct read of the
|
|
6
|
+
* `clockworks/events` book:
|
|
7
|
+
*
|
|
8
|
+
* - `nsg clock list` — print pending events (or, with
|
|
9
|
+
* `--include-processed`, every event), one event per two-line
|
|
10
|
+
* block (or a single line when payload is null), in id-ascending
|
|
11
|
+
* order. `--limit N` caps output at N entries.
|
|
12
|
+
* - `nsg clock tick [id]` — process a single event. Without `id`,
|
|
13
|
+
* the next pending event in id order; with `id`, exactly that
|
|
14
|
+
* event after a CLI-side pre-check that it exists and is still
|
|
15
|
+
* pending. Prints per-dispatch summary lines via the
|
|
16
|
+
* `processEvents({ onDispatch })` observer.
|
|
17
|
+
* - `nsg clock run` — loop `processEvents()` until the dispatcher
|
|
18
|
+
* reports zero processed events for an iteration. No sleep, no
|
|
19
|
+
* daemon — finite drain. Mid-sweep arrivals are picked up on the
|
|
20
|
+
* next iteration.
|
|
21
|
+
*
|
|
22
|
+
* The CLI package deliberately does not depend on the clockworks or
|
|
23
|
+
* stacks plugin packages — apparatus interfaces are declared inline
|
|
24
|
+
* and resolved at runtime via `guild().apparatus<T>(name)`. This
|
|
25
|
+
* mirrors the discipline practiced by `signal` and `start`.
|
|
26
|
+
*
|
|
27
|
+
* Hand-written rather than auto-built because:
|
|
28
|
+
* - `tick [id]` is an optional positional, which the auto-builder
|
|
29
|
+
* cannot express.
|
|
30
|
+
* - `--include-processed` and `--limit <N>` need locally-validated
|
|
31
|
+
* parsing.
|
|
32
|
+
* - Exit-code semantics are nontrivial: nonzero only when at least
|
|
33
|
+
* one dispatch recorded `status: error`, plus the
|
|
34
|
+
* missing-event-id and already-processed-event branches.
|
|
35
|
+
*
|
|
36
|
+
* See commission c-mody57g7 decisions D1–D20.
|
|
37
|
+
*/
|
|
38
|
+
import { Command } from 'commander';
|
|
39
|
+
import { guild } from '@shardworks/nexus-core';
|
|
40
|
+
import { clockStart, clockStatus, clockStop, runForegroundDaemonFromGuild, } from '@shardworks/clockworks-apparatus';
|
|
41
|
+
import { getStartedGuild } from "../started-guild.js";
|
|
42
|
+
// ── Constants (D9, D10, D13, D14, D15, D19) ──────────────────────────
|
|
43
|
+
/** Maximum payload-preview length for `list` (D19). */
|
|
44
|
+
const PAYLOAD_PREVIEW_MAX = 120;
|
|
45
|
+
/** Empty-queue messages — one per command (D13). */
|
|
46
|
+
const EMPTY_LIST = 'No pending events.';
|
|
47
|
+
const EMPTY_TICK = 'Queue is empty; nothing to process.';
|
|
48
|
+
const EMPTY_RUN = 'Queue is empty; processed 0 events.';
|
|
49
|
+
// ── Helpers ──────────────────────────────────────────────────────────
|
|
50
|
+
/**
|
|
51
|
+
* Resolve the loaded guild or throw the canonical no-guild error so
|
|
52
|
+
* the action wrapper can convert it to an `Error: …` exit-1 line.
|
|
53
|
+
*/
|
|
54
|
+
function requireGuild() {
|
|
55
|
+
try {
|
|
56
|
+
return guild();
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
throw new Error('Not inside a guild. Run `nsg init` to create one first.');
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Build the daemon-coexistence warning when the Clockworks daemon is
|
|
64
|
+
* already running. Returns `null` when the daemon is not running so
|
|
65
|
+
* callers can append it conditionally.
|
|
66
|
+
*
|
|
67
|
+
* The warning is non-fatal: `nsg clock tick` and `nsg clock run` keep
|
|
68
|
+
* working even when the daemon is up. The dispatch sweep
|
|
69
|
+
* (read-pending → invoke → patch-processed) is not atomic across
|
|
70
|
+
* processes, so a daemon and a manual invocation that overlap may
|
|
71
|
+
* each invoke the same relay for the same event. Operators rely on
|
|
72
|
+
* relay-author idempotency (see `RelayHandler` in
|
|
73
|
+
* `packages/plugins/clockworks/src/relay.ts`); this warning exists so
|
|
74
|
+
* they understand the contract is engaged whenever they tick or run
|
|
75
|
+
* alongside the daemon.
|
|
76
|
+
*/
|
|
77
|
+
function daemonCoexistenceWarning(home) {
|
|
78
|
+
const status = clockStatus(home);
|
|
79
|
+
if (!status.running)
|
|
80
|
+
return null;
|
|
81
|
+
return (`Warning: clockworks daemon is running (pid ${status.pid}); ` +
|
|
82
|
+
`this manual invocation will run concurrently — relays may be ` +
|
|
83
|
+
`invoked more than once for overlapping events.`);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Render the payload preview for `list`. Returns null when the
|
|
87
|
+
* payload is exactly null (D19 — payload line omitted entirely);
|
|
88
|
+
* otherwise returns a truncated JSON string.
|
|
89
|
+
*/
|
|
90
|
+
export function renderPayloadPreview(payload) {
|
|
91
|
+
if (payload === null)
|
|
92
|
+
return null;
|
|
93
|
+
let json;
|
|
94
|
+
try {
|
|
95
|
+
json = JSON.stringify(payload);
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
json = '<unserializable>';
|
|
99
|
+
}
|
|
100
|
+
if (json === undefined)
|
|
101
|
+
return null;
|
|
102
|
+
if (json.length <= PAYLOAD_PREVIEW_MAX)
|
|
103
|
+
return json;
|
|
104
|
+
// Reserve one char for the trailing ellipsis.
|
|
105
|
+
return json.slice(0, PAYLOAD_PREVIEW_MAX - 1) + '…';
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Format a single event for `nsg clock list`. Two lines when payload
|
|
109
|
+
* is non-null; single line otherwise.
|
|
110
|
+
*/
|
|
111
|
+
export function formatEventBlock(event) {
|
|
112
|
+
const head = `${event.id} ${event.name} ${event.emitter} ${event.firedAt}`;
|
|
113
|
+
const preview = renderPayloadPreview(event.payload);
|
|
114
|
+
if (preview === null)
|
|
115
|
+
return head;
|
|
116
|
+
return `${head}\n payload: ${preview}`;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Format a single dispatch observation for the per-dispatch summary
|
|
120
|
+
* line emitted by `tick` and `run`. Per D10:
|
|
121
|
+
* `[<handlerName>] <status> <durationMs>ms`
|
|
122
|
+
* With `: <error>` appended on the same line when `status` is error.
|
|
123
|
+
*
|
|
124
|
+
* Loop-guard `'skipped'` rows render as
|
|
125
|
+
* `[<handlerName>] skipped: <loop-guard reason>`
|
|
126
|
+
* — the same colon-then-message convention as the error arm so output
|
|
127
|
+
* stays parseable. Skipped lines do NOT include a duration (the
|
|
128
|
+
* dispatcher never invoked the relay; surfacing `0ms` would only
|
|
129
|
+
* mislead operators).
|
|
130
|
+
*/
|
|
131
|
+
export function formatDispatchLine(obs) {
|
|
132
|
+
if (obs.status === 'skipped') {
|
|
133
|
+
const head = `[${obs.handlerName}] skipped`;
|
|
134
|
+
return obs.error ? `${head}: ${obs.error}` : head;
|
|
135
|
+
}
|
|
136
|
+
const head = `[${obs.handlerName}] ${obs.status} ${obs.durationMs}ms`;
|
|
137
|
+
if (obs.status === 'error' && obs.error) {
|
|
138
|
+
return `${head}: ${obs.error}`;
|
|
139
|
+
}
|
|
140
|
+
return head;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Read events for `nsg clock list` and render them.
|
|
144
|
+
*
|
|
145
|
+
* The book read uses `find` with a `where` filter when only pending
|
|
146
|
+
* events are wanted (the common case); otherwise `list` with no
|
|
147
|
+
* filter (the `--include-processed` path).
|
|
148
|
+
*/
|
|
149
|
+
export async function runList(input) {
|
|
150
|
+
const g = requireGuild();
|
|
151
|
+
const stacks = g.apparatus('stacks');
|
|
152
|
+
const events = stacks.book('clockworks', 'events');
|
|
153
|
+
const orderBy = [['id', 'asc']];
|
|
154
|
+
let rows;
|
|
155
|
+
if (input.includeProcessed) {
|
|
156
|
+
const opts = { orderBy };
|
|
157
|
+
if (input.limit !== undefined)
|
|
158
|
+
opts.limit = input.limit;
|
|
159
|
+
rows = await events.list(opts);
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
const query = {
|
|
163
|
+
where: [['processed', '=', false]],
|
|
164
|
+
orderBy,
|
|
165
|
+
};
|
|
166
|
+
if (input.limit !== undefined)
|
|
167
|
+
query.limit = input.limit;
|
|
168
|
+
rows = await events.find(query);
|
|
169
|
+
}
|
|
170
|
+
if (rows.length === 0) {
|
|
171
|
+
return { lines: [EMPTY_LIST], count: 0, empty: true };
|
|
172
|
+
}
|
|
173
|
+
const lines = [];
|
|
174
|
+
for (const row of rows) {
|
|
175
|
+
lines.push(formatEventBlock(row));
|
|
176
|
+
}
|
|
177
|
+
return { lines, count: rows.length, empty: false };
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Process a single event via `processEvents({ eventId })` or
|
|
181
|
+
* `processEvents({ max: 1 })` and capture the per-dispatch summary
|
|
182
|
+
* lines via the observer.
|
|
183
|
+
*
|
|
184
|
+
* The `events.get(id)` pre-check happens here per D4: missing-id and
|
|
185
|
+
* already-processed cases never reach the dispatcher.
|
|
186
|
+
*/
|
|
187
|
+
export async function runTick(input) {
|
|
188
|
+
const g = requireGuild();
|
|
189
|
+
const clockworks = g.apparatus('clockworks');
|
|
190
|
+
const stacks = g.apparatus('stacks');
|
|
191
|
+
const events = stacks.book('clockworks', 'events');
|
|
192
|
+
// Daemon-coexistence warning — emitted independently of the
|
|
193
|
+
// dispatch outcome so operators always see whether they're racing
|
|
194
|
+
// the daemon. Best-effort: a thrown clockStatus must not block tick.
|
|
195
|
+
const warnings = [];
|
|
196
|
+
try {
|
|
197
|
+
const w = daemonCoexistenceWarning(g.home);
|
|
198
|
+
if (w)
|
|
199
|
+
warnings.push(w);
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
// ignore — diagnostic warning, not load-bearing
|
|
203
|
+
}
|
|
204
|
+
const lines = [];
|
|
205
|
+
// Capture the targeted event row (or the next-pending one) so we can
|
|
206
|
+
// surface the no-match line per D16 without re-reading the book
|
|
207
|
+
// after the sweep.
|
|
208
|
+
let targetEvent;
|
|
209
|
+
if (input.eventId !== undefined) {
|
|
210
|
+
targetEvent = await events.get(input.eventId);
|
|
211
|
+
if (!targetEvent) {
|
|
212
|
+
return {
|
|
213
|
+
lines: [`Error: clockworks: event "${input.eventId}" not found in events book.`],
|
|
214
|
+
hadError: true,
|
|
215
|
+
empty: false,
|
|
216
|
+
notFound: true,
|
|
217
|
+
alreadyProcessed: false,
|
|
218
|
+
warnings,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
if (targetEvent.processed) {
|
|
222
|
+
return {
|
|
223
|
+
lines: [
|
|
224
|
+
`Warning: clockworks: event "${input.eventId}" has already been processed.`,
|
|
225
|
+
],
|
|
226
|
+
hadError: true,
|
|
227
|
+
empty: false,
|
|
228
|
+
notFound: false,
|
|
229
|
+
alreadyProcessed: true,
|
|
230
|
+
warnings,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
// Next-pending mode: peek ahead so we know which event the
|
|
236
|
+
// dispatcher will pick up. Using the same id-ascending order as
|
|
237
|
+
// the dispatcher's own find call so the peek matches.
|
|
238
|
+
const peek = await events.find({
|
|
239
|
+
where: [['processed', '=', false]],
|
|
240
|
+
orderBy: [['id', 'asc']],
|
|
241
|
+
limit: 1,
|
|
242
|
+
});
|
|
243
|
+
targetEvent = peek[0] ?? null;
|
|
244
|
+
if (!targetEvent) {
|
|
245
|
+
return {
|
|
246
|
+
lines: [EMPTY_TICK],
|
|
247
|
+
hadError: false,
|
|
248
|
+
empty: true,
|
|
249
|
+
notFound: false,
|
|
250
|
+
alreadyProcessed: false,
|
|
251
|
+
warnings,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
const observedEventIds = new Set();
|
|
256
|
+
const opts = {
|
|
257
|
+
onDispatch: (obs) => {
|
|
258
|
+
observedEventIds.add(obs.eventId);
|
|
259
|
+
lines.push(formatDispatchLine(obs));
|
|
260
|
+
},
|
|
261
|
+
};
|
|
262
|
+
if (input.eventId !== undefined) {
|
|
263
|
+
opts.eventId = input.eventId;
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
opts.max = 1;
|
|
267
|
+
}
|
|
268
|
+
const summary = await clockworks.processEvents(opts);
|
|
269
|
+
// The empty-queue branch is handled above for the next-pending mode.
|
|
270
|
+
// For the explicit-id mode, summary.processedEvents will be 1 — the
|
|
271
|
+
// pre-check already eliminated the missing/already-processed cases.
|
|
272
|
+
// Defensive fall-through: if somehow nothing was processed, treat
|
|
273
|
+
// it like an empty queue.
|
|
274
|
+
if (summary.processedEvents === 0) {
|
|
275
|
+
return {
|
|
276
|
+
lines: [EMPTY_TICK],
|
|
277
|
+
hadError: false,
|
|
278
|
+
empty: true,
|
|
279
|
+
notFound: false,
|
|
280
|
+
alreadyProcessed: false,
|
|
281
|
+
warnings,
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
// D16: a processed event with zero dispatch observations means
|
|
285
|
+
// there were no matching standing orders. Surface a single visibility
|
|
286
|
+
// line so operators don't see silence.
|
|
287
|
+
if (targetEvent && !observedEventIds.has(targetEvent.id)) {
|
|
288
|
+
lines.push(`${targetEvent.id} ${targetEvent.name} (no matching standing orders)`);
|
|
289
|
+
}
|
|
290
|
+
// D20: zero matching standing orders → exit 0.
|
|
291
|
+
return {
|
|
292
|
+
lines,
|
|
293
|
+
hadError: summary.errors > 0,
|
|
294
|
+
empty: false,
|
|
295
|
+
notFound: false,
|
|
296
|
+
alreadyProcessed: false,
|
|
297
|
+
warnings,
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Drain the queue. Loop `processEvents()` until it reports zero
|
|
302
|
+
* processed events for an iteration. No sleep, no daemon. Per-dispatch
|
|
303
|
+
* summary lines emit as they happen via the observer; the final
|
|
304
|
+
* `processed N events` line goes out at the end.
|
|
305
|
+
*/
|
|
306
|
+
export async function runRun() {
|
|
307
|
+
const g = requireGuild();
|
|
308
|
+
const clockworks = g.apparatus('clockworks');
|
|
309
|
+
const stacks = g.apparatus('stacks');
|
|
310
|
+
const events = stacks.book('clockworks', 'events');
|
|
311
|
+
// Daemon-coexistence warning — emitted independently of the drain
|
|
312
|
+
// outcome.
|
|
313
|
+
const warnings = [];
|
|
314
|
+
try {
|
|
315
|
+
const w = daemonCoexistenceWarning(g.home);
|
|
316
|
+
if (w)
|
|
317
|
+
warnings.push(w);
|
|
318
|
+
}
|
|
319
|
+
catch {
|
|
320
|
+
// ignore — diagnostic warning, not load-bearing
|
|
321
|
+
}
|
|
322
|
+
const lines = [];
|
|
323
|
+
let totalProcessed = 0;
|
|
324
|
+
let totalErrors = 0;
|
|
325
|
+
let firstIterationEmpty = false;
|
|
326
|
+
// Track which event ids produced at least one dispatch row this
|
|
327
|
+
// process so we can surface "(no matching standing orders)" for the
|
|
328
|
+
// ones that didn't.
|
|
329
|
+
const seenDispatchEventIds = new Set();
|
|
330
|
+
for (;;) {
|
|
331
|
+
// D16: capture the set of events the dispatcher will see this
|
|
332
|
+
// sweep so we can surface "(no matching standing orders)" lines
|
|
333
|
+
// for events that produced zero dispatch observations. `run` has
|
|
334
|
+
// no max cap, so every event in this snapshot will be flipped
|
|
335
|
+
// before the sweep returns.
|
|
336
|
+
const pendingBefore = await events.find({
|
|
337
|
+
where: [['processed', '=', false]],
|
|
338
|
+
orderBy: [['id', 'asc']],
|
|
339
|
+
});
|
|
340
|
+
const summary = await clockworks.processEvents({
|
|
341
|
+
onDispatch: (obs) => {
|
|
342
|
+
seenDispatchEventIds.add(obs.eventId);
|
|
343
|
+
lines.push(formatDispatchLine(obs));
|
|
344
|
+
},
|
|
345
|
+
});
|
|
346
|
+
if (summary.processedEvents === 0) {
|
|
347
|
+
if (totalProcessed === 0)
|
|
348
|
+
firstIterationEmpty = true;
|
|
349
|
+
break;
|
|
350
|
+
}
|
|
351
|
+
for (const ev of pendingBefore) {
|
|
352
|
+
if (!seenDispatchEventIds.has(ev.id)) {
|
|
353
|
+
lines.push(`${ev.id} ${ev.name} (no matching standing orders)`);
|
|
354
|
+
// Defensive: prevent re-emission if a later sweep would see
|
|
355
|
+
// the same id (it shouldn't — the row is now processed —
|
|
356
|
+
// but the guard keeps the line idempotent).
|
|
357
|
+
seenDispatchEventIds.add(ev.id);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
totalProcessed += summary.processedEvents;
|
|
361
|
+
totalErrors += summary.errors;
|
|
362
|
+
}
|
|
363
|
+
if (firstIterationEmpty) {
|
|
364
|
+
return {
|
|
365
|
+
lines: [EMPTY_RUN],
|
|
366
|
+
hadError: false,
|
|
367
|
+
totalProcessed: 0,
|
|
368
|
+
empty: true,
|
|
369
|
+
warnings,
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
lines.push(`processed ${totalProcessed} events`);
|
|
373
|
+
return {
|
|
374
|
+
lines,
|
|
375
|
+
hadError: totalErrors > 0,
|
|
376
|
+
totalProcessed,
|
|
377
|
+
empty: false,
|
|
378
|
+
warnings,
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Handle `nsg clock start`. Without `--foreground`, calls
|
|
383
|
+
* `clockStart(home)`, which spawns a detached child and blocks until
|
|
384
|
+
* the daemon is verified running. With `--foreground`, calls
|
|
385
|
+
* `runForegroundDaemonFromGuild` — the inline daemon body that the
|
|
386
|
+
* detached spawn re-execs into. The function returns only when the
|
|
387
|
+
* daemon shuts down (under SIGTERM or SIGINT).
|
|
388
|
+
*/
|
|
389
|
+
export async function runStart(input) {
|
|
390
|
+
const g = requireGuild();
|
|
391
|
+
if (input.foreground) {
|
|
392
|
+
// Inline foreground daemon body. `runForegroundDaemonFromGuild`
|
|
393
|
+
// installs SIGTERM/SIGINT handlers and returns once shutdown is
|
|
394
|
+
// signaled. Once it returns we exit cleanly.
|
|
395
|
+
//
|
|
396
|
+
// Pass the StartedGuild deposited by program.ts so the daemon's
|
|
397
|
+
// shutdown path runs `guildInstance.shutdown()` — and therefore
|
|
398
|
+
// every started apparatus's optional `stop()` — before
|
|
399
|
+
// process.exit(0).
|
|
400
|
+
const startedGuild = getStartedGuild();
|
|
401
|
+
const opts = {
|
|
402
|
+
onShutdown: () => process.exit(0),
|
|
403
|
+
};
|
|
404
|
+
if (input.interval !== undefined)
|
|
405
|
+
opts.intervalMs = input.interval;
|
|
406
|
+
if (startedGuild)
|
|
407
|
+
opts.startedGuild = startedGuild;
|
|
408
|
+
await runForegroundDaemonFromGuild(opts);
|
|
409
|
+
// Unreachable — onShutdown exits the process.
|
|
410
|
+
return { lines: [] };
|
|
411
|
+
}
|
|
412
|
+
const startOpts = {};
|
|
413
|
+
if (input.interval !== undefined)
|
|
414
|
+
startOpts.interval = input.interval;
|
|
415
|
+
const result = await clockStart(g.home, startOpts);
|
|
416
|
+
return {
|
|
417
|
+
lines: [
|
|
418
|
+
`Clockworks daemon started (pid: ${result.pid})`,
|
|
419
|
+
` Log file: ${result.logFile}`,
|
|
420
|
+
],
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Handle `nsg clock stop`. Thin wrapper around `clockStop`.
|
|
425
|
+
*
|
|
426
|
+
* Per spec: missing-pidfile and stale-pidfile cases exit zero with a
|
|
427
|
+
* message — they are not errors. The success-path message comes from
|
|
428
|
+
* the core API result so the three branches (`'signaled'`,
|
|
429
|
+
* `'no-pidfile'`, `'stale'`) stay aligned across CLI / programmatic
|
|
430
|
+
* consumers.
|
|
431
|
+
*/
|
|
432
|
+
export async function runStop() {
|
|
433
|
+
const g = requireGuild();
|
|
434
|
+
const result = await clockStop(g.home);
|
|
435
|
+
return { lines: [result.message] };
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Handle `nsg clock status`. Defaults to multi-line plain text;
|
|
439
|
+
* `--json` emits the structured shape verbatim. The output mirrors
|
|
440
|
+
* the `clock-status` MCP tool's payload so the surfaces stay aligned.
|
|
441
|
+
*/
|
|
442
|
+
export function runStatus(input) {
|
|
443
|
+
const g = requireGuild();
|
|
444
|
+
const status = clockStatus(g.home);
|
|
445
|
+
if (input.json) {
|
|
446
|
+
return { lines: [JSON.stringify(status, null, 2)], status };
|
|
447
|
+
}
|
|
448
|
+
if (!status.running) {
|
|
449
|
+
if (status.stalePidfile) {
|
|
450
|
+
return {
|
|
451
|
+
lines: [
|
|
452
|
+
'Clockworks daemon: not running.',
|
|
453
|
+
' (Stale pidfile detected and removed.)',
|
|
454
|
+
],
|
|
455
|
+
status,
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
return { lines: ['Clockworks daemon: not running.'], status };
|
|
459
|
+
}
|
|
460
|
+
const lines = [
|
|
461
|
+
'Clockworks daemon: running',
|
|
462
|
+
` PID: ${status.pid}`,
|
|
463
|
+
` Log file: ${status.logFile}`,
|
|
464
|
+
` Uptime: ${formatUptime(status.uptime ?? 0)}`,
|
|
465
|
+
];
|
|
466
|
+
return { lines, status };
|
|
467
|
+
}
|
|
468
|
+
/** Format a millisecond uptime as a short human-readable string. */
|
|
469
|
+
function formatUptime(ms) {
|
|
470
|
+
if (ms < 1000)
|
|
471
|
+
return `${ms}ms`;
|
|
472
|
+
const seconds = Math.floor(ms / 1000);
|
|
473
|
+
if (seconds < 60)
|
|
474
|
+
return `${seconds}s`;
|
|
475
|
+
const minutes = Math.floor(seconds / 60);
|
|
476
|
+
const remSeconds = seconds % 60;
|
|
477
|
+
if (minutes < 60)
|
|
478
|
+
return `${minutes}m${remSeconds}s`;
|
|
479
|
+
const hours = Math.floor(minutes / 60);
|
|
480
|
+
const remMinutes = minutes % 60;
|
|
481
|
+
return `${hours}h${remMinutes}m${remSeconds}s`;
|
|
482
|
+
}
|
|
483
|
+
// ── Commander Command ────────────────────────────────────────────────
|
|
484
|
+
/**
|
|
485
|
+
* Parse and validate the `--limit <N>` flag for `list`. Commander
|
|
486
|
+
* surfaces flag values as strings; we want a positive integer.
|
|
487
|
+
*/
|
|
488
|
+
function parseLimitOption(raw) {
|
|
489
|
+
const n = Number(raw);
|
|
490
|
+
if (!Number.isInteger(n) || n <= 0) {
|
|
491
|
+
throw new Error(`clock list: --limit must be a positive integer, got "${raw}".`);
|
|
492
|
+
}
|
|
493
|
+
return n;
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Parse and validate the `--interval <ms>` flag for `start`. Mirrors
|
|
497
|
+
* the fail-loud pattern of `parseLimitOption`.
|
|
498
|
+
*/
|
|
499
|
+
function parseIntervalOption(raw) {
|
|
500
|
+
const n = Number(raw);
|
|
501
|
+
if (!Number.isInteger(n) || n <= 0) {
|
|
502
|
+
throw new Error(`clock start: --interval must be a positive integer (ms), got "${raw}".`);
|
|
503
|
+
}
|
|
504
|
+
return n;
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Build the `nsg clock` Commander Command — the parent group plus the
|
|
508
|
+
* three subcommands. Each subcommand's action wrapper translates the
|
|
509
|
+
* structured handler output to printed lines and `process.exit(N)` per
|
|
510
|
+
* commission decision D8.
|
|
511
|
+
*/
|
|
512
|
+
export function buildClockCommand() {
|
|
513
|
+
const cmd = new Command('clock').description('Clockworks operator commands');
|
|
514
|
+
// ── list ──────────────────────────────────────────────────────────
|
|
515
|
+
const list = new Command('list')
|
|
516
|
+
.description('List events in the Clockworks events book.')
|
|
517
|
+
.option('--include-processed', 'Include processed events in addition to pending ones.')
|
|
518
|
+
.option('--limit <n>', 'Cap output at N entries. Without this flag, every matching event prints.', parseLimitOption)
|
|
519
|
+
.action(async (opts) => {
|
|
520
|
+
try {
|
|
521
|
+
const out = await runList({
|
|
522
|
+
includeProcessed: opts.includeProcessed,
|
|
523
|
+
limit: opts.limit,
|
|
524
|
+
});
|
|
525
|
+
for (const line of out.lines)
|
|
526
|
+
console.log(line);
|
|
527
|
+
}
|
|
528
|
+
catch (err) {
|
|
529
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
530
|
+
console.error(`Error: ${message}`);
|
|
531
|
+
process.exit(1);
|
|
532
|
+
}
|
|
533
|
+
});
|
|
534
|
+
// ── tick ──────────────────────────────────────────────────────────
|
|
535
|
+
const tick = new Command('tick')
|
|
536
|
+
.description('Process a single event (next pending, or the supplied id).')
|
|
537
|
+
.argument('[id]', 'Event id to process. Omit to take the next pending event.')
|
|
538
|
+
.action(async (id) => {
|
|
539
|
+
try {
|
|
540
|
+
const out = await runTick({ eventId: id });
|
|
541
|
+
// Daemon-coexistence warning(s) go to stderr first so the
|
|
542
|
+
// operator notices them ahead of the dispatch summary.
|
|
543
|
+
for (const w of out.warnings)
|
|
544
|
+
console.error(w);
|
|
545
|
+
// D8: print first, then explicitly exit non-zero — keeps the
|
|
546
|
+
// structured summary intact ahead of any "Error: …" prefix.
|
|
547
|
+
for (const line of out.lines) {
|
|
548
|
+
if (line.startsWith('Error:') || line.startsWith('Warning:')) {
|
|
549
|
+
console.error(line);
|
|
550
|
+
}
|
|
551
|
+
else {
|
|
552
|
+
console.log(line);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
if (out.notFound || out.alreadyProcessed) {
|
|
556
|
+
process.exit(1);
|
|
557
|
+
}
|
|
558
|
+
if (out.hadError) {
|
|
559
|
+
process.exit(1);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
catch (err) {
|
|
563
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
564
|
+
console.error(`Error: ${message}`);
|
|
565
|
+
process.exit(1);
|
|
566
|
+
}
|
|
567
|
+
});
|
|
568
|
+
// ── run ───────────────────────────────────────────────────────────
|
|
569
|
+
const run = new Command('run')
|
|
570
|
+
.description('Drain the queue. Loops processEvents() until zero events are processed.')
|
|
571
|
+
.action(async () => {
|
|
572
|
+
try {
|
|
573
|
+
const out = await runRun();
|
|
574
|
+
for (const w of out.warnings)
|
|
575
|
+
console.error(w);
|
|
576
|
+
for (const line of out.lines)
|
|
577
|
+
console.log(line);
|
|
578
|
+
if (out.hadError) {
|
|
579
|
+
process.exit(1);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
catch (err) {
|
|
583
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
584
|
+
console.error(`Error: ${message}`);
|
|
585
|
+
process.exit(1);
|
|
586
|
+
}
|
|
587
|
+
});
|
|
588
|
+
// ── start ─────────────────────────────────────────────────────────
|
|
589
|
+
const start = new Command('start')
|
|
590
|
+
.description('Start the Clockworks daemon (detached background process).')
|
|
591
|
+
.option('--interval <ms>', 'Polling interval in milliseconds (default 2000).', parseIntervalOption)
|
|
592
|
+
.option('-f, --foreground', 'Run the daemon body inline in this process (used by the detached re-exec).')
|
|
593
|
+
.action(async (opts) => {
|
|
594
|
+
try {
|
|
595
|
+
const input = {};
|
|
596
|
+
if (opts.interval !== undefined)
|
|
597
|
+
input.interval = opts.interval;
|
|
598
|
+
if (opts.foreground)
|
|
599
|
+
input.foreground = true;
|
|
600
|
+
const out = await runStart(input);
|
|
601
|
+
for (const line of out.lines)
|
|
602
|
+
console.log(line);
|
|
603
|
+
}
|
|
604
|
+
catch (err) {
|
|
605
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
606
|
+
console.error(`Error: ${message}`);
|
|
607
|
+
process.exit(1);
|
|
608
|
+
}
|
|
609
|
+
});
|
|
610
|
+
// ── stop ──────────────────────────────────────────────────────────
|
|
611
|
+
const stop = new Command('stop')
|
|
612
|
+
.description('Stop the Clockworks daemon (graceful SIGTERM with SIGKILL escalation).')
|
|
613
|
+
.action(async () => {
|
|
614
|
+
try {
|
|
615
|
+
const out = await runStop();
|
|
616
|
+
for (const line of out.lines)
|
|
617
|
+
console.log(line);
|
|
618
|
+
}
|
|
619
|
+
catch (err) {
|
|
620
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
621
|
+
console.error(`Error: ${message}`);
|
|
622
|
+
process.exit(1);
|
|
623
|
+
}
|
|
624
|
+
});
|
|
625
|
+
// ── status ────────────────────────────────────────────────────────
|
|
626
|
+
const status = new Command('status')
|
|
627
|
+
.description('Show whether the Clockworks daemon is running.')
|
|
628
|
+
.option('--json', 'Output the structured status as JSON.')
|
|
629
|
+
.action((opts) => {
|
|
630
|
+
try {
|
|
631
|
+
const input = {};
|
|
632
|
+
if (opts.json)
|
|
633
|
+
input.json = true;
|
|
634
|
+
const out = runStatus(input);
|
|
635
|
+
for (const line of out.lines)
|
|
636
|
+
console.log(line);
|
|
637
|
+
}
|
|
638
|
+
catch (err) {
|
|
639
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
640
|
+
console.error(`Error: ${message}`);
|
|
641
|
+
process.exit(1);
|
|
642
|
+
}
|
|
643
|
+
});
|
|
644
|
+
cmd.addCommand(list);
|
|
645
|
+
cmd.addCommand(tick);
|
|
646
|
+
cmd.addCommand(run);
|
|
647
|
+
cmd.addCommand(start);
|
|
648
|
+
cmd.addCommand(stop);
|
|
649
|
+
cmd.addCommand(status);
|
|
650
|
+
return cmd;
|
|
651
|
+
}
|
|
652
|
+
//# sourceMappingURL=clock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clock.js","sourceRoot":"","sources":["../../src/commands/clock.ts"],"names":[],"mappings":"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"}
|