switchroom 0.12.22 → 0.12.24
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/cli/switchroom.js +23 -2
- package/package.json +1 -1
- package/telegram-plugin/dist/gateway/gateway.js +350 -105
- package/telegram-plugin/gateway/gateway.ts +35 -0
- package/telegram-plugin/gateway/inbound-delivery-machine-shadow.ts +117 -0
- package/telegram-plugin/gateway/inbound-delivery-machine.ts +435 -0
- package/telegram-plugin/tests/inbound-delivery-machine.test.ts +475 -0
- package/telegram-plugin/uat/scenarios/jtbd-fast-trivial-dm.test.ts +127 -0
- package/telegram-plugin/uat/scenarios/jtbd-memory-survives-restart-dm.test.ts +239 -0
- package/telegram-plugin/uat/scenarios/jtbd-wake-audit-content-dm.test.ts +145 -0
|
@@ -27253,32 +27253,32 @@ function formatAuthQuotaLine(acc, now = Date.now()) {
|
|
|
27253
27253
|
}
|
|
27254
27254
|
return null;
|
|
27255
27255
|
}
|
|
27256
|
-
function renderAuthLine(
|
|
27257
|
-
if (!
|
|
27256
|
+
function renderAuthLine(state4, agentName3, now = Date.now()) {
|
|
27257
|
+
if (!state4 || state4.accounts.length === 0)
|
|
27258
27258
|
return [];
|
|
27259
|
-
const agentEntry =
|
|
27260
|
-
const activeLabel = agentEntry?.override ?? agentEntry?.account ??
|
|
27259
|
+
const agentEntry = state4.agents.find((a) => a.name === agentName3);
|
|
27260
|
+
const activeLabel = agentEntry?.override ?? agentEntry?.account ?? state4.active;
|
|
27261
27261
|
const seen = new Set;
|
|
27262
27262
|
const order = [];
|
|
27263
27263
|
if (activeLabel) {
|
|
27264
27264
|
order.push(activeLabel);
|
|
27265
27265
|
seen.add(activeLabel);
|
|
27266
27266
|
}
|
|
27267
|
-
for (const label of
|
|
27267
|
+
for (const label of state4.fallback_order) {
|
|
27268
27268
|
if (!seen.has(label)) {
|
|
27269
27269
|
order.push(label);
|
|
27270
27270
|
seen.add(label);
|
|
27271
27271
|
}
|
|
27272
27272
|
}
|
|
27273
|
-
for (const acc of
|
|
27273
|
+
for (const acc of state4.accounts) {
|
|
27274
27274
|
if (!seen.has(acc.label)) {
|
|
27275
27275
|
order.push(acc.label);
|
|
27276
27276
|
seen.add(acc.label);
|
|
27277
27277
|
}
|
|
27278
27278
|
}
|
|
27279
|
-
const byLabel = new Map(
|
|
27279
|
+
const byLabel = new Map(state4.accounts.map((a) => [a.label, a]));
|
|
27280
27280
|
const rows = [];
|
|
27281
|
-
rows.push(`<b>Accounts (${
|
|
27281
|
+
rows.push(`<b>Accounts (${state4.accounts.length})</b>`);
|
|
27282
27282
|
for (const label of order) {
|
|
27283
27283
|
const acc = byLabel.get(label);
|
|
27284
27284
|
if (!acc)
|
|
@@ -27540,15 +27540,15 @@ function uptimeMsForStarttime(starttimeTicks, fs2 = realProcFs) {
|
|
|
27540
27540
|
return null;
|
|
27541
27541
|
}
|
|
27542
27542
|
}
|
|
27543
|
-
function nextStepForAgentState(agentName3,
|
|
27544
|
-
if (
|
|
27543
|
+
function nextStepForAgentState(agentName3, state4) {
|
|
27544
|
+
if (state4 === "failed") {
|
|
27545
27545
|
return `Service failed \u2014 inspect with \`journalctl --user -u switchroom-${agentName3} -n 100\` then \`switchroom agent restart ${agentName3}\``;
|
|
27546
27546
|
}
|
|
27547
|
-
if (
|
|
27547
|
+
if (state4 === "inactive") {
|
|
27548
27548
|
return `Service inactive \u2014 start with \`switchroom agent start ${agentName3}\` (or \`systemctl --user start switchroom-${agentName3}\`)`;
|
|
27549
27549
|
}
|
|
27550
|
-
if (
|
|
27551
|
-
return `Service is in a transient \`${
|
|
27550
|
+
if (state4 === "deactivating" || state4 === "activating" || state4 === "auto-restart") {
|
|
27551
|
+
return `Service is in a transient \`${state4}\` state \u2014 re-check with \`switchroom agent status ${agentName3}\` in a few seconds`;
|
|
27552
27552
|
}
|
|
27553
27553
|
return `Inspect with \`journalctl --user -u switchroom-${agentName3} -n 100\``;
|
|
27554
27554
|
}
|
|
@@ -27670,8 +27670,8 @@ async function probeAgentProcess(agentName3, opts = {}) {
|
|
|
27670
27670
|
if ("error" in snapshot) {
|
|
27671
27671
|
return { status: "fail", label: "Agent", detail: snapshot.error };
|
|
27672
27672
|
}
|
|
27673
|
-
const { state:
|
|
27674
|
-
if (
|
|
27673
|
+
const { state: state4, kv } = snapshot;
|
|
27674
|
+
if (state4 === "active") {
|
|
27675
27675
|
let pid = kv["MainPID"] ?? "?";
|
|
27676
27676
|
if (opts.tmuxSupervisor) {
|
|
27677
27677
|
const resolved = await resolveTmuxSupervisorPid(agentName3, execFileFn);
|
|
@@ -27685,10 +27685,10 @@ async function probeAgentProcess(agentName3, opts = {}) {
|
|
|
27685
27685
|
}
|
|
27686
27686
|
const elapsedMs = Date.now() - startMs;
|
|
27687
27687
|
if (elapsedMs >= retryMaxMs) {
|
|
27688
|
-
const isTransient =
|
|
27688
|
+
const isTransient = state4 === "deactivating" || state4 === "activating" || state4 === "auto-restart";
|
|
27689
27689
|
const status = isTransient ? "degraded" : "fail";
|
|
27690
|
-
const nextStep = nextStepForAgentState(agentName3,
|
|
27691
|
-
return { status, label: "Agent", detail: `service ${
|
|
27690
|
+
const nextStep = nextStepForAgentState(agentName3, state4);
|
|
27691
|
+
return { status, label: "Agent", detail: `service ${state4}`, ...nextStep ? { nextStep } : {} };
|
|
27692
27692
|
}
|
|
27693
27693
|
await sleep2(retryIntervalMs);
|
|
27694
27694
|
}
|
|
@@ -27708,8 +27708,8 @@ async function* watchAgentProcess(agentName3, opts = {}) {
|
|
|
27708
27708
|
const now = opts.nowImpl ?? (() => Date.now());
|
|
27709
27709
|
const startMs = now();
|
|
27710
27710
|
let lastYieldedDetail = null;
|
|
27711
|
-
async function toProbeResult(
|
|
27712
|
-
if (
|
|
27711
|
+
async function toProbeResult(state4, kv, withinWindow) {
|
|
27712
|
+
if (state4 === "active") {
|
|
27713
27713
|
let pid = kv["MainPID"] ?? "?";
|
|
27714
27714
|
if (opts.tmuxSupervisor) {
|
|
27715
27715
|
const resolved = await resolveTmuxSupervisorPid(agentName3, execFileFn);
|
|
@@ -27722,15 +27722,15 @@ async function* watchAgentProcess(agentName3, opts = {}) {
|
|
|
27722
27722
|
return { status: "ok", label: "Agent", detail: parts.join(" \u00b7 ") };
|
|
27723
27723
|
}
|
|
27724
27724
|
if (withinWindow) {
|
|
27725
|
-
if (
|
|
27725
|
+
if (state4 === "failed") {
|
|
27726
27726
|
return { status: "fail", label: "Agent", detail: "service failed" };
|
|
27727
27727
|
}
|
|
27728
27728
|
return { status: "degraded", label: "Agent", detail: "service starting" };
|
|
27729
27729
|
}
|
|
27730
|
-
const isTransient =
|
|
27730
|
+
const isTransient = state4 === "deactivating" || state4 === "activating" || state4 === "auto-restart" || state4 === "inactive";
|
|
27731
27731
|
const status = isTransient ? "degraded" : "fail";
|
|
27732
|
-
const nextStep = nextStepForAgentState(agentName3,
|
|
27733
|
-
return { status, label: "Agent", detail: `service ${
|
|
27732
|
+
const nextStep = nextStepForAgentState(agentName3, state4);
|
|
27733
|
+
return { status, label: "Agent", detail: `service ${state4}`, ...nextStep ? { nextStep } : {} };
|
|
27734
27734
|
}
|
|
27735
27735
|
while (true) {
|
|
27736
27736
|
const elapsedMs = now() - startMs;
|
|
@@ -29553,14 +29553,14 @@ function switchPriority2(s) {
|
|
|
29553
29553
|
function escapeHtml12(s) {
|
|
29554
29554
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
29555
29555
|
}
|
|
29556
|
-
function buildSnapshotsFromState2(
|
|
29556
|
+
function buildSnapshotsFromState2(state4, quotas) {
|
|
29557
29557
|
const out = [];
|
|
29558
|
-
for (let i = 0;i <
|
|
29559
|
-
const acc =
|
|
29558
|
+
for (let i = 0;i < state4.accounts.length; i++) {
|
|
29559
|
+
const acc = state4.accounts[i];
|
|
29560
29560
|
const q = quotas[i];
|
|
29561
29561
|
out.push({
|
|
29562
29562
|
label: acc.label,
|
|
29563
|
-
isActive: acc.label ===
|
|
29563
|
+
isActive: acc.label === state4.active,
|
|
29564
29564
|
quota: q && q.ok ? q.data : null,
|
|
29565
29565
|
quotaError: q && !q.ok ? q.reason : undefined,
|
|
29566
29566
|
expiresAtMs: acc.expiresAt
|
|
@@ -43814,6 +43814,237 @@ function chatKeyWithSuffix(chatId, threadId, suffix) {
|
|
|
43814
43814
|
return `${chatKey(chatId, threadId)}:${suffix}`;
|
|
43815
43815
|
}
|
|
43816
43816
|
|
|
43817
|
+
// gateway/inbound-delivery-machine.ts
|
|
43818
|
+
function initialState() {
|
|
43819
|
+
return {
|
|
43820
|
+
global: { kind: "bridge_dead" },
|
|
43821
|
+
perKey: new Map
|
|
43822
|
+
};
|
|
43823
|
+
}
|
|
43824
|
+
var TURN_TTL_MS = 300000;
|
|
43825
|
+
var OUTBOUND_RECENT_MS = 60000;
|
|
43826
|
+
function emptyPerKey() {
|
|
43827
|
+
return { turnStartedAt: null, lastOutboundAt: null };
|
|
43828
|
+
}
|
|
43829
|
+
function updatePerKey(state3, key, update) {
|
|
43830
|
+
const prior = state3.perKey.get(key) ?? emptyPerKey();
|
|
43831
|
+
const next = update(prior);
|
|
43832
|
+
const m = new Map(state3.perKey);
|
|
43833
|
+
if (next.turnStartedAt == null && next.lastOutboundAt == null) {
|
|
43834
|
+
m.delete(key);
|
|
43835
|
+
} else {
|
|
43836
|
+
m.set(key, next);
|
|
43837
|
+
}
|
|
43838
|
+
return { ...state3, perKey: m };
|
|
43839
|
+
}
|
|
43840
|
+
function chatIdOfKey(key) {
|
|
43841
|
+
const idx = key.indexOf(":");
|
|
43842
|
+
return idx === -1 ? key : key.slice(0, idx);
|
|
43843
|
+
}
|
|
43844
|
+
function sweepSiblings(state3, chatId, exceptKey) {
|
|
43845
|
+
const effects = [];
|
|
43846
|
+
let next = state3;
|
|
43847
|
+
for (const [k, v] of state3.perKey) {
|
|
43848
|
+
if (k === exceptKey)
|
|
43849
|
+
continue;
|
|
43850
|
+
if (chatIdOfKey(k) !== chatId)
|
|
43851
|
+
continue;
|
|
43852
|
+
if (v.turnStartedAt == null)
|
|
43853
|
+
continue;
|
|
43854
|
+
effects.push({ kind: "clearTurnStarted", key: k });
|
|
43855
|
+
next = updatePerKey(next, k, (p) => ({ ...p, turnStartedAt: null }));
|
|
43856
|
+
}
|
|
43857
|
+
return { state: next, effects };
|
|
43858
|
+
}
|
|
43859
|
+
function transition(state3, event) {
|
|
43860
|
+
switch (event.kind) {
|
|
43861
|
+
case "bridgeUp": {
|
|
43862
|
+
if (state3.global.kind !== "bridge_dead") {
|
|
43863
|
+
return { state: state3, effects: [{ kind: "logTrace", stage: "bridgeUp_redundant" }] };
|
|
43864
|
+
}
|
|
43865
|
+
return {
|
|
43866
|
+
state: { ...state3, global: { kind: "bridge_alive_idle" } },
|
|
43867
|
+
effects: [
|
|
43868
|
+
{ kind: "redeliverPersistedPermVerdicts" },
|
|
43869
|
+
{ kind: "drainBuffer" },
|
|
43870
|
+
{ kind: "logTrace", stage: "bridge_recover" }
|
|
43871
|
+
]
|
|
43872
|
+
};
|
|
43873
|
+
}
|
|
43874
|
+
case "bridgeDown": {
|
|
43875
|
+
return {
|
|
43876
|
+
state: { ...state3, global: { kind: "bridge_dead" } },
|
|
43877
|
+
effects: [{ kind: "logTrace", stage: "bridge_flap" }]
|
|
43878
|
+
};
|
|
43879
|
+
}
|
|
43880
|
+
case "inbound": {
|
|
43881
|
+
const isSteering = event.msg.isSteering;
|
|
43882
|
+
const inTurn = state3.global.kind === "bridge_alive_in_turn";
|
|
43883
|
+
const alive = state3.global.kind !== "bridge_dead";
|
|
43884
|
+
if (!alive) {
|
|
43885
|
+
return {
|
|
43886
|
+
state: state3,
|
|
43887
|
+
effects: [
|
|
43888
|
+
{ kind: "bufferInbound", key: event.key, msg: event.msg },
|
|
43889
|
+
{ kind: "persistInbound", key: event.key, msg: event.msg },
|
|
43890
|
+
{ kind: "logTrace", stage: "inbound_bridge_dead_buffer", key: event.key }
|
|
43891
|
+
]
|
|
43892
|
+
};
|
|
43893
|
+
}
|
|
43894
|
+
if (inTurn && !isSteering) {
|
|
43895
|
+
return {
|
|
43896
|
+
state: state3,
|
|
43897
|
+
effects: [
|
|
43898
|
+
{ kind: "bufferInbound", key: event.key, msg: event.msg },
|
|
43899
|
+
{ kind: "persistInbound", key: event.key, msg: event.msg },
|
|
43900
|
+
{ kind: "logTrace", stage: "inbound_held_mid_turn", key: event.key, metadata: { msgId: event.msg.msgId } }
|
|
43901
|
+
]
|
|
43902
|
+
};
|
|
43903
|
+
}
|
|
43904
|
+
if (isSteering) {
|
|
43905
|
+
return {
|
|
43906
|
+
state: state3,
|
|
43907
|
+
effects: [
|
|
43908
|
+
{ kind: "deliverToBridge", key: event.key, msg: event.msg },
|
|
43909
|
+
{ kind: "logTrace", stage: "steer_delivered_mid_turn", key: event.key }
|
|
43910
|
+
]
|
|
43911
|
+
};
|
|
43912
|
+
}
|
|
43913
|
+
const next = {
|
|
43914
|
+
global: { kind: "bridge_alive_in_turn", activeTurn: event.key },
|
|
43915
|
+
perKey: state3.perKey
|
|
43916
|
+
};
|
|
43917
|
+
return {
|
|
43918
|
+
state: updatePerKey(next, event.key, (p) => ({ ...p, turnStartedAt: event.at })),
|
|
43919
|
+
effects: [
|
|
43920
|
+
{ kind: "setTurnStarted", key: event.key, at: event.at },
|
|
43921
|
+
{ kind: "deliverToBridge", key: event.key, msg: event.msg },
|
|
43922
|
+
{ kind: "logTrace", stage: "fresh_turn_deliver", key: event.key, metadata: { msgId: event.msg.msgId } }
|
|
43923
|
+
]
|
|
43924
|
+
};
|
|
43925
|
+
}
|
|
43926
|
+
case "turnStart": {
|
|
43927
|
+
const next = state3.global.kind === "bridge_alive_in_turn" ? state3 : { ...state3, global: { kind: "bridge_alive_in_turn", activeTurn: event.key } };
|
|
43928
|
+
return {
|
|
43929
|
+
state: updatePerKey(next, event.key, (p) => ({ ...p, turnStartedAt: event.at })),
|
|
43930
|
+
effects: [
|
|
43931
|
+
{ kind: "setTurnStarted", key: event.key, at: event.at },
|
|
43932
|
+
{ kind: "logTrace", stage: "turn_start", key: event.key }
|
|
43933
|
+
]
|
|
43934
|
+
};
|
|
43935
|
+
}
|
|
43936
|
+
case "turnEnd": {
|
|
43937
|
+
const chatId = chatIdOfKey(event.key);
|
|
43938
|
+
const stateAfterClear = updatePerKey(state3, event.key, (p) => ({
|
|
43939
|
+
turnStartedAt: null,
|
|
43940
|
+
lastOutboundAt: event.outboundEmitted ? event.at : p.lastOutboundAt
|
|
43941
|
+
}));
|
|
43942
|
+
const sweep = sweepSiblings(stateAfterClear, chatId, event.key);
|
|
43943
|
+
const wasActive = state3.global.kind === "bridge_alive_in_turn" && state3.global.activeTurn === event.key;
|
|
43944
|
+
const next = wasActive ? { ...sweep.state, global: { kind: "bridge_alive_idle" } } : sweep.state;
|
|
43945
|
+
const effects = [
|
|
43946
|
+
{ kind: "clearTurnStarted", key: event.key },
|
|
43947
|
+
...sweep.effects
|
|
43948
|
+
];
|
|
43949
|
+
if (event.outboundEmitted) {
|
|
43950
|
+
effects.push({ kind: "noteOutbound", key: event.key, at: event.at });
|
|
43951
|
+
}
|
|
43952
|
+
effects.push({ kind: "drainBuffer" });
|
|
43953
|
+
effects.push({ kind: "logTrace", stage: "turn_complete", key: event.key, metadata: { outboundEmitted: event.outboundEmitted } });
|
|
43954
|
+
return { state: next, effects };
|
|
43955
|
+
}
|
|
43956
|
+
case "modelOutbound": {
|
|
43957
|
+
return {
|
|
43958
|
+
state: updatePerKey(state3, event.key, (p) => ({ ...p, lastOutboundAt: event.at })),
|
|
43959
|
+
effects: [
|
|
43960
|
+
{ kind: "noteOutbound", key: event.key, at: event.at }
|
|
43961
|
+
]
|
|
43962
|
+
};
|
|
43963
|
+
}
|
|
43964
|
+
case "permVerdict": {
|
|
43965
|
+
const alive = state3.global.kind !== "bridge_dead";
|
|
43966
|
+
if (alive) {
|
|
43967
|
+
return {
|
|
43968
|
+
state: state3,
|
|
43969
|
+
effects: [
|
|
43970
|
+
{ kind: "deliverPermVerdict", verdict: event.verdict },
|
|
43971
|
+
{ kind: "logTrace", stage: "perm_verdict_delivered" }
|
|
43972
|
+
]
|
|
43973
|
+
};
|
|
43974
|
+
}
|
|
43975
|
+
return {
|
|
43976
|
+
state: state3,
|
|
43977
|
+
effects: [
|
|
43978
|
+
{ kind: "persistPermVerdict", verdict: event.verdict },
|
|
43979
|
+
{ kind: "logTrace", stage: "perm_verdict_persisted" }
|
|
43980
|
+
]
|
|
43981
|
+
};
|
|
43982
|
+
}
|
|
43983
|
+
case "tick": {
|
|
43984
|
+
const effects = [];
|
|
43985
|
+
let next = state3;
|
|
43986
|
+
for (const [k, v] of state3.perKey) {
|
|
43987
|
+
if (v.turnStartedAt == null)
|
|
43988
|
+
continue;
|
|
43989
|
+
const age = event.now - v.turnStartedAt;
|
|
43990
|
+
if (age <= TURN_TTL_MS) {
|
|
43991
|
+
continue;
|
|
43992
|
+
}
|
|
43993
|
+
const recentOutbound = v.lastOutboundAt != null && event.now - v.lastOutboundAt < OUTBOUND_RECENT_MS;
|
|
43994
|
+
if (recentOutbound) {
|
|
43995
|
+
effects.push({ kind: "logTrace", stage: "fallback_suppressed", key: k, metadata: { recentOutboundMs: event.now - (v.lastOutboundAt ?? 0) } });
|
|
43996
|
+
continue;
|
|
43997
|
+
}
|
|
43998
|
+
effects.push({ kind: "firePoke", key: k, level: "fallback" });
|
|
43999
|
+
effects.push({ kind: "clearTurnStarted", key: k });
|
|
44000
|
+
next = updatePerKey(next, k, (p) => ({ ...p, turnStartedAt: null }));
|
|
44001
|
+
if (next.global.kind === "bridge_alive_in_turn" && next.global.activeTurn === k) {
|
|
44002
|
+
next = { ...next, global: { kind: "bridge_alive_idle" } };
|
|
44003
|
+
}
|
|
44004
|
+
}
|
|
44005
|
+
return { state: next, effects };
|
|
44006
|
+
}
|
|
44007
|
+
}
|
|
44008
|
+
}
|
|
44009
|
+
|
|
44010
|
+
// gateway/inbound-delivery-machine-shadow.ts
|
|
44011
|
+
var state3 = initialState();
|
|
44012
|
+
var enabled2 = process.env.SWITCHROOM_DELIVERY_MACHINE_SHADOW !== "0";
|
|
44013
|
+
function shadowEmit(event) {
|
|
44014
|
+
if (!enabled2)
|
|
44015
|
+
return [];
|
|
44016
|
+
try {
|
|
44017
|
+
const result = transition(state3, event);
|
|
44018
|
+
state3 = result.state;
|
|
44019
|
+
const effectKinds = result.effects.map((e) => e.kind).join(",");
|
|
44020
|
+
const eventDetail = formatEventDetail(event);
|
|
44021
|
+
process.stderr.write(`gw-trace shadow event=${event.kind}${eventDetail} effects=[${effectKinds}] global=${state3.global.kind} perKeySize=${state3.perKey.size}
|
|
44022
|
+
`);
|
|
44023
|
+
return result.effects;
|
|
44024
|
+
} catch (err) {
|
|
44025
|
+
process.stderr.write(`gw-trace shadow ERROR event=${event.kind} err=${err instanceof Error ? err.message : String(err)}
|
|
44026
|
+
`);
|
|
44027
|
+
return [];
|
|
44028
|
+
}
|
|
44029
|
+
}
|
|
44030
|
+
function formatEventDetail(event) {
|
|
44031
|
+
switch (event.kind) {
|
|
44032
|
+
case "inbound":
|
|
44033
|
+
return ` key=${event.key} msg=${event.msg.msgId} steer=${event.msg.isSteering}`;
|
|
44034
|
+
case "turnStart":
|
|
44035
|
+
case "turnEnd":
|
|
44036
|
+
return ` key=${event.key}${event.kind === "turnEnd" ? ` outbound=${event.outboundEmitted}` : ""}`;
|
|
44037
|
+
case "permVerdict":
|
|
44038
|
+
return ` req=${event.verdict.requestId} behavior=${event.verdict.behavior}`;
|
|
44039
|
+
case "modelOutbound":
|
|
44040
|
+
return ` key=${event.key}`;
|
|
44041
|
+
case "bridgeUp":
|
|
44042
|
+
case "bridgeDown":
|
|
44043
|
+
case "tick":
|
|
44044
|
+
return "";
|
|
44045
|
+
}
|
|
44046
|
+
}
|
|
44047
|
+
|
|
43817
44048
|
// gateway/vault-grant-inbound-builders.ts
|
|
43818
44049
|
function buildVaultGrantApprovedInbound(opts) {
|
|
43819
44050
|
const ts = opts.nowMs ?? Date.now();
|
|
@@ -45248,7 +45479,7 @@ function extractToolResultErrorText(content) {
|
|
|
45248
45479
|
}
|
|
45249
45480
|
return "";
|
|
45250
45481
|
}
|
|
45251
|
-
function projectSubagentLine(line, agentId,
|
|
45482
|
+
function projectSubagentLine(line, agentId, state4) {
|
|
45252
45483
|
let obj;
|
|
45253
45484
|
try {
|
|
45254
45485
|
obj = JSON.parse(line);
|
|
@@ -45261,8 +45492,8 @@ function projectSubagentLine(line, agentId, state3) {
|
|
|
45261
45492
|
if (type === "user") {
|
|
45262
45493
|
const message = obj.message;
|
|
45263
45494
|
const content = message?.content;
|
|
45264
|
-
if (!
|
|
45265
|
-
|
|
45495
|
+
if (!state4.hasEmittedStart) {
|
|
45496
|
+
state4.hasEmittedStart = true;
|
|
45266
45497
|
let promptText = "";
|
|
45267
45498
|
if (typeof content === "string") {
|
|
45268
45499
|
promptText = content;
|
|
@@ -47046,10 +47277,10 @@ function loadCreditState(stateDir) {
|
|
|
47046
47277
|
} catch {}
|
|
47047
47278
|
return emptyCreditState();
|
|
47048
47279
|
}
|
|
47049
|
-
function saveCreditState(stateDir,
|
|
47280
|
+
function saveCreditState(stateDir, state4) {
|
|
47050
47281
|
mkdirSync15(stateDir, { recursive: true });
|
|
47051
47282
|
const path = join27(stateDir, STATE_FILE);
|
|
47052
|
-
writeFileSync17(path, JSON.stringify(
|
|
47283
|
+
writeFileSync17(path, JSON.stringify(state4, null, 2) + `
|
|
47053
47284
|
`, { mode: 384 });
|
|
47054
47285
|
}
|
|
47055
47286
|
|
|
@@ -47126,11 +47357,11 @@ function sweepStaleTurnActiveMarker(stateDir, opts) {
|
|
|
47126
47357
|
}
|
|
47127
47358
|
|
|
47128
47359
|
// ../src/build-info.ts
|
|
47129
|
-
var VERSION = "0.12.
|
|
47130
|
-
var COMMIT_SHA = "
|
|
47131
|
-
var COMMIT_DATE = "2026-05-
|
|
47132
|
-
var LATEST_PR =
|
|
47133
|
-
var COMMITS_AHEAD_OF_TAG =
|
|
47360
|
+
var VERSION = "0.12.24";
|
|
47361
|
+
var COMMIT_SHA = "7ab1329";
|
|
47362
|
+
var COMMIT_DATE = "2026-05-20T14:48:10+10:00";
|
|
47363
|
+
var LATEST_PR = 1582;
|
|
47364
|
+
var COMMITS_AHEAD_OF_TAG = 3;
|
|
47134
47365
|
|
|
47135
47366
|
// gateway/boot-version.ts
|
|
47136
47367
|
function formatRelativeAgo(iso) {
|
|
@@ -48079,6 +48310,7 @@ function streamKey3(chatId, threadId) {
|
|
|
48079
48310
|
return chatKey(chatId, threadId);
|
|
48080
48311
|
}
|
|
48081
48312
|
function purgeReactionTracking(key) {
|
|
48313
|
+
shadowEmit({ kind: "turnEnd", key, at: Date.now(), outboundEmitted: true });
|
|
48082
48314
|
const msgInfo = activeReactionMsgIds.get(key);
|
|
48083
48315
|
activeStatusReactions.delete(key);
|
|
48084
48316
|
activeReactionMsgIds.delete(key);
|
|
@@ -49002,6 +49234,7 @@ var ipcServer = createIpcServer({
|
|
|
49002
49234
|
onClientRegistered(client3) {
|
|
49003
49235
|
process.stderr.write(`telegram gateway: bridge registered \u2014 agent=${client3.agentName}
|
|
49004
49236
|
`);
|
|
49237
|
+
shadowEmit({ kind: "bridgeUp", at: Date.now() });
|
|
49005
49238
|
client3.send({ type: "status", status: "agent_connected" });
|
|
49006
49239
|
if (client3.agentName != null) {
|
|
49007
49240
|
const pending = pendingInboundBuffer.drain(client3.agentName);
|
|
@@ -49095,6 +49328,7 @@ var ipcServer = createIpcServer({
|
|
|
49095
49328
|
onClientDisconnected(client3) {
|
|
49096
49329
|
process.stderr.write(`telegram gateway: bridge disconnected \u2014 agent=${client3.agentName}
|
|
49097
49330
|
`);
|
|
49331
|
+
shadowEmit({ kind: "bridgeDown", at: Date.now() });
|
|
49098
49332
|
flushOnAgentDisconnect({
|
|
49099
49333
|
agentName: client3.agentName,
|
|
49100
49334
|
activeStatusReactions,
|
|
@@ -51057,7 +51291,7 @@ function handleSessionEvent(ev) {
|
|
|
51057
51291
|
}
|
|
51058
51292
|
function handlePtyPartial(text) {
|
|
51059
51293
|
const turn = currentTurn;
|
|
51060
|
-
const
|
|
51294
|
+
const state4 = {
|
|
51061
51295
|
currentSessionChatId: turn?.sessionChatId ?? null,
|
|
51062
51296
|
currentSessionThreadId: turn?.sessionThreadId,
|
|
51063
51297
|
pendingPtyPartial: pendingPtyPartial != null ? { text: pendingPtyPartial } : null,
|
|
@@ -51066,7 +51300,7 @@ function handlePtyPartial(text) {
|
|
|
51066
51300
|
suppressPtyPreview,
|
|
51067
51301
|
lastPtyPreviewByChat
|
|
51068
51302
|
};
|
|
51069
|
-
handlePtyPartialPure(text,
|
|
51303
|
+
handlePtyPartialPure(text, state4, {
|
|
51070
51304
|
bot,
|
|
51071
51305
|
retry: robustApiCall,
|
|
51072
51306
|
renderText: markdownToHtml,
|
|
@@ -51082,7 +51316,7 @@ function handlePtyPartial(text) {
|
|
|
51082
51316
|
},
|
|
51083
51317
|
writeError: (line) => process.stderr.write(line)
|
|
51084
51318
|
});
|
|
51085
|
-
pendingPtyPartial =
|
|
51319
|
+
pendingPtyPartial = state4.pendingPtyPartial?.text ?? null;
|
|
51086
51320
|
}
|
|
51087
51321
|
var gateDenyLastLoggedAt = new Map;
|
|
51088
51322
|
var GATE_DENY_LOG_WINDOW_MS = 60000;
|
|
@@ -51275,6 +51509,17 @@ async function handleInbound(ctx, text, downloadImage, attachment) {
|
|
|
51275
51509
|
return;
|
|
51276
51510
|
}
|
|
51277
51511
|
const inboundReceivedAt = Date.now();
|
|
51512
|
+
const _shadowKey = statusKey(ctx.chat?.id != null ? String(ctx.chat.id) : "0", ctx.message?.message_thread_id);
|
|
51513
|
+
shadowEmit({
|
|
51514
|
+
kind: "inbound",
|
|
51515
|
+
key: _shadowKey,
|
|
51516
|
+
msg: {
|
|
51517
|
+
msgId: ctx.message?.message_id ?? 0,
|
|
51518
|
+
isSteering: false,
|
|
51519
|
+
payload: null
|
|
51520
|
+
},
|
|
51521
|
+
at: Date.now()
|
|
51522
|
+
});
|
|
51278
51523
|
const turnInFlightAtReceipt = activeTurnStartedAt.size > 0;
|
|
51279
51524
|
const access = result.access;
|
|
51280
51525
|
const from = ctx.from;
|
|
@@ -53140,15 +53385,15 @@ async function doFireFleetAutoFallback(triggerAgent) {
|
|
|
53140
53385
|
`);
|
|
53141
53386
|
return false;
|
|
53142
53387
|
}
|
|
53143
|
-
const
|
|
53144
|
-
const probeResp =
|
|
53145
|
-
const quotas =
|
|
53388
|
+
const state4 = await client3.listState();
|
|
53389
|
+
const probeResp = state4.accounts.length > 0 ? await client3.probeQuota(state4.accounts.map((a) => a.label)).catch(() => ({ results: [] })) : { results: [] };
|
|
53390
|
+
const quotas = state4.accounts.map((a) => {
|
|
53146
53391
|
const hit = probeResp.results.find((r) => r.label === a.label);
|
|
53147
53392
|
return hit?.result ?? { ok: false, reason: "broker returned no result for account" };
|
|
53148
53393
|
});
|
|
53149
53394
|
const tz = process.env.SWITCHROOM_TIMEZONE ?? process.env.TZ ?? "UTC";
|
|
53150
53395
|
const outcome = await runFleetAutoFallback({
|
|
53151
|
-
state:
|
|
53396
|
+
state: state4,
|
|
53152
53397
|
quotas,
|
|
53153
53398
|
setActive: (label) => client3.setActive(label),
|
|
53154
53399
|
triggerAgent,
|
|
@@ -53334,9 +53579,9 @@ async function probeQuotaForBootCard(agent, timeoutMs) {
|
|
|
53334
53579
|
const client3 = await getAuthBrokerClient(agent);
|
|
53335
53580
|
if (!client3)
|
|
53336
53581
|
return null;
|
|
53337
|
-
const
|
|
53338
|
-
const entry =
|
|
53339
|
-
const label = entry?.override ?? entry?.account ??
|
|
53582
|
+
const state4 = await client3.listState();
|
|
53583
|
+
const entry = state4.agents.find((a) => a.name === agent);
|
|
53584
|
+
const label = entry?.override ?? entry?.account ?? state4.active;
|
|
53340
53585
|
if (!label)
|
|
53341
53586
|
return null;
|
|
53342
53587
|
const { results } = await client3.probeQuota([label], timeoutMs);
|
|
@@ -53853,34 +54098,34 @@ Which keys for <code>${escapeHtmlForTg(agent)}</code>?
|
|
|
53853
54098
|
startedAt: Date.now()
|
|
53854
54099
|
});
|
|
53855
54100
|
}
|
|
53856
|
-
async function grantWizardStep3(ctx, chatId,
|
|
54101
|
+
async function grantWizardStep3(ctx, chatId, state4) {
|
|
53857
54102
|
const kb = buildGrantDurationKeyboard();
|
|
53858
|
-
const keyList =
|
|
54103
|
+
const keyList = state4.selectedKeys.map((k) => `\u2022 <code>${escapeHtmlForTg(k)}</code>`).join(`
|
|
53859
54104
|
`);
|
|
53860
54105
|
const text = `<b>Grant capability token \u2014 Step 3/3</b>
|
|
53861
54106
|
|
|
53862
|
-
Keys for <code>${escapeHtmlForTg(
|
|
54107
|
+
Keys for <code>${escapeHtmlForTg(state4.agent)}</code>:
|
|
53863
54108
|
${keyList}
|
|
53864
54109
|
|
|
53865
54110
|
How long should this grant be valid?`;
|
|
53866
|
-
const msgId =
|
|
54111
|
+
const msgId = state4.wizardMsgId;
|
|
53867
54112
|
if (msgId != null) {
|
|
53868
54113
|
await ctx.api.editMessageText(chatId, msgId, text, { parse_mode: "HTML", reply_markup: kb }).catch(() => {});
|
|
53869
54114
|
} else {
|
|
53870
54115
|
const sent = await switchroomReply(ctx, text, { html: true, reply_markup: kb });
|
|
53871
|
-
|
|
54116
|
+
state4.wizardMsgId = sent?.message_id;
|
|
53872
54117
|
}
|
|
53873
|
-
pendingVaultOps.set(chatId, { ...
|
|
54118
|
+
pendingVaultOps.set(chatId, { ...state4, step: "duration" });
|
|
53874
54119
|
}
|
|
53875
|
-
async function grantWizardConfirm(ctx, chatId,
|
|
54120
|
+
async function grantWizardConfirm(ctx, chatId, state4) {
|
|
53876
54121
|
const kb = buildGrantConfirmKeyboard();
|
|
53877
|
-
const expiresLabel = formatGrantExpiry(
|
|
53878
|
-
const keyList =
|
|
54122
|
+
const expiresLabel = formatGrantExpiry(state4.ttlSeconds);
|
|
54123
|
+
const keyList = state4.selectedKeys.map((k) => `\u2022 <code>${escapeHtmlForTg(k)}</code>`).join(`
|
|
53879
54124
|
`);
|
|
53880
54125
|
const text = [
|
|
53881
54126
|
"<b>Confirm grant</b>",
|
|
53882
54127
|
"",
|
|
53883
|
-
`Agent: <code>${escapeHtmlForTg(
|
|
54128
|
+
`Agent: <code>${escapeHtmlForTg(state4.agent)}</code>`,
|
|
53884
54129
|
`Keys:
|
|
53885
54130
|
${keyList}`,
|
|
53886
54131
|
`Expires: <b>${escapeHtmlForTg(expiresLabel)}</b>`,
|
|
@@ -53888,34 +54133,34 @@ ${keyList}`,
|
|
|
53888
54133
|
"Tap <b>Generate</b> to mint the token."
|
|
53889
54134
|
].join(`
|
|
53890
54135
|
`);
|
|
53891
|
-
const msgId =
|
|
54136
|
+
const msgId = state4.wizardMsgId;
|
|
53892
54137
|
if (msgId != null) {
|
|
53893
54138
|
await ctx.api.editMessageText(chatId, msgId, text, { parse_mode: "HTML", reply_markup: kb }).catch(() => {});
|
|
53894
54139
|
} else {
|
|
53895
54140
|
const sent = await switchroomReply(ctx, text, { html: true, reply_markup: kb });
|
|
53896
|
-
|
|
54141
|
+
state4.wizardMsgId = sent?.message_id;
|
|
53897
54142
|
}
|
|
53898
|
-
const kernelRequestId = await mintGrantWizardKernelRequest(
|
|
54143
|
+
const kernelRequestId = await mintGrantWizardKernelRequest(state4.agent, loadAccess().allowFrom, state4.selectedKeys, state4.ttlSeconds ?? null);
|
|
53899
54144
|
pendingVaultOps.set(chatId, {
|
|
53900
|
-
...
|
|
54145
|
+
...state4,
|
|
53901
54146
|
step: "confirm",
|
|
53902
54147
|
expiresLabel,
|
|
53903
|
-
kernel_request_id: kernelRequestId ??
|
|
54148
|
+
kernel_request_id: kernelRequestId ?? state4.kernel_request_id
|
|
53904
54149
|
});
|
|
53905
54150
|
}
|
|
53906
|
-
async function executeGrantWizard(ctx, chatId,
|
|
54151
|
+
async function executeGrantWizard(ctx, chatId, state4) {
|
|
53907
54152
|
pendingVaultOps.delete(chatId);
|
|
53908
|
-
await recordGrantWizardKernelDecision(
|
|
54153
|
+
await recordGrantWizardKernelDecision(state4.kernel_request_id, "allow_once", ctx.from?.id ?? 0, loadAccess().allowFrom);
|
|
53909
54154
|
try {
|
|
53910
|
-
assertSafeAgentName(
|
|
54155
|
+
assertSafeAgentName(state4.agent);
|
|
53911
54156
|
} catch {
|
|
53912
54157
|
return;
|
|
53913
54158
|
}
|
|
53914
54159
|
const result = await mintGrantViaBroker({
|
|
53915
|
-
agent:
|
|
53916
|
-
keys:
|
|
53917
|
-
ttl_seconds:
|
|
53918
|
-
description:
|
|
54160
|
+
agent: state4.agent,
|
|
54161
|
+
keys: state4.selectedKeys,
|
|
54162
|
+
ttl_seconds: state4.ttlSeconds ?? null,
|
|
54163
|
+
description: state4.description
|
|
53919
54164
|
});
|
|
53920
54165
|
if (result.kind === "unreachable") {
|
|
53921
54166
|
await switchroomReply(ctx, `\uD83D\uDD34 Broker unreachable: ${escapeHtmlForTg(result.msg)}`, { html: true });
|
|
@@ -53926,16 +54171,16 @@ async function executeGrantWizard(ctx, chatId, state3) {
|
|
|
53926
54171
|
return;
|
|
53927
54172
|
}
|
|
53928
54173
|
const { token, id } = result;
|
|
53929
|
-
const tokenPath = join32(homedir12(), ".switchroom", "agents",
|
|
54174
|
+
const tokenPath = join32(homedir12(), ".switchroom", "agents", state4.agent, ".vault-token");
|
|
53930
54175
|
try {
|
|
53931
|
-
mkdirSync21(join32(homedir12(), ".switchroom", "agents",
|
|
54176
|
+
mkdirSync21(join32(homedir12(), ".switchroom", "agents", state4.agent), { recursive: true });
|
|
53932
54177
|
writeFileSync21(tokenPath, token, { mode: 384 });
|
|
53933
54178
|
} catch (err) {
|
|
53934
54179
|
await switchroomReply(ctx, `<b>Grant created but token write failed:</b> ${escapeHtmlForTg(String(err))}`, { html: true });
|
|
53935
54180
|
return;
|
|
53936
54181
|
}
|
|
53937
|
-
const msgId =
|
|
53938
|
-
const successText = `\u2705 Grant <code>${escapeHtmlForTg(id)}</code> created. Written to <code>~/.switchroom/agents/${escapeHtmlForTg(
|
|
54182
|
+
const msgId = state4.wizardMsgId;
|
|
54183
|
+
const successText = `\u2705 Grant <code>${escapeHtmlForTg(id)}</code> created. Written to <code>~/.switchroom/agents/${escapeHtmlForTg(state4.agent)}/.vault-token</code>`;
|
|
53939
54184
|
if (msgId != null) {
|
|
53940
54185
|
await finalizeCallback(ctx, {
|
|
53941
54186
|
ackText: "\u2705 Grant created",
|
|
@@ -54029,59 +54274,59 @@ Keys: <code>${escapeHtmlForTg(grant.key_allow.join(", "))}</code>`;
|
|
|
54029
54274
|
await ackSilently();
|
|
54030
54275
|
return;
|
|
54031
54276
|
}
|
|
54032
|
-
const
|
|
54033
|
-
if (!
|
|
54277
|
+
const state4 = pendingVaultOps.get(chatId);
|
|
54278
|
+
if (!state4 || state4.kind !== "grant-wizard") {
|
|
54034
54279
|
await ctx.editMessageText("\u26A0\uFE0F Wizard session expired. Run /vault grant to start again.").catch(() => {});
|
|
54035
54280
|
await ackSilently();
|
|
54036
54281
|
return;
|
|
54037
54282
|
}
|
|
54038
54283
|
if (data.startsWith("vg:agent:")) {
|
|
54039
54284
|
const agent = data.slice("vg:agent:".length);
|
|
54040
|
-
const msgId = ctx.callbackQuery?.message?.message_id ??
|
|
54285
|
+
const msgId = ctx.callbackQuery?.message?.message_id ?? state4.wizardMsgId;
|
|
54041
54286
|
await grantWizardStep2(ctx, chatId, agent, msgId);
|
|
54042
54287
|
await ackSilently();
|
|
54043
54288
|
return;
|
|
54044
54289
|
}
|
|
54045
54290
|
if (data.startsWith("vg:key:")) {
|
|
54046
54291
|
const key = data.slice("vg:key:".length);
|
|
54047
|
-
if (
|
|
54292
|
+
if (state4.step !== "keys") {
|
|
54048
54293
|
await ackSilently();
|
|
54049
54294
|
return;
|
|
54050
54295
|
}
|
|
54051
|
-
const selectedSet = new Set(
|
|
54296
|
+
const selectedSet = new Set(state4.selectedKeys ?? []);
|
|
54052
54297
|
if (selectedSet.has(key)) {
|
|
54053
54298
|
selectedSet.delete(key);
|
|
54054
54299
|
} else {
|
|
54055
54300
|
selectedSet.add(key);
|
|
54056
54301
|
}
|
|
54057
|
-
const updatedState = { ...
|
|
54302
|
+
const updatedState = { ...state4, selectedKeys: [...selectedSet] };
|
|
54058
54303
|
pendingVaultOps.set(chatId, updatedState);
|
|
54059
|
-
const kb = buildGrantKeysKeyboard(
|
|
54304
|
+
const kb = buildGrantKeysKeyboard(state4.availableKeys ?? [], selectedSet);
|
|
54060
54305
|
await ctx.editMessageReplyMarkup({ reply_markup: kb }).catch(() => {});
|
|
54061
54306
|
await ackSilently();
|
|
54062
54307
|
return;
|
|
54063
54308
|
}
|
|
54064
54309
|
if (data === "vg:keys-continue") {
|
|
54065
|
-
if (
|
|
54310
|
+
if (state4.step !== "keys") {
|
|
54066
54311
|
await ackSilently();
|
|
54067
54312
|
return;
|
|
54068
54313
|
}
|
|
54069
|
-
if (!
|
|
54314
|
+
if (!state4.selectedKeys || state4.selectedKeys.length === 0) {
|
|
54070
54315
|
await ctx.answerCallbackQuery({ text: "Select at least one key." }).catch(() => {});
|
|
54071
54316
|
return;
|
|
54072
54317
|
}
|
|
54073
|
-
await grantWizardStep3(ctx, chatId,
|
|
54318
|
+
await grantWizardStep3(ctx, chatId, state4);
|
|
54074
54319
|
await ackSilently();
|
|
54075
54320
|
return;
|
|
54076
54321
|
}
|
|
54077
54322
|
if (data.startsWith("vg:dur:")) {
|
|
54078
|
-
if (
|
|
54323
|
+
if (state4.step !== "duration") {
|
|
54079
54324
|
await ackSilently();
|
|
54080
54325
|
return;
|
|
54081
54326
|
}
|
|
54082
54327
|
const dur = data.slice("vg:dur:".length);
|
|
54083
54328
|
if (dur === "custom") {
|
|
54084
|
-
pendingVaultOps.set(chatId, { ...
|
|
54329
|
+
pendingVaultOps.set(chatId, { ...state4, awaitingCustomDuration: true });
|
|
54085
54330
|
const msg = ctx.callbackQuery?.message;
|
|
54086
54331
|
if (msg && "text" in msg && msg.text) {
|
|
54087
54332
|
await ctx.editMessageText(escapeHtmlForTg(msg.text) + `
|
|
@@ -54103,27 +54348,27 @@ Keys: <code>${escapeHtmlForTg(grant.key_allow.join(", "))}</code>`;
|
|
|
54103
54348
|
return;
|
|
54104
54349
|
}
|
|
54105
54350
|
}
|
|
54106
|
-
const newState = { ...
|
|
54351
|
+
const newState = { ...state4, ttlSeconds, awaitingCustomDuration: false };
|
|
54107
54352
|
await grantWizardConfirm(ctx, chatId, newState);
|
|
54108
54353
|
await ackSilently();
|
|
54109
54354
|
return;
|
|
54110
54355
|
}
|
|
54111
54356
|
if (data === "vg:back:duration") {
|
|
54112
|
-
if (
|
|
54357
|
+
if (state4.step !== "duration") {
|
|
54113
54358
|
await ackSilently();
|
|
54114
54359
|
return;
|
|
54115
54360
|
}
|
|
54116
|
-
const msgId =
|
|
54117
|
-
await grantWizardStep2(ctx, chatId,
|
|
54361
|
+
const msgId = state4.wizardMsgId;
|
|
54362
|
+
await grantWizardStep2(ctx, chatId, state4.agent, msgId);
|
|
54118
54363
|
await ackSilently();
|
|
54119
54364
|
return;
|
|
54120
54365
|
}
|
|
54121
54366
|
if (data === "vg:generate") {
|
|
54122
|
-
if (
|
|
54367
|
+
if (state4.step !== "confirm") {
|
|
54123
54368
|
await ackSilently();
|
|
54124
54369
|
return;
|
|
54125
54370
|
}
|
|
54126
|
-
await executeGrantWizard(ctx, chatId,
|
|
54371
|
+
await executeGrantWizard(ctx, chatId, state4);
|
|
54127
54372
|
await ackSilently();
|
|
54128
54373
|
return;
|
|
54129
54374
|
}
|
|
@@ -54361,15 +54606,15 @@ async function handleAuthDashboardCallback(ctx) {
|
|
|
54361
54606
|
} catch {}
|
|
54362
54607
|
return;
|
|
54363
54608
|
}
|
|
54364
|
-
const
|
|
54365
|
-
const probeResp =
|
|
54366
|
-
const quotas =
|
|
54609
|
+
const state4 = await client3.listState();
|
|
54610
|
+
const probeResp = state4.accounts.length > 0 ? await client3.probeQuota(state4.accounts.map((a) => a.label)).catch(() => ({ results: [] })) : { results: [] };
|
|
54611
|
+
const quotas = state4.accounts.map((a) => {
|
|
54367
54612
|
const hit = probeResp.results.find((r) => r.label === a.label);
|
|
54368
54613
|
return hit?.result ?? { ok: false, reason: "broker returned no result for account" };
|
|
54369
54614
|
});
|
|
54370
54615
|
const tz = process.env.SWITCHROOM_TIMEZONE ?? process.env.TZ ?? "UTC";
|
|
54371
54616
|
const { renderAuthSnapshotFormat2: renderAuthSnapshotFormat23, buildSnapshotsFromState: buildSnapshotsFromState3, buildSnapshotKeyboard: buildSnapshotKeyboard3 } = await Promise.resolve().then(() => (init_auth_snapshot_format(), exports_auth_snapshot_format));
|
|
54372
|
-
const snapshots = buildSnapshotsFromState3(
|
|
54617
|
+
const snapshots = buildSnapshotsFromState3(state4, quotas);
|
|
54373
54618
|
const text = renderAuthSnapshotFormat23(snapshots, {
|
|
54374
54619
|
tz,
|
|
54375
54620
|
now: new Date,
|
|
@@ -54757,16 +55002,16 @@ bot.command("usage", async (ctx) => {
|
|
|
54757
55002
|
try {
|
|
54758
55003
|
const client3 = await getAuthBrokerClient(currentAgent);
|
|
54759
55004
|
if (client3) {
|
|
54760
|
-
const
|
|
54761
|
-
if (
|
|
54762
|
-
const probeResp = await client3.probeQuota(
|
|
54763
|
-
const quotas =
|
|
55005
|
+
const state4 = await client3.listState();
|
|
55006
|
+
if (state4.accounts.length > 0) {
|
|
55007
|
+
const probeResp = await client3.probeQuota(state4.accounts.map((a) => a.label)).catch(() => ({ results: [] }));
|
|
55008
|
+
const quotas = state4.accounts.map((a) => {
|
|
54764
55009
|
const hit = probeResp.results.find((r) => r.label === a.label);
|
|
54765
55010
|
return hit?.result ?? { ok: false, reason: "broker returned no result for account" };
|
|
54766
55011
|
});
|
|
54767
55012
|
const { renderAuthSnapshotFormat2: renderAuthSnapshotFormat23, buildSnapshotsFromState: buildSnapshotsFromState3 } = await Promise.resolve().then(() => (init_auth_snapshot_format(), exports_auth_snapshot_format));
|
|
54768
55013
|
const tz = process.env.SWITCHROOM_TIMEZONE ?? process.env.TZ ?? "UTC";
|
|
54769
|
-
const snapshots = buildSnapshotsFromState3(
|
|
55014
|
+
const snapshots = buildSnapshotsFromState3(state4, quotas);
|
|
54770
55015
|
const text = renderAuthSnapshotFormat23(snapshots, {
|
|
54771
55016
|
tz,
|
|
54772
55017
|
now: new Date,
|
|
@@ -55606,7 +55851,7 @@ function handleChecklistUpdate(ctx, kind) {
|
|
|
55606
55851
|
const taskId = task.id != null ? String(task.id) : "?";
|
|
55607
55852
|
const user = task.user;
|
|
55608
55853
|
const userName = user?.username ?? (user?.id != null ? String(user.id) : "unknown");
|
|
55609
|
-
const
|
|
55854
|
+
const state4 = kind === "checklist_tasks_done" ? task.done === false ? "undone" : "done" : "added";
|
|
55610
55855
|
const inboundMsg = {
|
|
55611
55856
|
type: "inbound",
|
|
55612
55857
|
chatId: chat_id,
|
|
@@ -55614,20 +55859,20 @@ function handleChecklistUpdate(ctx, kind) {
|
|
|
55614
55859
|
user: userName,
|
|
55615
55860
|
userId: user?.id ?? 0,
|
|
55616
55861
|
ts,
|
|
55617
|
-
text: `(checklist task ${
|
|
55862
|
+
text: `(checklist task ${state4}: id=${taskId})`,
|
|
55618
55863
|
meta: {
|
|
55619
55864
|
chat_id,
|
|
55620
55865
|
message_id,
|
|
55621
55866
|
kind: "checklist_task_changed",
|
|
55622
55867
|
task_id: taskId,
|
|
55623
|
-
state:
|
|
55868
|
+
state: state4,
|
|
55624
55869
|
user: userName,
|
|
55625
55870
|
user_id: user?.id != null ? String(user.id) : "0",
|
|
55626
55871
|
ts: new Date(ts * 1000).toISOString()
|
|
55627
55872
|
}
|
|
55628
55873
|
};
|
|
55629
55874
|
ipcServer.broadcast(inboundMsg);
|
|
55630
|
-
process.stderr.write(`telegram gateway: checklist ${kind}: chat_id=${chat_id} message_id=${message_id} task_id=${taskId} state=${
|
|
55875
|
+
process.stderr.write(`telegram gateway: checklist ${kind}: chat_id=${chat_id} message_id=${message_id} task_id=${taskId} state=${state4} user=${userName}
|
|
55631
55876
|
`);
|
|
55632
55877
|
}
|
|
55633
55878
|
} catch (err) {
|