@secondlayer/sentinel 0.1.0 → 0.2.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.
@@ -2,6 +2,7 @@
2
2
  * Client for the Sentinel v1 API (docs/api.md). Shared by the MCP server and the CLI. No dependencies:
3
3
  * global fetch. Auth is one function, `authHeader`, so another credential can be swapped in later.
4
4
  */
5
+ import type { AlertLevel, FindingKind } from "./kind";
5
6
  export declare const DEFAULT_BASE_URL = "https://api.runsentinel.app";
6
7
  export declare class SentinelError extends Error {
7
8
  readonly status: number;
@@ -47,8 +48,25 @@ export type Finding = {
47
48
  verdict: string;
48
49
  disposition: string;
49
50
  poc?: string;
51
+ /** What the finding is for the people watching (client/kind.ts), stamped by the API. */
52
+ kind?: FindingKind;
53
+ /** How the finding's watch pages; absent on a refuted finding. */
54
+ alertLevel?: AlertLevel;
55
+ reverified?: boolean;
56
+ /** "fn" when `targetFn` names the function; "contract" when no single function carries it. */
57
+ scope?: "fn" | "contract";
58
+ /** Trust findings: the powers held by design, one entry each. */
59
+ powers?: Power[];
60
+ /** The watch row's subject, a short fn-level phrase (verified owners only). */
61
+ watchSubject?: string;
50
62
  [field: string]: unknown;
51
63
  };
64
+ /** One power a trust finding describes (monitoring/adjudication.ts `Power`, copied: no deps). */
65
+ export type Power = {
66
+ holder: string;
67
+ can: string;
68
+ fn?: string;
69
+ };
52
70
  /** A plan at the caller's access level: `access` is absent on the teaser. */
53
71
  export type PlanView = {
54
72
  view: string;
@@ -114,6 +132,11 @@ export type WatchSubject = {
114
132
  } | {
115
133
  kind: "asset";
116
134
  asset: string;
135
+ }
136
+ /** Control changes: one group over every fn that changes who controls the contract. */
137
+ | {
138
+ kind: "group";
139
+ group: "control";
117
140
  };
118
141
  export type WatchStatus = "suggested" | "live" | "paused";
119
142
  export type Units = {
@@ -146,8 +169,57 @@ export type StoredWatch = {
146
169
  updatedAt: string;
147
170
  units: Units | null;
148
171
  };
172
+ export type IntentKind = "money_out" | "control" | "finding" | "owner_fn";
173
+ /**
174
+ * One intent watch: what a team sees (Money out per asset, Control changes, one per finding, a fn the team
175
+ * added). `rows` are the stored watches behind it: what a rule edit, a switch or a mute acts on.
176
+ */
177
+ export type IntentWatch<R = StoredWatch & {
178
+ on: boolean;
179
+ }> = {
180
+ id: string;
181
+ kind: IntentKind;
182
+ title: string;
183
+ tag: string;
184
+ summary: string;
185
+ on: boolean;
186
+ alertLevel: "urgent" | "normal";
187
+ watchIds: string[];
188
+ rows: R[];
189
+ members: {
190
+ group: string;
191
+ fns: string[];
192
+ }[];
193
+ /** Money out: the asset, its token units and its threshold (null amount: every outflow alerts). */
194
+ asset?: string;
195
+ units?: Units | null;
196
+ threshold?: {
197
+ amount: string | null;
198
+ basis: string;
199
+ confirmed: boolean;
200
+ suggested: {
201
+ amount: string;
202
+ basis: string;
203
+ } | null;
204
+ };
205
+ findingRef?: {
206
+ title: string;
207
+ index: number | null;
208
+ };
209
+ };
210
+ /** The stored rows behind a list of intent watches, in order. */
211
+ export declare const rowsOf: <R>(intents: {
212
+ rows: R[];
213
+ }[]) => R[];
149
214
  export type WatchesView = {
150
- watches: StoredWatch[];
215
+ intents: IntentWatch[];
216
+ /** "N of M on", over intent watches. */
217
+ counts: {
218
+ on: number;
219
+ total: number;
220
+ };
221
+ /** Finding-based watches hidden until the account verifies control (a count only). */
222
+ locked: number;
151
223
  events: {
152
224
  id: string;
153
225
  watchId: string;
@@ -167,13 +239,13 @@ export type StartedMonitoring = {
167
239
  contractId: string;
168
240
  planId: string;
169
241
  status: "draft" | "requested" | "live";
170
- watches: StoredWatchView[];
242
+ intents: IntentWatch<StoredWatchView>[];
171
243
  webhookUrl: string | null;
172
244
  slackUrl: string | null;
173
245
  emailAlerts: boolean;
174
246
  hasSigningSecret: boolean;
175
247
  };
176
- type StoredWatchView = Pick<StoredWatch, "id" | "subject" | "rule" | "status" | "title">;
248
+ type StoredWatchView = Pick<StoredWatch, "id" | "subject" | "rule" | "suggestedRule" | "delivery" | "provenance" | "status" | "title" | "reason" | "units">;
177
249
  export type WatchChoice = {
178
250
  watchId?: string;
179
251
  fn: string;
@@ -200,7 +272,8 @@ export type DeliveryResult = {
200
272
  detail: string;
201
273
  };
202
274
  export declare const subjectKey: (s: WatchSubject) => string;
203
- /** The subject's display name: the fn name, or the token's symbol (never the raw token id). */
275
+ export declare const CONTROL_NAME = "Control changes";
276
+ /** The subject's display name: the fn name, the token's symbol (never the raw token id), or the group's. */
204
277
  export declare function subjectName(s: WatchSubject, units: Units | null): string;
205
278
  type HasSubject = {
206
279
  subject: WatchSubject;
@@ -220,7 +293,8 @@ export declare class SubjectError extends Error {
220
293
  export declare function groupSubjects<W extends HasSubject>(watches: W[]): SubjectMatch<W>[];
221
294
  /**
222
295
  * The watches on the subject `name` points at: its display name (fn name, token symbol, or the part
223
- * after `::`), its subjectKey (`fn:…` / `asset:…`) or a full asset id, case-insensitive. A name that
296
+ * after `::`, or "Control changes" / "control"), its subjectKey (`fn:…` / `asset:…` / `group:control`) or a
297
+ * full asset id, case-insensitive. A name that
224
298
  * matches nothing, or more than one subject, throws a SubjectError listing the candidates.
225
299
  */
226
300
  export declare function resolveSubject<W extends HasSubject>(watches: W[], name: string): SubjectMatch<W>;
@@ -231,6 +305,8 @@ export declare function ruleSummary(rule: WatchRule, units: Units | null): strin
231
305
  export type WatchKindTag = "finding" | "outflow" | "who-acts" | "governance" | "upgrade";
232
306
  /** The plain tag a rule is listed under. */
233
307
  export declare function kindTag(rule: WatchRule): WatchKindTag;
308
+ /** An intent watch's one line: a Money out threshold in token units (or its fail-safe), else its summary. */
309
+ export declare function intentLine(i: Pick<IntentWatch<unknown>, "kind" | "summary" | "threshold" | "units">): string;
234
310
  /** A subject's status from its rules: live if any is, else paused if all are, else suggested. */
235
311
  export declare function subjectStatus(ws: {
236
312
  status: WatchStatus;
@@ -355,7 +431,11 @@ export type WatchContext = {
355
431
  contractId: string;
356
432
  /** The plan's access level for this caller; a claimed one hides exploit detail. */
357
433
  access: PlanView["access"];
358
- watches: StoredWatch[];
434
+ intents: IntentWatch[];
435
+ /** The stored rows behind the intents: what subjects resolve over. */
436
+ watches: (StoredWatch & {
437
+ on: boolean;
438
+ })[];
359
439
  };
360
440
  /** The caller's watches for a plan. */
361
441
  export declare function watchContext(client: SentinelClient, planId: string): Promise<WatchContext>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@secondlayer/sentinel",
3
- "version": "0.1.0",
3
+ "version": "0.2.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",