dsh-perm-gate 0.2.0 → 0.2.1-beta.2

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/lib/events.d.ts CHANGED
@@ -5,12 +5,30 @@ export interface GateEvent {
5
5
  readonly ts: string;
6
6
  readonly sessionId: string;
7
7
  readonly tool: string;
8
- /** auto = allowed (rule/grant/llm), ask = routed to the human, deny = vetoed, learned = confirmation settled. */
9
- readonly kind: 'auto' | 'ask' | 'deny' | 'learned';
8
+ /**
9
+ * auto = allowed (rule/grant/llm), ask = routed to the human, deny = vetoed,
10
+ * learned = confirmation settled, manual-* = the human's terminal answer to an
11
+ * ask (approved / rejected / cancelled).
12
+ */
13
+ readonly kind: 'auto' | 'ask' | 'deny' | 'learned' | 'manual-approved' | 'manual-rejected' | 'manual-cancelled';
10
14
  /** Risk category when an LLM verdict contributed to the decision. */
11
15
  readonly risk?: string;
12
16
  /** Truncated decision reason. */
13
17
  readonly reason: string;
18
+ /** Decision path label (rule / grant / learned / llm-assist …) — the history tag. */
19
+ readonly verdict?: string;
20
+ /** The model's stated intent (justification) when one was available. */
21
+ readonly justification?: string;
22
+ /** Sandbox mode involved in the decision, when known. */
23
+ readonly mode?: string;
24
+ /** Risk category name (deletion / credential / neutral …) when classified. */
25
+ readonly category?: string;
26
+ /** Files the decision concerns (absolute, workspace-relative, or bare names). */
27
+ readonly files?: readonly string[];
28
+ /** Human confirmations so far for the learned key (manual-approve events). */
29
+ readonly learningCount?: number;
30
+ /** Confirmations required before that key auto-allows (manual-approve events). */
31
+ readonly threshold?: number;
14
32
  }
15
33
  export interface GateEventInput {
16
34
  readonly sessionId?: string;
@@ -18,15 +36,72 @@ export interface GateEventInput {
18
36
  readonly kind: GateEvent['kind'];
19
37
  readonly risk?: string;
20
38
  readonly reason: string;
39
+ readonly verdict?: string;
40
+ readonly justification?: string;
41
+ readonly mode?: string;
42
+ readonly category?: string;
43
+ readonly files?: readonly string[];
44
+ readonly learningCount?: number;
45
+ readonly threshold?: number;
46
+ /** Session working directory, used to resolve relative snapshot paths. */
47
+ readonly baseDir?: string;
21
48
  }
49
+ /** Read one file as snapshot text; null when unreadable, binary, or oversized. */
50
+ export declare function readSnapshotFile(absPath: string): string | null;
51
+ /**
52
+ * Resolve a path from a decision into an absolute path: `~` expands to home,
53
+ * absolute paths pass through, relative paths try the session cwd, the process
54
+ * cwd, then home (first existing wins; otherwise the first candidate).
55
+ */
56
+ export declare function resolveAbsPath(p: string, baseDir?: string): string;
57
+ export interface EventSnapshot {
58
+ readonly path: string;
59
+ readonly content: string;
60
+ readonly ts: string;
61
+ }
62
+ /** Write the pre-change snapshot of every file one event touched. */
63
+ export declare function saveEventSnapshots(dir: string, eventId: number, files: readonly string[], baseDir: string | undefined, sessionId: string, now?: () => number): void;
64
+ /** Load one event's snapshots ([] when absent or corrupt). */
65
+ export declare function loadEventSnapshots(dir: string, eventId: number): EventSnapshot[];
66
+ export interface DiffLine {
67
+ readonly type: 'same' | 'add' | 'del';
68
+ readonly aNo?: number;
69
+ readonly bNo?: number;
70
+ readonly text: string;
71
+ }
72
+ export interface DiffHunk {
73
+ readonly hiddenBefore: number;
74
+ readonly lines: readonly DiffLine[];
75
+ }
76
+ export interface DiffStats {
77
+ readonly added: number;
78
+ readonly removed: number;
79
+ readonly contextLines: number;
80
+ }
81
+ export interface DiffResult {
82
+ readonly hunks: readonly DiffHunk[];
83
+ readonly stats: DiffStats;
84
+ readonly changedLines: readonly DiffLine[];
85
+ }
86
+ /**
87
+ * Line-level diff with context: a greedy in-order LCS approximation (each `a`
88
+ * line matches the next unused equal `b` line), then change windows of ±`CTX`
89
+ * context lines clustered into hunks. Ported from dsh-approval-gate so both
90
+ * review pages render identical diffs.
91
+ */
92
+ export declare function diffLines(before: string | null | undefined, after: string | null | undefined, contextLines?: number): DiffResult;
22
93
  export declare class EventLog {
23
94
  /** JSONL path; `undefined` disables event recording entirely. */
24
95
  private readonly filePath;
25
96
  private readonly now;
97
+ /** Snapshot directory; `undefined` disables diff/revert support. */
98
+ private readonly snapshotsDir;
26
99
  private seq;
27
100
  constructor(
28
101
  /** JSONL path; `undefined` disables event recording entirely. */
29
- filePath: string | undefined, now?: () => number);
102
+ filePath: string | undefined, now?: () => number,
103
+ /** Snapshot directory; `undefined` disables diff/revert support. */
104
+ snapshotsDir?: string | undefined);
30
105
  /** Append one event; returns it, or undefined when recording is disabled/failed. */
31
106
  append(input: GateEventInput): GateEvent | undefined;
32
107
  /** Events with `id > since`, optionally filtered to one session. */
@@ -34,6 +109,8 @@ export declare class EventLog {
34
109
  sessionId?: string;
35
110
  since?: number;
36
111
  }): GateEvent[];
