@senpi/runtime 3.0.6-dev.runtime-phase-2.20260630134511 → 3.0.6-dev.runtime-phase-2.20260630134536

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.
Files changed (43) hide show
  1. package/dist/cli/guide-commands.d.ts.map +1 -1
  2. package/dist/cli/guide-commands.js +61 -0
  3. package/dist/cli/guide-commands.js.map +1 -1
  4. package/dist/cli/senpi-commands.d.ts +14 -0
  5. package/dist/cli/senpi-commands.d.ts.map +1 -1
  6. package/dist/cli/senpi-commands.js +386 -2
  7. package/dist/cli/senpi-commands.js.map +1 -1
  8. package/dist/dsl/plugin/index.d.ts.map +1 -1
  9. package/dist/dsl/plugin/index.js +6 -0
  10. package/dist/dsl/plugin/index.js.map +1 -1
  11. package/dist/health/types.d.ts +14 -0
  12. package/dist/health/types.d.ts.map +1 -1
  13. package/dist/health/types.js.map +1 -1
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +183 -2
  16. package/dist/index.js.map +1 -1
  17. package/dist/risk/risk-audit-log.d.ts +7 -0
  18. package/dist/risk/risk-audit-log.d.ts.map +1 -1
  19. package/dist/risk/risk-audit-log.js +48 -1
  20. package/dist/risk/risk-audit-log.js.map +1 -1
  21. package/dist/runtime/runtime.d.ts +2 -0
  22. package/dist/runtime/runtime.d.ts.map +1 -1
  23. package/dist/runtime/runtime.js +17 -3
  24. package/dist/runtime/runtime.js.map +1 -1
  25. package/dist/runtime-api/intake/scanner-registry.d.ts +3 -0
  26. package/dist/runtime-api/intake/scanner-registry.d.ts.map +1 -1
  27. package/dist/runtime-api/intake/scanner-registry.js +3 -0
  28. package/dist/runtime-api/intake/scanner-registry.js.map +1 -1
  29. package/dist/scanners/runtime-module.d.ts.map +1 -1
  30. package/dist/scanners/runtime-module.js +6 -0
  31. package/dist/scanners/runtime-module.js.map +1 -1
  32. package/dist/telemetry/event-store.d.ts +66 -0
  33. package/dist/telemetry/event-store.d.ts.map +1 -0
  34. package/dist/telemetry/event-store.js +202 -0
  35. package/dist/telemetry/event-store.js.map +1 -0
  36. package/dist/utils/logger.d.ts.map +1 -1
  37. package/dist/utils/logger.js +7 -15
  38. package/dist/utils/logger.js.map +1 -1
  39. package/dist/utils/wallet-address.d.ts +3 -0
  40. package/dist/utils/wallet-address.d.ts.map +1 -0
  41. package/dist/utils/wallet-address.js +17 -0
  42. package/dist/utils/wallet-address.js.map +1 -0
  43. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"guide-commands.d.ts","sourceRoot":"","sources":["../../src/cli/guide-commands.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AA0cH,eAAO,MAAM,eAAe,QA2HpB,CAAC;AAIT,kFAAkF;AAClF,UAAU,gBAAgB;IACxB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACvD,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAAC;IAC5C,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC;IAC9D,MAAM,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,gBAAgB,CAAC;CACxF;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,gBAAgB,EACvB,OAAO,EAAE,MAAM,GACd,IAAI,CA2CN"}
