@senpi/runtime 3.0.123 → 3.0.124
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/actions/action-events.d.ts +7 -21
- package/dist/actions/action-events.d.ts.map +1 -1
- package/dist/actions/action-events.js +26 -54
- package/dist/actions/action-events.js.map +1 -1
- package/dist/actions/action-runtime-module.d.ts.map +1 -1
- package/dist/actions/action-runtime-module.js +7 -38
- package/dist/actions/action-runtime-module.js.map +1 -1
- package/dist/actions/close-position/close-position.action.d.ts.map +1 -1
- package/dist/actions/close-position/close-position.action.js +15 -122
- package/dist/actions/close-position/close-position.action.js.map +1 -1
- package/dist/actions/decision-engine.d.ts.map +1 -1
- package/dist/actions/decision-engine.js +2 -15
- package/dist/actions/decision-engine.js.map +1 -1
- package/dist/actions/event-derivation.d.ts +2 -71
- package/dist/actions/event-derivation.d.ts.map +1 -1
- package/dist/actions/event-derivation.js +8 -251
- package/dist/actions/event-derivation.js.map +1 -1
- package/dist/actions/open-position/open-position.action.d.ts +2 -17
- package/dist/actions/open-position/open-position.action.d.ts.map +1 -1
- package/dist/actions/open-position/open-position.action.js +47 -162
- package/dist/actions/open-position/open-position.action.js.map +1 -1
- package/dist/actions/position-tracker/position-tracker.action.d.ts +1 -2
- package/dist/actions/position-tracker/position-tracker.action.d.ts.map +1 -1
- package/dist/actions/position-tracker/position-tracker.action.js +17 -62
- package/dist/actions/position-tracker/position-tracker.action.js.map +1 -1
- package/dist/actions/store/types.d.ts +2 -9
- package/dist/actions/store/types.d.ts.map +1 -1
- package/dist/actions/store/types.js.map +1 -1
- package/dist/actions/types.d.ts +0 -13
- package/dist/actions/types.d.ts.map +1 -1
- package/dist/actions/types.js +0 -13
- package/dist/actions/types.js.map +1 -1
- package/dist/cli/guide-commands.d.ts.map +1 -1
- package/dist/cli/guide-commands.js +0 -3
- package/dist/cli/guide-commands.js.map +1 -1
- package/dist/dsl/engine-client/event-mapping.d.ts.map +1 -1
- package/dist/dsl/engine-client/event-mapping.js +0 -14
- package/dist/dsl/engine-client/event-mapping.js.map +1 -1
- package/dist/dsl/events/build-closed-event.d.ts +1 -16
- package/dist/dsl/events/build-closed-event.d.ts.map +1 -1
- package/dist/dsl/events/build-closed-event.js +0 -6
- package/dist/dsl/events/build-closed-event.js.map +1 -1
- package/dist/dsl/events/handlers.d.ts +0 -7
- package/dist/dsl/events/handlers.d.ts.map +1 -1
- package/dist/dsl/events/handlers.js +7 -37
- package/dist/dsl/events/handlers.js.map +1 -1
- package/dist/dsl/monitor/create-monitor.d.ts +2 -6
- package/dist/dsl/monitor/create-monitor.d.ts.map +1 -1
- package/dist/dsl/monitor/create-monitor.js +9 -15
- package/dist/dsl/monitor/create-monitor.js.map +1 -1
- package/dist/dsl/monitor/dsl-failure-events.d.ts +0 -2
- package/dist/dsl/monitor/dsl-failure-events.d.ts.map +1 -1
- package/dist/dsl/monitor/dsl-failure-events.js +1 -2
- package/dist/dsl/monitor/dsl-failure-events.js.map +1 -1
- package/dist/dsl/monitor/process-one-position.d.ts +0 -1
- package/dist/dsl/monitor/process-one-position.d.ts.map +1 -1
- package/dist/dsl/monitor/process-one-position.js +25 -59
- package/dist/dsl/monitor/process-one-position.js.map +1 -1
- package/dist/dsl/plugin/index.d.ts +2 -8
- package/dist/dsl/plugin/index.d.ts.map +1 -1
- package/dist/dsl/plugin/index.js +6 -8
- package/dist/dsl/plugin/index.js.map +1 -1
- package/dist/health/types.d.ts +0 -13
- package/dist/health/types.d.ts.map +1 -1
- package/dist/health/types.js +0 -12
- package/dist/health/types.js.map +1 -1
- package/dist/index.d.ts +4 -27
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +42 -254
- package/dist/index.js.map +1 -1
- package/dist/runtime/action-registry.d.ts.map +1 -1
- package/dist/runtime/action-registry.js +3 -4
- package/dist/runtime/action-registry.js.map +1 -1
- package/dist/runtime/domain-events.d.ts.map +1 -1
- package/dist/runtime/domain-events.js +0 -7
- package/dist/runtime/domain-events.js.map +1 -1
- package/dist/runtime/lifecycle-events.d.ts +1 -9
- package/dist/runtime/lifecycle-events.d.ts.map +1 -1
- package/dist/runtime/lifecycle-events.js +2 -11
- package/dist/runtime/lifecycle-events.js.map +1 -1
- package/dist/runtime/reconcile-run.d.ts +3 -13
- package/dist/runtime/reconcile-run.d.ts.map +1 -1
- package/dist/runtime/reconcile-run.js +3 -4
- package/dist/runtime/reconcile-run.js.map +1 -1
- package/dist/runtime/reconcile-state.d.ts +0 -8
- package/dist/runtime/reconcile-state.d.ts.map +1 -1
- package/dist/runtime/reconcile-state.js +1 -4
- package/dist/runtime/reconcile-state.js.map +1 -1
- package/dist/runtime/run.d.ts +0 -1
- package/dist/runtime/run.d.ts.map +1 -1
- package/dist/runtime/run.js.map +1 -1
- package/dist/runtime/runtime-schema.js +3 -3
- package/dist/runtime/runtime-schema.js.map +1 -1
- package/dist/runtime/runtime.d.ts +0 -1
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +3 -27
- package/dist/runtime/runtime.js.map +1 -1
- package/dist/runtime/supervisor/long-running-supervisor.d.ts +0 -13
- package/dist/runtime/supervisor/long-running-supervisor.d.ts.map +1 -1
- package/dist/runtime/supervisor/long-running-supervisor.js +0 -1
- package/dist/runtime/supervisor/long-running-supervisor.js.map +1 -1
- package/dist/runtime/validate-dsl-position-tracking.d.ts.map +1 -1
- package/dist/runtime/validate-dsl-position-tracking.js +1 -2
- package/dist/runtime/validate-dsl-position-tracking.js.map +1 -1
- package/dist/runtime-api/handlers/ingest-signals.d.ts.map +1 -1
- package/dist/runtime-api/handlers/ingest-signals.js +0 -1
- package/dist/runtime-api/handlers/ingest-signals.js.map +1 -1
- package/dist/runtime-api/handlers/types.d.ts +0 -5
- package/dist/runtime-api/handlers/types.d.ts.map +1 -1
- package/dist/runtime-api/intake/intake-events.d.ts +1 -1
- package/dist/runtime-api/intake/intake-events.d.ts.map +1 -1
- package/dist/runtime-api/intake/intake-events.js +3 -9
- package/dist/runtime-api/intake/intake-events.js.map +1 -1
- package/dist/runtime-api/intake/intake-mount.d.ts.map +1 -1
- package/dist/runtime-api/intake/intake-mount.js +19 -4
- package/dist/runtime-api/intake/intake-mount.js.map +1 -1
- package/dist/runtime-api/intake/process-error-post.d.ts +1 -6
- package/dist/runtime-api/intake/process-error-post.d.ts.map +1 -1
- package/dist/runtime-api/intake/process-error-post.js +1 -5
- package/dist/runtime-api/intake/process-error-post.js.map +1 -1
- package/dist/runtime-api/intake/process-signal-post.d.ts +1 -7
- package/dist/runtime-api/intake/process-signal-post.d.ts.map +1 -1
- package/dist/runtime-api/intake/process-signal-post.js +0 -5
- package/dist/runtime-api/intake/process-signal-post.js.map +1 -1
- package/dist/runtime-api/intake/scaffold-error-router.js.map +1 -1
- package/dist/runtime-api/intake/scanner-launcher.d.ts.map +1 -1
- package/dist/runtime-api/intake/scanner-launcher.js +0 -15
- package/dist/runtime-api/intake/scanner-launcher.js.map +1 -1
- package/dist/runtime-api/intake/types.d.ts +0 -55
- package/dist/runtime-api/intake/types.d.ts.map +1 -1
- package/dist/runtime-api/routes/signals.d.ts +0 -2
- package/dist/runtime-api/routes/signals.d.ts.map +1 -1
- package/dist/runtime-api/routes/signals.js +1 -5
- package/dist/runtime-api/routes/signals.js.map +1 -1
- package/dist/runtime-api/routes/signals.schema.d.ts +0 -43
- package/dist/runtime-api/routes/signals.schema.d.ts.map +1 -1
- package/dist/runtime-api/routes/signals.schema.js +0 -43
- package/dist/runtime-api/routes/signals.schema.js.map +1 -1
- package/dist/runtime-api/server.d.ts +1 -7
- package/dist/runtime-api/server.d.ts.map +1 -1
- package/dist/runtime-api/server.js +0 -1
- package/dist/runtime-api/server.js.map +1 -1
- package/dist/scanners/engine/engine.d.ts +1 -22
- package/dist/scanners/engine/engine.d.ts.map +1 -1
- package/dist/scanners/engine/engine.js +11 -78
- package/dist/scanners/engine/engine.js.map +1 -1
- package/dist/scanners/engine/lifecycle.d.ts +1 -7
- package/dist/scanners/engine/lifecycle.d.ts.map +1 -1
- package/dist/scanners/events.d.ts +0 -4
- package/dist/scanners/events.d.ts.map +1 -1
- package/dist/scanners/events.js +0 -2
- package/dist/scanners/events.js.map +1 -1
- package/dist/scanners/external/scaffold/delivery.py +25 -194
- package/dist/scanners/external/scaffold/scaffold.py +31 -172
- package/dist/scanners/external/scaffold/senpi_mcp.py +8 -150
- package/dist/scanners/external-scanner-receiver.d.ts +0 -17
- package/dist/scanners/external-scanner-receiver.d.ts.map +1 -1
- package/dist/scanners/external-scanner-receiver.js +0 -8
- package/dist/scanners/external-scanner-receiver.js.map +1 -1
- package/dist/scanners/runtime-module.d.ts +0 -1
- package/dist/scanners/runtime-module.d.ts.map +1 -1
- package/dist/scanners/runtime-module.js +9 -66
- package/dist/scanners/runtime-module.js.map +1 -1
- package/dist/telemetry/attributes.d.ts +0 -20
- package/dist/telemetry/attributes.d.ts.map +1 -1
- package/dist/telemetry/attributes.js +0 -24
- package/dist/telemetry/attributes.js.map +1 -1
- package/dist/telemetry/event-builders.d.ts +6 -81
- package/dist/telemetry/event-builders.d.ts.map +1 -1
- package/dist/telemetry/event-builders.js +17 -141
- package/dist/telemetry/event-builders.js.map +1 -1
- package/dist/telemetry/event-store.d.ts +0 -6
- package/dist/telemetry/event-store.d.ts.map +1 -1
- package/dist/telemetry/event-store.js +8 -12
- package/dist/telemetry/event-store.js.map +1 -1
- package/dist/telemetry/metrics.d.ts +2 -14
- package/dist/telemetry/metrics.d.ts.map +1 -1
- package/dist/telemetry/metrics.js +4 -19
- package/dist/telemetry/metrics.js.map +1 -1
- package/dist/telemetry/spans/redact-pii.d.ts.map +1 -1
- package/dist/telemetry/spans/redact-pii.js +2 -18
- package/dist/telemetry/spans/redact-pii.js.map +1 -1
- package/dist/telemetry/tracing.d.ts +0 -9
- package/dist/telemetry/tracing.d.ts.map +1 -1
- package/dist/telemetry/tracing.js +0 -36
- package/dist/telemetry/tracing.js.map +1 -1
- package/dist/types/dsl/index.d.ts +0 -11
- package/dist/types/dsl/index.d.ts.map +1 -1
- package/dist/types/scanner.d.ts +0 -15
- package/dist/types/scanner.d.ts.map +1 -1
- package/dist/utils/event-catalog.d.ts +0 -166
- package/dist/utils/event-catalog.d.ts.map +1 -1
- package/dist/utils/event-catalog.js +0 -18
- package/dist/utils/event-catalog.js.map +1 -1
- package/dist/utils/logger.d.ts +1 -4
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js.map +1 -1
- package/dist/validate/recipe-checks.d.ts.map +1 -1
- package/dist/validate/recipe-checks.js +2 -2
- package/dist/validate/recipe-checks.js.map +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/dist/actions/skipped-signal-results.d.ts +0 -25
- package/dist/actions/skipped-signal-results.d.ts.map +0 -1
- package/dist/actions/skipped-signal-results.js +0 -71
- package/dist/actions/skipped-signal-results.js.map +0 -1
- package/dist/runtime-api/intake/ingest-request.d.ts +0 -17
- package/dist/runtime-api/intake/ingest-request.d.ts.map +0 -1
- package/dist/runtime-api/intake/ingest-request.js +0 -34
- package/dist/runtime-api/intake/ingest-request.js.map +0 -1
- package/dist/runtime-api/intake/scaffold-tick-router.d.ts +0 -39
- package/dist/runtime-api/intake/scaffold-tick-router.d.ts.map +0 -1
- package/dist/runtime-api/intake/scaffold-tick-router.js +0 -122
- package/dist/runtime-api/intake/scaffold-tick-router.js.map +0 -1
- package/dist/scanners/external/scaffold/tick_facts.py +0 -130
- package/dist/scanners/external/scaffold/ulid.py +0 -58
- package/dist/telemetry/live-telemetry.d.ts +0 -238
- package/dist/telemetry/live-telemetry.d.ts.map +0 -1
- package/dist/telemetry/live-telemetry.js +0 -853
- package/dist/telemetry/live-telemetry.js.map +0 -1
- package/dist/telemetry/scanner-stats.d.ts +0 -143
- package/dist/telemetry/scanner-stats.d.ts.map +0 -1
- package/dist/telemetry/scanner-stats.js +0 -426
- package/dist/telemetry/scanner-stats.js.map +0 -1
- package/dist/telemetry/scanner-tick-feed.d.ts +0 -87
- package/dist/telemetry/scanner-tick-feed.d.ts.map +0 -1
- package/dist/telemetry/scanner-tick-feed.js +0 -48
- package/dist/telemetry/scanner-tick-feed.js.map +0 -1
- package/dist/telemetry/strategy-topology.d.ts +0 -99
- package/dist/telemetry/strategy-topology.d.ts.map +0 -1
- package/dist/telemetry/strategy-topology.js +0 -93
- package/dist/telemetry/strategy-topology.js.map +0 -1
- package/dist/telemetry/telemetry-publisher.d.ts +0 -63
- package/dist/telemetry/telemetry-publisher.d.ts.map +0 -1
- package/dist/telemetry/telemetry-publisher.js +0 -229
- package/dist/telemetry/telemetry-publisher.js.map +0 -1
- package/dist/telemetry/tick-frame.d.ts +0 -212
- package/dist/telemetry/tick-frame.d.ts.map +0 -1
- package/dist/telemetry/tick-frame.js +0 -421
- package/dist/telemetry/tick-frame.js.map +0 -1
- package/dist/telemetry/timeline-buffer.d.ts +0 -95
- package/dist/telemetry/timeline-buffer.d.ts.map +0 -1
- package/dist/telemetry/timeline-buffer.js +0 -237
- package/dist/telemetry/timeline-buffer.js.map +0 -1
- package/dist/utils/telemetry-required-log.d.ts +0 -60
- package/dist/utils/telemetry-required-log.d.ts.map +0 -1
- package/dist/utils/telemetry-required-log.js +0 -105
- package/dist/utils/telemetry-required-log.js.map +0 -1
- package/dist/utils/ulid.d.ts +0 -9
- package/dist/utils/ulid.d.ts.map +0 -1
- package/dist/utils/ulid.js +0 -43
- package/dist/utils/ulid.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -64,11 +64,7 @@ import { createIntakeContext } from "./runtime-api/intake/intake-context.js";
|
|
|
64
64
|
import { wireRuntime, intakeUrlFor, selectScanners } from "./runtime-api/intake/intake-mount.js";
|
|
65
65
|
import { ingestDispatchMutex, ingestDispatchKey } from "./runtime-api/intake/ingest-mutex.js";
|
|
66
66
|
import { buildScaffoldErrorRouter } from "./runtime-api/intake/scaffold-error-router.js";
|
|
67
|
-
import { buildScaffoldTickRouter } from "./runtime-api/intake/scaffold-tick-router.js";
|
|
68
|
-
import { toIngestRequest } from "./runtime-api/intake/ingest-request.js";
|
|
69
67
|
import { loadRuntimeConfig } from "./runtime/load-runtime-config.js";
|
|
70
|
-
import { createLiveTelemetry } from "./telemetry/live-telemetry.js";
|
|
71
|
-
import { resolveTickTelemetry } from "./telemetry/tick-frame.js";
|
|
72
68
|
/** Initialize all core features (DSL, risk, health) on the given event bus. */
|
|
73
69
|
export function initCore(bus) {
|
|
74
70
|
initDsl(bus);
|
|
@@ -227,16 +223,6 @@ const senpiRuntimePlugin = {
|
|
|
227
223
|
? "env SENPI_LOG_LEVEL"
|
|
228
224
|
: "default";
|
|
229
225
|
pluginLogger.info(`[senpi-runtime] log level: ${startupLogLevel} (source: ${logLevelSourceLabel}). Set plugin config "logLevel" or env SENPI_LOG_LEVEL to debug|info|warn|error to override.`);
|
|
230
|
-
// Same shape as the log-level line above, and for the same reason: a box publishing less than
|
|
231
|
-
// an operator expects must say so at boot rather than be diagnosed from an empty screen. No env
|
|
232
|
-
// var is named because there is none — see `tickTelemetry` on SenpiRuntimePluginConfig.
|
|
233
|
-
const tickTelemetry = resolveTickTelemetry(config.tickTelemetry);
|
|
234
|
-
if (tickTelemetry.invalid !== undefined) {
|
|
235
|
-
pluginLogger.warn(`[senpi-runtime] Ignoring invalid plugin config ${tickTelemetry.invalid} (expected off|summary|verbose); keeping mcp=${tickTelemetry.settings.mcp} state=${tickTelemetry.settings.state}.`);
|
|
236
|
-
}
|
|
237
|
-
pluginLogger.info(tickTelemetry.settings.enabled
|
|
238
|
-
? `[senpi-runtime] tick telemetry: mcp=${tickTelemetry.settings.mcp} state=${tickTelemetry.settings.state} (source: ${config.tickTelemetry === undefined ? "default" : "plugin config tickTelemetry"}). Set plugin config "tickTelemetry" to off|summary|verbose, or {mcp,state}, to override.`
|
|
239
|
-
: `[senpi-runtime] tick telemetry: off (source: plugin config tickTelemetry). No per-tick frame is published.`);
|
|
240
226
|
const senpiCliStore = readSenpiCliStore();
|
|
241
227
|
const baseStateDir = resolveSenpiBaseStateDir({
|
|
242
228
|
store: senpiCliStore,
|
|
@@ -369,7 +355,6 @@ const senpiRuntimePlugin = {
|
|
|
369
355
|
}
|
|
370
356
|
let routeAcceptedSignalToRuntime;
|
|
371
357
|
let routeScaffoldErrorToRuntime;
|
|
372
|
-
let routeScaffoldTickToTelemetry;
|
|
373
358
|
const launchers = new Map();
|
|
374
359
|
// Runtimes that are UP but whose external scanners never wired (mount/launch/install
|
|
375
360
|
// failure), keyed runtimeId → failed phase. Populated at the four unwired sites,
|
|
@@ -397,149 +382,10 @@ const senpiRuntimePlugin = {
|
|
|
397
382
|
* engines, one margin account: the exact state `[E_WALLET_HAS_RUNTIME]` exists to prevent.
|
|
398
383
|
*/
|
|
399
384
|
const installsInFlight = new Map();
|
|
400
|
-
// ── Live telemetry ────────────────────────────────────────────────
|
|
401
|
-
// Every runtime this box knows about, running or not, keyed runtimeId. The topology payload has
|
|
402
|
-
// to name a stopped strategy too, so this is populated from the registry rather than from
|
|
403
|
-
// `runtimeHandles` (which holds only the live ones) and is the source of the two facts the
|
|
404
|
-
// registry entry does not carry: the strategy's display name and its declared scanners. Both come
|
|
405
|
-
// from the parsed YAML — `name` is the same `config.name` that `RuntimeHealthStatus.runtimeName`
|
|
406
|
-
// is built from, so a runtime whose config never parsed falls back to its id rather than to a
|
|
407
|
-
// guess, and its scanner list stays empty rather than inventing rows.
|
|
408
|
-
const telemetryStrategies = new Map();
|
|
409
|
-
const noteTelemetryRuntime = (runtimeId, address) => {
|
|
410
|
-
const existing = telemetryStrategies.get(runtimeId);
|
|
411
|
-
telemetryStrategies.set(runtimeId, {
|
|
412
|
-
address,
|
|
413
|
-
name: existing?.name ?? runtimeId,
|
|
414
|
-
scanners: existing?.scanners ?? [],
|
|
415
|
-
});
|
|
416
|
-
};
|
|
417
|
-
const noteTelemetryRuntimeConfig = (runtimeId, config) => {
|
|
418
|
-
telemetryStrategies.set(runtimeId, {
|
|
419
|
-
address: config.strategy?.wallet ?? telemetryStrategies.get(runtimeId)?.address ?? "",
|
|
420
|
-
name: config.name,
|
|
421
|
-
scanners: config.scanners ?? [],
|
|
422
|
-
});
|
|
423
|
-
};
|
|
424
385
|
// Dedicated logger for the runtime-api subtree — required because the
|
|
425
386
|
// PluginLogger surface (info/warn/error) lacks `debug`, while the
|
|
426
387
|
// Logger contract used by `runtime-api/` includes it.
|
|
427
388
|
const apiLogger = createLogger("[senpi-core][api]");
|
|
428
|
-
/**
|
|
429
|
-
* One gather per publish tick. Health and system state are read together because the two payloads
|
|
430
|
-
* need both: the topology reads health and `runtimeName`, the stats read the per-scanner rows,
|
|
431
|
-
* and `restartCount` / `degradedReason` live only on the health rows while every other scanner
|
|
432
|
-
* field lives only on the system-state rows — so they are joined here on `(runtimeId, scannerId)`.
|
|
433
|
-
*/
|
|
434
|
-
const collectTelemetryFacts = async () => {
|
|
435
|
-
const [statuses, states] = await Promise.all([
|
|
436
|
-
collectRuntimeHealthStatuses(runtimeHandles, api.logger),
|
|
437
|
-
collectRuntimeSystemStates(runtimeHandles, api.logger, baseStateDir),
|
|
438
|
-
]);
|
|
439
|
-
const healthByRuntime = new Map();
|
|
440
|
-
for (const status of statuses) {
|
|
441
|
-
if (status.runtimeId !== undefined)
|
|
442
|
-
healthByRuntime.set(status.runtimeId, status);
|
|
443
|
-
}
|
|
444
|
-
const scannerState = [];
|
|
445
|
-
// Registration facts per (runtimeId, scannerId), so the topology can report a scanner's live
|
|
446
|
-
// schedule rather than only what its YAML declared.
|
|
447
|
-
const registrations = new Map();
|
|
448
|
-
for (const state of states) {
|
|
449
|
-
const runtimeId = state.runtimeId;
|
|
450
|
-
const healthRows = runtimeId === undefined
|
|
451
|
-
? []
|
|
452
|
-
: healthByRuntime.get(runtimeId)?.components.scanners.scanners ?? [];
|
|
453
|
-
for (const row of state.components.scanners.state.scanners) {
|
|
454
|
-
const supervision = healthRows.find((r) => r.scannerId === row.scannerId);
|
|
455
|
-
const snapshot = {
|
|
456
|
-
address: row.address,
|
|
457
|
-
scannerId: row.scannerId,
|
|
458
|
-
health: row.health,
|
|
459
|
-
degradedReason: supervision?.degradedReason ?? null,
|
|
460
|
-
enabled: row.enabled,
|
|
461
|
-
inFlightSince: row.inFlightSince,
|
|
462
|
-
lastRunStartedAt: row.lastRunStartedAt,
|
|
463
|
-
lastRunFinishedAt: row.lastRunFinishedAt,
|
|
464
|
-
lastRunStatus: row.lastRunStatus,
|
|
465
|
-
lastRunReason: row.lastRunReason,
|
|
466
|
-
nextRunAt: row.nextRunAt,
|
|
467
|
-
lastAliveAt: row.lastAliveAt,
|
|
468
|
-
// No supervision row means the restart count is unknown, not zero. A zero here would
|
|
469
|
-
// read as "this scanner has never restarted" on a scanner nobody is supervising.
|
|
470
|
-
restartCount: supervision?.restartCount ?? null,
|
|
471
|
-
};
|
|
472
|
-
scannerState.push(snapshot);
|
|
473
|
-
if (runtimeId !== undefined) {
|
|
474
|
-
registrations.set(`${runtimeId}::${row.scannerId}`, {
|
|
475
|
-
...snapshot,
|
|
476
|
-
scheduleMode: row.scheduleMode,
|
|
477
|
-
configVersion: row.configVersion,
|
|
478
|
-
intervalSeconds: row.intervalSeconds,
|
|
479
|
-
});
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
const strategies = [];
|
|
484
|
-
for (const [runtimeId, entry] of telemetryStrategies) {
|
|
485
|
-
const health = healthByRuntime.get(runtimeId);
|
|
486
|
-
const scanners = entry.scanners.map((declared) => {
|
|
487
|
-
const live = registrations.get(`${runtimeId}::${declared.name}`);
|
|
488
|
-
return live === undefined
|
|
489
|
-
? { entry: declared }
|
|
490
|
-
: {
|
|
491
|
-
entry: declared,
|
|
492
|
-
registration: {
|
|
493
|
-
enabled: live.enabled,
|
|
494
|
-
scheduleMode: live.scheduleMode,
|
|
495
|
-
// The engine's own cadence, which is what the scanner actually polls on — a
|
|
496
|
-
// recipe may omit it and take the scanner definition's default. An external
|
|
497
|
-
// scanner registers zero because it is POSTed to rather than polled, and only
|
|
498
|
-
// the recipe knows the cadence its scaffold was told to tick at.
|
|
499
|
-
intervalSeconds: live.intervalSeconds > 0 ? live.intervalSeconds : declared.interval_seconds ?? null,
|
|
500
|
-
configVersion: live.configVersion,
|
|
501
|
-
},
|
|
502
|
-
};
|
|
503
|
-
});
|
|
504
|
-
strategies.push({
|
|
505
|
-
runtimeId,
|
|
506
|
-
address: entry.address,
|
|
507
|
-
// `runtimeName` is built from the same `config.name`; the indexed value is used because it
|
|
508
|
-
// is available for a stopped runtime too, where there is no health status to read.
|
|
509
|
-
name: health?.runtimeName ?? entry.name,
|
|
510
|
-
scanners,
|
|
511
|
-
});
|
|
512
|
-
}
|
|
513
|
-
return {
|
|
514
|
-
strategies,
|
|
515
|
-
runningRuntimeIds: runtimeHandles,
|
|
516
|
-
unwiredRuntimeIds: unwiredRuntimes,
|
|
517
|
-
readHealth: (runtimeId) => healthByRuntime.get(runtimeId),
|
|
518
|
-
scannerState,
|
|
519
|
-
};
|
|
520
|
-
};
|
|
521
|
-
const liveTelemetry = createLiveTelemetry({
|
|
522
|
-
collectFacts: collectTelemetryFacts,
|
|
523
|
-
tickTelemetry: config.tickTelemetry,
|
|
524
|
-
});
|
|
525
|
-
/**
|
|
526
|
-
* Wrapped gateway methods capture the broadcast handle on the FIRST request to ANY of them —
|
|
527
|
-
* not only on subscribe. `ctx.context` is the only route to the websocket push layer and it
|
|
528
|
-
* exists only inside a handler, so capturing it in the subscribe method alone would mean a box
|
|
529
|
-
* whose client never subscribes can never publish anything, silently.
|
|
530
|
-
*
|
|
531
|
-
* The wrapper covers only what is registered through it. `senpi.deploy.start`,
|
|
532
|
-
* `senpi.deploy.status` and `senpi.update` are registered straight onto the plugin api by their
|
|
533
|
-
* own registrars and never arm the handle. That is not a gap in practice: one wrapped call arms
|
|
534
|
-
* it for the life of the process, and the websocket client admits `senpi.telemetry.subscribe`,
|
|
535
|
-
* which is wrapped.
|
|
536
|
-
*/
|
|
537
|
-
const registerGatewayMethod = (name, handler, opts) => {
|
|
538
|
-
api.registerGatewayMethod(name, (ctx) => {
|
|
539
|
-
liveTelemetry.captureBroadcast(ctx, name);
|
|
540
|
-
return handler(ctx);
|
|
541
|
-
}, opts);
|
|
542
|
-
};
|
|
543
389
|
// A gateway seam failed to wire/launch a runtime's external scanner stack: the runtime is up but
|
|
544
390
|
// runs blind on internal scanners only. Two records, by design: a first-class `runtime.scanners_unwired`
|
|
545
391
|
// event (the queryable/alertable fact, by phase) and the migrated exception-form `logger.error`
|
|
@@ -713,14 +559,26 @@ const senpiRuntimePlugin = {
|
|
|
713
559
|
// /signals will not be mounted and no signals will be routed.
|
|
714
560
|
if (sharedIntakeContext) {
|
|
715
561
|
const ctx = sharedIntakeContext;
|
|
716
|
-
routeAcceptedSignalToRuntime = (signal,
|
|
562
|
+
routeAcceptedSignalToRuntime = (signal, _correlationId, scannerId) => {
|
|
717
563
|
const resolved = ctx.registry.resolve(scannerId);
|
|
718
564
|
if (!resolved)
|
|
719
565
|
return;
|
|
720
566
|
const h = runtimeHandles.get(resolved.runtimeId);
|
|
721
567
|
if (!h)
|
|
722
568
|
return;
|
|
723
|
-
const request =
|
|
569
|
+
const request = {
|
|
570
|
+
scanner: resolved.scannerName,
|
|
571
|
+
signal_id: signal.signal_id, // greppable handle across intake→ingest (obs only)
|
|
572
|
+
asset: signal.asset,
|
|
573
|
+
direction: signal.direction,
|
|
574
|
+
...(signal.signal_type !== undefined && { signal_type: signal.signal_type }),
|
|
575
|
+
data: signal.data,
|
|
576
|
+
// Per-signal sizing rides at the top level; the open-position action
|
|
577
|
+
// reads request.marginPct / request.leverage directly. Without this a
|
|
578
|
+
// supervised signal's sizing is lost ("no margin source resolved").
|
|
579
|
+
...(signal.marginPct !== undefined && { marginPct: signal.marginPct }),
|
|
580
|
+
...(signal.leverage !== undefined && { leverage: signal.leverage }),
|
|
581
|
+
};
|
|
724
582
|
// Trace the sizing-relevant fields the narrowed request carries, so a
|
|
725
583
|
// field dropped at this seam is visible instead of vanishing silently.
|
|
726
584
|
apiLogger.debug(`[intake] ingest req signal_id=${signal.signal_id} scanner=${resolved.scannerName} asset=${signal.asset} direction=${signal.direction} marginPct=${signal.marginPct} leverage=${signal.leverage}`);
|
|
@@ -740,18 +598,15 @@ const senpiRuntimePlugin = {
|
|
|
740
598
|
// The single server-level onError closure — the `/errors` counterpart of
|
|
741
599
|
// routeAcceptedSignalToRuntime. It records a scaffold-reported tick failure into
|
|
742
600
|
// the owning runtime's scanner telemetry so a scanner that fails every tick stops
|
|
743
|
-
// rendering "healthy".
|
|
744
|
-
// `candidate_rejected` body is a per-candidate reject on an otherwise-OK tick, not
|
|
745
|
-
// a failed run.
|
|
601
|
+
// rendering "healthy".
|
|
746
602
|
//
|
|
747
|
-
// This is the SHARED implementation (scaffold-error-router.ts),
|
|
748
|
-
// buildIntakeMount's onScaffoldError
|
|
749
|
-
//
|
|
603
|
+
// This is the SHARED implementation (scaffold-error-router.ts), not a copy of
|
|
604
|
+
// buildIntakeMount's onScaffoldError. It used to be a copy, and the copy had its
|
|
605
|
+
// own hardcoded three-type filter: when `mcp_error` was added to the tick-failure
|
|
606
|
+
// list it reached the tested seam and never reached this route, so the
|
|
607
|
+
// wedged-scanner signal was green in CI and inert in production. There is now one
|
|
608
|
+
// filter, and scaffold-error-router.test.ts drives THIS closure.
|
|
750
609
|
routeScaffoldErrorToRuntime = buildScaffoldErrorRouter(ctx, runtimeHandles);
|
|
751
|
-
// The per-tick level for a supervised external scanner. Both intake routes call it, so a
|
|
752
|
-
// quiet tick and a failed tick are equally visible; it needs no runtime handle because it
|
|
753
|
-
// publishes a level rather than recording a run.
|
|
754
|
-
routeScaffoldTickToTelemetry = buildScaffoldTickRouter(ctx);
|
|
755
610
|
}
|
|
756
611
|
// One bounded read: which registered wallets the platform says are dead, so a restart does
|
|
757
612
|
// not re-scaffold runtimes on closed wallets (fail-open — see runtime/boot-skip.ts).
|
|
@@ -803,9 +658,6 @@ const senpiRuntimePlugin = {
|
|
|
803
658
|
continue;
|
|
804
659
|
const pathOrContent = entry.runtimeYamlPath ?? entry.runtimeYamlContent;
|
|
805
660
|
const entryStateDir = buildRuntimeStateDir(baseStateDir, entry.id, entry.wallet ?? "");
|
|
806
|
-
// Indexed before the boot attempt: a runtime whose start throws is installed but stopped,
|
|
807
|
-
// and the telemetry topology has to be able to say so.
|
|
808
|
-
noteTelemetryRuntime(entry.id, entry.wallet ?? "");
|
|
809
661
|
const handle = await run(pathOrContent, {
|
|
810
662
|
fromPath: hasPath,
|
|
811
663
|
stateDir: entryStateDir,
|
|
@@ -829,7 +681,6 @@ const senpiRuntimePlugin = {
|
|
|
829
681
|
if (sharedIntakeContext) {
|
|
830
682
|
try {
|
|
831
683
|
const runtimeConfig = await loadRuntimeConfig(pathOrContent, { fromPath: hasPath });
|
|
832
|
-
noteTelemetryRuntimeConfig(entry.id, runtimeConfig);
|
|
833
684
|
// Content-installed runtimes carry their recipe dir in the registry
|
|
834
685
|
// entry (runtimeYamlDir) so relative scanner paths still resolve
|
|
835
686
|
// after a restart; path-installed ones derive it from the path.
|
|
@@ -881,7 +732,6 @@ const senpiRuntimePlugin = {
|
|
|
881
732
|
// event) so listRuntimes/health don't render a bare "running".
|
|
882
733
|
try {
|
|
883
734
|
const runtimeConfig = await loadRuntimeConfig(pathOrContent, { fromPath: hasPath });
|
|
884
|
-
noteTelemetryRuntimeConfig(entry.id, runtimeConfig);
|
|
885
735
|
if (selectScanners(runtimeConfig).length > 0) {
|
|
886
736
|
unwiredRuntimes.set(entry.id, "no_intake");
|
|
887
737
|
handle.attachSupervisionSource(() => ({
|
|
@@ -940,7 +790,6 @@ const senpiRuntimePlugin = {
|
|
|
940
790
|
intakeContext: sharedIntakeContext,
|
|
941
791
|
onAccepted: routeAcceptedSignalToRuntime,
|
|
942
792
|
onError: routeScaffoldErrorToRuntime,
|
|
943
|
-
onTick: routeScaffoldTickToTelemetry,
|
|
944
793
|
});
|
|
945
794
|
apiHandle.ready();
|
|
946
795
|
}
|
|
@@ -984,12 +833,6 @@ const senpiRuntimePlugin = {
|
|
|
984
833
|
}
|
|
985
834
|
}
|
|
986
835
|
}
|
|
987
|
-
// Publish ticks start only once the runtimes are up, so the first frames describe a real
|
|
988
|
-
// box. Gated by the same switch the skills coordinator uses: unit tests boot `register()`
|
|
989
|
-
// and must not acquire background timers. The subscribe method still answers without them.
|
|
990
|
-
if (process.env.SENPI_RUNTIME_API_DISABLED !== "true") {
|
|
991
|
-
liveTelemetry.start();
|
|
992
|
-
}
|
|
993
836
|
// Last, once everything above is up: the reaper's post-boot pass and hourly sweep. Its
|
|
994
837
|
// not-active escalation is also off until here, so no delete can land while the boot loop is
|
|
995
838
|
// still wiring runtimes and launchers. Nothing here may fail start() — a throw from inside the boot loop takes every runtime down, which
|
|
@@ -1007,14 +850,9 @@ const senpiRuntimePlugin = {
|
|
|
1007
850
|
}
|
|
1008
851
|
},
|
|
1009
852
|
async stop() {
|
|
1010
|
-
//
|
|
1011
|
-
//
|
|
1012
|
-
//
|
|
1013
|
-
// which is the right trade for a process on its way out.
|
|
1014
|
-
liveTelemetry.stop();
|
|
1015
|
-
// Then the reaper, before the runtimes are torn down below, so no pass starts deleting
|
|
1016
|
-
// while they go away. The wait is bounded, so a pass already under way cannot stop a handle
|
|
1017
|
-
// the teardown below is stopping too.
|
|
853
|
+
// Stop the reaper first so no pass starts deleting while the runtimes are torn down below,
|
|
854
|
+
// and wait (bounded) for a pass already under way, so its delete cannot stop a handle the
|
|
855
|
+
// teardown below is stopping too.
|
|
1018
856
|
await reaper.stop();
|
|
1019
857
|
// Drain the HTTP server FIRST so in-flight POST /signals requests
|
|
1020
858
|
// finish before the underlying runtime they target is torn down.
|
|
@@ -1351,10 +1189,6 @@ const senpiRuntimePlugin = {
|
|
|
1351
1189
|
onStrategyNotActive: (address) => reaper.checkWallet(address),
|
|
1352
1190
|
});
|
|
1353
1191
|
runtimeHandles.set(resolvedId, handle);
|
|
1354
|
-
if (parsedConfig)
|
|
1355
|
-
noteTelemetryRuntimeConfig(resolvedId, parsedConfig);
|
|
1356
|
-
else
|
|
1357
|
-
noteTelemetryRuntime(resolvedId, wallet);
|
|
1358
1192
|
// Registry create fact — distinct from the runtime.started boot transition (which also fires
|
|
1359
1193
|
// on a transient restart). Emitted inside emitEvent's guard so telemetry never fails the install.
|
|
1360
1194
|
emitEvent(apiLogger, () => buildRuntimeCreatedEvent({ runtimeId: resolvedId, address: wallet, recipeName: runtimeName }));
|
|
@@ -1467,7 +1301,7 @@ const senpiRuntimePlugin = {
|
|
|
1467
1301
|
}
|
|
1468
1302
|
}
|
|
1469
1303
|
/** Gateway respond accepts (ok, payload?, error?) with error as { code, message }; plugin SDK types may omit the third arg. */
|
|
1470
|
-
registerGatewayMethod("senpi.installRuntime", async (ctx) => {
|
|
1304
|
+
api.registerGatewayMethod("senpi.installRuntime", async (ctx) => {
|
|
1471
1305
|
const respond = ctx.respond;
|
|
1472
1306
|
const result = await installRuntimeCore(ctx.params);
|
|
1473
1307
|
if (result.ok)
|
|
@@ -1475,7 +1309,7 @@ const senpiRuntimePlugin = {
|
|
|
1475
1309
|
else
|
|
1476
1310
|
respond(false, undefined, result.error);
|
|
1477
1311
|
}, { scope: "operator.write" });
|
|
1478
|
-
registerGatewayMethod("senpi.listRuntimes", async (ctx) => {
|
|
1312
|
+
api.registerGatewayMethod("senpi.listRuntimes", async (ctx) => {
|
|
1479
1313
|
const respond = ctx.respond;
|
|
1480
1314
|
const { readRegistry } = await import("./runtime/strategy-registry.js");
|
|
1481
1315
|
const registry = await readRegistry(baseStateDir);
|
|
@@ -1618,9 +1452,6 @@ const senpiRuntimePlugin = {
|
|
|
1618
1452
|
// "running — NO ENTRY SCANNERS" forever. The map is otherwise only cleared on a
|
|
1619
1453
|
// successful wire/install, which a scanner-less reinstall never reaches.
|
|
1620
1454
|
unwiredRuntimes.delete(targetId);
|
|
1621
|
-
// Same reuse hazard: a deleted id left in the index would keep publishing a strategy that no
|
|
1622
|
-
// longer exists, and would hand a reinstall the old name and scanner list.
|
|
1623
|
-
telemetryStrategies.delete(targetId);
|
|
1624
1455
|
bootSkippedRuntimes.delete(targetId);
|
|
1625
1456
|
// Archive state directory before removing from registry
|
|
1626
1457
|
if (deletedEntry) {
|
|
@@ -1651,7 +1482,7 @@ const senpiRuntimePlugin = {
|
|
|
1651
1482
|
}));
|
|
1652
1483
|
return { ok: true, payload: { id: targetId } };
|
|
1653
1484
|
}
|
|
1654
|
-
registerGatewayMethod("senpi.deleteRuntime", async (ctx) => {
|
|
1485
|
+
api.registerGatewayMethod("senpi.deleteRuntime", async (ctx) => {
|
|
1655
1486
|
const respond = ctx.respond;
|
|
1656
1487
|
const result = await deleteRuntimeCore(ctx.params);
|
|
1657
1488
|
if (result.ok)
|
|
@@ -1758,17 +1589,6 @@ const senpiRuntimePlugin = {
|
|
|
1758
1589
|
return checkProofCoversRecipe(packageDir, verifyProof(packageDir), appliedRecipe, (f) => readFileSync(f, "utf8"));
|
|
1759
1590
|
},
|
|
1760
1591
|
applyToRuntime: makeApplyToRuntime(runtimeHandles, async (runtimeId, next, recipe) => {
|
|
1761
|
-
// Re-index the topology facts FIRST, ahead of every early return and every failure path
|
|
1762
|
-
// below. `makeApplyToRuntime` only reaches this callback once the in-process swap has
|
|
1763
|
-
// succeeded, so `next` is already the recipe this box runs: its display name and its
|
|
1764
|
-
// declared scanner list are the ones the topology payload must name. Leaving the index on
|
|
1765
|
-
// the previous config would publish strategy rows the new scanner stats cannot join to.
|
|
1766
|
-
//
|
|
1767
|
-
// Ahead of the early return because an apply on a box with no intake still swapped the
|
|
1768
|
-
// recipe, and ahead of the launcher because a launcher that fails is a runtime running the
|
|
1769
|
-
// new recipe with no external scanners — the degraded state a dashboard most needs to show,
|
|
1770
|
-
// and one it can only render if the declared scanners are the new ones.
|
|
1771
|
-
noteTelemetryRuntimeConfig(runtimeId, next);
|
|
1772
1592
|
// Restart this runtime's external scanner children against the new package.
|
|
1773
1593
|
//
|
|
1774
1594
|
// The rebuild swaps in-process components; these are separate OS processes, spawned once
|
|
@@ -1916,7 +1736,7 @@ const senpiRuntimePlugin = {
|
|
|
1916
1736
|
* producers — slated for removal in Task 5 once the migration counter
|
|
1917
1737
|
* decays to zero (see `runtime-phase-2-api-plan.md` Section 8).
|
|
1918
1738
|
*/
|
|
1919
|
-
registerGatewayMethod("senpi.ingestExternalScannerData", async (ctx) => {
|
|
1739
|
+
api.registerGatewayMethod("senpi.ingestExternalScannerData", async (ctx) => {
|
|
1920
1740
|
const respond = ctx.respond;
|
|
1921
1741
|
// TODO(s11): wire actual telemetry counter for
|
|
1922
1742
|
// runtime.deprecated_gateway_ingest_call (event name, properties:
|
|
@@ -1935,7 +1755,6 @@ const senpiRuntimePlugin = {
|
|
|
1935
1755
|
...(request.direction !== undefined && { direction: request.direction }),
|
|
1936
1756
|
...(request.score !== undefined && { score: request.score }),
|
|
1937
1757
|
...(request.signal_type !== undefined && { signal_type: request.signal_type }),
|
|
1938
|
-
...(request.tick_id !== undefined && { tick_id: request.tick_id }),
|
|
1939
1758
|
...(request.data !== undefined && { data: request.data }),
|
|
1940
1759
|
...(request.signals !== undefined && { signals: request.signals }),
|
|
1941
1760
|
};
|
|
@@ -1993,7 +1812,7 @@ const senpiRuntimePlugin = {
|
|
|
1993
1812
|
});
|
|
1994
1813
|
}
|
|
1995
1814
|
}, { scope: "operator.write" });
|
|
1996
|
-
registerGatewayMethod("senpi.listDslPositions", async (ctx) => {
|
|
1815
|
+
api.registerGatewayMethod("senpi.listDslPositions", async (ctx) => {
|
|
1997
1816
|
const respond = ctx.respond;
|
|
1998
1817
|
const runtimeId = typeof ctx.params?.runtimeId === "string" ? ctx.params.runtimeId : undefined;
|
|
1999
1818
|
const address = typeof ctx.params?.address === "string" ? ctx.params.address : undefined;
|
|
@@ -2018,7 +1837,7 @@ const senpiRuntimePlugin = {
|
|
|
2018
1837
|
}
|
|
2019
1838
|
respond(true, { positions });
|
|
2020
1839
|
}, { scope: "operator.read" });
|
|
2021
|
-
registerGatewayMethod("senpi.getDslPositionState", async (ctx) => {
|
|
1840
|
+
api.registerGatewayMethod("senpi.getDslPositionState", async (ctx) => {
|
|
2022
1841
|
const respond = ctx.respond;
|
|
2023
1842
|
const asset = typeof ctx.params?.asset === "string" ? ctx.params.asset : undefined;
|
|
2024
1843
|
if (!asset) {
|
|
@@ -2059,7 +1878,7 @@ const senpiRuntimePlugin = {
|
|
|
2059
1878
|
}
|
|
2060
1879
|
respond(true, { positions: matches });
|
|
2061
1880
|
}, { scope: "operator.read" });
|
|
2062
|
-
registerGatewayMethod("senpi.listDslArchives", async (ctx) => {
|
|
1881
|
+
api.registerGatewayMethod("senpi.listDslArchives", async (ctx) => {
|
|
2063
1882
|
const respond = ctx.respond;
|
|
2064
1883
|
const runtimeId = typeof ctx.params?.runtimeId === "string" ? ctx.params.runtimeId : undefined;
|
|
2065
1884
|
const address = typeof ctx.params?.address === "string" ? ctx.params.address : undefined;
|
|
@@ -2085,7 +1904,7 @@ const senpiRuntimePlugin = {
|
|
|
2085
1904
|
closes = closes.slice(0, limit);
|
|
2086
1905
|
respond(true, { closes });
|
|
2087
1906
|
}, { scope: "operator.read" });
|
|
2088
|
-
registerGatewayMethod("senpi.getHealthStatus", async (ctx) => {
|
|
1907
|
+
api.registerGatewayMethod("senpi.getHealthStatus", async (ctx) => {
|
|
2089
1908
|
const respond = ctx.respond;
|
|
2090
1909
|
const updater = autoUpdateCoordinator.getSnapshot();
|
|
2091
1910
|
const runtimeId = typeof ctx.params?.runtimeId === "string" ? ctx.params.runtimeId : undefined;
|
|
@@ -2113,7 +1932,7 @@ const senpiRuntimePlugin = {
|
|
|
2113
1932
|
const statuses = await collectRuntimeHealthStatuses(runtimeHandles, api.logger);
|
|
2114
1933
|
respond(true, { statuses, updater });
|
|
2115
1934
|
}, { scope: "operator.read" });
|
|
2116
|
-
registerGatewayMethod("senpi.getSystemState", async (ctx) => {
|
|
1935
|
+
api.registerGatewayMethod("senpi.getSystemState", async (ctx) => {
|
|
2117
1936
|
const respond = ctx.respond;
|
|
2118
1937
|
const updater = autoUpdateCoordinator.getSnapshot();
|
|
2119
1938
|
const runtimeId = typeof ctx.params?.runtimeId === "string" ? ctx.params.runtimeId : undefined;
|
|
@@ -2141,36 +1960,6 @@ const senpiRuntimePlugin = {
|
|
|
2141
1960
|
const states = await collectRuntimeSystemStates(runtimeHandles, api.logger, baseStateDir);
|
|
2142
1961
|
respond(true, { states, updater });
|
|
2143
1962
|
}, { scope: "operator.read" });
|
|
2144
|
-
/**
|
|
2145
|
-
* Live telemetry — the one method of the stream, called once per connect.
|
|
2146
|
-
*
|
|
2147
|
-
* It returns the current value of all three broadcast payloads plus the recent record window, so
|
|
2148
|
-
* a client joining a box that has been running for hours renders a full screen immediately
|
|
2149
|
-
* instead of waiting for the next thing to happen. `(afterEpoch, afterSeq)` resumes a client that
|
|
2150
|
-
* already holds part of this epoch's run — a cursor naming any other epoch is dropped, because a
|
|
2151
|
-
* seq from a previous run cannot address these records. `truncated` says when the records between
|
|
2152
|
-
* a cursor of this epoch and the oldest record still held are gone, which nothing in `recent`
|
|
2153
|
-
* alone can express.
|
|
2154
|
-
*
|
|
2155
|
-
* Read-only, like every other inspection method here. The scope that decides who RECEIVES the
|
|
2156
|
-
* broadcasts is a property of the client's own connection, not of this method.
|
|
2157
|
-
*/
|
|
2158
|
-
registerGatewayMethod("senpi.telemetry.subscribe", async (ctx) => {
|
|
2159
|
-
const respond = ctx.respond;
|
|
2160
|
-
try {
|
|
2161
|
-
respond(true, await liveTelemetry.snapshot({
|
|
2162
|
-
afterEpoch: ctx.params?.afterEpoch,
|
|
2163
|
-
afterSeq: ctx.params?.afterSeq,
|
|
2164
|
-
}));
|
|
2165
|
-
}
|
|
2166
|
-
catch (err) {
|
|
2167
|
-
api.logger.warn("[senpi-runtime] telemetry subscribe error", { err });
|
|
2168
|
-
respond(false, undefined, {
|
|
2169
|
-
code: "INTERNAL_ERROR",
|
|
2170
|
-
message: `Failed to build the telemetry snapshot: ${formatGatewayError(err)}`,
|
|
2171
|
-
});
|
|
2172
|
-
}
|
|
2173
|
-
}, { scope: "operator.read" });
|
|
2174
1963
|
/**
|
|
2175
1964
|
* Force the auto-update poll to run now instead of waiting for its timer.
|
|
2176
1965
|
*
|
|
@@ -2229,7 +2018,7 @@ const senpiRuntimePlugin = {
|
|
|
2229
2018
|
* persisted action-store machinery (`src/actions/store/`) usable
|
|
2230
2019
|
* from the operator-facing CLI again.
|
|
2231
2020
|
*/
|
|
2232
|
-
registerGatewayMethod("senpi.listActions", async (ctx) => {
|
|
2021
|
+
api.registerGatewayMethod("senpi.listActions", async (ctx) => {
|
|
2233
2022
|
const respond = ctx.respond;
|
|
2234
2023
|
const runtimeId = typeof ctx.params?.runtimeId === "string" ? ctx.params.runtimeId : undefined;
|
|
2235
2024
|
const address = typeof ctx.params?.address === "string" ? ctx.params.address : undefined;
|
|
@@ -2259,7 +2048,7 @@ const senpiRuntimePlugin = {
|
|
|
2259
2048
|
}
|
|
2260
2049
|
respond(true, { actions: merged });
|
|
2261
2050
|
}, { scope: "operator.read" });
|
|
2262
|
-
registerGatewayMethod("senpi.getActionState", async (ctx) => {
|
|
2051
|
+
api.registerGatewayMethod("senpi.getActionState", async (ctx) => {
|
|
2263
2052
|
const respond = ctx.respond;
|
|
2264
2053
|
const runtimeId = typeof ctx.params?.runtimeId === "string" ? ctx.params.runtimeId : undefined;
|
|
2265
2054
|
const actionName = typeof ctx.params?.actionName === "string" ? ctx.params.actionName : undefined;
|
|
@@ -2296,7 +2085,7 @@ const senpiRuntimePlugin = {
|
|
|
2296
2085
|
});
|
|
2297
2086
|
}
|
|
2298
2087
|
}, { scope: "operator.read" });
|
|
2299
|
-
registerGatewayMethod("senpi.getActionHistory", async (ctx) => {
|
|
2088
|
+
api.registerGatewayMethod("senpi.getActionHistory", async (ctx) => {
|
|
2300
2089
|
const respond = ctx.respond;
|
|
2301
2090
|
const runtimeId = typeof ctx.params?.runtimeId === "string" ? ctx.params.runtimeId : undefined;
|
|
2302
2091
|
const actionName = typeof ctx.params?.actionName === "string" ? ctx.params.actionName : undefined;
|
|
@@ -2364,7 +2153,7 @@ const senpiRuntimePlugin = {
|
|
|
2364
2153
|
// reachable on HTTP `/audit`. Passes through the caller-controlled subset
|
|
2365
2154
|
// of the audit_query contract; resource scoping (wallet → strategyId) is
|
|
2366
2155
|
// owned by handle.auditQuery, never the caller.
|
|
2367
|
-
registerGatewayMethod("senpi.auditQuery", async (ctx) => {
|
|
2156
|
+
api.registerGatewayMethod("senpi.auditQuery", async (ctx) => {
|
|
2368
2157
|
const respond = ctx.respond;
|
|
2369
2158
|
const runtimeId = typeof ctx.params?.runtimeId === "string" ? ctx.params.runtimeId : undefined;
|
|
2370
2159
|
if (!runtimeId) {
|
|
@@ -2412,7 +2201,7 @@ const senpiRuntimePlugin = {
|
|
|
2412
2201
|
// its state root private, so re-derive it from baseStateDir + the handle's
|
|
2413
2202
|
// wallet (same helper the writer's stateDir was built with); the writer
|
|
2414
2203
|
// nests entries under `<root>/<address>/risk-guard/audit.jsonl`.
|
|
2415
|
-
registerGatewayMethod("senpi.getRiskAudit", async (ctx) => {
|
|
2204
|
+
api.registerGatewayMethod("senpi.getRiskAudit", async (ctx) => {
|
|
2416
2205
|
const respond = ctx.respond;
|
|
2417
2206
|
const runtimeId = typeof ctx.params?.runtimeId === "string" ? ctx.params.runtimeId : undefined;
|
|
2418
2207
|
if (!runtimeId) {
|
|
@@ -2455,7 +2244,7 @@ const senpiRuntimePlugin = {
|
|
|
2455
2244
|
// Per-strategy local domain-event ring (on-disk JSONL) — the trade narrative, queryable locally.
|
|
2456
2245
|
// Same state-root re-derivation as getRiskAudit: the Runtime keeps its root private, so rebuild it
|
|
2457
2246
|
// from baseStateDir + the handle's wallet; the writer nests rows under `<root>/strategies/<address>/events/`.
|
|
2458
|
-
registerGatewayMethod("senpi.getEvents", async (ctx) => {
|
|
2247
|
+
api.registerGatewayMethod("senpi.getEvents", async (ctx) => {
|
|
2459
2248
|
const respond = ctx.respond;
|
|
2460
2249
|
const runtimeId = typeof ctx.params?.runtimeId === "string" ? ctx.params.runtimeId : undefined;
|
|
2461
2250
|
if (!runtimeId) {
|
|
@@ -2512,12 +2301,12 @@ const senpiRuntimePlugin = {
|
|
|
2512
2301
|
}
|
|
2513
2302
|
}, { scope: "operator.read" });
|
|
2514
2303
|
// ─── Skills manager — read + mutate ──────────────────────────────────────
|
|
2515
|
-
registerGatewayMethod("senpi.skills.status", async (ctx) => {
|
|
2304
|
+
api.registerGatewayMethod("senpi.skills.status", async (ctx) => {
|
|
2516
2305
|
const respond = ctx.respond;
|
|
2517
2306
|
const snapshot = skillsCoordinator.getSnapshot();
|
|
2518
2307
|
respond(true, { snapshot });
|
|
2519
2308
|
}, { scope: "operator.read" });
|
|
2520
|
-
registerGatewayMethod("senpi.skills.update", async (ctx) => {
|
|
2309
|
+
api.registerGatewayMethod("senpi.skills.update", async (ctx) => {
|
|
2521
2310
|
const respond = ctx.respond;
|
|
2522
2311
|
const name = typeof ctx.params?.name === "string" ? ctx.params.name.trim() : undefined;
|
|
2523
2312
|
if (!name) {
|
|
@@ -2542,7 +2331,7 @@ const senpiRuntimePlugin = {
|
|
|
2542
2331
|
});
|
|
2543
2332
|
}
|
|
2544
2333
|
}, { scope: "operator.write" });
|
|
2545
|
-
registerGatewayMethod("senpi.skills.updateAll", async (ctx) => {
|
|
2334
|
+
api.registerGatewayMethod("senpi.skills.updateAll", async (ctx) => {
|
|
2546
2335
|
const respond = ctx.respond;
|
|
2547
2336
|
try {
|
|
2548
2337
|
const results = await skillsCoordinator.updateAll();
|
|
@@ -2608,7 +2397,6 @@ function parseGatewayExternalScannerIngestParams(params) {
|
|
|
2608
2397
|
direction: params?.direction,
|
|
2609
2398
|
score: params?.score,
|
|
2610
2399
|
signal_type: params?.signal_type,
|
|
2611
|
-
tick_id: params?.tick_id,
|
|
2612
2400
|
data: params?.data,
|
|
2613
2401
|
signals: params?.signals,
|
|
2614
2402
|
},
|