@senpi/runtime 3.0.132 → 3.0.138
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 +4 -12
- 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 -12
- package/dist/actions/open-position/open-position.action.d.ts.map +1 -1
- package/dist/actions/open-position/open-position.action.js +41 -144
- 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 +13 -8
- package/dist/cli/guide-commands.js.map +1 -1
- package/dist/cli/senpi-commands.d.ts.map +1 -1
- package/dist/cli/senpi-commands.js +11 -4
- package/dist/cli/senpi-commands.js.map +1 -1
- package/dist/constants/dsl/index.d.ts +0 -6
- package/dist/constants/dsl/index.d.ts.map +1 -1
- package/dist/constants/dsl/index.js +0 -6
- package/dist/constants/dsl/index.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 -82
- package/dist/dsl/monitor/create-monitor.js.map +1 -1
- package/dist/dsl/monitor/dsl-failure-events.d.ts +2 -45
- package/dist/dsl/monitor/dsl-failure-events.d.ts.map +1 -1
- package/dist/dsl/monitor/dsl-failure-events.js +3 -52
- 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 +36 -159
- 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 +41 -271
- 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/auto-update/coordinator.d.ts +6 -13
- package/dist/runtime/auto-update/coordinator.d.ts.map +1 -1
- package/dist/runtime/auto-update/coordinator.js +18 -86
- package/dist/runtime/auto-update/coordinator.js.map +1 -1
- package/dist/runtime/auto-update/run-update-command.d.ts.map +1 -1
- package/dist/runtime/auto-update/run-update-command.js +3 -4
- package/dist/runtime/auto-update/run-update-command.js.map +1 -1
- package/dist/runtime/auto-update/types.d.ts +5 -11
- package/dist/runtime/auto-update/types.d.ts.map +1 -1
- package/dist/runtime/auto-update/types.js +0 -11
- package/dist/runtime/auto-update/types.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 +3 -15
- package/dist/runtime/lifecycle-events.d.ts.map +1 -1
- package/dist/runtime/lifecycle-events.js +3 -17
- package/dist/runtime/lifecycle-events.js.map +1 -1
- package/dist/runtime/lifecycle-reaper.d.ts +6 -4
- package/dist/runtime/lifecycle-reaper.d.ts.map +1 -1
- package/dist/runtime/lifecycle-reaper.js +6 -4
- package/dist/runtime/lifecycle-reaper.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/risk-guard.d.ts +20 -1
- package/dist/runtime/risk-guard.d.ts.map +1 -1
- package/dist/runtime/risk-guard.js +47 -6
- package/dist/runtime/risk-guard.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 +3 -2
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +30 -37
- package/dist/runtime/runtime.js.map +1 -1
- package/dist/runtime/strategy-lifecycle.d.ts +108 -2
- package/dist/runtime/strategy-lifecycle.d.ts.map +1 -1
- package/dist/runtime/strategy-lifecycle.js +325 -4
- package/dist/runtime/strategy-lifecycle.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 -48
- 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 -202
- package/dist/utils/event-catalog.d.ts.map +1 -1
- package/dist/utils/event-catalog.js +0 -26
- 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 +4 -8
- 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/dsl-positions.d.ts +0 -111
- package/dist/telemetry/dsl-positions.d.ts.map +0 -1
- package/dist/telemetry/dsl-positions.js +0 -118
- package/dist/telemetry/dsl-positions.js.map +0 -1
- package/dist/telemetry/live-telemetry.d.ts +0 -257
- package/dist/telemetry/live-telemetry.d.ts.map +0 -1
- package/dist/telemetry/live-telemetry.js +0 -959
- 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 -83
- package/dist/telemetry/telemetry-publisher.d.ts.map +0 -1
- package/dist/telemetry/telemetry-publisher.js +0 -256
- 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,168 +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
|
-
// The DSL states, read straight off each runtime's plugin. Synchronous and in-memory — this is
|
|
514
|
-
// the same store the `senpi.listDslPositions` RPC reads — so it costs the gather nothing, and a
|
|
515
|
-
// recipe with no DSL exit block has no plugin and contributes no rows. A runtime whose read
|
|
516
|
-
// throws is skipped rather than failing the whole gather, on the same rule health follows: a
|
|
517
|
-
// strategy mid-teardown must not take the stream down.
|
|
518
|
-
const dslPositions = [];
|
|
519
|
-
for (const [runtimeId, handle] of runtimeHandles) {
|
|
520
|
-
if (!handle.dsl)
|
|
521
|
-
continue;
|
|
522
|
-
try {
|
|
523
|
-
for (const state of handle.dsl.listActiveDslStates()) {
|
|
524
|
-
dslPositions.push({ runtimeId, state });
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
catch (err) {
|
|
528
|
-
api.logger.warn("[senpi-runtime] could not read DSL states for telemetry", { runtimeId, err });
|
|
529
|
-
}
|
|
530
|
-
}
|
|
531
|
-
return {
|
|
532
|
-
strategies,
|
|
533
|
-
runningRuntimeIds: runtimeHandles,
|
|
534
|
-
unwiredRuntimeIds: unwiredRuntimes,
|
|
535
|
-
readHealth: (runtimeId) => healthByRuntime.get(runtimeId),
|
|
536
|
-
scannerState,
|
|
537
|
-
dslPositions,
|
|
538
|
-
};
|
|
539
|
-
};
|
|
540
|
-
const liveTelemetry = createLiveTelemetry({
|
|
541
|
-
collectFacts: collectTelemetryFacts,
|
|
542
|
-
tickTelemetry: config.tickTelemetry,
|
|
543
|
-
});
|
|
544
|
-
/**
|
|
545
|
-
* Wrapped gateway methods capture the broadcast handle on the FIRST request to ANY of them —
|
|
546
|
-
* not only on subscribe. `ctx.context` is the only route to the websocket push layer and it
|
|
547
|
-
* exists only inside a handler, so capturing it in the subscribe method alone would mean a box
|
|
548
|
-
* whose client never subscribes can never publish anything, silently.
|
|
549
|
-
*
|
|
550
|
-
* The wrapper covers only what is registered through it. `senpi.deploy.start`,
|
|
551
|
-
* `senpi.deploy.status` and `senpi.update` are registered straight onto the plugin api by their
|
|
552
|
-
* own registrars and never arm the handle. That is not a gap in practice: one wrapped call arms
|
|
553
|
-
* it for the life of the process, and the websocket client admits `senpi.telemetry.subscribe`,
|
|
554
|
-
* which is wrapped.
|
|
555
|
-
*/
|
|
556
|
-
const registerGatewayMethod = (name, handler, opts) => {
|
|
557
|
-
api.registerGatewayMethod(name, (ctx) => {
|
|
558
|
-
liveTelemetry.captureBroadcast(ctx, name);
|
|
559
|
-
return handler(ctx);
|
|
560
|
-
}, opts);
|
|
561
|
-
};
|
|
562
389
|
// A gateway seam failed to wire/launch a runtime's external scanner stack: the runtime is up but
|
|
563
390
|
// runs blind on internal scanners only. Two records, by design: a first-class `runtime.scanners_unwired`
|
|
564
391
|
// event (the queryable/alertable fact, by phase) and the migrated exception-form `logger.error`
|
|
@@ -666,7 +493,8 @@ const senpiRuntimePlugin = {
|
|
|
666
493
|
// ── lifecycle reaper ─────────────────────────────────────────────────────────────────────────
|
|
667
494
|
// A runtime exists iff its strategy is open. Every close path ends at the backend and none of
|
|
668
495
|
// them tells this box, so the reaper asks: once after boot, hourly, and whenever the backend
|
|
669
|
-
// rejects an order with STRATEGY_NOT_ACTIVE.
|
|
496
|
+
// rejects an order with STRATEGY_NOT_ACTIVE. Enforcing by default since the 3.0.121 observe-only
|
|
497
|
+
// validation; SENPI_REAPER_ENFORCE=false returns a box to observe-only (see
|
|
670
498
|
// runtime/lifecycle-reaper.ts for the safety rule). Constructed here so both `run()` call sites
|
|
671
499
|
// (boot and install) can hand it their not-active rejections; it does no I/O until started.
|
|
672
500
|
const reaperBootDelayOverride = resolveReaperBootDelayMs(process.env);
|
|
@@ -732,14 +560,26 @@ const senpiRuntimePlugin = {
|
|
|
732
560
|
// /signals will not be mounted and no signals will be routed.
|
|
733
561
|
if (sharedIntakeContext) {
|
|
734
562
|
const ctx = sharedIntakeContext;
|
|
735
|
-
routeAcceptedSignalToRuntime = (signal,
|
|
563
|
+
routeAcceptedSignalToRuntime = (signal, _correlationId, scannerId) => {
|
|
736
564
|
const resolved = ctx.registry.resolve(scannerId);
|
|
737
565
|
if (!resolved)
|
|
738
566
|
return;
|
|
739
567
|
const h = runtimeHandles.get(resolved.runtimeId);
|
|
740
568
|
if (!h)
|
|
741
569
|
return;
|
|
742
|
-
const request =
|
|
570
|
+
const request = {
|
|
571
|
+
scanner: resolved.scannerName,
|
|
572
|
+
signal_id: signal.signal_id, // greppable handle across intake→ingest (obs only)
|
|
573
|
+
asset: signal.asset,
|
|
574
|
+
direction: signal.direction,
|
|
575
|
+
...(signal.signal_type !== undefined && { signal_type: signal.signal_type }),
|
|
576
|
+
data: signal.data,
|
|
577
|
+
// Per-signal sizing rides at the top level; the open-position action
|
|
578
|
+
// reads request.marginPct / request.leverage directly. Without this a
|
|
579
|
+
// supervised signal's sizing is lost ("no margin source resolved").
|
|
580
|
+
...(signal.marginPct !== undefined && { marginPct: signal.marginPct }),
|
|
581
|
+
...(signal.leverage !== undefined && { leverage: signal.leverage }),
|
|
582
|
+
};
|
|
743
583
|
// Trace the sizing-relevant fields the narrowed request carries, so a
|
|
744
584
|
// field dropped at this seam is visible instead of vanishing silently.
|
|
745
585
|
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}`);
|
|
@@ -759,18 +599,15 @@ const senpiRuntimePlugin = {
|
|
|
759
599
|
// The single server-level onError closure — the `/errors` counterpart of
|
|
760
600
|
// routeAcceptedSignalToRuntime. It records a scaffold-reported tick failure into
|
|
761
601
|
// the owning runtime's scanner telemetry so a scanner that fails every tick stops
|
|
762
|
-
// rendering "healthy".
|
|
763
|
-
// `candidate_rejected` body is a per-candidate reject on an otherwise-OK tick, not
|
|
764
|
-
// a failed run.
|
|
602
|
+
// rendering "healthy".
|
|
765
603
|
//
|
|
766
|
-
// This is the SHARED implementation (scaffold-error-router.ts),
|
|
767
|
-
// buildIntakeMount's onScaffoldError
|
|
768
|
-
//
|
|
604
|
+
// This is the SHARED implementation (scaffold-error-router.ts), not a copy of
|
|
605
|
+
// buildIntakeMount's onScaffoldError. It used to be a copy, and the copy had its
|
|
606
|
+
// own hardcoded three-type filter: when `mcp_error` was added to the tick-failure
|
|
607
|
+
// list it reached the tested seam and never reached this route, so the
|
|
608
|
+
// wedged-scanner signal was green in CI and inert in production. There is now one
|
|
609
|
+
// filter, and scaffold-error-router.test.ts drives THIS closure.
|
|
769
610
|
routeScaffoldErrorToRuntime = buildScaffoldErrorRouter(ctx, runtimeHandles);
|
|
770
|
-
// The per-tick level for a supervised external scanner. Both intake routes call it, so a
|
|
771
|
-
// quiet tick and a failed tick are equally visible; it needs no runtime handle because it
|
|
772
|
-
// publishes a level rather than recording a run.
|
|
773
|
-
routeScaffoldTickToTelemetry = buildScaffoldTickRouter(ctx);
|
|
774
611
|
}
|
|
775
612
|
// One bounded read: which registered wallets the platform says are dead, so a restart does
|
|
776
613
|
// not re-scaffold runtimes on closed wallets (fail-open — see runtime/boot-skip.ts).
|
|
@@ -822,9 +659,6 @@ const senpiRuntimePlugin = {
|
|
|
822
659
|
continue;
|
|
823
660
|
const pathOrContent = entry.runtimeYamlPath ?? entry.runtimeYamlContent;
|
|
824
661
|
const entryStateDir = buildRuntimeStateDir(baseStateDir, entry.id, entry.wallet ?? "");
|
|
825
|
-
// Indexed before the boot attempt: a runtime whose start throws is installed but stopped,
|
|
826
|
-
// and the telemetry topology has to be able to say so.
|
|
827
|
-
noteTelemetryRuntime(entry.id, entry.wallet ?? "");
|
|
828
662
|
const handle = await run(pathOrContent, {
|
|
829
663
|
fromPath: hasPath,
|
|
830
664
|
stateDir: entryStateDir,
|
|
@@ -848,7 +682,6 @@ const senpiRuntimePlugin = {
|
|
|
848
682
|
if (sharedIntakeContext) {
|
|
849
683
|
try {
|
|
850
684
|
const runtimeConfig = await loadRuntimeConfig(pathOrContent, { fromPath: hasPath });
|
|
851
|
-
noteTelemetryRuntimeConfig(entry.id, runtimeConfig);
|
|
852
685
|
// Content-installed runtimes carry their recipe dir in the registry
|
|
853
686
|
// entry (runtimeYamlDir) so relative scanner paths still resolve
|
|
854
687
|
// after a restart; path-installed ones derive it from the path.
|
|
@@ -900,7 +733,6 @@ const senpiRuntimePlugin = {
|
|
|
900
733
|
// event) so listRuntimes/health don't render a bare "running".
|
|
901
734
|
try {
|
|
902
735
|
const runtimeConfig = await loadRuntimeConfig(pathOrContent, { fromPath: hasPath });
|
|
903
|
-
noteTelemetryRuntimeConfig(entry.id, runtimeConfig);
|
|
904
736
|
if (selectScanners(runtimeConfig).length > 0) {
|
|
905
737
|
unwiredRuntimes.set(entry.id, "no_intake");
|
|
906
738
|
handle.attachSupervisionSource(() => ({
|
|
@@ -959,7 +791,6 @@ const senpiRuntimePlugin = {
|
|
|
959
791
|
intakeContext: sharedIntakeContext,
|
|
960
792
|
onAccepted: routeAcceptedSignalToRuntime,
|
|
961
793
|
onError: routeScaffoldErrorToRuntime,
|
|
962
|
-
onTick: routeScaffoldTickToTelemetry,
|
|
963
794
|
});
|
|
964
795
|
apiHandle.ready();
|
|
965
796
|
}
|
|
@@ -1003,12 +834,6 @@ const senpiRuntimePlugin = {
|
|
|
1003
834
|
}
|
|
1004
835
|
}
|
|
1005
836
|
}
|
|
1006
|
-
// Publish ticks start only once the runtimes are up, so the first frames describe a real
|
|
1007
|
-
// box. Gated by the same switch the skills coordinator uses: unit tests boot `register()`
|
|
1008
|
-
// and must not acquire background timers. The subscribe method still answers without them.
|
|
1009
|
-
if (process.env.SENPI_RUNTIME_API_DISABLED !== "true") {
|
|
1010
|
-
liveTelemetry.start();
|
|
1011
|
-
}
|
|
1012
837
|
// Last, once everything above is up: the reaper's post-boot pass and hourly sweep. Its
|
|
1013
838
|
// not-active escalation is also off until here, so no delete can land while the boot loop is
|
|
1014
839
|
// still wiring runtimes and launchers. Nothing here may fail start() — a throw from inside the boot loop takes every runtime down, which
|
|
@@ -1026,11 +851,6 @@ const senpiRuntimePlugin = {
|
|
|
1026
851
|
}
|
|
1027
852
|
},
|
|
1028
853
|
async stop() {
|
|
1029
|
-
// Live telemetry goes first: it owns a timer and an in-memory buffer, nothing downstream
|
|
1030
|
-
// depends on it, and stopping it here guarantees no publish tick reads a half-torn-down
|
|
1031
|
-
// runtime handle. Records emitted during the teardown below land in a buffer nobody drains,
|
|
1032
|
-
// which is the right trade for a process on its way out.
|
|
1033
|
-
liveTelemetry.stop();
|
|
1034
854
|
// Stop the reaper first so no pass starts deleting while the runtimes are torn down below,
|
|
1035
855
|
// and wait (bounded) for a pass already under way, so its delete cannot stop a handle the
|
|
1036
856
|
// teardown below is stopping too.
|
|
@@ -1370,10 +1190,6 @@ const senpiRuntimePlugin = {
|
|
|
1370
1190
|
onStrategyNotActive: (address) => reaper.checkWallet(address),
|
|
1371
1191
|
});
|
|
1372
1192
|
runtimeHandles.set(resolvedId, handle);
|
|
1373
|
-
if (parsedConfig)
|
|
1374
|
-
noteTelemetryRuntimeConfig(resolvedId, parsedConfig);
|
|
1375
|
-
else
|
|
1376
|
-
noteTelemetryRuntime(resolvedId, wallet);
|
|
1377
1193
|
// Registry create fact — distinct from the runtime.started boot transition (which also fires
|
|
1378
1194
|
// on a transient restart). Emitted inside emitEvent's guard so telemetry never fails the install.
|
|
1379
1195
|
emitEvent(apiLogger, () => buildRuntimeCreatedEvent({ runtimeId: resolvedId, address: wallet, recipeName: runtimeName }));
|
|
@@ -1486,7 +1302,7 @@ const senpiRuntimePlugin = {
|
|
|
1486
1302
|
}
|
|
1487
1303
|
}
|
|
1488
1304
|
/** Gateway respond accepts (ok, payload?, error?) with error as { code, message }; plugin SDK types may omit the third arg. */
|
|
1489
|
-
registerGatewayMethod("senpi.installRuntime", async (ctx) => {
|
|
1305
|
+
api.registerGatewayMethod("senpi.installRuntime", async (ctx) => {
|
|
1490
1306
|
const respond = ctx.respond;
|
|
1491
1307
|
const result = await installRuntimeCore(ctx.params);
|
|
1492
1308
|
if (result.ok)
|
|
@@ -1494,7 +1310,7 @@ const senpiRuntimePlugin = {
|
|
|
1494
1310
|
else
|
|
1495
1311
|
respond(false, undefined, result.error);
|
|
1496
1312
|
}, { scope: "operator.write" });
|
|
1497
|
-
registerGatewayMethod("senpi.listRuntimes", async (ctx) => {
|
|
1313
|
+
api.registerGatewayMethod("senpi.listRuntimes", async (ctx) => {
|
|
1498
1314
|
const respond = ctx.respond;
|
|
1499
1315
|
const { readRegistry } = await import("./runtime/strategy-registry.js");
|
|
1500
1316
|
const registry = await readRegistry(baseStateDir);
|
|
@@ -1637,9 +1453,6 @@ const senpiRuntimePlugin = {
|
|
|
1637
1453
|
// "running — NO ENTRY SCANNERS" forever. The map is otherwise only cleared on a
|
|
1638
1454
|
// successful wire/install, which a scanner-less reinstall never reaches.
|
|
1639
1455
|
unwiredRuntimes.delete(targetId);
|
|
1640
|
-
// Same reuse hazard: a deleted id left in the index would keep publishing a strategy that no
|
|
1641
|
-
// longer exists, and would hand a reinstall the old name and scanner list.
|
|
1642
|
-
telemetryStrategies.delete(targetId);
|
|
1643
1456
|
bootSkippedRuntimes.delete(targetId);
|
|
1644
1457
|
// Archive state directory before removing from registry
|
|
1645
1458
|
if (deletedEntry) {
|
|
@@ -1670,7 +1483,7 @@ const senpiRuntimePlugin = {
|
|
|
1670
1483
|
}));
|
|
1671
1484
|
return { ok: true, payload: { id: targetId } };
|
|
1672
1485
|
}
|
|
1673
|
-
registerGatewayMethod("senpi.deleteRuntime", async (ctx) => {
|
|
1486
|
+
api.registerGatewayMethod("senpi.deleteRuntime", async (ctx) => {
|
|
1674
1487
|
const respond = ctx.respond;
|
|
1675
1488
|
const result = await deleteRuntimeCore(ctx.params);
|
|
1676
1489
|
if (result.ok)
|
|
@@ -1777,17 +1590,6 @@ const senpiRuntimePlugin = {
|
|
|
1777
1590
|
return checkProofCoversRecipe(packageDir, verifyProof(packageDir), appliedRecipe, (f) => readFileSync(f, "utf8"));
|
|
1778
1591
|
},
|
|
1779
1592
|
applyToRuntime: makeApplyToRuntime(runtimeHandles, async (runtimeId, next, recipe) => {
|
|
1780
|
-
// Re-index the topology facts FIRST, ahead of every early return and every failure path
|
|
1781
|
-
// below. `makeApplyToRuntime` only reaches this callback once the in-process swap has
|
|
1782
|
-
// succeeded, so `next` is already the recipe this box runs: its display name and its
|
|
1783
|
-
// declared scanner list are the ones the topology payload must name. Leaving the index on
|
|
1784
|
-
// the previous config would publish strategy rows the new scanner stats cannot join to.
|
|
1785
|
-
//
|
|
1786
|
-
// Ahead of the early return because an apply on a box with no intake still swapped the
|
|
1787
|
-
// recipe, and ahead of the launcher because a launcher that fails is a runtime running the
|
|
1788
|
-
// new recipe with no external scanners — the degraded state a dashboard most needs to show,
|
|
1789
|
-
// and one it can only render if the declared scanners are the new ones.
|
|
1790
|
-
noteTelemetryRuntimeConfig(runtimeId, next);
|
|
1791
1593
|
// Restart this runtime's external scanner children against the new package.
|
|
1792
1594
|
//
|
|
1793
1595
|
// The rebuild swaps in-process components; these are separate OS processes, spawned once
|
|
@@ -1935,7 +1737,7 @@ const senpiRuntimePlugin = {
|
|
|
1935
1737
|
* producers — slated for removal in Task 5 once the migration counter
|
|
1936
1738
|
* decays to zero (see `runtime-phase-2-api-plan.md` Section 8).
|
|
1937
1739
|
*/
|
|
1938
|
-
registerGatewayMethod("senpi.ingestExternalScannerData", async (ctx) => {
|
|
1740
|
+
api.registerGatewayMethod("senpi.ingestExternalScannerData", async (ctx) => {
|
|
1939
1741
|
const respond = ctx.respond;
|
|
1940
1742
|
// TODO(s11): wire actual telemetry counter for
|
|
1941
1743
|
// runtime.deprecated_gateway_ingest_call (event name, properties:
|
|
@@ -1954,7 +1756,6 @@ const senpiRuntimePlugin = {
|
|
|
1954
1756
|
...(request.direction !== undefined && { direction: request.direction }),
|
|
1955
1757
|
...(request.score !== undefined && { score: request.score }),
|
|
1956
1758
|
...(request.signal_type !== undefined && { signal_type: request.signal_type }),
|
|
1957
|
-
...(request.tick_id !== undefined && { tick_id: request.tick_id }),
|
|
1958
1759
|
...(request.data !== undefined && { data: request.data }),
|
|
1959
1760
|
...(request.signals !== undefined && { signals: request.signals }),
|
|
1960
1761
|
};
|
|
@@ -2012,7 +1813,7 @@ const senpiRuntimePlugin = {
|
|
|
2012
1813
|
});
|
|
2013
1814
|
}
|
|
2014
1815
|
}, { scope: "operator.write" });
|
|
2015
|
-
registerGatewayMethod("senpi.listDslPositions", async (ctx) => {
|
|
1816
|
+
api.registerGatewayMethod("senpi.listDslPositions", async (ctx) => {
|
|
2016
1817
|
const respond = ctx.respond;
|
|
2017
1818
|
const runtimeId = typeof ctx.params?.runtimeId === "string" ? ctx.params.runtimeId : undefined;
|
|
2018
1819
|
const address = typeof ctx.params?.address === "string" ? ctx.params.address : undefined;
|
|
@@ -2037,7 +1838,7 @@ const senpiRuntimePlugin = {
|
|
|
2037
1838
|
}
|
|
2038
1839
|
respond(true, { positions });
|
|
2039
1840
|
}, { scope: "operator.read" });
|
|
2040
|
-
registerGatewayMethod("senpi.getDslPositionState", async (ctx) => {
|
|
1841
|
+
api.registerGatewayMethod("senpi.getDslPositionState", async (ctx) => {
|
|
2041
1842
|
const respond = ctx.respond;
|
|
2042
1843
|
const asset = typeof ctx.params?.asset === "string" ? ctx.params.asset : undefined;
|
|
2043
1844
|
if (!asset) {
|
|
@@ -2078,7 +1879,7 @@ const senpiRuntimePlugin = {
|
|
|
2078
1879
|
}
|
|
2079
1880
|
respond(true, { positions: matches });
|
|
2080
1881
|
}, { scope: "operator.read" });
|
|
2081
|
-
registerGatewayMethod("senpi.listDslArchives", async (ctx) => {
|
|
1882
|
+
api.registerGatewayMethod("senpi.listDslArchives", async (ctx) => {
|
|
2082
1883
|
const respond = ctx.respond;
|
|
2083
1884
|
const runtimeId = typeof ctx.params?.runtimeId === "string" ? ctx.params.runtimeId : undefined;
|
|
2084
1885
|
const address = typeof ctx.params?.address === "string" ? ctx.params.address : undefined;
|
|
@@ -2104,7 +1905,7 @@ const senpiRuntimePlugin = {
|
|
|
2104
1905
|
closes = closes.slice(0, limit);
|
|
2105
1906
|
respond(true, { closes });
|
|
2106
1907
|
}, { scope: "operator.read" });
|
|
2107
|
-
registerGatewayMethod("senpi.getHealthStatus", async (ctx) => {
|
|
1908
|
+
api.registerGatewayMethod("senpi.getHealthStatus", async (ctx) => {
|
|
2108
1909
|
const respond = ctx.respond;
|
|
2109
1910
|
const updater = autoUpdateCoordinator.getSnapshot();
|
|
2110
1911
|
const runtimeId = typeof ctx.params?.runtimeId === "string" ? ctx.params.runtimeId : undefined;
|
|
@@ -2132,7 +1933,7 @@ const senpiRuntimePlugin = {
|
|
|
2132
1933
|
const statuses = await collectRuntimeHealthStatuses(runtimeHandles, api.logger);
|
|
2133
1934
|
respond(true, { statuses, updater });
|
|
2134
1935
|
}, { scope: "operator.read" });
|
|
2135
|
-
registerGatewayMethod("senpi.getSystemState", async (ctx) => {
|
|
1936
|
+
api.registerGatewayMethod("senpi.getSystemState", async (ctx) => {
|
|
2136
1937
|
const respond = ctx.respond;
|
|
2137
1938
|
const updater = autoUpdateCoordinator.getSnapshot();
|
|
2138
1939
|
const runtimeId = typeof ctx.params?.runtimeId === "string" ? ctx.params.runtimeId : undefined;
|
|
@@ -2160,36 +1961,6 @@ const senpiRuntimePlugin = {
|
|
|
2160
1961
|
const states = await collectRuntimeSystemStates(runtimeHandles, api.logger, baseStateDir);
|
|
2161
1962
|
respond(true, { states, updater });
|
|
2162
1963
|
}, { scope: "operator.read" });
|
|
2163
|
-
/**
|
|
2164
|
-
* Live telemetry — the one method of the stream, called once per connect.
|
|
2165
|
-
*
|
|
2166
|
-
* It returns the current value of all three broadcast payloads plus the recent record window, so
|
|
2167
|
-
* a client joining a box that has been running for hours renders a full screen immediately
|
|
2168
|
-
* instead of waiting for the next thing to happen. `(afterEpoch, afterSeq)` resumes a client that
|
|
2169
|
-
* already holds part of this epoch's run — a cursor naming any other epoch is dropped, because a
|
|
2170
|
-
* seq from a previous run cannot address these records. `truncated` says when the records between
|
|
2171
|
-
* a cursor of this epoch and the oldest record still held are gone, which nothing in `recent`
|
|
2172
|
-
* alone can express.
|
|
2173
|
-
*
|
|
2174
|
-
* Read-only, like every other inspection method here. The scope that decides who RECEIVES the
|
|
2175
|
-
* broadcasts is a property of the client's own connection, not of this method.
|
|
2176
|
-
*/
|
|
2177
|
-
registerGatewayMethod("senpi.telemetry.subscribe", async (ctx) => {
|
|
2178
|
-
const respond = ctx.respond;
|
|
2179
|
-
try {
|
|
2180
|
-
respond(true, await liveTelemetry.snapshot({
|
|
2181
|
-
afterEpoch: ctx.params?.afterEpoch,
|
|
2182
|
-
afterSeq: ctx.params?.afterSeq,
|
|
2183
|
-
}));
|
|
2184
|
-
}
|
|
2185
|
-
catch (err) {
|
|
2186
|
-
api.logger.warn("[senpi-runtime] telemetry subscribe error", { err });
|
|
2187
|
-
respond(false, undefined, {
|
|
2188
|
-
code: "INTERNAL_ERROR",
|
|
2189
|
-
message: `Failed to build the telemetry snapshot: ${formatGatewayError(err)}`,
|
|
2190
|
-
});
|
|
2191
|
-
}
|
|
2192
|
-
}, { scope: "operator.read" });
|
|
2193
1964
|
/**
|
|
2194
1965
|
* Force the auto-update poll to run now instead of waiting for its timer.
|
|
2195
1966
|
*
|
|
@@ -2248,7 +2019,7 @@ const senpiRuntimePlugin = {
|
|
|
2248
2019
|
* persisted action-store machinery (`src/actions/store/`) usable
|
|
2249
2020
|
* from the operator-facing CLI again.
|
|
2250
2021
|
*/
|
|
2251
|
-
registerGatewayMethod("senpi.listActions", async (ctx) => {
|
|
2022
|
+
api.registerGatewayMethod("senpi.listActions", async (ctx) => {
|
|
2252
2023
|
const respond = ctx.respond;
|
|
2253
2024
|
const runtimeId = typeof ctx.params?.runtimeId === "string" ? ctx.params.runtimeId : undefined;
|
|
2254
2025
|
const address = typeof ctx.params?.address === "string" ? ctx.params.address : undefined;
|
|
@@ -2278,7 +2049,7 @@ const senpiRuntimePlugin = {
|
|
|
2278
2049
|
}
|
|
2279
2050
|
respond(true, { actions: merged });
|
|
2280
2051
|
}, { scope: "operator.read" });
|
|
2281
|
-
registerGatewayMethod("senpi.getActionState", async (ctx) => {
|
|
2052
|
+
api.registerGatewayMethod("senpi.getActionState", async (ctx) => {
|
|
2282
2053
|
const respond = ctx.respond;
|
|
2283
2054
|
const runtimeId = typeof ctx.params?.runtimeId === "string" ? ctx.params.runtimeId : undefined;
|
|
2284
2055
|
const actionName = typeof ctx.params?.actionName === "string" ? ctx.params.actionName : undefined;
|
|
@@ -2315,7 +2086,7 @@ const senpiRuntimePlugin = {
|
|
|
2315
2086
|
});
|
|
2316
2087
|
}
|
|
2317
2088
|
}, { scope: "operator.read" });
|
|
2318
|
-
registerGatewayMethod("senpi.getActionHistory", async (ctx) => {
|
|
2089
|
+
api.registerGatewayMethod("senpi.getActionHistory", async (ctx) => {
|
|
2319
2090
|
const respond = ctx.respond;
|
|
2320
2091
|
const runtimeId = typeof ctx.params?.runtimeId === "string" ? ctx.params.runtimeId : undefined;
|
|
2321
2092
|
const actionName = typeof ctx.params?.actionName === "string" ? ctx.params.actionName : undefined;
|
|
@@ -2383,7 +2154,7 @@ const senpiRuntimePlugin = {
|
|
|
2383
2154
|
// reachable on HTTP `/audit`. Passes through the caller-controlled subset
|
|
2384
2155
|
// of the audit_query contract; resource scoping (wallet → strategyId) is
|
|
2385
2156
|
// owned by handle.auditQuery, never the caller.
|
|
2386
|
-
registerGatewayMethod("senpi.auditQuery", async (ctx) => {
|
|
2157
|
+
api.registerGatewayMethod("senpi.auditQuery", async (ctx) => {
|
|
2387
2158
|
const respond = ctx.respond;
|
|
2388
2159
|
const runtimeId = typeof ctx.params?.runtimeId === "string" ? ctx.params.runtimeId : undefined;
|
|
2389
2160
|
if (!runtimeId) {
|
|
@@ -2431,7 +2202,7 @@ const senpiRuntimePlugin = {
|
|
|
2431
2202
|
// its state root private, so re-derive it from baseStateDir + the handle's
|
|
2432
2203
|
// wallet (same helper the writer's stateDir was built with); the writer
|
|
2433
2204
|
// nests entries under `<root>/<address>/risk-guard/audit.jsonl`.
|
|
2434
|
-
registerGatewayMethod("senpi.getRiskAudit", async (ctx) => {
|
|
2205
|
+
api.registerGatewayMethod("senpi.getRiskAudit", async (ctx) => {
|
|
2435
2206
|
const respond = ctx.respond;
|
|
2436
2207
|
const runtimeId = typeof ctx.params?.runtimeId === "string" ? ctx.params.runtimeId : undefined;
|
|
2437
2208
|
if (!runtimeId) {
|
|
@@ -2474,7 +2245,7 @@ const senpiRuntimePlugin = {
|
|
|
2474
2245
|
// Per-strategy local domain-event ring (on-disk JSONL) — the trade narrative, queryable locally.
|
|
2475
2246
|
// Same state-root re-derivation as getRiskAudit: the Runtime keeps its root private, so rebuild it
|
|
2476
2247
|
// from baseStateDir + the handle's wallet; the writer nests rows under `<root>/strategies/<address>/events/`.
|
|
2477
|
-
registerGatewayMethod("senpi.getEvents", async (ctx) => {
|
|
2248
|
+
api.registerGatewayMethod("senpi.getEvents", async (ctx) => {
|
|
2478
2249
|
const respond = ctx.respond;
|
|
2479
2250
|
const runtimeId = typeof ctx.params?.runtimeId === "string" ? ctx.params.runtimeId : undefined;
|
|
2480
2251
|
if (!runtimeId) {
|
|
@@ -2531,12 +2302,12 @@ const senpiRuntimePlugin = {
|
|
|
2531
2302
|
}
|
|
2532
2303
|
}, { scope: "operator.read" });
|
|
2533
2304
|
// ─── Skills manager — read + mutate ──────────────────────────────────────
|
|
2534
|
-
registerGatewayMethod("senpi.skills.status", async (ctx) => {
|
|
2305
|
+
api.registerGatewayMethod("senpi.skills.status", async (ctx) => {
|
|
2535
2306
|
const respond = ctx.respond;
|
|
2536
2307
|
const snapshot = skillsCoordinator.getSnapshot();
|
|
2537
2308
|
respond(true, { snapshot });
|
|
2538
2309
|
}, { scope: "operator.read" });
|
|
2539
|
-
registerGatewayMethod("senpi.skills.update", async (ctx) => {
|
|
2310
|
+
api.registerGatewayMethod("senpi.skills.update", async (ctx) => {
|
|
2540
2311
|
const respond = ctx.respond;
|
|
2541
2312
|
const name = typeof ctx.params?.name === "string" ? ctx.params.name.trim() : undefined;
|
|
2542
2313
|
if (!name) {
|
|
@@ -2561,7 +2332,7 @@ const senpiRuntimePlugin = {
|
|
|
2561
2332
|
});
|
|
2562
2333
|
}
|
|
2563
2334
|
}, { scope: "operator.write" });
|
|
2564
|
-
registerGatewayMethod("senpi.skills.updateAll", async (ctx) => {
|
|
2335
|
+
api.registerGatewayMethod("senpi.skills.updateAll", async (ctx) => {
|
|
2565
2336
|
const respond = ctx.respond;
|
|
2566
2337
|
try {
|
|
2567
2338
|
const results = await skillsCoordinator.updateAll();
|
|
@@ -2627,7 +2398,6 @@ function parseGatewayExternalScannerIngestParams(params) {
|
|
|
2627
2398
|
direction: params?.direction,
|
|
2628
2399
|
score: params?.score,
|
|
2629
2400
|
signal_type: params?.signal_type,
|
|
2630
|
-
tick_id: params?.tick_id,
|
|
2631
2401
|
data: params?.data,
|
|
2632
2402
|
signals: params?.signals,
|
|
2633
2403
|
},
|