@drisp/cli 0.5.8 → 0.5.11
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/athena-gateway.js +297 -267
- package/dist/{chunk-XIWMD4GT.js → chunk-2QMUBFZZ.js} +3557 -146
- package/dist/cli.js +309 -3344
- package/dist/dashboard-daemon.js +1 -1
- package/package.json +1 -1
package/dist/athena-gateway.js
CHANGED
|
@@ -24,6 +24,159 @@ import {
|
|
|
24
24
|
// src/gateway/daemon.ts
|
|
25
25
|
import fs4 from "fs";
|
|
26
26
|
|
|
27
|
+
// src/gateway/channelManager.ts
|
|
28
|
+
var DEFAULT_DEDUP_WINDOW = 1024;
|
|
29
|
+
var DuplicateChannelError = class extends Error {
|
|
30
|
+
constructor(id) {
|
|
31
|
+
super(`channel ${id} already registered`);
|
|
32
|
+
this.name = "DuplicateChannelError";
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
var UnknownChannelError = class extends Error {
|
|
36
|
+
constructor(id) {
|
|
37
|
+
super(`channel ${id} not registered`);
|
|
38
|
+
this.name = "UnknownChannelError";
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
var ChannelManager = class {
|
|
42
|
+
entries = /* @__PURE__ */ new Map();
|
|
43
|
+
dedup = [];
|
|
44
|
+
dedupSet = /* @__PURE__ */ new Set();
|
|
45
|
+
dedupMax;
|
|
46
|
+
log;
|
|
47
|
+
inboundSink = null;
|
|
48
|
+
healthSink = null;
|
|
49
|
+
stopped = false;
|
|
50
|
+
constructor(opts = {}) {
|
|
51
|
+
this.dedupMax = opts.dedupWindow ?? DEFAULT_DEDUP_WINDOW;
|
|
52
|
+
this.log = opts.log;
|
|
53
|
+
}
|
|
54
|
+
/** Register the single inbound dispatch target. M5 wires the router here. */
|
|
55
|
+
setInboundSink(sink) {
|
|
56
|
+
this.inboundSink = sink;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Returns the attachmentId associated with `channelId` at registration
|
|
60
|
+
* time, or undefined if the channel is unknown or registered without one.
|
|
61
|
+
*/
|
|
62
|
+
getAttachmentId(channelId) {
|
|
63
|
+
return this.entries.get(channelId)?.attachmentId;
|
|
64
|
+
}
|
|
65
|
+
setHealthSink(sink) {
|
|
66
|
+
this.healthSink = sink;
|
|
67
|
+
}
|
|
68
|
+
listChannels() {
|
|
69
|
+
return [...this.entries.values()].map((e) => ({
|
|
70
|
+
id: e.adapter.id,
|
|
71
|
+
health: e.lastHealth
|
|
72
|
+
}));
|
|
73
|
+
}
|
|
74
|
+
/** Snapshot of currently registered adapters; used by the relay coordinator. */
|
|
75
|
+
listAdapters() {
|
|
76
|
+
return [...this.entries.values()].map((e) => e.adapter);
|
|
77
|
+
}
|
|
78
|
+
async register(adapter, opts = {}) {
|
|
79
|
+
if (this.stopped) {
|
|
80
|
+
throw new Error("channel manager already stopped");
|
|
81
|
+
}
|
|
82
|
+
if (this.entries.has(adapter.id)) {
|
|
83
|
+
throw new DuplicateChannelError(adapter.id);
|
|
84
|
+
}
|
|
85
|
+
const abort = new AbortController();
|
|
86
|
+
const inboundListener = (msg) => this.handleInbound(adapter.id, msg);
|
|
87
|
+
const healthListener = (sample) => {
|
|
88
|
+
const entry2 = this.entries.get(adapter.id);
|
|
89
|
+
if (entry2) entry2.lastHealth = sample;
|
|
90
|
+
this.healthSink?.(sample);
|
|
91
|
+
};
|
|
92
|
+
const startPromise = adapter.start({
|
|
93
|
+
log: (level, msg) => this.log?.(level, `[${adapter.id}] ${msg}`),
|
|
94
|
+
signal: abort.signal,
|
|
95
|
+
emitInbound: inboundListener,
|
|
96
|
+
emitHealth: healthListener
|
|
97
|
+
});
|
|
98
|
+
const entry = {
|
|
99
|
+
adapter,
|
|
100
|
+
abort,
|
|
101
|
+
startPromise
|
|
102
|
+
};
|
|
103
|
+
if (opts.attachmentId !== void 0) entry.attachmentId = opts.attachmentId;
|
|
104
|
+
this.entries.set(adapter.id, entry);
|
|
105
|
+
try {
|
|
106
|
+
await startPromise;
|
|
107
|
+
} catch (err) {
|
|
108
|
+
this.entries.delete(adapter.id);
|
|
109
|
+
throw err;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
async unregister(id, reason) {
|
|
113
|
+
const entry = this.entries.get(id);
|
|
114
|
+
if (!entry) {
|
|
115
|
+
throw new UnknownChannelError(id);
|
|
116
|
+
}
|
|
117
|
+
this.entries.delete(id);
|
|
118
|
+
entry.abort.abort();
|
|
119
|
+
await entry.adapter.stop(reason);
|
|
120
|
+
}
|
|
121
|
+
async send(channelId, msg) {
|
|
122
|
+
const entry = this.entries.get(channelId);
|
|
123
|
+
if (!entry) {
|
|
124
|
+
throw new UnknownChannelError(channelId);
|
|
125
|
+
}
|
|
126
|
+
return entry.adapter.send(msg);
|
|
127
|
+
}
|
|
128
|
+
async probe(channelId) {
|
|
129
|
+
const entry = this.entries.get(channelId);
|
|
130
|
+
if (!entry) {
|
|
131
|
+
throw new UnknownChannelError(channelId);
|
|
132
|
+
}
|
|
133
|
+
return entry.adapter.probe();
|
|
134
|
+
}
|
|
135
|
+
async stop(reason = "shutdown") {
|
|
136
|
+
if (this.stopped) return;
|
|
137
|
+
this.stopped = true;
|
|
138
|
+
const ids = [...this.entries.keys()];
|
|
139
|
+
for (const id of ids.reverse()) {
|
|
140
|
+
try {
|
|
141
|
+
await this.unregister(id, reason);
|
|
142
|
+
} catch (err) {
|
|
143
|
+
this.log?.(
|
|
144
|
+
"warn",
|
|
145
|
+
`channel ${id} stop failed: ${err instanceof Error ? err.message : String(err)}`
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
handleInbound(channelId, msg) {
|
|
151
|
+
if (this.dedupSet.has(msg.idempotencyKey)) {
|
|
152
|
+
this.log?.("debug", `dropping duplicate inbound ${msg.idempotencyKey}`);
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
this.dedupSet.add(msg.idempotencyKey);
|
|
156
|
+
this.dedup.push(msg.idempotencyKey);
|
|
157
|
+
while (this.dedup.length > this.dedupMax) {
|
|
158
|
+
const evicted = this.dedup.shift();
|
|
159
|
+
if (evicted !== void 0) this.dedupSet.delete(evicted);
|
|
160
|
+
}
|
|
161
|
+
const sink = this.inboundSink;
|
|
162
|
+
if (!sink) {
|
|
163
|
+
this.log?.(
|
|
164
|
+
"debug",
|
|
165
|
+
`no inbound sink registered; dropping ${msg.idempotencyKey}`
|
|
166
|
+
);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
try {
|
|
170
|
+
sink(msg, { attachmentId: this.entries.get(channelId)?.attachmentId });
|
|
171
|
+
} catch (err) {
|
|
172
|
+
this.log?.(
|
|
173
|
+
"warn",
|
|
174
|
+
`inbound sink threw: ${err instanceof Error ? err.message : String(err)}`
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
|
|
27
180
|
// src/infra/config/channels.ts
|
|
28
181
|
import fs from "fs";
|
|
29
182
|
import os from "os";
|
|
@@ -1886,158 +2039,144 @@ function instantiateAdapter(sidecar) {
|
|
|
1886
2039
|
return { ok: true, adapter: module.create(parsed.config, sidecar.instanceId) };
|
|
1887
2040
|
}
|
|
1888
2041
|
|
|
1889
|
-
// src/gateway/
|
|
1890
|
-
var
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
this.
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
/**
|
|
1921
|
-
* Returns the attachmentId associated with `channelId` at registration
|
|
1922
|
-
* time, or undefined if the channel is unknown or registered without one.
|
|
1923
|
-
*/
|
|
1924
|
-
getAttachmentId(channelId) {
|
|
1925
|
-
return this.entries.get(channelId)?.attachmentId;
|
|
1926
|
-
}
|
|
1927
|
-
setHealthSink(sink) {
|
|
1928
|
-
this.healthSink = sink;
|
|
1929
|
-
}
|
|
1930
|
-
listChannels() {
|
|
1931
|
-
return [...this.entries.values()].map((e) => ({
|
|
1932
|
-
id: e.adapter.id,
|
|
1933
|
-
health: e.lastHealth
|
|
1934
|
-
}));
|
|
1935
|
-
}
|
|
1936
|
-
/** Snapshot of currently registered adapters; used by the relay coordinator. */
|
|
1937
|
-
listAdapters() {
|
|
1938
|
-
return [...this.entries.values()].map((e) => e.adapter);
|
|
1939
|
-
}
|
|
1940
|
-
async register(adapter, opts = {}) {
|
|
1941
|
-
if (this.stopped) {
|
|
1942
|
-
throw new Error("channel manager already stopped");
|
|
1943
|
-
}
|
|
1944
|
-
if (this.entries.has(adapter.id)) {
|
|
1945
|
-
throw new DuplicateChannelError(adapter.id);
|
|
1946
|
-
}
|
|
1947
|
-
const abort = new AbortController();
|
|
1948
|
-
const inboundListener = (msg) => this.handleInbound(adapter.id, msg);
|
|
1949
|
-
const healthListener = (sample) => {
|
|
1950
|
-
const entry2 = this.entries.get(adapter.id);
|
|
1951
|
-
if (entry2) entry2.lastHealth = sample;
|
|
1952
|
-
this.healthSink?.(sample);
|
|
1953
|
-
};
|
|
1954
|
-
const startPromise = adapter.start({
|
|
1955
|
-
log: (level, msg) => this.log?.(level, `[${adapter.id}] ${msg}`),
|
|
1956
|
-
signal: abort.signal,
|
|
1957
|
-
emitInbound: inboundListener,
|
|
1958
|
-
emitHealth: healthListener
|
|
1959
|
-
});
|
|
1960
|
-
const entry = {
|
|
1961
|
-
adapter,
|
|
1962
|
-
abort,
|
|
1963
|
-
startPromise
|
|
1964
|
-
};
|
|
1965
|
-
if (opts.attachmentId !== void 0) entry.attachmentId = opts.attachmentId;
|
|
1966
|
-
this.entries.set(adapter.id, entry);
|
|
1967
|
-
try {
|
|
1968
|
-
await startPromise;
|
|
1969
|
-
} catch (err) {
|
|
1970
|
-
this.entries.delete(adapter.id);
|
|
1971
|
-
throw err;
|
|
1972
|
-
}
|
|
1973
|
-
}
|
|
1974
|
-
async unregister(id, reason) {
|
|
1975
|
-
const entry = this.entries.get(id);
|
|
1976
|
-
if (!entry) {
|
|
1977
|
-
throw new UnknownChannelError(id);
|
|
1978
|
-
}
|
|
1979
|
-
this.entries.delete(id);
|
|
1980
|
-
entry.abort.abort();
|
|
1981
|
-
await entry.adapter.stop(reason);
|
|
1982
|
-
}
|
|
1983
|
-
async send(channelId, msg) {
|
|
1984
|
-
const entry = this.entries.get(channelId);
|
|
1985
|
-
if (!entry) {
|
|
1986
|
-
throw new UnknownChannelError(channelId);
|
|
2042
|
+
// src/gateway/channelSidecarReconciler.ts
|
|
2043
|
+
var ChannelSidecarReconciler = class {
|
|
2044
|
+
channelManager;
|
|
2045
|
+
home;
|
|
2046
|
+
loadSidecars;
|
|
2047
|
+
instantiateAdapter;
|
|
2048
|
+
stdout;
|
|
2049
|
+
stderr;
|
|
2050
|
+
constructor(opts) {
|
|
2051
|
+
this.channelManager = opts.channelManager;
|
|
2052
|
+
this.home = opts.home;
|
|
2053
|
+
this.loadSidecars = opts.loadSidecars ?? loadChannelSidecars;
|
|
2054
|
+
this.instantiateAdapter = opts.instantiateAdapter ?? instantiateAdapter;
|
|
2055
|
+
this.stdout = opts.stdout ?? ((message) => process.stdout.write(message));
|
|
2056
|
+
this.stderr = opts.stderr ?? ((message) => process.stderr.write(message));
|
|
2057
|
+
}
|
|
2058
|
+
async reconcile(opts) {
|
|
2059
|
+
const results = [];
|
|
2060
|
+
const { sidecars, errors } = this.loadSidecars(this.home);
|
|
2061
|
+
for (const err of errors) {
|
|
2062
|
+
const id = pathIdFromSidecarPath(err.path);
|
|
2063
|
+
results.push({
|
|
2064
|
+
id,
|
|
2065
|
+
ok: false,
|
|
2066
|
+
action: "failed",
|
|
2067
|
+
reason: err.reason
|
|
2068
|
+
});
|
|
2069
|
+
if (opts.logFailures) {
|
|
2070
|
+
this.stderr(`athena-gateway: skipping ${err.path}: ${err.reason}
|
|
2071
|
+
`);
|
|
2072
|
+
}
|
|
1987
2073
|
}
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
2074
|
+
if (opts.unregisterStale) {
|
|
2075
|
+
const sidecarIds = new Set(sidecars.map((sidecar) => sidecar.instanceId));
|
|
2076
|
+
for (const channel of this.channelManager.listChannels()) {
|
|
2077
|
+
if (sidecarIds.has(channel.id)) continue;
|
|
2078
|
+
try {
|
|
2079
|
+
await this.channelManager.unregister(channel.id, "shutdown");
|
|
2080
|
+
results.push({
|
|
2081
|
+
id: channel.id,
|
|
2082
|
+
ok: true,
|
|
2083
|
+
action: "unregistered"
|
|
2084
|
+
});
|
|
2085
|
+
} catch (err) {
|
|
2086
|
+
const reason = errorReason(err);
|
|
2087
|
+
results.push({
|
|
2088
|
+
id: channel.id,
|
|
2089
|
+
ok: false,
|
|
2090
|
+
action: "failed",
|
|
2091
|
+
reason
|
|
2092
|
+
});
|
|
2093
|
+
if (opts.logFailures) {
|
|
2094
|
+
this.stderr(
|
|
2095
|
+
`athena-gateway: unregister ${channel.id} failed: ${reason}
|
|
2096
|
+
`
|
|
2097
|
+
);
|
|
2098
|
+
}
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
1994
2101
|
}
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2102
|
+
for (const sidecar of sidecars) {
|
|
2103
|
+
const existed = this.channelManager.listChannels().some((channel) => channel.id === sidecar.instanceId);
|
|
2104
|
+
if (existed) {
|
|
2105
|
+
try {
|
|
2106
|
+
await this.channelManager.unregister(sidecar.instanceId, "shutdown");
|
|
2107
|
+
} catch (err) {
|
|
2108
|
+
const reason = errorReason(err);
|
|
2109
|
+
results.push({
|
|
2110
|
+
id: sidecar.instanceId,
|
|
2111
|
+
ok: false,
|
|
2112
|
+
action: "failed",
|
|
2113
|
+
reason
|
|
2114
|
+
});
|
|
2115
|
+
if (opts.logFailures) {
|
|
2116
|
+
this.stderr(
|
|
2117
|
+
`athena-gateway: unregister ${sidecar.instanceId} failed: ${reason}
|
|
2118
|
+
`
|
|
2119
|
+
);
|
|
2120
|
+
}
|
|
2121
|
+
continue;
|
|
2122
|
+
}
|
|
2123
|
+
}
|
|
2124
|
+
const built = this.instantiateAdapter(sidecar);
|
|
2125
|
+
if (!built.ok) {
|
|
2126
|
+
results.push({
|
|
2127
|
+
id: sidecar.instanceId,
|
|
2128
|
+
ok: false,
|
|
2129
|
+
action: "failed",
|
|
2130
|
+
reason: built.reason
|
|
2131
|
+
});
|
|
2132
|
+
if (opts.logFailures) {
|
|
2133
|
+
this.stderr(
|
|
2134
|
+
`athena-gateway: ${sidecar.instanceId}: ${built.reason}
|
|
2135
|
+
`
|
|
2136
|
+
);
|
|
2137
|
+
}
|
|
2138
|
+
continue;
|
|
2139
|
+
}
|
|
2002
2140
|
try {
|
|
2003
|
-
await this.
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
"warn",
|
|
2007
|
-
`channel ${id} stop failed: ${err instanceof Error ? err.message : String(err)}`
|
|
2141
|
+
await this.channelManager.register(
|
|
2142
|
+
built.adapter,
|
|
2143
|
+
sidecar.attachmentId !== void 0 ? { attachmentId: sidecar.attachmentId } : {}
|
|
2008
2144
|
);
|
|
2145
|
+
results.push({
|
|
2146
|
+
id: sidecar.instanceId,
|
|
2147
|
+
ok: true,
|
|
2148
|
+
action: existed ? "replaced" : "registered"
|
|
2149
|
+
});
|
|
2150
|
+
if (opts.logRegistrations) {
|
|
2151
|
+
this.stdout(`athena-gateway: registered ${sidecar.instanceId}
|
|
2152
|
+
`);
|
|
2153
|
+
}
|
|
2154
|
+
} catch (err) {
|
|
2155
|
+
const reason = errorReason(err);
|
|
2156
|
+
results.push({
|
|
2157
|
+
id: sidecar.instanceId,
|
|
2158
|
+
ok: false,
|
|
2159
|
+
action: "failed",
|
|
2160
|
+
reason
|
|
2161
|
+
});
|
|
2162
|
+
if (opts.logFailures) {
|
|
2163
|
+
this.stderr(
|
|
2164
|
+
`athena-gateway: register ${sidecar.instanceId} failed: ${reason}
|
|
2165
|
+
`
|
|
2166
|
+
);
|
|
2167
|
+
}
|
|
2009
2168
|
}
|
|
2010
2169
|
}
|
|
2011
|
-
|
|
2012
|
-
handleInbound(channelId, msg) {
|
|
2013
|
-
if (this.dedupSet.has(msg.idempotencyKey)) {
|
|
2014
|
-
this.log?.("debug", `dropping duplicate inbound ${msg.idempotencyKey}`);
|
|
2015
|
-
return;
|
|
2016
|
-
}
|
|
2017
|
-
this.dedupSet.add(msg.idempotencyKey);
|
|
2018
|
-
this.dedup.push(msg.idempotencyKey);
|
|
2019
|
-
while (this.dedup.length > this.dedupMax) {
|
|
2020
|
-
const evicted = this.dedup.shift();
|
|
2021
|
-
if (evicted !== void 0) this.dedupSet.delete(evicted);
|
|
2022
|
-
}
|
|
2023
|
-
const sink = this.inboundSink;
|
|
2024
|
-
if (!sink) {
|
|
2025
|
-
this.log?.(
|
|
2026
|
-
"debug",
|
|
2027
|
-
`no inbound sink registered; dropping ${msg.idempotencyKey}`
|
|
2028
|
-
);
|
|
2029
|
-
return;
|
|
2030
|
-
}
|
|
2031
|
-
try {
|
|
2032
|
-
sink(msg, { attachmentId: this.entries.get(channelId)?.attachmentId });
|
|
2033
|
-
} catch (err) {
|
|
2034
|
-
this.log?.(
|
|
2035
|
-
"warn",
|
|
2036
|
-
`inbound sink threw: ${err instanceof Error ? err.message : String(err)}`
|
|
2037
|
-
);
|
|
2038
|
-
}
|
|
2170
|
+
return { results };
|
|
2039
2171
|
}
|
|
2040
2172
|
};
|
|
2173
|
+
function pathIdFromSidecarPath(filePath) {
|
|
2174
|
+
const base = filePath.split(/[\\/]/).pop() ?? filePath;
|
|
2175
|
+
return base.endsWith(".json") ? base.slice(0, -".json".length) : base;
|
|
2176
|
+
}
|
|
2177
|
+
function errorReason(err) {
|
|
2178
|
+
return err instanceof Error ? err.message : String(err);
|
|
2179
|
+
}
|
|
2041
2180
|
|
|
2042
2181
|
// src/gateway/control/handlers.ts
|
|
2043
2182
|
import { createRequire } from "module";
|
|
@@ -2241,7 +2380,7 @@ var cachedVersion = null;
|
|
|
2241
2380
|
function readVersion() {
|
|
2242
2381
|
if (cachedVersion !== null) return cachedVersion;
|
|
2243
2382
|
try {
|
|
2244
|
-
const injected = "0.5.
|
|
2383
|
+
const injected = "0.5.11";
|
|
2245
2384
|
if (typeof injected === "string" && injected.length > 0) {
|
|
2246
2385
|
cachedVersion = injected;
|
|
2247
2386
|
return cachedVersion;
|
|
@@ -3848,10 +3987,6 @@ function buildListenerStatus(spec, resolvedPort) {
|
|
|
3848
3987
|
loopback: isLoopbackHost(spec.host)
|
|
3849
3988
|
};
|
|
3850
3989
|
}
|
|
3851
|
-
function pathIdFromSidecarPath(filePath) {
|
|
3852
|
-
const base = filePath.split(/[\\/]/).pop() ?? filePath;
|
|
3853
|
-
return base.endsWith(".json") ? base.slice(0, -".json".length) : base;
|
|
3854
|
-
}
|
|
3855
3990
|
async function startDaemon(opts) {
|
|
3856
3991
|
const startedAt = Date.now();
|
|
3857
3992
|
const pid = process.pid;
|
|
@@ -3905,125 +4040,20 @@ async function startDaemon(opts) {
|
|
|
3905
4040
|
channelManager.setInboundSink((inbound, ctx) => {
|
|
3906
4041
|
pipeline.handleInbound(inbound, ctx);
|
|
3907
4042
|
});
|
|
3908
|
-
const
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
ok: false,
|
|
3917
|
-
action: "failed",
|
|
3918
|
-
reason: err.reason
|
|
3919
|
-
});
|
|
3920
|
-
}
|
|
3921
|
-
const sidecarIds = new Set(sidecars.map((s) => s.instanceId));
|
|
3922
|
-
for (const channel of channelManager.listChannels()) {
|
|
3923
|
-
if (sidecarIds.has(channel.id)) continue;
|
|
3924
|
-
try {
|
|
3925
|
-
await channelManager.unregister(channel.id, "shutdown");
|
|
3926
|
-
results.push({
|
|
3927
|
-
id: channel.id,
|
|
3928
|
-
ok: true,
|
|
3929
|
-
action: "unregistered"
|
|
3930
|
-
});
|
|
3931
|
-
} catch (err) {
|
|
3932
|
-
results.push({
|
|
3933
|
-
id: channel.id,
|
|
3934
|
-
ok: false,
|
|
3935
|
-
action: "failed",
|
|
3936
|
-
reason: err instanceof Error ? err.message : String(err)
|
|
3937
|
-
});
|
|
3938
|
-
}
|
|
3939
|
-
}
|
|
3940
|
-
for (const sidecar of sidecars) {
|
|
3941
|
-
const existed = channelManager.listChannels().some((channel) => channel.id === sidecar.instanceId);
|
|
3942
|
-
if (existed) {
|
|
3943
|
-
try {
|
|
3944
|
-
await channelManager.unregister(sidecar.instanceId, "shutdown");
|
|
3945
|
-
} catch (err) {
|
|
3946
|
-
results.push({
|
|
3947
|
-
id: sidecar.instanceId,
|
|
3948
|
-
ok: false,
|
|
3949
|
-
action: "failed",
|
|
3950
|
-
reason: err instanceof Error ? err.message : String(err)
|
|
3951
|
-
});
|
|
3952
|
-
continue;
|
|
3953
|
-
}
|
|
3954
|
-
}
|
|
3955
|
-
const built = instantiateAdapter(sidecar);
|
|
3956
|
-
if (!built.ok) {
|
|
3957
|
-
results.push({
|
|
3958
|
-
id: sidecar.instanceId,
|
|
3959
|
-
ok: false,
|
|
3960
|
-
action: "failed",
|
|
3961
|
-
reason: built.reason
|
|
3962
|
-
});
|
|
3963
|
-
continue;
|
|
3964
|
-
}
|
|
3965
|
-
try {
|
|
3966
|
-
await channelManager.register(
|
|
3967
|
-
built.adapter,
|
|
3968
|
-
sidecar.attachmentId !== void 0 ? { attachmentId: sidecar.attachmentId } : {}
|
|
3969
|
-
);
|
|
3970
|
-
results.push({
|
|
3971
|
-
id: sidecar.instanceId,
|
|
3972
|
-
ok: true,
|
|
3973
|
-
action: existed ? "replaced" : "registered"
|
|
3974
|
-
});
|
|
3975
|
-
if (!opts.silent) {
|
|
3976
|
-
process.stdout.write(
|
|
3977
|
-
`athena-gateway: registered ${sidecar.instanceId}
|
|
3978
|
-
`
|
|
3979
|
-
);
|
|
3980
|
-
}
|
|
3981
|
-
} catch (err) {
|
|
3982
|
-
results.push({
|
|
3983
|
-
id: sidecar.instanceId,
|
|
3984
|
-
ok: false,
|
|
3985
|
-
action: "failed",
|
|
3986
|
-
reason: err instanceof Error ? err.message : String(err)
|
|
3987
|
-
});
|
|
3988
|
-
}
|
|
3989
|
-
}
|
|
3990
|
-
return { results };
|
|
3991
|
-
};
|
|
4043
|
+
const channelSidecarReconciler = new ChannelSidecarReconciler({
|
|
4044
|
+
channelManager,
|
|
4045
|
+
home: opts.env?.HOME
|
|
4046
|
+
});
|
|
4047
|
+
const reloadChannels = async () => channelSidecarReconciler.reconcile({
|
|
4048
|
+
unregisterStale: true,
|
|
4049
|
+
logRegistrations: !opts.silent
|
|
4050
|
+
});
|
|
3992
4051
|
if (!opts.skipChannelLoad) {
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
);
|
|
3999
|
-
}
|
|
4000
|
-
for (const sidecar of sidecars) {
|
|
4001
|
-
const built = instantiateAdapter(sidecar);
|
|
4002
|
-
if (!built.ok) {
|
|
4003
|
-
process.stderr.write(
|
|
4004
|
-
`athena-gateway: ${sidecar.instanceId}: ${built.reason}
|
|
4005
|
-
`
|
|
4006
|
-
);
|
|
4007
|
-
continue;
|
|
4008
|
-
}
|
|
4009
|
-
try {
|
|
4010
|
-
await channelManager.register(
|
|
4011
|
-
built.adapter,
|
|
4012
|
-
sidecar.attachmentId !== void 0 ? { attachmentId: sidecar.attachmentId } : {}
|
|
4013
|
-
);
|
|
4014
|
-
if (!opts.silent) {
|
|
4015
|
-
process.stdout.write(
|
|
4016
|
-
`athena-gateway: registered ${sidecar.instanceId}
|
|
4017
|
-
`
|
|
4018
|
-
);
|
|
4019
|
-
}
|
|
4020
|
-
} catch (err) {
|
|
4021
|
-
process.stderr.write(
|
|
4022
|
-
`athena-gateway: register ${sidecar.instanceId} failed: ${err instanceof Error ? err.message : String(err)}
|
|
4023
|
-
`
|
|
4024
|
-
);
|
|
4025
|
-
}
|
|
4026
|
-
}
|
|
4052
|
+
await channelSidecarReconciler.reconcile({
|
|
4053
|
+
unregisterStale: false,
|
|
4054
|
+
logFailures: true,
|
|
4055
|
+
logRegistrations: !opts.silent
|
|
4056
|
+
});
|
|
4027
4057
|
}
|
|
4028
4058
|
const handler = createDispatcher({
|
|
4029
4059
|
startedAt,
|