@senpi/runtime 3.0.135 → 3.0.139

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 (293) hide show
  1. package/dist/actions/action-events.d.ts +7 -21
  2. package/dist/actions/action-events.d.ts.map +1 -1
  3. package/dist/actions/action-events.js +26 -54
  4. package/dist/actions/action-events.js.map +1 -1
  5. package/dist/actions/action-runtime-module.d.ts.map +1 -1
  6. package/dist/actions/action-runtime-module.js +7 -38
  7. package/dist/actions/action-runtime-module.js.map +1 -1
  8. package/dist/actions/close-position/close-position.action.d.ts.map +1 -1
  9. package/dist/actions/close-position/close-position.action.js +15 -122
  10. package/dist/actions/close-position/close-position.action.js.map +1 -1
  11. package/dist/actions/decision-engine.d.ts.map +1 -1
  12. package/dist/actions/decision-engine.js +2 -15
  13. package/dist/actions/decision-engine.js.map +1 -1
  14. package/dist/actions/event-derivation.d.ts +2 -71
  15. package/dist/actions/event-derivation.d.ts.map +1 -1
  16. package/dist/actions/event-derivation.js +8 -251
  17. package/dist/actions/event-derivation.js.map +1 -1
  18. package/dist/actions/open-position/open-position.action.d.ts +2 -12
  19. package/dist/actions/open-position/open-position.action.d.ts.map +1 -1
  20. package/dist/actions/open-position/open-position.action.js +41 -141
  21. package/dist/actions/open-position/open-position.action.js.map +1 -1
  22. package/dist/actions/position-tracker/position-tracker.action.d.ts +1 -2
  23. package/dist/actions/position-tracker/position-tracker.action.d.ts.map +1 -1
  24. package/dist/actions/position-tracker/position-tracker.action.js +17 -62
  25. package/dist/actions/position-tracker/position-tracker.action.js.map +1 -1
  26. package/dist/actions/store/types.d.ts +2 -9
  27. package/dist/actions/store/types.d.ts.map +1 -1
  28. package/dist/actions/store/types.js.map +1 -1
  29. package/dist/actions/types.d.ts +0 -13
  30. package/dist/actions/types.d.ts.map +1 -1
  31. package/dist/actions/types.js +0 -13
  32. package/dist/actions/types.js.map +1 -1
  33. package/dist/cli/guide-commands.d.ts.map +1 -1
  34. package/dist/cli/guide-commands.js +7 -4
  35. package/dist/cli/guide-commands.js.map +1 -1
  36. package/dist/constants/dsl/index.d.ts +0 -6
  37. package/dist/constants/dsl/index.d.ts.map +1 -1
  38. package/dist/constants/dsl/index.js +0 -6
  39. package/dist/constants/dsl/index.js.map +1 -1
  40. package/dist/constants/telemetry.d.ts +15 -0
  41. package/dist/constants/telemetry.d.ts.map +1 -0
  42. package/dist/constants/telemetry.js +28 -0
  43. package/dist/constants/telemetry.js.map +1 -0
  44. package/dist/dsl/engine-client/event-mapping.d.ts.map +1 -1
  45. package/dist/dsl/engine-client/event-mapping.js +0 -14
  46. package/dist/dsl/engine-client/event-mapping.js.map +1 -1
  47. package/dist/dsl/events/build-closed-event.d.ts +1 -16
  48. package/dist/dsl/events/build-closed-event.d.ts.map +1 -1
  49. package/dist/dsl/events/build-closed-event.js +0 -6
  50. package/dist/dsl/events/build-closed-event.js.map +1 -1
  51. package/dist/dsl/events/handlers.d.ts +0 -7
  52. package/dist/dsl/events/handlers.d.ts.map +1 -1
  53. package/dist/dsl/events/handlers.js +7 -37
  54. package/dist/dsl/events/handlers.js.map +1 -1
  55. package/dist/dsl/monitor/create-monitor.d.ts +2 -6
  56. package/dist/dsl/monitor/create-monitor.d.ts.map +1 -1
  57. package/dist/dsl/monitor/create-monitor.js +9 -82
  58. package/dist/dsl/monitor/create-monitor.js.map +1 -1
  59. package/dist/dsl/monitor/dsl-failure-events.d.ts +2 -45
  60. package/dist/dsl/monitor/dsl-failure-events.d.ts.map +1 -1
  61. package/dist/dsl/monitor/dsl-failure-events.js +3 -52
  62. package/dist/dsl/monitor/dsl-failure-events.js.map +1 -1
  63. package/dist/dsl/monitor/process-one-position.d.ts +0 -1
  64. package/dist/dsl/monitor/process-one-position.d.ts.map +1 -1
  65. package/dist/dsl/monitor/process-one-position.js +36 -159
  66. package/dist/dsl/monitor/process-one-position.js.map +1 -1
  67. package/dist/dsl/plugin/index.d.ts +2 -8
  68. package/dist/dsl/plugin/index.d.ts.map +1 -1
  69. package/dist/dsl/plugin/index.js +8 -20
  70. package/dist/dsl/plugin/index.js.map +1 -1
  71. package/dist/health/types.d.ts +0 -13
  72. package/dist/health/types.d.ts.map +1 -1
  73. package/dist/health/types.js +0 -12
  74. package/dist/health/types.js.map +1 -1
  75. package/dist/index.d.ts +8 -27
  76. package/dist/index.d.ts.map +1 -1
  77. package/dist/index.js +105 -272
  78. package/dist/index.js.map +1 -1
  79. package/dist/runtime/action-registry.d.ts.map +1 -1
  80. package/dist/runtime/action-registry.js +3 -4
  81. package/dist/runtime/action-registry.js.map +1 -1
  82. package/dist/runtime/domain-events.d.ts.map +1 -1
  83. package/dist/runtime/domain-events.js +0 -7
  84. package/dist/runtime/domain-events.js.map +1 -1
  85. package/dist/runtime/events-telemetry.d.ts +96 -0
  86. package/dist/runtime/events-telemetry.d.ts.map +1 -0
  87. package/dist/runtime/events-telemetry.js +232 -0
  88. package/dist/runtime/events-telemetry.js.map +1 -0
  89. package/dist/runtime/lifecycle-events.d.ts +3 -15
  90. package/dist/runtime/lifecycle-events.d.ts.map +1 -1
  91. package/dist/runtime/lifecycle-events.js +3 -17
  92. package/dist/runtime/lifecycle-events.js.map +1 -1
  93. package/dist/runtime/lifecycle-reaper.d.ts +6 -4
  94. package/dist/runtime/lifecycle-reaper.d.ts.map +1 -1
  95. package/dist/runtime/lifecycle-reaper.js +6 -4
  96. package/dist/runtime/lifecycle-reaper.js.map +1 -1
  97. package/dist/runtime/reconcile-run.d.ts +3 -13
  98. package/dist/runtime/reconcile-run.d.ts.map +1 -1
  99. package/dist/runtime/reconcile-run.js +3 -4
  100. package/dist/runtime/reconcile-run.js.map +1 -1
  101. package/dist/runtime/reconcile-state.d.ts +0 -8
  102. package/dist/runtime/reconcile-state.d.ts.map +1 -1
  103. package/dist/runtime/reconcile-state.js +1 -4
  104. package/dist/runtime/reconcile-state.js.map +1 -1
  105. package/dist/runtime/risk-guard.d.ts +20 -1
  106. package/dist/runtime/risk-guard.d.ts.map +1 -1
  107. package/dist/runtime/risk-guard.js +47 -6
  108. package/dist/runtime/risk-guard.js.map +1 -1
  109. package/dist/runtime/run.d.ts +7 -1
  110. package/dist/runtime/run.d.ts.map +1 -1
  111. package/dist/runtime/run.js +7 -0
  112. package/dist/runtime/run.js.map +1 -1
  113. package/dist/runtime/runtime-schema.js +3 -3
  114. package/dist/runtime/runtime-schema.js.map +1 -1
  115. package/dist/runtime/runtime.d.ts +22 -2
  116. package/dist/runtime/runtime.d.ts.map +1 -1
  117. package/dist/runtime/runtime.js +74 -39
  118. package/dist/runtime/runtime.js.map +1 -1
  119. package/dist/runtime/strategies-store.d.ts +26 -0
  120. package/dist/runtime/strategies-store.d.ts.map +1 -0
  121. package/dist/runtime/strategies-store.js +47 -0
  122. package/dist/runtime/strategies-store.js.map +1 -0
  123. package/dist/runtime/strategies-telemetry.d.ts +91 -0
  124. package/dist/runtime/strategies-telemetry.d.ts.map +1 -0
  125. package/dist/runtime/strategies-telemetry.js +128 -0
  126. package/dist/runtime/strategies-telemetry.js.map +1 -0
  127. package/dist/runtime/strategy-lifecycle.d.ts +108 -2
  128. package/dist/runtime/strategy-lifecycle.d.ts.map +1 -1
  129. package/dist/runtime/strategy-lifecycle.js +325 -4
  130. package/dist/runtime/strategy-lifecycle.js.map +1 -1
  131. package/dist/runtime/supervisor/long-running-supervisor.d.ts +0 -13
  132. package/dist/runtime/supervisor/long-running-supervisor.d.ts.map +1 -1
  133. package/dist/runtime/supervisor/long-running-supervisor.js +0 -1
  134. package/dist/runtime/supervisor/long-running-supervisor.js.map +1 -1
  135. package/dist/runtime/validate-dsl-position-tracking.d.ts.map +1 -1
  136. package/dist/runtime/validate-dsl-position-tracking.js +1 -2
  137. package/dist/runtime/validate-dsl-position-tracking.js.map +1 -1
  138. package/dist/runtime-api/handlers/ingest-signals.d.ts.map +1 -1
  139. package/dist/runtime-api/handlers/ingest-signals.js +0 -1
  140. package/dist/runtime-api/handlers/ingest-signals.js.map +1 -1
  141. package/dist/runtime-api/handlers/types.d.ts +0 -5
  142. package/dist/runtime-api/handlers/types.d.ts.map +1 -1
  143. package/dist/runtime-api/intake/intake-events.d.ts +1 -1
  144. package/dist/runtime-api/intake/intake-events.d.ts.map +1 -1
  145. package/dist/runtime-api/intake/intake-events.js +3 -9
  146. package/dist/runtime-api/intake/intake-events.js.map +1 -1
  147. package/dist/runtime-api/intake/intake-mount.d.ts +2 -0
  148. package/dist/runtime-api/intake/intake-mount.d.ts.map +1 -1
  149. package/dist/runtime-api/intake/intake-mount.js +25 -7
  150. package/dist/runtime-api/intake/intake-mount.js.map +1 -1
  151. package/dist/runtime-api/intake/process-error-post.d.ts +1 -6
  152. package/dist/runtime-api/intake/process-error-post.d.ts.map +1 -1
  153. package/dist/runtime-api/intake/process-error-post.js +1 -5
  154. package/dist/runtime-api/intake/process-error-post.js.map +1 -1
  155. package/dist/runtime-api/intake/process-signal-post.d.ts +1 -7
  156. package/dist/runtime-api/intake/process-signal-post.d.ts.map +1 -1
  157. package/dist/runtime-api/intake/process-signal-post.js +0 -5
  158. package/dist/runtime-api/intake/process-signal-post.js.map +1 -1
  159. package/dist/runtime-api/intake/scaffold-error-router.js.map +1 -1
  160. package/dist/runtime-api/intake/scanner-launcher.d.ts.map +1 -1
  161. package/dist/runtime-api/intake/scanner-launcher.js +0 -15
  162. package/dist/runtime-api/intake/scanner-launcher.js.map +1 -1
  163. package/dist/runtime-api/intake/types.d.ts +0 -55
  164. package/dist/runtime-api/intake/types.d.ts.map +1 -1
  165. package/dist/runtime-api/routes/signals.d.ts +0 -2
  166. package/dist/runtime-api/routes/signals.d.ts.map +1 -1
  167. package/dist/runtime-api/routes/signals.js +11 -5
  168. package/dist/runtime-api/routes/signals.js.map +1 -1
  169. package/dist/runtime-api/routes/signals.schema.d.ts +0 -43
  170. package/dist/runtime-api/routes/signals.schema.d.ts.map +1 -1
  171. package/dist/runtime-api/routes/signals.schema.js +0 -43
  172. package/dist/runtime-api/routes/signals.schema.js.map +1 -1
  173. package/dist/runtime-api/server.d.ts +1 -7
  174. package/dist/runtime-api/server.d.ts.map +1 -1
  175. package/dist/runtime-api/server.js +0 -1
  176. package/dist/runtime-api/server.js.map +1 -1
  177. package/dist/scanners/engine/engine.d.ts +1 -22
  178. package/dist/scanners/engine/engine.d.ts.map +1 -1
  179. package/dist/scanners/engine/engine.js +11 -78
  180. package/dist/scanners/engine/engine.js.map +1 -1
  181. package/dist/scanners/engine/lifecycle.d.ts +1 -7
  182. package/dist/scanners/engine/lifecycle.d.ts.map +1 -1
  183. package/dist/scanners/events.d.ts +0 -4
  184. package/dist/scanners/events.d.ts.map +1 -1
  185. package/dist/scanners/events.js +0 -2
  186. package/dist/scanners/events.js.map +1 -1
  187. package/dist/scanners/external/scaffold/delivery.py +25 -194
  188. package/dist/scanners/external/scaffold/scaffold.py +31 -172
  189. package/dist/scanners/external/scaffold/senpi_mcp.py +8 -150
  190. package/dist/scanners/external-scanner-receiver.d.ts +0 -17
  191. package/dist/scanners/external-scanner-receiver.d.ts.map +1 -1
  192. package/dist/scanners/external-scanner-receiver.js +0 -8
  193. package/dist/scanners/external-scanner-receiver.js.map +1 -1
  194. package/dist/scanners/runtime-module.d.ts +0 -1
  195. package/dist/scanners/runtime-module.d.ts.map +1 -1
  196. package/dist/scanners/runtime-module.js +9 -66
  197. package/dist/scanners/runtime-module.js.map +1 -1
  198. package/dist/state/state-manager.d.ts +2 -0
  199. package/dist/state/state-manager.d.ts.map +1 -1
  200. package/dist/state/state-manager.js +8 -0
  201. package/dist/state/state-manager.js.map +1 -1
  202. package/dist/telemetry/attributes.d.ts +0 -20
  203. package/dist/telemetry/attributes.d.ts.map +1 -1
  204. package/dist/telemetry/attributes.js +0 -24
  205. package/dist/telemetry/attributes.js.map +1 -1
  206. package/dist/telemetry/event-builders.d.ts +6 -81
  207. package/dist/telemetry/event-builders.d.ts.map +1 -1
  208. package/dist/telemetry/event-builders.js +17 -141
  209. package/dist/telemetry/event-builders.js.map +1 -1
  210. package/dist/telemetry/event-store.d.ts.map +1 -1
  211. package/dist/telemetry/event-store.js +2 -6
  212. package/dist/telemetry/event-store.js.map +1 -1
  213. package/dist/telemetry/metrics.d.ts +2 -14
  214. package/dist/telemetry/metrics.d.ts.map +1 -1
  215. package/dist/telemetry/metrics.js +4 -19
  216. package/dist/telemetry/metrics.js.map +1 -1
  217. package/dist/telemetry/spans/redact-pii.d.ts.map +1 -1
  218. package/dist/telemetry/spans/redact-pii.js +11 -16
  219. package/dist/telemetry/spans/redact-pii.js.map +1 -1
  220. package/dist/telemetry/tracing.d.ts +0 -9
  221. package/dist/telemetry/tracing.d.ts.map +1 -1
  222. package/dist/telemetry/tracing.js +0 -36
  223. package/dist/telemetry/tracing.js.map +1 -1
  224. package/dist/types/dsl/index.d.ts +0 -48
  225. package/dist/types/dsl/index.d.ts.map +1 -1
  226. package/dist/types/scanner.d.ts +0 -15
  227. package/dist/types/scanner.d.ts.map +1 -1
  228. package/dist/utils/event-catalog.d.ts +0 -202
  229. package/dist/utils/event-catalog.d.ts.map +1 -1
  230. package/dist/utils/event-catalog.js +0 -26
  231. package/dist/utils/event-catalog.js.map +1 -1
  232. package/dist/utils/logger.d.ts +1 -4
  233. package/dist/utils/logger.d.ts.map +1 -1
  234. package/dist/utils/logger.js.map +1 -1
  235. package/dist/validate/recipe-checks.d.ts.map +1 -1
  236. package/dist/validate/recipe-checks.js +2 -2
  237. package/dist/validate/recipe-checks.js.map +1 -1
  238. package/openclaw.plugin.json +1 -1
  239. package/package.json +1 -1
  240. package/dist/actions/skipped-signal-results.d.ts +0 -25
  241. package/dist/actions/skipped-signal-results.d.ts.map +0 -1
  242. package/dist/actions/skipped-signal-results.js +0 -71
  243. package/dist/actions/skipped-signal-results.js.map +0 -1
  244. package/dist/runtime-api/intake/ingest-request.d.ts +0 -17
  245. package/dist/runtime-api/intake/ingest-request.d.ts.map +0 -1
  246. package/dist/runtime-api/intake/ingest-request.js +0 -34
  247. package/dist/runtime-api/intake/ingest-request.js.map +0 -1
  248. package/dist/runtime-api/intake/scaffold-tick-router.d.ts +0 -39
  249. package/dist/runtime-api/intake/scaffold-tick-router.d.ts.map +0 -1
  250. package/dist/runtime-api/intake/scaffold-tick-router.js +0 -122
  251. package/dist/runtime-api/intake/scaffold-tick-router.js.map +0 -1
  252. package/dist/scanners/external/scaffold/tick_facts.py +0 -130
  253. package/dist/scanners/external/scaffold/ulid.py +0 -58
  254. package/dist/telemetry/dsl-positions.d.ts +0 -111
  255. package/dist/telemetry/dsl-positions.d.ts.map +0 -1
  256. package/dist/telemetry/dsl-positions.js +0 -118
  257. package/dist/telemetry/dsl-positions.js.map +0 -1
  258. package/dist/telemetry/live-telemetry.d.ts +0 -257
  259. package/dist/telemetry/live-telemetry.d.ts.map +0 -1
  260. package/dist/telemetry/live-telemetry.js +0 -959
  261. package/dist/telemetry/live-telemetry.js.map +0 -1
  262. package/dist/telemetry/scanner-stats.d.ts +0 -143
  263. package/dist/telemetry/scanner-stats.d.ts.map +0 -1
  264. package/dist/telemetry/scanner-stats.js +0 -426
  265. package/dist/telemetry/scanner-stats.js.map +0 -1
  266. package/dist/telemetry/scanner-tick-feed.d.ts +0 -87
  267. package/dist/telemetry/scanner-tick-feed.d.ts.map +0 -1
  268. package/dist/telemetry/scanner-tick-feed.js +0 -48
  269. package/dist/telemetry/scanner-tick-feed.js.map +0 -1
  270. package/dist/telemetry/strategy-topology.d.ts +0 -99
  271. package/dist/telemetry/strategy-topology.d.ts.map +0 -1
  272. package/dist/telemetry/strategy-topology.js +0 -93
  273. package/dist/telemetry/strategy-topology.js.map +0 -1
  274. package/dist/telemetry/telemetry-publisher.d.ts +0 -83
  275. package/dist/telemetry/telemetry-publisher.d.ts.map +0 -1
  276. package/dist/telemetry/telemetry-publisher.js +0 -256
  277. package/dist/telemetry/telemetry-publisher.js.map +0 -1
  278. package/dist/telemetry/tick-frame.d.ts +0 -212
  279. package/dist/telemetry/tick-frame.d.ts.map +0 -1
  280. package/dist/telemetry/tick-frame.js +0 -421
  281. package/dist/telemetry/tick-frame.js.map +0 -1
  282. package/dist/telemetry/timeline-buffer.d.ts +0 -95
  283. package/dist/telemetry/timeline-buffer.d.ts.map +0 -1
  284. package/dist/telemetry/timeline-buffer.js +0 -237
  285. package/dist/telemetry/timeline-buffer.js.map +0 -1
  286. package/dist/utils/telemetry-required-log.d.ts +0 -60
  287. package/dist/utils/telemetry-required-log.d.ts.map +0 -1
  288. package/dist/utils/telemetry-required-log.js +0 -105
  289. package/dist/utils/telemetry-required-log.js.map +0 -1
  290. package/dist/utils/ulid.d.ts +0 -9
  291. package/dist/utils/ulid.d.ts.map +0 -1
  292. package/dist/utils/ulid.js +0 -43
  293. package/dist/utils/ulid.js.map +0 -1
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Strategies telemetry: the payload built from the strategies store, and the loop that broadcasts
3
+ * that payload as `plugin.senpi.strategies`.
4
+ */
5
+ import type { DslState } from "../types/dsl/index.js";
6
+ import type { StrategyRecord } from "./strategies-store.js";
7
+ /** Minted once per plugin process. `plugin.senpi.events` carries the same value. */
8
+ export declare const PROCESS_EPOCH: `${string}-${string}-${string}-${string}-${string}`;
9
+ export interface StrategyScannerPayload {
10
+ scannerId: string;
11
+ intervalSeconds: number;
12
+ lastAliveAt: number | null;
13
+ }
14
+ export interface StrategyDslTierPayload {
15
+ triggerPct: number;
16
+ lockHwPct: number;
17
+ triggerPrice: number;
18
+ reached: boolean;
19
+ }
20
+ export interface StrategyDslPayload {
21
+ asset: string;
22
+ dex: string;
23
+ direction: "LONG" | "SHORT";
24
+ entryPrice: number;
25
+ leverage: number;
26
+ phase: 1 | 2;
27
+ firstStopLoss: number;
28
+ lastPrice: number;
29
+ lastPriceAt: number | null;
30
+ floorPrice: number;
31
+ currentTierIndex: number | null;
32
+ tierSince: number | null;
33
+ tiers: StrategyDslTierPayload[];
34
+ }
35
+ export interface StrategyPayload {
36
+ address: string;
37
+ name: string;
38
+ scanners: StrategyScannerPayload[];
39
+ dsl: StrategyDslPayload[];
40
+ }
41
+ export interface StrategiesPayload {
42
+ v: 1;
43
+ epoch: string;
44
+ generatedAt: number;
45
+ strategies: StrategyPayload[];
46
+ }
47
+ /** Liveness of one external scanner, epoch ms, or `null` when nothing was heard since the child (re)started. */
48
+ export type LastAliveAtFn = (runtimeId: string, scannerName: string) => number | null;
49
+ /** Active DSL states of one runtime, read from memory. `[]` when the runtime has no handle or no DSL. */
50
+ export type DslStatesFn = (runtimeId: string) => readonly DslState[];
51
+ export type StrategiesBroadcastFn = (event: string, payload: unknown, opts?: {
52
+ dropIfSlow?: boolean;
53
+ }) => void;
54
+ /**
55
+ * Builds the payload from the store and the DSL states. Copies only the payload fields from each
56
+ * DSL state. A runtime's state manager loads every address directory under its state directory.
57
+ * Only DSL states with a string `address` equal to the strategy wallet are kept.
58
+ */
59
+ export declare function buildStrategiesPayload(input: {
60
+ epoch: string;
61
+ generatedAt: number;
62
+ store: ReadonlyMap<string, StrategyRecord>;
63
+ lastAliveAt: LastAliveAtFn;
64
+ dslStates: DslStatesFn;
65
+ /** Called with the runtime id when reading or copying that runtime's DSL states throws. */
66
+ onDslError?: (runtimeId: string, err: unknown) => void;
67
+ }): StrategiesPayload;
68
+ export interface StrategiesPublisher {
69
+ /** Ticks once, then every interval. A second call while running does nothing. */
70
+ start(): void;
71
+ /** Stops the ticks and resets the last payload to `strategies: []`. */
72
+ stop(): void;
73
+ /** The payload of the last tick. Before the first tick and after stop: `strategies: []`. */
74
+ lastPayload(): StrategiesPayload;
75
+ }
76
+ /**
77
+ * Each tick builds the payload from the store, the liveness reader and the DSL state reader, keeps
78
+ * it as the last payload, and broadcasts it when a broadcast function is available. The loop reads
79
+ * the store and never writes it.
80
+ */
81
+ export declare function createStrategiesPublisher(deps: {
82
+ store: ReadonlyMap<string, StrategyRecord>;
83
+ lastAliveAt: LastAliveAtFn;
84
+ dslStates: DslStatesFn;
85
+ getBroadcast: () => StrategiesBroadcastFn | undefined;
86
+ onError?: (err: unknown) => void;
87
+ onDslError?: (runtimeId: string, err: unknown) => void;
88
+ epoch?: string;
89
+ now?: () => number;
90
+ }): StrategiesPublisher;
91
+ //# sourceMappingURL=strategies-telemetry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strategies-telemetry.d.ts","sourceRoot":"","sources":["../../src/runtime/strategies-telemetry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Strategies telemetry: the payload built from the strategies store, and the loop that broadcasts
3
+ * that payload as `plugin.senpi.strategies`.
4
+ */
5
+ import { randomUUID } from "node:crypto";
6
+ import { STRATEGIES_EVENT_NAME, STRATEGIES_PUBLISH_INTERVAL_MS } from "../constants/telemetry.js";
7
+ /** Minted once per plugin process. `plugin.senpi.events` carries the same value. */
8
+ export const PROCESS_EPOCH = randomUUID();
9
+ function normalizeAddress(address) {
10
+ return address.trim().toLowerCase();
11
+ }
12
+ /** Epoch ms of an ISO string, or `null` when it does not parse. */
13
+ function epochMsOrNull(iso) {
14
+ const ms = Date.parse(iso);
15
+ return Number.isNaN(ms) ? null : ms;
16
+ }
17
+ /**
18
+ * Copies the payload fields of one DSL state into new objects.
19
+ *
20
+ * `triggerPrice` solves the move check of `tierIndexFromPrice` (`src/dsl/engine/floors.ts`) for
21
+ * equality: the price move from entry, times leverage, in percent, equals `triggerPct`. In floating
22
+ * point, `tierIndexFromPrice` at exactly `triggerPrice` can compute a move a few ulps below
23
+ * `triggerPct`.
24
+ */
25
+ function dslPayloadFromState(state) {
26
+ const sign = state.direction === "LONG" ? 1 : -1;
27
+ const current = state.currentTierIndex;
28
+ return {
29
+ asset: state.asset,
30
+ dex: state.dex,
31
+ direction: state.direction,
32
+ entryPrice: state.entryPrice,
33
+ leverage: state.leverage,
34
+ phase: state.phase,
35
+ firstStopLoss: state.phase1.absoluteFloor,
36
+ lastPrice: state.lastPrice,
37
+ lastPriceAt: epochMsOrNull(state.lastCheck),
38
+ floorPrice: state.floorPrice,
39
+ currentTierIndex: current,
40
+ tierSince: state.tierSince === null ? null : epochMsOrNull(state.tierSince),
41
+ tiers: state.tiers.map((tier, i) => ({
42
+ triggerPct: tier.triggerPct,
43
+ lockHwPct: tier.lockHwPct,
44
+ triggerPrice: state.entryPrice * (1 + (sign * tier.triggerPct) / 100 / state.leverage),
45
+ reached: current !== null && i <= current,
46
+ })),
47
+ };
48
+ }
49
+ /**
50
+ * Builds the payload from the store and the DSL states. Copies only the payload fields from each
51
+ * DSL state. A runtime's state manager loads every address directory under its state directory.
52
+ * Only DSL states with a string `address` equal to the strategy wallet are kept.
53
+ */
54
+ export function buildStrategiesPayload(input) {
55
+ const strategies = [];
56
+ // A throw while reading or copying one runtime's DSL states gives that strategy `dsl: []`.
57
+ const dslRows = (runtimeId, address) => {
58
+ try {
59
+ return input
60
+ .dslStates(runtimeId)
61
+ .filter((state) => typeof state.address === "string" && normalizeAddress(state.address) === address)
62
+ .map(dslPayloadFromState);
63
+ }
64
+ catch (err) {
65
+ input.onDslError?.(runtimeId, err);
66
+ return [];
67
+ }
68
+ };
69
+ for (const [runtimeId, record] of input.store) {
70
+ const address = normalizeAddress(record.address);
71
+ strategies.push({
72
+ address,
73
+ name: record.name,
74
+ scanners: record.scanners.map((scanner) => ({
75
+ scannerId: scanner.scannerId,
76
+ intervalSeconds: scanner.intervalSeconds,
77
+ lastAliveAt: input.lastAliveAt(runtimeId, scanner.scannerId),
78
+ })),
79
+ dsl: dslRows(runtimeId, address),
80
+ });
81
+ }
82
+ return { v: 1, epoch: input.epoch, generatedAt: input.generatedAt, strategies };
83
+ }
84
+ /**
85
+ * Each tick builds the payload from the store, the liveness reader and the DSL state reader, keeps
86
+ * it as the last payload, and broadcasts it when a broadcast function is available. The loop reads
87
+ * the store and never writes it.
88
+ */
89
+ export function createStrategiesPublisher(deps) {
90
+ const epoch = deps.epoch ?? PROCESS_EPOCH;
91
+ const now = deps.now ?? Date.now;
92
+ const empty = () => ({ v: 1, epoch, generatedAt: now(), strategies: [] });
93
+ let last = empty();
94
+ let timer;
95
+ const tick = () => {
96
+ try {
97
+ last = buildStrategiesPayload({
98
+ epoch,
99
+ generatedAt: now(),
100
+ store: deps.store,
101
+ lastAliveAt: deps.lastAliveAt,
102
+ dslStates: deps.dslStates,
103
+ onDslError: deps.onDslError,
104
+ });
105
+ deps.getBroadcast()?.(STRATEGIES_EVENT_NAME, last, { dropIfSlow: true });
106
+ }
107
+ catch (err) {
108
+ deps.onError?.(err);
109
+ }
110
+ };
111
+ return {
112
+ start() {
113
+ if (timer !== undefined)
114
+ return;
115
+ tick();
116
+ timer = setInterval(tick, STRATEGIES_PUBLISH_INTERVAL_MS);
117
+ timer.unref?.();
118
+ },
119
+ stop() {
120
+ if (timer !== undefined)
121
+ clearInterval(timer);
122
+ timer = undefined;
123
+ last = empty();
124
+ },
125
+ lastPayload: () => last,
126
+ };
127
+ }
128
+ //# sourceMappingURL=strategies-telemetry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strategies-telemetry.js","sourceRoot":"","sources":["../../src/runtime/strategies-telemetry.ts"],"names":[],"mappings":"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"}
@@ -1,12 +1,32 @@
1
1
  /**
2
- * In-memory seed of the Theme-4 strategy lifecycle state machine (running→paused→stopped).
3
- * Short-term (§4); the durable crash-safe (SQLite) version is §5 merge work.
2
+ * Seed of the Theme-4 strategy lifecycle state machine (running→paused→stopped). The self-pause
3
+ * state is in memory; the halt latches are persisted (below). Short-term (§4); the durable
4
+ * crash-safe (SQLite) version is §5 merge work.
4
5
  *
5
6
  * Owns the self-pause state that RiskGuard used to hold. RiskGuard is now a stateless
6
7
  * gate evaluator that only reports; this component remembers which gates are currently
7
8
  * paused per strategy and fires the hook event + user notification on a genuine
8
9
  * running→paused transition, deduped so it alerts once per breach and re-arms only on
9
10
  * an explicit OPEN (re-running) of the same gate.
11
+ *
12
+ * It also owns the halt LATCH for the halt-class gates in {@link LATCHED_GATES}
13
+ * (daily loss, drawdown). Their live inputs are mark-to-market, so a strategy sitting
14
+ * near its limit reads breached / not-breached on every price bounce; without a latch
15
+ * each bounce reopened entries mid-day. {@link StrategyLifecycle.applyLatch} is called by
16
+ * the risk guard on every evaluation of those gates and overrides a fresh OPEN with
17
+ * CLOSED until the latch's release rule fires:
18
+ * - daily_loss_halt: the next UTC day (day taken from the MCP snapshot, not the box clock);
19
+ * - drawdown_halt: the next UTC day only when `drawdown_reset_on_day_rollover` is true;
20
+ * otherwise never.
21
+ * A latch for a gate that is no longer configured is dropped when the recipe is rebuilt
22
+ * ({@link StrategyLifecycle.pruneLatches}), so re-adding the rail later starts clean.
23
+ *
24
+ * Latches are persisted per strategy through {@link StrategyLifecycleDeps.latchStore} (the
25
+ * runtime's StateManager, file `<stateDir>/<address>/risk-halt-latch.json`), so a latch survives
26
+ * a gateway restart, an npm auto-update and a fleet redeploy: the restarted runtime reloads it on
27
+ * the strategy's first halt check and enforces it exactly as before, with the same release rules.
28
+ * The self-pause state above is still in memory only, so a restored latch announces its pause
29
+ * once more after a restart.
10
30
  */
