@senpi/runtime 3.0.102 → 3.0.106
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 +25 -56
- 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 +1 -18
- 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 +12 -86
- package/dist/actions/close-position/close-position.action.js.map +1 -1
- package/dist/actions/event-derivation.d.ts +2 -40
- package/dist/actions/event-derivation.d.ts.map +1 -1
- package/dist/actions/event-derivation.js +9 -189
- package/dist/actions/event-derivation.js.map +1 -1
- package/dist/actions/open-position/open-position.action.d.ts.map +1 -1
- package/dist/actions/open-position/open-position.action.js +17 -115
- 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 +15 -50
- package/dist/actions/position-tracker/position-tracker.action.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 -15
- 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 -5
- 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 -49
- package/dist/dsl/events/handlers.js.map +1 -1
- package/dist/dsl/monitor/create-monitor.d.ts.map +1 -1
- package/dist/dsl/monitor/create-monitor.js +0 -7
- 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 -6
- package/dist/dsl/monitor/process-one-position.d.ts.map +1 -1
- package/dist/dsl/monitor/process-one-position.js +21 -55
- package/dist/dsl/monitor/process-one-position.js.map +1 -1
- package/dist/health/types.d.ts +0 -6
- package/dist/health/types.d.ts.map +1 -1
- package/dist/health/types.js.map +1 -1
- package/dist/index.d.ts +4 -16
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +47 -245
- package/dist/index.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 +0 -2
- package/dist/runtime/reconcile-run.d.ts.map +1 -1
- package/dist/runtime/reconcile-run.js +1 -2
- 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 -3
- package/dist/runtime/reconcile-state.js.map +1 -1
- package/dist/runtime/runtime.d.ts +5 -5
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +20 -44
- package/dist/runtime/runtime.js.map +1 -1
- package/dist/runtime/strategy-registry.d.ts +1 -0
- package/dist/runtime/strategy-registry.d.ts.map +1 -1
- package/dist/runtime/strategy-registry.js +19 -0
- package/dist/runtime/strategy-registry.js.map +1 -1
- package/dist/runtime/supervisor/long-running-supervisor.d.ts +0 -8
- 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/update-apply-deps.d.ts +6 -0
- package/dist/runtime/update-apply-deps.d.ts.map +1 -1
- package/dist/runtime/update-apply-deps.js +8 -19
- package/dist/runtime/update-apply-deps.js.map +1 -1
- package/dist/runtime-api/intake/intake-events.d.ts +3 -3
- package/dist/runtime-api/intake/intake-events.d.ts.map +1 -1
- package/dist/runtime-api/intake/intake-events.js +3 -21
- package/dist/runtime-api/intake/intake-events.js.map +1 -1
- package/dist/runtime-api/intake/intake-mount.d.ts +2 -0
- package/dist/runtime-api/intake/intake-mount.d.ts.map +1 -1
- package/dist/runtime-api/intake/intake-mount.js +10 -57
- package/dist/runtime-api/intake/intake-mount.js.map +1 -1
- package/dist/runtime-api/intake/process-signal-post.d.ts +0 -11
- package/dist/runtime-api/intake/process-signal-post.d.ts.map +1 -1
- package/dist/runtime-api/intake/process-signal-post.js +8 -39
- package/dist/runtime-api/intake/process-signal-post.js.map +1 -1
- package/dist/runtime-api/intake/scaffold-error-router.d.ts +43 -0
- package/dist/runtime-api/intake/scaffold-error-router.d.ts.map +1 -0
- package/dist/runtime-api/intake/scaffold-error-router.js +63 -0
- package/dist/runtime-api/intake/scaffold-error-router.js.map +1 -0
- package/dist/runtime-api/intake/scanner-launcher.d.ts.map +1 -1
- package/dist/runtime-api/intake/scanner-launcher.js +0 -12
- package/dist/runtime-api/intake/scanner-launcher.js.map +1 -1
- package/dist/runtime-api/intake/types.d.ts +1 -22
- package/dist/runtime-api/intake/types.d.ts.map +1 -1
- package/dist/runtime-api/routes/signals.d.ts.map +1 -1
- package/dist/runtime-api/routes/signals.js +1 -7
- package/dist/runtime-api/routes/signals.js.map +1 -1
- package/dist/runtime-api/routes/signals.schema.d.ts +0 -1
- package/dist/runtime-api/routes/signals.schema.d.ts.map +1 -1
- package/dist/runtime-api/routes/signals.schema.js +0 -6
- package/dist/runtime-api/routes/signals.schema.js.map +1 -1
- package/dist/scanners/engine/engine.d.ts +0 -5
- package/dist/scanners/engine/engine.d.ts.map +1 -1
- package/dist/scanners/engine/engine.js +2 -30
- package/dist/scanners/engine/engine.js.map +1 -1
- package/dist/scanners/external/scaffold/delivery.py +12 -79
- package/dist/scanners/external/scaffold/scaffold.py +9 -63
- package/dist/scanners/external/scaffold/senpi_mcp.py +81 -10
- package/dist/scanners/external-scanner-receiver.d.ts +0 -11
- package/dist/scanners/external-scanner-receiver.d.ts.map +1 -1
- package/dist/scanners/external-scanner-receiver.js.map +1 -1
- package/dist/scanners/runtime-module.d.ts.map +1 -1
- package/dist/scanners/runtime-module.js +0 -5
- package/dist/scanners/runtime-module.js.map +1 -1
- package/dist/senpi/client.d.ts.map +1 -1
- package/dist/senpi/client.js +4 -12
- package/dist/senpi/client.js.map +1 -1
- package/dist/senpi/types.d.ts +0 -5
- package/dist/senpi/types.d.ts.map +1 -1
- package/dist/skills-manager/manifest.d.ts.map +1 -1
- package/dist/skills-manager/manifest.js +3 -12
- package/dist/skills-manager/manifest.js.map +1 -1
- package/dist/skills-manager/skills-manifest.json +3 -3
- package/dist/telemetry/event-builders.d.ts +6 -74
- package/dist/telemetry/event-builders.d.ts.map +1 -1
- package/dist/telemetry/event-builders.js +11 -108
- 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 +6 -6
- 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/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 -9
- package/dist/types/scanner.d.ts.map +1 -1
- package/dist/utils/event-catalog.d.ts +0 -81
- package/dist/utils/event-catalog.d.ts.map +1 -1
- package/dist/utils/event-catalog.js +0 -1
- package/dist/utils/event-catalog.js.map +1 -1
- package/dist/utils/keyed-mutex.d.ts +1 -3
- package/dist/utils/keyed-mutex.d.ts.map +1 -1
- package/dist/utils/keyed-mutex.js +1 -3
- package/dist/utils/keyed-mutex.js.map +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/dist/actions/skipped-signal-results.d.ts +0 -16
- package/dist/actions/skipped-signal-results.d.ts.map +0 -1
- package/dist/actions/skipped-signal-results.js +0 -47
- package/dist/actions/skipped-signal-results.js.map +0 -1
- package/dist/scanners/external/scaffold/ulid.py +0 -58
- package/dist/telemetry/live-telemetry.d.ts +0 -158
- package/dist/telemetry/live-telemetry.d.ts.map +0 -1
- package/dist/telemetry/live-telemetry.js +0 -581
- package/dist/telemetry/live-telemetry.js.map +0 -1
- package/dist/telemetry/scanner-stats.d.ts +0 -136
- package/dist/telemetry/scanner-stats.d.ts.map +0 -1
- package/dist/telemetry/scanner-stats.js +0 -304
- package/dist/telemetry/scanner-stats.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/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/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
|
@@ -42,7 +42,6 @@ import { VERSION } from "./version.js";
|
|
|
42
42
|
import { resolvePackageName } from "./runtime/auto-update/resolve-package-name.js";
|
|
43
43
|
import { runOpenClawPluginsUpdate } from "./runtime/auto-update/run-update-command.js";
|
|
44
44
|
import { registerSpanHooks } from "./telemetry/spans/index.js";
|
|
45
|
-
import { recordSignalIntake } from "./telemetry/metrics.js";
|
|
46
45
|
import { registerSessionContextSeedHook } from "./prompt/session-context-seed-hook.js";
|
|
47
46
|
import { initDefaultPiiRedactor } from "./telemetry/spans/redact-pii.js";
|
|
48
47
|
import { initOtelSdk, shutdownOtelSdk } from "./telemetry/otel-sdk.js";
|
|
@@ -62,8 +61,8 @@ import { ingestSignalsHandler } from "./runtime-api/handlers/ingest-signals.js";
|
|
|
62
61
|
import { createIntakeContext } from "./runtime-api/intake/intake-context.js";
|
|
63
62
|
import { wireRuntime, intakeUrlFor, selectScanners } from "./runtime-api/intake/intake-mount.js";
|
|
64
63
|
import { ingestDispatchMutex, ingestDispatchKey } from "./runtime-api/intake/ingest-mutex.js";
|
|
64
|
+
import { buildScaffoldErrorRouter } from "./runtime-api/intake/scaffold-error-router.js";
|
|
65
65
|
import { loadRuntimeConfig } from "./runtime/load-runtime-config.js";
|
|
66
|
-
import { createLiveTelemetry } from "./telemetry/live-telemetry.js";
|
|
67
66
|
/** Initialize all core features (DSL, risk, health) on the given event bus. */
|
|
68
67
|
export function initCore(bus) {
|
|
69
68
|
initDsl(bus);
|
|
@@ -360,30 +359,6 @@ const senpiRuntimePlugin = {
|
|
|
360
359
|
// cleared on a successful wire/install. senpi.listRuntimes reads it to render
|
|
361
360
|
// "running — NO ENTRY SCANNERS" instead of a bare "running" for a blind runtime.
|
|
362
361
|
const unwiredRuntimes = new Map();
|
|
363
|
-
// ── Live telemetry ────────────────────────────────────────────────
|
|
364
|
-
// Every runtime this box knows about, running or not, keyed runtimeId. The topology payload has
|
|
365
|
-
// to name a stopped strategy too, so this is populated from the registry rather than from
|
|
366
|
-
// `runtimeHandles` (which holds only the live ones) and is the source of the two facts the
|
|
367
|
-
// registry entry does not carry: the strategy's display name and its declared scanners. Both come
|
|
368
|
-
// from the parsed YAML — `name` is the same `config.name` that `RuntimeHealthStatus.runtimeName`
|
|
369
|
-
// is built from, so a runtime whose config never parsed falls back to its id rather than to a
|
|
370
|
-
// guess, and its scanner list stays empty rather than inventing rows.
|
|
371
|
-
const telemetryStrategies = new Map();
|
|
372
|
-
const noteTelemetryRuntime = (runtimeId, address) => {
|
|
373
|
-
const existing = telemetryStrategies.get(runtimeId);
|
|
374
|
-
telemetryStrategies.set(runtimeId, {
|
|
375
|
-
address,
|
|
376
|
-
name: existing?.name ?? runtimeId,
|
|
377
|
-
scanners: existing?.scanners ?? [],
|
|
378
|
-
});
|
|
379
|
-
};
|
|
380
|
-
const noteTelemetryRuntimeConfig = (runtimeId, config) => {
|
|
381
|
-
telemetryStrategies.set(runtimeId, {
|
|
382
|
-
address: config.strategy?.wallet ?? telemetryStrategies.get(runtimeId)?.address ?? "",
|
|
383
|
-
name: config.name,
|
|
384
|
-
scanners: config.scanners ?? [],
|
|
385
|
-
});
|
|
386
|
-
};
|
|
387
362
|
/**
|
|
388
363
|
* Wallets with an install IN FLIGHT in this process, keyed by lowercased address.
|
|
389
364
|
*
|
|
@@ -405,112 +380,6 @@ const senpiRuntimePlugin = {
|
|
|
405
380
|
// PluginLogger surface (info/warn/error) lacks `debug`, while the
|
|
406
381
|
// Logger contract used by `runtime-api/` includes it.
|
|
407
382
|
const apiLogger = createLogger("[senpi-core][api]");
|
|
408
|
-
/**
|
|
409
|
-
* One gather per publish tick. Health and system state are read together because the two payloads
|
|
410
|
-
* need both: the topology reads health and `runtimeName`, the stats read the per-scanner rows,
|
|
411
|
-
* and `restartCount` / `degradedReason` live only on the health rows while every other scanner
|
|
412
|
-
* field lives only on the system-state rows — so they are joined here on `(runtimeId, scannerId)`.
|
|
413
|
-
*/
|
|
414
|
-
const collectTelemetryFacts = async () => {
|
|
415
|
-
const [statuses, states] = await Promise.all([
|
|
416
|
-
collectRuntimeHealthStatuses(runtimeHandles, api.logger),
|
|
417
|
-
collectRuntimeSystemStates(runtimeHandles, api.logger, baseStateDir),
|
|
418
|
-
]);
|
|
419
|
-
const healthByRuntime = new Map();
|
|
420
|
-
for (const status of statuses) {
|
|
421
|
-
if (status.runtimeId !== undefined)
|
|
422
|
-
healthByRuntime.set(status.runtimeId, status);
|
|
423
|
-
}
|
|
424
|
-
const scannerState = [];
|
|
425
|
-
// Registration facts per (runtimeId, scannerId), so the topology can report a scanner's live
|
|
426
|
-
// schedule rather than only what its YAML declared.
|
|
427
|
-
const registrations = new Map();
|
|
428
|
-
for (const state of states) {
|
|
429
|
-
const runtimeId = state.runtimeId;
|
|
430
|
-
const healthRows = runtimeId === undefined
|
|
431
|
-
? []
|
|
432
|
-
: healthByRuntime.get(runtimeId)?.components.scanners.scanners ?? [];
|
|
433
|
-
for (const row of state.components.scanners.state.scanners) {
|
|
434
|
-
const supervision = healthRows.find((r) => r.scannerId === row.scannerId);
|
|
435
|
-
const snapshot = {
|
|
436
|
-
address: row.address,
|
|
437
|
-
scannerId: row.scannerId,
|
|
438
|
-
health: row.health,
|
|
439
|
-
degradedReason: supervision?.degradedReason ?? null,
|
|
440
|
-
enabled: row.enabled,
|
|
441
|
-
inFlightSince: row.inFlightSince,
|
|
442
|
-
lastRunStartedAt: row.lastRunStartedAt,
|
|
443
|
-
lastRunFinishedAt: row.lastRunFinishedAt,
|
|
444
|
-
lastRunStatus: row.lastRunStatus,
|
|
445
|
-
lastRunReason: row.lastRunReason,
|
|
446
|
-
nextRunAt: row.nextRunAt,
|
|
447
|
-
lastAliveAt: row.lastAliveAt,
|
|
448
|
-
// No supervision row means the restart count is unknown, not zero. A zero here would
|
|
449
|
-
// read as "this scanner has never restarted" on a scanner nobody is supervising.
|
|
450
|
-
restartCount: supervision?.restartCount ?? null,
|
|
451
|
-
};
|
|
452
|
-
scannerState.push(snapshot);
|
|
453
|
-
if (runtimeId !== undefined) {
|
|
454
|
-
registrations.set(`${runtimeId}::${row.scannerId}`, {
|
|
455
|
-
...snapshot,
|
|
456
|
-
scheduleMode: row.scheduleMode,
|
|
457
|
-
configVersion: row.configVersion,
|
|
458
|
-
intervalSeconds: row.intervalSeconds,
|
|
459
|
-
});
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
const strategies = [];
|
|
464
|
-
for (const [runtimeId, entry] of telemetryStrategies) {
|
|
465
|
-
const health = healthByRuntime.get(runtimeId);
|
|
466
|
-
const scanners = entry.scanners.map((declared) => {
|
|
467
|
-
const live = registrations.get(`${runtimeId}::${declared.name}`);
|
|
468
|
-
return live === undefined
|
|
469
|
-
? { entry: declared }
|
|
470
|
-
: {
|
|
471
|
-
entry: declared,
|
|
472
|
-
registration: {
|
|
473
|
-
enabled: live.enabled,
|
|
474
|
-
scheduleMode: live.scheduleMode,
|
|
475
|
-
// The engine's own cadence, which is what the scanner actually polls on — a
|
|
476
|
-
// recipe may omit it and take the scanner definition's default. An external
|
|
477
|
-
// scanner registers zero because it is POSTed to rather than polled, and only
|
|
478
|
-
// the recipe knows the cadence its scaffold was told to tick at.
|
|
479
|
-
intervalSeconds: live.intervalSeconds > 0 ? live.intervalSeconds : declared.interval_seconds ?? null,
|
|
480
|
-
configVersion: live.configVersion,
|
|
481
|
-
},
|
|
482
|
-
};
|
|
483
|
-
});
|
|
484
|
-
strategies.push({
|
|
485
|
-
runtimeId,
|
|
486
|
-
address: entry.address,
|
|
487
|
-
// `runtimeName` is built from the same `config.name`; the indexed value is used because it
|
|
488
|
-
// is available for a stopped runtime too, where there is no health status to read.
|
|
489
|
-
name: health?.runtimeName ?? entry.name,
|
|
490
|
-
scanners,
|
|
491
|
-
});
|
|
492
|
-
}
|
|
493
|
-
return {
|
|
494
|
-
strategies,
|
|
495
|
-
runningRuntimeIds: runtimeHandles,
|
|
496
|
-
unwiredRuntimeIds: unwiredRuntimes,
|
|
497
|
-
readHealth: (runtimeId) => healthByRuntime.get(runtimeId),
|
|
498
|
-
scannerState,
|
|
499
|
-
};
|
|
500
|
-
};
|
|
501
|
-
const liveTelemetry = createLiveTelemetry({ collectFacts: collectTelemetryFacts });
|
|
502
|
-
/**
|
|
503
|
-
* Every gateway method goes through here so the broadcast handle is captured on the FIRST request
|
|
504
|
-
* of any kind. `ctx.context` is the only route to the websocket push layer and it exists only
|
|
505
|
-
* inside a handler — capturing it in the subscribe method alone would mean a box whose client
|
|
506
|
-
* never subscribes can never publish anything, silently.
|
|
507
|
-
*/
|
|
508
|
-
const registerGatewayMethod = (name, handler, opts) => {
|
|
509
|
-
api.registerGatewayMethod(name, (ctx) => {
|
|
510
|
-
liveTelemetry.captureBroadcast(ctx, name);
|
|
511
|
-
return handler(ctx);
|
|
512
|
-
}, opts);
|
|
513
|
-
};
|
|
514
383
|
// A gateway seam failed to wire/launch a runtime's external scanner stack: the runtime is up but
|
|
515
384
|
// runs blind on internal scanners only. Two records, by design: a first-class `runtime.scanners_unwired`
|
|
516
385
|
// event (the queryable/alertable fact, by phase) and the migrated exception-form `logger.error`
|
|
@@ -651,7 +520,7 @@ const senpiRuntimePlugin = {
|
|
|
651
520
|
// /signals will not be mounted and no signals will be routed.
|
|
652
521
|
if (sharedIntakeContext) {
|
|
653
522
|
const ctx = sharedIntakeContext;
|
|
654
|
-
routeAcceptedSignalToRuntime = (signal,
|
|
523
|
+
routeAcceptedSignalToRuntime = (signal, _correlationId, scannerId) => {
|
|
655
524
|
const resolved = ctx.registry.resolve(scannerId);
|
|
656
525
|
if (!resolved)
|
|
657
526
|
return;
|
|
@@ -670,12 +539,6 @@ const senpiRuntimePlugin = {
|
|
|
670
539
|
// supervised signal's sizing is lost ("no margin source resolved").
|
|
671
540
|
...(signal.marginPct !== undefined && { marginPct: signal.marginPct }),
|
|
672
541
|
...(signal.leverage !== undefined && { leverage: signal.leverage }),
|
|
673
|
-
// The producing scan and the admitting acceptance row. Spread rather
|
|
674
|
-
// than assigned so a signal without a tick id yields no key at all — an
|
|
675
|
-
// undefined-valued key would ride on to an event attribute that exists
|
|
676
|
-
// and says nothing.
|
|
677
|
-
...(signal.tick_id !== undefined && { tick_id: signal.tick_id }),
|
|
678
|
-
...(correlationId !== undefined && { correlationId }),
|
|
679
542
|
};
|
|
680
543
|
// Trace the sizing-relevant fields the narrowed request carries, so a
|
|
681
544
|
// field dropped at this seam is visible instead of vanishing silently.
|
|
@@ -691,37 +554,20 @@ const senpiRuntimePlugin = {
|
|
|
691
554
|
.then(() => {
|
|
692
555
|
apiLogger.info(`[intake] ingest ok signal_id=${signal.signal_id} scanner=${resolved.scannerName} asset=${signal.asset} scanner_id=${scannerId}`);
|
|
693
556
|
})
|
|
694
|
-
.catch((err) => {
|
|
695
|
-
// Post-acceptance failure: the scaffold journaled this signal
|
|
696
|
-
// delivered and will NOT retry (the high-water-mark already
|
|
697
|
-
// advanced — a retry would double-trade). This is the one
|
|
698
|
-
// remaining silent-drop path, so it must be maximally visible.
|
|
699
|
-
apiLogger.error(`[intake] ingest failed AFTER acceptance — signal dropped (signal_id=${signal.signal_id} scanner=${resolved.scannerName} asset=${signal.asset})`, { scannerId, err });
|
|
700
|
-
recordSignalIntake({
|
|
701
|
-
scannerName: resolved.scannerName,
|
|
702
|
-
disposition: "dropped_after_accept",
|
|
703
|
-
});
|
|
704
|
-
});
|
|
557
|
+
.catch((err) => apiLogger.error("[intake] ingest failed", { scannerId, err }));
|
|
705
558
|
};
|
|
706
559
|
// The single server-level onError closure — the `/errors` counterpart of
|
|
707
560
|
// routeAcceptedSignalToRuntime. It records a scaffold-reported tick failure into
|
|
708
561
|
// the owning runtime's scanner telemetry so a scanner that fails every tick stops
|
|
709
|
-
// rendering "healthy".
|
|
710
|
-
//
|
|
711
|
-
//
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
if (!resolved)
|
|
719
|
-
return;
|
|
720
|
-
const h = runtimeHandles.get(resolved.runtimeId);
|
|
721
|
-
if (!h)
|
|
722
|
-
return;
|
|
723
|
-
h.recordExternalScannerError(resolved.scannerName, error);
|
|
724
|
-
};
|
|
562
|
+
// rendering "healthy".
|
|
563
|
+
//
|
|
564
|
+
// This is the SHARED implementation (scaffold-error-router.ts), not a copy of
|
|
565
|
+
// buildIntakeMount's onScaffoldError. It used to be a copy, and the copy had its
|
|
566
|
+
// own hardcoded three-type filter: when `mcp_error` was added to the tick-failure
|
|
567
|
+
// list it reached the tested seam and never reached this route, so the
|
|
568
|
+
// wedged-scanner signal was green in CI and inert in production. There is now one
|
|
569
|
+
// filter, and scaffold-error-router.test.ts drives THIS closure.
|
|
570
|
+
routeScaffoldErrorToRuntime = buildScaffoldErrorRouter(ctx, runtimeHandles);
|
|
725
571
|
}
|
|
726
572
|
const started = [];
|
|
727
573
|
try {
|
|
@@ -734,9 +580,6 @@ const senpiRuntimePlugin = {
|
|
|
734
580
|
continue;
|
|
735
581
|
const pathOrContent = entry.runtimeYamlPath ?? entry.runtimeYamlContent;
|
|
736
582
|
const entryStateDir = buildRuntimeStateDir(baseStateDir, entry.id, entry.wallet ?? "");
|
|
737
|
-
// Indexed before the boot attempt: a runtime whose start throws is installed but stopped,
|
|
738
|
-
// and the telemetry topology has to be able to say so.
|
|
739
|
-
noteTelemetryRuntime(entry.id, entry.wallet ?? "");
|
|
740
583
|
const handle = await run(pathOrContent, {
|
|
741
584
|
fromPath: hasPath,
|
|
742
585
|
stateDir: entryStateDir,
|
|
@@ -759,7 +602,6 @@ const senpiRuntimePlugin = {
|
|
|
759
602
|
if (sharedIntakeContext) {
|
|
760
603
|
try {
|
|
761
604
|
const runtimeConfig = await loadRuntimeConfig(pathOrContent, { fromPath: hasPath });
|
|
762
|
-
noteTelemetryRuntimeConfig(entry.id, runtimeConfig);
|
|
763
605
|
// Content-installed runtimes carry their recipe dir in the registry
|
|
764
606
|
// entry (runtimeYamlDir) so relative scanner paths still resolve
|
|
765
607
|
// after a restart; path-installed ones derive it from the path.
|
|
@@ -811,7 +653,6 @@ const senpiRuntimePlugin = {
|
|
|
811
653
|
// event) so listRuntimes/health don't render a bare "running".
|
|
812
654
|
try {
|
|
813
655
|
const runtimeConfig = await loadRuntimeConfig(pathOrContent, { fromPath: hasPath });
|
|
814
|
-
noteTelemetryRuntimeConfig(entry.id, runtimeConfig);
|
|
815
656
|
if (selectScanners(runtimeConfig).length > 0) {
|
|
816
657
|
unwiredRuntimes.set(entry.id, "no_intake");
|
|
817
658
|
handle.attachSupervisionSource(() => ({
|
|
@@ -913,19 +754,8 @@ const senpiRuntimePlugin = {
|
|
|
913
754
|
}
|
|
914
755
|
}
|
|
915
756
|
}
|
|
916
|
-
// Publish ticks start only once the runtimes are up, so the first frames describe a real
|
|
917
|
-
// box. Gated by the same switch the skills coordinator uses: unit tests boot `register()`
|
|
918
|
-
// and must not acquire background timers. The subscribe method still answers without them.
|
|
919
|
-
if (process.env.SENPI_RUNTIME_API_DISABLED !== "true") {
|
|
920
|
-
liveTelemetry.start();
|
|
921
|
-
}
|
|
922
757
|
},
|
|
923
758
|
async stop() {
|
|
924
|
-
// Live telemetry goes first: it owns a timer and an in-memory buffer, nothing downstream
|
|
925
|
-
// depends on it, and stopping it here guarantees no publish tick reads a half-torn-down
|
|
926
|
-
// runtime handle. Records emitted during the teardown below land in a buffer nobody drains,
|
|
927
|
-
// which is the right trade for a process on its way out.
|
|
928
|
-
liveTelemetry.stop();
|
|
929
759
|
// Drain the HTTP server FIRST so in-flight POST /signals requests
|
|
930
760
|
// finish before the underlying runtime they target is torn down.
|
|
931
761
|
// `apiHandle.close()` never throws.
|
|
@@ -973,7 +803,7 @@ const senpiRuntimePlugin = {
|
|
|
973
803
|
async function installRuntimeCore(params) {
|
|
974
804
|
const toError = (message) => ({ code: "INVALID_REQUEST", message });
|
|
975
805
|
const toUnavailable = (message) => ({ code: "UNAVAILABLE", message });
|
|
976
|
-
const { readRegistry, writeRegistry, validateEntry, hasId, findByWallet, deriveRuntimeId, sanitizeId } = await import("./runtime/strategy-registry.js");
|
|
806
|
+
const { readRegistry, writeRegistry, withRegistryLock, validateEntry, hasId, findByWallet, deriveRuntimeId, sanitizeId } = await import("./runtime/strategy-registry.js");
|
|
977
807
|
const id = typeof params?.id === "string" ? params.id : undefined;
|
|
978
808
|
const runtimeYamlPath = typeof params?.runtimeYamlPath === "string" ? params.runtimeYamlPath : undefined;
|
|
979
809
|
const runtimeYamlContent = typeof params?.runtimeYamlContent === "string" ? params.runtimeYamlContent : undefined;
|
|
@@ -1231,8 +1061,13 @@ const senpiRuntimePlugin = {
|
|
|
1231
1061
|
if (!valid.ok) {
|
|
1232
1062
|
return { ok: false, error: toError(valid.error) };
|
|
1233
1063
|
}
|
|
1234
|
-
registry
|
|
1235
|
-
|
|
1064
|
+
// Re-read under the registry lock rather than writing back `registry`: that snapshot predates
|
|
1065
|
+
// the gate and the checks above, and writing it would drop whatever another writer (an
|
|
1066
|
+
// update, a delete) changed in between. Same for the rollback and for delete below.
|
|
1067
|
+
await withRegistryLock(baseStateDir, async () => {
|
|
1068
|
+
const current = await readRegistry(baseStateDir);
|
|
1069
|
+
await writeRegistry(baseStateDir, { ...current, runtimes: [...current.runtimes, entry] });
|
|
1070
|
+
});
|
|
1236
1071
|
/**
|
|
1237
1072
|
* The unwired verdict for THIS install, tracked locally rather than read back out of
|
|
1238
1073
|
* `unwiredRuntimes`, so the result reports what this call did and never a leftover verdict
|
|
@@ -1255,10 +1090,6 @@ const senpiRuntimePlugin = {
|
|
|
1255
1090
|
runtimeId: resolvedId,
|
|
1256
1091
|
});
|
|
1257
1092
|
runtimeHandles.set(resolvedId, handle);
|
|
1258
|
-
if (parsedConfig)
|
|
1259
|
-
noteTelemetryRuntimeConfig(resolvedId, parsedConfig);
|
|
1260
|
-
else
|
|
1261
|
-
noteTelemetryRuntime(resolvedId, wallet);
|
|
1262
1093
|
// Registry create fact — distinct from the runtime.started boot transition (which also fires
|
|
1263
1094
|
// on a transient restart). Emitted inside emitEvent's guard so telemetry never fails the install.
|
|
1264
1095
|
emitEvent(apiLogger, () => buildRuntimeCreatedEvent({ runtimeId: resolvedId, address: wallet, recipeName: runtimeName }));
|
|
@@ -1357,8 +1188,10 @@ const senpiRuntimePlugin = {
|
|
|
1357
1188
|
};
|
|
1358
1189
|
}
|
|
1359
1190
|
catch (err) {
|
|
1360
|
-
|
|
1361
|
-
|
|
1191
|
+
await withRegistryLock(baseStateDir, async () => {
|
|
1192
|
+
const current = await readRegistry(baseStateDir);
|
|
1193
|
+
await writeRegistry(baseStateDir, { ...current, runtimes: current.runtimes.filter((e) => e.id !== resolvedId) });
|
|
1194
|
+
});
|
|
1362
1195
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1363
1196
|
return { ok: false, error: toUnavailable(`Could not start the runtime. This is usually due to invalid or incomplete YAML.\n\n${msg}`) };
|
|
1364
1197
|
}
|
|
@@ -1369,7 +1202,7 @@ const senpiRuntimePlugin = {
|
|
|
1369
1202
|
}
|
|
1370
1203
|
}
|
|
1371
1204
|
/** Gateway respond accepts (ok, payload?, error?) with error as { code, message }; plugin SDK types may omit the third arg. */
|
|
1372
|
-
registerGatewayMethod("senpi.installRuntime", async (ctx) => {
|
|
1205
|
+
api.registerGatewayMethod("senpi.installRuntime", async (ctx) => {
|
|
1373
1206
|
const respond = ctx.respond;
|
|
1374
1207
|
const result = await installRuntimeCore(ctx.params);
|
|
1375
1208
|
if (result.ok)
|
|
@@ -1377,7 +1210,7 @@ const senpiRuntimePlugin = {
|
|
|
1377
1210
|
else
|
|
1378
1211
|
respond(false, undefined, result.error);
|
|
1379
1212
|
}, { scope: "operator.write" });
|
|
1380
|
-
registerGatewayMethod("senpi.listRuntimes", async (ctx) => {
|
|
1213
|
+
api.registerGatewayMethod("senpi.listRuntimes", async (ctx) => {
|
|
1381
1214
|
const respond = ctx.respond;
|
|
1382
1215
|
const { readRegistry } = await import("./runtime/strategy-registry.js");
|
|
1383
1216
|
const registry = await readRegistry(baseStateDir);
|
|
@@ -1412,7 +1245,7 @@ const senpiRuntimePlugin = {
|
|
|
1412
1245
|
* unwired-verdict cleanup all happen exactly once, here.
|
|
1413
1246
|
*/
|
|
1414
1247
|
async function deleteRuntimeCore(params) {
|
|
1415
|
-
const { readRegistry, writeRegistry } = await import("./runtime/strategy-registry.js");
|
|
1248
|
+
const { readRegistry, writeRegistry, withRegistryLock } = await import("./runtime/strategy-registry.js");
|
|
1416
1249
|
const registry = await readRegistry(baseStateDir);
|
|
1417
1250
|
let targetId = typeof params?.id === "string" ? params.id : undefined;
|
|
1418
1251
|
const targetAddress = typeof params?.address === "string" ? params.address : undefined;
|
|
@@ -1460,9 +1293,6 @@ const senpiRuntimePlugin = {
|
|
|
1460
1293
|
// "running — NO ENTRY SCANNERS" forever. The map is otherwise only cleared on a
|
|
1461
1294
|
// successful wire/install, which a scanner-less reinstall never reaches.
|
|
1462
1295
|
unwiredRuntimes.delete(targetId);
|
|
1463
|
-
// Same reuse hazard: a deleted id left in the index would keep publishing a strategy that no
|
|
1464
|
-
// longer exists, and would hand a reinstall the old name and scanner list.
|
|
1465
|
-
telemetryStrategies.delete(targetId);
|
|
1466
1296
|
// Archive state directory before removing from registry
|
|
1467
1297
|
if (deletedEntry) {
|
|
1468
1298
|
const runtimeStateDir = buildRuntimeStateDir(baseStateDir, targetId, deletedEntry.wallet ?? "");
|
|
@@ -1476,8 +1306,10 @@ const senpiRuntimePlugin = {
|
|
|
1476
1306
|
}
|
|
1477
1307
|
}
|
|
1478
1308
|
if (deletedEntry) {
|
|
1479
|
-
|
|
1480
|
-
|
|
1309
|
+
await withRegistryLock(baseStateDir, async () => {
|
|
1310
|
+
const current = await readRegistry(baseStateDir);
|
|
1311
|
+
await writeRegistry(baseStateDir, { ...current, runtimes: current.runtimes.filter((e) => e.id !== targetId) });
|
|
1312
|
+
});
|
|
1481
1313
|
}
|
|
1482
1314
|
// Registry delete fact — the permanent-removal discriminator a transient runtime.stopped can't
|
|
1483
1315
|
// give. Unconditional (a never-booted runtime stops no handle, so emits no runtime.stopped) and
|
|
@@ -1489,7 +1321,7 @@ const senpiRuntimePlugin = {
|
|
|
1489
1321
|
}));
|
|
1490
1322
|
return { ok: true, payload: { id: targetId } };
|
|
1491
1323
|
}
|
|
1492
|
-
registerGatewayMethod("senpi.deleteRuntime", async (ctx) => {
|
|
1324
|
+
api.registerGatewayMethod("senpi.deleteRuntime", async (ctx) => {
|
|
1493
1325
|
const respond = ctx.respond;
|
|
1494
1326
|
const result = await deleteRuntimeCore(ctx.params);
|
|
1495
1327
|
if (result.ok)
|
|
@@ -1743,7 +1575,7 @@ const senpiRuntimePlugin = {
|
|
|
1743
1575
|
* producers — slated for removal in Task 5 once the migration counter
|
|
1744
1576
|
* decays to zero (see `runtime-phase-2-api-plan.md` Section 8).
|
|
1745
1577
|
*/
|
|
1746
|
-
registerGatewayMethod("senpi.ingestExternalScannerData", async (ctx) => {
|
|
1578
|
+
api.registerGatewayMethod("senpi.ingestExternalScannerData", async (ctx) => {
|
|
1747
1579
|
const respond = ctx.respond;
|
|
1748
1580
|
// TODO(s11): wire actual telemetry counter for
|
|
1749
1581
|
// runtime.deprecated_gateway_ingest_call (event name, properties:
|
|
@@ -1819,7 +1651,7 @@ const senpiRuntimePlugin = {
|
|
|
1819
1651
|
});
|
|
1820
1652
|
}
|
|
1821
1653
|
}, { scope: "operator.write" });
|
|
1822
|
-
registerGatewayMethod("senpi.listDslPositions", async (ctx) => {
|
|
1654
|
+
api.registerGatewayMethod("senpi.listDslPositions", async (ctx) => {
|
|
1823
1655
|
const respond = ctx.respond;
|
|
1824
1656
|
const runtimeId = typeof ctx.params?.runtimeId === "string" ? ctx.params.runtimeId : undefined;
|
|
1825
1657
|
const address = typeof ctx.params?.address === "string" ? ctx.params.address : undefined;
|
|
@@ -1844,7 +1676,7 @@ const senpiRuntimePlugin = {
|
|
|
1844
1676
|
}
|
|
1845
1677
|
respond(true, { positions });
|
|
1846
1678
|
}, { scope: "operator.read" });
|
|
1847
|
-
registerGatewayMethod("senpi.getDslPositionState", async (ctx) => {
|
|
1679
|
+
api.registerGatewayMethod("senpi.getDslPositionState", async (ctx) => {
|
|
1848
1680
|
const respond = ctx.respond;
|
|
1849
1681
|
const asset = typeof ctx.params?.asset === "string" ? ctx.params.asset : undefined;
|
|
1850
1682
|
if (!asset) {
|
|
@@ -1885,7 +1717,7 @@ const senpiRuntimePlugin = {
|
|
|
1885
1717
|
}
|
|
1886
1718
|
respond(true, { positions: matches });
|
|
1887
1719
|
}, { scope: "operator.read" });
|
|
1888
|
-
registerGatewayMethod("senpi.listDslArchives", async (ctx) => {
|
|
1720
|
+
api.registerGatewayMethod("senpi.listDslArchives", async (ctx) => {
|
|
1889
1721
|
const respond = ctx.respond;
|
|
1890
1722
|
const runtimeId = typeof ctx.params?.runtimeId === "string" ? ctx.params.runtimeId : undefined;
|
|
1891
1723
|
const address = typeof ctx.params?.address === "string" ? ctx.params.address : undefined;
|
|
@@ -1911,7 +1743,7 @@ const senpiRuntimePlugin = {
|
|
|
1911
1743
|
closes = closes.slice(0, limit);
|
|
1912
1744
|
respond(true, { closes });
|
|
1913
1745
|
}, { scope: "operator.read" });
|
|
1914
|
-
registerGatewayMethod("senpi.getHealthStatus", async (ctx) => {
|
|
1746
|
+
api.registerGatewayMethod("senpi.getHealthStatus", async (ctx) => {
|
|
1915
1747
|
const respond = ctx.respond;
|
|
1916
1748
|
const updater = autoUpdateCoordinator.getSnapshot();
|
|
1917
1749
|
const runtimeId = typeof ctx.params?.runtimeId === "string" ? ctx.params.runtimeId : undefined;
|
|
@@ -1939,7 +1771,7 @@ const senpiRuntimePlugin = {
|
|
|
1939
1771
|
const statuses = await collectRuntimeHealthStatuses(runtimeHandles, api.logger);
|
|
1940
1772
|
respond(true, { statuses, updater });
|
|
1941
1773
|
}, { scope: "operator.read" });
|
|
1942
|
-
registerGatewayMethod("senpi.getSystemState", async (ctx) => {
|
|
1774
|
+
api.registerGatewayMethod("senpi.getSystemState", async (ctx) => {
|
|
1943
1775
|
const respond = ctx.respond;
|
|
1944
1776
|
const updater = autoUpdateCoordinator.getSnapshot();
|
|
1945
1777
|
const runtimeId = typeof ctx.params?.runtimeId === "string" ? ctx.params.runtimeId : undefined;
|
|
@@ -1967,36 +1799,6 @@ const senpiRuntimePlugin = {
|
|
|
1967
1799
|
const states = await collectRuntimeSystemStates(runtimeHandles, api.logger, baseStateDir);
|
|
1968
1800
|
respond(true, { states, updater });
|
|
1969
1801
|
}, { scope: "operator.read" });
|
|
1970
|
-
/**
|
|
1971
|
-
* Live telemetry — the one method of the stream, called once per connect.
|
|
1972
|
-
*
|
|
1973
|
-
* It returns the current value of all three broadcast payloads plus the recent record window, so
|
|
1974
|
-
* a client joining a box that has been running for hours renders a full screen immediately
|
|
1975
|
-
* instead of waiting for the next thing to happen. `(afterEpoch, afterSeq)` resumes a client that
|
|
1976
|
-
* already holds part of this epoch's run — a cursor naming any other epoch is dropped, because a
|
|
1977
|
-
* seq from a previous run cannot address these records. `truncated` says when the records between
|
|
1978
|
-
* a cursor of this epoch and the oldest record still held are gone, which nothing in `recent`
|
|
1979
|
-
* alone can express.
|
|
1980
|
-
*
|
|
1981
|
-
* Read-only, like every other inspection method here. The scope that decides who RECEIVES the
|
|
1982
|
-
* broadcasts is a property of the client's own connection, not of this method.
|
|
1983
|
-
*/
|
|
1984
|
-
registerGatewayMethod("senpi.telemetry.subscribe", async (ctx) => {
|
|
1985
|
-
const respond = ctx.respond;
|
|
1986
|
-
try {
|
|
1987
|
-
respond(true, await liveTelemetry.snapshot({
|
|
1988
|
-
afterEpoch: ctx.params?.afterEpoch,
|
|
1989
|
-
afterSeq: ctx.params?.afterSeq,
|
|
1990
|
-
}));
|
|
1991
|
-
}
|
|
1992
|
-
catch (err) {
|
|
1993
|
-
api.logger.warn("[senpi-runtime] telemetry subscribe error", { err });
|
|
1994
|
-
respond(false, undefined, {
|
|
1995
|
-
code: "INTERNAL_ERROR",
|
|
1996
|
-
message: `Failed to build the telemetry snapshot: ${formatGatewayError(err)}`,
|
|
1997
|
-
});
|
|
1998
|
-
}
|
|
1999
|
-
}, { scope: "operator.read" });
|
|
2000
1802
|
/**
|
|
2001
1803
|
* Action layer — read-only inspection.
|
|
2002
1804
|
*
|
|
@@ -2016,7 +1818,7 @@ const senpiRuntimePlugin = {
|
|
|
2016
1818
|
* persisted action-store machinery (`src/actions/store/`) usable
|
|
2017
1819
|
* from the operator-facing CLI again.
|
|
2018
1820
|
*/
|
|
2019
|
-
registerGatewayMethod("senpi.listActions", async (ctx) => {
|
|
1821
|
+
api.registerGatewayMethod("senpi.listActions", async (ctx) => {
|
|
2020
1822
|
const respond = ctx.respond;
|
|
2021
1823
|
const runtimeId = typeof ctx.params?.runtimeId === "string" ? ctx.params.runtimeId : undefined;
|
|
2022
1824
|
const address = typeof ctx.params?.address === "string" ? ctx.params.address : undefined;
|
|
@@ -2046,7 +1848,7 @@ const senpiRuntimePlugin = {
|
|
|
2046
1848
|
}
|
|
2047
1849
|
respond(true, { actions: merged });
|
|
2048
1850
|
}, { scope: "operator.read" });
|
|
2049
|
-
registerGatewayMethod("senpi.getActionState", async (ctx) => {
|
|
1851
|
+
api.registerGatewayMethod("senpi.getActionState", async (ctx) => {
|
|
2050
1852
|
const respond = ctx.respond;
|
|
2051
1853
|
const runtimeId = typeof ctx.params?.runtimeId === "string" ? ctx.params.runtimeId : undefined;
|
|
2052
1854
|
const actionName = typeof ctx.params?.actionName === "string" ? ctx.params.actionName : undefined;
|
|
@@ -2083,7 +1885,7 @@ const senpiRuntimePlugin = {
|
|
|
2083
1885
|
});
|
|
2084
1886
|
}
|
|
2085
1887
|
}, { scope: "operator.read" });
|
|
2086
|
-
registerGatewayMethod("senpi.getActionHistory", async (ctx) => {
|
|
1888
|
+
api.registerGatewayMethod("senpi.getActionHistory", async (ctx) => {
|
|
2087
1889
|
const respond = ctx.respond;
|
|
2088
1890
|
const runtimeId = typeof ctx.params?.runtimeId === "string" ? ctx.params.runtimeId : undefined;
|
|
2089
1891
|
const actionName = typeof ctx.params?.actionName === "string" ? ctx.params.actionName : undefined;
|
|
@@ -2151,7 +1953,7 @@ const senpiRuntimePlugin = {
|
|
|
2151
1953
|
// reachable on HTTP `/audit`. Passes through the caller-controlled subset
|
|
2152
1954
|
// of the audit_query contract; resource scoping (wallet → strategyId) is
|
|
2153
1955
|
// owned by handle.auditQuery, never the caller.
|
|
2154
|
-
registerGatewayMethod("senpi.auditQuery", async (ctx) => {
|
|
1956
|
+
api.registerGatewayMethod("senpi.auditQuery", async (ctx) => {
|
|
2155
1957
|
const respond = ctx.respond;
|
|
2156
1958
|
const runtimeId = typeof ctx.params?.runtimeId === "string" ? ctx.params.runtimeId : undefined;
|
|
2157
1959
|
if (!runtimeId) {
|
|
@@ -2199,7 +2001,7 @@ const senpiRuntimePlugin = {
|
|
|
2199
2001
|
// its state root private, so re-derive it from baseStateDir + the handle's
|
|
2200
2002
|
// wallet (same helper the writer's stateDir was built with); the writer
|
|
2201
2003
|
// nests entries under `<root>/<address>/risk-guard/audit.jsonl`.
|
|
2202
|
-
registerGatewayMethod("senpi.getRiskAudit", async (ctx) => {
|
|
2004
|
+
api.registerGatewayMethod("senpi.getRiskAudit", async (ctx) => {
|
|
2203
2005
|
const respond = ctx.respond;
|
|
2204
2006
|
const runtimeId = typeof ctx.params?.runtimeId === "string" ? ctx.params.runtimeId : undefined;
|
|
2205
2007
|
if (!runtimeId) {
|
|
@@ -2242,7 +2044,7 @@ const senpiRuntimePlugin = {
|
|
|
2242
2044
|
// Per-strategy local domain-event ring (on-disk JSONL) — the trade narrative, queryable locally.
|
|
2243
2045
|
// Same state-root re-derivation as getRiskAudit: the Runtime keeps its root private, so rebuild it
|
|
2244
2046
|
// from baseStateDir + the handle's wallet; the writer nests rows under `<root>/strategies/<address>/events/`.
|
|
2245
|
-
registerGatewayMethod("senpi.getEvents", async (ctx) => {
|
|
2047
|
+
api.registerGatewayMethod("senpi.getEvents", async (ctx) => {
|
|
2246
2048
|
const respond = ctx.respond;
|
|
2247
2049
|
const runtimeId = typeof ctx.params?.runtimeId === "string" ? ctx.params.runtimeId : undefined;
|
|
2248
2050
|
if (!runtimeId) {
|
|
@@ -2299,12 +2101,12 @@ const senpiRuntimePlugin = {
|
|
|
2299
2101
|
}
|
|
2300
2102
|
}, { scope: "operator.read" });
|
|
2301
2103
|
// ─── Skills manager — read + mutate ──────────────────────────────────────
|
|
2302
|
-
registerGatewayMethod("senpi.skills.status", async (ctx) => {
|
|
2104
|
+
api.registerGatewayMethod("senpi.skills.status", async (ctx) => {
|
|
2303
2105
|
const respond = ctx.respond;
|
|
2304
2106
|
const snapshot = skillsCoordinator.getSnapshot();
|
|
2305
2107
|
respond(true, { snapshot });
|
|
2306
2108
|
}, { scope: "operator.read" });
|
|
2307
|
-
registerGatewayMethod("senpi.skills.update", async (ctx) => {
|
|
2109
|
+
api.registerGatewayMethod("senpi.skills.update", async (ctx) => {
|
|
2308
2110
|
const respond = ctx.respond;
|
|
2309
2111
|
const name = typeof ctx.params?.name === "string" ? ctx.params.name.trim() : undefined;
|
|
2310
2112
|
if (!name) {
|
|
@@ -2329,7 +2131,7 @@ const senpiRuntimePlugin = {
|
|
|
2329
2131
|
});
|
|
2330
2132
|
}
|
|
2331
2133
|
}, { scope: "operator.write" });
|
|
2332
|
-
registerGatewayMethod("senpi.skills.updateAll", async (ctx) => {
|
|
2134
|
+
api.registerGatewayMethod("senpi.skills.updateAll", async (ctx) => {
|
|
2333
2135
|
const respond = ctx.respond;
|
|
2334
2136
|
try {
|
|
2335
2137
|
const results = await skillsCoordinator.updateAll();
|