112
+ /** One event by id (undefined when absent). */
113
+ byId(id: number): GateEvent | undefined;
37
114
  private nextId;
38
115
  }
39
116
  /**
@@ -48,9 +125,68 @@ export interface WebServerLike {
48
125
  }): () => void;
49
126
  }
50
127
  export declare const EVENTS_ROUTE = "/api/dsh-perm-gate/events";
128
+ export declare const LEARNING_ROUTE = "/api/dsh-perm-gate/learning";
129
+ export declare const HEALTH_ROUTE = "/api/dsh-perm-gate/health";
130
+ export declare const RECEIVER_ROUTE = "/api/dsh-perm-gate/receiver";
131
+ export declare const DIFF_ROUTE = "/api/dsh-perm-gate/diff";
132
+ export declare const REVERT_ROUTE = "/api/dsh-perm-gate/revert";
133
+ export declare const SNAPSHOTS_STATS_ROUTE = "/api/dsh-perm-gate/snapshots-stats";
134
+ export declare const SNAPSHOTS_CLEAR_ROUTE = "/api/dsh-perm-gate/snapshots-clear";
51
135
  /**
52
136
  * Register `GET /api/dsh-perm-gate/events?sessionId=&since=` on the webServer
53
137
  * service. Returns whether the route was registered (false when the service is
54
138
  * unavailable — the host keeps running, only the HTTP API is missing).
55
139
  */
56
- export declare function registerEventsRoute(server: unknown, log: EventLog): boolean;
140
+ export declare function registerEventsRoute(server: unknown, log: EventLog): (() => void) | undefined;
141
+ /** Delivers a revert instruction into the conversation (see index.ts wiring). */
142
+ export type SessionSender = (sessionId: string, content: string) => Promise<{
143
+ ok: boolean;
144
+ via?: string;
145
+ error?: string;
146
+ }>;
147
+ /**
148
+ * Register the review-page routes:
149
+ * `GET /diff?eventId=&path=` → before/after line diff for one file
150
+ * `POST /revert` → deliver a revert instruction into the session
151
+ * `GET /snapshots-stats?sessionId=` → snapshot count/bytes/ids/file map
152
+ * `POST /snapshots-clear` → drop snapshots (session-scoped or all)
153
+ */
154
+ export declare function registerReviewRoutes(server: unknown, deps: {
155
+ log: EventLog;
156
+ snapshotsDir: string | undefined;
157
+ send: SessionSender;
158
+ audit?: (line: string) => void;
159
+ }): (() => void)[];
160
+ /**
161
+ * Register `GET /api/dsh-perm-gate/receiver` — the receiver projection for the
162
+ * settings card: the effective provider/model plus (host mode) the live
163
+ * provider/model-group catalog from the DSH `llm` service.
164
+ */
165
+ export declare function registerReceiverRoute(server: unknown, provider: {
166
+ info(): Promise<unknown>;
167
+ }): (() => void) | undefined;
168
+ /**
169
+ * Register `POST /api/dsh-perm-gate/health` — runs one minimal completion
170
+ * through the currently configured llmAssist receiver and returns
171
+ * `{ ok, ms, detail }` (the settings card's health test).
172
+ */
173
+ export declare function registerHealthRoute(server: unknown, provider: {
174
+ check(): Promise<{
175
+ ok: boolean;
176
+ ms: number;
177
+ detail: string;
178
+ }>;
179
+ }): (() => void) | undefined;
180
+ /** The learning-store face the settings UI's sediment view needs. */
181
+ export interface LearningRouteProvider {
182
+ snapshot(): unknown;
183
+ threshold(): number;
184
+ reset(key: string, fp?: string): void;
185
+ }
186
+ /**
187
+ * Register the learning-store routes on the webServer service:
188
+ * `GET /api/dsh-perm-gate/learning` → the store snapshot + live threshold,
189
+ * `POST /api/dsh-perm-gate/learning` → `{ key, fp? }` terminates one key's
190
+ * learning or drops one sedimented sample. Returns whether registered.
191
+ */
192
+ export declare function registerLearningRoute(server: unknown, provider: LearningRouteProvider): (() => void) | undefined;