@mattstack/rt-client 0.27.0 → 0.28.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/dist/commands.d.ts +16 -3
- package/dist/index.js +78 -1
- package/package.json +1 -1
- package/src/client.ts +4 -1
- package/src/commands.ts +9 -4
- package/src/settings/registry-defs.ts +74 -0
package/dist/commands.d.ts
CHANGED
|
@@ -247,7 +247,11 @@ export interface HerdStatusData {
|
|
|
247
247
|
sessionDead: boolean | null;
|
|
248
248
|
lastGateStatus: GateStatus | null;
|
|
249
249
|
lastGateDelivery: "delivered" | "dead-pane" | "confirmed" | "stuck" | null;
|
|
250
|
-
lastGateConsumed: boolean | null;
|
|
250
|
+
lastGateConsumed: boolean | null; /** The daemon watchdog's escalation ladder for this job: strikes so far and when it last acted. Absent when the job is not on the ladder (healthy, no watchdog wired, or the daemon restarted since). */
|
|
251
|
+
watchdog?: {
|
|
252
|
+
strikes: number;
|
|
253
|
+
lastPokeAt: number | null;
|
|
254
|
+
};
|
|
251
255
|
}>;
|
|
252
256
|
unread: number;
|
|
253
257
|
lifecycleConnected: boolean;
|
|
@@ -486,6 +490,10 @@ export interface ReconcilerStatus {
|
|
|
486
490
|
herdrReachable: boolean;
|
|
487
491
|
executors: ExecutorView[];
|
|
488
492
|
}
|
|
493
|
+
/** What a claude spawn's folder-trust check established, when one ran:
|
|
494
|
+
`none` = no dialog was up, `accepted` = one was answered, `stuck` = one is
|
|
495
|
+
still up and needs a human, `unchecked` = nothing could be established. */
|
|
496
|
+
export type TrustOutcome = "none" | "accepted" | "stuck" | "unchecked";
|
|
489
497
|
export interface AgentRecord {
|
|
490
498
|
id: string;
|
|
491
499
|
repo: string;
|
|
@@ -1160,9 +1168,12 @@ export interface Commands {
|
|
|
1160
1168
|
handle?: string;
|
|
1161
1169
|
bg?: boolean;
|
|
1162
1170
|
subject?: string;
|
|
1163
|
-
yolo?: boolean;
|
|
1171
|
+
yolo?: boolean; /** How long the folder-trust check lets the dialog paint before reading the screen; interactive launches keep the short default, herd:spawn passes its own longer budget. */
|
|
1172
|
+
trustWaitMs?: number;
|
|
1173
|
+
};
|
|
1174
|
+
data: AgentRecord & {
|
|
1175
|
+
trust?: TrustOutcome;
|
|
1164
1176
|
};
|
|
1165
|
-
data: AgentRecord;
|
|
1166
1177
|
};
|
|
1167
1178
|
"agent:resume": {
|
|
1168
1179
|
payload: {
|
|
@@ -1634,6 +1645,7 @@ export interface Commands {
|
|
|
1634
1645
|
repo: string;
|
|
1635
1646
|
session: string;
|
|
1636
1647
|
hidden?: boolean;
|
|
1648
|
+
callerPane?: string;
|
|
1637
1649
|
};
|
|
1638
1650
|
data: {
|
|
1639
1651
|
herd: string;
|
|
@@ -1648,6 +1660,7 @@ export interface Commands {
|
|
|
1648
1660
|
payload: {
|
|
1649
1661
|
herd: string;
|
|
1650
1662
|
session: string;
|
|
1663
|
+
callerPane?: string;
|
|
1651
1664
|
};
|
|
1652
1665
|
data: {
|
|
1653
1666
|
subscription: string;
|
package/dist/index.js
CHANGED
|
@@ -382,6 +382,8 @@ function herdStart(a, o = {}) {
|
|
|
382
382
|
const payload = { name: a.name, repo: a.repo, session: a.session };
|
|
383
383
|
if (a.hidden !== undefined)
|
|
384
384
|
payload.hidden = a.hidden;
|
|
385
|
+
if (a.callerPane !== undefined)
|
|
386
|
+
payload.callerPane = a.callerPane;
|
|
385
387
|
return rtCommand("herd:start", payload, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 60000 });
|
|
386
388
|
}
|
|
387
389
|
function herdSpawn(a, o = {}) {
|
|
@@ -425,7 +427,10 @@ function herdList(a = {}, o = {}) {
|
|
|
425
427
|
return rtCommand("herd:list", payload, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 1e4 });
|
|
426
428
|
}
|
|
427
429
|
function herdResume(a, o = {}) {
|
|
428
|
-
|
|
430
|
+
const payload = { herd: a.herd, session: a.session };
|
|
431
|
+
if (a.callerPane !== undefined)
|
|
432
|
+
payload.callerPane = a.callerPane;
|
|
433
|
+
return rtCommand("herd:resume", payload, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 1e4 });
|
|
429
434
|
}
|
|
430
435
|
function herdClose(a, o = {}) {
|
|
431
436
|
return rtCommand("herd:close", { herd: a.herd, job: a.job }, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 30000 });
|
|
@@ -1605,6 +1610,78 @@ var REGISTRY = [
|
|
|
1605
1610
|
default: 10,
|
|
1606
1611
|
merge: "replace",
|
|
1607
1612
|
description: `Minutes an open herd-owned gate waits before the escalation sweep surfaces it to the human (topic gate/escalated/<id>). Fires on either trigger: the TTL elapses (reason "ttl"), or the owning herd's shepherd subscription is gone or dead before the TTL (reason "owner-dead"). 0 escalates any eligible gate on the first sweep after it opens. A fresh key, not an ownership-latch port, so a default is fine here.`
|
|
1613
|
+
},
|
|
1614
|
+
{
|
|
1615
|
+
key: "herd.watchdog.enabled",
|
|
1616
|
+
type: "boolean",
|
|
1617
|
+
scopes: ["machine"],
|
|
1618
|
+
default: true,
|
|
1619
|
+
merge: "replace",
|
|
1620
|
+
description: "Turns the herd watchdog sweep on."
|
|
1621
|
+
},
|
|
1622
|
+
{
|
|
1623
|
+
key: "herd.watchdog.fastMins",
|
|
1624
|
+
type: "number",
|
|
1625
|
+
scopes: ["machine"],
|
|
1626
|
+
default: 2,
|
|
1627
|
+
merge: "replace",
|
|
1628
|
+
description: "Idle minutes before a worker with a pending DM, mention, or answered gate is poked."
|
|
1629
|
+
},
|
|
1630
|
+
{
|
|
1631
|
+
key: "herd.watchdog.shepherdFastMins",
|
|
1632
|
+
type: "number",
|
|
1633
|
+
scopes: ["machine"],
|
|
1634
|
+
default: 5,
|
|
1635
|
+
merge: "replace",
|
|
1636
|
+
description: "Minutes an open human-owned gate in the herd may stay unanswered before the shepherd is poked. Unread DMs and mentions for the shepherd wedge immediately and are not delayed by this key."
|
|
1637
|
+
},
|
|
1638
|
+
{
|
|
1639
|
+
key: "herd.watchdog.backstopMins",
|
|
1640
|
+
type: "number",
|
|
1641
|
+
scopes: ["machine"],
|
|
1642
|
+
default: 15,
|
|
1643
|
+
merge: "replace",
|
|
1644
|
+
description: "Idle minutes before any non-gated active worker is poked."
|
|
1645
|
+
},
|
|
1646
|
+
{
|
|
1647
|
+
key: "herd.watchdog.retryMins",
|
|
1648
|
+
type: "number",
|
|
1649
|
+
scopes: ["machine"],
|
|
1650
|
+
default: 5,
|
|
1651
|
+
merge: "replace",
|
|
1652
|
+
description: "Minutes between escalation strikes while the watchdog keeps poking an unresponsive worker."
|
|
1653
|
+
},
|
|
1654
|
+
{
|
|
1655
|
+
key: "herd.watchdog.notifyQuietMins",
|
|
1656
|
+
type: "number",
|
|
1657
|
+
scopes: ["machine"],
|
|
1658
|
+
default: 30,
|
|
1659
|
+
merge: "replace",
|
|
1660
|
+
description: "Minimum minutes between macOS notifications for the same herd."
|
|
1661
|
+
},
|
|
1662
|
+
{
|
|
1663
|
+
key: "herd.watchdog.nagMins",
|
|
1664
|
+
type: "number",
|
|
1665
|
+
scopes: ["machine"],
|
|
1666
|
+
default: 30,
|
|
1667
|
+
merge: "replace",
|
|
1668
|
+
description: "Minutes a done job may hold its pane before the shepherd is nagged to reclaim it."
|
|
1669
|
+
},
|
|
1670
|
+
{
|
|
1671
|
+
key: "herd.watchdog.notifyHuman",
|
|
1672
|
+
type: "boolean",
|
|
1673
|
+
scopes: ["machine"],
|
|
1674
|
+
default: true,
|
|
1675
|
+
merge: "replace",
|
|
1676
|
+
description: "Whether the watchdog's top escalation rung sends a macOS notification to the human."
|
|
1677
|
+
},
|
|
1678
|
+
{
|
|
1679
|
+
key: "herd.watchdog.midRunTrustAccept",
|
|
1680
|
+
type: "boolean",
|
|
1681
|
+
scopes: ["machine"],
|
|
1682
|
+
default: false,
|
|
1683
|
+
merge: "replace",
|
|
1684
|
+
description: "Whether the watchdog may drive a mid-run folder-trust dialog on a daemon-provisioned tree itself, rather than only parking the job and notifying (RT-196). Off by default: the screen match cannot yet confirm the dialog's folder matches the job's worktree, so a working session showing an unrelated permission prompt with the same shape is a real risk."
|
|
1608
1685
|
}
|
|
1609
1686
|
];
|
|
1610
1687
|
|
package/package.json
CHANGED
package/src/client.ts
CHANGED
|
@@ -561,6 +561,7 @@ export function herdStart(
|
|
|
561
561
|
): Promise<RtResponse<Commands["herd:start"]["data"]>> {
|
|
562
562
|
const payload: Record<string, unknown> = { name: a.name, repo: a.repo, session: a.session };
|
|
563
563
|
if (a.hidden !== undefined) payload.hidden = a.hidden;
|
|
564
|
+
if (a.callerPane !== undefined) payload.callerPane = a.callerPane;
|
|
564
565
|
return rtCommand<Commands["herd:start"]["data"]>("herd:start", payload, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 60_000 });
|
|
565
566
|
}
|
|
566
567
|
|
|
@@ -635,7 +636,9 @@ export function herdResume(
|
|
|
635
636
|
a: Commands["herd:resume"]["payload"],
|
|
636
637
|
o: RtClientOptions = {},
|
|
637
638
|
): Promise<RtResponse<Commands["herd:resume"]["data"]>> {
|
|
638
|
-
|
|
639
|
+
const payload: Record<string, unknown> = { herd: a.herd, session: a.session };
|
|
640
|
+
if (a.callerPane !== undefined) payload.callerPane = a.callerPane;
|
|
641
|
+
return rtCommand<Commands["herd:resume"]["data"]>("herd:resume", payload, { sockPath: o.sockPath, timeoutMs: o.timeoutMs ?? 10_000 });
|
|
639
642
|
}
|
|
640
643
|
|
|
641
644
|
/** Closes a herdr pane, one CLI call under the runner's own 15s budget. */
|
package/src/commands.ts
CHANGED
|
@@ -171,7 +171,7 @@ export interface HerdJobInfo { herd: string; name: string; worktree: string; bra
|
|
|
171
171
|
/** `lastGateStatus`/`lastGateDelivery` come from the job's `lastGate` row: a TERMINAL gate (answered or closed) whose delivery is `dead-pane` is the "worker not woken" case the shepherd must act on. `lastGateConsumed` is `null` when there is nothing to consume (no last gate, not answered, or not nudged), and otherwise reports whether the nudged pane has read its answer. */
|
|
172
172
|
export interface HerdStatusData {
|
|
173
173
|
herd: HerdInfo;
|
|
174
|
-
jobs: Array<HerdJobInfo & { openGate: string | null; paneStatus: string | null; /** The worker session behind this job's pane is gone while the job still reads in-flight: herdr lists the pane but no claude is on it. Null when herdr does not list the pane at all (it closed, or herdr is unreachable), which proves nothing either way. */ sessionDead: boolean | null; lastGateStatus: GateStatus | null; lastGateDelivery: "delivered" | "dead-pane" | "confirmed" | "stuck" | null; lastGateConsumed: boolean | null }>;
|
|
174
|
+
jobs: Array<HerdJobInfo & { openGate: string | null; paneStatus: string | null; /** The worker session behind this job's pane is gone while the job still reads in-flight: herdr lists the pane but no claude is on it. Null when herdr does not list the pane at all (it closed, or herdr is unreachable), which proves nothing either way. */ sessionDead: boolean | null; lastGateStatus: GateStatus | null; lastGateDelivery: "delivered" | "dead-pane" | "confirmed" | "stuck" | null; lastGateConsumed: boolean | null; /** The daemon watchdog's escalation ladder for this job: strikes so far and when it last acted. Absent when the job is not on the ladder (healthy, no watchdog wired, or the daemon restarted since). */ watchdog?: { strikes: number; lastPokeAt: number | null } }>;
|
|
175
175
|
unread: number;
|
|
176
176
|
lifecycleConnected: boolean;
|
|
177
177
|
hiddenUp: boolean | null;
|
|
@@ -349,6 +349,11 @@ export interface ReconcilerStatus {
|
|
|
349
349
|
executors: ExecutorView[];
|
|
350
350
|
}
|
|
351
351
|
|
|
352
|
+
/** What a claude spawn's folder-trust check established, when one ran:
|
|
353
|
+
`none` = no dialog was up, `accepted` = one was answered, `stuck` = one is
|
|
354
|
+
still up and needs a human, `unchecked` = nothing could be established. */
|
|
355
|
+
export type TrustOutcome = "none" | "accepted" | "stuck" | "unchecked";
|
|
356
|
+
|
|
352
357
|
export interface AgentRecord {
|
|
353
358
|
id: string; repo: string; cwd: string; provider: string;
|
|
354
359
|
surface: AgentSurface; sessionId: string;
|
|
@@ -618,7 +623,7 @@ export interface Commands {
|
|
|
618
623
|
"chat:dm-open": { payload: { from: string; to: string; sessionId?: string }; data: { room: string; created: boolean } };
|
|
619
624
|
|
|
620
625
|
// ─── Agent handoff (rt agent) ────────────────────────────────────────────
|
|
621
|
-
"agent:start": { payload: { repo: string; cwd: string; prompt?: string; surface?: AgentSurface; provider?: string; 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; yolo?: boolean }; data: AgentRecord };
|
|
626
|
+
"agent:start": { payload: { repo: string; cwd: string; prompt?: string; surface?: AgentSurface; provider?: string; 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; yolo?: boolean; /** How long the folder-trust check lets the dialog paint before reading the screen; interactive launches keep the short default, herd:spawn passes its own longer budget. */ trustWaitMs?: number }; data: AgentRecord & { trust?: TrustOutcome } };
|
|
622
627
|
"agent:resume": { payload: { id: string; prompt?: string; surface?: AgentSurface; workspace?: string; tab?: string }; data: AgentRecord };
|
|
623
628
|
"agent:get": { payload: { id: string }; data: AgentRecord };
|
|
624
629
|
"agent:list": { payload: { repo?: string }; data: { agents: AgentRecord[] } };
|
|
@@ -751,8 +756,8 @@ export interface Commands {
|
|
|
751
756
|
"gate:subscriptions": { payload: { session?: string; live?: boolean }; data: { subscriptions: GateSubscription[] } };
|
|
752
757
|
|
|
753
758
|
// ─── Herd (shepherd run registry) ────────────────────────────────────────
|
|
754
|
-
"herd:start": { payload: { name: string; repo: string; session: string; hidden?: boolean }; data: { herd: string; room: string; workspace: string; subscription: string; handle: string; hidden: boolean } };
|
|
755
|
-
"herd:resume": { payload: { herd: string; session: string }; data: { subscription: string; gates: GateRow[]; unread: number; status: HerdStatusData; handle: string } };
|
|
759
|
+
"herd:start": { payload: { name: string; repo: string; session: string; hidden?: boolean; callerPane?: string }; data: { herd: string; room: string; workspace: string; subscription: string; handle: string; hidden: boolean } };
|
|
760
|
+
"herd:resume": { payload: { herd: string; session: string; callerPane?: string }; data: { subscription: string; gates: GateRow[]; unread: number; status: HerdStatusData; handle: string } };
|
|
756
761
|
"herd:status": { payload: { herd: string }; data: HerdStatusData };
|
|
757
762
|
/** Active herds only unless `all`, so a shepherd's "which herd am I on" question has one answer. */
|
|
758
763
|
"herd:list": { payload: { all?: boolean }; data: { herds: HerdListRow[] } };
|
|
@@ -751,4 +751,78 @@ export const REGISTRY: readonly SettingDef[] = [
|
|
|
751
751
|
merge: "replace",
|
|
752
752
|
description: "Minutes an open herd-owned gate waits before the escalation sweep surfaces it to the human (topic gate/escalated/<id>). Fires on either trigger: the TTL elapses (reason \"ttl\"), or the owning herd's shepherd subscription is gone or dead before the TTL (reason \"owner-dead\"). 0 escalates any eligible gate on the first sweep after it opens. A fresh key, not an ownership-latch port, so a default is fine here.",
|
|
753
753
|
},
|
|
754
|
+
|
|
755
|
+
// --- herd (watchdog) ---------------------------------------------------
|
|
756
|
+
{
|
|
757
|
+
key: "herd.watchdog.enabled",
|
|
758
|
+
type: "boolean",
|
|
759
|
+
scopes: ["machine"],
|
|
760
|
+
default: true,
|
|
761
|
+
merge: "replace",
|
|
762
|
+
description: "Turns the herd watchdog sweep on.",
|
|
763
|
+
},
|
|
764
|
+
{
|
|
765
|
+
key: "herd.watchdog.fastMins",
|
|
766
|
+
type: "number",
|
|
767
|
+
scopes: ["machine"],
|
|
768
|
+
default: 2,
|
|
769
|
+
merge: "replace",
|
|
770
|
+
description: "Idle minutes before a worker with a pending DM, mention, or answered gate is poked.",
|
|
771
|
+
},
|
|
772
|
+
{
|
|
773
|
+
key: "herd.watchdog.shepherdFastMins",
|
|
774
|
+
type: "number",
|
|
775
|
+
scopes: ["machine"],
|
|
776
|
+
default: 5,
|
|
777
|
+
merge: "replace",
|
|
778
|
+
description: "Minutes an open human-owned gate in the herd may stay unanswered before the shepherd is poked. Unread DMs and mentions for the shepherd wedge immediately and are not delayed by this key.",
|
|
779
|
+
},
|
|
780
|
+
{
|
|
781
|
+
key: "herd.watchdog.backstopMins",
|
|
782
|
+
type: "number",
|
|
783
|
+
scopes: ["machine"],
|
|
784
|
+
default: 15,
|
|
785
|
+
merge: "replace",
|
|
786
|
+
description: "Idle minutes before any non-gated active worker is poked.",
|
|
787
|
+
},
|
|
788
|
+
{
|
|
789
|
+
key: "herd.watchdog.retryMins",
|
|
790
|
+
type: "number",
|
|
791
|
+
scopes: ["machine"],
|
|
792
|
+
default: 5,
|
|
793
|
+
merge: "replace",
|
|
794
|
+
description: "Minutes between escalation strikes while the watchdog keeps poking an unresponsive worker.",
|
|
795
|
+
},
|
|
796
|
+
{
|
|
797
|
+
key: "herd.watchdog.notifyQuietMins",
|
|
798
|
+
type: "number",
|
|
799
|
+
scopes: ["machine"],
|
|
800
|
+
default: 30,
|
|
801
|
+
merge: "replace",
|
|
802
|
+
description: "Minimum minutes between macOS notifications for the same herd.",
|
|
803
|
+
},
|
|
804
|
+
{
|
|
805
|
+
key: "herd.watchdog.nagMins",
|
|
806
|
+
type: "number",
|
|
807
|
+
scopes: ["machine"],
|
|
808
|
+
default: 30,
|
|
809
|
+
merge: "replace",
|
|
810
|
+
description: "Minutes a done job may hold its pane before the shepherd is nagged to reclaim it.",
|
|
811
|
+
},
|
|
812
|
+
{
|
|
813
|
+
key: "herd.watchdog.notifyHuman",
|
|
814
|
+
type: "boolean",
|
|
815
|
+
scopes: ["machine"],
|
|
816
|
+
default: true,
|
|
817
|
+
merge: "replace",
|
|
818
|
+
description: "Whether the watchdog's top escalation rung sends a macOS notification to the human.",
|
|
819
|
+
},
|
|
820
|
+
{
|
|
821
|
+
key: "herd.watchdog.midRunTrustAccept",
|
|
822
|
+
type: "boolean",
|
|
823
|
+
scopes: ["machine"],
|
|
824
|
+
default: false,
|
|
825
|
+
merge: "replace",
|
|
826
|
+
description: "Whether the watchdog may drive a mid-run folder-trust dialog on a daemon-provisioned tree itself, rather than only parking the job and notifying (RT-196). Off by default: the screen match cannot yet confirm the dialog's folder matches the job's worktree, so a working session showing an unrelated permission prompt with the same shape is a real risk.",
|
|
827
|
+
},
|
|
754
828
|
];
|