@mattstack/rt-client 0.19.1 → 0.20.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 +1 -0
- package/dist/client.d.ts +3 -0
- package/dist/commands.d.ts +56 -3
- package/dist/index.d.ts +2 -2
- package/dist/index.js +22 -2
- package/package.json +1 -1
- package/src/client.ts +16 -1
- package/src/commands.ts +50 -6
- package/src/index.ts +5 -0
- package/src/settings/registry-defs.ts +9 -0
- package/src/transport.ts +6 -1
package/README.md
CHANGED
|
@@ -104,6 +104,7 @@ const stop = createRelay({ // one daemon sub
|
|
|
104
104
|
| `chatPost` / `chatDm` / `chatDmOpen` / `chatRead` / `chatMessages` / `chatMark` | messages: post, DM, open a DM room without posting, read-and-advance, page, advance the cursor |
|
|
105
105
|
| `paneList` / `panePeek` / `paneSpawn` / `paneAccounts` / `paneDirectories` | herdr panes: list with presence joined, peek a screen, start claude in a tab, cswap accounts, directory suggestions |
|
|
106
106
|
| `chatInvite` | type `/chat:join <room>` into a pane; `accepted`, `queued` or `refused` |
|
|
107
|
+
| `paneSend` | type a line into a pane; `accepted`, `queued` or `refused`, plus an optional `continuation` the daemon types once the pane's turn has ended |
|
|
107
108
|
| `createRelay` / `subscribe` | the event stream; `daemonHealth` the reachability probe |
|
|
108
109
|
|
|
109
110
|
Pass `{ sockPath }` as the trailing options to reach a non-default daemon
|
package/dist/client.d.ts
CHANGED
|
@@ -183,6 +183,9 @@ export declare function paneSend(a: Commands["pane:send"]["payload"], o?: RtClie
|
|
|
183
183
|
/** Brings a herdr pane to the front. The daemon routes this to the tray, which
|
|
184
184
|
owns the herdr focus and the native terminal-window raise. */
|
|
185
185
|
export declare function paneFocus(a: Commands["pane:focus"]["payload"], o?: RtClientOptions): Promise<RtResponse<Commands["pane:focus"]["data"]>>;
|
|
186
|
+
/** Never triggers a sweep; a plain read of the last one's snapshot. */
|
|
187
|
+
export declare function reconcilerStatus(o?: RtClientOptions): Promise<RtResponse<Commands["reconciler:status"]["data"]>>;
|
|
188
|
+
export declare function reconcilerClear(a: Commands["reconciler:clear"]["payload"], o?: RtClientOptions): Promise<RtResponse<Commands["reconciler:clear"]["data"]>>;
|
|
186
189
|
export declare function gateOpen(a: Commands["gate:open"]["payload"], o?: RtClientOptions): Promise<RtResponse<Commands["gate:open"]["data"]>>;
|
|
187
190
|
export declare function gateAnswer(a: Commands["gate:answer"]["payload"], o?: RtClientOptions): Promise<RtResponse<Commands["gate:answer"]["data"]>>;
|
|
188
191
|
/** Daemon clamps its own wait to 240s (gates-store.ts); the client abort
|
package/dist/commands.d.ts
CHANGED
|
@@ -102,6 +102,8 @@ export interface EventsBusEvent {
|
|
|
102
102
|
value gates-store.ts's release tracking (CAS winner or loser) reacts to. */
|
|
103
103
|
export declare const GATE_BY_PANE = "pane";
|
|
104
104
|
export type GateStatus = "open" | "answered" | "parked" | "closed";
|
|
105
|
+
/** Reconciler's view of an agent's liveness; also the value `GateRow.executor` is stamped with. */
|
|
106
|
+
export type ExecutorState = "live" | "blocked" | "hidden" | "gone" | "cleared" | "unknown";
|
|
105
107
|
export type GateOption = string | {
|
|
106
108
|
value: string;
|
|
107
109
|
label: string;
|
|
@@ -143,7 +145,10 @@ export interface GateRow {
|
|
|
143
145
|
openedAt: number;
|
|
144
146
|
parkedAt: number | null;
|
|
145
147
|
closedAt: number | null;
|
|
146
|
-
|
|
148
|
+
/** "resolved" is stamped only by the reconciler's auto-recovery close
|
|
149
|
+
(a blocked/gone pane came back); every other closer uses one of the
|
|
150
|
+
other three. */
|
|
151
|
+
closedReason: "abandoned" | "superseded" | "pruned" | "resolved" | null;
|
|
147
152
|
/** Set only when `closedReason` is "superseded": the id of the gate that superseded this one. */
|
|
148
153
|
supersededBy: string | null;
|
|
149
154
|
agent: string | null;
|
|
@@ -152,12 +157,17 @@ export interface GateRow {
|
|
|
152
157
|
session: string;
|
|
153
158
|
} | null;
|
|
154
159
|
delivery: {
|
|
155
|
-
outcome: "delivered" | "dead-pane";
|
|
160
|
+
outcome: "delivered" | "dead-pane" | "confirmed" | "stuck";
|
|
156
161
|
at: number;
|
|
157
162
|
} | null;
|
|
158
163
|
released: boolean;
|
|
159
164
|
owner: string | null;
|
|
160
165
|
escalatedAt: number | null;
|
|
166
|
+
/** Set by answer-time execution handling: an answered gate whose executor
|
|
167
|
+
couldn't be resumed. Cleared (absent) once resumption succeeds. */
|
|
168
|
+
execution?: "unassigned";
|
|
169
|
+
/** Stamped by the reconciler sweep for open/parked rows only. */
|
|
170
|
+
executor?: ExecutorState;
|
|
161
171
|
}
|
|
162
172
|
export interface GateSubscription {
|
|
163
173
|
id: string;
|
|
@@ -213,7 +223,7 @@ export interface HerdStatusData {
|
|
|
213
223
|
openGate: string | null;
|
|
214
224
|
paneStatus: string | null;
|
|
215
225
|
lastGateStatus: GateStatus | null;
|
|
216
|
-
lastGateDelivery: "delivered" | "dead-pane" | null;
|
|
226
|
+
lastGateDelivery: "delivered" | "dead-pane" | "confirmed" | "stuck" | null;
|
|
217
227
|
}>;
|
|
218
228
|
unread: number;
|
|
219
229
|
lifecycleConnected: boolean;
|
|
@@ -345,10 +355,14 @@ export interface InviteResult {
|
|
|
345
355
|
}
|
|
346
356
|
/** Duplicated shape on purpose: mirrors lib/daemon/inject.ts's InjectResult. */
|
|
347
357
|
export type PaneDelivery = "accepted" | "queued" | "refused";
|
|
358
|
+
/** `continuation` is present only when the daemon scheduled a second line for after the target's current turn. */
|
|
348
359
|
export interface PaneSendResult {
|
|
349
360
|
paneId: string;
|
|
350
361
|
delivered: PaneDelivery;
|
|
351
362
|
reason?: string;
|
|
363
|
+
continuation?: {
|
|
364
|
+
delivered: "deferred";
|
|
365
|
+
};
|
|
352
366
|
}
|
|
353
367
|
/** `attendTab` is set only for a `bg:` ref: focus for a background pane IS
|
|
354
368
|
the attend flow (a visible tab running a terminal attach), and this is
|
|
@@ -431,6 +445,23 @@ export interface RunDetail {
|
|
|
431
445
|
schemaAhead: boolean;
|
|
432
446
|
}
|
|
433
447
|
export type AgentSurface = "herdr" | "headless";
|
|
448
|
+
/** The reconciler's per-agent snapshot: one row per agent it knows about, live or not. */
|
|
449
|
+
export interface ExecutorView {
|
|
450
|
+
agentId: string;
|
|
451
|
+
repo: string | null;
|
|
452
|
+
subject: string | null;
|
|
453
|
+
surface: AgentSurface;
|
|
454
|
+
sessionId: string;
|
|
455
|
+
paneRef: string | null;
|
|
456
|
+
state: ExecutorState;
|
|
457
|
+
since: number;
|
|
458
|
+
openGateIds: string[];
|
|
459
|
+
}
|
|
460
|
+
export interface ReconcilerStatus {
|
|
461
|
+
sweptAt: number;
|
|
462
|
+
herdrReachable: boolean;
|
|
463
|
+
executors: ExecutorView[];
|
|
464
|
+
}
|
|
434
465
|
export interface AgentRecord {
|
|
435
466
|
id: string;
|
|
436
467
|
repo: string;
|
|
@@ -444,6 +475,12 @@ export interface AgentRecord {
|
|
|
444
475
|
label?: string;
|
|
445
476
|
caller?: string;
|
|
446
477
|
handle?: string;
|
|
478
|
+
/** The gate-protocol subject stamped as RT_GATE_SUBJECT at launch. Left
|
|
479
|
+
undefined when the caller passed none (RT_GATE_SUBJECT still falls
|
|
480
|
+
back to "agent:<id>" at launch time); an explicit value is persisted
|
|
481
|
+
so a resume re-stamps the same one, AND gates whether the gate-fork
|
|
482
|
+
PreToolUse hook gets injected at all. */
|
|
483
|
+
subject?: string;
|
|
447
484
|
paneId?: string;
|
|
448
485
|
tabId?: string;
|
|
449
486
|
workspaceId?: string;
|
|
@@ -1096,6 +1133,7 @@ export interface Commands {
|
|
|
1096
1133
|
herdrSocket?: string;
|
|
1097
1134
|
handle?: string;
|
|
1098
1135
|
bg?: boolean;
|
|
1136
|
+
subject?: string;
|
|
1099
1137
|
};
|
|
1100
1138
|
data: AgentRecord;
|
|
1101
1139
|
};
|
|
@@ -1182,6 +1220,7 @@ export interface Commands {
|
|
|
1182
1220
|
paneId: string;
|
|
1183
1221
|
text: string;
|
|
1184
1222
|
callerPane?: string;
|
|
1223
|
+
continuation?: string;
|
|
1185
1224
|
};
|
|
1186
1225
|
data: PaneSendResult;
|
|
1187
1226
|
};
|
|
@@ -1360,6 +1399,20 @@ export interface Commands {
|
|
|
1360
1399
|
payload: Record<string, never>;
|
|
1361
1400
|
data: unknown;
|
|
1362
1401
|
};
|
|
1402
|
+
/** Read-only: the last sweep's snapshot. Never triggers a sweep itself. */
|
|
1403
|
+
"reconciler:status": {
|
|
1404
|
+
payload: Record<string, never>;
|
|
1405
|
+
data: ReconcilerStatus;
|
|
1406
|
+
};
|
|
1407
|
+
/** Manual override: marks the agent cleared and closes its open/parked gates (reconciler.ts's clear()). */
|
|
1408
|
+
"reconciler:clear": {
|
|
1409
|
+
payload: {
|
|
1410
|
+
agentId: string;
|
|
1411
|
+
};
|
|
1412
|
+
data: {
|
|
1413
|
+
cleared: true;
|
|
1414
|
+
};
|
|
1415
|
+
};
|
|
1363
1416
|
"gate:open": {
|
|
1364
1417
|
payload: {
|
|
1365
1418
|
subject: string;
|
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, chatAck, chatClaim, chatRelease, chatPost, chatRead, chatRooms, chatWho, chatMark, chatMessages, chatSignIn, chatSignOut, chatAway, chatBack, chatBuddies, chatDm, chatArchive, chatDmOpen, eventsHead, eventsEmit, eventsWait, eventsList, agentStart, agentResume, agentGet, agentList, paneList, panePeek, paneSpawn, paneAccounts, paneDirectories, chatInvite, paneSend, paneFocus, gateOpen, gateAnswer, gateWait, gateList, gatePark, gateClose, gateSubscribe, gateUnsubscribe, gateSubscriptions, herdStart, herdSpawn, herdAsk, herdMilestone, herdAnswer, herdReport, herdGates, herdStatus, herdList, herdResume, herdClose, herdAttend, herdWrapUp, herdStopHidden, bgEnsure, bgStatus, bgStop, bgRelease, } from "./client.ts";
|
|
3
|
+
export { readProjectMRs, readDiscussions, readMrsByBranch, readBranchCache, resolveForgeToken, listRuns, getRun, abandonRun, chatJoin, chatLeave, chatAck, chatClaim, chatRelease, chatPost, chatRead, chatRooms, chatWho, chatMark, chatMessages, chatSignIn, chatSignOut, chatAway, chatBack, chatBuddies, chatDm, chatArchive, chatDmOpen, eventsHead, eventsEmit, eventsWait, eventsList, agentStart, agentResume, agentGet, agentList, paneList, panePeek, paneSpawn, paneAccounts, paneDirectories, chatInvite, paneSend, paneFocus, reconcilerStatus, reconcilerClear, gateOpen, gateAnswer, gateWait, gateList, gatePark, gateClose, gateSubscribe, gateUnsubscribe, gateSubscriptions, herdStart, herdSpawn, herdAsk, herdMilestone, herdAnswer, herdReport, herdGates, herdStatus, herdList, herdResume, herdClose, herdAttend, herdWrapUp, herdStopHidden, bgEnsure, bgStatus, bgStop, bgRelease, } from "./client.ts";
|
|
4
4
|
export { COMMAND_NAMES, GATE_BY_PANE, gateOptionValue, gateOptionLabel } 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, ChatClaimOutcome, RoomSummary, BuddyStatus, PresenceRow, AgentRecord, AgentSurface, AgentStatus, ChatPane, PaneAccount, PaneDirectory, InviteResult, PaneDelivery, PaneSendResult, PaneFocusResult, GateStatus, GateOption, GateOrigin, GateQuestion, GateAnswer, GateRow, GateSubscription, HerdInfo, HerdListRow, HerdJobInfo, HerdStatusData, } 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, ChatClaimOutcome, RoomSummary, BuddyStatus, PresenceRow, AgentRecord, AgentSurface, AgentStatus, ExecutorState, ExecutorView, ReconcilerStatus, ChatPane, PaneAccount, PaneDirectory, InviteResult, PaneDelivery, PaneSendResult, PaneFocusResult, GateStatus, GateOption, GateOrigin, GateQuestion, GateAnswer, GateRow, GateSubscription, HerdInfo, HerdListRow, HerdJobInfo, HerdStatusData, } 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
|
@@ -5,7 +5,7 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
|
5
5
|
import { homedir } from "os";
|
|
6
6
|
import { join } from "path";
|
|
7
7
|
function defaultSock() {
|
|
8
|
-
return join(process.env.HOME ?? homedir(), ".mattstack", "rt", "rt.sock");
|
|
8
|
+
return process.env.RT_DAEMON_SOCK || join(process.env.HOME ?? homedir(), ".mattstack", "rt", "rt.sock");
|
|
9
9
|
}
|
|
10
10
|
var DEFAULT_SOCK = defaultSock();
|
|
11
11
|
async function rtCommand(cmd, payload, opts = {}) {
|
|
@@ -205,7 +205,7 @@ function eventsList(payload, o = {}) {
|
|
|
205
205
|
}
|
|
206
206
|
function agentStart(a, o = {}) {
|
|
207
207
|
const payload = { repo: a.repo, cwd: a.cwd };
|
|
208
|
-
for (const k of ["prompt", "surface", "model", "effort", "account", "label", "caller", "workspace", "tab", "extraArgs", "env", "herdrSocket", "handle", "bg"]) {
|
|
208
|
+
for (const k of ["prompt", "surface", "model", "effort", "account", "label", "caller", "workspace", "tab", "extraArgs", "env", "herdrSocket", "handle", "bg", "subject"]) {
|
|
209
209
|
if (a[k] !== undefined)
|
|
210
210
|
payload[k] = a[k];
|
|
211
211
|
}
|
|
@@ -265,6 +265,8 @@ function paneSend(a, o = {}) {
|
|
|
265
265
|
const payload = { paneId: a.paneId, text: a.text };
|
|
266
266
|
if (a.callerPane !== undefined)
|
|
267
267
|
payload.callerPane = a.callerPane;
|
|
268
|
+
if (a.continuation !== undefined)
|
|
269
|
+
payload.continuation = a.continuation;
|
|
268
270
|
return rtCommand("pane:send", payload, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 30000 });
|
|
269
271
|
}
|
|
270
272
|
function paneFocus(a, o = {}) {
|
|
@@ -273,6 +275,12 @@ function paneFocus(a, o = {}) {
|
|
|
273
275
|
payload.callerWorkspace = a.callerWorkspace;
|
|
274
276
|
return rtCommand("pane:focus", payload, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 1e4 });
|
|
275
277
|
}
|
|
278
|
+
function reconcilerStatus(o = {}) {
|
|
279
|
+
return rtCommand("reconciler:status", {}, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 1e4 });
|
|
280
|
+
}
|
|
281
|
+
function reconcilerClear(a, o = {}) {
|
|
282
|
+
return rtCommand("reconciler:clear", { agentId: a.agentId }, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 1e4 });
|
|
283
|
+
}
|
|
276
284
|
function gateOpen(a, o = {}) {
|
|
277
285
|
const payload = { subject: a.subject, kind: a.kind, questions: a.questions };
|
|
278
286
|
for (const k of ["meta", "agent", "pane", "nudge", "context", "origin"])
|
|
@@ -478,6 +486,8 @@ var COMMAND_NAMES = [
|
|
|
478
486
|
"endpoint:status",
|
|
479
487
|
"repos:locate",
|
|
480
488
|
"freshness:reconcile",
|
|
489
|
+
"reconciler:status",
|
|
490
|
+
"reconciler:clear",
|
|
481
491
|
"gate:open",
|
|
482
492
|
"gate:answer",
|
|
483
493
|
"gate:wait",
|
|
@@ -1031,6 +1041,14 @@ var REGISTRY = [
|
|
|
1031
1041
|
merge: "replace",
|
|
1032
1042
|
description: 'The machine\'s intended flavor, "dev" or "prod". Normally written by `rt settings dev-mode` after a successful handoff; a manual `rt settings set` is the blessed repair escape hatch — the daemon park loop converges on whatever this says. Unset ⇒ derived from the dev wrapper\'s presence.'
|
|
1033
1043
|
},
|
|
1044
|
+
{
|
|
1045
|
+
key: "setup.waived",
|
|
1046
|
+
type: "array",
|
|
1047
|
+
scopes: ["machine"],
|
|
1048
|
+
default: [],
|
|
1049
|
+
merge: "replace",
|
|
1050
|
+
description: "Finish-gated setup rows the user skipped on this Mac through `rt setup waive` (today only tool.fast-browser-extension); the wizard's Finish no longer waits on them. Machine-only: a loaded Chrome extension is a per-profile fact and the choice is per machine, so it never travels with a team or user store."
|
|
1051
|
+
},
|
|
1034
1052
|
{
|
|
1035
1053
|
key: "rt.integrations",
|
|
1036
1054
|
type: "object",
|
|
@@ -2253,6 +2271,8 @@ export {
|
|
|
2253
2271
|
resolveNameToIdentity,
|
|
2254
2272
|
resolveForgeToken,
|
|
2255
2273
|
repoNameForPath,
|
|
2274
|
+
reconcilerStatus,
|
|
2275
|
+
reconcilerClear,
|
|
2256
2276
|
readStore,
|
|
2257
2277
|
readProjectMRs,
|
|
2258
2278
|
readMrsByBranch,
|
package/package.json
CHANGED
package/src/client.ts
CHANGED
|
@@ -356,7 +356,7 @@ export function agentStart(
|
|
|
356
356
|
a: Commands["agent:start"]["payload"], o: RtClientOptions = {},
|
|
357
357
|
): Promise<RtResponse<AgentRecord>> {
|
|
358
358
|
const payload: Record<string, unknown> = { repo: a.repo, cwd: a.cwd };
|
|
359
|
-
for (const k of ["prompt", "surface", "model", "effort", "account", "label", "caller", "workspace", "tab", "extraArgs", "env", "herdrSocket", "handle", "bg"] as const) {
|
|
359
|
+
for (const k of ["prompt", "surface", "model", "effort", "account", "label", "caller", "workspace", "tab", "extraArgs", "env", "herdrSocket", "handle", "bg", "subject"] as const) {
|
|
360
360
|
if (a[k] !== undefined) payload[k] = a[k];
|
|
361
361
|
}
|
|
362
362
|
return rtCommand<AgentRecord>("agent:start", payload, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 30_000 });
|
|
@@ -432,6 +432,7 @@ export function paneSend(
|
|
|
432
432
|
): Promise<RtResponse<Commands["pane:send"]["data"]>> {
|
|
433
433
|
const payload: Record<string, unknown> = { paneId: a.paneId, text: a.text };
|
|
434
434
|
if (a.callerPane !== undefined) payload.callerPane = a.callerPane;
|
|
435
|
+
if (a.continuation !== undefined) payload.continuation = a.continuation;
|
|
435
436
|
return rtCommand<Commands["pane:send"]["data"]>("pane:send", payload, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 30_000 });
|
|
436
437
|
}
|
|
437
438
|
|
|
@@ -446,6 +447,20 @@ export function paneFocus(
|
|
|
446
447
|
return rtCommand<Commands["pane:focus"]["data"]>("pane:focus", payload, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 10_000 });
|
|
447
448
|
}
|
|
448
449
|
|
|
450
|
+
// ─── Reconciler (executor state; lib/daemon/reconciler.ts) ────────────────
|
|
451
|
+
|
|
452
|
+
/** Never triggers a sweep; a plain read of the last one's snapshot. */
|
|
453
|
+
export function reconcilerStatus(o: RtClientOptions = {}): Promise<RtResponse<Commands["reconciler:status"]["data"]>> {
|
|
454
|
+
return rtCommand<Commands["reconciler:status"]["data"]>("reconciler:status", {}, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 10_000 });
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
export function reconcilerClear(
|
|
458
|
+
a: Commands["reconciler:clear"]["payload"],
|
|
459
|
+
o: RtClientOptions = {},
|
|
460
|
+
): Promise<RtResponse<Commands["reconciler:clear"]["data"]>> {
|
|
461
|
+
return rtCommand<Commands["reconciler:clear"]["data"]>("reconciler:clear", { agentId: a.agentId }, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 10_000 });
|
|
462
|
+
}
|
|
463
|
+
|
|
449
464
|
// ─── Gates (BOARD-20/21 gate facility) ─────────────────────────────────────
|
|
450
465
|
|
|
451
466
|
export function gateOpen(
|
package/src/commands.ts
CHANGED
|
@@ -95,6 +95,8 @@ export interface EventsBusEvent { id: number; topic: string; payload: unknown; e
|
|
|
95
95
|
export const GATE_BY_PANE = "pane";
|
|
96
96
|
|
|
97
97
|
export type GateStatus = "open" | "answered" | "parked" | "closed";
|
|
98
|
+
/** Reconciler's view of an agent's liveness; also the value `GateRow.executor` is stamped with. */
|
|
99
|
+
export type ExecutorState = "live" | "blocked" | "hidden" | "gone" | "cleared" | "unknown";
|
|
98
100
|
export type GateOption = string | { value: string; label: string };
|
|
99
101
|
export interface GateOrigin {
|
|
100
102
|
paneId?: string;
|
|
@@ -118,15 +120,23 @@ export interface GateRow {
|
|
|
118
120
|
origin?: GateOrigin | null;
|
|
119
121
|
status: GateStatus; answer: GateAnswer | null;
|
|
120
122
|
openedAt: number; parkedAt: number | null; closedAt: number | null;
|
|
121
|
-
|
|
123
|
+
/** "resolved" is stamped only by the reconciler's auto-recovery close
|
|
124
|
+
(a blocked/gone pane came back); every other closer uses one of the
|
|
125
|
+
other three. */
|
|
126
|
+
closedReason: "abandoned" | "superseded" | "pruned" | "resolved" | null;
|
|
122
127
|
/** Set only when `closedReason` is "superseded": the id of the gate that superseded this one. */
|
|
123
128
|
supersededBy: string | null;
|
|
124
129
|
agent: string | null; pane: string | null;
|
|
125
130
|
nudge: { session: string } | null;
|
|
126
|
-
delivery: { outcome: "delivered" | "dead-pane"; at: number } | null;
|
|
131
|
+
delivery: { outcome: "delivered" | "dead-pane" | "confirmed" | "stuck"; at: number } | null;
|
|
127
132
|
released: boolean;
|
|
128
133
|
owner: string | null;
|
|
129
134
|
escalatedAt: number | null;
|
|
135
|
+
/** Set by answer-time execution handling: an answered gate whose executor
|
|
136
|
+
couldn't be resumed. Cleared (absent) once resumption succeeds. */
|
|
137
|
+
execution?: "unassigned";
|
|
138
|
+
/** Stamped by the reconciler sweep for open/parked rows only. */
|
|
139
|
+
executor?: ExecutorState;
|
|
130
140
|
}
|
|
131
141
|
|
|
132
142
|
export interface GateSubscription {
|
|
@@ -147,7 +157,7 @@ export interface HerdJobInfo { herd: string; name: string; worktree: string; bra
|
|
|
147
157
|
/** `lastGateStatus`/`lastGateDelivery` come from the job's `lastGate` row: an `answered` gate whose delivery is `dead-pane` is the "answered, worker not woken" case the shepherd must act on. */
|
|
148
158
|
export interface HerdStatusData {
|
|
149
159
|
herd: HerdInfo;
|
|
150
|
-
jobs: Array<HerdJobInfo & { openGate: string | null; paneStatus: string | null; lastGateStatus: GateStatus | null; lastGateDelivery: "delivered" | "dead-pane" | null }>;
|
|
160
|
+
jobs: Array<HerdJobInfo & { openGate: string | null; paneStatus: string | null; lastGateStatus: GateStatus | null; lastGateDelivery: "delivered" | "dead-pane" | "confirmed" | "stuck" | null }>;
|
|
151
161
|
unread: number;
|
|
152
162
|
lifecycleConnected: boolean;
|
|
153
163
|
hiddenUp: boolean | null;
|
|
@@ -251,7 +261,8 @@ export interface InviteResult { paneId: string; delivered: "accepted" | "queued"
|
|
|
251
261
|
|
|
252
262
|
/** Duplicated shape on purpose: mirrors lib/daemon/inject.ts's InjectResult. */
|
|
253
263
|
export type PaneDelivery = "accepted" | "queued" | "refused";
|
|
254
|
-
|
|
264
|
+
/** `continuation` is present only when the daemon scheduled a second line for after the target's current turn. */
|
|
265
|
+
export interface PaneSendResult { paneId: string; delivered: PaneDelivery; reason?: string; continuation?: { delivered: "deferred" } }
|
|
255
266
|
/** `attendTab` is set only for a `bg:` ref: focus for a background pane IS
|
|
256
267
|
the attend flow (a visible tab running a terminal attach), and this is
|
|
257
268
|
that tab's id. */
|
|
@@ -305,11 +316,36 @@ export interface RunDetail { run: RunSummary; stages: RunStageRow[]; fields: Run
|
|
|
305
316
|
|
|
306
317
|
export type AgentSurface = "herdr" | "headless";
|
|
307
318
|
|
|
319
|
+
/** The reconciler's per-agent snapshot: one row per agent it knows about, live or not. */
|
|
320
|
+
export interface ExecutorView {
|
|
321
|
+
agentId: string;
|
|
322
|
+
repo: string | null;
|
|
323
|
+
subject: string | null;
|
|
324
|
+
surface: AgentSurface;
|
|
325
|
+
sessionId: string;
|
|
326
|
+
paneRef: string | null;
|
|
327
|
+
state: ExecutorState;
|
|
328
|
+
since: number;
|
|
329
|
+
openGateIds: string[];
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
export interface ReconcilerStatus {
|
|
333
|
+
sweptAt: number;
|
|
334
|
+
herdrReachable: boolean;
|
|
335
|
+
executors: ExecutorView[];
|
|
336
|
+
}
|
|
337
|
+
|
|
308
338
|
export interface AgentRecord {
|
|
309
339
|
id: string; repo: string; cwd: string; provider: string;
|
|
310
340
|
surface: AgentSurface; sessionId: string;
|
|
311
341
|
model?: string; effort?: string; account?: string;
|
|
312
342
|
label?: string; caller?: string; handle?: string;
|
|
343
|
+
/** The gate-protocol subject stamped as RT_GATE_SUBJECT at launch. Left
|
|
344
|
+
undefined when the caller passed none (RT_GATE_SUBJECT still falls
|
|
345
|
+
back to "agent:<id>" at launch time); an explicit value is persisted
|
|
346
|
+
so a resume re-stamps the same one, AND gates whether the gate-fork
|
|
347
|
+
PreToolUse hook gets injected at all. */
|
|
348
|
+
subject?: string;
|
|
313
349
|
paneId?: string; tabId?: string; workspaceId?: string;
|
|
314
350
|
extraArgs?: string; exitCode?: number; resultPath?: string;
|
|
315
351
|
createdAt: number; lastResumedAt?: number; finishedAt?: number;
|
|
@@ -568,7 +604,7 @@ export interface Commands {
|
|
|
568
604
|
"chat:dm-open": { payload: { from: string; to: string; sessionId?: string }; data: { room: string; created: boolean } };
|
|
569
605
|
|
|
570
606
|
// ─── Agent handoff (rt agent) ────────────────────────────────────────────
|
|
571
|
-
"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; env?: Record<string, string>; herdrSocket?: string; handle?: string; bg?: boolean }; data: AgentRecord };
|
|
607
|
+
"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; env?: Record<string, string>; herdrSocket?: string; handle?: string; bg?: boolean; subject?: string }; data: AgentRecord };
|
|
572
608
|
"agent:resume": { payload: { id: string; prompt?: string; surface?: AgentSurface; workspace?: string; tab?: string }; data: AgentRecord };
|
|
573
609
|
"agent:get": { payload: { id: string }; data: AgentRecord };
|
|
574
610
|
"agent:list": { payload: { repo?: string }; data: { agents: AgentRecord[] } };
|
|
@@ -581,7 +617,7 @@ export interface Commands {
|
|
|
581
617
|
payload: { cwd: string; account?: string; model?: string; effort?: string; prompt?: string; workspace?: string };
|
|
582
618
|
data: { pane: ChatPane; ready: boolean };
|
|
583
619
|
};
|
|
584
|
-
"pane:send": { payload: { paneId: string; text: string; callerPane?: string }; data: PaneSendResult };
|
|
620
|
+
"pane:send": { payload: { paneId: string; text: string; callerPane?: string; continuation?: string }; data: PaneSendResult };
|
|
585
621
|
/** `callerWorkspace` (HERDR_WORKSPACE_ID) is required only for a `bg:`
|
|
586
622
|
ref, whose focus opens an attend tab in the caller's own workspace. */
|
|
587
623
|
"pane:focus": { payload: { paneId: string; callerWorkspace?: string }; data: PaneFocusResult };
|
|
@@ -619,6 +655,12 @@ export interface Commands {
|
|
|
619
655
|
"repos:locate": { payload: { newPath: string; repo?: string; dryRun?: boolean }; data: unknown };
|
|
620
656
|
"freshness:reconcile": { payload: Record<string, never>; data: unknown };
|
|
621
657
|
|
|
658
|
+
// ─── Reconciler (executor state; lib/daemon/reconciler.ts) ───────────────
|
|
659
|
+
/** Read-only: the last sweep's snapshot. Never triggers a sweep itself. */
|
|
660
|
+
"reconciler:status": { payload: Record<string, never>; data: ReconcilerStatus };
|
|
661
|
+
/** Manual override: marks the agent cleared and closes its open/parked gates (reconciler.ts's clear()). */
|
|
662
|
+
"reconciler:clear": { payload: { agentId: string }; data: { cleared: true } };
|
|
663
|
+
|
|
622
664
|
// ─── Gate facility (BOARD-20/21) ─────────────────────────────────────────
|
|
623
665
|
"gate:open": { payload: { subject: string; kind: string; questions: GateQuestion[]; meta?: Record<string, unknown>; agent?: string; pane?: string; nudge?: { session: string }; context?: string; origin?: GateOrigin }; data: { id: string; supersededId: string | null } };
|
|
624
666
|
/**
|
|
@@ -769,6 +811,8 @@ export const COMMAND_NAMES: readonly CommandName[] = [
|
|
|
769
811
|
"endpoint:status",
|
|
770
812
|
"repos:locate",
|
|
771
813
|
"freshness:reconcile",
|
|
814
|
+
"reconciler:status",
|
|
815
|
+
"reconciler:clear",
|
|
772
816
|
"gate:open",
|
|
773
817
|
"gate:answer",
|
|
774
818
|
"gate:wait",
|
package/src/index.ts
CHANGED
|
@@ -45,6 +45,8 @@ export {
|
|
|
45
45
|
chatInvite,
|
|
46
46
|
paneSend,
|
|
47
47
|
paneFocus,
|
|
48
|
+
reconcilerStatus,
|
|
49
|
+
reconcilerClear,
|
|
48
50
|
gateOpen,
|
|
49
51
|
gateAnswer,
|
|
50
52
|
gateWait,
|
|
@@ -104,6 +106,9 @@ export type {
|
|
|
104
106
|
AgentRecord,
|
|
105
107
|
AgentSurface,
|
|
106
108
|
AgentStatus,
|
|
109
|
+
ExecutorState,
|
|
110
|
+
ExecutorView,
|
|
111
|
+
ReconcilerStatus,
|
|
107
112
|
ChatPane,
|
|
108
113
|
PaneAccount,
|
|
109
114
|
PaneDirectory,
|
|
@@ -295,6 +295,15 @@ export const REGISTRY: readonly SettingDef[] = [
|
|
|
295
295
|
merge: "replace",
|
|
296
296
|
description: "The machine's intended flavor, \"dev\" or \"prod\". Normally written by `rt settings dev-mode` after a successful handoff; a manual `rt settings set` is the blessed repair escape hatch — the daemon park loop converges on whatever this says. Unset ⇒ derived from the dev wrapper's presence.",
|
|
297
297
|
},
|
|
298
|
+
{
|
|
299
|
+
key: "setup.waived",
|
|
300
|
+
type: "array",
|
|
301
|
+
scopes: ["machine"],
|
|
302
|
+
default: [],
|
|
303
|
+
merge: "replace",
|
|
304
|
+
description:
|
|
305
|
+
"Finish-gated setup rows the user skipped on this Mac through `rt setup waive` (today only tool.fast-browser-extension); the wizard's Finish no longer waits on them. Machine-only: a loaded Chrome extension is a per-profile fact and the choice is per machine, so it never travels with a team or user store.",
|
|
306
|
+
},
|
|
298
307
|
{
|
|
299
308
|
key: "rt.integrations",
|
|
300
309
|
type: "object",
|
package/src/transport.ts
CHANGED
|
@@ -38,8 +38,13 @@ export interface RtClientOptions {
|
|
|
38
38
|
// lib/, so this literal cannot import rtDir(). repo-tools/lib/rt-paths.ts is
|
|
39
39
|
// the authority — change there first, mirror here (same convention as
|
|
40
40
|
// settings/paths.ts's call-time `home()`).
|
|
41
|
+
//
|
|
42
|
+
// RT_DAEMON_SOCK wins over the HOME-derived default (same pattern as
|
|
43
|
+
// lib/daemon-client.ts's RT_APP_SOCKET for tray.sock): an isolated daemon
|
|
44
|
+
// (per-agent launch, an e2e run) points every rt-client caller, including
|
|
45
|
+
// the `rt` CLI's own subcommands, at its own socket without repointing HOME.
|
|
41
46
|
function defaultSock(): string {
|
|
42
|
-
return join(process.env.HOME ?? homedir(), ".mattstack", "rt", "rt.sock");
|
|
47
|
+
return process.env.RT_DAEMON_SOCK || join(process.env.HOME ?? homedir(), ".mattstack", "rt", "rt.sock");
|
|
43
48
|
}
|
|
44
49
|
|
|
45
50
|
/**
|