1
+ {"version":3,"file":"guide-commands.d.ts","sourceRoot":"","sources":["../../src/cli/guide-commands.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AA6cH,eAAO,MAAM,eAAe,QAqLpB,CAAC;AAIT,kFAAkF;AAClF,UAAU,gBAAgB;IACxB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACvD,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAAC;IAC5C,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC;IAC9D,MAAM,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,gBAAgB,CAAC;CACxF;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,gBAAgB,EACvB,OAAO,EAAE,MAAM,GACd,IAAI,CA2CN"}
@@ -23,6 +23,9 @@ Quick commands:
23
23
  senpi guide scanners Scanner types and config fields
24
24
  senpi guide actions Action types and decision modes
25
25
  senpi guide dsl DSL exit: phases, lock modes, tiers, time-based cuts
26
+ senpi scanner Per-scanner health: runs, errors, liveness, barren detection
27
+ senpi events Local domain-event log — the trade narrative
28
+ senpi explain <asset> Stitch one asset's position lifecycle from the event log
26
29
  senpi dsl positions Active DSL positions (CLI inspection)
27
30
  senpi dsl inspect Full DSL state for one asset
28
31
  senpi dsl closes Archived closes with reason
@@ -485,6 +488,16 @@ senpi runtime — Manage runtimes
485
488
  --address <wallet> Delete by wallet address
486
489
  runtime list List installed runtimes (id, wallet, source, status)
487
490
 
491
+ senpi status — Lightweight runtime health digest
492
+ status Overall health + scanners (with degraded count),
493
+ DSL monitor liveness, risk eligibility + gates
494
+ -r, --runtime <id> Filter by runtime ID
495
+ --json Raw JSON output
496
+ state Full runtime system state — the escape hatch when the
497
+ digest isn't enough (per-component raw state)
498
+ -r, --runtime <id> Filter by runtime ID
499
+ --json Raw JSON output
500
+
488
501
  senpi dsl — Inspect DSL exit engine
489
502
  dsl positions Active DSL-tracked positions
490
503
  -r, --runtime <id> Filter by runtime ID
@@ -520,6 +533,47 @@ senpi action — Action layer (execution history, decisions)
520
533
  -l, --limit <n> Max rows
521
534
  --json Raw JSON output
522
535
 
536
+ senpi risk — Risk eligibility + per-gate status (allowed to trade, and why not)
537
+ risk Eligibility, gate totals, per-gate status/reason/fault
538
+ -r, --runtime <id> Filter by runtime ID
539
+ --json Raw JSON output
540
+ risk audit Gate-check audit log — per-evaluation pass/CLOSED/COOLDOWN history
541
+ -r, --runtime <id> Runtime ID (required)
542
+ -a, --address <addr> Strategy address (defaults to runtime wallet)
543
+ --since <iso> ISO 8601 lower bound on entry time
544
+ -l, --limit <n> Max entries (default 100)
545
+ --json Raw JSON output
546
+
547
+ senpi audit — Backend trade-audit trail (MCP tool calls + AI reasoning)
548
+ audit Tool calls with success, duration, reasoning
549
+ -r, --runtime <id> Runtime ID (required)
550
+ --tool <name> Filter by exact tool name
551
+ --action-type <type> read | create | update | delete
552
+ --success <bool> Filter by success (true|false)
553
+ --since <iso> ISO 8601 lower bound on request time
554
+ --until <iso> ISO 8601 upper bound on request time
555
+ -l, --limit <n> Max rows (default 50)
556
+ --json Raw JSON output
557
+
558
+ senpi events — Local domain-event log (the trade narrative)
559
+ events Position/dsl/order/signal events from the on-disk ring
560
+ -r, --runtime <id> Runtime ID (required)
561
+ -a, --address <addr> Strategy address (defaults to runtime wallet)
562
+ --name <event> Filter by exact event name (e.g. position.opened)
563
+ --asset <symbol> Filter by asset (e.g. BTC)
564
+ --level <level> debug | info | warn | error
565
+ --since <iso> ISO 8601 lower bound on event time
566
+ --until <iso> ISO 8601 upper bound on event time
567
+ -l, --limit <n> Max events (default 200)
568
+ --json Raw JSON output
569
+
570
+ senpi explain — Stitch one asset's position lifecycle (opened → dsl → closed)
571
+ explain <asset> Chronological event narrative for one asset
572
+ -r, --runtime <id> Runtime ID (required)
573
+ -a, --address <addr> Strategy address (defaults to runtime wallet)
574
+ -l, --limit <n> Max events to scan (default 500)
575
+ --json Raw JSON output
576
+
523
577
  senpi guide — In-shell reference
524
578
  guide Overview and quick commands
525
579
  guide scanners Scanner types and config fields
@@ -565,6 +619,13 @@ senpi.listDslArchives
565
619
  closeReason, closedAt, peakROE, currentROE, elapsedMinutes, phase }] }
566
620
  Close reasons: dsl_breach, hard_timeout, weak_peak_cut, dead_weight_cut, exchange_sl_hit, manual
567
621
 
