@secondlayer/sentinel 0.2.1 → 0.3.0
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/cli.js +8 -9
- package/dist/index.js +9 -9
- package/dist/mcp.js +17 -11
- package/dist/sentinel-client.d.ts +28 -15
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -176,16 +176,15 @@ function ruleSummary(rule, units) {
|
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
178
|
}
|
|
179
|
+
function assetClause(a) {
|
|
180
|
+
const symbol = subjectName({ kind: "asset", asset: a.asset }, a.units);
|
|
181
|
+
const amount = a.threshold.amount;
|
|
182
|
+
if (amount === null)
|
|
183
|
+
return `${symbol} every outflow`;
|
|
184
|
+
return `${symbol} over ${a.units ? toUnits(amount, a.units.decimals) : `${group(amount)} base units`}`;
|
|
185
|
+
}
|
|
179
186
|
function intentLine(i) {
|
|
180
|
-
|
|
181
|
-
if (i.kind !== "money_out" || !t)
|
|
182
|
-
return i.summary;
|
|
183
|
-
const units = i.units ?? null;
|
|
184
|
-
if (t.amount === null) {
|
|
185
|
-
const sug = t.suggested ? ` (suggested ${amountText(t.suggested.amount, units)}, ${t.suggested.basis})` : "";
|
|
186
|
-
return `no threshold yet: every outflow alerts${sug}`;
|
|
187
|
-
}
|
|
188
|
-
return `${amountText(t.amount, units)} or more in one tx · ${t.basis}`;
|
|
187
|
+
return i.kind === "money_out" && i.assets?.length ? i.assets.map(assetClause).join(" · ") : i.summary;
|
|
189
188
|
}
|
|
190
189
|
var isMutableRule = (rule) => rule.kind !== "signature" && rule.kind !== "audit";
|
|
191
190
|
function mutedUntilOf(w, now = Date.now()) {
|
package/dist/index.js
CHANGED
|
@@ -185,16 +185,15 @@ function kindTag(rule) {
|
|
|
185
185
|
return rule.triggerClass === "governance.proposal_submitted" ? "governance" : "upgrade";
|
|
186
186
|
}
|
|
187
187
|
}
|
|
188
|
+
function assetClause(a) {
|
|
189
|
+
const symbol = subjectName({ kind: "asset", asset: a.asset }, a.units);
|
|
190
|
+
const amount = a.threshold.amount;
|
|
191
|
+
if (amount === null)
|
|
192
|
+
return `${symbol} every outflow`;
|
|
193
|
+
return `${symbol} over ${a.units ? toUnits(amount, a.units.decimals) : `${group(amount)} base units`}`;
|
|
194
|
+
}
|
|
188
195
|
function intentLine(i) {
|
|
189
|
-
|
|
190
|
-
if (i.kind !== "money_out" || !t)
|
|
191
|
-
return i.summary;
|
|
192
|
-
const units = i.units ?? null;
|
|
193
|
-
if (t.amount === null) {
|
|
194
|
-
const sug = t.suggested ? ` (suggested ${amountText(t.suggested.amount, units)}, ${t.suggested.basis})` : "";
|
|
195
|
-
return `no threshold yet: every outflow alerts${sug}`;
|
|
196
|
-
}
|
|
197
|
-
return `${amountText(t.amount, units)} or more in one tx · ${t.basis}`;
|
|
196
|
+
return i.kind === "money_out" && i.assets?.length ? i.assets.map(assetClause).join(" · ") : i.summary;
|
|
198
197
|
}
|
|
199
198
|
function subjectStatus(ws) {
|
|
200
199
|
const st = ws.map((w) => w.status);
|
|
@@ -295,6 +294,7 @@ export {
|
|
|
295
294
|
NOT_LOGGED_IN,
|
|
296
295
|
SentinelError,
|
|
297
296
|
SubjectError,
|
|
297
|
+
assetClause,
|
|
298
298
|
clearSession,
|
|
299
299
|
clearTokenFile,
|
|
300
300
|
createClient,
|
package/dist/mcp.js
CHANGED
|
@@ -12750,16 +12750,15 @@ function ruleSummary(rule, units) {
|
|
|
12750
12750
|
}
|
|
12751
12751
|
}
|
|
12752
12752
|
}
|
|
12753
|
+
function assetClause(a) {
|
|
12754
|
+
const symbol = subjectName({ kind: "asset", asset: a.asset }, a.units);
|
|
12755
|
+
const amount = a.threshold.amount;
|
|
12756
|
+
if (amount === null)
|
|
12757
|
+
return `${symbol} every outflow`;
|
|
12758
|
+
return `${symbol} over ${a.units ? toUnits(amount, a.units.decimals) : `${group(amount)} base units`}`;
|
|
12759
|
+
}
|
|
12753
12760
|
function intentLine(i) {
|
|
12754
|
-
|
|
12755
|
-
if (i.kind !== "money_out" || !t)
|
|
12756
|
-
return i.summary;
|
|
12757
|
-
const units = i.units ?? null;
|
|
12758
|
-
if (t.amount === null) {
|
|
12759
|
-
const sug = t.suggested ? ` (suggested ${amountText(t.suggested.amount, units)}, ${t.suggested.basis})` : "";
|
|
12760
|
-
return `no threshold yet: every outflow alerts${sug}`;
|
|
12761
|
-
}
|
|
12762
|
-
return `${amountText(t.amount, units)} or more in one tx · ${t.basis}`;
|
|
12761
|
+
return i.kind === "money_out" && i.assets?.length ? i.assets.map(assetClause).join(" · ") : i.summary;
|
|
12763
12762
|
}
|
|
12764
12763
|
function subjectStatus(ws) {
|
|
12765
12764
|
const st = ws.map((w) => w.status);
|
|
@@ -20648,6 +20647,13 @@ function intentView(i) {
|
|
|
20648
20647
|
alertLevel: i.alertLevel,
|
|
20649
20648
|
coverage: i.coverage,
|
|
20650
20649
|
summary: intentLine(i),
|
|
20650
|
+
...i.assets ? {
|
|
20651
|
+
assets: i.assets.map((a) => ({
|
|
20652
|
+
subject: subjectName({ kind: "asset", asset: a.asset }, a.units),
|
|
20653
|
+
limit: assetClause(a),
|
|
20654
|
+
watchIds: a.watchIds
|
|
20655
|
+
}))
|
|
20656
|
+
} : {},
|
|
20651
20657
|
members: i.members,
|
|
20652
20658
|
...i.alsoChecks ? { alsoChecks: i.alsoChecks } : {},
|
|
20653
20659
|
status: subjectStatus(i.rows),
|
|
@@ -20859,7 +20865,7 @@ function buildTools(client) {
|
|
|
20859
20865
|
run: async (a) => a.confirm === true ? client.testsFromRepo(a.planId) : paidRun("Run the Clarinet suite from this pre-launch plan's repo in the airgapped sandbox.")
|
|
20860
20866
|
},
|
|
20861
20867
|
list_watches: {
|
|
20862
|
-
description: "What a plan watches, as intent watches (Money out per token, Control changes, one per finding, the fns you added): on or off, the threshold or summary, the fns covered, what it can see (coverage: direct-calls means a call made from another contract isn't visible yet), each rule in token units, any mute, and the subject name the other watch tools take.",
|
|
20868
|
+
description: "What a plan watches, as intent watches (Money out once per contract with a limit per token, Control changes, one per finding, the fns you added): on or off, the threshold or summary, the fns covered, what it can see (coverage: direct-calls means a call made from another contract isn't visible yet), each rule in token units, any mute, and the subject name the other watch tools take.",
|
|
20863
20869
|
input: { planId },
|
|
20864
20870
|
run: async (a) => {
|
|
20865
20871
|
const ctx = await watchContext(client, a.planId);
|
|
@@ -21043,7 +21049,7 @@ async function runTool(tool, args) {
|
|
|
21043
21049
|
}
|
|
21044
21050
|
}
|
|
21045
21051
|
function buildServer(client) {
|
|
21046
|
-
const server = new McpServer({ name: "sentinel", version: "0.
|
|
21052
|
+
const server = new McpServer({ name: "sentinel", version: "0.3.0" });
|
|
21047
21053
|
for (const [name, tool] of Object.entries(buildTools(client))) {
|
|
21048
21054
|
server.registerTool(name, { description: tool.description, inputSchema: tool.input }, (args) => runTool(tool, args));
|
|
21049
21055
|
}
|
|
@@ -170,8 +170,29 @@ export type StoredWatch = {
|
|
|
170
170
|
units: Units | null;
|
|
171
171
|
};
|
|
172
172
|
export type IntentKind = "money_out" | "control" | "finding" | "owner_fn";
|
|
173
|
+
/** A Money out limit: null amount means every outflow alerts until one is set. */
|
|
174
|
+
export type Threshold = {
|
|
175
|
+
amount: string | null;
|
|
176
|
+
basis: string;
|
|
177
|
+
confirmed: boolean;
|
|
178
|
+
suggested: {
|
|
179
|
+
amount: string;
|
|
180
|
+
basis: string;
|
|
181
|
+
} | null;
|
|
182
|
+
};
|
|
183
|
+
/** One asset inside Money out: its own limit, the rows behind it and its last 7 UTC days (oldest first). */
|
|
184
|
+
export type AssetWatch = {
|
|
185
|
+
asset: string;
|
|
186
|
+
units: Units | null;
|
|
187
|
+
threshold: Threshold;
|
|
188
|
+
watchIds: string[];
|
|
189
|
+
stats7d: {
|
|
190
|
+
events: number[];
|
|
191
|
+
alerts: number[];
|
|
192
|
+
};
|
|
193
|
+
};
|
|
173
194
|
/**
|
|
174
|
-
* One intent watch: what a team sees (Money out
|
|
195
|
+
* One intent watch: what a team sees (Money out holding every asset, Control changes, one per finding, a fn the team
|
|
175
196
|
* added). `rows` are the stored watches behind it: what a rule edit, a switch or a mute acts on.
|
|
176
197
|
*/
|
|
177
198
|
export type IntentWatch<R = StoredWatch & {
|
|
@@ -192,18 +213,8 @@ export type IntentWatch<R = StoredWatch & {
|
|
|
192
213
|
group: string;
|
|
193
214
|
fns: string[];
|
|
194
215
|
}[];
|
|
195
|
-
/** Money out: the
|
|
196
|
-
|
|
197
|
-
units?: Units | null;
|
|
198
|
-
threshold?: {
|
|
199
|
-
amount: string | null;
|
|
200
|
-
basis: string;
|
|
201
|
-
confirmed: boolean;
|
|
202
|
-
suggested: {
|
|
203
|
-
amount: string;
|
|
204
|
-
basis: string;
|
|
205
|
-
} | null;
|
|
206
|
-
};
|
|
216
|
+
/** Money out: every asset the contract sends, STX first then by symbol, each with its own limit. */
|
|
217
|
+
assets?: AssetWatch[];
|
|
207
218
|
findingRef?: {
|
|
208
219
|
title: string;
|
|
209
220
|
index: number | null;
|
|
@@ -313,8 +324,10 @@ export declare function ruleSummary(rule: WatchRule, units: Units | null): strin
|
|
|
313
324
|
export type WatchKindTag = "finding" | "outflow" | "who-acts" | "governance" | "upgrade";
|
|
314
325
|
/** The plain tag a rule is listed under. */
|
|
315
326
|
export declare function kindTag(rule: WatchRule): WatchKindTag;
|
|
316
|
-
/**
|
|
317
|
-
export declare function
|
|
327
|
+
/** One Money out clause: `STX over 500` or `MIA every outflow`, in token units where they are known. */
|
|
328
|
+
export declare function assetClause(a: Pick<AssetWatch, "asset" | "units" | "threshold">): string;
|
|
329
|
+
/** An intent watch's one line: a Money out clause per asset, else its summary. */
|
|
330
|
+
export declare function intentLine(i: Pick<IntentWatch<unknown>, "kind" | "summary" | "assets">): string;
|
|
318
331
|
/** A subject's status from its rules: live if any is, else paused if all are, else suggested. */
|
|
319
332
|
export declare function subjectStatus(ws: {
|
|
320
333
|
status: WatchStatus;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@secondlayer/sentinel",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Sentinel from a terminal or an agent: the CLI, an MCP server and a client for your Stacks contract monitoring.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "https://runsentinel.app/docs",
|