@senpi/runtime 3.0.24 → 3.0.26
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/approvals/approval-store.d.ts +35 -0
- package/dist/approvals/approval-store.d.ts.map +1 -0
- package/dist/approvals/approval-store.js +87 -0
- package/dist/approvals/approval-store.js.map +1 -0
- package/dist/approvals/manifest.d.ts +47 -0
- package/dist/approvals/manifest.d.ts.map +1 -0
- package/dist/approvals/manifest.js +91 -0
- package/dist/approvals/manifest.js.map +1 -0
- package/dist/approvals/tool-approval-gate.d.ts +93 -0
- package/dist/approvals/tool-approval-gate.d.ts.map +1 -0
- package/dist/approvals/tool-approval-gate.js +205 -0
- package/dist/approvals/tool-approval-gate.js.map +1 -0
- package/dist/approvals/tool-approvals-manifest.json +28 -0
- package/dist/dsl/notifications/formatter.js +2 -2
- package/dist/dsl/notifications/formatter.js.map +1 -1
- package/dist/dsl/notifications/index.d.ts.map +1 -1
- package/dist/dsl/notifications/index.js +28 -2
- package/dist/dsl/notifications/index.js.map +1 -1
- package/dist/dsl/notifications/raise-correlator.d.ts +87 -0
- package/dist/dsl/notifications/raise-correlator.d.ts.map +1 -0
- package/dist/dsl/notifications/raise-correlator.js +136 -0
- package/dist/dsl/notifications/raise-correlator.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +37 -1
- package/dist/index.js.map +1 -1
- package/dist/runtime/auto-update/coordinator.d.ts +1 -1
- package/dist/runtime/auto-update/coordinator.js +1 -1
- package/dist/runtime/strategy-lifecycle.js +3 -3
- package/dist/runtime/strategy-lifecycle.js.map +1 -1
- package/dist/types/notification.d.ts +1 -1
- package/openclaw.plugin.json +10 -1
- package/package.json +3 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"formatter.js","sourceRoot":"","sources":["../../../src/dsl/notifications/formatter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH,OAAO,EACL,WAAW,EACX,SAAS,EACT,MAAM,GACP,MAAM,mBAAmB,CAAC;AAE3B,SAAS,MAAM,CAAC,GAAW;IACzB,OAAO,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;AAChC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,CAAuB;IAC3D,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;IACtB,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC;IAC7B,MAAM,SAAS,GAAG,CAAC,CAAC,eAAe,IAAI,CAAC,CAAC;IACzC,MAAM,SAAS,GAAG,MAAM,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC,CAAC;IAC7C,MAAM,MAAM,GAAG,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC;IACjC,MAAM,EAAE,GAAG,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC;IAC/B,MAAM,UAAU,GAAG,MAAM,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC;IAC3C,MAAM,SAAS,GAAG,CAAC,CAAC,SAAS,IAAI,MAAM,CAAC;IACxC,OAAO;QACL,SAAS,EAAE,kBAAkB;QAC7B,QAAQ,EAAE,cAAc,SAAS,CAAC,SAAS,CAAC,OAAO,KAAK,EAAE;QAC1D,KAAK,EACH,MAAM,KAAK,IAAI,SAAS,oBAAoB,SAAS,CAAC,SAAS,CAAC,KAAK,MAAM,CAAC,SAAS,CAAC,
|
|
1
|
+
{"version":3,"file":"formatter.js","sourceRoot":"","sources":["../../../src/dsl/notifications/formatter.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/dsl/notifications/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAoB,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/dsl/notifications/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAoB,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAiB9G,MAAM,WAAW,sBAAsB;IACrC,+FAA+F;IAC/F,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,yBAAyB;IACxC,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,wBAAgB,UAAU,CACxB,QAAQ,EAAE,mBAAmB,EAC7B,KAAK,EAAE,MAAM,GAAG,mBAAmB,GAClC,IAAI,CAWN;AAwDD,wBAAgB,+BAA+B,CAC7C,GAAG,EAAE,aAAa,EAClB,QAAQ,EAAE,mBAAmB,EAC7B,OAAO,CAAC,EAAE,sBAAsB,GAC/B,yBAAyB,CAiE3B"}
|
|
@@ -6,6 +6,7 @@ import { DSL_EVENTS } from "../../constants/dsl/index.js";
|
|
|
6
6
|
import { createLogger } from "../../utils/logger.js";
|
|
7
7
|
import { randomUUID } from "node:crypto";
|
|
8
8
|
import { formatDslTierAdvanced, formatDslSlUpdated, } from "./formatter.js";
|
|
9
|
+
import { RaiseCorrelator, raiseKey } from "./raise-correlator.js";
|
|
9
10
|
const logger = createLogger("[senpi-core][dsl-notifications]");
|
|
10
11
|
export function safeNotify(notifier, input) {
|
|
11
12
|
try {
|
|
@@ -70,11 +71,30 @@ export function createDslNotificationSubscriber(bus, notifier, options) {
|
|
|
70
71
|
function notify(input) {
|
|
71
72
|
safeNotify(notifier, applyMessagePrefix(input, prefix));
|
|
72
73
|
}
|
|
74
|
+
// PF-2: a single DSL raise must yield EITHER "Profit locked" OR "Stop raised",
|
|
75
|
+
// never both. When a tier advance locks profit (lockedProfitPct > 0) it emits
|
|
76
|
+
// Profit locked and records intent here; the paired SL_UPDATED for the same
|
|
77
|
+
// raise is then suppressed. A tier that locks nothing (<= 0) emits no
|
|
78
|
+
// Profit-locked message and lets its stop-raise through. See RaiseCorrelator.
|
|
79
|
+
const correlator = new RaiseCorrelator();
|
|
73
80
|
const onTierAdvanced = (e) => {
|
|
74
81
|
runNotificationHandler(() => {
|
|
75
82
|
const ev = e;
|
|
76
|
-
const
|
|
77
|
-
|
|
83
|
+
const key = raiseKey(ev);
|
|
84
|
+
// lockedUSD > 0 ⟺ lockedProfitPct > 0 (lockedUSD = margin * pct/100, margin >= 0).
|
|
85
|
+
if ((ev.lockedProfitPct ?? 0) > 0) {
|
|
86
|
+
correlator.recordProfitLock(key, ev.timestamp);
|
|
87
|
+
const copy = formatDslTierAdvanced(ev);
|
|
88
|
+
notify(buildOpenablePayload(copy, "DSL_PROFIT_LOCK", ev.address, ev.timestamp, ev.asset, ev.dex));
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
// Else branch: nothing locked ("+$0.00"). Suppress the Profit-locked
|
|
92
|
+
// message and clear any stale marker so the paired stop-raise emits.
|
|
93
|
+
correlator.clear(key);
|
|
94
|
+
logger.debug("[dsl-notifications] tier advance locked no profit; deferring to stop-raise", {
|
|
95
|
+
asset: ev.asset,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
78
98
|
});
|
|
79
99
|
};
|
|
80
100
|
const onSlUpdated = (e) => {
|
|
@@ -82,6 +102,12 @@ export function createDslNotificationSubscriber(bus, notifier, options) {
|
|
|
82
102
|
return;
|
|
83
103
|
runNotificationHandler(() => {
|
|
84
104
|
const ev = e;
|
|
105
|
+
if (correlator.shouldSuppressStopRaise(raiseKey(ev), ev.timestamp)) {
|
|
106
|
+
logger.debug("[dsl-notifications] stop-raise suppressed: same raise already sent Profit locked", {
|
|
107
|
+
asset: ev.asset,
|
|
108
|
+
});
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
85
111
|
const copy = formatDslSlUpdated(ev);
|
|
86
112
|
// The SL-updated event carries no book, so the seed omits `dex`.
|
|
87
113
|
notify(buildOpenablePayload(copy, "DSL_STOP_RAISE", ev.address, ev.timestamp, ev.asset));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/dsl/notifications/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAK9E,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EACL,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/dsl/notifications/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Correlates the two bus events a single DSL raise can produce so the
|
|
3
|
+
* notification dispatch sends EITHER "Profit locked" OR "Stop raised", never
|
|
4
|
+
* both (PF-2).
|
|
5
|
+
*
|
|
6
|
+
* On one raise tick a position can emit `TIER_ADVANCED` (→ Profit locked) and,
|
|
7
|
+
* when the exchange SL is synced, `SL_UPDATED` (→ Stop raised). TIER_ADVANCED
|
|
8
|
+
* always precedes SL_UPDATED on both emit paths (local monitor: synchronous
|
|
9
|
+
* emit order; backend poll: ASC-sorted, tier-before-SL), so the tier handler
|
|
10
|
+
* records intent here and the SL handler consults it.
|
|
11
|
+
*
|
|
12
|
+
* Correlation is per position (`__positionId`, falling back to `address::asset`)
|
|
13
|
+
* and keyed on the events' OWN timestamps, not wall-clock time:
|
|
14
|
+
* - Local path: both events carry the SAME tick `timestamp` string (an
|
|
15
|
+
* `editPosition` network call sits between the two emits, so their
|
|
16
|
+
* wall-clock gap can be seconds — event-time comparison is immune to that).
|
|
17
|
+
* - Backend path: the two events are separate records whose `createdAt` may
|
|
18
|
+
* differ by a few ms within one evaluation → matched by a small tolerance.
|
|
19
|
+
*
|
|
20
|
+
* The tolerance stays well below the minimum monitor interval (5s) so a later,
|
|
21
|
+
* genuinely-independent raise's SL — whose timestamp is a different tick, ≥ 5s
|
|
22
|
+
* away — is never mistaken for the same raise. Wall-clock time is used ONLY to
|
|
23
|
+
* garbage-collect orphan markers whose paired SL never arrives.
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* Max spread (ms) between a tier's timestamp and its paired SL's timestamp for
|
|
27
|
+
* them to count as the same raise. Covers the backend path's few-ms `createdAt`
|
|
28
|
+
* spread; MUST stay below the minimum monitor interval (MIN_INTERVAL_SECONDS =
|
|
29
|
+
* 5s) so two independent raises for one position never collide.
|
|
30
|
+
*/
|
|
31
|
+
export declare const RAISE_CORRELATION_TOLERANCE_MS = 2000;
|
|
32
|
+
/**
|
|
33
|
+
* Marker lifetime (ms, wall-clock) before garbage-collection. Bounds memory when
|
|
34
|
+
* a profit-lock tier's paired SL never arrives (e.g. a Phase-1 tier that syncs no
|
|
35
|
+
* exchange SL). Generous: past the correlation tolerance a marker can only match
|
|
36
|
+
* via exact-timestamp equality, which an independent later raise never produces.
|
|
37
|
+
*/
|
|
38
|
+
export declare const RAISE_MARKER_TTL_MS = 60000;
|
|
39
|
+
/** Hard size backstop: if the map ever grows past this, oldest entries are evicted. */
|
|
40
|
+
export declare const RAISE_MAX_ENTRIES = 5000;
|
|
41
|
+
/** Per-position correlation key: cross-flow position id, else address::asset. */
|
|
42
|
+
export declare function raiseKey(ev: {
|
|
43
|
+
__positionId?: string;
|
|
44
|
+
address?: string;
|
|
45
|
+
asset?: string;
|
|
46
|
+
}): string;
|
|
47
|
+
export interface RaiseCorrelatorOptions {
|
|
48
|
+
/** Injectable clock for TTL/GC in tests. Defaults to `Date.now`. */
|
|
49
|
+
now?: () => number;
|
|
50
|
+
toleranceMs?: number;
|
|
51
|
+
ttlMs?: number;
|
|
52
|
+
maxEntries?: number;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Records profit-lock intent per raise and answers whether a following
|
|
56
|
+
* stop-raise belongs to the same raise (and must therefore be suppressed).
|
|
57
|
+
*/
|
|
58
|
+
export declare class RaiseCorrelator {
|
|
59
|
+
private readonly markers;
|
|
60
|
+
private readonly now;
|
|
61
|
+
private readonly toleranceMs;
|
|
62
|
+
private readonly ttlMs;
|
|
63
|
+
private readonly maxEntries;
|
|
64
|
+
constructor(opts?: RaiseCorrelatorOptions);
|
|
65
|
+
/**
|
|
66
|
+
* A tier advanced with locked profit (> 0). Remember it so the paired
|
|
67
|
+
* stop-raise for the SAME raise is suppressed. A newer raise overwrites the
|
|
68
|
+
* position's prior marker.
|
|
69
|
+
*/
|
|
70
|
+
recordProfitLock(key: string, tierTimestamp: string): void;
|
|
71
|
+
/**
|
|
72
|
+
* A tier advanced with NO locked profit (<= 0) → PF-2 "else" branch: no
|
|
73
|
+
* Profit-locked message and the paired stop-raise must go through. Drop any
|
|
74
|
+
* stale marker so it cannot suppress this position's next stop-raise.
|
|
75
|
+
*/
|
|
76
|
+
clear(key: string): void;
|
|
77
|
+
/**
|
|
78
|
+
* True when this stop-raise is the SL half of a profit-locking raise already
|
|
79
|
+
* announced as "Profit locked" → suppress it. Consumes the marker (once).
|
|
80
|
+
*/
|
|
81
|
+
shouldSuppressStopRaise(key: string, slTimestamp: string): boolean;
|
|
82
|
+
/** Test/observability helper. */
|
|
83
|
+
size(): number;
|
|
84
|
+
/** Remove expired entries; if still at capacity, evict the oldest. */
|
|
85
|
+
private evict;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=raise-correlator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"raise-correlator.d.ts","sourceRoot":"","sources":["../../../src/dsl/notifications/raise-correlator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,8BAA8B,OAAQ,CAAC;AAEpD;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,QAAS,CAAC;AAE1C,uFAAuF;AACvF,eAAO,MAAM,iBAAiB,OAAQ,CAAC;AAEvC,iFAAiF;AACjF,wBAAgB,QAAQ,CAAC,EAAE,EAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAGhG;AAQD,MAAM,WAAW,sBAAsB;IACrC,oEAAoE;IACpE,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkC;IAC1D,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;gBAExB,IAAI,CAAC,EAAE,sBAAsB;IAOzC;;;;OAIG;IACH,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,IAAI;IAW1D;;;;OAIG;IACH,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIxB;;;OAGG;IACH,uBAAuB,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO;IAsBlE,iCAAiC;IACjC,IAAI,IAAI,MAAM;IAId,sEAAsE;IACtE,OAAO,CAAC,KAAK;CAgBd"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Correlates the two bus events a single DSL raise can produce so the
|
|
3
|
+
* notification dispatch sends EITHER "Profit locked" OR "Stop raised", never
|
|
4
|
+
* both (PF-2).
|
|
5
|
+
*
|
|
6
|
+
* On one raise tick a position can emit `TIER_ADVANCED` (→ Profit locked) and,
|
|
7
|
+
* when the exchange SL is synced, `SL_UPDATED` (→ Stop raised). TIER_ADVANCED
|
|
8
|
+
* always precedes SL_UPDATED on both emit paths (local monitor: synchronous
|
|
9
|
+
* emit order; backend poll: ASC-sorted, tier-before-SL), so the tier handler
|
|
10
|
+
* records intent here and the SL handler consults it.
|
|
11
|
+
*
|
|
12
|
+
* Correlation is per position (`__positionId`, falling back to `address::asset`)
|
|
13
|
+
* and keyed on the events' OWN timestamps, not wall-clock time:
|
|
14
|
+
* - Local path: both events carry the SAME tick `timestamp` string (an
|
|
15
|
+
* `editPosition` network call sits between the two emits, so their
|
|
16
|
+
* wall-clock gap can be seconds — event-time comparison is immune to that).
|
|
17
|
+
* - Backend path: the two events are separate records whose `createdAt` may
|
|
18
|
+
* differ by a few ms within one evaluation → matched by a small tolerance.
|
|
19
|
+
*
|
|
20
|
+
* The tolerance stays well below the minimum monitor interval (5s) so a later,
|
|
21
|
+
* genuinely-independent raise's SL — whose timestamp is a different tick, ≥ 5s
|
|
22
|
+
* away — is never mistaken for the same raise. Wall-clock time is used ONLY to
|
|
23
|
+
* garbage-collect orphan markers whose paired SL never arrives.
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* Max spread (ms) between a tier's timestamp and its paired SL's timestamp for
|
|
27
|
+
* them to count as the same raise. Covers the backend path's few-ms `createdAt`
|
|
28
|
+
* spread; MUST stay below the minimum monitor interval (MIN_INTERVAL_SECONDS =
|
|
29
|
+
* 5s) so two independent raises for one position never collide.
|
|
30
|
+
*/
|
|
31
|
+
export const RAISE_CORRELATION_TOLERANCE_MS = 2_000;
|
|
32
|
+
/**
|
|
33
|
+
* Marker lifetime (ms, wall-clock) before garbage-collection. Bounds memory when
|
|
34
|
+
* a profit-lock tier's paired SL never arrives (e.g. a Phase-1 tier that syncs no
|
|
35
|
+
* exchange SL). Generous: past the correlation tolerance a marker can only match
|
|
36
|
+
* via exact-timestamp equality, which an independent later raise never produces.
|
|
37
|
+
*/
|
|
38
|
+
export const RAISE_MARKER_TTL_MS = 60_000;
|
|
39
|
+
/** Hard size backstop: if the map ever grows past this, oldest entries are evicted. */
|
|
40
|
+
export const RAISE_MAX_ENTRIES = 5_000;
|
|
41
|
+
/** Per-position correlation key: cross-flow position id, else address::asset. */
|
|
42
|
+
export function raiseKey(ev) {
|
|
43
|
+
if (ev.__positionId != null && ev.__positionId !== "")
|
|
44
|
+
return ev.__positionId;
|
|
45
|
+
return `${ev.address ?? ""}::${ev.asset ?? ""}`;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Records profit-lock intent per raise and answers whether a following
|
|
49
|
+
* stop-raise belongs to the same raise (and must therefore be suppressed).
|
|
50
|
+
*/
|
|
51
|
+
export class RaiseCorrelator {
|
|
52
|
+
markers = new Map();
|
|
53
|
+
now;
|
|
54
|
+
toleranceMs;
|
|
55
|
+
ttlMs;
|
|
56
|
+
maxEntries;
|
|
57
|
+
constructor(opts) {
|
|
58
|
+
this.now = opts?.now ?? Date.now;
|
|
59
|
+
this.toleranceMs = opts?.toleranceMs ?? RAISE_CORRELATION_TOLERANCE_MS;
|
|
60
|
+
this.ttlMs = opts?.ttlMs ?? RAISE_MARKER_TTL_MS;
|
|
61
|
+
this.maxEntries = opts?.maxEntries ?? RAISE_MAX_ENTRIES;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* A tier advanced with locked profit (> 0). Remember it so the paired
|
|
65
|
+
* stop-raise for the SAME raise is suppressed. A newer raise overwrites the
|
|
66
|
+
* position's prior marker.
|
|
67
|
+
*/
|
|
68
|
+
recordProfitLock(key, tierTimestamp) {
|
|
69
|
+
if (this.markers.size >= this.maxEntries && !this.markers.has(key)) {
|
|
70
|
+
this.evict();
|
|
71
|
+
}
|
|
72
|
+
this.markers.set(key, {
|
|
73
|
+
tierTimestamp,
|
|
74
|
+
tierTimeMs: Date.parse(tierTimestamp),
|
|
75
|
+
insertedAtMs: this.now(),
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* A tier advanced with NO locked profit (<= 0) → PF-2 "else" branch: no
|
|
80
|
+
* Profit-locked message and the paired stop-raise must go through. Drop any
|
|
81
|
+
* stale marker so it cannot suppress this position's next stop-raise.
|
|
82
|
+
*/
|
|
83
|
+
clear(key) {
|
|
84
|
+
this.markers.delete(key);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* True when this stop-raise is the SL half of a profit-locking raise already
|
|
88
|
+
* announced as "Profit locked" → suppress it. Consumes the marker (once).
|
|
89
|
+
*/
|
|
90
|
+
shouldSuppressStopRaise(key, slTimestamp) {
|
|
91
|
+
const marker = this.markers.get(key);
|
|
92
|
+
if (!marker)
|
|
93
|
+
return false;
|
|
94
|
+
if (this.now() - marker.insertedAtMs > this.ttlMs) {
|
|
95
|
+
// Orphan whose SL never arrived — GC and let this SL through.
|
|
96
|
+
this.markers.delete(key);
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
const slMs = Date.parse(slTimestamp);
|
|
100
|
+
const sameRaise = slTimestamp === marker.tierTimestamp ||
|
|
101
|
+
(Number.isFinite(slMs) &&
|
|
102
|
+
Number.isFinite(marker.tierTimeMs) &&
|
|
103
|
+
Math.abs(slMs - marker.tierTimeMs) <= this.toleranceMs);
|
|
104
|
+
if (sameRaise) {
|
|
105
|
+
this.markers.delete(key);
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
// A later, independent raise's SL: leave the (soon-to-expire) marker in place.
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
/** Test/observability helper. */
|
|
112
|
+
size() {
|
|
113
|
+
return this.markers.size;
|
|
114
|
+
}
|
|
115
|
+
/** Remove expired entries; if still at capacity, evict the oldest. */
|
|
116
|
+
evict() {
|
|
117
|
+
const cutoff = this.now() - this.ttlMs;
|
|
118
|
+
for (const [k, m] of this.markers) {
|
|
119
|
+
if (m.insertedAtMs < cutoff)
|
|
120
|
+
this.markers.delete(k);
|
|
121
|
+
}
|
|
122
|
+
if (this.markers.size < this.maxEntries)
|
|
123
|
+
return;
|
|
124
|
+
let oldestKey;
|
|
125
|
+
let oldestAt = Infinity;
|
|
126
|
+
for (const [k, m] of this.markers) {
|
|
127
|
+
if (m.insertedAtMs < oldestAt) {
|
|
128
|
+
oldestAt = m.insertedAtMs;
|
|
129
|
+
oldestKey = k;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (oldestKey != null)
|
|
133
|
+
this.markers.delete(oldestKey);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=raise-correlator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"raise-correlator.js","sourceRoot":"","sources":["../../../src/dsl/notifications/raise-correlator.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* the loader's relative-import path entirely.
|
|
13
13
|
*/
|
|
14
14
|
import type { SenpiEventBus } from "./dsl/events/index.js";
|
|
15
|
+
import { type ToolApprovalsMode } from "./approvals/tool-approval-gate.js";
|
|
15
16
|
/** Initialize all core features (DSL, risk, health) on the given event bus. */
|
|
16
17
|
export declare function initCore(bus: SenpiEventBus): void;
|
|
17
18
|
export { initDsl, DslPlugin, dslLogger, setDslLogLevel, parseDslPluginConfig, DslConfigValidationError, dslValidationIssue, EVENTS as DslEvents, DSL_EVENTS, } from "./dsl/index.js";
|
|
@@ -46,6 +47,15 @@ export interface SenpiRuntimePluginConfig {
|
|
|
46
47
|
stateDir?: string;
|
|
47
48
|
apiKey?: string;
|
|
48
49
|
logLevel?: string;
|
|
50
|
+
/**
|
|
51
|
+
* MCP tool approval gate mode override (see src/approvals/tool-approval-gate.ts):
|
|
52
|
+
* "trades" requires interactive approval for state-changing senpi MCP tools,
|
|
53
|
+
* "all" gates every senpi MCP tool, "off" disables the gate. The gated tool
|
|
54
|
+
* set and the default mode ship in the checked-in
|
|
55
|
+
* src/approvals/tool-approvals-manifest.json. Precedence:
|
|
56
|
+
* env SENPI_TOOL_APPROVALS > this setting > manifest default.
|
|
57
|
+
*/
|
|
58
|
+
toolApprovals?: ToolApprovalsMode;
|
|
49
59
|
autoUpdate?: Record<string, unknown>;
|
|
50
60
|
skillsManager?: {
|
|
51
61
|
enabled?: boolean;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAiCH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -33,11 +33,13 @@ import { VERSION } from "./version.js";
|
|
|
33
33
|
import { resolvePackageName } from "./runtime/auto-update/resolve-package-name.js";
|
|
34
34
|
import { runOpenClawPluginsUpdate } from "./runtime/auto-update/run-update-command.js";
|
|
35
35
|
import { registerSpanHooks } from "./telemetry/spans/index.js";
|
|
36
|
+
import { registerSessionContextSeedHook } from "./prompt/session-context-seed-hook.js";
|
|
36
37
|
import { initDefaultPiiRedactor } from "./telemetry/spans/redact-pii.js";
|
|
37
38
|
import { initOtelSdk, shutdownOtelSdk } from "./telemetry/otel-sdk.js";
|
|
38
39
|
import { getLogLevel, getLogLevelSource, parseLogLevel, setLogLevel, } from "./utils/logger.js";
|
|
39
40
|
import { ExternalScannerIngestError, } from "./scanners/external-scanner-receiver.js";
|
|
40
41
|
import { createLogger } from "./utils/logger.js";
|
|
42
|
+
import { registerToolApprovalGate, resolveToolApprovalsMode, } from "./approvals/tool-approval-gate.js";
|
|
41
43
|
import { EVENT_NAME, eventAttrs } from "./utils/event-catalog.js";
|
|
42
44
|
import { emitEvent } from "./actions/event-derivation.js";
|
|
43
45
|
import { buildRuntimeCreatedEvent, buildRuntimeDeletedEvent } from "./runtime/lifecycle-events.js";
|
|
@@ -205,6 +207,40 @@ const senpiRuntimePlugin = {
|
|
|
205
207
|
err: err instanceof Error ? err.message : String(err),
|
|
206
208
|
});
|
|
207
209
|
}
|
|
210
|
+
// Session-context seed turn — a producer (e.g. a "reply"-tapped notification) arrives as
|
|
211
|
+
// a normal chat turn wrapped in fixed markers; this hook forces an exact NO_REPLY for it
|
|
212
|
+
// so the seed row lands in history without emitting a reply to the channel.
|
|
213
|
+
try {
|
|
214
|
+
registerSessionContextSeedHook({ api });
|
|
215
|
+
pluginLogger.info("[senpi-runtime] session-context seed hook registered");
|
|
216
|
+
}
|
|
217
|
+
catch (err) {
|
|
218
|
+
pluginLogger.warn("[senpi-runtime] failed to register session-context seed hook", {
|
|
219
|
+
err: err instanceof Error ? err.message : String(err),
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
// MCP tool approval gate — state-changing senpi MCP tools require an
|
|
223
|
+
// interactive user approval before executing. Prompts reach senpi-web via
|
|
224
|
+
// the bridge's operator.approvals-scoped gateway connection; allow-always
|
|
225
|
+
// decisions persist in <stateDir>/tool-approvals.json.
|
|
226
|
+
// See docs/mcp-tool-approvals-design.md.
|
|
227
|
+
try {
|
|
228
|
+
registerToolApprovalGate({
|
|
229
|
+
api,
|
|
230
|
+
mode: resolveToolApprovalsMode({
|
|
231
|
+
pluginConfig: config,
|
|
232
|
+
env: process.env,
|
|
233
|
+
logger: pluginLogger,
|
|
234
|
+
}),
|
|
235
|
+
stateDir: baseStateDir,
|
|
236
|
+
logger: pluginLogger,
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
catch (err) {
|
|
240
|
+
pluginLogger.warn("[senpi-runtime] failed to register tool approval gate", {
|
|
241
|
+
err: err instanceof Error ? err.message : String(err),
|
|
242
|
+
});
|
|
243
|
+
}
|
|
208
244
|
const runtimeHandles = new Map();
|
|
209
245
|
let apiHandle;
|
|
210
246
|
// Supervised scanner state — module-scoped so stop() can reach them.
|
|
@@ -248,7 +284,7 @@ const senpiRuntimePlugin = {
|
|
|
248
284
|
// A gateway seam failed to wire/launch a runtime's external scanner stack: the runtime is up but
|
|
249
285
|
// runs blind on internal scanners only. Two records, by design: a first-class `runtime.scanners_unwired`
|
|
250
286
|
// event (the queryable/alertable fact, by phase) and the migrated exception-form `logger.error`
|
|
251
|
-
// (carries the stack + trace context
|
|
287
|
+
// (carries the stack + trace context for the internal log).
|
|
252
288
|
const eventScannersUnwired = (phase, runtimeId, wallet, message, error) => {
|
|
253
289
|
apiLogger.event(EVENT_NAME.runtimeScannersUnwired, "error", {
|
|
254
290
|
body: message,
|