@seat-mesh/daemon 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/border-paint.d.ts +11 -0
- package/dist/border-paint.d.ts.map +1 -0
- package/dist/border-paint.js +163 -0
- package/dist/border-paint.js.map +1 -0
- package/dist/bullmq-runtime.d.ts +19 -0
- package/dist/bullmq-runtime.d.ts.map +1 -0
- package/dist/bullmq-runtime.js +78 -0
- package/dist/bullmq-runtime.js.map +1 -0
- package/dist/compose-gate.d.ts +18 -0
- package/dist/compose-gate.d.ts.map +1 -0
- package/dist/compose-gate.js +80 -0
- package/dist/compose-gate.js.map +1 -0
- package/dist/compose-gate.test.d.ts +2 -0
- package/dist/compose-gate.test.d.ts.map +1 -0
- package/dist/compose-gate.test.js +35 -0
- package/dist/compose-gate.test.js.map +1 -0
- package/dist/connectivity-recovery.d.ts +81 -0
- package/dist/connectivity-recovery.d.ts.map +1 -0
- package/dist/connectivity-recovery.js +454 -0
- package/dist/connectivity-recovery.js.map +1 -0
- package/dist/connectivity-recovery.test.d.ts +2 -0
- package/dist/connectivity-recovery.test.d.ts.map +1 -0
- package/dist/connectivity-recovery.test.js +147 -0
- package/dist/connectivity-recovery.test.js.map +1 -0
- package/dist/create-queue-store.d.ts +8 -0
- package/dist/create-queue-store.d.ts.map +1 -0
- package/dist/create-queue-store.js +13 -0
- package/dist/create-queue-store.js.map +1 -0
- package/dist/delivery-hold.d.ts +10 -0
- package/dist/delivery-hold.d.ts.map +1 -0
- package/dist/delivery-hold.js +21 -0
- package/dist/delivery-hold.js.map +1 -0
- package/dist/delivery-hold.test.d.ts +2 -0
- package/dist/delivery-hold.test.d.ts.map +1 -0
- package/dist/delivery-hold.test.js +35 -0
- package/dist/delivery-hold.test.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/inject-delivery.d.ts +26 -0
- package/dist/inject-delivery.d.ts.map +1 -0
- package/dist/inject-delivery.js +108 -0
- package/dist/inject-delivery.js.map +1 -0
- package/dist/inject-delivery.test.d.ts +2 -0
- package/dist/inject-delivery.test.d.ts.map +1 -0
- package/dist/inject-delivery.test.js +14 -0
- package/dist/inject-delivery.test.js.map +1 -0
- package/dist/jsonl-dedupe.test.d.ts +2 -0
- package/dist/jsonl-dedupe.test.d.ts.map +1 -0
- package/dist/jsonl-dedupe.test.js +27 -0
- package/dist/jsonl-dedupe.test.js.map +1 -0
- package/dist/jsonl-store.d.ts +103 -0
- package/dist/jsonl-store.d.ts.map +1 -0
- package/dist/jsonl-store.js +235 -0
- package/dist/jsonl-store.js.map +1 -0
- package/dist/mesh-inbox-server.d.ts +3 -0
- package/dist/mesh-inbox-server.d.ts.map +1 -0
- package/dist/mesh-inbox-server.js +483 -0
- package/dist/mesh-inbox-server.js.map +1 -0
- package/dist/mesh-inbox-supervisor.d.ts +3 -0
- package/dist/mesh-inbox-supervisor.d.ts.map +1 -0
- package/dist/mesh-inbox-supervisor.js +227 -0
- package/dist/mesh-inbox-supervisor.js.map +1 -0
- package/dist/mesh-orchestrator.d.ts +32 -0
- package/dist/mesh-orchestrator.d.ts.map +1 -0
- package/dist/mesh-orchestrator.js +340 -0
- package/dist/mesh-orchestrator.js.map +1 -0
- package/dist/oc-resume-ack.d.ts +32 -0
- package/dist/oc-resume-ack.d.ts.map +1 -0
- package/dist/oc-resume-ack.js +89 -0
- package/dist/oc-resume-ack.js.map +1 -0
- package/dist/oc-resume-ack.test.d.ts +2 -0
- package/dist/oc-resume-ack.test.d.ts.map +1 -0
- package/dist/oc-resume-ack.test.js +23 -0
- package/dist/oc-resume-ack.test.js.map +1 -0
- package/dist/oc-resume.d.ts +25 -0
- package/dist/oc-resume.d.ts.map +1 -0
- package/dist/oc-resume.js +102 -0
- package/dist/oc-resume.js.map +1 -0
- package/dist/orchestrator.d.ts +17 -0
- package/dist/orchestrator.d.ts.map +1 -0
- package/dist/orchestrator.js +11 -0
- package/dist/orchestrator.js.map +1 -0
- package/dist/pane-ops-drain.d.ts +14 -0
- package/dist/pane-ops-drain.d.ts.map +1 -0
- package/dist/pane-ops-drain.js +53 -0
- package/dist/pane-ops-drain.js.map +1 -0
- package/dist/peer-backlog.d.ts +18 -0
- package/dist/peer-backlog.d.ts.map +1 -0
- package/dist/peer-backlog.js +137 -0
- package/dist/peer-backlog.js.map +1 -0
- package/dist/peer-comms-checkback.d.ts +5 -0
- package/dist/peer-comms-checkback.d.ts.map +1 -0
- package/dist/peer-comms-checkback.js +57 -0
- package/dist/peer-comms-checkback.js.map +1 -0
- package/dist/peer-skip.d.ts +10 -0
- package/dist/peer-skip.d.ts.map +1 -0
- package/dist/peer-skip.js +26 -0
- package/dist/peer-skip.js.map +1 -0
- package/dist/peer-skip.test.d.ts +2 -0
- package/dist/peer-skip.test.d.ts.map +1 -0
- package/dist/peer-skip.test.js +33 -0
- package/dist/peer-skip.test.js.map +1 -0
- package/dist/ppa-state.d.ts +32 -0
- package/dist/ppa-state.d.ts.map +1 -0
- package/dist/ppa-state.js +63 -0
- package/dist/ppa-state.js.map +1 -0
- package/dist/sqlite-store.d.ts +44 -0
- package/dist/sqlite-store.d.ts.map +1 -0
- package/dist/sqlite-store.js +422 -0
- package/dist/sqlite-store.js.map +1 -0
- package/dist/sqlite-store.test.d.ts +2 -0
- package/dist/sqlite-store.test.d.ts.map +1 -0
- package/dist/sqlite-store.test.js +63 -0
- package/dist/sqlite-store.test.js.map +1 -0
- package/dist/workers.d.ts +11 -0
- package/dist/workers.d.ts.map +1 -0
- package/dist/workers.js +12 -0
- package/dist/workers.js.map +1 -0
- package/package.json +28 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { LoadedProfile, ProviderRegistry, ResolvedUxConfig } from "@seat-mesh/core";
|
|
2
|
+
import type { QueueStore } from "./create-queue-store.js";
|
|
3
|
+
export interface BorderPaintConnectivity {
|
|
4
|
+
proxyDownActive: boolean;
|
|
5
|
+
ocLimitedPaneIds: Set<string>;
|
|
6
|
+
}
|
|
7
|
+
/** Immediate border refresh for one pane (e.g. after resume ack clears OC-LIMIT). */
|
|
8
|
+
export declare function repaintMeshPaneBorder(registry: ProviderRegistry, store: QueueStore, paneId: string, connectivity?: BorderPaintConnectivity, inheritGlobal?: boolean, label?: string, stateDir?: string, ux?: ResolvedUxConfig | null): void;
|
|
9
|
+
/** Paint @mesh_status (+ optional @mesh_patience) on live panes. */
|
|
10
|
+
export declare function paintMeshBorders(loaded: LoadedProfile, registry: ProviderRegistry, store: QueueStore, session: string, baseWindow: string, workersWindow: string, minisWindow: string, skipPaneIds?: Set<string>, connectivity?: BorderPaintConnectivity, stateDir?: string): void;
|
|
11
|
+
//# sourceMappingURL=border-paint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"border-paint.d.ts","sourceRoot":"","sources":["../src/border-paint.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAiB,aAAa,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAUxG,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AA0B1D,MAAM,WAAW,uBAAuB;IACtC,eAAe,EAAE,OAAO,CAAC;IACzB,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC/B;AA0ED,qFAAqF;AACrF,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,gBAAgB,EAC1B,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,uBAAuB,EACtC,aAAa,UAAQ,EACrB,KAAK,SAAK,EACV,QAAQ,CAAC,EAAE,MAAM,EACjB,EAAE,CAAC,EAAE,gBAAgB,GAAG,IAAI,GAC3B,IAAI,CAIN;AAED,oEAAoE;AACpE,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,gBAAgB,EAC1B,KAAK,EAAE,UAAU,EACjB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,MAAM,EACnB,WAAW,GAAE,GAAG,CAAC,MAAM,CAAa,EACpC,YAAY,CAAC,EAAE,uBAAuB,EACtC,QAAQ,CAAC,EAAE,MAAM,GAChB,IAAI,CA0FN"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { evaluateUxRules, resolveUxConfig } from "@seat-mesh/core";
|
|
3
|
+
import { capturePaneSnapshot, listMeshMinis, listMeshWorkers, meshManagerPane, meshSecretaryPane, } from "@seat-mesh/tmux";
|
|
4
|
+
import { classifyCoordDelivery } from "./compose-gate.js";
|
|
5
|
+
import { PpaStateStore } from "./ppa-state.js";
|
|
6
|
+
let ppaStore = null;
|
|
7
|
+
function ppaForStateDir(stateDir) {
|
|
8
|
+
if (!ppaStore)
|
|
9
|
+
ppaStore = new PpaStateStore(stateDir);
|
|
10
|
+
return ppaStore;
|
|
11
|
+
}
|
|
12
|
+
function tmuxSet(paneId, key, value) {
|
|
13
|
+
spawnSync("tmux", ["set-option", "-p", "-t", paneId, key, value], { encoding: "utf8" });
|
|
14
|
+
}
|
|
15
|
+
const BORDER_PAINT_BATCH = 6;
|
|
16
|
+
let borderPaintOffset = 0;
|
|
17
|
+
function phaseLabel(phase, busyLabel, limitKind) {
|
|
18
|
+
if (phase === "busy")
|
|
19
|
+
return busyLabel ?? "BUSY";
|
|
20
|
+
if (phase === "limit")
|
|
21
|
+
return limitKind ?? "LIMIT";
|
|
22
|
+
if (phase === "typing")
|
|
23
|
+
return "typing";
|
|
24
|
+
if (phase === "afk")
|
|
25
|
+
return "AFK";
|
|
26
|
+
if (phase === "plain_shell")
|
|
27
|
+
return "empty";
|
|
28
|
+
return "idle";
|
|
29
|
+
}
|
|
30
|
+
function borderFromState(st, ux, snap, provId) {
|
|
31
|
+
if (st.phase === "limit") {
|
|
32
|
+
if (ux) {
|
|
33
|
+
const uxHit = evaluateUxRules(snap, provId, ux);
|
|
34
|
+
if (uxHit?.border)
|
|
35
|
+
return uxHit.border;
|
|
36
|
+
}
|
|
37
|
+
if (st.limitKind === "oc-connect")
|
|
38
|
+
return "PROXY-DOWN";
|
|
39
|
+
return `OC-LIMIT:${st.limitKind ?? "limit"}`;
|
|
40
|
+
}
|
|
41
|
+
if (ux) {
|
|
42
|
+
const uxHit = evaluateUxRules(snap, provId, ux);
|
|
43
|
+
if (uxHit?.border)
|
|
44
|
+
return uxHit.border;
|
|
45
|
+
}
|
|
46
|
+
return phaseLabel(st.phase, st.busyLabel, st.limitKind);
|
|
47
|
+
}
|
|
48
|
+
function paintOnePaneBorder(registry, store, paneId, connectivity, inheritGlobal, label, ppa, activeCb, ux) {
|
|
49
|
+
const snap = capturePaneSnapshot(paneId);
|
|
50
|
+
if (!snap)
|
|
51
|
+
return;
|
|
52
|
+
const prov = registry.detect(snap);
|
|
53
|
+
if (!prov) {
|
|
54
|
+
tmuxSet(paneId, "@mesh_status", "empty");
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const st = prov.composerState(snap);
|
|
58
|
+
let borderStatus = borderFromState(st, ux, snap, prov.id);
|
|
59
|
+
if (st.phase !== "limit" &&
|
|
60
|
+
inheritGlobal &&
|
|
61
|
+
connectivity &&
|
|
62
|
+
(connectivity.proxyDownActive || connectivity.ocLimitedPaneIds.size > 0)) {
|
|
63
|
+
borderStatus = connectivity.proxyDownActive ? "PROXY-DOWN" : "OC-LIMIT:oc-limit";
|
|
64
|
+
}
|
|
65
|
+
tmuxSet(paneId, "@mesh_status", borderStatus);
|
|
66
|
+
if (ppa && label) {
|
|
67
|
+
ppa.touch({
|
|
68
|
+
paneId,
|
|
69
|
+
label,
|
|
70
|
+
agent: prov.id,
|
|
71
|
+
border: borderStatus,
|
|
72
|
+
composerPhase: st.phase,
|
|
73
|
+
composerLabel: st.busyLabel ?? st.limitKind ?? "",
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
const ownerCb = store
|
|
77
|
+
.readCheckbacks()
|
|
78
|
+
.filter((r) => r.status === "active" && r.ownerPane === paneId).length;
|
|
79
|
+
if (ownerCb > 0) {
|
|
80
|
+
tmuxSet(paneId, "@mesh_patience", `PS:${ownerCb}`);
|
|
81
|
+
}
|
|
82
|
+
else if (activeCb > 0) {
|
|
83
|
+
tmuxSet(paneId, "@mesh_patience", `PO:${activeCb}`);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
tmuxSet(paneId, "@mesh_patience", "");
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/** Immediate border refresh for one pane (e.g. after resume ack clears OC-LIMIT). */
|
|
90
|
+
export function repaintMeshPaneBorder(registry, store, paneId, connectivity, inheritGlobal = false, label = "", stateDir, ux) {
|
|
91
|
+
const ppa = stateDir ? ppaForStateDir(stateDir) : null;
|
|
92
|
+
const activeCb = store.readCheckbacks().filter((r) => r.status === "active").length;
|
|
93
|
+
paintOnePaneBorder(registry, store, paneId, connectivity, inheritGlobal, label, ppa, activeCb, ux);
|
|
94
|
+
}
|
|
95
|
+
/** Paint @mesh_status (+ optional @mesh_patience) on live panes. */
|
|
96
|
+
export function paintMeshBorders(loaded, registry, store, session, baseWindow, workersWindow, minisWindow, skipPaneIds = new Set(), connectivity, stateDir) {
|
|
97
|
+
const ux = loaded.profile.ux !== undefined ? resolveUxConfig(loaded.profile.ux) : null;
|
|
98
|
+
const ppa = stateDir ? ppaForStateDir(stateDir) : null;
|
|
99
|
+
const activeCb = store.readCheckbacks().filter((r) => r.status === "active").length;
|
|
100
|
+
const unresolved = store.readInbox().filter((r) => !r.resolved).length;
|
|
101
|
+
const unsent = store
|
|
102
|
+
.readInbox()
|
|
103
|
+
.filter((r) => !r.resolved && !(r.sent && r.sentAt && r.deliverPane)).length;
|
|
104
|
+
const paintOne = (paneId, _defaultPorts, inheritGlobal = false, label = "") => {
|
|
105
|
+
if (skipPaneIds.has(paneId))
|
|
106
|
+
return;
|
|
107
|
+
paintOnePaneBorder(registry, store, paneId, connectivity, inheritGlobal, label, ppa, activeCb, ux);
|
|
108
|
+
};
|
|
109
|
+
const targets = [
|
|
110
|
+
...listMeshWorkers(session, workersWindow).map((w) => ({
|
|
111
|
+
paneId: w.paneId,
|
|
112
|
+
ports: w.ports,
|
|
113
|
+
label: `slot-${w.slot}`,
|
|
114
|
+
})),
|
|
115
|
+
...listMeshMinis(session, minisWindow).map((m) => ({
|
|
116
|
+
paneId: m.paneId,
|
|
117
|
+
ports: m.ports,
|
|
118
|
+
label: `mini-${m.mini}`,
|
|
119
|
+
})),
|
|
120
|
+
];
|
|
121
|
+
if (targets.length) {
|
|
122
|
+
const batch = Math.min(BORDER_PAINT_BATCH, targets.length);
|
|
123
|
+
for (let i = 0; i < batch; i++) {
|
|
124
|
+
const t = targets[(borderPaintOffset + i) % targets.length];
|
|
125
|
+
paintOne(t.paneId, t.ports, false, t.label);
|
|
126
|
+
}
|
|
127
|
+
borderPaintOffset = (borderPaintOffset + batch) % targets.length;
|
|
128
|
+
}
|
|
129
|
+
const paintCoordInboxOrComposer = (paneId, ports, label, inheritGlobal) => {
|
|
130
|
+
if (unsent > 0) {
|
|
131
|
+
const snap = capturePaneSnapshot(paneId);
|
|
132
|
+
const prov = snap ? registry.detect(snap) : null;
|
|
133
|
+
const st = prov && snap ? prov.composerState(snap) : null;
|
|
134
|
+
const gate = prov && snap && st
|
|
135
|
+
? classifyCoordDelivery(paneId, st, snap.captureTail, prov.id)
|
|
136
|
+
: null;
|
|
137
|
+
let suffix = "pending";
|
|
138
|
+
if (gate?.phase === "wait-typing")
|
|
139
|
+
suffix = "wait typing";
|
|
140
|
+
else if (gate?.phase === "wait-busy")
|
|
141
|
+
suffix = "wait generate";
|
|
142
|
+
else if (gate?.phase === "wait-settle" && gate.settleInSec != null) {
|
|
143
|
+
suffix = `settle ${gate.settleInSec}s`;
|
|
144
|
+
}
|
|
145
|
+
tmuxSet(paneId, "@mesh_status", `INBOX · ${unsent} · ${suffix}`);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
if (unresolved > 0) {
|
|
149
|
+
tmuxSet(paneId, "@mesh_status", `INBOX · ${unresolved} unresolved`);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
paintOne(paneId, ports, inheritGlobal, label);
|
|
153
|
+
};
|
|
154
|
+
const mgr = meshManagerPane(session, baseWindow);
|
|
155
|
+
if (mgr) {
|
|
156
|
+
paintCoordInboxOrComposer(mgr, "manager", "manager", false);
|
|
157
|
+
}
|
|
158
|
+
const sec = meshSecretaryPane(session, baseWindow);
|
|
159
|
+
if (sec) {
|
|
160
|
+
paintOne(sec, "secretary", true, "secretary");
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=border-paint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"border-paint.js","sourceRoot":"","sources":["../src/border-paint.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Queue, Worker } from "bullmq";
|
|
2
|
+
import { Redis } from "ioredis";
|
|
3
|
+
export type InjectJobOp = "drain-tick" | "inbox-row" | "peer-row";
|
|
4
|
+
export interface InjectJobData {
|
|
5
|
+
op: InjectJobOp;
|
|
6
|
+
rowId?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface BullmqRuntime {
|
|
9
|
+
connection: Redis;
|
|
10
|
+
injectQueue: Queue<InjectJobData>;
|
|
11
|
+
injectWorker: Worker<InjectJobData>;
|
|
12
|
+
close: () => Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
/** Returns null when Redis is unreachable (host poll loop remains the fallback). */
|
|
15
|
+
export declare function startBullmqRuntime(redisUrl: string, processor: (job: InjectJobData) => Promise<void>, log: (line: string) => void): Promise<BullmqRuntime | null>;
|
|
16
|
+
export declare function enqueueDrainTick(queue: Queue<InjectJobData>): Promise<void>;
|
|
17
|
+
export declare function enqueueInboxRow(queue: Queue<InjectJobData>, rowId: string): Promise<void>;
|
|
18
|
+
export declare function enqueuePeerRow(queue: Queue<InjectJobData>, rowId: string): Promise<void>;
|
|
19
|
+
//# sourceMappingURL=bullmq-runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bullmq-runtime.d.ts","sourceRoot":"","sources":["../src/bullmq-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,EAA0B,MAAM,QAAQ,CAAC;AAC/D,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAGhC,MAAM,MAAM,WAAW,GAAG,YAAY,GAAG,WAAW,GAAG,UAAU,CAAC;AAElE,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,WAAW,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,KAAK,CAAC;IAClB,WAAW,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC;IAClC,YAAY,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC;IACpC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AAED,oFAAoF;AACpF,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,EAChD,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAC1B,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAqE/B;AAED,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,KAAK,CAAC,aAAa,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAMjF;AAED,wBAAsB,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC,aAAa,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/F;AAED,wBAAsB,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,aAAa,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE9F"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { Queue, Worker } from "bullmq";
|
|
2
|
+
import { Redis } from "ioredis";
|
|
3
|
+
import { QUEUE_NAMES } from "./workers.js";
|
|
4
|
+
/** Returns null when Redis is unreachable (host poll loop remains the fallback). */
|
|
5
|
+
export async function startBullmqRuntime(redisUrl, processor, log) {
|
|
6
|
+
const connection = new Redis(redisUrl, {
|
|
7
|
+
maxRetriesPerRequest: null,
|
|
8
|
+
connectTimeout: 2500,
|
|
9
|
+
lazyConnect: true,
|
|
10
|
+
});
|
|
11
|
+
try {
|
|
12
|
+
await connection.connect();
|
|
13
|
+
await connection.ping();
|
|
14
|
+
}
|
|
15
|
+
catch (e) {
|
|
16
|
+
log(`BULLMQ skipped (redis unreachable): ${e.message}`);
|
|
17
|
+
try {
|
|
18
|
+
await connection.quit();
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
/* ignore */
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
const injectQueue = new Queue(QUEUE_NAMES.inject, {
|
|
27
|
+
connection: connection,
|
|
28
|
+
defaultJobOptions: {
|
|
29
|
+
removeOnComplete: 100,
|
|
30
|
+
removeOnFail: 50,
|
|
31
|
+
attempts: 8,
|
|
32
|
+
backoff: { type: "fixed", delay: 2000 },
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
const injectWorker = new Worker(QUEUE_NAMES.inject, async (job) => {
|
|
36
|
+
await processor(job.data);
|
|
37
|
+
}, {
|
|
38
|
+
connection: connection,
|
|
39
|
+
concurrency: 1,
|
|
40
|
+
});
|
|
41
|
+
injectWorker.on("failed", (job, err) => {
|
|
42
|
+
if (job?.data?.op) {
|
|
43
|
+
log(`BULLMQ fail op=${job.data.op} ${err.message}`);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
log(`BULLMQ connected ${redisUrl} queue=${QUEUE_NAMES.inject}`);
|
|
47
|
+
return {
|
|
48
|
+
connection,
|
|
49
|
+
injectQueue,
|
|
50
|
+
injectWorker,
|
|
51
|
+
close: async () => {
|
|
52
|
+
await injectWorker.close();
|
|
53
|
+
await injectQueue.close();
|
|
54
|
+
await connection.quit();
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
catch (e) {
|
|
59
|
+
log(`BULLMQ init failed: ${e.message}`);
|
|
60
|
+
try {
|
|
61
|
+
await connection.quit();
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
/* ignore */
|
|
65
|
+
}
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
export async function enqueueDrainTick(queue) {
|
|
70
|
+
await queue.add("drain-tick", { op: "drain-tick" }, { jobId: `drain-tick-${Date.now()}`, removeOnComplete: true });
|
|
71
|
+
}
|
|
72
|
+
export async function enqueueInboxRow(queue, rowId) {
|
|
73
|
+
await queue.add("inbox-row", { op: "inbox-row", rowId }, { jobId: `inbox-${rowId}` });
|
|
74
|
+
}
|
|
75
|
+
export async function enqueuePeerRow(queue, rowId) {
|
|
76
|
+
await queue.add("peer-row", { op: "peer-row", rowId }, { jobId: `peer-${rowId}` });
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=bullmq-runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bullmq-runtime.js","sourceRoot":"","sources":["../src/bullmq-runtime.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ComposerState } from "@seat-mesh/core";
|
|
2
|
+
/** Post-generate / empty-composer settle (manager + secretary only). */
|
|
3
|
+
export declare const COORD_IDLE_SETTLE_MS: number;
|
|
4
|
+
export type CoordGatePhase = "idle" | "wait-busy" | "wait-typing" | "wait-settle" | "wait-not-ready" | "plain_shell";
|
|
5
|
+
export interface CoordGateResult {
|
|
6
|
+
phase: CoordGatePhase;
|
|
7
|
+
canDeliver: boolean;
|
|
8
|
+
settleInSec?: number;
|
|
9
|
+
draftFp?: string;
|
|
10
|
+
}
|
|
11
|
+
/** Reset gate clocks (tests). */
|
|
12
|
+
export declare function resetCoordGateState(paneId?: string): void;
|
|
13
|
+
/**
|
|
14
|
+
* Manager/secretary inject gate: never paste while generating or typing;
|
|
15
|
+
* after generate ends, wait full COORD_IDLE_SETTLE_MS before idle inject.
|
|
16
|
+
*/
|
|
17
|
+
export declare function classifyCoordDelivery(paneId: string, state: ComposerState, captureTail: string, providerId: string, nowMs?: number): CoordGateResult;
|
|
18
|
+
//# sourceMappingURL=compose-gate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compose-gate.d.ts","sourceRoot":"","sources":["../src/compose-gate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGrD,wEAAwE;AACxE,eAAO,MAAM,oBAAoB,QAAwD,CAAC;AAE1F,MAAM,MAAM,cAAc,GACtB,MAAM,GACN,WAAW,GACX,aAAa,GACb,aAAa,GACb,gBAAgB,GAChB,aAAa,CAAC;AAElB,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,cAAc,CAAC;IACtB,UAAU,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAmBD,iCAAiC;AACjC,wBAAgB,mBAAmB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAGzD;AAWD;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,aAAa,EACpB,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,KAAK,SAAa,GACjB,eAAe,CAsDjB"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { coordComposerDraft } from "@seat-mesh/providers";
|
|
2
|
+
/** Post-generate / empty-composer settle (manager + secretary only). */
|
|
3
|
+
export const COORD_IDLE_SETTLE_MS = Number(process.env.MESH_INBOX_IDLE_SETTLE_MS ?? 5000);
|
|
4
|
+
const gateByPane = new Map();
|
|
5
|
+
function gateState(paneId) {
|
|
6
|
+
let s = gateByPane.get(paneId);
|
|
7
|
+
if (!s) {
|
|
8
|
+
s = { wasBusy: false, lastBusyEndedAt: 0, idleReadySince: 0 };
|
|
9
|
+
gateByPane.set(paneId, s);
|
|
10
|
+
}
|
|
11
|
+
return s;
|
|
12
|
+
}
|
|
13
|
+
/** Reset gate clocks (tests). */
|
|
14
|
+
export function resetCoordGateState(paneId) {
|
|
15
|
+
if (paneId)
|
|
16
|
+
gateByPane.delete(paneId);
|
|
17
|
+
else
|
|
18
|
+
gateByPane.clear();
|
|
19
|
+
}
|
|
20
|
+
function composerIdleReady(state, captureTail, providerId) {
|
|
21
|
+
if (state.phase === "plain_shell" || state.phase === "limit")
|
|
22
|
+
return false;
|
|
23
|
+
if (state.phase === "busy" || state.phase === "typing")
|
|
24
|
+
return false;
|
|
25
|
+
const draft = state.draftFingerprint?.trim() || coordComposerDraft(captureTail, providerId);
|
|
26
|
+
if (draft)
|
|
27
|
+
return false;
|
|
28
|
+
return state.phase === "empty" || state.phase === "afk";
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Manager/secretary inject gate: never paste while generating or typing;
|
|
32
|
+
* after generate ends, wait full COORD_IDLE_SETTLE_MS before idle inject.
|
|
33
|
+
*/
|
|
34
|
+
export function classifyCoordDelivery(paneId, state, captureTail, providerId, nowMs = Date.now()) {
|
|
35
|
+
const st = gateState(paneId);
|
|
36
|
+
if (state.phase === "plain_shell") {
|
|
37
|
+
return { phase: "plain_shell", canDeliver: false };
|
|
38
|
+
}
|
|
39
|
+
if (state.phase === "limit") {
|
|
40
|
+
return { phase: "wait-not-ready", canDeliver: false };
|
|
41
|
+
}
|
|
42
|
+
if (state.phase === "busy") {
|
|
43
|
+
st.wasBusy = true;
|
|
44
|
+
st.idleReadySince = 0;
|
|
45
|
+
return { phase: "wait-busy", canDeliver: false };
|
|
46
|
+
}
|
|
47
|
+
if (st.wasBusy) {
|
|
48
|
+
st.wasBusy = false;
|
|
49
|
+
st.lastBusyEndedAt = nowMs;
|
|
50
|
+
st.idleReadySince = 0;
|
|
51
|
+
}
|
|
52
|
+
const draftFp = state.draftFingerprint?.trim() ||
|
|
53
|
+
coordComposerDraft(captureTail, providerId) ||
|
|
54
|
+
undefined;
|
|
55
|
+
if (state.phase === "typing" || draftFp) {
|
|
56
|
+
st.idleReadySince = 0;
|
|
57
|
+
return { phase: "wait-typing", canDeliver: false, draftFp };
|
|
58
|
+
}
|
|
59
|
+
if (!composerIdleReady(state, captureTail, providerId)) {
|
|
60
|
+
st.idleReadySince = 0;
|
|
61
|
+
return { phase: "wait-not-ready", canDeliver: false };
|
|
62
|
+
}
|
|
63
|
+
if (!st.idleReadySince)
|
|
64
|
+
st.idleReadySince = nowMs;
|
|
65
|
+
const settleSec = COORD_IDLE_SETTLE_MS / 1000;
|
|
66
|
+
const emptySettled = (nowMs - st.idleReadySince) / 1000;
|
|
67
|
+
const busySettled = st.lastBusyEndedAt
|
|
68
|
+
? (nowMs - st.lastBusyEndedAt) / 1000
|
|
69
|
+
: settleSec;
|
|
70
|
+
const settled = Math.min(emptySettled, busySettled);
|
|
71
|
+
if (settled < settleSec) {
|
|
72
|
+
return {
|
|
73
|
+
phase: "wait-settle",
|
|
74
|
+
canDeliver: false,
|
|
75
|
+
settleInSec: Math.max(0, Math.ceil(settleSec - settled)),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
return { phase: "idle", canDeliver: true };
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=compose-gate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compose-gate.js","sourceRoot":"","sources":["../src/compose-gate.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE1D,wEAAwE;AACxE,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,yBAAyB,IAAI,IAAI,CAAC,CAAC;AAuB1F,MAAM,UAAU,GAAG,IAAI,GAAG,EAAyB,CAAC;AAEpD,SAAS,SAAS,CAAC,MAAc;IAC/B,IAAI,CAAC,GAAG,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC/B,IAAI,CAAC,CAAC,EAAE,CAAC;QACP,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,CAAC;QAC9D,UAAU,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,iCAAiC;AACjC,MAAM,UAAU,mBAAmB,CAAC,MAAe;IACjD,IAAI,MAAM;QAAE,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;;QACjC,UAAU,CAAC,KAAK,EAAE,CAAC;AAC1B,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAoB,EAAE,WAAmB,EAAE,UAAkB;IACtF,IAAI,KAAK,CAAC,KAAK,KAAK,aAAa,IAAI,KAAK,CAAC,KAAK,KAAK,OAAO;QAAE,OAAO,KAAK,CAAC;IAC3E,IAAI,KAAK,CAAC,KAAK,KAAK,MAAM,IAAI,KAAK,CAAC,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACrE,MAAM,KAAK,GACT,KAAK,CAAC,gBAAgB,EAAE,IAAI,EAAE,IAAI,kBAAkB,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;IAChF,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC;IACxB,OAAO,KAAK,CAAC,KAAK,KAAK,OAAO,IAAI,KAAK,CAAC,KAAK,KAAK,KAAK,CAAC;AAC1D,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CACnC,MAAc,EACd,KAAoB,EACpB,WAAmB,EACnB,UAAkB,EAClB,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE;IAElB,MAAM,EAAE,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;IAE7B,IAAI,KAAK,CAAC,KAAK,KAAK,aAAa,EAAE,CAAC;QAClC,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;IACrD,CAAC;IACD,IAAI,KAAK,CAAC,KAAK,KAAK,OAAO,EAAE,CAAC;QAC5B,OAAO,EAAE,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;IACxD,CAAC;IAED,IAAI,KAAK,CAAC,KAAK,KAAK,MAAM,EAAE,CAAC;QAC3B,EAAE,CAAC,OAAO,GAAG,IAAI,CAAC;QAClB,EAAE,CAAC,cAAc,GAAG,CAAC,CAAC;QACtB,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;IACnD,CAAC;IAED,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC;QACf,EAAE,CAAC,OAAO,GAAG,KAAK,CAAC;QACnB,EAAE,CAAC,eAAe,GAAG,KAAK,CAAC;QAC3B,EAAE,CAAC,cAAc,GAAG,CAAC,CAAC;IACxB,CAAC;IAED,MAAM,OAAO,GACX,KAAK,CAAC,gBAAgB,EAAE,IAAI,EAAE;QAC9B,kBAAkB,CAAC,WAAW,EAAE,UAAU,CAAC;QAC3C,SAAS,CAAC;IACZ,IAAI,KAAK,CAAC,KAAK,KAAK,QAAQ,IAAI,OAAO,EAAE,CAAC;QACxC,EAAE,CAAC,cAAc,GAAG,CAAC,CAAC;QACtB,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;IAC9D,CAAC;IAED,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE,WAAW,EAAE,UAAU,CAAC,EAAE,CAAC;QACvD,EAAE,CAAC,cAAc,GAAG,CAAC,CAAC;QACtB,OAAO,EAAE,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;IACxD,CAAC;IAED,IAAI,CAAC,EAAE,CAAC,cAAc;QAAE,EAAE,CAAC,cAAc,GAAG,KAAK,CAAC;IAElD,MAAM,SAAS,GAAG,oBAAoB,GAAG,IAAI,CAAC;IAC9C,MAAM,YAAY,GAAG,CAAC,KAAK,GAAG,EAAE,CAAC,cAAc,CAAC,GAAG,IAAI,CAAC;IACxD,MAAM,WAAW,GAAG,EAAE,CAAC,eAAe;QACpC,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC,eAAe,CAAC,GAAG,IAAI;QACrC,CAAC,CAAC,SAAS,CAAC;IACd,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;IAEpD,IAAI,OAAO,GAAG,SAAS,EAAE,CAAC;QACxB,OAAO;YACL,KAAK,EAAE,aAAa;YACpB,UAAU,EAAE,KAAK;YACjB,WAAW,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,CAAC;SACzD,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;AAC7C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compose-gate.test.d.ts","sourceRoot":"","sources":["../src/compose-gate.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { describe, expect, it, beforeEach } from "vitest";
|
|
2
|
+
import { classifyCoordDelivery, COORD_IDLE_SETTLE_MS, resetCoordGateState, } from "./compose-gate.js";
|
|
3
|
+
const PANE = "%99";
|
|
4
|
+
describe("classifyCoordDelivery", () => {
|
|
5
|
+
beforeEach(() => resetCoordGateState(PANE));
|
|
6
|
+
it("holds while busy (generating)", () => {
|
|
7
|
+
const r = classifyCoordDelivery(PANE, { phase: "busy", busyLabel: "Thinking" }, "", "opencode", 1_000_000);
|
|
8
|
+
expect(r.canDeliver).toBe(false);
|
|
9
|
+
expect(r.phase).toBe("wait-busy");
|
|
10
|
+
});
|
|
11
|
+
it("holds while typing / draft", () => {
|
|
12
|
+
const r = classifyCoordDelivery(PANE, { phase: "typing", draftFingerprint: "fix the inbox" }, "", "cursor-agent", 1_000_000);
|
|
13
|
+
expect(r.canDeliver).toBe(false);
|
|
14
|
+
expect(r.phase).toBe("wait-typing");
|
|
15
|
+
});
|
|
16
|
+
it("waits settle after busy ends", () => {
|
|
17
|
+
const t0 = 1_000_000;
|
|
18
|
+
classifyCoordDelivery(PANE, { phase: "busy" }, "", "opencode", t0);
|
|
19
|
+
const r = classifyCoordDelivery(PANE, { phase: "empty" }, "ctrl+p commands\nAsk anything", "opencode", t0 + 1000);
|
|
20
|
+
expect(r.canDeliver).toBe(false);
|
|
21
|
+
expect(r.phase).toBe("wait-settle");
|
|
22
|
+
expect(r.settleInSec).toBeGreaterThan(0);
|
|
23
|
+
});
|
|
24
|
+
it("delivers after full settle window", () => {
|
|
25
|
+
const t0 = 2_000_000;
|
|
26
|
+
const tEdge = t0 + 100;
|
|
27
|
+
classifyCoordDelivery(PANE, { phase: "busy" }, "", "opencode", t0);
|
|
28
|
+
// Rising edge: first poll after generate stops starts both settle clocks.
|
|
29
|
+
classifyCoordDelivery(PANE, { phase: "empty" }, "ctrl+p commands", "opencode", tEdge);
|
|
30
|
+
const r = classifyCoordDelivery(PANE, { phase: "empty" }, "ctrl+p commands", "opencode", tEdge + COORD_IDLE_SETTLE_MS + 100);
|
|
31
|
+
expect(r.canDeliver).toBe(true);
|
|
32
|
+
expect(r.phase).toBe("idle");
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
//# sourceMappingURL=compose-gate.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compose-gate.test.js","sourceRoot":"","sources":["../src/compose-gate.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { type LoadedProfile, type ProviderRegistry } from "@seat-mesh/core";
|
|
2
|
+
import { type ResumeWaveMeta } from "./oc-resume.js";
|
|
3
|
+
/**
|
|
4
|
+
* Seconds left on the Proxy-SMART file cooldown (0 = none / expired).
|
|
5
|
+
* Reads the same stamp file cpe-proxy-smart-restart.sh writes — never the daemon's
|
|
6
|
+
* own state — so the daemon and any harness script agree on cooldown status.
|
|
7
|
+
*/
|
|
8
|
+
export declare function smartRestartCooldownLeftSec(stampPath?: string, cooldownSec?: number, nowMs?: number): number;
|
|
9
|
+
/**
|
|
10
|
+
* Consecutive ipify probe failures before treating carrier as down (debounce flaky curls).
|
|
11
|
+
* Exported for unit testing without tmux/process spawning.
|
|
12
|
+
*/
|
|
13
|
+
export declare function updateIpifyProbeStreak(state: Pick<ConnectivityRecoveryState, "ipifyFailStreak">, carrierOk: boolean, threshold: number): {
|
|
14
|
+
confirmedDown: boolean;
|
|
15
|
+
streak: number;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Pure rising-edge/episode reducer for the OC-LIMIT (rate-limit) state machine.
|
|
19
|
+
* Exported for unit testing without tmux/process spawning.
|
|
20
|
+
*/
|
|
21
|
+
export declare function updateRateLimitEpisode(state: Pick<ConnectivityRecoveryState, "rateLimitEpisodeActive" | "lastRateLimitSeenAt">, anyRateLimitNow: boolean, nowMs?: number, graceMs?: number): {
|
|
22
|
+
action: "start" | "continue" | "clear" | "none";
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Pure decision: after Proxy-SMART exits, should rotate-until run next?
|
|
26
|
+
* Mirrors inbox-server.mjs shouldRunRotateUntilAfterSmart — chain rotate-until
|
|
27
|
+
* when SMART was skipped (cooldown), failed, or the carrier IP did not change.
|
|
28
|
+
*/
|
|
29
|
+
export declare function shouldChainRotateUntilAfterSmart(input: {
|
|
30
|
+
exitCode: number;
|
|
31
|
+
ipBefore: string | null;
|
|
32
|
+
ipAfter: string | null;
|
|
33
|
+
}): boolean;
|
|
34
|
+
/** Drop OC-LIMIT border state for a pane once resume ack confirms it is working again. */
|
|
35
|
+
export declare function clearOcLimitBannerForPane(state: ConnectivityRecoveryState, paneId: string): boolean;
|
|
36
|
+
/** When no panes remain limited, end the OC-LIMIT episode so borders and proxy recovery unlock. */
|
|
37
|
+
export declare function maybeEndRateLimitEpisode(state: ConnectivityRecoveryState): void;
|
|
38
|
+
export interface ConnectivityRecoveryState {
|
|
39
|
+
ocLimited: Set<string>;
|
|
40
|
+
connectPanes: Set<string>;
|
|
41
|
+
proxyDownActive: boolean;
|
|
42
|
+
recoveryRunning: boolean;
|
|
43
|
+
lastProxyUpAt: number;
|
|
44
|
+
lastRotateAt: number;
|
|
45
|
+
/** Carrier IP when PROXY-DOWN episode started (for notify on recovery). */
|
|
46
|
+
carrierIpAtEpisodeStart: string | null;
|
|
47
|
+
/** True while ANY OC pane has shown a rate-limit this episode (rising-edge gate). */
|
|
48
|
+
rateLimitEpisodeActive: boolean;
|
|
49
|
+
/** ms epoch a rate-limited pane was last observed (episode-clear grace timer). */
|
|
50
|
+
lastRateLimitSeenAt: number;
|
|
51
|
+
/** ms epoch the current PROXY-DOWN episode started (0 = no active episode). */
|
|
52
|
+
proxyDownEpisodeStartAt: number;
|
|
53
|
+
/** True once the "still down" toast has fired for the current episode (no repeat spam). */
|
|
54
|
+
proxyDownStuckNotified: boolean;
|
|
55
|
+
/** One Proxy-SMART/rotate-until per OC-LIMIT episode — no restart loop while banner persists. */
|
|
56
|
+
rateLimitRecoveryStarted: boolean;
|
|
57
|
+
/** Consecutive daemon polls where ipify via proxy failed (reset on success). */
|
|
58
|
+
ipifyFailStreak: number;
|
|
59
|
+
}
|
|
60
|
+
export declare function newConnectivityRecoveryState(): ConnectivityRecoveryState;
|
|
61
|
+
/**
|
|
62
|
+
* Pure decision: has a PROXY-DOWN episode been running long enough, with no
|
|
63
|
+
* "still down" toast sent yet, to warrant telling operator it's stuck (not silent)?
|
|
64
|
+
* Exported for unit testing without tmux/process spawning.
|
|
65
|
+
*/
|
|
66
|
+
export declare function shouldNotifyProxyDownStuck(state: Pick<ConnectivityRecoveryState, "proxyDownEpisodeStartAt" | "proxyDownStuckNotified">, nowMs?: number, thresholdMs?: number): boolean;
|
|
67
|
+
export interface ConnectivityPollInput {
|
|
68
|
+
loaded: LoadedProfile;
|
|
69
|
+
registry: ProviderRegistry;
|
|
70
|
+
workspace: string;
|
|
71
|
+
session: string;
|
|
72
|
+
baseWindow: string;
|
|
73
|
+
workersWindow: string;
|
|
74
|
+
minisWindow: string;
|
|
75
|
+
state: ConnectivityRecoveryState;
|
|
76
|
+
log: (line: string) => void;
|
|
77
|
+
resumeOpenCodePanes: (reason: string, meta?: ResumeWaveMeta) => void;
|
|
78
|
+
}
|
|
79
|
+
/** Scan all monitor panes; update limit sets; trigger async recovery on rising edges only. */
|
|
80
|
+
export declare function pollConnectivityRecovery(input: ConnectivityPollInput): void;
|
|
81
|
+
//# sourceMappingURL=connectivity-recovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connectivity-recovery.d.ts","sourceRoot":"","sources":["../src/connectivity-recovery.ts"],"names":[],"mappings":"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"}
|