11
31
  import type { RiskGateEvaluation, RiskGateId, RiskSource } from "../health/types.js";
12
32
  import type { HookSystem } from "../types/hooks.js";
@@ -43,6 +63,62 @@ export interface StrategyLifecycleDeps {
43
63
  notifications?: NotificationService;
44
64
  /** Runtime name attached to fired hook events (defaults to "runtime"). */
45
65
  runtimeName?: string;
66
+ /**
67
+ * Durable home for the halt latches (the runtime passes its StateManager). Without it the
68
+ * latches live in memory only and a gateway restart forgets them, which is the behaviour tests
69
+ * and the stub path get.
70
+ */
71
+ latchStore?: HaltLatchStore;
72
+ }
73
+ /**
74
+ * The slice of StateManager the halt latch persists through. Typed structurally so a test can
75
+ * hand in a fake; StateManager satisfies it as-is.
76
+ *
77
+ * Contract relied on: `getOrLoad` resolves undefined when nothing is stored (StateManager also
78
+ * resolves undefined for a corrupt file, which it tombstones and warns about) and REJECTS on a
79
+ * transient IO error; `set` persists durably or rejects.
80
+ */
81
+ export interface HaltLatchStore {
82
+ getOrLoad(key: string): Promise<unknown>;
83
+ set(key: string, value: unknown): Promise<void>;
84
+ }
85
+ /**
86
+ * State key of a strategy's persisted halt latches. StateManager maps it to
87
+ * `<stateDir>/<address>/risk-halt-latch.json`: inside the strategy's own dir, so it is archived
88
+ * with the strategy, and not `strategy` / `dsl-*`, so hydrate and the DSL listings ignore it.
89
+ */
90
+ export declare function haltLatchKey(address: string): string;
91
+ /** Schema version of the persisted latch file; any other version is read as "no latch". */
92
+ export declare const HALT_LATCH_STATE_VERSION = 1;
93
+ /**
94
+ * Halt-class gates whose genuine breach latches until its release rule fires, instead of
95
+ * reopening on the next non-breached reading. `max_entries_day` is deliberately absent:
96
+ * its mid-day reopen is tracked separately and keeps the pre-latch behaviour here.
97
+ */
98
+ export declare const LATCHED_GATES: ReadonlySet<RiskGateId>;
99
+ export interface ApplyLatchOpts {
100
+ /**
101
+ * Release the latch when an evaluation from a later UTC day arrives. Always true for
102
+ * daily_loss_halt; `drawdown_reset_on_day_rollover` for drawdown_halt.
103
+ */
104
+ releaseOnDayRollover: boolean;
105
+ }
106
+ /** What a latch remembers about the breach that set it. Also its persisted per-gate shape. */
107
+ export interface HaltLatch {
108
+ /** UTC day (YYYY-MM-DD) of the snapshot that tripped the gate. */
109
+ utcDay: string;
110
+ /** Wall-clock ISO time the latch was set. */
111
+ latchedAt: string;
112
+ /** The breaching evaluation's own reason (live numbers at trip time). */
113
+ trippedReason: string;
114
+ }
115
+ /**
116
+ * On-disk shape of one strategy's halt latches. An address with nothing latched is written as
117
+ * `{ version: 1, gates: {} }` rather than deleted, so "cleared" is a durable fact too.
118
+ */
119
+ export interface PersistedHaltLatches {
120
+ version: typeof HALT_LATCH_STATE_VERSION;
121
+ gates: Partial<Record<RiskGateId, HaltLatch>>;
46
122
  }