622
+ senpi.getEvents
623
+ Params: runtimeId (string, required), address? (string), name? (string), asset? (string),
624
+ level? ("debug"|"info"|"warn"|"error"), since? (ISO), until? (ISO), limit? (number, default 200)
625
+ Success: { entries: [{ name, level, body, ts, attrs }], address }
626
+ Note: Local on-disk ring at <runtime-state>/strategies/<address>/events/; stores every event's
627
+ body + capped scalars (the redact free-text slot is collector-only).
628
+
568
629
  senpi.listActions
569
630
  Params: runtimeId? (string), address? (string), actionName? (string)
570
631
  Success: { actions: [{ runtimeId, ...ActionLatestState }] }
@@ -1 +1 @@
1
- {"version":3,"file":"guide-commands.js","sourceRoot":"","sources":["../../src/cli/guide-commands.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"guide-commands.js","sourceRoot":"","sources":["../../src/cli/guide-commands.ts"],"names":[],"mappings":"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"}
@@ -2,12 +2,26 @@
2
2
  * OpenClaw CLI commands: openclaw senpi runtime create | list | delete.
3
3
  * Thin layer: all three invoke gateway RPCs only; validation and registry live in the gateway.
4
4
  */
5
+ import type { RiskAuditEntry } from "../risk/risk-audit-log.js";
6
+ import type { StoredEvent } from "../telemetry/event-store.js";
5
7
  /**
6
8
  * Register senpi subcommands on the given Commander program.
7
9
  */
8
10
  export declare function registerSenpiCli(program: {
9
11
  command: (name: string, desc?: string) => CommanderCommand | unknown;
10
12
  }): void;
13
+ /**
14
+ * Render the risk audit log as a tab-separated digest (newest entries last,
15
+ * as returned). Each row: time, source, then `guardrail=result` per
16
+ * evaluation (with the reason appended for non-pass results).
17
+ */
18
+ export declare function renderRiskAuditDigest(entries: RiskAuditEntry[]): string;
19
+ export declare function renderEventsDigest(entries: StoredEvent[]): string;
20
+ /**
21
+ * Stitch an asset's lifecycle: events oldest-first, each line tagged with its position id where one is
22
+ * present, so a reader can follow opened → dsl transitions → close across one or more positions.
23
+ */
24
+ export declare function renderExplain(asset: string, entries: StoredEvent[]): string;
11
25
  /** Minimal Commander command type for subcommands and options. */
12
26
  interface CommanderCommand {
13
27
  command(name: string, desc?: string): CommanderCommand;
@@ -1 +1 @@
1
- {"version":3,"file":"senpi-commands.d.ts","sourceRoot":"","sources":["../../src/cli/senpi-commands.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAkBH;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE;IAAE,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,gBAAgB,GAAG,OAAO,CAAA;CAAE,GAChF,IAAI,CA8+BN;AAoMD,kEAAkE;AAClE,UAAU,gBAAgB;IACxB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACvD,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAAC;IAC5C,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC;IAC/D,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC;IAC9D,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACtE,MAAM,CACJ,EAAE,EACE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,GACzD,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,GACzE,gBAAgB,CAAC;CACrB"}
1
+ {"version":3,"file":"senpi-commands.d.ts","sourceRoot":"","sources":["../../src/cli/senpi-commands.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAgBH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAI/D;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE;IAAE,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,gBAAgB,GAAG,OAAO,CAAA;CAAE,GAChF,IAAI,CAivCN;AA8ID;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,MAAM,CAWvE;AAmDD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM,CASjE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM,CAW3E;AA8HD,kEAAkE;AAClE,UAAU,gBAAgB;IACxB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACvD,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAAC;IAC5C,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC;IAC/D,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC;IAC9D,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACtE,MAAM,CACJ,EAAE,EACE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,GACzD,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,GACzE,gBAAgB,CAAC;CACrB"}
@@ -659,6 +659,236 @@ export function registerSenpiCli(program) {
659
659
  console.log("");
660
660
  }
661
661
  });
662
+ senpi
663
+ .command("scanner")
664
+ .description("Per-scanner supervisor health: runs, errors, liveness, barren detection")
665
+ .option("-r, --runtime <id>", "Filter by runtime id")
666
+ .option("--json", "Print raw JSON from the gateway")
667
+ .action(async (opts) => {
668
+ const params = {};
669
+ if (typeof opts.runtime === "string" && opts.runtime.length > 0)
670
+ params.runtimeId = opts.runtime;
671
+ const data = callGatewayJson("senpi.getSystemState", params);
672
+ if (!data) {
673
+ return;
674
+ }
675
+ if (data.ok === false) {
676
+ const err = data.error;
677
+ console.error(err?.message ?? "Request failed.");
678
+ process.exitCode = 1;
679
+ return;
680
+ }
681
+ const payload = (data.payload ?? data);
682
+ const states = selectMany(payload.state, payload.states ?? []);
683
+ if (opts.json) {
684
+ const scanners = states.map((s) => ({
685
+ runtimeId: s.runtimeId ?? s.runtimeName,
686
+ scanners: s.components?.scanners?.state?.scanners ?? [],
687
+ }));
688
+ console.log(JSON.stringify({ ok: true, scanners }, null, 2));
689
+ return;
690
+ }
691
+ if (states.length === 0) {
692
+ console.log("No running runtime scanners.");
693
+ return;
694
+ }
695
+ for (const state of states) {
696
+ printScanners(state);
697
+ if (states.length > 1)
698
+ console.log("");
699
+ }
700
+ });
701
+ const riskCmd = senpi.command("risk");
702
+ riskCmd
703
+ .description("Risk eligibility + per-gate status — am I allowed to trade, and why not")
704
+ .option("-r, --runtime <id>", "Filter by runtime id")
705
+ .option("--json", "Print raw JSON from the gateway")
706
+ .action(async (opts) => {
707
+ const params = {};
708
+ if (typeof opts.runtime === "string" && opts.runtime.length > 0)
709
+ params.runtimeId = opts.runtime;
710
+ const data = callGatewayJson("senpi.getHealthStatus", params);
711
+ if (!data) {
712
+ return;
713
+ }
714
+ if (data.ok === false) {
715
+ const err = data.error;
716
+ console.error(err?.message ?? "Request failed.");
717
+ process.exitCode = 1;
718
+ return;
719
+ }
720
+ const payload = (data.payload ?? data);
721
+ const statuses = selectMany(payload.status, payload.statuses ?? []);
722
+ if (opts.json) {
723
+ const risk = statuses.map((s) => ({
724
+ runtimeId: s.runtimeId ?? s.runtimeName,
725
+ risk: s.components?.risk ?? null,
726
+ }));
727
+ console.log(JSON.stringify({ ok: true, risk }, null, 2));
728
+ return;
729
+ }
730
+ if (statuses.length === 0) {
731
+ console.log("No running runtime risk status.");
732
+ return;
733
+ }
734
+ for (const status of statuses) {
735
+ printRisk(status);
736
+ if (statuses.length > 1)
737
+ console.log("");
738
+ }
739
+ });
740
+ riskCmd
741
+ .command("audit")
742
+ .description("Risk gate-check audit log — per-evaluation pass/CLOSED/COOLDOWN history")
743
+ .option("-r, --runtime <id>", "Runtime id (required)")
744
+ .option("-a, --address <addr>", "Strategy address (defaults to runtime wallet)")
745
+ .option("--since <iso>", "ISO 8601 lower bound on entry time")
746
+ .option("-l, --limit <n>", "Max entries (default 100)")
747
+ .option("--json", "Print raw JSON from the gateway")
748
+ .action(async (opts) => {
749
+ if (!opts.runtime) {
750
+ console.error("--runtime <id> is required.");
751
+ process.exitCode = 1;
752
+ return;
753
+ }
754
+ const params = { runtimeId: opts.runtime };
755
+ if (opts.address)
756
+ params.address = opts.address;
757
+ const limit = opts.limit ? Number.parseInt(opts.limit, 10) : 100;
758
+ if (Number.isFinite(limit))
759
+ params.limit = limit;
760
+ const data = callGatewayJson("senpi.getRiskAudit", params);
761
+ if (!data) {
762
+ return;
763
+ }
764
+ if (data.ok === false) {
765
+ const err = data.error;
766
+ console.error(err?.message ?? "Request failed.");
767
+ process.exitCode = 1;
768
+ return;
769
+ }
770
+ const inner = (data.payload ?? data);
771
+ let entries = inner.entries ?? [];
772
+ // ISO 8601 UTC timestamps sort lexicographically, so a string compare
773
+ // is a correct lower-bound filter.
774
+ if (opts.since)
775
+ entries = entries.filter((e) => e.ts >= opts.since);
776
+ if (opts.json) {
777
+ console.log(JSON.stringify({ ok: true, entries }, null, 2));
778
+ return;
779
+ }
780
+ console.log(renderRiskAuditDigest(entries));
781
+ });
782
+ senpi
783
+ .command("audit")
784
+ .description("Backend trade-audit trail (MCP tool calls + AI reasoning)")
785
+ .option("-r, --runtime <id>", "Runtime id (required)")
786
+ .option("--tool <name>", "Filter by exact tool name")
787
+ .option("--action-type <type>", "Filter by action type (read|create|update|delete)")
788
+ .option("--success <bool>", "Filter by success (true|false)")
789
+ .option("--since <iso>", "ISO 8601 lower bound on request time")
790
+ .option("--until <iso>", "ISO 8601 upper bound on request time")
791
+ .option("-l, --limit <n>", "Max rows (default 50)")
792
+ .option("--json", "Print raw JSON from the gateway")
793
+ .action(async (opts) => {
794
+ if (!opts.runtime) {
795
+ console.error("--runtime <id> is required.");
796
+ process.exitCode = 1;
797
+ return;
798
+ }
799
+ const params = { runtimeId: opts.runtime };
800
+ if (opts.tool)
801
+ params.tool_name = opts.tool;
802
+ if (opts.actionType)
803
+ params.action_type = opts.actionType;
804
+ if (opts.success === "true")
805
+ params.success = true;
806
+ else if (opts.success === "false")
807
+ params.success = false;
808
+ if (opts.since)
809
+ params.start_time = opts.since;
810
+ if (opts.until)
811
+ params.end_time = opts.until;
812
+ const limit = opts.limit ? Number.parseInt(opts.limit, 10) : 50;
813
+ if (Number.isFinite(limit))
814
+ params.limit = limit;
815
+ const data = callGatewayJson("senpi.auditQuery", params);
816
+ if (!data) {
817
+ return;
818
+ }
819
+ if (data.ok === false) {
820
+ const err = data.error;
821
+ console.error(err?.message ?? "Request failed.");
822
+ process.exitCode = 1;
823
+ return;
824
+ }
825
+ const inner = (data.payload ?? data);
826
+ const result = inner.result ?? { entries: [], count: 0, total: 0, has_more: false };
827
+ if (opts.json) {
828
+ console.log(JSON.stringify({ ok: true, result }, null, 2));
829
+ return;
830
+ }
831
+ if (result.entries.length === 0) {
832
+ console.log("No audit entries.");
833
+ return;
834
+ }
835
+ console.log("Time\tTool\tType\tOK\tDur(ms)\tReasoning");
836
+ for (const e of result.entries) {
837
+ // A malformed backend timestamp makes toISOString() throw RangeError; show a placeholder.
838
+ const parsed = new Date(e.timestamp);
839
+ const t = Number.isNaN(parsed.getTime()) ? "—" : parsed.toISOString().slice(11, 19);
840
+ const dur = e.duration_ms == null ? "—" : String(e.duration_ms);
841
+ const reason = (e.ai_reasoning ?? "").replace(/\s+/g, " ").slice(0, 60);
842
+ console.log([t, e.tool, e.action_type, e.success ? "ok" : "FAIL", dur, reason].join("\t"));
843
+ }
844
+ if (result.has_more) {
845
+ console.log(`… more (showing ${result.count} of ~${result.total}; raise -l or use --json)`);
846
+ }
847
+ });
848
+ senpi
849
+ .command("events")
850
+ .description("Local domain-event log — the trade narrative (position/dsl/order/signal events)")
851
+ .option("-r, --runtime <id>", "Runtime id (required)")
852
+ .option("-a, --address <addr>", "Strategy address (defaults to runtime wallet)")
853
+ .option("--name <event>", "Filter by exact event name (e.g. position.opened)")
854
+ .option("--asset <symbol>", "Filter by asset (e.g. BTC)")
855
+ .option("--level <level>", "Filter by severity (debug|info|warn|error)")
856
+ .option("--since <iso>", "ISO 8601 lower bound on event time")
857
+ .option("--until <iso>", "ISO 8601 upper bound on event time")
858
+ .option("-l, --limit <n>", "Max events (default 200)")
859
+ .option("--json", "Print raw JSON from the gateway")
860
+ .action(async (opts) => {
861
+ const entries = await fetchEvents(opts);
862
+ if (entries === null)
863
+ return;
864
+ if (opts.json) {
865
+ console.log(JSON.stringify({ ok: true, entries }, null, 2));
866
+ return;
867
+ }
868
+ console.log(renderEventsDigest(entries));
869
+ });
870
+ senpi
871
+ .command("explain <asset>")
872
+ .description("Stitch one asset's position lifecycle from the local event log (opened → dsl → closed)")
873
+ .option("-r, --runtime <id>", "Runtime id (required)")
874
+ .option("-a, --address <addr>", "Strategy address (defaults to runtime wallet)")
875
+ .option("-l, --limit <n>", "Max events to scan (default 500)")
876
+ .option("--json", "Print raw JSON from the gateway")
877
+ .action(async (asset, opts) => {
878
+ const entries = await fetchEvents({
879
+ runtime: opts.runtime,
880
+ address: opts.address,
881
+ asset,
882
+ limit: opts.limit ?? "500",
883
+ });
884
+ if (entries === null)
885
+ return;
886
+ if (opts.json) {
887
+ console.log(JSON.stringify({ ok: true, asset, entries }, null, 2));
888
+ return;
889
+ }
890
+ console.log(renderExplain(asset, entries));
891
+ });
662
892
  // ── Skills subcommand ────────────────────────────────────────────────────────
663
893
  const skills = senpi.command("skills");
664
894
  skills.description("Manage Senpi skills (status, update)");
@@ -891,12 +1121,23 @@ function printHealthStatus(status) {
891
1121
  const scannerSummary = scanners?.summary ?? "Scanner summary unavailable.";
892
1122
  const enabled = typeof scanners?.totals?.enabled === "number" ? scanners.totals.enabled : "?";
893
1123
  const registered = typeof scanners?.totals?.registered === "number" ? scanners.totals.registered : "?";
1124
+ const degraded = typeof scanners?.totals?.degraded === "number" ? scanners.totals.degraded : 0;
1125
+ const degradedSuffix = degraded > 0 ? `, ${degraded} degraded` : "";
894
1126
  console.log(`Runtime: ${status.runtimeId ?? status.runtimeName ?? "unknown"}`);
895
1127
  console.log(`Overall Health: ${status.health ?? "unknown"}`);
896
1128
  console.log(`Log Level: ${status.logLevel ?? "unknown"}`);
897
- console.log(`Scanners: ${scannerSummary} (enabled ${enabled}/${registered})`);
1129
+ console.log(`Scanners: ${scannerSummary} (enabled ${enabled}/${registered}${degradedSuffix})`);
898
1130
  if (dsl?.summary) {
899
1131
  console.log(`DSL: ${dsl.summary}`);
1132
+ const monitor = dsl.monitor;
1133
+ if (monitor) {
1134
+ const flight = monitor.inFlight ? " (tick in flight)" : "";
1135
+ const next = monitor.nextTickAt
1136
+ ? `, next tick ${new Date(monitor.nextTickAt).toISOString().slice(11, 19)}`
1137
+ : "";
1138
+ const err = monitor.lastTickError ? ` — last tick error: ${monitor.lastTickError}` : "";
1139
+ console.log(` Monitor: ${monitor.running ? "running" : "stopped"}${flight}${next}${err}`);
1140
+ }
900
1141
  }
901
1142
  if (actions?.summary) {
902
1143
  const ar = typeof actions.totals?.registered === "number" ? actions.totals.registered : "?";
@@ -904,7 +1145,7 @@ function printHealthStatus(status) {
904
1145
  console.log(`Actions: ${actions.summary} (registered ${ar}, ${ae} enabled)`);
905
1146
  }
906
1147
  if (risk && risk.enabled) {
907
- console.log(`Risk Health: ${risk.health}`);
1148
+ console.log(`Risk Eligibility: ${risk.eligibility} | Health: ${risk.health}`);
908
1149
  console.log("Risk Gates:");
909
1150
  for (const gate of risk.gates) {
910
1151
  const label = gate.gateName.padEnd(22);
@@ -913,6 +1154,117 @@ function printHealthStatus(status) {
913
1154
  }
914
1155
  }
915
1156
  }
1157
+ function printRisk(status) {
1158
+ const risk = status.components?.risk;
1159
+ console.log(`Runtime: ${status.runtimeId ?? status.runtimeName ?? "unknown"}`);
1160
+ if (!risk || !risk.enabled) {
1161
+ console.log("Risk guardrails: disabled.");
1162
+ return;
1163
+ }
1164
+ console.log(`Eligibility: ${risk.eligibility} | Health: ${risk.health}`);
1165
+ const t = risk.totals;
1166
+ console.log(`Gates: ${t.open} open, ${t.cooldown} cooldown, ${t.closed} closed (${t.fallbackCount} fallback, ${t.failedCount} failed)`);
1167
+ for (const g of risk.gates) {
1168
+ const label = g.gateName.padEnd(22);
1169
+ const reason = g.reason && g.status !== "OPEN" ? ` — ${g.reason}` : "";
1170
+ // Surface evaluation faults the status summary hides: a gate that errored
1171
+ // and the fallback it fell back to.
1172
+ const flag = !g.evaluationOk ? ` [${g.failureKind}${g.fallbackApplied ? ",fallback" : ""}]` : "";
1173
+ console.log(` ${label}${g.status}${reason}${flag}`);
1174
+ }
1175
+ }
1176
+ /**
1177
+ * Render the risk audit log as a tab-separated digest (newest entries last,
1178
+ * as returned). Each row: time, source, then `guardrail=result` per
1179
+ * evaluation (with the reason appended for non-pass results).
1180
+ */
1181
+ export function renderRiskAuditDigest(entries) {
1182
+ if (entries.length === 0)
1183
+ return "No risk audit.";
1184
+ const lines = ["Time\tSource\tEvaluations"];
1185
+ for (const e of entries) {
1186
+ const t = new Date(e.ts).toISOString().slice(11, 19);
1187
+ const evals = (e.evaluations ?? [])
1188
+ .map((ev) => `${ev.guardrail}=${ev.result}${ev.reason && ev.result !== "pass" ? `(${ev.reason})` : ""}`)
1189
+ .join(" ");
1190
+ lines.push([t, e.source, evals || "—"].join("\t"));
1191
+ }
1192
+ return lines.join("\n");
1193
+ }
1194
+ /**
1195
+ * Shared fetch for `senpi events` / `senpi explain`: validate --runtime, call senpi.getEvents, and
1196
+ * return the entries. Returns `null` (and sets exitCode/prints) on a missing runtime, transport
1197
+ * failure, or a gateway error — the caller stops.
1198
+ */
1199
+ function fetchEvents(opts) {
1200
+ if (!opts.runtime) {
1201
+ console.error("--runtime <id> is required.");
1202
+ process.exitCode = 1;
1203
+ return null;
1204
+ }
1205
+ const params = { runtimeId: opts.runtime };
1206
+ if (opts.address)
1207
+ params.address = opts.address;
1208
+ if (opts.name)
1209
+ params.name = opts.name;
1210
+ if (opts.asset)
1211
+ params.asset = opts.asset;
1212
+ if (opts.level)
1213
+ params.level = opts.level;
1214
+ if (opts.since)
1215
+ params.since = opts.since;
1216
+ if (opts.until)
1217
+ params.until = opts.until;
1218
+ if (opts.limit) {
1219
+ const limit = Number.parseInt(opts.limit, 10);
1220
+ if (Number.isFinite(limit))
1221
+ params.limit = limit;
1222
+ }
1223
+ const data = callGatewayJson("senpi.getEvents", params);
1224
+ if (!data)
1225
+ return null;
1226
+ if (data.ok === false) {
1227
+ const err = data.error;
1228
+ console.error(err?.message ?? "Request failed.");
1229
+ process.exitCode = 1;
1230
+ return null;
1231
+ }
1232
+ const inner = (data.payload ?? data);
1233
+ return inner.entries ?? [];
1234
+ }
1235
+ /** The asset an event concerns, if any (position/dsl carry `senpi.asset`; signals carry `senpi.signal.asset`). */
1236
+ function eventAsset(e) {
1237
+ const a = e.attrs?.["senpi.asset"] ?? e.attrs?.["senpi.signal.asset"];
1238
+ return typeof a === "string" ? a : undefined;
1239
+ }
1240
+ export function renderEventsDigest(entries) {
1241
+ if (entries.length === 0)
1242
+ return "No events.";
1243
+ const lines = ["Time\tLevel\tEvent\tAsset\tDetail"];
1244
+ for (const e of entries) {
1245
+ const t = new Date(e.ts).toISOString().slice(11, 19);
1246
+ const detail = (e.body ?? "").replace(/\s+/g, " ").slice(0, 60);
1247
+ lines.push([t, e.level, e.name, eventAsset(e) ?? "—", detail].join("\t"));
1248
+ }
1249
+ return lines.join("\n");
1250
+ }
1251
+ /**
1252
+ * Stitch an asset's lifecycle: events oldest-first, each line tagged with its position id where one is
1253
+ * present, so a reader can follow opened → dsl transitions → close across one or more positions.
1254
+ */
1255
+ export function renderExplain(asset, entries) {
1256
+ if (entries.length === 0)
1257
+ return `No events for ${asset}.`;
1258
+ const lines = [`${asset} — ${entries.length} event(s)`];
1259
+ for (const e of entries) {
1260
+ const t = new Date(e.ts).toISOString().slice(11, 19);
1261
+ const pos = typeof e.attrs?.["senpi.position.id"] === "string" ? e.attrs["senpi.position.id"] : undefined;
1262
+ const tag = pos ? ` [pos ${truncateAddr(String(pos))}]` : "";
1263
+ const detail = (e.body ?? "").replace(/\s+/g, " ");
1264
+ lines.push(` ${t} ${e.name}\t${detail}${tag}`);
1265
+ }
1266
+ return lines.join("\n");
1267
+ }
916
1268
  function printSystemState(state) {
917
1269
  const scanners = state.components?.scanners?.state;
918
1270
  const dsl = state.components?.dsl;
@@ -983,4 +1335,36 @@ function printSystemState(state) {
983
1335
  }
984
1336
  }
985
1337
  }
1338
+ function printScanners(state) {
1339
+ const rows = state.components?.scanners?.state?.scanners ?? [];
1340
+ console.log(`Runtime: ${state.runtimeId ?? state.runtimeName ?? "unknown"}`);
1341
+ console.log(`Scanners: ${rows.length}`);
1342
+ for (const s of rows) {
1343
+ // Barren = wired and running but never emitted a signal — a real "alive but producing nothing" gap.
1344
+ const barren = s.health !== "disabled" && (s.runCount ?? 0) > 0 && (s.signalsProduced ?? 0) === 0;
1345
+ // Liveness clock is external-only: n/a for interval scanners, — for an external one not yet heard from.
1346
+ const alive = s.lastAliveAt != null
1347
+ ? String(s.lastAliveAt)
1348
+ : s.scheduleMode === "external"
1349
+ ? "—"
1350
+ : "n/a";
1351
+ console.log([
1352
+ " scanner",
1353
+ s.scannerId ?? "—",
1354
+ `mode=${s.scheduleMode ?? "—"}`,
1355
+ `health=${s.health ?? "unknown"}`,
1356
+ `enabled=${String(s.enabled ?? false)}`,
1357
+ `inFlight=${String(s.inFlight ?? false)}`,
1358
+ `runs=${s.runCount ?? 0}`,
1359
+ `errors=${s.errorCount ?? 0}`,
1360
+ `consec_errors=${s.consecutiveErrorCount ?? 0}`,
1361
+ `signals=${s.signalsProduced ?? 0}`,
1362
+ `alive=${alive}`,
1363
+ `next=${s.nextRunAt == null ? "—" : String(s.nextRunAt)}`,
1364
+ `last=${s.lastRunStatus ?? "—"}`,
1365
+ ...(s.lastRunReason ? [`reason=${s.lastRunReason}`] : []),
1366
+ ...(barren ? ["BARREN"] : []),
1367
+ ].join(" "));
1368
+ }
1369
+ }
986
1370
  //# sourceMappingURL=senpi-commands.js.map