@mattstack/rt-client 0.6.1 → 0.7.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 +39 -0
- package/dist/client.d.ts +36 -1
- package/dist/commands.d.ts +175 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +146 -7
- package/package.json +1 -1
- package/src/client.ts +102 -3
- package/src/commands.ts +64 -2
- package/src/index.ts +19 -0
- package/src/settings/registry-defs.ts +52 -5
package/README.md
CHANGED
|
@@ -74,6 +74,45 @@ doesn't error, it resolves empty. `parseIdentity` is strict — only strings
|
|
|
74
74
|
`serializeIdentity` emitted parse — so validate payloads with it, and never
|
|
75
75
|
hand-assemble or string-split a wire.
|
|
76
76
|
|
|
77
|
+
## Chat
|
|
78
|
+
|
|
79
|
+
The `rt chat` surface the chat viewer (`~/Documents/GitHub/chat`) is built
|
|
80
|
+
on. Every call degrades to `{ ok: false, error }` instead of throwing, and a
|
|
81
|
+
daemon that is down and a daemon that refused look the same to the caller;
|
|
82
|
+
branch on `ok`, not on exceptions.
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
import { chatRooms, chatMessages, chatPost, createRelay, daemonHealth } from '@mattstack/rt-client';
|
|
86
|
+
|
|
87
|
+
const rooms = await chatRooms({ handle: 'matt' }); // { ok, data: { rooms } }
|
|
88
|
+
const page = await chatMessages({ room: 'build', limit: 50 }); // newest page; `before: <id>` pages older
|
|
89
|
+
await chatPost({ handle: 'matt', room: 'build', body: 'on it' });
|
|
90
|
+
|
|
91
|
+
const health = await daemonHealth(); // { reachable, error? }, never throws
|
|
92
|
+
const stop = createRelay({ // one daemon subscription, republished
|
|
93
|
+
match: t => t.startsWith('chat/'), // `chat/<room>/msg`, `chat/wake/<handle>`
|
|
94
|
+
topic: 'chat',
|
|
95
|
+
publish: (topic, data) => server.publish(topic, data),
|
|
96
|
+
});
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
| Function | Daemon verb |
|
|
100
|
+
| --- | --- |
|
|
101
|
+
| `chatSignIn` / `chatSignOut` / `chatAway` / `chatBack` / `chatPulse` | presence: the buddy-list row and its heartbeats |
|
|
102
|
+
| `chatBuddies` / `chatWho` / `chatRooms` | the roster, one room's members, a handle's rooms |
|
|
103
|
+
| `chatJoin` / `chatLeave` / `chatArchive` | membership (`wakeOn: mention \| all \| none`); archive parks a room for everyone until a post revives it |
|
|
104
|
+
| `chatPost` / `chatDm` / `chatDmOpen` / `chatRead` / `chatMessages` / `chatMark` | messages: post, DM, open a DM room without posting, read-and-advance, page, advance the cursor |
|
|
105
|
+
| `chatArm` / `chatTouch` / `chatDisarm` / `chatUnreadWaking` | the tail's wake protocol; the CLI's `rt chat tail` uses these |
|
|
106
|
+
| `paneList` / `panePeek` / `paneSpawn` / `paneAccounts` / `paneDirectories` | herdr panes: list with presence joined, peek a screen, start claude in a tab, cswap accounts, directory suggestions |
|
|
107
|
+
| `chatInvite` | type `/chat:join <room>` into a pane; `accepted`, `queued` or `refused` |
|
|
108
|
+
| `createRelay` / `subscribe` | the event stream; `daemonHealth` the reachability probe |
|
|
109
|
+
|
|
110
|
+
Pass `{ sockPath }` as the trailing options to reach a non-default daemon
|
|
111
|
+
socket. The verbs, their payloads and the wake protocol are specified in
|
|
112
|
+
repo-tools `docs/superpowers/specs/2026-08-23-rt-chat-design.md` and
|
|
113
|
+
`2026-08-24-rt-chat-presence-design.md`; the agent-facing rules are
|
|
114
|
+
`skills/rt-chat/SKILL.md`.
|
|
115
|
+
|
|
77
116
|
## License
|
|
78
117
|
|
|
79
118
|
MIT
|
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, BranchEnrichment, ForgeSlug, ForgeTokenData, RunSummary, RunDetail, WakeMode, ChatMember, ChatMessage, RoomSummary, BuddyStatus, PresenceRow } from "./commands.ts";
|
|
2
|
+
import type { DemandDecl, ProjectMRsData, DiscussionsData, MrByBranchData, BranchEnrichment, ForgeSlug, ForgeTokenData, RunSummary, RunDetail, WakeMode, ChatMember, ChatMessage, RoomSummary, BuddyStatus, PresenceRow, AgentRecord, Commands } 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
|
|
@@ -76,6 +76,7 @@ export declare function chatRead(a: {
|
|
|
76
76
|
}>>;
|
|
77
77
|
export declare function chatRooms(a: {
|
|
78
78
|
handle: string;
|
|
79
|
+
includeArchived?: boolean;
|
|
79
80
|
}, o?: RtClientOptions): Promise<RtResponse<{
|
|
80
81
|
rooms: RoomSummary[];
|
|
81
82
|
}>>;
|
|
@@ -102,6 +103,7 @@ export declare function chatArm(a: {
|
|
|
102
103
|
}, o?: RtClientOptions): Promise<RtResponse<Record<string, never>>>;
|
|
103
104
|
export declare function chatTouch(a: {
|
|
104
105
|
handle: string;
|
|
106
|
+
room?: string;
|
|
105
107
|
sessionId?: string;
|
|
106
108
|
}, o?: RtClientOptions): Promise<RtResponse<Record<string, never>>>;
|
|
107
109
|
export declare function chatDisarm(a: {
|
|
@@ -170,6 +172,39 @@ export declare function chatDm(a: {
|
|
|
170
172
|
id: number;
|
|
171
173
|
recipients: string[];
|
|
172
174
|
}>>;
|
|
175
|
+
export declare function chatArchive(a: {
|
|
176
|
+
room: string;
|
|
177
|
+
handle: string;
|
|
178
|
+
archived: boolean;
|
|
179
|
+
}, o?: RtClientOptions): Promise<RtResponse<{
|
|
180
|
+
room: string;
|
|
181
|
+
archivedAt: number | null;
|
|
182
|
+
}>>;
|
|
183
|
+
export declare function chatDmOpen(a: {
|
|
184
|
+
from: string;
|
|
185
|
+
to: string;
|
|
186
|
+
sessionId?: string;
|
|
187
|
+
}, o?: RtClientOptions): Promise<RtResponse<{
|
|
188
|
+
room: string;
|
|
189
|
+
created: boolean;
|
|
190
|
+
}>>;
|
|
173
191
|
export declare function eventsHead(o?: RtClientOptions): Promise<RtResponse<{
|
|
174
192
|
cursor: number;
|
|
175
193
|
}>>;
|
|
194
|
+
export declare function agentStart(a: Commands["agent:start"]["payload"], o?: RtClientOptions): Promise<RtResponse<AgentRecord>>;
|
|
195
|
+
export declare function agentResume(a: Commands["agent:resume"]["payload"], o?: RtClientOptions): Promise<RtResponse<AgentRecord>>;
|
|
196
|
+
export declare function agentGet(a: {
|
|
197
|
+
id: string;
|
|
198
|
+
}, o?: RtClientOptions): Promise<RtResponse<AgentRecord>>;
|
|
199
|
+
export declare function agentList(a: {
|
|
200
|
+
repo?: string;
|
|
201
|
+
}, o?: RtClientOptions): Promise<RtResponse<{
|
|
202
|
+
agents: AgentRecord[];
|
|
203
|
+
}>>;
|
|
204
|
+
export declare function paneList(o?: RtClientOptions): Promise<RtResponse<Commands["pane:list"]["data"]>>;
|
|
205
|
+
export declare function panePeek(a: Commands["pane:peek"]["payload"], o?: RtClientOptions): Promise<RtResponse<Commands["pane:peek"]["data"]>>;
|
|
206
|
+
/** The spawn waits on claude starting, so its budget is minutes, not seconds. */
|
|
207
|
+
export declare function paneSpawn(a: Commands["pane:spawn"]["payload"], o?: RtClientOptions): Promise<RtResponse<Commands["pane:spawn"]["data"]>>;
|
|
208
|
+
export declare function paneAccounts(o?: RtClientOptions): Promise<RtResponse<Commands["pane:accounts"]["data"]>>;
|
|
209
|
+
export declare function paneDirectories(a: Commands["pane:directories"]["payload"], o?: RtClientOptions): Promise<RtResponse<Commands["pane:directories"]["data"]>>;
|
|
210
|
+
export declare function chatInvite(a: Commands["chat:invite"]["payload"], o?: RtClientOptions): Promise<RtResponse<Commands["chat:invite"]["data"]>>;
|
package/dist/commands.d.ts
CHANGED
|
@@ -129,6 +129,8 @@ export interface RoomSummary {
|
|
|
129
129
|
};
|
|
130
130
|
/** Set only by chat:rooms's left join against chat_room_defaults; undefined for a room never stamped a default (every DM room included). */
|
|
131
131
|
defaultWake?: WakeMode;
|
|
132
|
+
/** Set only when chat:rooms was asked for archived rooms; absent on an open room. */
|
|
133
|
+
archivedAt?: number;
|
|
132
134
|
}
|
|
133
135
|
/**
|
|
134
136
|
* Duplicated shape on purpose, same reasoning as ChatMember/ChatMessage
|
|
@@ -151,6 +153,39 @@ export interface PresenceRow {
|
|
|
151
153
|
armedAt?: number;
|
|
152
154
|
signedOutAt?: number;
|
|
153
155
|
}
|
|
156
|
+
export type AgentStatus = "idle" | "working" | "blocked" | "done" | "unknown";
|
|
157
|
+
/** Duplicated shape on purpose (see EventsBusEvent above): mirrors the daemon's pane row, which rt-client cannot import. */
|
|
158
|
+
export interface ChatPane {
|
|
159
|
+
paneId: string;
|
|
160
|
+
workspace: string;
|
|
161
|
+
title?: string;
|
|
162
|
+
cwd?: string;
|
|
163
|
+
repo?: string;
|
|
164
|
+
branch?: string;
|
|
165
|
+
agentStatus: AgentStatus;
|
|
166
|
+
sessionId?: string;
|
|
167
|
+
presence?: {
|
|
168
|
+
handle: string;
|
|
169
|
+
status: BuddyStatus;
|
|
170
|
+
rooms: string[];
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
export interface PaneAccount {
|
|
174
|
+
slot: number;
|
|
175
|
+
email: string;
|
|
176
|
+
alias?: string;
|
|
177
|
+
headroom?: string;
|
|
178
|
+
}
|
|
179
|
+
export interface PaneDirectory {
|
|
180
|
+
path: string;
|
|
181
|
+
repo: string;
|
|
182
|
+
branch?: string;
|
|
183
|
+
}
|
|
184
|
+
export interface InviteResult {
|
|
185
|
+
paneId: string;
|
|
186
|
+
delivered: "accepted" | "queued" | "refused";
|
|
187
|
+
reason?: string;
|
|
188
|
+
}
|
|
154
189
|
export type Attention = {
|
|
155
190
|
needs: boolean;
|
|
156
191
|
reason: "failed" | "stale" | "stranded" | "blocked" | null;
|
|
@@ -223,6 +258,29 @@ export interface RunDetail {
|
|
|
223
258
|
decisions: RunDecisionRow[];
|
|
224
259
|
schemaAhead: boolean;
|
|
225
260
|
}
|
|
261
|
+
export type AgentSurface = "herdr" | "headless";
|
|
262
|
+
export interface AgentRecord {
|
|
263
|
+
id: string;
|
|
264
|
+
repo: string;
|
|
265
|
+
cwd: string;
|
|
266
|
+
provider: string;
|
|
267
|
+
surface: AgentSurface;
|
|
268
|
+
sessionId: string;
|
|
269
|
+
model?: string;
|
|
270
|
+
effort?: string;
|
|
271
|
+
account?: string;
|
|
272
|
+
label?: string;
|
|
273
|
+
caller?: string;
|
|
274
|
+
paneId?: string;
|
|
275
|
+
tabId?: string;
|
|
276
|
+
workspaceId?: string;
|
|
277
|
+
extraArgs?: string;
|
|
278
|
+
exitCode?: number;
|
|
279
|
+
resultPath?: string;
|
|
280
|
+
createdAt: number;
|
|
281
|
+
lastResumedAt?: number;
|
|
282
|
+
finishedAt?: number;
|
|
283
|
+
}
|
|
226
284
|
export interface Commands {
|
|
227
285
|
"project-mrs:read": {
|
|
228
286
|
payload: {
|
|
@@ -415,6 +473,7 @@ export interface Commands {
|
|
|
415
473
|
"chat:rooms": {
|
|
416
474
|
payload: {
|
|
417
475
|
handle: string;
|
|
476
|
+
includeArchived?: boolean;
|
|
418
477
|
};
|
|
419
478
|
data: {
|
|
420
479
|
rooms: RoomSummary[];
|
|
@@ -456,6 +515,7 @@ export interface Commands {
|
|
|
456
515
|
"chat:touch": {
|
|
457
516
|
payload: {
|
|
458
517
|
handle: string;
|
|
518
|
+
room?: string;
|
|
459
519
|
sessionId?: string;
|
|
460
520
|
};
|
|
461
521
|
data: Record<string, never>;
|
|
@@ -554,6 +614,121 @@ export interface Commands {
|
|
|
554
614
|
recipients: string[];
|
|
555
615
|
};
|
|
556
616
|
};
|
|
617
|
+
"chat:archive": {
|
|
618
|
+
payload: {
|
|
619
|
+
room: string;
|
|
620
|
+
handle: string;
|
|
621
|
+
archived: boolean;
|
|
622
|
+
};
|
|
623
|
+
data: {
|
|
624
|
+
room: string;
|
|
625
|
+
archivedAt: number | null;
|
|
626
|
+
};
|
|
627
|
+
};
|
|
628
|
+
"chat:dm-open": {
|
|
629
|
+
payload: {
|
|
630
|
+
from: string;
|
|
631
|
+
to: string;
|
|
632
|
+
sessionId?: string;
|
|
633
|
+
};
|
|
634
|
+
data: {
|
|
635
|
+
room: string;
|
|
636
|
+
created: boolean;
|
|
637
|
+
};
|
|
638
|
+
};
|
|
639
|
+
"agent:start": {
|
|
640
|
+
payload: {
|
|
641
|
+
repo: string;
|
|
642
|
+
cwd: string;
|
|
643
|
+
prompt?: string;
|
|
644
|
+
surface?: AgentSurface;
|
|
645
|
+
model?: string;
|
|
646
|
+
effort?: string;
|
|
647
|
+
account?: string;
|
|
648
|
+
label?: string;
|
|
649
|
+
caller?: string;
|
|
650
|
+
workspace?: string;
|
|
651
|
+
tab?: string;
|
|
652
|
+
extraArgs?: string;
|
|
653
|
+
};
|
|
654
|
+
data: AgentRecord;
|
|
655
|
+
};
|
|
656
|
+
"agent:resume": {
|
|
657
|
+
payload: {
|
|
658
|
+
id: string;
|
|
659
|
+
prompt?: string;
|
|
660
|
+
surface?: AgentSurface;
|
|
661
|
+
};
|
|
662
|
+
data: AgentRecord;
|
|
663
|
+
};
|
|
664
|
+
"agent:get": {
|
|
665
|
+
payload: {
|
|
666
|
+
id: string;
|
|
667
|
+
};
|
|
668
|
+
data: AgentRecord;
|
|
669
|
+
};
|
|
670
|
+
"agent:list": {
|
|
671
|
+
payload: {
|
|
672
|
+
repo?: string;
|
|
673
|
+
};
|
|
674
|
+
data: {
|
|
675
|
+
agents: AgentRecord[];
|
|
676
|
+
};
|
|
677
|
+
};
|
|
678
|
+
"chat:invite": {
|
|
679
|
+
payload: {
|
|
680
|
+
paneId: string;
|
|
681
|
+
room: string;
|
|
682
|
+
note?: string;
|
|
683
|
+
from: string;
|
|
684
|
+
callerPane?: string;
|
|
685
|
+
};
|
|
686
|
+
data: InviteResult;
|
|
687
|
+
};
|
|
688
|
+
"pane:list": {
|
|
689
|
+
payload: Record<string, never>;
|
|
690
|
+
data: {
|
|
691
|
+
panes: ChatPane[];
|
|
692
|
+
};
|
|
693
|
+
};
|
|
694
|
+
"pane:peek": {
|
|
695
|
+
payload: {
|
|
696
|
+
paneId: string;
|
|
697
|
+
lines?: number;
|
|
698
|
+
};
|
|
699
|
+
data: {
|
|
700
|
+
paneId: string;
|
|
701
|
+
lines: string[];
|
|
702
|
+
};
|
|
703
|
+
};
|
|
704
|
+
"pane:accounts": {
|
|
705
|
+
payload: Record<string, never>;
|
|
706
|
+
data: {
|
|
707
|
+
accounts: PaneAccount[];
|
|
708
|
+
};
|
|
709
|
+
};
|
|
710
|
+
"pane:directories": {
|
|
711
|
+
payload: {
|
|
712
|
+
q?: string;
|
|
713
|
+
};
|
|
714
|
+
data: {
|
|
715
|
+
directories: PaneDirectory[];
|
|
716
|
+
};
|
|
717
|
+
};
|
|
718
|
+
"pane:spawn": {
|
|
719
|
+
payload: {
|
|
720
|
+
cwd: string;
|
|
721
|
+
account?: string;
|
|
722
|
+
model?: string;
|
|
723
|
+
effort?: string;
|
|
724
|
+
prompt?: string;
|
|
725
|
+
workspace?: string;
|
|
726
|
+
};
|
|
727
|
+
data: {
|
|
728
|
+
pane: ChatPane;
|
|
729
|
+
ready: boolean;
|
|
730
|
+
};
|
|
731
|
+
};
|
|
557
732
|
}
|
|
558
733
|
export type CommandName = keyof Commands;
|
|
559
734
|
export declare const COMMAND_NAMES: readonly CommandName[];
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export { rtCommand, DEFAULT_SOCK } from "./transport.ts";
|
|
2
2
|
export type { RtResponse, RtClientOptions } from "./transport.ts";
|
|
3
|
-
export { readProjectMRs, readDiscussions, readMrsByBranch, readBranchCache, resolveForgeToken, listRuns, getRun, abandonRun, chatJoin, chatLeave, chatPost, chatRead, chatRooms, chatWho, chatMark, chatMessages, chatArm, chatTouch, chatDisarm, chatUnreadWaking, chatSignIn, chatSignOut, chatAway, chatBack, chatBuddies, chatPulse, chatDm, eventsHead, } from "./client.ts";
|
|
3
|
+
export { readProjectMRs, readDiscussions, readMrsByBranch, readBranchCache, resolveForgeToken, listRuns, getRun, abandonRun, chatJoin, chatLeave, chatPost, chatRead, chatRooms, chatWho, chatMark, chatMessages, chatArm, chatTouch, chatDisarm, chatUnreadWaking, chatSignIn, chatSignOut, chatAway, chatBack, chatBuddies, chatPulse, chatDm, chatArchive, chatDmOpen, eventsHead, agentStart, agentResume, agentGet, agentList, paneList, panePeek, paneSpawn, paneAccounts, paneDirectories, chatInvite, } from "./client.ts";
|
|
4
4
|
export { COMMAND_NAMES } from "./commands.ts";
|
|
5
|
-
export type { Discussion, DemandDecl, ProjectMRsScope, ProjectMRsData, DiscussionsData, MrByBranchEntry, MrByBranchData, BranchEnrichment, Commands, CommandName, ForgeSlug, ForgeTokenData, Attention, RunSummary, RunStageRow, RunFieldRow, RunDecisionRow, RunDetail, WakeMode, ChatMember, ChatMessage, RoomSummary, BuddyStatus, PresenceRow, } from "./commands.ts";
|
|
5
|
+
export type { Discussion, DemandDecl, ProjectMRsScope, ProjectMRsData, DiscussionsData, MrByBranchEntry, MrByBranchData, BranchEnrichment, Commands, CommandName, ForgeSlug, ForgeTokenData, Attention, RunSummary, RunStageRow, RunFieldRow, RunDecisionRow, RunDetail, WakeMode, ChatMember, ChatMessage, RoomSummary, BuddyStatus, PresenceRow, AgentRecord, AgentSurface, AgentStatus, ChatPane, PaneAccount, PaneDirectory, InviteResult, } from "./commands.ts";
|
|
6
6
|
export { subscribe, createRelay, DEFAULT_WS_URL } from "./relay.ts";
|
|
7
7
|
export type { RelayEventType } from "./relay.ts";
|
|
8
8
|
export { daemonHealth } from "./health.ts";
|
package/dist/index.js
CHANGED
|
@@ -95,7 +95,10 @@ function chatRead(a, o = {}) {
|
|
|
95
95
|
return rtCommand("chat:read", payload, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 1e4 });
|
|
96
96
|
}
|
|
97
97
|
function chatRooms(a, o = {}) {
|
|
98
|
-
|
|
98
|
+
const payload = { handle: a.handle };
|
|
99
|
+
if (a.includeArchived === true)
|
|
100
|
+
payload.includeArchived = true;
|
|
101
|
+
return rtCommand("chat:rooms", payload, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 1e4 });
|
|
99
102
|
}
|
|
100
103
|
function chatWho(a, o = {}) {
|
|
101
104
|
return rtCommand("chat:who", { room: a.room }, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 1e4 });
|
|
@@ -124,6 +127,8 @@ function chatArm(a, o = {}) {
|
|
|
124
127
|
}
|
|
125
128
|
function chatTouch(a, o = {}) {
|
|
126
129
|
const payload = { handle: a.handle };
|
|
130
|
+
if (a.room !== undefined)
|
|
131
|
+
payload.room = a.room;
|
|
127
132
|
if (a.sessionId !== undefined)
|
|
128
133
|
payload.sessionId = a.sessionId;
|
|
129
134
|
return rtCommand("chat:touch", payload, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 1e4 });
|
|
@@ -184,9 +189,76 @@ function chatDm(a, o = {}) {
|
|
|
184
189
|
payload.sessionId = a.sessionId;
|
|
185
190
|
return rtCommand("chat:dm", payload, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 1e4 });
|
|
186
191
|
}
|
|
192
|
+
function chatArchive(a, o = {}) {
|
|
193
|
+
return rtCommand("chat:archive", { room: a.room, handle: a.handle, archived: a.archived }, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 1e4 });
|
|
194
|
+
}
|
|
195
|
+
function chatDmOpen(a, o = {}) {
|
|
196
|
+
const payload = { from: a.from, to: a.to };
|
|
197
|
+
if (a.sessionId !== undefined)
|
|
198
|
+
payload.sessionId = a.sessionId;
|
|
199
|
+
return rtCommand("chat:dm-open", payload, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 1e4 });
|
|
200
|
+
}
|
|
187
201
|
function eventsHead(o = {}) {
|
|
188
202
|
return rtCommand("events:head", {}, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 1e4 });
|
|
189
203
|
}
|
|
204
|
+
function agentStart(a, o = {}) {
|
|
205
|
+
const payload = { repo: a.repo, cwd: a.cwd };
|
|
206
|
+
for (const k of ["prompt", "surface", "model", "effort", "account", "label", "caller", "workspace", "tab", "extraArgs"]) {
|
|
207
|
+
if (a[k] !== undefined)
|
|
208
|
+
payload[k] = a[k];
|
|
209
|
+
}
|
|
210
|
+
return rtCommand("agent:start", payload, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 30000 });
|
|
211
|
+
}
|
|
212
|
+
function agentResume(a, o = {}) {
|
|
213
|
+
const payload = { id: a.id };
|
|
214
|
+
if (a.prompt !== undefined)
|
|
215
|
+
payload.prompt = a.prompt;
|
|
216
|
+
if (a.surface !== undefined)
|
|
217
|
+
payload.surface = a.surface;
|
|
218
|
+
return rtCommand("agent:resume", payload, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 30000 });
|
|
219
|
+
}
|
|
220
|
+
function agentGet(a, o = {}) {
|
|
221
|
+
return rtCommand("agent:get", { id: a.id }, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 1e4 });
|
|
222
|
+
}
|
|
223
|
+
function agentList(a, o = {}) {
|
|
224
|
+
const payload = {};
|
|
225
|
+
if (a.repo !== undefined)
|
|
226
|
+
payload.repo = a.repo;
|
|
227
|
+
return rtCommand("agent:list", payload, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 1e4 });
|
|
228
|
+
}
|
|
229
|
+
function paneList(o = {}) {
|
|
230
|
+
return rtCommand("pane:list", {}, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 1e4 });
|
|
231
|
+
}
|
|
232
|
+
function panePeek(a, o = {}) {
|
|
233
|
+
const payload = { paneId: a.paneId };
|
|
234
|
+
if (a.lines !== undefined)
|
|
235
|
+
payload.lines = a.lines;
|
|
236
|
+
return rtCommand("pane:peek", payload, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 1e4 });
|
|
237
|
+
}
|
|
238
|
+
function paneSpawn(a, o = {}) {
|
|
239
|
+
const payload = { cwd: a.cwd };
|
|
240
|
+
for (const k of ["account", "model", "effort", "prompt", "workspace"])
|
|
241
|
+
if (a[k] !== undefined)
|
|
242
|
+
payload[k] = a[k];
|
|
243
|
+
return rtCommand("pane:spawn", payload, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 90000 });
|
|
244
|
+
}
|
|
245
|
+
function paneAccounts(o = {}) {
|
|
246
|
+
return rtCommand("pane:accounts", {}, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 1e4 });
|
|
247
|
+
}
|
|
248
|
+
function paneDirectories(a, o = {}) {
|
|
249
|
+
const payload = {};
|
|
250
|
+
if (a.q !== undefined)
|
|
251
|
+
payload.q = a.q;
|
|
252
|
+
return rtCommand("pane:directories", payload, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 1e4 });
|
|
253
|
+
}
|
|
254
|
+
function chatInvite(a, o = {}) {
|
|
255
|
+
const payload = { paneId: a.paneId, room: a.room, from: a.from };
|
|
256
|
+
if (a.note !== undefined)
|
|
257
|
+
payload.note = a.note;
|
|
258
|
+
if (a.callerPane !== undefined)
|
|
259
|
+
payload.callerPane = a.callerPane;
|
|
260
|
+
return rtCommand("chat:invite", payload, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 30000 });
|
|
261
|
+
}
|
|
190
262
|
// src/commands.ts
|
|
191
263
|
var COMMAND_NAMES = [
|
|
192
264
|
"project-mrs:read",
|
|
@@ -219,7 +291,19 @@ var COMMAND_NAMES = [
|
|
|
219
291
|
"chat:back",
|
|
220
292
|
"chat:buddies",
|
|
221
293
|
"chat:pulse",
|
|
222
|
-
"chat:dm"
|
|
294
|
+
"chat:dm",
|
|
295
|
+
"chat:archive",
|
|
296
|
+
"chat:dm-open",
|
|
297
|
+
"agent:start",
|
|
298
|
+
"agent:resume",
|
|
299
|
+
"agent:get",
|
|
300
|
+
"agent:list",
|
|
301
|
+
"chat:invite",
|
|
302
|
+
"pane:list",
|
|
303
|
+
"pane:peek",
|
|
304
|
+
"pane:accounts",
|
|
305
|
+
"pane:directories",
|
|
306
|
+
"pane:spawn"
|
|
223
307
|
];
|
|
224
308
|
// src/relay.ts
|
|
225
309
|
var DEFAULT_WS_URL = "ws://127.0.0.1:9401/ws";
|
|
@@ -659,7 +743,7 @@ var REGISTRY = [
|
|
|
659
743
|
type: "array",
|
|
660
744
|
scopes: ["team"],
|
|
661
745
|
merge: "replace",
|
|
662
|
-
description: "The
|
|
746
|
+
description: "The authors tab's roster: whose MRs the classic board lists, including hidden-by-default entries. Codeowners tabs list MRs from anyone."
|
|
663
747
|
},
|
|
664
748
|
{
|
|
665
749
|
key: "board.title",
|
|
@@ -680,14 +764,14 @@ var REGISTRY = [
|
|
|
680
764
|
type: "array",
|
|
681
765
|
scopes: ["team"],
|
|
682
766
|
merge: "replace",
|
|
683
|
-
description: "Ticket key prefixes (e.g. RT, MAT) the
|
|
767
|
+
description: "Ticket key prefixes (e.g. RT, MAT) that keep the authors tab to the team's own tickets and link out to Linear from an MR title; rows on a codeowners tab pass regardless of prefix."
|
|
684
768
|
},
|
|
685
769
|
{
|
|
686
770
|
key: "board.slack",
|
|
687
771
|
type: "object",
|
|
688
772
|
scopes: ["team"],
|
|
689
773
|
merge: "deep",
|
|
690
|
-
description: "The board's Slack posting config (app id, client id, channel, callback port);
|
|
774
|
+
description: "The board's Slack posting config (app id, client id, channel, callback port); channel is the default that a tab's slackChannel overrides per MR. Client secrets stay out of this store."
|
|
691
775
|
},
|
|
692
776
|
{
|
|
693
777
|
key: "board.doctorSkill",
|
|
@@ -708,7 +792,7 @@ var REGISTRY = [
|
|
|
708
792
|
type: "array",
|
|
709
793
|
scopes: ["team"],
|
|
710
794
|
merge: "replace",
|
|
711
|
-
description: "Board
|
|
795
|
+
description: "Board tabs ({id, label, source, slackChannel?, reviewSkill?}), editable from the board's settings modal. source.kind 'authors' is the classic roster board; 'codeowners' lists MRs from any author blocked on an unapproved CODEOWNERS section. Absent = one implicit authors tab (fallback lives in the board reader, never here)."
|
|
712
796
|
},
|
|
713
797
|
{
|
|
714
798
|
key: "board.staleAfterDays",
|
|
@@ -736,7 +820,7 @@ var REGISTRY = [
|
|
|
736
820
|
type: "array",
|
|
737
821
|
scopes: ["user"],
|
|
738
822
|
merge: "replace",
|
|
739
|
-
description: "Usernames this developer hides from the
|
|
823
|
+
description: "Usernames this developer hides from the authors tab's board.members roster; overlays the team truth without editing it."
|
|
740
824
|
},
|
|
741
825
|
{
|
|
742
826
|
key: "board.triage",
|
|
@@ -816,6 +900,21 @@ var REGISTRY = [
|
|
|
816
900
|
merge: "replace",
|
|
817
901
|
description: "The human's own chat handle, so agents can @-mention them by name."
|
|
818
902
|
},
|
|
903
|
+
{
|
|
904
|
+
key: "chat.viewerUrl",
|
|
905
|
+
type: "string",
|
|
906
|
+
scopes: ["user"],
|
|
907
|
+
merge: "replace",
|
|
908
|
+
description: "Base URL of the chat viewer, no trailing slash. When set, rt chat post and the tail's wake lines end with a link to the room or message."
|
|
909
|
+
},
|
|
910
|
+
{
|
|
911
|
+
key: "chat.herdrWorkspace",
|
|
912
|
+
type: "string",
|
|
913
|
+
scopes: ["user"],
|
|
914
|
+
default: "chat",
|
|
915
|
+
merge: "replace",
|
|
916
|
+
description: "herdr workspace label that rt pane spawn opens new agent tabs in; created when missing."
|
|
917
|
+
},
|
|
819
918
|
{
|
|
820
919
|
key: "chat.push.provider",
|
|
821
920
|
type: "string",
|
|
@@ -829,6 +928,34 @@ var REGISTRY = [
|
|
|
829
928
|
scopes: ["user"],
|
|
830
929
|
merge: "replace",
|
|
831
930
|
description: "Destination (topic/URL/token) the configured chat.push.provider sends to."
|
|
931
|
+
},
|
|
932
|
+
{
|
|
933
|
+
key: "agent.model",
|
|
934
|
+
type: "string",
|
|
935
|
+
scopes: ["user", "machine"],
|
|
936
|
+
merge: "replace",
|
|
937
|
+
description: "Default --model for rt agent launches; unset omits the flag."
|
|
938
|
+
},
|
|
939
|
+
{
|
|
940
|
+
key: "agent.effort",
|
|
941
|
+
type: "string",
|
|
942
|
+
scopes: ["user", "machine"],
|
|
943
|
+
merge: "replace",
|
|
944
|
+
description: "Default --effort for rt agent launches; unset omits the flag."
|
|
945
|
+
},
|
|
946
|
+
{
|
|
947
|
+
key: "agent.account",
|
|
948
|
+
type: "string",
|
|
949
|
+
scopes: ["user", "machine"],
|
|
950
|
+
merge: "replace",
|
|
951
|
+
description: "cswap account email rt agent launches under; unset uses the default claude profile."
|
|
952
|
+
},
|
|
953
|
+
{
|
|
954
|
+
key: "agent.extraArgs",
|
|
955
|
+
type: "string",
|
|
956
|
+
scopes: ["user", "machine"],
|
|
957
|
+
merge: "replace",
|
|
958
|
+
description: "Opaque extra claude arguments appended to every rt agent launch (escape hatch)."
|
|
832
959
|
}
|
|
833
960
|
];
|
|
834
961
|
|
|
@@ -1624,6 +1751,11 @@ export {
|
|
|
1624
1751
|
readDiscussions,
|
|
1625
1752
|
readBranchCache,
|
|
1626
1753
|
parseIdentity,
|
|
1754
|
+
paneSpawn,
|
|
1755
|
+
panePeek,
|
|
1756
|
+
paneList,
|
|
1757
|
+
paneDirectories,
|
|
1758
|
+
paneAccounts,
|
|
1627
1759
|
normalizeRemote,
|
|
1628
1760
|
listTeams,
|
|
1629
1761
|
listSettings,
|
|
@@ -1653,13 +1785,20 @@ export {
|
|
|
1653
1785
|
chatMark,
|
|
1654
1786
|
chatLeave,
|
|
1655
1787
|
chatJoin,
|
|
1788
|
+
chatInvite,
|
|
1789
|
+
chatDmOpen,
|
|
1656
1790
|
chatDm,
|
|
1657
1791
|
chatDisarm,
|
|
1658
1792
|
chatBuddies,
|
|
1659
1793
|
chatBack,
|
|
1660
1794
|
chatAway,
|
|
1661
1795
|
chatArm,
|
|
1796
|
+
chatArchive,
|
|
1662
1797
|
allDefs,
|
|
1798
|
+
agentStart,
|
|
1799
|
+
agentResume,
|
|
1800
|
+
agentList,
|
|
1801
|
+
agentGet,
|
|
1663
1802
|
abandonRun,
|
|
1664
1803
|
SCOPE_ORDER,
|
|
1665
1804
|
REGISTRY,
|
package/package.json
CHANGED
package/src/client.ts
CHANGED
|
@@ -21,6 +21,8 @@ import type {
|
|
|
21
21
|
RoomSummary,
|
|
22
22
|
BuddyStatus,
|
|
23
23
|
PresenceRow,
|
|
24
|
+
AgentRecord,
|
|
25
|
+
Commands,
|
|
24
26
|
} from "./commands.ts";
|
|
25
27
|
|
|
26
28
|
/**
|
|
@@ -184,10 +186,12 @@ export function chatRead(
|
|
|
184
186
|
}
|
|
185
187
|
|
|
186
188
|
export function chatRooms(
|
|
187
|
-
a: { handle: string },
|
|
189
|
+
a: { handle: string; includeArchived?: boolean },
|
|
188
190
|
o: RtClientOptions = {},
|
|
189
191
|
): Promise<RtResponse<{ rooms: RoomSummary[] }>> {
|
|
190
|
-
|
|
192
|
+
const payload: Record<string, unknown> = { handle: a.handle };
|
|
193
|
+
if (a.includeArchived === true) payload.includeArchived = true;
|
|
194
|
+
return rtCommand<{ rooms: RoomSummary[] }>("chat:rooms", payload, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 10_000 });
|
|
191
195
|
}
|
|
192
196
|
|
|
193
197
|
export function chatWho(
|
|
@@ -227,10 +231,11 @@ export function chatArm(
|
|
|
227
231
|
}
|
|
228
232
|
|
|
229
233
|
export function chatTouch(
|
|
230
|
-
a: { handle: string; sessionId?: string },
|
|
234
|
+
a: { handle: string; room?: string; sessionId?: string },
|
|
231
235
|
o: RtClientOptions = {},
|
|
232
236
|
): Promise<RtResponse<Record<string, never>>> {
|
|
233
237
|
const payload: Record<string, unknown> = { handle: a.handle };
|
|
238
|
+
if (a.room !== undefined) payload.room = a.room;
|
|
234
239
|
if (a.sessionId !== undefined) payload.sessionId = a.sessionId;
|
|
235
240
|
return rtCommand<Record<string, never>>("chat:touch", payload, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 10_000 });
|
|
236
241
|
}
|
|
@@ -320,6 +325,100 @@ export function chatDm(
|
|
|
320
325
|
return rtCommand<{ room: string; id: number; recipients: string[] }>("chat:dm", payload, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 10_000 });
|
|
321
326
|
}
|
|
322
327
|
|
|
328
|
+
export function chatArchive(
|
|
329
|
+
a: { room: string; handle: string; archived: boolean },
|
|
330
|
+
o: RtClientOptions = {},
|
|
331
|
+
): Promise<RtResponse<{ room: string; archivedAt: number | null }>> {
|
|
332
|
+
return rtCommand<{ room: string; archivedAt: number | null }>(
|
|
333
|
+
"chat:archive",
|
|
334
|
+
{ room: a.room, handle: a.handle, archived: a.archived },
|
|
335
|
+
{ sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 10_000 },
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
export function chatDmOpen(
|
|
340
|
+
a: { from: string; to: string; sessionId?: string },
|
|
341
|
+
o: RtClientOptions = {},
|
|
342
|
+
): Promise<RtResponse<{ room: string; created: boolean }>> {
|
|
343
|
+
const payload: Record<string, unknown> = { from: a.from, to: a.to };
|
|
344
|
+
if (a.sessionId !== undefined) payload.sessionId = a.sessionId;
|
|
345
|
+
return rtCommand<{ room: string; created: boolean }>("chat:dm-open", payload, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 10_000 });
|
|
346
|
+
}
|
|
347
|
+
|
|
323
348
|
export function eventsHead(o: RtClientOptions = {}): Promise<RtResponse<{ cursor: number }>> {
|
|
324
349
|
return rtCommand<{ cursor: number }>("events:head", {}, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 10_000 });
|
|
325
350
|
}
|
|
351
|
+
|
|
352
|
+
// ─── Agent handoff (rt agent) ─────────────────────────────────────────────
|
|
353
|
+
|
|
354
|
+
export function agentStart(
|
|
355
|
+
a: Commands["agent:start"]["payload"], o: RtClientOptions = {},
|
|
356
|
+
): Promise<RtResponse<AgentRecord>> {
|
|
357
|
+
const payload: Record<string, unknown> = { repo: a.repo, cwd: a.cwd };
|
|
358
|
+
for (const k of ["prompt", "surface", "model", "effort", "account", "label", "caller", "workspace", "tab", "extraArgs"] as const) {
|
|
359
|
+
if (a[k] !== undefined) payload[k] = a[k];
|
|
360
|
+
}
|
|
361
|
+
return rtCommand<AgentRecord>("agent:start", payload, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 30_000 });
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
export function agentResume(
|
|
365
|
+
a: Commands["agent:resume"]["payload"], o: RtClientOptions = {},
|
|
366
|
+
): Promise<RtResponse<AgentRecord>> {
|
|
367
|
+
const payload: Record<string, unknown> = { id: a.id };
|
|
368
|
+
if (a.prompt !== undefined) payload.prompt = a.prompt;
|
|
369
|
+
if (a.surface !== undefined) payload.surface = a.surface;
|
|
370
|
+
return rtCommand<AgentRecord>("agent:resume", payload, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 30_000 });
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
export function agentGet(a: { id: string }, o: RtClientOptions = {}): Promise<RtResponse<AgentRecord>> {
|
|
374
|
+
return rtCommand<AgentRecord>("agent:get", { id: a.id }, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 10_000 });
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
export function agentList(a: { repo?: string }, o: RtClientOptions = {}): Promise<RtResponse<{ agents: AgentRecord[] }>> {
|
|
378
|
+
const payload: Record<string, unknown> = {};
|
|
379
|
+
if (a.repo !== undefined) payload.repo = a.repo;
|
|
380
|
+
return rtCommand<{ agents: AgentRecord[] }>("agent:list", payload, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 10_000 });
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// ─── Panes (rt chat invite) ────────────────────────────────────────────────
|
|
384
|
+
// herdr-facing verbs; the daemon answers `herdr unavailable` without herdr.
|
|
385
|
+
|
|
386
|
+
export function paneList(o: RtClientOptions = {}): Promise<RtResponse<Commands["pane:list"]["data"]>> {
|
|
387
|
+
return rtCommand<Commands["pane:list"]["data"]>("pane:list", {}, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 10_000 });
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
export function panePeek(a: Commands["pane:peek"]["payload"], o: RtClientOptions = {}): Promise<RtResponse<Commands["pane:peek"]["data"]>> {
|
|
391
|
+
const payload: Record<string, unknown> = { paneId: a.paneId };
|
|
392
|
+
if (a.lines !== undefined) payload.lines = a.lines;
|
|
393
|
+
return rtCommand<Commands["pane:peek"]["data"]>("pane:peek", payload, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 10_000 });
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/** The spawn waits on claude starting, so its budget is minutes, not seconds. */
|
|
397
|
+
export function paneSpawn(
|
|
398
|
+
a: Commands["pane:spawn"]["payload"],
|
|
399
|
+
o: RtClientOptions = {},
|
|
400
|
+
): Promise<RtResponse<Commands["pane:spawn"]["data"]>> {
|
|
401
|
+
const payload: Record<string, unknown> = { cwd: a.cwd };
|
|
402
|
+
for (const k of ["account", "model", "effort", "prompt", "workspace"] as const) if (a[k] !== undefined) payload[k] = a[k];
|
|
403
|
+
return rtCommand<Commands["pane:spawn"]["data"]>("pane:spawn", payload, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 90_000 });
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
export function paneAccounts(o: RtClientOptions = {}): Promise<RtResponse<Commands["pane:accounts"]["data"]>> {
|
|
407
|
+
return rtCommand<Commands["pane:accounts"]["data"]>("pane:accounts", {}, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 10_000 });
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
export function paneDirectories(a: Commands["pane:directories"]["payload"], o: RtClientOptions = {}): Promise<RtResponse<Commands["pane:directories"]["data"]>> {
|
|
411
|
+
const payload: Record<string, unknown> = {};
|
|
412
|
+
if (a.q !== undefined) payload.q = a.q;
|
|
413
|
+
return rtCommand<Commands["pane:directories"]["data"]>("pane:directories", payload, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 10_000 });
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
export function chatInvite(
|
|
417
|
+
a: Commands["chat:invite"]["payload"],
|
|
418
|
+
o: RtClientOptions = {},
|
|
419
|
+
): Promise<RtResponse<Commands["chat:invite"]["data"]>> {
|
|
420
|
+
const payload: Record<string, unknown> = { paneId: a.paneId, room: a.room, from: a.from };
|
|
421
|
+
if (a.note !== undefined) payload.note = a.note;
|
|
422
|
+
if (a.callerPane !== undefined) payload.callerPane = a.callerPane;
|
|
423
|
+
return rtCommand<Commands["chat:invite"]["data"]>("chat:invite", payload, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 30_000 });
|
|
424
|
+
}
|
package/src/commands.ts
CHANGED
|
@@ -121,6 +121,8 @@ export interface RoomSummary {
|
|
|
121
121
|
participants?: { a: string; b: string };
|
|
122
122
|
/** Set only by chat:rooms's left join against chat_room_defaults; undefined for a room never stamped a default (every DM room included). */
|
|
123
123
|
defaultWake?: WakeMode;
|
|
124
|
+
/** Set only when chat:rooms was asked for archived rooms; absent on an open room. */
|
|
125
|
+
archivedAt?: number;
|
|
124
126
|
}
|
|
125
127
|
|
|
126
128
|
/**
|
|
@@ -146,6 +148,25 @@ export interface PresenceRow {
|
|
|
146
148
|
signedOutAt?: number;
|
|
147
149
|
}
|
|
148
150
|
|
|
151
|
+
export type AgentStatus = "idle" | "working" | "blocked" | "done" | "unknown";
|
|
152
|
+
|
|
153
|
+
/** Duplicated shape on purpose (see EventsBusEvent above): mirrors the daemon's pane row, which rt-client cannot import. */
|
|
154
|
+
export interface ChatPane {
|
|
155
|
+
paneId: string;
|
|
156
|
+
workspace: string;
|
|
157
|
+
title?: string;
|
|
158
|
+
cwd?: string;
|
|
159
|
+
repo?: string;
|
|
160
|
+
branch?: string;
|
|
161
|
+
agentStatus: AgentStatus;
|
|
162
|
+
sessionId?: string;
|
|
163
|
+
presence?: { handle: string; status: BuddyStatus; rooms: string[] };
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export interface PaneAccount { slot: number; email: string; alias?: string; headroom?: string }
|
|
167
|
+
export interface PaneDirectory { path: string; repo: string; branch?: string }
|
|
168
|
+
export interface InviteResult { paneId: string; delivered: "accepted" | "queued" | "refused"; reason?: string }
|
|
169
|
+
|
|
149
170
|
// SKILLS-53: one judgment, computed once in rt, so the console and the tray
|
|
150
171
|
// never derive two verdicts that can disagree.
|
|
151
172
|
export type Attention = {
|
|
@@ -192,6 +213,18 @@ export interface RunFieldRow { key: string; value: string; produced_by: string;
|
|
|
192
213
|
export interface RunDecisionRow { contract: string; scope: string; selection: string; decided_by: string; decided_at: number; }
|
|
193
214
|
export interface RunDetail { run: RunSummary; stages: RunStageRow[]; fields: RunFieldRow[]; decisions: RunDecisionRow[]; schemaAhead: boolean; }
|
|
194
215
|
|
|
216
|
+
export type AgentSurface = "herdr" | "headless";
|
|
217
|
+
|
|
218
|
+
export interface AgentRecord {
|
|
219
|
+
id: string; repo: string; cwd: string; provider: string;
|
|
220
|
+
surface: AgentSurface; sessionId: string;
|
|
221
|
+
model?: string; effort?: string; account?: string;
|
|
222
|
+
label?: string; caller?: string;
|
|
223
|
+
paneId?: string; tabId?: string; workspaceId?: string;
|
|
224
|
+
extraArgs?: string; exitCode?: number; resultPath?: string;
|
|
225
|
+
createdAt: number; lastResumedAt?: number; finishedAt?: number;
|
|
226
|
+
}
|
|
227
|
+
|
|
195
228
|
export interface Commands {
|
|
196
229
|
"project-mrs:read": { payload: { repoName: string; maxAgeMs?: number; demand?: DemandDecl }; data: ProjectMRsData };
|
|
197
230
|
"discussions:read": { payload: { repoName: string; iid: number }; data: DiscussionsData };
|
|
@@ -252,12 +285,12 @@ export interface Commands {
|
|
|
252
285
|
"chat:leave": { payload: { room: string; handle: string }; data: Record<string, never> };
|
|
253
286
|
"chat:post": { payload: { room: string; handle: string; body: string; mentions?: string[] }; data: { id: number; recipients: string[] } };
|
|
254
287
|
"chat:read": { payload: { handle: string; room?: string; limit?: number; sinceMs?: number }; data: { rooms: { room: string; messages: ChatMessage[] }[] } };
|
|
255
|
-
"chat:rooms": { payload: { handle: string }; data: { rooms: RoomSummary[] } };
|
|
288
|
+
"chat:rooms": { payload: { handle: string; includeArchived?: boolean }; data: { rooms: RoomSummary[] } };
|
|
256
289
|
"chat:who": { payload: { room: string }; data: { members: ChatMember[] } };
|
|
257
290
|
"chat:mark": { payload: { handle: string; room?: string }; data: Record<string, never> };
|
|
258
291
|
"chat:messages": { payload: { room: string; before?: number; limit?: number }; data: { messages: ChatMessage[] } };
|
|
259
292
|
"chat:arm": { payload: { handle: string; room?: string; sessionId?: string }; data: Record<string, never> };
|
|
260
|
-
"chat:touch": { payload: { handle: string; sessionId?: string }; data: Record<string, never> };
|
|
293
|
+
"chat:touch": { payload: { handle: string; room?: string; sessionId?: string }; data: Record<string, never> };
|
|
261
294
|
"chat:disarm": { payload: { handle: string; sessionId?: string }; data: Record<string, never> };
|
|
262
295
|
"chat:unread-waking": { payload: { handle: string; room?: string }; data: { rooms: { room: string; count: number; mentions: number; maxId: number }[] } };
|
|
263
296
|
|
|
@@ -277,6 +310,23 @@ export interface Commands {
|
|
|
277
310
|
data: { unread: { dms: number; mentions: number; rooms: number }; status: BuddyStatus };
|
|
278
311
|
};
|
|
279
312
|
"chat:dm": { payload: { from: string; to: string; body: string; sessionId?: string }; data: { room: string; id: number; recipients: string[] } };
|
|
313
|
+
"chat:archive": { payload: { room: string; handle: string; archived: boolean }; data: { room: string; archivedAt: number | null } };
|
|
314
|
+
"chat:dm-open": { payload: { from: string; to: string; sessionId?: string }; data: { room: string; created: boolean } };
|
|
315
|
+
|
|
316
|
+
// ─── Agent handoff (rt agent) ────────────────────────────────────────────
|
|
317
|
+
"agent:start": { payload: { repo: string; cwd: string; prompt?: string; surface?: AgentSurface; model?: string; effort?: string; account?: string; label?: string; caller?: string; workspace?: string; tab?: string; extraArgs?: string }; data: AgentRecord };
|
|
318
|
+
"agent:resume": { payload: { id: string; prompt?: string; surface?: AgentSurface }; data: AgentRecord };
|
|
319
|
+
"agent:get": { payload: { id: string }; data: AgentRecord };
|
|
320
|
+
"agent:list": { payload: { repo?: string }; data: { agents: AgentRecord[] } };
|
|
321
|
+
"chat:invite": { payload: { paneId: string; room: string; note?: string; from: string; callerPane?: string }; data: InviteResult };
|
|
322
|
+
"pane:list": { payload: Record<string, never>; data: { panes: ChatPane[] } };
|
|
323
|
+
"pane:peek": { payload: { paneId: string; lines?: number }; data: { paneId: string; lines: string[] } };
|
|
324
|
+
"pane:accounts": { payload: Record<string, never>; data: { accounts: PaneAccount[] } };
|
|
325
|
+
"pane:directories": { payload: { q?: string }; data: { directories: PaneDirectory[] } };
|
|
326
|
+
"pane:spawn": {
|
|
327
|
+
payload: { cwd: string; account?: string; model?: string; effort?: string; prompt?: string; workspace?: string };
|
|
328
|
+
data: { pane: ChatPane; ready: boolean };
|
|
329
|
+
};
|
|
280
330
|
}
|
|
281
331
|
|
|
282
332
|
export type CommandName = keyof Commands;
|
|
@@ -313,4 +363,16 @@ export const COMMAND_NAMES: readonly CommandName[] = [
|
|
|
313
363
|
"chat:buddies",
|
|
314
364
|
"chat:pulse",
|
|
315
365
|
"chat:dm",
|
|
366
|
+
"chat:archive",
|
|
367
|
+
"chat:dm-open",
|
|
368
|
+
"agent:start",
|
|
369
|
+
"agent:resume",
|
|
370
|
+
"agent:get",
|
|
371
|
+
"agent:list",
|
|
372
|
+
"chat:invite",
|
|
373
|
+
"pane:list",
|
|
374
|
+
"pane:peek",
|
|
375
|
+
"pane:accounts",
|
|
376
|
+
"pane:directories",
|
|
377
|
+
"pane:spawn",
|
|
316
378
|
];
|
package/src/index.ts
CHANGED
|
@@ -29,7 +29,19 @@ export {
|
|
|
29
29
|
chatBuddies,
|
|
30
30
|
chatPulse,
|
|
31
31
|
chatDm,
|
|
32
|
+
chatArchive,
|
|
33
|
+
chatDmOpen,
|
|
32
34
|
eventsHead,
|
|
35
|
+
agentStart,
|
|
36
|
+
agentResume,
|
|
37
|
+
agentGet,
|
|
38
|
+
agentList,
|
|
39
|
+
paneList,
|
|
40
|
+
panePeek,
|
|
41
|
+
paneSpawn,
|
|
42
|
+
paneAccounts,
|
|
43
|
+
paneDirectories,
|
|
44
|
+
chatInvite,
|
|
33
45
|
} from "./client.ts";
|
|
34
46
|
|
|
35
47
|
export { COMMAND_NAMES } from "./commands.ts";
|
|
@@ -58,6 +70,13 @@ export type {
|
|
|
58
70
|
RoomSummary,
|
|
59
71
|
BuddyStatus,
|
|
60
72
|
PresenceRow,
|
|
73
|
+
AgentRecord,
|
|
74
|
+
AgentSurface,
|
|
75
|
+
AgentStatus,
|
|
76
|
+
ChatPane,
|
|
77
|
+
PaneAccount,
|
|
78
|
+
PaneDirectory,
|
|
79
|
+
InviteResult,
|
|
61
80
|
} from "./commands.ts";
|
|
62
81
|
|
|
63
82
|
export { subscribe, createRelay, DEFAULT_WS_URL } from "./relay.ts";
|
|
@@ -308,7 +308,7 @@ export const REGISTRY: readonly SettingDef[] = [
|
|
|
308
308
|
type: "array",
|
|
309
309
|
scopes: ["team"],
|
|
310
310
|
merge: "replace",
|
|
311
|
-
description: "The
|
|
311
|
+
description: "The authors tab's roster: whose MRs the classic board lists, including hidden-by-default entries. Codeowners tabs list MRs from anyone.",
|
|
312
312
|
},
|
|
313
313
|
{
|
|
314
314
|
key: "board.title",
|
|
@@ -329,14 +329,14 @@ export const REGISTRY: readonly SettingDef[] = [
|
|
|
329
329
|
type: "array",
|
|
330
330
|
scopes: ["team"],
|
|
331
331
|
merge: "replace",
|
|
332
|
-
description: "Ticket key prefixes (e.g. RT, MAT) the
|
|
332
|
+
description: "Ticket key prefixes (e.g. RT, MAT) that keep the authors tab to the team's own tickets and link out to Linear from an MR title; rows on a codeowners tab pass regardless of prefix.",
|
|
333
333
|
},
|
|
334
334
|
{
|
|
335
335
|
key: "board.slack",
|
|
336
336
|
type: "object",
|
|
337
337
|
scopes: ["team"],
|
|
338
338
|
merge: "deep",
|
|
339
|
-
description: "The board's Slack posting config (app id, client id, channel, callback port);
|
|
339
|
+
description: "The board's Slack posting config (app id, client id, channel, callback port); channel is the default that a tab's slackChannel overrides per MR. Client secrets stay out of this store.",
|
|
340
340
|
},
|
|
341
341
|
{
|
|
342
342
|
key: "board.doctorSkill",
|
|
@@ -357,7 +357,7 @@ export const REGISTRY: readonly SettingDef[] = [
|
|
|
357
357
|
type: "array",
|
|
358
358
|
scopes: ["team"],
|
|
359
359
|
merge: "replace",
|
|
360
|
-
description: "Board
|
|
360
|
+
description: "Board tabs ({id, label, source, slackChannel?, reviewSkill?}), editable from the board's settings modal. source.kind 'authors' is the classic roster board; 'codeowners' lists MRs from any author blocked on an unapproved CODEOWNERS section. Absent = one implicit authors tab (fallback lives in the board reader, never here).",
|
|
361
361
|
},
|
|
362
362
|
|
|
363
363
|
// --- board (user) ----------------------------------------------------------
|
|
@@ -387,7 +387,7 @@ export const REGISTRY: readonly SettingDef[] = [
|
|
|
387
387
|
type: "array",
|
|
388
388
|
scopes: ["user"],
|
|
389
389
|
merge: "replace",
|
|
390
|
-
description: "Usernames this developer hides from the
|
|
390
|
+
description: "Usernames this developer hides from the authors tab's board.members roster; overlays the team truth without editing it.",
|
|
391
391
|
},
|
|
392
392
|
{
|
|
393
393
|
key: "board.triage",
|
|
@@ -473,6 +473,21 @@ export const REGISTRY: readonly SettingDef[] = [
|
|
|
473
473
|
merge: "replace",
|
|
474
474
|
description: "The human's own chat handle, so agents can @-mention them by name.",
|
|
475
475
|
},
|
|
476
|
+
{
|
|
477
|
+
key: "chat.viewerUrl",
|
|
478
|
+
type: "string",
|
|
479
|
+
scopes: ["user"],
|
|
480
|
+
merge: "replace",
|
|
481
|
+
description: "Base URL of the chat viewer, no trailing slash. When set, rt chat post and the tail's wake lines end with a link to the room or message.",
|
|
482
|
+
},
|
|
483
|
+
{
|
|
484
|
+
key: "chat.herdrWorkspace",
|
|
485
|
+
type: "string",
|
|
486
|
+
scopes: ["user"],
|
|
487
|
+
default: "chat",
|
|
488
|
+
merge: "replace",
|
|
489
|
+
description: "herdr workspace label that rt pane spawn opens new agent tabs in; created when missing.",
|
|
490
|
+
},
|
|
476
491
|
{
|
|
477
492
|
key: "chat.push.provider",
|
|
478
493
|
type: "string",
|
|
@@ -487,4 +502,36 @@ export const REGISTRY: readonly SettingDef[] = [
|
|
|
487
502
|
merge: "replace",
|
|
488
503
|
description: "Destination (topic/URL/token) the configured chat.push.provider sends to.",
|
|
489
504
|
},
|
|
505
|
+
|
|
506
|
+
// --- agent (rt agent handoff) --------------------------------------------
|
|
507
|
+
// No defaults by design: an unset key means the flag is omitted from the
|
|
508
|
+
// claude invocation entirely (spec "Settings").
|
|
509
|
+
{
|
|
510
|
+
key: "agent.model",
|
|
511
|
+
type: "string",
|
|
512
|
+
scopes: ["user", "machine"],
|
|
513
|
+
merge: "replace",
|
|
514
|
+
description: "Default --model for rt agent launches; unset omits the flag.",
|
|
515
|
+
},
|
|
516
|
+
{
|
|
517
|
+
key: "agent.effort",
|
|
518
|
+
type: "string",
|
|
519
|
+
scopes: ["user", "machine"],
|
|
520
|
+
merge: "replace",
|
|
521
|
+
description: "Default --effort for rt agent launches; unset omits the flag.",
|
|
522
|
+
},
|
|
523
|
+
{
|
|
524
|
+
key: "agent.account",
|
|
525
|
+
type: "string",
|
|
526
|
+
scopes: ["user", "machine"],
|
|
527
|
+
merge: "replace",
|
|
528
|
+
description: "cswap account email rt agent launches under; unset uses the default claude profile.",
|
|
529
|
+
},
|
|
530
|
+
{
|
|
531
|
+
key: "agent.extraArgs",
|
|
532
|
+
type: "string",
|
|
533
|
+
scopes: ["user", "machine"],
|
|
534
|
+
merge: "replace",
|
|
535
|
+
description: "Opaque extra claude arguments appended to every rt agent launch (escape hatch).",
|
|
536
|
+
},
|
|
490
537
|
];
|