47
123
  export interface StrategyLifecycle {
48
124
  /**
@@ -53,6 +129,36 @@ export interface StrategyLifecycle {
53
129
  * @param source evaluation source (runtime / cli)
54
130
  */
55
131
  observe(address: string, label: string, evaluations: RiskGateEvaluation[], source: RiskSource): void;
132
+ /**
133
+ * Apply the halt latch to one fresh evaluation of a {@link LATCHED_GATES} gate and return
134
+ * the evaluation to enforce (other gates pass through untouched).
135
+ *
136
+ * - A genuine breach (CLOSED + evaluationOk + no fallback) sets the latch if none is held.
137
+ * Fail-closed / fallback evaluations never set it.
138
+ * - While latched, a fresh OPEN is overridden to CLOSED with a latched reason and
139
+ * `evaluationOk: true` — the evaluation itself succeeded; the gate is closed by the latch.
140
+ * - The latch is released only by a successful evaluation from a later UTC day, and only
141
+ * when `opts.releaseOnDayRollover` is true. The fresh evaluation is then enforced as-is.
142
+ *
143
+ * Async because of persistence: the strategy's persisted latches are loaded on its first call,
144
+ * and a set or release is written before the verdict returns. It cannot throw.
145
+ * - A failed load fails closed for that call: CLOSED with `evaluationOk: false`,
146
+ * `fallbackApplied: true`, `failureKind: "transport"`, like a failed snapshot fetch. A latch on
147
+ * disk this process has not read must not read as OPEN. Nothing is set or released on that
148
+ * call, so no pause fires; the next call retries the load.
149
+ * - A failed write is logged and never changes the verdict: the in-memory latch keeps enforcing.
150
+ */
151
+ applyLatch(address: string, evaluation: RiskGateEvaluation, opts: ApplyLatchOpts): Promise<RiskGateEvaluation>;
152
+ /**
153
+ * Drop the latches (and the matching pause state) of latched gates that are no longer
154
+ * configured for `address`. Called when the recipe is rebuilt: a gate whose rail was removed
155
+ * no longer enforces anything, so its latch must not resurface if the rail is added back later.
156
+ * Emits `runtime.resumed` for a dropped gate that was paused.
157
+ *
158
+ * Loads the persisted latches first (so a latch saved by an earlier process is pruned too) and
159
+ * writes the result. Never throws: the rebuild commit that calls it must not fail on disk IO.
160
+ */
161
+ pruneLatches(address: string, configured: ReadonlySet<RiskGateId>): Promise<void>;
56
162
  }
