@mattstack/rt-client 0.2.0 → 0.4.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/README.md CHANGED
@@ -17,8 +17,11 @@ const repos = await rtCommand(['repos', 'list']);
17
17
  const mrs = await readProjectMRs('group/repo');
18
18
  ```
19
19
 
20
- Requires a running rt daemon. Install rt with `brew install m4ttheweric/tap/rt`,
21
- then `rt verify`.
20
+ Requires a running rt daemon. Install rt from the latest GitHub Release
21
+ (`./rt --post-install`), then `rt verify`.
22
+
23
+ Bun-only: the settings exec path (`src/settings/exec.ts`) shells out via
24
+ `Bun.spawn`, so this package does not run under Node.
22
25
 
23
26
  `@mattstack/glance` is a peer dependency: rt-client returns glance's forge types
24
27
  so merge request shapes stay identical across rt, gitq, and mr-board.
package/dist/client.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { RtResponse, RtClientOptions } from "./transport.ts";
2
- import type { DemandDecl, ProjectMRsData, DiscussionsData, MrByBranchData, ForgeSlug, ForgeTokenData } from "./commands.ts";
2
+ import type { DemandDecl, ProjectMRsData, DiscussionsData, MrByBranchData, ForgeSlug, ForgeTokenData, RunSummary, RunDetail, WakeMode, ChatMember, ChatMessage, RoomSummary } from "./commands.ts";
3
3
  /**
4
4
  * One repo's project open-MR store. A cold repo forces a full paginated sync
5
5
  * on the daemon side when maxAgeMs demands it, which can run tens of seconds
@@ -18,6 +18,97 @@ export declare function readMrsByBranch(repoName: string, branches: string[], op
18
18
  * side: an untracked repo comes back `ok: false` with the `rt daemon track`
19
19
  * command to run, which is the fail-closed shape callers should surface
20
20
  * verbatim. Callers keep env-var precedence on their own side; this is the
21
- * fallback that replaces reading ~/.rt/secrets.json directly.
21
+ * fallback that replaces reading ~/.mattstack/rt/secrets.json directly.
22
22
  */
23
23
  export declare function resolveForgeToken(repoName: string, forge: ForgeSlug, opts?: RtClientOptions): Promise<RtResponse<ForgeTokenData>>;
24
+ export declare function listRuns(repo?: string, opts?: RtClientOptions): Promise<RtResponse<{
25
+ runs: RunSummary[];
26
+ }>>;
27
+ export declare function getRun(runId: string, repo?: string, opts?: RtClientOptions): Promise<RtResponse<RunDetail>>;
28
+ /**
29
+ * SKILLS-54. rt's only write path into run state, so a wedged run can be
30
+ * resolved by a person instead of lying in the data forever. The write happens
31
+ * in the daemon and is attributed there; consumers never touch the run DB.
32
+ */
33
+ export declare function abandonRun(runId: string, repo?: string, reason?: string, opts?: RtClientOptions): Promise<RtResponse<{
34
+ ok: boolean;
35
+ }>>;
36
+ export declare function chatJoin(a: {
37
+ room: string;
38
+ handle: string;
39
+ wakeOn?: WakeMode;
40
+ cwd?: string;
41
+ pane?: string;
42
+ }, o?: RtClientOptions): Promise<RtResponse<{
43
+ handle: string;
44
+ memberCount: number;
45
+ unread: number;
46
+ }>>;
47
+ export declare function chatLeave(a: {
48
+ room: string;
49
+ handle: string;
50
+ }, o?: RtClientOptions): Promise<RtResponse<Record<string, never>>>;
51
+ export declare function chatPost(a: {
52
+ room: string;
53
+ handle: string;
54
+ body: string;
55
+ }, o?: RtClientOptions): Promise<RtResponse<{
56
+ id: number;
57
+ recipients: string[];
58
+ }>>;
59
+ export declare function chatRead(a: {
60
+ handle: string;
61
+ room?: string;
62
+ limit?: number;
63
+ sinceMs?: number;
64
+ }, o?: RtClientOptions): Promise<RtResponse<{
65
+ rooms: {
66
+ room: string;
67
+ messages: ChatMessage[];
68
+ }[];
69
+ }>>;
70
+ export declare function chatRooms(a: {
71
+ handle: string;
72
+ }, o?: RtClientOptions): Promise<RtResponse<{
73
+ rooms: RoomSummary[];
74
+ }>>;
75
+ export declare function chatWho(a: {
76
+ room: string;
77
+ }, o?: RtClientOptions): Promise<RtResponse<{
78
+ members: ChatMember[];
79
+ }>>;
80
+ export declare function chatMark(a: {
81
+ handle: string;
82
+ room?: string;
83
+ }, o?: RtClientOptions): Promise<RtResponse<Record<string, never>>>;
84
+ export declare function chatMessages(a: {
85
+ room: string;
86
+ before?: number;
87
+ limit?: number;
88
+ }, o?: RtClientOptions): Promise<RtResponse<{
89
+ messages: ChatMessage[];
90
+ }>>;
91
+ export declare function chatArm(a: {
92
+ handle: string;
93
+ room?: string;
94
+ }, o?: RtClientOptions): Promise<RtResponse<Record<string, never>>>;
95
+ export declare function chatTouch(a: {
96
+ handle: string;
97
+ }, o?: RtClientOptions): Promise<RtResponse<Record<string, never>>>;
98
+ export declare function chatDisarm(a: {
99
+ handle: string;
100
+ }, o?: RtClientOptions): Promise<RtResponse<Record<string, never>>>;
101
+ export declare function chatUnreadWaking(a: {
102
+ handle: string;
103
+ room?: string;
104
+ }, o?: RtClientOptions): Promise<RtResponse<{
105
+ rooms: {
106
+ room: string;
107
+ count: number;
108
+ mentions: number;
109
+ maxId: number;
110
+ }[];
111
+ }>>;
112
+ export declare function eventsHead(o?: RtClientOptions): Promise<RtResponse<{
113
+ cursor: number;
114
+ }>>;
@@ -45,6 +45,106 @@ export type ForgeSlug = "gitlab" | "github";
45
45
  export interface ForgeTokenData {
46
46
  token: string;
47
47
  }
48
+ /**
49
+ * Duplicated shape on purpose (RT-44): rt-client cannot import daemon
50
+ * internals, so this mirrors lib/daemon/events-bus.ts's BusEvent.
51
+ */
52
+ export interface EventsBusEvent {
53
+ id: number;
54
+ topic: string;
55
+ payload: unknown;
56
+ emittedAt: number;
57
+ }
58
+ /**
59
+ * Duplicated shape on purpose, same reasoning as EventsBusEvent above:
60
+ * these mirror lib/state/chat-store.ts's types, which rt-client cannot
61
+ * import (it's outside lib/state/ and outside this package entirely).
62
+ */
63
+ export type WakeMode = "mention" | "all" | "none";
64
+ export interface ChatMember {
65
+ room: string;
66
+ handle: string;
67
+ joinedAt: number;
68
+ lastReadId: number;
69
+ wakeOn: WakeMode;
70
+ lastSeenAt?: number;
71
+ armedAt?: number;
72
+ cwd?: string;
73
+ pane?: string;
74
+ }
75
+ export interface ChatMessage {
76
+ id: number;
77
+ room: string;
78
+ handle: string;
79
+ body: string;
80
+ mentions: string[];
81
+ replyTo?: number;
82
+ postedAt: number;
83
+ }
84
+ export interface RoomSummary {
85
+ room: string;
86
+ memberCount: number;
87
+ unread: number;
88
+ mentions: number;
89
+ lastPostedAt?: number;
90
+ }
91
+ export type Attention = {
92
+ needs: boolean;
93
+ reason: "failed" | "stale" | "stranded" | null;
94
+ evidence: string;
95
+ };
96
+ export interface RunSummary {
97
+ id: string;
98
+ repo: string;
99
+ work_type: string;
100
+ pipeline: string;
101
+ status: string;
102
+ current_stage: string | null;
103
+ spawned_by: string | null;
104
+ started_at: number;
105
+ ended_at: number | null;
106
+ pack_commits: string | null;
107
+ pack_dirty: number;
108
+ attention: Attention;
109
+ /** Max over stage, field, and decision timestamps; falls back to
110
+ `started_at` when the run has produced no events yet. The board orders
111
+ by silence, so this — not `started_at` — is its sort key. */
112
+ last_event_at: number;
113
+ /** Denormalized from the run's `ticket` / `branch` fields so the LIST view
114
+ can render and search them without a detail fetch per row. Null when
115
+ the run has not produced that field yet. */
116
+ ticket: string | null;
117
+ branch: string | null;
118
+ }
119
+ export interface RunStageRow {
120
+ name: string;
121
+ status: string;
122
+ attempt: number;
123
+ started_at: number | null;
124
+ ended_at: number | null;
125
+ reason: string | null;
126
+ detail_path: string | null;
127
+ }
128
+ export interface RunFieldRow {
129
+ key: string;
130
+ value: string;
131
+ produced_by: string;
132
+ at: number;
133
+ }
134
+ export interface RunDecisionRow {
135
+ contract: string;
136
+ scope: string;
137
+ selection: string;
138
+ decided_by: string;
139
+ decided_at: number;
140
+ }
141
+ export interface RunDetail {
142
+ run: RunSummary;
143
+ stages: RunStageRow[];
144
+ fields: RunFieldRow[];
145
+ decisions: RunDecisionRow[];
146
+ schemaAhead: boolean;
147
+ }
48
148
  export interface Commands {
49
149
  "project-mrs:read": {
50
150
  payload: {
@@ -71,7 +171,7 @@ export interface Commands {
71
171
  /**
72
172
  * The forge token for one tracked repo (MAT-33). Repo-scoped on purpose:
73
173
  * rt gates access per repo through repo-tracking.json, and this verb is
74
- * what lets consumers stop reading ~/.rt/secrets.json directly, which
174
+ * what lets consumers stop reading ~/.mattstack/rt/secrets.json directly, which
75
175
  * walked around that grant model entirely. An untracked repo is refused;
76
176
  * the caller's env vars keep precedence on the caller's side.
77
177
  */
@@ -82,6 +182,223 @@ export interface Commands {
82
182
  };
83
183
  data: ForgeTokenData;
84
184
  };
185
+ /**
186
+ * A per-`scope` whitelisted subset of secrets, each scope reading its own
187
+ * encrypted domain(s): "extension" (default, so the VS Code extension
188
+ * needs no change) is linearApiKey/gitlabToken from the `rt` domain;
189
+ * "deck" is cfApiToken/cfZoneId from the `deck` domain; "board" is
190
+ * cross-domain — slackToken/slackClientSecret/slackSigningSecret from the
191
+ * `board` domain plus gitlabToken/switchboardToken/switchboardAdminToken
192
+ * from the `rt` domain. `data` is a union of the per-scope shapes, not a
193
+ * merged bag of every key — that makes a caller narrowing on the wrong
194
+ * scope's fields a compile error instead of a silent `undefined`. Every
195
+ * key optional (present only when set). Not a general secrets export —
196
+ * extend a whitelist here, in lockstep with
197
+ * lib/daemon/handlers/secrets.ts and (for "extension")
198
+ * extensions/vscode/rt-context/src/secrets.ts, if a consumer needs another
199
+ * key.
200
+ *
201
+ * `token` is required and checked in the HANDLER (not a transport-layer
202
+ * gate alone), since this verb is reachable over the unauthenticated unix
203
+ * socket too — see lib/daemon/handlers/secrets.ts's doc comment. HTTP
204
+ * callers get it forwarded automatically from their X-RT-Token header;
205
+ * socket callers must read ~/.mattstack/rt/api-token themselves. The gate
206
+ * applies identically to every scope.
207
+ */
208
+ "secrets:read": {
209
+ payload: {
210
+ token?: string;
211
+ scope?: "extension" | "deck" | "board";
212
+ };
213
+ data: {
214
+ linearApiKey?: string;
215
+ gitlabToken?: string;
216
+ } | {
217
+ cfApiToken?: string;
218
+ cfZoneId?: string;
219
+ } | {
220
+ slackToken?: string;
221
+ slackClientSecret?: string;
222
+ slackSigningSecret?: string;
223
+ gitlabToken?: string;
224
+ switchboardToken?: string;
225
+ switchboardAdminToken?: string;
226
+ };
227
+ };
228
+ "events:emit": {
229
+ payload: {
230
+ topic: string;
231
+ payload?: unknown;
232
+ };
233
+ data: {
234
+ id: number;
235
+ };
236
+ };
237
+ "events:wait": {
238
+ payload: {
239
+ pattern: string;
240
+ after?: number;
241
+ waitMs?: number;
242
+ };
243
+ data: {
244
+ events: EventsBusEvent[];
245
+ cursor: number;
246
+ };
247
+ };
248
+ "events:list": {
249
+ payload: {
250
+ pattern: string;
251
+ after?: number;
252
+ limit?: number;
253
+ };
254
+ data: {
255
+ events: EventsBusEvent[];
256
+ cursor: number;
257
+ };
258
+ };
259
+ "events:head": {
260
+ payload: Record<string, never>;
261
+ data: {
262
+ cursor: number;
263
+ };
264
+ };
265
+ "runs:list": {
266
+ payload: {
267
+ repo?: string;
268
+ };
269
+ data: {
270
+ runs: RunSummary[];
271
+ };
272
+ };
273
+ "runs:get": {
274
+ payload: {
275
+ runId: string;
276
+ repo?: string;
277
+ };
278
+ data: RunDetail;
279
+ };
280
+ "runs:abandon": {
281
+ payload: {
282
+ runId: string;
283
+ repo?: string;
284
+ reason?: string;
285
+ };
286
+ data: {
287
+ ok: boolean;
288
+ };
289
+ };
290
+ "chat:join": {
291
+ payload: {
292
+ room: string;
293
+ handle: string;
294
+ wakeOn?: WakeMode;
295
+ cwd?: string;
296
+ pane?: string;
297
+ };
298
+ data: {
299
+ handle: string;
300
+ memberCount: number;
301
+ unread: number;
302
+ };
303
+ };
304
+ "chat:leave": {
305
+ payload: {
306
+ room: string;
307
+ handle: string;
308
+ };
309
+ data: Record<string, never>;
310
+ };
311
+ "chat:post": {
312
+ payload: {
313
+ room: string;
314
+ handle: string;
315
+ body: string;
316
+ };
317
+ data: {
318
+ id: number;
319
+ recipients: string[];
320
+ };
321
+ };
322
+ "chat:read": {
323
+ payload: {
324
+ handle: string;
325
+ room?: string;
326
+ limit?: number;
327
+ sinceMs?: number;
328
+ };
329
+ data: {
330
+ rooms: {
331
+ room: string;
332
+ messages: ChatMessage[];
333
+ }[];
334
+ };
335
+ };
336
+ "chat:rooms": {
337
+ payload: {
338
+ handle: string;
339
+ };
340
+ data: {
341
+ rooms: RoomSummary[];
342
+ };
343
+ };
344
+ "chat:who": {
345
+ payload: {
346
+ room: string;
347
+ };
348
+ data: {
349
+ members: ChatMember[];
350
+ };
351
+ };
352
+ "chat:mark": {
353
+ payload: {
354
+ handle: string;
355
+ room?: string;
356
+ };
357
+ data: Record<string, never>;
358
+ };
359
+ "chat:messages": {
360
+ payload: {
361
+ room: string;
362
+ before?: number;
363
+ limit?: number;
364
+ };
365
+ data: {
366
+ messages: ChatMessage[];
367
+ };
368
+ };
369
+ "chat:arm": {
370
+ payload: {
371
+ handle: string;
372
+ room?: string;
373
+ };
374
+ data: Record<string, never>;
375
+ };
376
+ "chat:touch": {
377
+ payload: {
378
+ handle: string;
379
+ };
380
+ data: Record<string, never>;
381
+ };
382
+ "chat:disarm": {
383
+ payload: {
384
+ handle: string;
385
+ };
386
+ data: Record<string, never>;
387
+ };
388
+ "chat:unread-waking": {
389
+ payload: {
390
+ handle: string;
391
+ room?: string;
392
+ };
393
+ data: {
394
+ rooms: {
395
+ room: string;
396
+ count: number;
397
+ mentions: number;
398
+ maxId: number;
399
+ }[];
400
+ };
401
+ };
85
402
  }
86
403
  export type CommandName = keyof Commands;
87
404
  export declare const COMMAND_NAMES: readonly CommandName[];
package/dist/index.d.ts CHANGED
@@ -1,8 +1,18 @@
1
1
  export { rtCommand, DEFAULT_SOCK } from "./transport.ts";
2
2
  export type { RtResponse, RtClientOptions } from "./transport.ts";
3
- export { readProjectMRs, readDiscussions, readMrsByBranch, resolveForgeToken } from "./client.ts";
3
+ export { readProjectMRs, readDiscussions, readMrsByBranch, resolveForgeToken, listRuns, getRun, abandonRun, chatJoin, chatLeave, chatPost, chatRead, chatRooms, chatWho, chatMark, chatMessages, chatArm, chatTouch, chatDisarm, chatUnreadWaking, eventsHead, } from "./client.ts";
4
4
  export { COMMAND_NAMES } from "./commands.ts";
5
- export type { Discussion, DemandDecl, ProjectMRsScope, ProjectMRsData, DiscussionsData, MrByBranchEntry, MrByBranchData, Commands, CommandName, ForgeSlug, ForgeTokenData, } from "./commands.ts";
5
+ export type { Discussion, DemandDecl, ProjectMRsScope, ProjectMRsData, DiscussionsData, MrByBranchEntry, MrByBranchData, Commands, CommandName, ForgeSlug, ForgeTokenData, Attention, RunSummary, RunStageRow, RunFieldRow, RunDecisionRow, RunDetail, WakeMode, ChatMember, ChatMessage, RoomSummary, } from "./commands.ts";
6
6
  export { subscribe, DEFAULT_WS_URL } from "./relay.ts";
7
7
  export type { RelayEventType } from "./relay.ts";
8
8
  export { repoNameForPath } from "./repos.ts";
9
+ export { getSetting, listSettings, explainSetting, expandVariables, SCOPE_ORDER } from "./settings/resolve.ts";
10
+ export type { Scope, Provenance, ResolveOpts, Resolved, InvalidScope, ListedSetting, ExplainRow, ExpandCtx, } from "./settings/resolve.ts";
11
+ export { setSetting } from "./settings/write.ts";
12
+ export type { SetSettingOpts } from "./settings/write.ts";
13
+ export { getDef, allDefs, validateValue, isMigrated } from "./settings/registry-machinery.ts";
14
+ export type { SettingDef, SettingScope } from "./settings/registry-machinery.ts";
15
+ export { REGISTRY } from "./settings/registry-defs.ts";
16
+ export { readStore, listTeams } from "./settings/stores.ts";
17
+ export type { StoreFile } from "./settings/stores.ts";
18
+ export { normalizeRemote, identityFromRemote, deriveRepoIdentity, clearIdentityMemo, serializeIdentity, parseIdentity, resolveNameToIdentity, type RepoIdentity, } from "./settings/identity.ts";