57
163
  export declare function createStrategyLifecycle(deps?: StrategyLifecycleDeps): StrategyLifecycle;
58
164
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"strategy-lifecycle.d.ts","sourceRoot":"","sources":["../../src/runtime/strategy-lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,kBAAkB,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,KAAK,EAAE,gBAAgB,EAAuB,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAO3G;;;kEAGkE;AAClE,UAAU,SAAS;IACjB,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAC;IACd;2DACuD;IACvD,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC,CAIrE,CAAC;AA6HF;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,EACnD,MAAM,EAAE,MAAM,GACb,gBAAgB,CAGlB;AAED,MAAM,WAAW,qBAAqB;IACpC,gEAAgE;IAChE,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,yEAAyE;IACzE,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC,0EAA0E;IAC1E,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC;;;;;;OAMG;IACH,OAAO,CACL,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,kBAAkB,EAAE,EACjC,MAAM,EAAE,UAAU,GACjB,IAAI,CAAC;CACT;AAED,wBAAgB,uBAAuB,CAAC,IAAI,GAAE,qBAA0B,GAAG,iBAAiB,CAyE3F"}
1
+ {"version":3,"file":"strategy-lifecycle.d.ts","sourceRoot":"","sources":["../../src/runtime/strategy-lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAIH,OAAO,KAAK,EAAE,kBAAkB,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,KAAK,EAAE,gBAAgB,EAAuB,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAO3G;;;kEAGkE;AAClE,UAAU,SAAS;IACjB,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAC;IACd;2DACuD;IACvD,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC,CAIrE,CAAC;AAkIF;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,EACnD,MAAM,EAAE,MAAM,GACb,gBAAgB,CAGlB;AAED,MAAM,WAAW,qBAAqB;IACpC,gEAAgE;IAChE,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,yEAAyE;IACzE,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC,0EAA0E;IAC1E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,UAAU,CAAC,EAAE,cAAc,CAAC;CAC7B;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACzC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACjD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,2FAA2F;AAC3F,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C;;;;GAIG;AACH,eAAO,MAAM,aAAa,EAAE,WAAW,CAAC,UAAU,CAGhD,CAAC;AAEH,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,oBAAoB,EAAE,OAAO,CAAC;CAC/B;AAED,8FAA8F;AAC9F,MAAM,WAAW,SAAS;IACxB,kEAAkE;IAClE,MAAM,EAAE,MAAM,CAAC;IACf,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,yEAAyE;IACzE,aAAa,EAAE,MAAM,CAAC;CACvB;AAgBD;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,wBAAwB,CAAC;IACzC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC;CAC/C;AA6ED,MAAM,WAAW,iBAAiB;IAChC;;;;;;OAMG;IACH,OAAO,CACL,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,kBAAkB,EAAE,EACjC,MAAM,EAAE,UAAU,GACjB,IAAI,CAAC;IAER;;;;;;;;;;;;;;;;;;OAkBG;IACH,UAAU,CACR,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,kBAAkB,EAC9B,IAAI,EAAE,cAAc,GACnB,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAE/B;;;;;;;;OAQG;IACH,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,WAAW,CAAC,UAAU,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnF;AAED,wBAAgB,uBAAuB,CAAC,IAAI,GAAE,qBAA0B,GAAG,iBAAiB,CAsQ3F"}