switchroom 0.15.44 → 0.16.4
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/agent-scheduler/index.js +122 -88
- package/dist/auth-broker/index.js +463 -177
- package/dist/cli/autoaccept-poll.js +4842 -35
- package/dist/cli/drive-write-pretool.mjs +17 -14
- package/dist/cli/notion-write-pretool.mjs +117 -86
- package/dist/cli/self-improve-apply-guard-pretool.mjs +626 -0
- package/dist/cli/self-improve-stop.mjs +428 -0
- package/dist/cli/skill-validate-pretool.mjs +72 -72
- package/dist/cli/switchroom.js +3249 -1241
- package/dist/cli/ui/index.html +1 -1
- package/dist/host-control/main.js +2833 -355
- package/dist/vault/approvals/kernel-server.js +7482 -7439
- package/dist/vault/broker/server.js +11315 -11272
- package/examples/minimal.yaml +1 -0
- package/examples/switchroom.yaml +1 -0
- package/package.json +3 -3
- package/profiles/_base/start.sh.hbs +88 -1
- package/profiles/_shared/execution-discipline.md.hbs +18 -0
- package/profiles/default/CLAUDE.md.hbs +3 -22
- package/telegram-plugin/.claude-plugin/plugin.json +2 -2
- package/telegram-plugin/answer-stream-flag.ts +12 -49
- package/telegram-plugin/answer-stream.ts +5 -150
- package/telegram-plugin/auth-snapshot-format.ts +280 -48
- package/telegram-plugin/auto-fallback-fleet.ts +44 -1
- package/telegram-plugin/context-exhaustion.ts +12 -0
- package/telegram-plugin/demo-mask.ts +154 -0
- package/telegram-plugin/dist/bridge/bridge.js +167 -124
- package/telegram-plugin/dist/gateway/gateway.js +3039 -1159
- package/telegram-plugin/dist/server.js +215 -172
- package/telegram-plugin/docs/waiting-ux-spec.md +2 -2
- package/telegram-plugin/draft-stream.ts +47 -410
- package/telegram-plugin/final-answer-detect.ts +17 -12
- package/telegram-plugin/fleet-fallback-resume.ts +131 -0
- package/telegram-plugin/format.ts +56 -19
- package/telegram-plugin/gateway/auth-add-flow.ts +332 -127
- package/telegram-plugin/gateway/auth-broker-client.ts +2 -2
- package/telegram-plugin/gateway/auth-command.ts +70 -14
- package/telegram-plugin/gateway/clean-shutdown-marker.ts +44 -0
- package/telegram-plugin/gateway/config-approval-handler.test.ts +91 -4
- package/telegram-plugin/gateway/config-approval-handler.ts +94 -13
- package/telegram-plugin/gateway/current-turn-map.ts +188 -0
- package/telegram-plugin/gateway/disconnect-flush.ts +3 -1
- package/telegram-plugin/gateway/effort-command.ts +8 -3
- package/telegram-plugin/gateway/emission-authority.ts +369 -0
- package/telegram-plugin/gateway/feed-open-gate.ts +292 -0
- package/telegram-plugin/gateway/gateway.ts +1837 -291
- package/telegram-plugin/gateway/inject-handler.test.ts +2 -1
- package/telegram-plugin/gateway/ms365-write-approval.test.ts +4 -4
- package/telegram-plugin/gateway/represent-guard.ts +72 -0
- package/telegram-plugin/gateway/status-surface-log.test.ts +5 -4
- package/telegram-plugin/gateway/status-surface-log.ts +14 -3
- package/telegram-plugin/history.ts +33 -11
- package/telegram-plugin/hooks/repo-context-pretool.mjs +26 -0
- package/telegram-plugin/hooks/subagent-tracker-posttool.mjs +5 -0
- package/telegram-plugin/hooks/subagent-tracker-pretool.mjs +8 -0
- package/telegram-plugin/hooks/tool-label-pretool.mjs +39 -15
- package/telegram-plugin/issues-card.ts +4 -0
- package/telegram-plugin/model-unavailable.ts +124 -0
- package/telegram-plugin/narrative-dedup.ts +69 -0
- package/telegram-plugin/over-ping-safety-net.ts +70 -4
- package/telegram-plugin/package.json +3 -3
- package/telegram-plugin/pending-work-progress.ts +12 -0
- package/telegram-plugin/permission-rule.ts +32 -5
- package/telegram-plugin/permission-title.ts +152 -9
- package/telegram-plugin/quota-check.ts +13 -0
- package/telegram-plugin/quota-watch.ts +135 -7
- package/telegram-plugin/registry/turns-schema.test.ts +24 -0
- package/telegram-plugin/registry/turns-schema.ts +9 -0
- package/telegram-plugin/runtime-metrics.ts +13 -0
- package/telegram-plugin/session-tail.ts +96 -11
- package/telegram-plugin/silence-poke.ts +170 -24
- package/telegram-plugin/slot-banner-driver.ts +3 -0
- package/telegram-plugin/status-no-truncate.ts +44 -0
- package/telegram-plugin/status-reactions.ts +20 -3
- package/telegram-plugin/stream-controller.ts +4 -23
- package/telegram-plugin/stream-reply-handler.ts +6 -24
- package/telegram-plugin/streaming-metrics.ts +91 -0
- package/telegram-plugin/subagent-watcher.ts +212 -66
- package/telegram-plugin/tests/activity-ever-opened-sticky.test.ts +47 -0
- package/telegram-plugin/tests/answer-stream-dedup.test.ts +9 -26
- package/telegram-plugin/tests/answer-stream-flag.test.ts +25 -58
- package/telegram-plugin/tests/answer-stream-silent-markers.test.ts +41 -51
- package/telegram-plugin/tests/answer-stream.test.ts +2 -411
- package/telegram-plugin/tests/auth-add-flow.test.ts +488 -253
- package/telegram-plugin/tests/auth-command-format2.test.ts +71 -1
- package/telegram-plugin/tests/auth-snapshot-format.test.ts +376 -6
- package/telegram-plugin/tests/auto-fallback-fleet.test.ts +120 -0
- package/telegram-plugin/tests/cross-turn-card-gate.test.ts +424 -0
- package/telegram-plugin/tests/demo-mask.test.ts +127 -0
- package/telegram-plugin/tests/draft-stream.test.ts +0 -827
- package/telegram-plugin/tests/emission-authority-card-drain-gate.test.ts +236 -0
- package/telegram-plugin/tests/emission-authority-facade.test.ts +488 -0
- package/telegram-plugin/tests/emission-authority-open-gate.test.ts +179 -0
- package/telegram-plugin/tests/emission-authority-ping-gate.test.ts +395 -0
- package/telegram-plugin/tests/emission-determinism-wiring.test.ts +177 -0
- package/telegram-plugin/tests/feed-heartbeat-liveness-open.test.ts +146 -0
- package/telegram-plugin/tests/feed-open-gate.test.ts +259 -0
- package/telegram-plugin/tests/feed-survival.test.ts +526 -0
- package/telegram-plugin/tests/fleet-fallback-resume.test.ts +197 -0
- package/telegram-plugin/tests/gateway-clean-shutdown-marker.test.ts +117 -0
- package/telegram-plugin/tests/gateway-no-reply-single-emit.test.ts +4 -11
- package/telegram-plugin/tests/history.test.ts +60 -0
- package/telegram-plugin/tests/model-unavailable.test.ts +118 -0
- package/telegram-plugin/tests/narrative-dedup.test.ts +118 -0
- package/telegram-plugin/tests/orphaned-reply-rearm.test.ts +285 -0
- package/telegram-plugin/tests/over-ping-final-answer-decoupling.test.ts +194 -0
- package/telegram-plugin/tests/over-ping-safety-net.test.ts +2 -2
- package/telegram-plugin/tests/per-topic-current-turn.test.ts +373 -0
- package/telegram-plugin/tests/permission-card-origin-kill-switch.test.ts +42 -0
- package/telegram-plugin/tests/permission-rule.test.ts +17 -0
- package/telegram-plugin/tests/permission-title.test.ts +206 -17
- package/telegram-plugin/tests/quota-watch.test.ts +252 -9
- package/telegram-plugin/tests/reply-terminal-reaction.test.ts +6 -1
- package/telegram-plugin/tests/repo-context-pretool.test.ts +62 -0
- package/telegram-plugin/tests/represent-guard.test.ts +162 -0
- package/telegram-plugin/tests/session-tail.test.ts +147 -3
- package/telegram-plugin/tests/silence-liveness-wiring.test.ts +18 -0
- package/telegram-plugin/tests/status-card-budget-parity.test.ts +72 -0
- package/telegram-plugin/tests/status-surface-log.test.ts +146 -0
- package/telegram-plugin/tests/subagent-watcher-clip-narrative.test.ts +58 -0
- package/telegram-plugin/tests/subagent-watcher-parent-turn-key.test.ts +102 -0
- package/telegram-plugin/tests/subagent-watcher-workflow-visibility.test.ts +225 -0
- package/telegram-plugin/tests/subagent-watcher.test.ts +147 -0
- package/telegram-plugin/tests/telegram-activity-visibility-integration.test.ts +597 -0
- package/telegram-plugin/tests/telegram-format.test.ts +101 -6
- package/telegram-plugin/tests/tool-activity-summary.test.ts +550 -15
- package/telegram-plugin/tests/tool-label-pretool.test.ts +73 -0
- package/telegram-plugin/tests/tool-label-sidecar.test.ts +44 -0
- package/telegram-plugin/tests/tool-labels.test.ts +67 -0
- package/telegram-plugin/tests/turn-liveness-floor.test.ts +196 -0
- package/telegram-plugin/tests/turn-liveness-invariant.test.ts +340 -0
- package/telegram-plugin/tests/welcome-text.test.ts +32 -3
- package/telegram-plugin/tests/worker-activity-feed.test.ts +470 -22
- package/telegram-plugin/tool-activity-summary.ts +375 -58
- package/telegram-plugin/turn-liveness-floor.ts +240 -0
- package/telegram-plugin/uat/assertions.ts +115 -0
- package/telegram-plugin/uat/driver.ts +68 -0
- package/telegram-plugin/uat/scenarios/bg-sub-agent-dispatch-dm.test.ts +119 -133
- package/telegram-plugin/uat/scenarios/jtbd-answer-pings.test.ts +94 -0
- package/telegram-plugin/uat/scenarios/jtbd-cross-turn-card-dm.test.ts +109 -0
- package/telegram-plugin/uat/scenarios/jtbd-foreground-feed-thinkgap-dm.test.ts +478 -0
- package/telegram-plugin/uat/scenarios/jtbd-foreground-feed-visibility-dm.test.ts +396 -0
- package/telegram-plugin/uat/scenarios/jtbd-liveness-feed-open-dm.test.ts +202 -0
- package/telegram-plugin/uat/scenarios/jtbd-reply-is-last-dm.test.ts +202 -0
- package/telegram-plugin/uat/scenarios/reactions-dm.test.ts +93 -87
- package/telegram-plugin/welcome-text.ts +13 -1
- package/telegram-plugin/worker-activity-feed.ts +157 -82
- package/telegram-plugin/draft-transport.ts +0 -122
- package/telegram-plugin/tests/draft-retirement-wiring.test.ts +0 -82
- package/telegram-plugin/tests/draft-transport.test.ts +0 -211
|
@@ -16,7 +16,7 @@ var __export = (target, all) => {
|
|
|
16
16
|
};
|
|
17
17
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
18
18
|
|
|
19
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/nodes/identity.js
|
|
19
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/nodes/identity.js
|
|
20
20
|
var require_identity = __commonJS((exports) => {
|
|
21
21
|
var ALIAS = Symbol.for("yaml.alias");
|
|
22
22
|
var DOC = Symbol.for("yaml.document");
|
|
@@ -70,7 +70,7 @@ var require_identity = __commonJS((exports) => {
|
|
|
70
70
|
exports.isSeq = isSeq;
|
|
71
71
|
});
|
|
72
72
|
|
|
73
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/visit.js
|
|
73
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/visit.js
|
|
74
74
|
var require_visit = __commonJS((exports) => {
|
|
75
75
|
var identity = require_identity();
|
|
76
76
|
var BREAK = Symbol("break visit");
|
|
@@ -225,7 +225,7 @@ var require_visit = __commonJS((exports) => {
|
|
|
225
225
|
exports.visitAsync = visitAsync;
|
|
226
226
|
});
|
|
227
227
|
|
|
228
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/doc/directives.js
|
|
228
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/doc/directives.js
|
|
229
229
|
var require_directives = __commonJS((exports) => {
|
|
230
230
|
var identity = require_identity();
|
|
231
231
|
var visit = require_visit();
|
|
@@ -377,7 +377,7 @@ var require_directives = __commonJS((exports) => {
|
|
|
377
377
|
exports.Directives = Directives;
|
|
378
378
|
});
|
|
379
379
|
|
|
380
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/doc/anchors.js
|
|
380
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/doc/anchors.js
|
|
381
381
|
var require_anchors = __commonJS((exports) => {
|
|
382
382
|
var identity = require_identity();
|
|
383
383
|
var visit = require_visit();
|
|
@@ -439,7 +439,7 @@ var require_anchors = __commonJS((exports) => {
|
|
|
439
439
|
exports.findNewAnchor = findNewAnchor;
|
|
440
440
|
});
|
|
441
441
|
|
|
442
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/doc/applyReviver.js
|
|
442
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/doc/applyReviver.js
|
|
443
443
|
var require_applyReviver = __commonJS((exports) => {
|
|
444
444
|
function applyReviver(reviver, obj, key, val) {
|
|
445
445
|
if (val && typeof val === "object") {
|
|
@@ -486,7 +486,7 @@ var require_applyReviver = __commonJS((exports) => {
|
|
|
486
486
|
exports.applyReviver = applyReviver;
|
|
487
487
|
});
|
|
488
488
|
|
|
489
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/nodes/toJS.js
|
|
489
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/nodes/toJS.js
|
|
490
490
|
var require_toJS = __commonJS((exports) => {
|
|
491
491
|
var identity = require_identity();
|
|
492
492
|
function toJS(value, arg, ctx) {
|
|
@@ -513,7 +513,7 @@ var require_toJS = __commonJS((exports) => {
|
|
|
513
513
|
exports.toJS = toJS;
|
|
514
514
|
});
|
|
515
515
|
|
|
516
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/nodes/Node.js
|
|
516
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/nodes/Node.js
|
|
517
517
|
var require_Node = __commonJS((exports) => {
|
|
518
518
|
var applyReviver = require_applyReviver();
|
|
519
519
|
var identity = require_identity();
|
|
@@ -550,7 +550,7 @@ var require_Node = __commonJS((exports) => {
|
|
|
550
550
|
exports.NodeBase = NodeBase;
|
|
551
551
|
});
|
|
552
552
|
|
|
553
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/nodes/Alias.js
|
|
553
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/nodes/Alias.js
|
|
554
554
|
var require_Alias = __commonJS((exports) => {
|
|
555
555
|
var anchors = require_anchors();
|
|
556
556
|
var visit = require_visit();
|
|
@@ -658,7 +658,7 @@ var require_Alias = __commonJS((exports) => {
|
|
|
658
658
|
exports.Alias = Alias;
|
|
659
659
|
});
|
|
660
660
|
|
|
661
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/nodes/Scalar.js
|
|
661
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/nodes/Scalar.js
|
|
662
662
|
var require_Scalar = __commonJS((exports) => {
|
|
663
663
|
var identity = require_identity();
|
|
664
664
|
var Node = require_Node();
|
|
@@ -686,7 +686,7 @@ var require_Scalar = __commonJS((exports) => {
|
|
|
686
686
|
exports.isScalarValue = isScalarValue;
|
|
687
687
|
});
|
|
688
688
|
|
|
689
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/doc/createNode.js
|
|
689
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/doc/createNode.js
|
|
690
690
|
var require_createNode = __commonJS((exports) => {
|
|
691
691
|
var Alias = require_Alias();
|
|
692
692
|
var identity = require_identity();
|
|
@@ -758,7 +758,7 @@ var require_createNode = __commonJS((exports) => {
|
|
|
758
758
|
exports.createNode = createNode;
|
|
759
759
|
});
|
|
760
760
|
|
|
761
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/nodes/Collection.js
|
|
761
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/nodes/Collection.js
|
|
762
762
|
var require_Collection = __commonJS((exports) => {
|
|
763
763
|
var createNode = require_createNode();
|
|
764
764
|
var identity = require_identity();
|
|
@@ -873,7 +873,7 @@ var require_Collection = __commonJS((exports) => {
|
|
|
873
873
|
exports.isEmptyPath = isEmptyPath;
|
|
874
874
|
});
|
|
875
875
|
|
|
876
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/stringify/stringifyComment.js
|
|
876
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/stringify/stringifyComment.js
|
|
877
877
|
var require_stringifyComment = __commonJS((exports) => {
|
|
878
878
|
var stringifyComment = (str) => str.replace(/^(?!$)(?: $)?/gm, "#");
|
|
879
879
|
function indentComment(comment, indent) {
|
|
@@ -890,7 +890,7 @@ var require_stringifyComment = __commonJS((exports) => {
|
|
|
890
890
|
exports.stringifyComment = stringifyComment;
|
|
891
891
|
});
|
|
892
892
|
|
|
893
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/stringify/foldFlowLines.js
|
|
893
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/stringify/foldFlowLines.js
|
|
894
894
|
var require_foldFlowLines = __commonJS((exports) => {
|
|
895
895
|
var FOLD_FLOW = "flow";
|
|
896
896
|
var FOLD_BLOCK = "block";
|
|
@@ -1027,7 +1027,7 @@ ${indent}${text.slice(fold + 1, end2)}`;
|
|
|
1027
1027
|
exports.foldFlowLines = foldFlowLines;
|
|
1028
1028
|
});
|
|
1029
1029
|
|
|
1030
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/stringify/stringifyString.js
|
|
1030
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/stringify/stringifyString.js
|
|
1031
1031
|
var require_stringifyString = __commonJS((exports) => {
|
|
1032
1032
|
var Scalar = require_Scalar();
|
|
1033
1033
|
var foldFlowLines = require_foldFlowLines();
|
|
@@ -1325,7 +1325,7 @@ ${indent}`);
|
|
|
1325
1325
|
exports.stringifyString = stringifyString;
|
|
1326
1326
|
});
|
|
1327
1327
|
|
|
1328
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/stringify/stringify.js
|
|
1328
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/stringify/stringify.js
|
|
1329
1329
|
var require_stringify = __commonJS((exports) => {
|
|
1330
1330
|
var anchors = require_anchors();
|
|
1331
1331
|
var identity = require_identity();
|
|
@@ -1446,7 +1446,7 @@ ${ctx.indent}${str}`;
|
|
|
1446
1446
|
exports.stringify = stringify;
|
|
1447
1447
|
});
|
|
1448
1448
|
|
|
1449
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/stringify/stringifyPair.js
|
|
1449
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/stringify/stringifyPair.js
|
|
1450
1450
|
var require_stringifyPair = __commonJS((exports) => {
|
|
1451
1451
|
var identity = require_identity();
|
|
1452
1452
|
var Scalar = require_Scalar();
|
|
@@ -1582,7 +1582,7 @@ ${ctx.indent}`;
|
|
|
1582
1582
|
exports.stringifyPair = stringifyPair;
|
|
1583
1583
|
});
|
|
1584
1584
|
|
|
1585
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/log.js
|
|
1585
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/log.js
|
|
1586
1586
|
var require_log = __commonJS((exports) => {
|
|
1587
1587
|
var node_process = __require("process");
|
|
1588
1588
|
function debug(logLevel, ...messages) {
|
|
@@ -1601,7 +1601,7 @@ var require_log = __commonJS((exports) => {
|
|
|
1601
1601
|
exports.warn = warn;
|
|
1602
1602
|
});
|
|
1603
1603
|
|
|
1604
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/yaml-1.1/merge.js
|
|
1604
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/yaml-1.1/merge.js
|
|
1605
1605
|
var require_merge = __commonJS((exports) => {
|
|
1606
1606
|
var identity = require_identity();
|
|
1607
1607
|
var Scalar = require_Scalar();
|
|
@@ -1655,7 +1655,7 @@ var require_merge = __commonJS((exports) => {
|
|
|
1655
1655
|
exports.merge = merge;
|
|
1656
1656
|
});
|
|
1657
1657
|
|
|
1658
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/nodes/addPairToJSMap.js
|
|
1658
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/nodes/addPairToJSMap.js
|
|
1659
1659
|
var require_addPairToJSMap = __commonJS((exports) => {
|
|
1660
1660
|
var log = require_log();
|
|
1661
1661
|
var merge = require_merge();
|
|
@@ -1716,7 +1716,7 @@ var require_addPairToJSMap = __commonJS((exports) => {
|
|
|
1716
1716
|
exports.addPairToJSMap = addPairToJSMap;
|
|
1717
1717
|
});
|
|
1718
1718
|
|
|
1719
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/nodes/Pair.js
|
|
1719
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/nodes/Pair.js
|
|
1720
1720
|
var require_Pair = __commonJS((exports) => {
|
|
1721
1721
|
var createNode = require_createNode();
|
|
1722
1722
|
var stringifyPair = require_stringifyPair();
|
|
@@ -1754,7 +1754,7 @@ var require_Pair = __commonJS((exports) => {
|
|
|
1754
1754
|
exports.createPair = createPair;
|
|
1755
1755
|
});
|
|
1756
1756
|
|
|
1757
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/stringify/stringifyCollection.js
|
|
1757
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/stringify/stringifyCollection.js
|
|
1758
1758
|
var require_stringifyCollection = __commonJS((exports) => {
|
|
1759
1759
|
var identity = require_identity();
|
|
1760
1760
|
var stringify = require_stringify();
|
|
@@ -1906,7 +1906,7 @@ ${indent}${end}`;
|
|
|
1906
1906
|
exports.stringifyCollection = stringifyCollection;
|
|
1907
1907
|
});
|
|
1908
1908
|
|
|
1909
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/nodes/YAMLMap.js
|
|
1909
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/nodes/YAMLMap.js
|
|
1910
1910
|
var require_YAMLMap = __commonJS((exports) => {
|
|
1911
1911
|
var stringifyCollection = require_stringifyCollection();
|
|
1912
1912
|
var addPairToJSMap = require_addPairToJSMap();
|
|
@@ -2033,7 +2033,7 @@ var require_YAMLMap = __commonJS((exports) => {
|
|
|
2033
2033
|
exports.findPair = findPair;
|
|
2034
2034
|
});
|
|
2035
2035
|
|
|
2036
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/common/map.js
|
|
2036
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/common/map.js
|
|
2037
2037
|
var require_map = __commonJS((exports) => {
|
|
2038
2038
|
var identity = require_identity();
|
|
2039
2039
|
var YAMLMap = require_YAMLMap();
|
|
@@ -2052,7 +2052,7 @@ var require_map = __commonJS((exports) => {
|
|
|
2052
2052
|
exports.map = map;
|
|
2053
2053
|
});
|
|
2054
2054
|
|
|
2055
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/nodes/YAMLSeq.js
|
|
2055
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/nodes/YAMLSeq.js
|
|
2056
2056
|
var require_YAMLSeq = __commonJS((exports) => {
|
|
2057
2057
|
var createNode = require_createNode();
|
|
2058
2058
|
var stringifyCollection = require_stringifyCollection();
|
|
@@ -2145,7 +2145,7 @@ var require_YAMLSeq = __commonJS((exports) => {
|
|
|
2145
2145
|
exports.YAMLSeq = YAMLSeq;
|
|
2146
2146
|
});
|
|
2147
2147
|
|
|
2148
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/common/seq.js
|
|
2148
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/common/seq.js
|
|
2149
2149
|
var require_seq = __commonJS((exports) => {
|
|
2150
2150
|
var identity = require_identity();
|
|
2151
2151
|
var YAMLSeq = require_YAMLSeq();
|
|
@@ -2164,7 +2164,7 @@ var require_seq = __commonJS((exports) => {
|
|
|
2164
2164
|
exports.seq = seq;
|
|
2165
2165
|
});
|
|
2166
2166
|
|
|
2167
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/common/string.js
|
|
2167
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/common/string.js
|
|
2168
2168
|
var require_string = __commonJS((exports) => {
|
|
2169
2169
|
var stringifyString = require_stringifyString();
|
|
2170
2170
|
var string = {
|
|
@@ -2180,7 +2180,7 @@ var require_string = __commonJS((exports) => {
|
|
|
2180
2180
|
exports.string = string;
|
|
2181
2181
|
});
|
|
2182
2182
|
|
|
2183
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/common/null.js
|
|
2183
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/common/null.js
|
|
2184
2184
|
var require_null = __commonJS((exports) => {
|
|
2185
2185
|
var Scalar = require_Scalar();
|
|
2186
2186
|
var nullTag = {
|
|
@@ -2195,7 +2195,7 @@ var require_null = __commonJS((exports) => {
|
|
|
2195
2195
|
exports.nullTag = nullTag;
|
|
2196
2196
|
});
|
|
2197
2197
|
|
|
2198
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/core/bool.js
|
|
2198
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/core/bool.js
|
|
2199
2199
|
var require_bool = __commonJS((exports) => {
|
|
2200
2200
|
var Scalar = require_Scalar();
|
|
2201
2201
|
var boolTag = {
|
|
@@ -2216,7 +2216,7 @@ var require_bool = __commonJS((exports) => {
|
|
|
2216
2216
|
exports.boolTag = boolTag;
|
|
2217
2217
|
});
|
|
2218
2218
|
|
|
2219
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/stringify/stringifyNumber.js
|
|
2219
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/stringify/stringifyNumber.js
|
|
2220
2220
|
var require_stringifyNumber = __commonJS((exports) => {
|
|
2221
2221
|
function stringifyNumber({ format, minFractionDigits, tag, value }) {
|
|
2222
2222
|
if (typeof value === "bigint")
|
|
@@ -2240,7 +2240,7 @@ var require_stringifyNumber = __commonJS((exports) => {
|
|
|
2240
2240
|
exports.stringifyNumber = stringifyNumber;
|
|
2241
2241
|
});
|
|
2242
2242
|
|
|
2243
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/core/float.js
|
|
2243
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/core/float.js
|
|
2244
2244
|
var require_float = __commonJS((exports) => {
|
|
2245
2245
|
var Scalar = require_Scalar();
|
|
2246
2246
|
var stringifyNumber = require_stringifyNumber();
|
|
@@ -2283,7 +2283,7 @@ var require_float = __commonJS((exports) => {
|
|
|
2283
2283
|
exports.floatNaN = floatNaN;
|
|
2284
2284
|
});
|
|
2285
2285
|
|
|
2286
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/core/int.js
|
|
2286
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/core/int.js
|
|
2287
2287
|
var require_int = __commonJS((exports) => {
|
|
2288
2288
|
var stringifyNumber = require_stringifyNumber();
|
|
2289
2289
|
var intIdentify = (value) => typeof value === "bigint" || Number.isInteger(value);
|
|
@@ -2325,7 +2325,7 @@ var require_int = __commonJS((exports) => {
|
|
|
2325
2325
|
exports.intOct = intOct;
|
|
2326
2326
|
});
|
|
2327
2327
|
|
|
2328
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/core/schema.js
|
|
2328
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/core/schema.js
|
|
2329
2329
|
var require_schema = __commonJS((exports) => {
|
|
2330
2330
|
var map = require_map();
|
|
2331
2331
|
var _null = require_null();
|
|
@@ -2350,7 +2350,7 @@ var require_schema = __commonJS((exports) => {
|
|
|
2350
2350
|
exports.schema = schema;
|
|
2351
2351
|
});
|
|
2352
2352
|
|
|
2353
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/json/schema.js
|
|
2353
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/json/schema.js
|
|
2354
2354
|
var require_schema2 = __commonJS((exports) => {
|
|
2355
2355
|
var Scalar = require_Scalar();
|
|
2356
2356
|
var map = require_map();
|
|
@@ -2414,7 +2414,7 @@ var require_schema2 = __commonJS((exports) => {
|
|
|
2414
2414
|
exports.schema = schema;
|
|
2415
2415
|
});
|
|
2416
2416
|
|
|
2417
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/yaml-1.1/binary.js
|
|
2417
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/yaml-1.1/binary.js
|
|
2418
2418
|
var require_binary = __commonJS((exports) => {
|
|
2419
2419
|
var node_buffer = __require("buffer");
|
|
2420
2420
|
var Scalar = require_Scalar();
|
|
@@ -2469,7 +2469,7 @@ var require_binary = __commonJS((exports) => {
|
|
|
2469
2469
|
exports.binary = binary;
|
|
2470
2470
|
});
|
|
2471
2471
|
|
|
2472
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/yaml-1.1/pairs.js
|
|
2472
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/yaml-1.1/pairs.js
|
|
2473
2473
|
var require_pairs = __commonJS((exports) => {
|
|
2474
2474
|
var identity = require_identity();
|
|
2475
2475
|
var Pair = require_Pair();
|
|
@@ -2544,7 +2544,7 @@ ${cn.comment}` : item.comment;
|
|
|
2544
2544
|
exports.resolvePairs = resolvePairs;
|
|
2545
2545
|
});
|
|
2546
2546
|
|
|
2547
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/yaml-1.1/omap.js
|
|
2547
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/yaml-1.1/omap.js
|
|
2548
2548
|
var require_omap = __commonJS((exports) => {
|
|
2549
2549
|
var identity = require_identity();
|
|
2550
2550
|
var toJS = require_toJS();
|
|
@@ -2616,7 +2616,7 @@ var require_omap = __commonJS((exports) => {
|
|
|
2616
2616
|
exports.omap = omap;
|
|
2617
2617
|
});
|
|
2618
2618
|
|
|
2619
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/yaml-1.1/bool.js
|
|
2619
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/yaml-1.1/bool.js
|
|
2620
2620
|
var require_bool2 = __commonJS((exports) => {
|
|
2621
2621
|
var Scalar = require_Scalar();
|
|
2622
2622
|
function boolStringify({ value, source }, ctx) {
|
|
@@ -2645,7 +2645,7 @@ var require_bool2 = __commonJS((exports) => {
|
|
|
2645
2645
|
exports.trueTag = trueTag;
|
|
2646
2646
|
});
|
|
2647
2647
|
|
|
2648
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/yaml-1.1/float.js
|
|
2648
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/yaml-1.1/float.js
|
|
2649
2649
|
var require_float2 = __commonJS((exports) => {
|
|
2650
2650
|
var Scalar = require_Scalar();
|
|
2651
2651
|
var stringifyNumber = require_stringifyNumber();
|
|
@@ -2691,7 +2691,7 @@ var require_float2 = __commonJS((exports) => {
|
|
|
2691
2691
|
exports.floatNaN = floatNaN;
|
|
2692
2692
|
});
|
|
2693
2693
|
|
|
2694
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/yaml-1.1/int.js
|
|
2694
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/yaml-1.1/int.js
|
|
2695
2695
|
var require_int2 = __commonJS((exports) => {
|
|
2696
2696
|
var stringifyNumber = require_stringifyNumber();
|
|
2697
2697
|
var intIdentify = (value) => typeof value === "bigint" || Number.isInteger(value);
|
|
@@ -2767,7 +2767,7 @@ var require_int2 = __commonJS((exports) => {
|
|
|
2767
2767
|
exports.intOct = intOct;
|
|
2768
2768
|
});
|
|
2769
2769
|
|
|
2770
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/yaml-1.1/set.js
|
|
2770
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/yaml-1.1/set.js
|
|
2771
2771
|
var require_set = __commonJS((exports) => {
|
|
2772
2772
|
var identity = require_identity();
|
|
2773
2773
|
var Pair = require_Pair();
|
|
@@ -2850,7 +2850,7 @@ var require_set = __commonJS((exports) => {
|
|
|
2850
2850
|
exports.set = set;
|
|
2851
2851
|
});
|
|
2852
2852
|
|
|
2853
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/yaml-1.1/timestamp.js
|
|
2853
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/yaml-1.1/timestamp.js
|
|
2854
2854
|
var require_timestamp = __commonJS((exports) => {
|
|
2855
2855
|
var stringifyNumber = require_stringifyNumber();
|
|
2856
2856
|
function parseSexagesimal(str, asBigInt) {
|
|
@@ -2932,7 +2932,7 @@ var require_timestamp = __commonJS((exports) => {
|
|
|
2932
2932
|
exports.timestamp = timestamp;
|
|
2933
2933
|
});
|
|
2934
2934
|
|
|
2935
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/yaml-1.1/schema.js
|
|
2935
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/yaml-1.1/schema.js
|
|
2936
2936
|
var require_schema3 = __commonJS((exports) => {
|
|
2937
2937
|
var map = require_map();
|
|
2938
2938
|
var _null = require_null();
|
|
@@ -2973,7 +2973,7 @@ var require_schema3 = __commonJS((exports) => {
|
|
|
2973
2973
|
exports.schema = schema;
|
|
2974
2974
|
});
|
|
2975
2975
|
|
|
2976
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/tags.js
|
|
2976
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/tags.js
|
|
2977
2977
|
var require_tags = __commonJS((exports) => {
|
|
2978
2978
|
var map = require_map();
|
|
2979
2979
|
var _null = require_null();
|
|
@@ -3064,7 +3064,7 @@ var require_tags = __commonJS((exports) => {
|
|
|
3064
3064
|
exports.getTags = getTags;
|
|
3065
3065
|
});
|
|
3066
3066
|
|
|
3067
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/Schema.js
|
|
3067
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/schema/Schema.js
|
|
3068
3068
|
var require_Schema = __commonJS((exports) => {
|
|
3069
3069
|
var identity = require_identity();
|
|
3070
3070
|
var map = require_map();
|
|
@@ -3094,7 +3094,7 @@ var require_Schema = __commonJS((exports) => {
|
|
|
3094
3094
|
exports.Schema = Schema;
|
|
3095
3095
|
});
|
|
3096
3096
|
|
|
3097
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/stringify/stringifyDocument.js
|
|
3097
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/stringify/stringifyDocument.js
|
|
3098
3098
|
var require_stringifyDocument = __commonJS((exports) => {
|
|
3099
3099
|
var identity = require_identity();
|
|
3100
3100
|
var stringify = require_stringify();
|
|
@@ -3174,7 +3174,7 @@ var require_stringifyDocument = __commonJS((exports) => {
|
|
|
3174
3174
|
exports.stringifyDocument = stringifyDocument;
|
|
3175
3175
|
});
|
|
3176
3176
|
|
|
3177
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/doc/Document.js
|
|
3177
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/doc/Document.js
|
|
3178
3178
|
var require_Document = __commonJS((exports) => {
|
|
3179
3179
|
var Alias = require_Alias();
|
|
3180
3180
|
var Collection = require_Collection();
|
|
@@ -3409,7 +3409,7 @@ var require_Document = __commonJS((exports) => {
|
|
|
3409
3409
|
exports.Document = Document;
|
|
3410
3410
|
});
|
|
3411
3411
|
|
|
3412
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/errors.js
|
|
3412
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/errors.js
|
|
3413
3413
|
var require_errors = __commonJS((exports) => {
|
|
3414
3414
|
class YAMLError extends Error {
|
|
3415
3415
|
constructor(name, pos, code, message) {
|
|
@@ -3474,7 +3474,7 @@ ${pointer}
|
|
|
3474
3474
|
exports.prettifyError = prettifyError;
|
|
3475
3475
|
});
|
|
3476
3476
|
|
|
3477
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/resolve-props.js
|
|
3477
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/resolve-props.js
|
|
3478
3478
|
var require_resolve_props = __commonJS((exports) => {
|
|
3479
3479
|
function resolveProps(tokens, { flow, indicator, next, offset, onError, parentIndent, startOnNewline }) {
|
|
3480
3480
|
let spaceBefore = false;
|
|
@@ -3604,7 +3604,7 @@ var require_resolve_props = __commonJS((exports) => {
|
|
|
3604
3604
|
exports.resolveProps = resolveProps;
|
|
3605
3605
|
});
|
|
3606
3606
|
|
|
3607
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/util-contains-newline.js
|
|
3607
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/util-contains-newline.js
|
|
3608
3608
|
var require_util_contains_newline = __commonJS((exports) => {
|
|
3609
3609
|
function containsNewline(key) {
|
|
3610
3610
|
if (!key)
|
|
@@ -3644,7 +3644,7 @@ var require_util_contains_newline = __commonJS((exports) => {
|
|
|
3644
3644
|
exports.containsNewline = containsNewline;
|
|
3645
3645
|
});
|
|
3646
3646
|
|
|
3647
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/util-flow-indent-check.js
|
|
3647
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/util-flow-indent-check.js
|
|
3648
3648
|
var require_util_flow_indent_check = __commonJS((exports) => {
|
|
3649
3649
|
var utilContainsNewline = require_util_contains_newline();
|
|
3650
3650
|
function flowIndentCheck(indent, fc, onError) {
|
|
@@ -3659,7 +3659,7 @@ var require_util_flow_indent_check = __commonJS((exports) => {
|
|
|
3659
3659
|
exports.flowIndentCheck = flowIndentCheck;
|
|
3660
3660
|
});
|
|
3661
3661
|
|
|
3662
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/util-map-includes.js
|
|
3662
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/util-map-includes.js
|
|
3663
3663
|
var require_util_map_includes = __commonJS((exports) => {
|
|
3664
3664
|
var identity = require_identity();
|
|
3665
3665
|
function mapIncludes(ctx, items, search) {
|
|
@@ -3672,7 +3672,7 @@ var require_util_map_includes = __commonJS((exports) => {
|
|
|
3672
3672
|
exports.mapIncludes = mapIncludes;
|
|
3673
3673
|
});
|
|
3674
3674
|
|
|
3675
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/resolve-block-map.js
|
|
3675
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/resolve-block-map.js
|
|
3676
3676
|
var require_resolve_block_map = __commonJS((exports) => {
|
|
3677
3677
|
var Pair = require_Pair();
|
|
3678
3678
|
var YAMLMap = require_YAMLMap();
|
|
@@ -3779,7 +3779,7 @@ var require_resolve_block_map = __commonJS((exports) => {
|
|
|
3779
3779
|
exports.resolveBlockMap = resolveBlockMap;
|
|
3780
3780
|
});
|
|
3781
3781
|
|
|
3782
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/resolve-block-seq.js
|
|
3782
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/resolve-block-seq.js
|
|
3783
3783
|
var require_resolve_block_seq = __commonJS((exports) => {
|
|
3784
3784
|
var YAMLSeq = require_YAMLSeq();
|
|
3785
3785
|
var resolveProps = require_resolve_props();
|
|
@@ -3827,7 +3827,7 @@ var require_resolve_block_seq = __commonJS((exports) => {
|
|
|
3827
3827
|
exports.resolveBlockSeq = resolveBlockSeq;
|
|
3828
3828
|
});
|
|
3829
3829
|
|
|
3830
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/resolve-end.js
|
|
3830
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/resolve-end.js
|
|
3831
3831
|
var require_resolve_end = __commonJS((exports) => {
|
|
3832
3832
|
function resolveEnd(end, offset, reqSpace, onError) {
|
|
3833
3833
|
let comment = "";
|
|
@@ -3867,7 +3867,7 @@ var require_resolve_end = __commonJS((exports) => {
|
|
|
3867
3867
|
exports.resolveEnd = resolveEnd;
|
|
3868
3868
|
});
|
|
3869
3869
|
|
|
3870
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/resolve-flow-collection.js
|
|
3870
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/resolve-flow-collection.js
|
|
3871
3871
|
var require_resolve_flow_collection = __commonJS((exports) => {
|
|
3872
3872
|
var identity = require_identity();
|
|
3873
3873
|
var Pair = require_Pair();
|
|
@@ -4058,7 +4058,7 @@ var require_resolve_flow_collection = __commonJS((exports) => {
|
|
|
4058
4058
|
exports.resolveFlowCollection = resolveFlowCollection;
|
|
4059
4059
|
});
|
|
4060
4060
|
|
|
4061
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/compose-collection.js
|
|
4061
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/compose-collection.js
|
|
4062
4062
|
var require_compose_collection = __commonJS((exports) => {
|
|
4063
4063
|
var identity = require_identity();
|
|
4064
4064
|
var Scalar = require_Scalar();
|
|
@@ -4120,7 +4120,7 @@ var require_compose_collection = __commonJS((exports) => {
|
|
|
4120
4120
|
exports.composeCollection = composeCollection;
|
|
4121
4121
|
});
|
|
4122
4122
|
|
|
4123
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/resolve-block-scalar.js
|
|
4123
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/resolve-block-scalar.js
|
|
4124
4124
|
var require_resolve_block_scalar = __commonJS((exports) => {
|
|
4125
4125
|
var Scalar = require_Scalar();
|
|
4126
4126
|
function resolveBlockScalar(ctx, scalar, onError) {
|
|
@@ -4313,7 +4313,7 @@ var require_resolve_block_scalar = __commonJS((exports) => {
|
|
|
4313
4313
|
exports.resolveBlockScalar = resolveBlockScalar;
|
|
4314
4314
|
});
|
|
4315
4315
|
|
|
4316
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/resolve-flow-scalar.js
|
|
4316
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/resolve-flow-scalar.js
|
|
4317
4317
|
var require_resolve_flow_scalar = __commonJS((exports) => {
|
|
4318
4318
|
var Scalar = require_Scalar();
|
|
4319
4319
|
var resolveEnd = require_resolve_end();
|
|
@@ -4529,7 +4529,7 @@ var require_resolve_flow_scalar = __commonJS((exports) => {
|
|
|
4529
4529
|
exports.resolveFlowScalar = resolveFlowScalar;
|
|
4530
4530
|
});
|
|
4531
4531
|
|
|
4532
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/compose-scalar.js
|
|
4532
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/compose-scalar.js
|
|
4533
4533
|
var require_compose_scalar = __commonJS((exports) => {
|
|
4534
4534
|
var identity = require_identity();
|
|
4535
4535
|
var Scalar = require_Scalar();
|
|
@@ -4607,7 +4607,7 @@ var require_compose_scalar = __commonJS((exports) => {
|
|
|
4607
4607
|
exports.composeScalar = composeScalar;
|
|
4608
4608
|
});
|
|
4609
4609
|
|
|
4610
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/util-empty-scalar-position.js
|
|
4610
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/util-empty-scalar-position.js
|
|
4611
4611
|
var require_util_empty_scalar_position = __commonJS((exports) => {
|
|
4612
4612
|
function emptyScalarPosition(offset, before, pos) {
|
|
4613
4613
|
if (before) {
|
|
@@ -4634,7 +4634,7 @@ var require_util_empty_scalar_position = __commonJS((exports) => {
|
|
|
4634
4634
|
exports.emptyScalarPosition = emptyScalarPosition;
|
|
4635
4635
|
});
|
|
4636
4636
|
|
|
4637
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/compose-node.js
|
|
4637
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/compose-node.js
|
|
4638
4638
|
var require_compose_node = __commonJS((exports) => {
|
|
4639
4639
|
var Alias = require_Alias();
|
|
4640
4640
|
var identity = require_identity();
|
|
@@ -4737,7 +4737,7 @@ var require_compose_node = __commonJS((exports) => {
|
|
|
4737
4737
|
exports.composeNode = composeNode;
|
|
4738
4738
|
});
|
|
4739
4739
|
|
|
4740
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/compose-doc.js
|
|
4740
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/compose-doc.js
|
|
4741
4741
|
var require_compose_doc = __commonJS((exports) => {
|
|
4742
4742
|
var Document = require_Document();
|
|
4743
4743
|
var composeNode = require_compose_node();
|
|
@@ -4777,7 +4777,7 @@ var require_compose_doc = __commonJS((exports) => {
|
|
|
4777
4777
|
exports.composeDoc = composeDoc;
|
|
4778
4778
|
});
|
|
4779
4779
|
|
|
4780
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/composer.js
|
|
4780
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/compose/composer.js
|
|
4781
4781
|
var require_composer = __commonJS((exports) => {
|
|
4782
4782
|
var node_process = __require("process");
|
|
4783
4783
|
var directives = require_directives();
|
|
@@ -4966,7 +4966,7 @@ ${end.comment}` : end.comment;
|
|
|
4966
4966
|
exports.Composer = Composer;
|
|
4967
4967
|
});
|
|
4968
4968
|
|
|
4969
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/parse/cst-scalar.js
|
|
4969
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/parse/cst-scalar.js
|
|
4970
4970
|
var require_cst_scalar = __commonJS((exports) => {
|
|
4971
4971
|
var resolveBlockScalar = require_resolve_block_scalar();
|
|
4972
4972
|
var resolveFlowScalar = require_resolve_flow_scalar();
|
|
@@ -5156,7 +5156,7 @@ var require_cst_scalar = __commonJS((exports) => {
|
|
|
5156
5156
|
exports.setScalarValue = setScalarValue;
|
|
5157
5157
|
});
|
|
5158
5158
|
|
|
5159
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/parse/cst-stringify.js
|
|
5159
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/parse/cst-stringify.js
|
|
5160
5160
|
var require_cst_stringify = __commonJS((exports) => {
|
|
5161
5161
|
var stringify = (cst) => ("type" in cst) ? stringifyToken(cst) : stringifyItem(cst);
|
|
5162
5162
|
function stringifyToken(token) {
|
|
@@ -5214,7 +5214,7 @@ var require_cst_stringify = __commonJS((exports) => {
|
|
|
5214
5214
|
exports.stringify = stringify;
|
|
5215
5215
|
});
|
|
5216
5216
|
|
|
5217
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/parse/cst-visit.js
|
|
5217
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/parse/cst-visit.js
|
|
5218
5218
|
var require_cst_visit = __commonJS((exports) => {
|
|
5219
5219
|
var BREAK = Symbol("break visit");
|
|
5220
5220
|
var SKIP = Symbol("skip children");
|
|
@@ -5273,7 +5273,7 @@ var require_cst_visit = __commonJS((exports) => {
|
|
|
5273
5273
|
exports.visit = visit;
|
|
5274
5274
|
});
|
|
5275
5275
|
|
|
5276
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/parse/cst.js
|
|
5276
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/parse/cst.js
|
|
5277
5277
|
var require_cst = __commonJS((exports) => {
|
|
5278
5278
|
var cstScalar = require_cst_scalar();
|
|
5279
5279
|
var cstStringify = require_cst_stringify();
|
|
@@ -5374,7 +5374,7 @@ var require_cst = __commonJS((exports) => {
|
|
|
5374
5374
|
exports.tokenType = tokenType;
|
|
5375
5375
|
});
|
|
5376
5376
|
|
|
5377
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/parse/lexer.js
|
|
5377
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/parse/lexer.js
|
|
5378
5378
|
var require_lexer = __commonJS((exports) => {
|
|
5379
5379
|
var cst = require_cst();
|
|
5380
5380
|
function isEmpty(ch) {
|
|
@@ -5960,7 +5960,7 @@ var require_lexer = __commonJS((exports) => {
|
|
|
5960
5960
|
exports.Lexer = Lexer;
|
|
5961
5961
|
});
|
|
5962
5962
|
|
|
5963
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/parse/line-counter.js
|
|
5963
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/parse/line-counter.js
|
|
5964
5964
|
var require_line_counter = __commonJS((exports) => {
|
|
5965
5965
|
class LineCounter {
|
|
5966
5966
|
constructor() {
|
|
@@ -5988,7 +5988,7 @@ var require_line_counter = __commonJS((exports) => {
|
|
|
5988
5988
|
exports.LineCounter = LineCounter;
|
|
5989
5989
|
});
|
|
5990
5990
|
|
|
5991
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/parse/parser.js
|
|
5991
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/parse/parser.js
|
|
5992
5992
|
var require_parser = __commonJS((exports) => {
|
|
5993
5993
|
var node_process = __require("process");
|
|
5994
5994
|
var cst = require_cst();
|
|
@@ -6837,7 +6837,7 @@ var require_parser = __commonJS((exports) => {
|
|
|
6837
6837
|
exports.Parser = Parser;
|
|
6838
6838
|
});
|
|
6839
6839
|
|
|
6840
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/public-api.js
|
|
6840
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/public-api.js
|
|
6841
6841
|
var require_public_api = __commonJS((exports) => {
|
|
6842
6842
|
var composer = require_composer();
|
|
6843
6843
|
var Document = require_Document();
|
|
@@ -6939,7 +6939,7 @@ import { readFileSync as readFileSync2, existsSync as existsSync3 } from "node:f
|
|
|
6939
6939
|
import { homedir } from "node:os";
|
|
6940
6940
|
import { resolve as resolve3 } from "node:path";
|
|
6941
6941
|
|
|
6942
|
-
// node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/index.js
|
|
6942
|
+
// ../../switchroom/node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/index.js
|
|
6943
6943
|
var composer = require_composer();
|
|
6944
6944
|
var Document = require_Document();
|
|
6945
6945
|
var Schema = require_Schema();
|
|
@@ -6985,7 +6985,7 @@ var $stringify = publicApi.stringify;
|
|
|
6985
6985
|
var $visit = visit.visit;
|
|
6986
6986
|
var $visitAsync = visit.visitAsync;
|
|
6987
6987
|
|
|
6988
|
-
// node_modules/.bun/zod@3.25.76/node_modules/zod/v3/external.js
|
|
6988
|
+
// ../../switchroom/node_modules/.bun/zod@3.25.76/node_modules/zod/v3/external.js
|
|
6989
6989
|
var exports_external = {};
|
|
6990
6990
|
__export(exports_external, {
|
|
6991
6991
|
void: () => voidType,
|
|
@@ -7097,7 +7097,7 @@ __export(exports_external, {
|
|
|
7097
7097
|
BRAND: () => BRAND
|
|
7098
7098
|
});
|
|
7099
7099
|
|
|
7100
|
-
// node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/util.js
|
|
7100
|
+
// ../../switchroom/node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/util.js
|
|
7101
7101
|
var util;
|
|
7102
7102
|
(function(util2) {
|
|
7103
7103
|
util2.assertEqual = (_) => {};
|
|
@@ -7228,7 +7228,7 @@ var getParsedType = (data) => {
|
|
|
7228
7228
|
}
|
|
7229
7229
|
};
|
|
7230
7230
|
|
|
7231
|
-
// node_modules/.bun/zod@3.25.76/node_modules/zod/v3/ZodError.js
|
|
7231
|
+
// ../../switchroom/node_modules/.bun/zod@3.25.76/node_modules/zod/v3/ZodError.js
|
|
7232
7232
|
var ZodIssueCode = util.arrayToEnum([
|
|
7233
7233
|
"invalid_type",
|
|
7234
7234
|
"invalid_literal",
|
|
@@ -7347,7 +7347,7 @@ ZodError.create = (issues) => {
|
|
|
7347
7347
|
return error;
|
|
7348
7348
|
};
|
|
7349
7349
|
|
|
7350
|
-
// node_modules/.bun/zod@3.25.76/node_modules/zod/v3/locales/en.js
|
|
7350
|
+
// ../../switchroom/node_modules/.bun/zod@3.25.76/node_modules/zod/v3/locales/en.js
|
|
7351
7351
|
var errorMap = (issue, _ctx) => {
|
|
7352
7352
|
let message;
|
|
7353
7353
|
switch (issue.code) {
|
|
@@ -7450,7 +7450,7 @@ var errorMap = (issue, _ctx) => {
|
|
|
7450
7450
|
};
|
|
7451
7451
|
var en_default = errorMap;
|
|
7452
7452
|
|
|
7453
|
-
// node_modules/.bun/zod@3.25.76/node_modules/zod/v3/errors.js
|
|
7453
|
+
// ../../switchroom/node_modules/.bun/zod@3.25.76/node_modules/zod/v3/errors.js
|
|
7454
7454
|
var overrideErrorMap = en_default;
|
|
7455
7455
|
function setErrorMap(map) {
|
|
7456
7456
|
overrideErrorMap = map;
|
|
@@ -7458,7 +7458,7 @@ function setErrorMap(map) {
|
|
|
7458
7458
|
function getErrorMap() {
|
|
7459
7459
|
return overrideErrorMap;
|
|
7460
7460
|
}
|
|
7461
|
-
// node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
|
|
7461
|
+
// ../../switchroom/node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
|
|
7462
7462
|
var makeIssue = (params) => {
|
|
7463
7463
|
const { data, path, errorMaps, issueData } = params;
|
|
7464
7464
|
const fullPath = [...path, ...issueData.path || []];
|
|
@@ -7564,14 +7564,14 @@ var isAborted = (x) => x.status === "aborted";
|
|
|
7564
7564
|
var isDirty = (x) => x.status === "dirty";
|
|
7565
7565
|
var isValid = (x) => x.status === "valid";
|
|
7566
7566
|
var isAsync = (x) => typeof Promise !== "undefined" && x instanceof Promise;
|
|
7567
|
-
// node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/errorUtil.js
|
|
7567
|
+
// ../../switchroom/node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/errorUtil.js
|
|
7568
7568
|
var errorUtil;
|
|
7569
7569
|
(function(errorUtil2) {
|
|
7570
7570
|
errorUtil2.errToObj = (message) => typeof message === "string" ? { message } : message || {};
|
|
7571
7571
|
errorUtil2.toString = (message) => typeof message === "string" ? message : message?.message;
|
|
7572
7572
|
})(errorUtil || (errorUtil = {}));
|
|
7573
7573
|
|
|
7574
|
-
// node_modules/.bun/zod@3.25.76/node_modules/zod/v3/types.js
|
|
7574
|
+
// ../../switchroom/node_modules/.bun/zod@3.25.76/node_modules/zod/v3/types.js
|
|
7575
7575
|
class ParseInputLazyPath {
|
|
7576
7576
|
constructor(parent, value, path, key) {
|
|
7577
7577
|
this._cachedPath = [];
|
|
@@ -11150,7 +11150,7 @@ var TelegramChannelSchema = exports_external.object({
|
|
|
11150
11150
|
format: exports_external.enum(["html", "markdownv2", "text"]).optional().describe("Default reply format passed to the plugin"),
|
|
11151
11151
|
rate_limit_ms: exports_external.number().optional().describe("Minimum delay between outgoing messages in ms"),
|
|
11152
11152
|
stream_mode: exports_external.enum(["pty", "checklist"]).optional().describe("How live progress is streamed to Telegram during a turn. " + "'pty' (default) surfaces text snapshots of Claude Code's TUI — " + "compatible but can flicker as Ink re-renders. 'checklist' drives " + "a structured progress card from session-tail events — stable " + "order, per-tool status emojis, fires only on semantic transitions."),
|
|
11153
|
-
stream_throttle_ms: exports_external.number().int().nonnegative().optional().describe("Throttle window in ms between successive stream edits
|
|
11153
|
+
stream_throttle_ms: exports_external.number().int().nonnegative().optional().describe("Throttle window in ms between successive in-place stream edits " + "during a turn. Lower = more responsive stream, higher = fewer API " + "calls. Floored at 250 by draft-stream itself. Default 400 ms for DMs " + "and 1000 ms for groups/forums (respects Telegram's ~1 edit/sec/message " + "practical ceiling). Override per-agent if a particular agent needs " + "snappier or quieter streaming."),
|
|
11154
11154
|
clear_status_on_completion: exports_external.boolean().optional().describe("When true, the live activity/status feed (the in-place 'what it's " + "doing' message — Reading X, Searching the web for Y, …) is DELETED " + "when the turn's final answer lands, so only the reply remains. " + "Default false: the status message is left in the chat as a record " + "(its last step marked done) — no post-then-delete. Per-agent " + "override; cascades defaults → profile → agent (per-key)."),
|
|
11155
11155
|
hotReloadStable: exports_external.boolean().optional().describe("If true, the stable workspace prefix (AGENTS.md, SOUL.md, USER.md, " + "IDENTITY.md, TOOLS.md) is re-injected on every turn via " + "the UserPromptSubmit hook instead of baked into --append-system-prompt " + "at session start. Lets workspace edits propagate without a restart. " + "Costs ~5-10% per-turn latency/spend since the stable prefix is no " + "longer prompt-cached."),
|
|
11156
11156
|
inject_on_change: exports_external.boolean().optional().describe("Context-efficiency gate for per-turn hook injection (default true). " + "When true (the default), the turn-pacing directive and dynamic " + "workspace content are only re-emitted when their content changes or " + "the session_id changes — suppressing redundant injection that " + "otherwise triples compaction frequency. Set to false to revert to " + "the legacy always-emit behaviour (every turn injects the full " + "content regardless of whether it changed)."),
|
|
@@ -11238,6 +11238,14 @@ var GoogleWorkspaceConfigSchema = exports_external.object({
|
|
|
11238
11238
|
approvers: exports_external.array(ApproverIdSchema).min(1).describe("Array of numeric Telegram user IDs authorized to approve drive onboarding. " + "At least one must be specified."),
|
|
11239
11239
|
tier: GoogleWorkspaceTierSchema.optional().describe("RFC G Phase 1: which upstream MCP tier to expose. " + "core (default) = ~16 tools (Drive+Docs+Sheets+Calendar). " + "extended = ~40 tools (+Slides, Forms, Tasks, Chat). " + "complete = ~60+ tools (+Gmail; not recommended yet — see RFC G §5).")
|
|
11240
11240
|
}).optional();
|
|
11241
|
+
var LiteLLMConfigSchema = exports_external.object({
|
|
11242
|
+
enabled: exports_external.boolean().optional().describe("Opt-in toggle. When true, `switchroom apply` provisions a per-agent " + "LiteLLM virtual key and injects routing env into the container. " + "Default OFF."),
|
|
11243
|
+
base_url: exports_external.string().optional().describe("LiteLLM proxy base URL the agent's claude CLI routes through, e.g. " + "'http://127.0.0.1:4010'. Agents use network_mode:host, so loopback " + "reaches a host-bound proxy. Exported as ANTHROPIC_BASE_URL."),
|
|
11244
|
+
admin_key: exports_external.string().optional().describe("LiteLLM master/admin key used at apply time to provision the team + " + "virtual key. Supports a vault reference (e.g. " + "'vault:litellm/master-key') — resolution happens at apply time via " + "the vault-broker. Never injected into the agent container."),
|
|
11245
|
+
team: exports_external.string().optional().describe("LiteLLM team alias the per-agent key is created under. Defaults to " + "'switchroom' (applied in code, not as a schema default)."),
|
|
11246
|
+
small_fast_model: exports_external.string().optional().describe("Model id exported as ANTHROPIC_SMALL_FAST_MODEL for the claude CLI's " + "background/fast lane, e.g. 'claude-haiku-4-5-20251001'."),
|
|
11247
|
+
tags: exports_external.record(exports_external.string(), exports_external.string()).optional().describe("Extra key/value metadata tags attached to the provisioned LiteLLM " + "virtual key. Merged per-key across cascade layers (agent wins).")
|
|
11248
|
+
}).optional().describe("LiteLLM routing config — opt-in per-agent virtual-key auto-provisioning " + "+ routing env. Default OFF. See LiteLLMConfigSchema doc for the full flow.");
|
|
11241
11249
|
var MicrosoftWorkspaceConfigSchema = exports_external.object({
|
|
11242
11250
|
microsoft_client_id: exports_external.string().min(1).optional().describe("Microsoft OAuth application (client) ID from Entra portal " + "(literal string or vault reference e.g. " + "'vault:microsoft-oauth-client-id'). OPTIONAL — omit it to use " + "switchroom's shipped default Microsoft app (zero-config). " + "Set it only to bring your own Entra app (BYO)."),
|
|
11243
11251
|
microsoft_client_secret: exports_external.string().min(1).optional().describe("Microsoft OAuth client secret. Optional — public-client apps " + "(Mobile + Desktop platform with 'Allow public client flows' " + "enabled) work without a secret; confidential clients pass " + "one. Either literal or vault reference e.g. " + "'vault:microsoft-oauth-client-secret'."),
|
|
@@ -11334,6 +11342,7 @@ var profileFields = {
|
|
|
11334
11342
|
mcp_servers: exports_external.record(exports_external.string(), exports_external.unknown()).optional(),
|
|
11335
11343
|
hooks: AgentHooksSchema,
|
|
11336
11344
|
env: exports_external.record(exports_external.string(), exports_external.string()).optional(),
|
|
11345
|
+
litellm: LiteLLMConfigSchema,
|
|
11337
11346
|
system_prompt_append: exports_external.string().optional(),
|
|
11338
11347
|
skills: exports_external.array(exports_external.string()).optional(),
|
|
11339
11348
|
bundled_skills: exports_external.record(exports_external.string(), exports_external.boolean()).optional().describe("Opt-out map for switchroom's bundled-default skills " + "(e.g. skill-creator, mcp-builder, webapp-testing, pdf, docx, " + "xlsx, pptx, switchroom-cli, switchroom-status, switchroom-health). " + "Set a key to `false` to suppress that default for this agent. " + "Cascades from defaults.bundled_skills."),
|
|
@@ -11406,6 +11415,7 @@ var AgentSchema = exports_external.object({
|
|
|
11406
11415
|
mcp_servers: exports_external.record(exports_external.string(), exports_external.unknown()).optional().describe("Additional MCP server configurations"),
|
|
11407
11416
|
hooks: AgentHooksSchema.describe("Claude Code lifecycle hooks (SessionStart, UserPromptSubmit, Stop, etc). " + "Written to settings.json.hooks in Claude Code's native shape."),
|
|
11408
11417
|
env: exports_external.record(exports_external.string(), exports_external.string()).optional().describe("Environment variables exported in start.sh before claude runs"),
|
|
11418
|
+
litellm: LiteLLMConfigSchema.describe("Per-agent LiteLLM routing override. Presence with `enabled: true` opts " + "this agent IN to per-agent virtual-key auto-provisioning + routing env " + "(falls back to the top-level `litellm:` block for base_url/admin_key/" + "team/small_fast_model). Deep-merges one level over defaults/profile; " + "`tags` merge per-key, agent wins. Default OFF."),
|
|
11409
11419
|
system_prompt_append: exports_external.string().optional().describe("Text passed via claude's --append-system-prompt flag. " + "Appended to the default or CLAUDE.md-derived system prompt."),
|
|
11410
11420
|
skills: exports_external.array(exports_external.string()).optional().describe("Names of skills from switchroom.skills_dir to symlink into this " + "agent's skills/ directory. Unioned with defaults.skills."),
|
|
11411
11421
|
bundled_skills: exports_external.record(exports_external.string(), exports_external.boolean()).optional().describe("Per-agent override of switchroom's bundled-default skills " + "(skill-creator, mcp-builder, webapp-testing, pdf, docx, xlsx, " + "pptx, switchroom-cli/status/health). Set a key to `false` to " + "opt out for this agent. Per-agent value wins over defaults.bundled_skills."),
|
|
@@ -11531,7 +11541,7 @@ var WebServiceConfigSchema = exports_external.object({
|
|
|
11531
11541
|
});
|
|
11532
11542
|
var HostdConfigSchema = exports_external.object({
|
|
11533
11543
|
config_edit_enabled: exports_external.boolean().default(false).describe("Opt-in toggle for the `config_propose_edit` hostd verb (RFC " + "admin-agent-config-edit §3). Default false — the verb returns " + "`E_CONFIG_EDIT_DISABLED` until the operator explicitly flips " + "this to true. When true, admin agents can propose unified-diff " + "patches against " + "`/state/config/switchroom.yaml`, gated by an operator approval " + "card in the primary chat. Same trust posture as `update_apply` " + "and `agent_restart`: the human-in-the-loop tap is the security " + "boundary, not the agent's judgement."),
|
|
11534
|
-
config_edit_rate_per_hour: exports_external.number().int().min(1).max(20).default(3).describe("Per-requesting-agent rate cap for `config_propose_edit` cards " + "(RFC admin-agent-config-edit §5). Default 3 cards/hour; min 1, " + "max 20.
|
|
11544
|
+
config_edit_rate_per_hour: exports_external.number().int().min(1).max(20).default(3).describe("Per-requesting-agent rate cap for `config_propose_edit` cards " + "(RFC admin-agent-config-edit §5). Default 3 cards/hour; min 1, " + "max 20. ENFORCED server-side: a caller exceeding this in a sliding " + "1-hour window is rejected with `E_RATE_LIMITED` (carrying a " + "`retry_after` fix) instead of posting another operator approval " + "card — so a looping agent is throttled rather than spamming the chat.")
|
|
11535
11545
|
});
|
|
11536
11546
|
var CronEgressSchema = exports_external.object({
|
|
11537
11547
|
allowed_hosts: exports_external.array(exports_external.string().min(1)).default([]).describe("Hosts a poll may reach (exact, https-only). loopback/private/IP-literal are always rejected."),
|
|
@@ -11564,11 +11574,14 @@ var SwitchroomConfigSchema = exports_external.object({
|
|
|
11564
11574
|
message: "Consumer name must be a path-safe slug (letters, digits, underscore, hyphen)"
|
|
11565
11575
|
}).describe("Socket-path identity; binds at /run/switchroom/auth-broker/<name>/sock"),
|
|
11566
11576
|
account: exports_external.string().min(1).describe("Pinned account label for this consumer. `get-credentials` returns " + "this account's credentials; `mark-exhausted` from this consumer " + "only affects this account."),
|
|
11567
|
-
uid: exports_external.number().int().nonnegative().optional().describe("Optional UID to chown the consumer socket to (defaults to 0 = root, " + "suitable for sibling containers running as root).")
|
|
11568
|
-
|
|
11577
|
+
uid: exports_external.number().int().nonnegative().optional().describe("Optional UID to chown the consumer socket to (defaults to 0 = root, " + "suitable for sibling containers running as root)."),
|
|
11578
|
+
mirror_dir: exports_external.string().optional().describe("Optional host-side directory path. When set, the broker actively " + "writes the consumer's effective-account `.credentials.json` mirror " + "here — in addition to serving creds on demand via `get-credentials`. " + "Use this to eliminate the pull-latency gap: without a mirror the " + "consumer only gets failover creds at its next scheduled re-fetch " + "(up to 30 min). With a mirror the broker pushes failover creds " + "immediately when it detects exhaustion (consumer-quota-sensor tick, " + "or a mark-exhausted RPC on the pinned account). The directory must " + "be accessible to the broker container (bind-mounted from the host) " + "and to the consumer container; the broker writes " + "`<mirror_dir>/.credentials.json` atomically. Chown is attempted to " + "`uid` (default 0) — swallowed when CAP_CHOWN is absent.")
|
|
11579
|
+
})).optional().describe("Non-agent peers that hold a broker socket (RFC H §4.8). Each gets " + "its own `/run/switchroom/auth-broker/<name>/sock` chowned to its UID. " + "Consumers cannot be admins; a consumer name that collides with an " + "agent (whether that agent has `admin: true` or not) is a config " + "error caught at schema validation."),
|
|
11580
|
+
allow_overage_accounts: exports_external.array(exports_external.string().min(1)).optional().describe("Opt-in list of account labels (bare strings matching `auth.active` / " + "`auth.fallback_order` entries) that may be served PAST the weekly " + "utilization wall when Anthropic overage billing is available for the " + "account (`overageStatus === 'allowed'`). Overage is REAL MONEY — " + "default is empty (no account gets this). An account in this list is " + "only kept eligible when its fresh quota snapshot reports " + "`overageStatus: 'allowed'` AND `overageDisabledReason` is NOT " + "'out_of_credits' (i.e. the overage credit has not been exhausted). " + "As soon as `overageDisabledReason` becomes 'out_of_credits', the " + "account is blocked immediately regardless of this flag. Overage lifts " + "ONLY the utilization wall — it cannot lift an active exhaustion mark " + "written by a real 429 (`mark-exhausted`).")
|
|
11569
11581
|
}).optional().describe("Switchroom-auth-broker configuration (RFC H). Fleet-wide active account, " + "fallback order, admin-agent ACL, and ephemeral-consumer surface. " + "Required from the v0.8+ schema onwards; pre-v0.8 fleets are migrated " + "in-place by `switchroom apply` (see src/auth/migrate-schema.ts)."),
|
|
11570
11582
|
drive: GoogleWorkspaceConfigSchema.describe("RFC D legacy key — use `google_workspace:` instead. Optional Google " + "Workspace onboarding configuration. When set, supplies Google OAuth " + "client credentials, the approver allowlist for `switchroom drive " + "connect`, and the optional tier knob. Env vars " + "(SWITCHROOM_GOOGLE_CLIENT_ID, SWITCHROOM_GOOGLE_CLIENT_SECRET, " + "SWITCHROOM_APPROVER_USER_ID) take precedence over this block when " + "set, preserving back-compat with the env-only flow shipped in #766."),
|
|
11571
11583
|
google_workspace: GoogleWorkspaceConfigSchema.describe("RFC G canonical key. Top-level Google Workspace configuration — " + "OAuth client credentials, approver allowlist, and tier knob (`core` " + "| `extended` | `complete`, default `core`). Mutually exclusive with " + "`drive:` at the top level (loader fails fast if both are set)."),
|
|
11584
|
+
litellm: LiteLLMConfigSchema.describe("Top-level LiteLLM routing infra — global base_url, admin_key (the " + "LiteLLM master key, supports a `vault:` ref), team alias, and " + "small_fast_model shared by every agent that opts in. Set `enabled: " + "true` here to default the whole fleet on (each agent can still set " + "`litellm.enabled: false` to opt out). Default OFF."),
|
|
11572
11585
|
microsoft_workspace: MicrosoftWorkspaceConfigSchema.describe("RFC #1873 (Microsoft 365 integration). Top-level Microsoft Workspace " + "configuration — OAuth client credentials (Entra app), authority " + "endpoint (defaults to /common for personal MSA + work), and the " + "org_mode opt-in for Teams/SharePoint surfaces. Block is optional; " + "when omitted the broker does not register the Microsoft provider."),
|
|
11573
11586
|
notion_workspace: NotionWorkspaceConfigSchema.describe("RFC reference/rfcs/notion-integration.md. Top-level Notion integration " + "config — vault key for the integration token, friendly-name → " + "database UUID map, optional MCP-package version pin, and optional " + "global rate-limit override (default 3 rps, Notion's documented " + "public-API limit). Block is optional; when omitted no agent gets a " + "Notion MCP entry regardless of per-agent config."),
|
|
11574
11587
|
quota: QuotaConfigSchema.optional().describe("Optional weekly/monthly USD spend budgets rendered in the session " + "greeting. Usage is read from ccusage at runtime; no network calls."),
|
|
@@ -11988,6 +12001,24 @@ function mergeAgentConfig(defaultsIn, agentIn) {
|
|
|
11988
12001
|
...merged.env ?? {}
|
|
11989
12002
|
};
|
|
11990
12003
|
}
|
|
12004
|
+
if (defaults.litellm || merged.litellm) {
|
|
12005
|
+
const base = defaults.litellm ?? {};
|
|
12006
|
+
const override = merged.litellm ?? {};
|
|
12007
|
+
const combined = { ...base };
|
|
12008
|
+
for (const [k, v] of Object.entries(override)) {
|
|
12009
|
+
if (v === undefined)
|
|
12010
|
+
continue;
|
|
12011
|
+
if (k === "tags" && base.tags && typeof v === "object" && v !== null && !Array.isArray(v)) {
|
|
12012
|
+
combined.tags = {
|
|
12013
|
+
...base.tags,
|
|
12014
|
+
...v
|
|
12015
|
+
};
|
|
12016
|
+
} else {
|
|
12017
|
+
combined[k] = v;
|
|
12018
|
+
}
|
|
12019
|
+
}
|
|
12020
|
+
merged.litellm = combined;
|
|
12021
|
+
}
|
|
11991
12022
|
if (defaults.subagents || merged.subagents) {
|
|
11992
12023
|
const dSub = defaults.subagents ?? {};
|
|
11993
12024
|
const mSub = merged.subagents ?? {};
|
|
@@ -12357,6 +12388,14 @@ import { dirname as dirname3, join as join4, resolve as resolve7 } from "node:pa
|
|
|
12357
12388
|
// src/agents/compose.ts
|
|
12358
12389
|
import { createHash } from "node:crypto";
|
|
12359
12390
|
|
|
12391
|
+
// src/config/timezone.ts
|
|
12392
|
+
var CONTAINER_DEFAULT_UTC_ZONES = new Set([
|
|
12393
|
+
"UTC",
|
|
12394
|
+
"Etc/UTC",
|
|
12395
|
+
"Etc/Universal",
|
|
12396
|
+
"Universal"
|
|
12397
|
+
]);
|
|
12398
|
+
|
|
12360
12399
|
// src/vault/broker/peercred.ts
|
|
12361
12400
|
var RESERVED_AGENT_NAMES = new Set(["operator", "hostd"]);
|
|
12362
12401
|
function isReservedAgentName(name) {
|
|
@@ -12387,6 +12426,9 @@ var BIND_MOUNT_EXACT_SOURCE_DENY = new Set(["/var/run/docker.sock"]);
|
|
|
12387
12426
|
var OAUTH_BETA = "oauth-2025-04-20";
|
|
12388
12427
|
var DEFAULT_USER_AGENT = "claude-cli/1.0.0 (external, cli)";
|
|
12389
12428
|
var DEFAULT_PROBE_MODEL = "claude-haiku-4-5-20251001";
|
|
12429
|
+
function isProbeThin(q) {
|
|
12430
|
+
return q.fiveHourUtilPresent === false && q.sevenDayUtilPresent === false;
|
|
12431
|
+
}
|
|
12390
12432
|
function parseFloatHeader(headers, name) {
|
|
12391
12433
|
const v = headers.get(name);
|
|
12392
12434
|
if (v == null || v.trim().length === 0)
|
|
@@ -12417,6 +12459,8 @@ function parseQuotaHeaders(headers) {
|
|
|
12417
12459
|
data: {
|
|
12418
12460
|
fiveHourUtilizationPct: (fiveHour ?? 0) * 100,
|
|
12419
12461
|
sevenDayUtilizationPct: (sevenDay ?? 0) * 100,
|
|
12462
|
+
fiveHourUtilPresent: fiveHour != null,
|
|
12463
|
+
sevenDayUtilPresent: sevenDay != null,
|
|
12420
12464
|
fiveHourResetAt: parseEpochHeader(headers, "anthropic-ratelimit-unified-5h-reset"),
|
|
12421
12465
|
sevenDayResetAt: parseEpochHeader(headers, "anthropic-ratelimit-unified-7d-reset"),
|
|
12422
12466
|
representativeClaim: headers.get("anthropic-ratelimit-unified-representative-claim"),
|
|
@@ -12470,57 +12514,50 @@ async function fetchQuota(opts) {
|
|
|
12470
12514
|
return parsed;
|
|
12471
12515
|
}
|
|
12472
12516
|
|
|
12473
|
-
// src/auth/broker/consumer-quota-sensor.ts
|
|
12474
|
-
var EXHAUSTION_PCT = 99.5;
|
|
12475
|
-
var DEFAULT_CONSUMER_PROBE_INTERVAL_MS = 10 * 60 * 1000;
|
|
12476
|
-
function quotaIndicatesExhaustion(result) {
|
|
12477
|
-
if (!result.ok)
|
|
12478
|
-
return { exhausted: false, until: null };
|
|
12479
|
-
const d = result.data;
|
|
12480
|
-
const fiveBlocked = d.fiveHourUtilizationPct >= EXHAUSTION_PCT;
|
|
12481
|
-
const sevenBlocked = d.sevenDayUtilizationPct >= EXHAUSTION_PCT;
|
|
12482
|
-
if (!fiveBlocked && !sevenBlocked)
|
|
12483
|
-
return { exhausted: false, until: null };
|
|
12484
|
-
const fiveReset = fiveBlocked ? d.fiveHourResetAt?.getTime() ?? null : null;
|
|
12485
|
-
const sevenReset = sevenBlocked ? d.sevenDayResetAt?.getTime() ?? null : null;
|
|
12486
|
-
const candidates = [fiveReset, sevenReset].filter((x) => x != null);
|
|
12487
|
-
const until = candidates.length > 0 ? Math.max(...candidates) : null;
|
|
12488
|
-
return { exhausted: true, until };
|
|
12489
|
-
}
|
|
12490
|
-
function resolveConsumerProbeIntervalMs(env) {
|
|
12491
|
-
if (env.SWITCHROOM_DISABLE_CONSUMER_QUOTA_PROBE === "1")
|
|
12492
|
-
return 0;
|
|
12493
|
-
const raw = env.SWITCHROOM_CONSUMER_QUOTA_PROBE_MS;
|
|
12494
|
-
if (raw !== undefined) {
|
|
12495
|
-
const n = Number(raw);
|
|
12496
|
-
if (Number.isFinite(n) && n >= 0)
|
|
12497
|
-
return n;
|
|
12498
|
-
}
|
|
12499
|
-
return DEFAULT_CONSUMER_PROBE_INTERVAL_MS;
|
|
12500
|
-
}
|
|
12501
|
-
|
|
12502
12517
|
// src/auth/broker/account-eligibility.ts
|
|
12503
12518
|
var WALL_PCT = 99.5;
|
|
12504
12519
|
var HEALTHY_CLEAR_PCT = 80;
|
|
12505
12520
|
var SNAPSHOT_STALE_AGE_MS = 24 * 60 * 60 * 1000;
|
|
12521
|
+
var OVERAGE_EXHAUSTED_REASONS = new Set(["out_of_credits"]);
|
|
12506
12522
|
function snapshotFresh(s, now, maxAgeMs = SNAPSHOT_STALE_AGE_MS) {
|
|
12507
12523
|
return !!s && now - s.capturedAt <= maxAgeMs && s.capturedAt <= now + 60000;
|
|
12508
12524
|
}
|
|
12509
12525
|
function snapshotWalled(s) {
|
|
12510
12526
|
return s.fiveHourUtilizationPct >= WALL_PCT || s.sevenDayUtilizationPct >= WALL_PCT;
|
|
12511
12527
|
}
|
|
12528
|
+
function overageLiftsWall(snapshot, inAllowList) {
|
|
12529
|
+
if (!inAllowList)
|
|
12530
|
+
return false;
|
|
12531
|
+
if (snapshot.overageStatus !== "allowed")
|
|
12532
|
+
return false;
|
|
12533
|
+
const reason = snapshot.overageDisabledReason;
|
|
12534
|
+
if (reason != null && OVERAGE_EXHAUSTED_REASONS.has(reason))
|
|
12535
|
+
return false;
|
|
12536
|
+
return true;
|
|
12537
|
+
}
|
|
12512
12538
|
function snapshotClearlyHealthy(s) {
|
|
12513
12539
|
return s.fiveHourUtilizationPct < HEALTHY_CLEAR_PCT && s.sevenDayUtilizationPct < HEALTHY_CLEAR_PCT;
|
|
12514
12540
|
}
|
|
12515
|
-
function
|
|
12516
|
-
const { mark, snapshot, now } = opts;
|
|
12541
|
+
function accountEligibility(opts) {
|
|
12542
|
+
const { mark, snapshot, now, allowOverage = false } = opts;
|
|
12517
12543
|
if (snapshotFresh(snapshot, now)) {
|
|
12518
12544
|
const markedAt = mark?.marked_at ?? 0;
|
|
12519
12545
|
if (snapshot.capturedAt >= markedAt) {
|
|
12520
|
-
|
|
12546
|
+
if (snapshotWalled(snapshot)) {
|
|
12547
|
+
if (overageLiftsWall(snapshot, allowOverage)) {
|
|
12548
|
+
return "eligible";
|
|
12549
|
+
}
|
|
12550
|
+
return "blocked";
|
|
12551
|
+
}
|
|
12552
|
+
return "eligible";
|
|
12521
12553
|
}
|
|
12522
12554
|
}
|
|
12523
|
-
|
|
12555
|
+
if (mark !== undefined && mark.exhausted_until > now)
|
|
12556
|
+
return "blocked";
|
|
12557
|
+
return "unknown";
|
|
12558
|
+
}
|
|
12559
|
+
function isAccountBlocked(opts) {
|
|
12560
|
+
return accountEligibility(opts) === "blocked";
|
|
12524
12561
|
}
|
|
12525
12562
|
function snapshotShouldClearMark(snapshot, mark, now) {
|
|
12526
12563
|
if (!mark)
|
|
@@ -12529,6 +12566,8 @@ function snapshotShouldClearMark(snapshot, mark, now) {
|
|
|
12529
12566
|
return false;
|
|
12530
12567
|
if (snapshot.capturedAt < (mark.marked_at ?? 0))
|
|
12531
12568
|
return false;
|
|
12569
|
+
if (isProbeThin(snapshot))
|
|
12570
|
+
return false;
|
|
12532
12571
|
return snapshotClearlyHealthy(snapshot);
|
|
12533
12572
|
}
|
|
12534
12573
|
function clampMarkExpiry(opts) {
|
|
@@ -12540,6 +12579,46 @@ function clampMarkExpiry(opts) {
|
|
|
12540
12579
|
return liveContradictsWeeklyWall ? shortCeil : proposedUntil;
|
|
12541
12580
|
}
|
|
12542
12581
|
|
|
12582
|
+
// src/auth/broker/consumer-quota-sensor.ts
|
|
12583
|
+
var EXHAUSTION_PCT = 99.5;
|
|
12584
|
+
var DEFAULT_CONSUMER_PROBE_INTERVAL_MS = 10 * 60 * 1000;
|
|
12585
|
+
function quotaIndicatesExhaustion(result, allowOverage = false) {
|
|
12586
|
+
if (!result.ok)
|
|
12587
|
+
return { exhausted: false, until: null };
|
|
12588
|
+
const d = result.data;
|
|
12589
|
+
const fiveBlocked = d.fiveHourUtilizationPct >= EXHAUSTION_PCT;
|
|
12590
|
+
const sevenBlocked = d.sevenDayUtilizationPct >= EXHAUSTION_PCT;
|
|
12591
|
+
if (!fiveBlocked && !sevenBlocked)
|
|
12592
|
+
return { exhausted: false, until: null };
|
|
12593
|
+
if (allowOverage) {
|
|
12594
|
+
const snap = {
|
|
12595
|
+
fiveHourUtilizationPct: d.fiveHourUtilizationPct,
|
|
12596
|
+
sevenDayUtilizationPct: d.sevenDayUtilizationPct,
|
|
12597
|
+
capturedAt: Date.now(),
|
|
12598
|
+
overageStatus: d.overageStatus,
|
|
12599
|
+
overageDisabledReason: d.overageDisabledReason
|
|
12600
|
+
};
|
|
12601
|
+
if (overageLiftsWall(snap, true))
|
|
12602
|
+
return { exhausted: false, until: null };
|
|
12603
|
+
}
|
|
12604
|
+
const fiveReset = fiveBlocked ? d.fiveHourResetAt?.getTime() ?? null : null;
|
|
12605
|
+
const sevenReset = sevenBlocked ? d.sevenDayResetAt?.getTime() ?? null : null;
|
|
12606
|
+
const candidates = [fiveReset, sevenReset].filter((x) => x != null);
|
|
12607
|
+
const until = candidates.length > 0 ? Math.max(...candidates) : null;
|
|
12608
|
+
return { exhausted: true, until };
|
|
12609
|
+
}
|
|
12610
|
+
function resolveConsumerProbeIntervalMs(env) {
|
|
12611
|
+
if (env.SWITCHROOM_DISABLE_CONSUMER_QUOTA_PROBE === "1")
|
|
12612
|
+
return 0;
|
|
12613
|
+
const raw = env.SWITCHROOM_CONSUMER_QUOTA_PROBE_MS;
|
|
12614
|
+
if (raw !== undefined) {
|
|
12615
|
+
const n = Number(raw);
|
|
12616
|
+
if (Number.isFinite(n) && n >= 0)
|
|
12617
|
+
return n;
|
|
12618
|
+
}
|
|
12619
|
+
return DEFAULT_CONSUMER_PROBE_INTERVAL_MS;
|
|
12620
|
+
}
|
|
12621
|
+
|
|
12543
12622
|
// src/util/atomic.ts
|
|
12544
12623
|
import { randomBytes } from "node:crypto";
|
|
12545
12624
|
import { closeSync, constants, fsyncSync, openSync, renameSync, rmSync, writeSync } from "node:fs";
|
|
@@ -12721,7 +12800,7 @@ function atomicWriteJson(destPath, value, mode = 384) {
|
|
|
12721
12800
|
// src/auth/account-refresh.ts
|
|
12722
12801
|
var REFRESH_THRESHOLD_MS = 60 * 60 * 1000;
|
|
12723
12802
|
var DEFAULT_TOKEN_URL = process.env.SWITCHROOM_OAUTH_TOKEN_URL ?? "https://console.anthropic.com/v1/oauth/token";
|
|
12724
|
-
var DEFAULT_CLIENT_ID = process.env.SWITCHROOM_OAUTH_CLIENT_ID ?? "
|
|
12803
|
+
var DEFAULT_CLIENT_ID = process.env.SWITCHROOM_OAUTH_CLIENT_ID ?? "9d1c250a-e61b-44d9-88ed-5944d1962f5e";
|
|
12725
12804
|
var defaultFetcher = async (url, init) => {
|
|
12726
12805
|
const res = await fetch(url, {
|
|
12727
12806
|
method: init.method,
|
|
@@ -13543,7 +13622,8 @@ var ProbeQuotaRequestSchema = exports_external.object({
|
|
|
13543
13622
|
op: exports_external.literal("probe-quota"),
|
|
13544
13623
|
id: exports_external.string().min(1),
|
|
13545
13624
|
accounts: exports_external.array(exports_external.string().min(1)).min(1).max(32),
|
|
13546
|
-
timeoutMs: exports_external.number().int().positive().max(60000).optional()
|
|
13625
|
+
timeoutMs: exports_external.number().int().positive().max(60000).optional(),
|
|
13626
|
+
forceLive: exports_external.boolean().optional()
|
|
13547
13627
|
});
|
|
13548
13628
|
var ClaimNotificationRequestSchema = exports_external.object({
|
|
13549
13629
|
v: exports_external.literal(PROTOCOL_VERSION),
|
|
@@ -13594,7 +13674,8 @@ var ListStateDataSchema = exports_external.object({
|
|
|
13594
13674
|
fallback_order: exports_external.array(exports_external.string()),
|
|
13595
13675
|
accounts: exports_external.array(AccountStateSchema),
|
|
13596
13676
|
agents: exports_external.array(AgentStateSchema),
|
|
13597
|
-
consumers: exports_external.array(ConsumerStateSchema)
|
|
13677
|
+
consumers: exports_external.array(ConsumerStateSchema),
|
|
13678
|
+
active_overage_serving: exports_external.boolean().optional()
|
|
13598
13679
|
});
|
|
13599
13680
|
var SetActiveDataSchema = exports_external.object({
|
|
13600
13681
|
active: exports_external.string(),
|
|
@@ -13710,6 +13791,30 @@ var AUDIT_ROTATE_BYTES = 10 * 1024 * 1024;
|
|
|
13710
13791
|
var AUDIT_KEEP = 5;
|
|
13711
13792
|
var AUDIT_LINE_MAX = 4000;
|
|
13712
13793
|
var NOTIFICATION_CLAIM_MAX_AGE_MS = 86400000;
|
|
13794
|
+
var DEFAULT_QUOTA_PROBE_TTL_MS = 45000;
|
|
13795
|
+
function quotaProbeTtlMs() {
|
|
13796
|
+
const raw = process.env.SWITCHROOM_QUOTA_PROBE_TTL_MS;
|
|
13797
|
+
if (raw == null || raw === "")
|
|
13798
|
+
return DEFAULT_QUOTA_PROBE_TTL_MS;
|
|
13799
|
+
const n = Number(raw);
|
|
13800
|
+
return Number.isFinite(n) && n >= 0 ? n : DEFAULT_QUOTA_PROBE_TTL_MS;
|
|
13801
|
+
}
|
|
13802
|
+
function cachedSnapshotToResult(s) {
|
|
13803
|
+
return {
|
|
13804
|
+
ok: true,
|
|
13805
|
+
data: {
|
|
13806
|
+
fiveHourUtilizationPct: s.fiveHourUtilizationPct,
|
|
13807
|
+
sevenDayUtilizationPct: s.sevenDayUtilizationPct,
|
|
13808
|
+
fiveHourResetAt: s.fiveHourResetAt ? new Date(s.fiveHourResetAt) : null,
|
|
13809
|
+
sevenDayResetAt: s.sevenDayResetAt ? new Date(s.sevenDayResetAt) : null,
|
|
13810
|
+
representativeClaim: s.representativeClaim,
|
|
13811
|
+
overageStatus: s.overageStatus,
|
|
13812
|
+
overageDisabledReason: s.overageDisabledReason,
|
|
13813
|
+
fiveHourUtilPresent: s.fiveHourUtilPresent,
|
|
13814
|
+
sevenDayUtilPresent: s.sevenDayUtilPresent
|
|
13815
|
+
}
|
|
13816
|
+
};
|
|
13817
|
+
}
|
|
13713
13818
|
function sha256Hex(content) {
|
|
13714
13819
|
return createHash2("sha256").update(content).digest("hex");
|
|
13715
13820
|
}
|
|
@@ -13764,6 +13869,7 @@ class AuthBroker {
|
|
|
13764
13869
|
providers;
|
|
13765
13870
|
quota = {};
|
|
13766
13871
|
lastQuotaCache = {};
|
|
13872
|
+
probeInFlight = new Map;
|
|
13767
13873
|
shaIndex = {};
|
|
13768
13874
|
thresholdViolations = {};
|
|
13769
13875
|
notificationClaims = {};
|
|
@@ -14164,7 +14270,7 @@ class AuthBroker {
|
|
|
14164
14270
|
await this.opListMicrosoftAccounts(socket, reqId, identity2);
|
|
14165
14271
|
break;
|
|
14166
14272
|
case "probe-quota":
|
|
14167
|
-
await this.opProbeQuota(socket, reqId, identity2, req.accounts, req.timeoutMs);
|
|
14273
|
+
await this.opProbeQuota(socket, reqId, identity2, req.accounts, req.timeoutMs, req.forceLive);
|
|
14168
14274
|
break;
|
|
14169
14275
|
case "claim-notification":
|
|
14170
14276
|
this.opClaimNotification(socket, reqId, identity2, req.key, req.windowMs);
|
|
@@ -14206,12 +14312,78 @@ class AuthBroker {
|
|
|
14206
14312
|
return account;
|
|
14207
14313
|
return this.accountWithFailover(account);
|
|
14208
14314
|
}
|
|
14315
|
+
isOverageAllowed(account) {
|
|
14316
|
+
return (this.config.auth?.allow_overage_accounts ?? []).includes(account);
|
|
14317
|
+
}
|
|
14209
14318
|
isAccountExhausted(account) {
|
|
14210
14319
|
return isAccountBlocked({
|
|
14211
14320
|
mark: this.quota[account],
|
|
14212
14321
|
snapshot: this.lastQuotaCache[account],
|
|
14213
|
-
now: this.now()
|
|
14322
|
+
now: this.now(),
|
|
14323
|
+
allowOverage: this.isOverageAllowed(account)
|
|
14324
|
+
});
|
|
14325
|
+
}
|
|
14326
|
+
isActiveOverageServing(account) {
|
|
14327
|
+
if (!account)
|
|
14328
|
+
return false;
|
|
14329
|
+
if (!this.isOverageAllowed(account))
|
|
14330
|
+
return false;
|
|
14331
|
+
const snapshot = this.lastQuotaCache[account];
|
|
14332
|
+
const now = this.now();
|
|
14333
|
+
if (!snapshot || !snapshotFresh(snapshot, now))
|
|
14334
|
+
return false;
|
|
14335
|
+
if (!overageLiftsWall(snapshot, true))
|
|
14336
|
+
return false;
|
|
14337
|
+
return accountEligibility({
|
|
14338
|
+
mark: this.quota[account],
|
|
14339
|
+
snapshot,
|
|
14340
|
+
now,
|
|
14341
|
+
allowOverage: true
|
|
14342
|
+
}) === "eligible";
|
|
14343
|
+
}
|
|
14344
|
+
accountEligibilityOf(account) {
|
|
14345
|
+
const snapshot = this.lastQuotaCache[account];
|
|
14346
|
+
const allowOverage = this.isOverageAllowed(account);
|
|
14347
|
+
const verdict = accountEligibility({
|
|
14348
|
+
mark: this.quota[account],
|
|
14349
|
+
snapshot,
|
|
14350
|
+
now: this.now(),
|
|
14351
|
+
allowOverage
|
|
14214
14352
|
});
|
|
14353
|
+
if (verdict === "eligible" && allowOverage && snapshot && (snapshot.fiveHourUtilizationPct >= WALL_PCT || snapshot.sevenDayUtilizationPct >= WALL_PCT)) {
|
|
14354
|
+
process.stdout.write(`auth-broker: ${account} is past the utilization wall but eligible via allow_overage — Anthropic overage billing active (5h=${snapshot.fiveHourUtilizationPct.toFixed(1)}%, 7d=${snapshot.sevenDayUtilizationPct.toFixed(1)}%)
|
|
14355
|
+
`);
|
|
14356
|
+
}
|
|
14357
|
+
return verdict;
|
|
14358
|
+
}
|
|
14359
|
+
async probeAndCacheOne(account) {
|
|
14360
|
+
try {
|
|
14361
|
+
const creds = readAccountCredentials(account, this.home);
|
|
14362
|
+
const token = creds?.claudeAiOauth?.accessToken;
|
|
14363
|
+
if (!token)
|
|
14364
|
+
return;
|
|
14365
|
+
const result = await this.probeQuotaSingleFlight(account, token);
|
|
14366
|
+
if (result.ok)
|
|
14367
|
+
this.cacheQuotaSnapshot(account, result);
|
|
14368
|
+
} catch {}
|
|
14369
|
+
}
|
|
14370
|
+
async nextHealthyAccountLive(current, order) {
|
|
14371
|
+
const cached = this.nextHealthyAccount(current, order);
|
|
14372
|
+
if (cached && this.accountEligibilityOf(cached) === "eligible")
|
|
14373
|
+
return cached;
|
|
14374
|
+
const start = order.indexOf(current);
|
|
14375
|
+
const ring = start === -1 ? [...order] : order.map((_, i) => order[(start + 1 + i) % order.length]).filter((x) => !!x);
|
|
14376
|
+
const unknowns = ring.filter((cand) => cand && cand !== current && accountExists(cand, this.home) && this.accountEligibilityOf(cand) === "unknown");
|
|
14377
|
+
await Promise.all(unknowns.map((cand) => this.probeAndCacheOne(cand)));
|
|
14378
|
+
const reselected = this.nextHealthyAccount(current, order);
|
|
14379
|
+
if (reselected && this.accountEligibilityOf(reselected) === "eligible")
|
|
14380
|
+
return reselected;
|
|
14381
|
+
for (const cand of ring) {
|
|
14382
|
+
if (cand && cand !== current && accountExists(cand, this.home) && this.accountEligibilityOf(cand) === "unknown") {
|
|
14383
|
+
return cand;
|
|
14384
|
+
}
|
|
14385
|
+
}
|
|
14386
|
+
return null;
|
|
14215
14387
|
}
|
|
14216
14388
|
accountWithFailover(account) {
|
|
14217
14389
|
if (!account || !this.isAccountExhausted(account))
|
|
@@ -14222,23 +14394,27 @@ class AuthBroker {
|
|
|
14222
14394
|
if (readAccountCredentials(cand, this.home))
|
|
14223
14395
|
return cand;
|
|
14224
14396
|
}
|
|
14397
|
+
const active = this.config.auth?.active;
|
|
14398
|
+
if (active && active !== account && !this.isAccountExhausted(active) && readAccountCredentials(active, this.home)) {
|
|
14399
|
+
return active;
|
|
14400
|
+
}
|
|
14225
14401
|
return account;
|
|
14226
14402
|
}
|
|
14227
14403
|
async opGetCredentials(socket, id, identity2) {
|
|
14228
14404
|
const account = this.servingAccount(identity2);
|
|
14229
14405
|
if (!account) {
|
|
14230
|
-
this.audit({ op: "get-credentials", identity: identity2, ok: false, error: "no-active-account" });
|
|
14406
|
+
this.audit({ op: "get-credentials", identity: identity2, accountKind: "claude", ok: false, error: "no-active-account" });
|
|
14231
14407
|
socket.write(encodeError(id, "ACCOUNT_NOT_FOUND", "no active account configured"));
|
|
14232
14408
|
return;
|
|
14233
14409
|
}
|
|
14234
14410
|
const creds = readAccountCredentials(account, this.home);
|
|
14235
14411
|
if (!creds) {
|
|
14236
|
-
this.audit({ op: "get-credentials", identity: identity2, account, ok: false, error: "missing-credentials" });
|
|
14412
|
+
this.audit({ op: "get-credentials", identity: identity2, account, accountKind: "claude", ok: false, error: "missing-credentials" });
|
|
14237
14413
|
socket.write(encodeError(id, "ACCOUNT_NOT_FOUND", `no credentials for account '${account}'`));
|
|
14238
14414
|
return;
|
|
14239
14415
|
}
|
|
14240
14416
|
const expiresAt = creds.claudeAiOauth?.expiresAt;
|
|
14241
|
-
this.audit({ op: "get-credentials", identity: identity2, account, ok: true });
|
|
14417
|
+
this.audit({ op: "get-credentials", identity: identity2, account, accountKind: "claude", ok: true });
|
|
14242
14418
|
socket.write(encodeSuccess(id, { account, credentials: creds, expiresAt }));
|
|
14243
14419
|
}
|
|
14244
14420
|
async opListState(socket, id, identity2) {
|
|
@@ -14269,13 +14445,15 @@ class AuthBroker {
|
|
|
14269
14445
|
account: c.account,
|
|
14270
14446
|
last_seen_at: this.consumerLastSeen[c.name] ?? null
|
|
14271
14447
|
}));
|
|
14448
|
+
const active_overage_serving = this.isActiveOverageServing(this.callerAccount(identity2));
|
|
14272
14449
|
this.audit({ op: "list-state", identity: identity2, ok: true });
|
|
14273
14450
|
socket.write(encodeSuccess(id, {
|
|
14274
14451
|
active: auth.active ?? "",
|
|
14275
14452
|
fallback_order: auth.fallback_order ?? [],
|
|
14276
14453
|
accounts,
|
|
14277
14454
|
agents,
|
|
14278
|
-
consumers
|
|
14455
|
+
consumers,
|
|
14456
|
+
active_overage_serving
|
|
14279
14457
|
}));
|
|
14280
14458
|
}
|
|
14281
14459
|
async opListGoogleAccounts(socket, id, identity2) {
|
|
@@ -14290,35 +14468,60 @@ class AuthBroker {
|
|
|
14290
14468
|
clientId: creds.googleOauth.clientId
|
|
14291
14469
|
};
|
|
14292
14470
|
}).filter((entry) => entry !== null).sort((a, b) => a.account.localeCompare(b.account));
|
|
14293
|
-
this.audit({ op: "list-google-accounts", identity: identity2, ok: true });
|
|
14471
|
+
this.audit({ op: "list-google-accounts", identity: identity2, accountKind: "google", ok: true });
|
|
14294
14472
|
socket.write(encodeSuccess(id, { accounts }));
|
|
14295
14473
|
}
|
|
14296
|
-
async opProbeQuota(socket, id, identity2, accounts, timeoutMs) {
|
|
14474
|
+
async opProbeQuota(socket, id, identity2, accounts, timeoutMs, forceLive) {
|
|
14475
|
+
const ttlMs = forceLive ? 0 : quotaProbeTtlMs();
|
|
14297
14476
|
const results = await Promise.all(accounts.map(async (label) => {
|
|
14477
|
+
const cached = this.lastQuotaCache[label];
|
|
14478
|
+
if (ttlMs > 0 && cached && this.now() - cached.capturedAt < ttlMs) {
|
|
14479
|
+
return { label, result: cachedSnapshotToResult(cached), served: "cache", capturedAt: cached.capturedAt };
|
|
14480
|
+
}
|
|
14298
14481
|
const creds = readAccountCredentials(label, this.home);
|
|
14299
14482
|
const token = creds?.claudeAiOauth?.accessToken;
|
|
14300
14483
|
if (!token) {
|
|
14484
|
+
if (cached) {
|
|
14485
|
+
return { label, result: cachedSnapshotToResult(cached), served: "cache", capturedAt: cached.capturedAt };
|
|
14486
|
+
}
|
|
14301
14487
|
const result2 = {
|
|
14302
14488
|
ok: false,
|
|
14303
14489
|
reason: "no credentials for account in broker store"
|
|
14304
14490
|
};
|
|
14305
|
-
this.audit({ op: "probe-quota", identity: identity2, account: label, ok: false, error: "missing-credentials" });
|
|
14491
|
+
this.audit({ op: "probe-quota", identity: identity2, account: label, accountKind: "claude", ok: false, error: "missing-credentials" });
|
|
14306
14492
|
return { label, result: result2 };
|
|
14307
14493
|
}
|
|
14308
|
-
const result = await this.
|
|
14494
|
+
const result = await this.probeQuotaSingleFlight(label, token, timeoutMs);
|
|
14309
14495
|
this.audit({
|
|
14310
14496
|
op: "probe-quota",
|
|
14311
14497
|
identity: identity2,
|
|
14312
14498
|
account: label,
|
|
14499
|
+
accountKind: "claude",
|
|
14313
14500
|
ok: result.ok,
|
|
14314
14501
|
error: result.ok ? undefined : result.reason
|
|
14315
14502
|
});
|
|
14316
|
-
if (result.ok)
|
|
14503
|
+
if (result.ok) {
|
|
14317
14504
|
this.cacheQuotaSnapshot(label, result);
|
|
14318
|
-
|
|
14505
|
+
return { label, result, served: "live" };
|
|
14506
|
+
}
|
|
14507
|
+
if (cached) {
|
|
14508
|
+
return { label, result: cachedSnapshotToResult(cached), served: "cache", capturedAt: cached.capturedAt };
|
|
14509
|
+
}
|
|
14510
|
+
return { label, result, served: "live" };
|
|
14319
14511
|
}));
|
|
14320
14512
|
socket.write(encodeSuccess(id, { results }));
|
|
14321
14513
|
}
|
|
14514
|
+
probeQuotaSingleFlight(label, token, timeoutMs) {
|
|
14515
|
+
const existing = this.probeInFlight.get(label);
|
|
14516
|
+
if (existing)
|
|
14517
|
+
return existing;
|
|
14518
|
+
const pending = this.fetchQuotaImpl({ accessToken: token, timeoutMs }).finally(() => {
|
|
14519
|
+
if (this.probeInFlight.get(label) === pending)
|
|
14520
|
+
this.probeInFlight.delete(label);
|
|
14521
|
+
});
|
|
14522
|
+
this.probeInFlight.set(label, pending);
|
|
14523
|
+
return pending;
|
|
14524
|
+
}
|
|
14322
14525
|
cacheQuotaSnapshot(label, result) {
|
|
14323
14526
|
if (!result.ok)
|
|
14324
14527
|
return;
|
|
@@ -14330,14 +14533,18 @@ class AuthBroker {
|
|
|
14330
14533
|
representativeClaim: result.data.representativeClaim,
|
|
14331
14534
|
overageStatus: result.data.overageStatus,
|
|
14332
14535
|
overageDisabledReason: result.data.overageDisabledReason,
|
|
14333
|
-
capturedAt: this.now()
|
|
14536
|
+
capturedAt: this.now(),
|
|
14537
|
+
fiveHourUtilPresent: result.data.fiveHourUtilPresent,
|
|
14538
|
+
sevenDayUtilPresent: result.data.sevenDayUtilPresent
|
|
14334
14539
|
};
|
|
14335
14540
|
this.lastQuotaCache[label] = snapshot;
|
|
14541
|
+
this.persistLastQuotaCache();
|
|
14336
14542
|
if (snapshotShouldClearMark(snapshot, this.quota[label], this.now())) {
|
|
14337
14543
|
delete this.quota[label];
|
|
14338
14544
|
this.persistQuota();
|
|
14339
14545
|
process.stdout.write(`auth-broker: live probe shows ${label} healthy (5h=${snapshot.fiveHourUtilizationPct}% 7d=${snapshot.sevenDayUtilizationPct}%) — cleared stale exhaustion mark
|
|
14340
14546
|
`);
|
|
14547
|
+
this.fanoutToAffectedConsumers(label);
|
|
14341
14548
|
}
|
|
14342
14549
|
}
|
|
14343
14550
|
async fleetQuotaProbeTick() {
|
|
@@ -14371,9 +14578,15 @@ class AuthBroker {
|
|
|
14371
14578
|
continue;
|
|
14372
14579
|
}
|
|
14373
14580
|
this.cacheQuotaSnapshot(label, result);
|
|
14374
|
-
const
|
|
14375
|
-
|
|
14581
|
+
const allowOverage = this.isOverageAllowed(label);
|
|
14582
|
+
const decision = quotaIndicatesExhaustion(result, allowOverage);
|
|
14583
|
+
if (!decision.exhausted) {
|
|
14584
|
+
if (result.ok && (result.data.fiveHourUtilizationPct >= EXHAUSTION_PCT || result.data.sevenDayUtilizationPct >= EXHAUSTION_PCT) && allowOverage) {
|
|
14585
|
+
process.stdout.write(`auth-broker: consumer-quota-sensor ${label} is wall-walled but serving via overage (allow_overage) — Anthropic overage billing is active
|
|
14586
|
+
`);
|
|
14587
|
+
}
|
|
14376
14588
|
continue;
|
|
14589
|
+
}
|
|
14377
14590
|
const now = this.now();
|
|
14378
14591
|
const exhaustedUntil = clampMarkExpiry({
|
|
14379
14592
|
proposedUntil: decision.until ?? now + MARK_EXHAUSTED_DEFAULT_MS,
|
|
@@ -14386,19 +14599,20 @@ class AuthBroker {
|
|
|
14386
14599
|
continue;
|
|
14387
14600
|
this.quota[label] = { exhausted_until: exhaustedUntil, marked_at: now };
|
|
14388
14601
|
this.persistQuota();
|
|
14389
|
-
this.audit({ op: "mark-exhausted", identity: { kind: "operator" }, account: label, ok: true });
|
|
14602
|
+
this.audit({ op: "mark-exhausted", identity: { kind: "operator" }, account: label, accountKind: "claude", ok: true });
|
|
14390
14603
|
process.stdout.write(`auth-broker: consumer-quota-sensor marked ${label} exhausted until ${new Date(exhaustedUntil).toISOString()} — consumer(s) fail over
|
|
14391
14604
|
`);
|
|
14605
|
+
this.fanoutToAffectedConsumers(label);
|
|
14392
14606
|
}
|
|
14393
14607
|
}
|
|
14394
14608
|
async opSetActive(socket, id, identity2, account) {
|
|
14395
14609
|
if (!this.isAdmin(identity2)) {
|
|
14396
|
-
this.audit({ op: "set-active", identity: identity2, account, ok: false, error: "FORBIDDEN" });
|
|
14610
|
+
this.audit({ op: "set-active", identity: identity2, account, accountKind: "claude", ok: false, error: "FORBIDDEN" });
|
|
14397
14611
|
this.respondForbidden(socket, id, "set-active requires admin");
|
|
14398
14612
|
return;
|
|
14399
14613
|
}
|
|
14400
14614
|
if (!accountExists(account, this.home)) {
|
|
14401
|
-
this.audit({ op: "set-active", identity: identity2, account, ok: false, error: "ACCOUNT_NOT_FOUND" });
|
|
14615
|
+
this.audit({ op: "set-active", identity: identity2, account, accountKind: "claude", ok: false, error: "ACCOUNT_NOT_FOUND" });
|
|
14402
14616
|
socket.write(encodeError(id, "ACCOUNT_NOT_FOUND", `account '${account}' not found`));
|
|
14403
14617
|
return;
|
|
14404
14618
|
}
|
|
@@ -14408,13 +14622,14 @@ class AuthBroker {
|
|
|
14408
14622
|
};
|
|
14409
14623
|
this.config = cfg;
|
|
14410
14624
|
const fanned = this.fanoutToAffectedAgents(account);
|
|
14411
|
-
this.
|
|
14625
|
+
this.fanoutAllConsumers();
|
|
14626
|
+
this.audit({ op: "set-active", identity: identity2, account, accountKind: "claude", ok: true });
|
|
14412
14627
|
socket.write(encodeSuccess(id, { active: account, fanned }));
|
|
14413
14628
|
}
|
|
14414
14629
|
async opMarkExhausted(socket, id, identity2, until) {
|
|
14415
14630
|
const account = this.callerAccount(identity2);
|
|
14416
14631
|
if (!account) {
|
|
14417
|
-
this.audit({ op: "mark-exhausted", identity: identity2, ok: false, error: "no-active-account" });
|
|
14632
|
+
this.audit({ op: "mark-exhausted", identity: identity2, accountKind: "claude", ok: false, error: "no-active-account" });
|
|
14418
14633
|
socket.write(encodeError(id, "ACCOUNT_NOT_FOUND", "no active account configured"));
|
|
14419
14634
|
return;
|
|
14420
14635
|
}
|
|
@@ -14427,9 +14642,10 @@ class AuthBroker {
|
|
|
14427
14642
|
});
|
|
14428
14643
|
this.quota[account] = { exhausted_until: exhaustedUntil, marked_at: now };
|
|
14429
14644
|
this.persistQuota();
|
|
14430
|
-
const
|
|
14431
|
-
const
|
|
14432
|
-
this.
|
|
14645
|
+
const rolledTo = await this.nextHealthyAccountLive(account, this.config.auth?.fallback_order ?? []);
|
|
14646
|
+
const rolled = this.fanoutFailoverTo(account, rolledTo);
|
|
14647
|
+
this.fanoutToAffectedConsumers(account);
|
|
14648
|
+
this.audit({ op: "mark-exhausted", identity: identity2, account, accountKind: "claude", ok: true });
|
|
14433
14649
|
socket.write(encodeSuccess(id, { account, rolled, rolledTo }));
|
|
14434
14650
|
}
|
|
14435
14651
|
opClaimNotification(socket, id, identity2, key, windowMs) {
|
|
@@ -14449,29 +14665,29 @@ class AuthBroker {
|
|
|
14449
14665
|
}
|
|
14450
14666
|
async opRefreshAccount(socket, id, identity2, account) {
|
|
14451
14667
|
if (!this.isAdmin(identity2)) {
|
|
14452
|
-
this.audit({ op: "refresh-account", identity: identity2, account, ok: false, error: "FORBIDDEN" });
|
|
14668
|
+
this.audit({ op: "refresh-account", identity: identity2, account, accountKind: "claude", ok: false, error: "FORBIDDEN" });
|
|
14453
14669
|
this.respondForbidden(socket, id, "refresh-account requires admin");
|
|
14454
14670
|
return;
|
|
14455
14671
|
}
|
|
14456
14672
|
if (!accountExists(account, this.home)) {
|
|
14457
|
-
this.audit({ op: "refresh-account", identity: identity2, account, ok: false, error: "ACCOUNT_NOT_FOUND" });
|
|
14673
|
+
this.audit({ op: "refresh-account", identity: identity2, account, accountKind: "claude", ok: false, error: "ACCOUNT_NOT_FOUND" });
|
|
14458
14674
|
socket.write(encodeError(id, "ACCOUNT_NOT_FOUND", `account '${account}' not found`));
|
|
14459
14675
|
return;
|
|
14460
14676
|
}
|
|
14461
14677
|
const result = await this.refreshOneAccount(account, true);
|
|
14462
14678
|
if (result.kind === "failed") {
|
|
14463
|
-
this.audit({ op: "refresh-account", identity: identity2, account, ok: false, error: result.error });
|
|
14679
|
+
this.audit({ op: "refresh-account", identity: identity2, account, accountKind: "claude", ok: false, error: result.error });
|
|
14464
14680
|
socket.write(encodeError(id, "REFRESH_FAILED", result.error));
|
|
14465
14681
|
return;
|
|
14466
14682
|
}
|
|
14467
14683
|
const creds = readAccountCredentials(account, this.home);
|
|
14468
14684
|
const expiresAt = creds?.claudeAiOauth?.expiresAt;
|
|
14469
|
-
this.audit({ op: "refresh-account", identity: identity2, account, ok: true });
|
|
14685
|
+
this.audit({ op: "refresh-account", identity: identity2, account, accountKind: "claude", ok: true });
|
|
14470
14686
|
socket.write(encodeSuccess(id, { account, expiresAt }));
|
|
14471
14687
|
}
|
|
14472
14688
|
async opAddAccount(socket, id, identity2, label, credentials, replace) {
|
|
14473
14689
|
if (!this.isAdmin(identity2)) {
|
|
14474
|
-
this.audit({ op: "add-account", identity: identity2, account: label, ok: false, error: "FORBIDDEN" });
|
|
14690
|
+
this.audit({ op: "add-account", identity: identity2, account: label, accountKind: "claude", ok: false, error: "FORBIDDEN" });
|
|
14475
14691
|
this.respondForbidden(socket, id, "add-account requires admin");
|
|
14476
14692
|
return;
|
|
14477
14693
|
}
|
|
@@ -14482,7 +14698,7 @@ class AuthBroker {
|
|
|
14482
14698
|
return;
|
|
14483
14699
|
}
|
|
14484
14700
|
if (accountExists(label, this.home) && !replace) {
|
|
14485
|
-
this.audit({ op: "add-account", identity: identity2, account: label, ok: false, error: "ACCOUNT_ALREADY_EXISTS" });
|
|
14701
|
+
this.audit({ op: "add-account", identity: identity2, account: label, accountKind: "claude", ok: false, error: "ACCOUNT_ALREADY_EXISTS" });
|
|
14486
14702
|
socket.write(encodeError(id, "ACCOUNT_ALREADY_EXISTS", `account '${label}' already exists; pass replace:true to overwrite`));
|
|
14487
14703
|
return;
|
|
14488
14704
|
}
|
|
@@ -14500,12 +14716,12 @@ class AuthBroker {
|
|
|
14500
14716
|
this.persistShaIndex();
|
|
14501
14717
|
this.fanoutToAffectedAgents(label);
|
|
14502
14718
|
const expiresAt = credentials.claudeAiOauth?.expiresAt;
|
|
14503
|
-
this.audit({ op: "add-account", identity: identity2, account: label, ok: true, replace });
|
|
14719
|
+
this.audit({ op: "add-account", identity: identity2, account: label, accountKind: "claude", ok: true, replace });
|
|
14504
14720
|
socket.write(encodeSuccess(id, { label, expiresAt }));
|
|
14505
14721
|
}
|
|
14506
14722
|
async opRmAccount(socket, id, identity2, label) {
|
|
14507
14723
|
if (!this.isAdmin(identity2)) {
|
|
14508
|
-
this.audit({ op: "rm-account", identity: identity2, account: label, ok: false, error: "FORBIDDEN" });
|
|
14724
|
+
this.audit({ op: "rm-account", identity: identity2, account: label, accountKind: "claude", ok: false, error: "FORBIDDEN" });
|
|
14509
14725
|
this.respondForbidden(socket, id, "rm-account requires admin");
|
|
14510
14726
|
return;
|
|
14511
14727
|
}
|
|
@@ -14533,10 +14749,12 @@ class AuthBroker {
|
|
|
14533
14749
|
delete this.quota[label];
|
|
14534
14750
|
delete this.thresholdViolations[label];
|
|
14535
14751
|
this.lastWrittenExpiresAt.delete(label);
|
|
14752
|
+
delete this.lastQuotaCache[label];
|
|
14536
14753
|
this.persistShaIndex();
|
|
14537
14754
|
this.persistQuota();
|
|
14538
14755
|
this.persistThresholdViolations();
|
|
14539
|
-
this.
|
|
14756
|
+
this.persistLastQuotaCache();
|
|
14757
|
+
this.audit({ op: "rm-account", identity: identity2, account: label, accountKind: "claude", ok: true });
|
|
14540
14758
|
socket.write(encodeSuccess(id, { label }));
|
|
14541
14759
|
}
|
|
14542
14760
|
async opGoogleGetCredentials(socket, id, identity2) {
|
|
@@ -14548,30 +14766,30 @@ class AuthBroker {
|
|
|
14548
14766
|
const agent = (this.config.agents ?? {})[agentName];
|
|
14549
14767
|
const account = agent?.google_workspace?.account;
|
|
14550
14768
|
if (!account) {
|
|
14551
|
-
this.audit({ op: "get-credentials", identity: identity2, ok: false, error: "no-google-account-configured" });
|
|
14769
|
+
this.audit({ op: "get-credentials", identity: identity2, accountKind: "google", ok: false, error: "no-google-account-configured" });
|
|
14552
14770
|
socket.write(encodeError(id, "ACCOUNT_NOT_FOUND", `agent '${agentName}' has no google_workspace.account configured in switchroom.yaml`));
|
|
14553
14771
|
return;
|
|
14554
14772
|
}
|
|
14555
14773
|
const ga = this.config.google_accounts;
|
|
14556
14774
|
const enabledFor = ga?.[account]?.enabled_for ?? [];
|
|
14557
14775
|
if (!enabledFor.includes(agentName)) {
|
|
14558
|
-
this.audit({ op: "get-credentials", identity: identity2, account, ok: false, error: "acl-deny" });
|
|
14776
|
+
this.audit({ op: "get-credentials", identity: identity2, account, accountKind: "google", ok: false, error: "acl-deny" });
|
|
14559
14777
|
socket.write(encodeError(id, "FORBIDDEN", `agent '${agentName}' not in google_accounts['${account}'].enabled_for[] — operator must run \`switchroom auth google enable ${account} ${agentName}\``));
|
|
14560
14778
|
return;
|
|
14561
14779
|
}
|
|
14562
14780
|
const creds = readGoogleAccountCredentials(this.stateDir, account);
|
|
14563
14781
|
if (!creds) {
|
|
14564
|
-
this.audit({ op: "get-credentials", identity: identity2, account, ok: false, error: "missing-credentials" });
|
|
14782
|
+
this.audit({ op: "get-credentials", identity: identity2, account, accountKind: "google", ok: false, error: "missing-credentials" });
|
|
14565
14783
|
socket.write(encodeError(id, "ACCOUNT_NOT_FOUND", `no Google credentials for account '${account}' — operator must run \`switchroom auth google account add ${account}\``));
|
|
14566
14784
|
return;
|
|
14567
14785
|
}
|
|
14568
14786
|
const expiresAt = creds.googleOauth?.expiresAt;
|
|
14569
|
-
this.audit({ op: "get-credentials", identity: identity2, account, ok: true });
|
|
14787
|
+
this.audit({ op: "get-credentials", identity: identity2, account, accountKind: "google", ok: true });
|
|
14570
14788
|
socket.write(encodeSuccess(id, { account, credentials: creds, expiresAt }));
|
|
14571
14789
|
}
|
|
14572
14790
|
async opGoogleAddAccount(socket, id, identity2, label, credentials, replace) {
|
|
14573
14791
|
if (!this.isAdmin(identity2)) {
|
|
14574
|
-
this.audit({ op: "add-account", identity: identity2, account: label, ok: false, error: "FORBIDDEN" });
|
|
14792
|
+
this.audit({ op: "add-account", identity: identity2, account: label, accountKind: "google", ok: false, error: "FORBIDDEN" });
|
|
14575
14793
|
this.respondForbidden(socket, id, "add-account requires admin");
|
|
14576
14794
|
return;
|
|
14577
14795
|
}
|
|
@@ -14582,7 +14800,7 @@ class AuthBroker {
|
|
|
14582
14800
|
return;
|
|
14583
14801
|
}
|
|
14584
14802
|
if (googleAccountExists(this.stateDir, label) && !replace) {
|
|
14585
|
-
this.audit({ op: "add-account", identity: identity2, account: label, ok: false, error: "ACCOUNT_ALREADY_EXISTS" });
|
|
14803
|
+
this.audit({ op: "add-account", identity: identity2, account: label, accountKind: "google", ok: false, error: "ACCOUNT_ALREADY_EXISTS" });
|
|
14586
14804
|
socket.write(encodeError(id, "ACCOUNT_ALREADY_EXISTS", `google account '${label}' already exists; pass replace:true to overwrite`));
|
|
14587
14805
|
return;
|
|
14588
14806
|
}
|
|
@@ -14593,12 +14811,12 @@ class AuthBroker {
|
|
|
14593
14811
|
return;
|
|
14594
14812
|
}
|
|
14595
14813
|
const expiresAt = credentials.googleOauth?.expiresAt;
|
|
14596
|
-
this.audit({ op: "add-account", identity: identity2, account: label, ok: true, replace });
|
|
14814
|
+
this.audit({ op: "add-account", identity: identity2, account: label, accountKind: "google", ok: true, replace });
|
|
14597
14815
|
socket.write(encodeSuccess(id, { label, expiresAt }));
|
|
14598
14816
|
}
|
|
14599
14817
|
async opGoogleRmAccount(socket, id, identity2, label) {
|
|
14600
14818
|
if (!this.isAdmin(identity2)) {
|
|
14601
|
-
this.audit({ op: "rm-account", identity: identity2, account: label, ok: false, error: "FORBIDDEN" });
|
|
14819
|
+
this.audit({ op: "rm-account", identity: identity2, account: label, accountKind: "google", ok: false, error: "FORBIDDEN" });
|
|
14602
14820
|
this.respondForbidden(socket, id, "rm-account requires admin");
|
|
14603
14821
|
return;
|
|
14604
14822
|
}
|
|
@@ -14624,7 +14842,7 @@ class AuthBroker {
|
|
|
14624
14842
|
socket.write(encodeError(id, "INTERNAL", err.message));
|
|
14625
14843
|
return;
|
|
14626
14844
|
}
|
|
14627
|
-
this.audit({ op: "rm-account", identity: identity2, account: label, ok: true });
|
|
14845
|
+
this.audit({ op: "rm-account", identity: identity2, account: label, accountKind: "google", ok: true });
|
|
14628
14846
|
socket.write(encodeSuccess(id, { label }));
|
|
14629
14847
|
}
|
|
14630
14848
|
async opMicrosoftGetCredentials(socket, id, identity2) {
|
|
@@ -14636,30 +14854,30 @@ class AuthBroker {
|
|
|
14636
14854
|
const agent = (this.config.agents ?? {})[agentName];
|
|
14637
14855
|
const account = agent?.microsoft_workspace?.account;
|
|
14638
14856
|
if (!account) {
|
|
14639
|
-
this.audit({ op: "get-credentials", identity: identity2, ok: false, error: "no-microsoft-account-configured" });
|
|
14857
|
+
this.audit({ op: "get-credentials", identity: identity2, accountKind: "microsoft", ok: false, error: "no-microsoft-account-configured" });
|
|
14640
14858
|
socket.write(encodeError(id, "ACCOUNT_NOT_FOUND", `agent '${agentName}' has no microsoft_workspace.account configured in switchroom.yaml`));
|
|
14641
14859
|
return;
|
|
14642
14860
|
}
|
|
14643
14861
|
const ma = this.config.microsoft_accounts;
|
|
14644
14862
|
const enabledFor = ma?.[account]?.enabled_for ?? [];
|
|
14645
14863
|
if (!enabledFor.includes(agentName)) {
|
|
14646
|
-
this.audit({ op: "get-credentials", identity: identity2, account, ok: false, error: "acl-deny" });
|
|
14864
|
+
this.audit({ op: "get-credentials", identity: identity2, account, accountKind: "microsoft", ok: false, error: "acl-deny" });
|
|
14647
14865
|
socket.write(encodeError(id, "FORBIDDEN", `agent '${agentName}' not in microsoft_accounts['${account}'].enabled_for[] — operator must run \`switchroom auth microsoft enable ${account} ${agentName}\``));
|
|
14648
14866
|
return;
|
|
14649
14867
|
}
|
|
14650
14868
|
const creds = readMicrosoftAccountCredentials(this.stateDir, account);
|
|
14651
14869
|
if (!creds) {
|
|
14652
|
-
this.audit({ op: "get-credentials", identity: identity2, account, ok: false, error: "missing-credentials" });
|
|
14870
|
+
this.audit({ op: "get-credentials", identity: identity2, account, accountKind: "microsoft", ok: false, error: "missing-credentials" });
|
|
14653
14871
|
socket.write(encodeError(id, "ACCOUNT_NOT_FOUND", `no Microsoft credentials for account '${account}' — operator must run \`switchroom auth microsoft account add ${account}\``));
|
|
14654
14872
|
return;
|
|
14655
14873
|
}
|
|
14656
14874
|
const expiresAt = creds.microsoftOauth?.expiresAt;
|
|
14657
|
-
this.audit({ op: "get-credentials", identity: identity2, account, ok: true });
|
|
14875
|
+
this.audit({ op: "get-credentials", identity: identity2, account, accountKind: "microsoft", ok: true });
|
|
14658
14876
|
socket.write(encodeSuccess(id, { account, credentials: creds, expiresAt }));
|
|
14659
14877
|
}
|
|
14660
14878
|
async opMicrosoftAddAccount(socket, id, identity2, label, credentials, replace) {
|
|
14661
14879
|
if (!this.isAdmin(identity2)) {
|
|
14662
|
-
this.audit({ op: "add-account", identity: identity2, account: label, ok: false, error: "FORBIDDEN" });
|
|
14880
|
+
this.audit({ op: "add-account", identity: identity2, account: label, accountKind: "microsoft", ok: false, error: "FORBIDDEN" });
|
|
14663
14881
|
this.respondForbidden(socket, id, "add-account requires admin");
|
|
14664
14882
|
return;
|
|
14665
14883
|
}
|
|
@@ -14670,7 +14888,7 @@ class AuthBroker {
|
|
|
14670
14888
|
return;
|
|
14671
14889
|
}
|
|
14672
14890
|
if (microsoftAccountExists(this.stateDir, label) && !replace) {
|
|
14673
|
-
this.audit({ op: "add-account", identity: identity2, account: label, ok: false, error: "ACCOUNT_ALREADY_EXISTS" });
|
|
14891
|
+
this.audit({ op: "add-account", identity: identity2, account: label, accountKind: "microsoft", ok: false, error: "ACCOUNT_ALREADY_EXISTS" });
|
|
14674
14892
|
socket.write(encodeError(id, "ACCOUNT_ALREADY_EXISTS", `microsoft account '${label}' already exists; pass replace:true to overwrite`));
|
|
14675
14893
|
return;
|
|
14676
14894
|
}
|
|
@@ -14681,12 +14899,12 @@ class AuthBroker {
|
|
|
14681
14899
|
return;
|
|
14682
14900
|
}
|
|
14683
14901
|
const expiresAt = credentials.microsoftOauth?.expiresAt;
|
|
14684
|
-
this.audit({ op: "add-account", identity: identity2, account: label, ok: true, replace });
|
|
14902
|
+
this.audit({ op: "add-account", identity: identity2, account: label, accountKind: "microsoft", ok: true, replace });
|
|
14685
14903
|
socket.write(encodeSuccess(id, { label, expiresAt }));
|
|
14686
14904
|
}
|
|
14687
14905
|
async opMicrosoftRmAccount(socket, id, identity2, label) {
|
|
14688
14906
|
if (!this.isAdmin(identity2)) {
|
|
14689
|
-
this.audit({ op: "rm-account", identity: identity2, account: label, ok: false, error: "FORBIDDEN" });
|
|
14907
|
+
this.audit({ op: "rm-account", identity: identity2, account: label, accountKind: "microsoft", ok: false, error: "FORBIDDEN" });
|
|
14690
14908
|
this.respondForbidden(socket, id, "rm-account requires admin");
|
|
14691
14909
|
return;
|
|
14692
14910
|
}
|
|
@@ -14712,7 +14930,7 @@ class AuthBroker {
|
|
|
14712
14930
|
socket.write(encodeError(id, "INTERNAL", err.message));
|
|
14713
14931
|
return;
|
|
14714
14932
|
}
|
|
14715
|
-
this.audit({ op: "rm-account", identity: identity2, account: label, ok: true });
|
|
14933
|
+
this.audit({ op: "rm-account", identity: identity2, account: label, accountKind: "microsoft", ok: true });
|
|
14716
14934
|
socket.write(encodeSuccess(id, { label }));
|
|
14717
14935
|
}
|
|
14718
14936
|
async opListMicrosoftAccounts(socket, id, identity2) {
|
|
@@ -14728,12 +14946,12 @@ class AuthBroker {
|
|
|
14728
14946
|
accountType: creds.microsoftOauth.accountType
|
|
14729
14947
|
};
|
|
14730
14948
|
}).filter((entry) => entry !== null).sort((a, b) => a.account.localeCompare(b.account));
|
|
14731
|
-
this.audit({ op: "list-microsoft-accounts", identity: identity2, ok: true });
|
|
14949
|
+
this.audit({ op: "list-microsoft-accounts", identity: identity2, accountKind: "microsoft", ok: true });
|
|
14732
14950
|
socket.write(encodeSuccess(id, { accounts }));
|
|
14733
14951
|
}
|
|
14734
14952
|
async opSetOverride(socket, id, identity2, agentName, account) {
|
|
14735
14953
|
if (!this.isAdmin(identity2)) {
|
|
14736
|
-
this.audit({ op: "set-override", identity: identity2, account: account ?? undefined, ok: false, error: "FORBIDDEN" });
|
|
14954
|
+
this.audit({ op: "set-override", identity: identity2, account: account ?? undefined, accountKind: "claude", ok: false, error: "FORBIDDEN" });
|
|
14737
14955
|
this.respondForbidden(socket, id, "set-override requires admin");
|
|
14738
14956
|
return;
|
|
14739
14957
|
}
|
|
@@ -14755,7 +14973,7 @@ class AuthBroker {
|
|
|
14755
14973
|
agents[agentName] = { ...cur, auth };
|
|
14756
14974
|
this.config = { ...this.config, agents };
|
|
14757
14975
|
this.fanoutForAgent(agentName);
|
|
14758
|
-
this.audit({ op: "set-override", identity: identity2, account: account ?? undefined, ok: true });
|
|
14976
|
+
this.audit({ op: "set-override", identity: identity2, account: account ?? undefined, accountKind: "claude", ok: true });
|
|
14759
14977
|
socket.write(encodeSuccess(id, { agent: agentName, account }));
|
|
14760
14978
|
}
|
|
14761
14979
|
async refreshTick() {
|
|
@@ -14892,6 +15110,7 @@ class AuthBroker {
|
|
|
14892
15110
|
this.shaIndex[label] = sha256Hex(contents);
|
|
14893
15111
|
this.persistShaIndex();
|
|
14894
15112
|
this.fanoutToAffectedAgents(label);
|
|
15113
|
+
this.fanoutToAffectedConsumers(label);
|
|
14895
15114
|
return { kind: "refreshed", newExpiresAt };
|
|
14896
15115
|
}
|
|
14897
15116
|
if (outcome.kind === "failed") {
|
|
@@ -14913,6 +15132,9 @@ class AuthBroker {
|
|
|
14913
15132
|
if (this.fanoutForAgent(name))
|
|
14914
15133
|
out.push(name);
|
|
14915
15134
|
}
|
|
15135
|
+
for (const consumerName of this.fanoutAllConsumers()) {
|
|
15136
|
+
out.push(`consumer:${consumerName}`);
|
|
15137
|
+
}
|
|
14916
15138
|
return out;
|
|
14917
15139
|
}
|
|
14918
15140
|
fanoutToAffectedAgents(label) {
|
|
@@ -14927,10 +15149,68 @@ class AuthBroker {
|
|
|
14927
15149
|
}
|
|
14928
15150
|
return fanned;
|
|
14929
15151
|
}
|
|
14930
|
-
|
|
15152
|
+
fanoutToAffectedConsumers(label) {
|
|
15153
|
+
const fanned = [];
|
|
15154
|
+
for (const consumer of this.config.auth?.consumers ?? []) {
|
|
15155
|
+
if (!consumer.mirror_dir)
|
|
15156
|
+
continue;
|
|
15157
|
+
const isPinned = consumer.account === label;
|
|
15158
|
+
const effective = this.servingAccountForConsumer(consumer.name);
|
|
15159
|
+
const isEffective = effective === label;
|
|
15160
|
+
if (!isPinned && !isEffective)
|
|
15161
|
+
continue;
|
|
15162
|
+
const toMirror = effective ?? consumer.account;
|
|
15163
|
+
if (this.mirrorAccountToConsumer(toMirror, consumer)) {
|
|
15164
|
+
fanned.push(consumer.name);
|
|
15165
|
+
}
|
|
15166
|
+
}
|
|
15167
|
+
return fanned;
|
|
15168
|
+
}
|
|
15169
|
+
fanoutAllConsumers() {
|
|
15170
|
+
const out = [];
|
|
15171
|
+
for (const consumer of this.config.auth?.consumers ?? []) {
|
|
15172
|
+
if (!consumer.mirror_dir)
|
|
15173
|
+
continue;
|
|
15174
|
+
const effective = this.servingAccountForConsumer(consumer.name);
|
|
15175
|
+
if (!effective)
|
|
15176
|
+
continue;
|
|
15177
|
+
if (this.mirrorAccountToConsumer(effective, consumer))
|
|
15178
|
+
out.push(consumer.name);
|
|
15179
|
+
}
|
|
15180
|
+
return out;
|
|
15181
|
+
}
|
|
15182
|
+
servingAccountForConsumer(name) {
|
|
15183
|
+
const c = (this.config.auth?.consumers ?? []).find((x) => x.name === name);
|
|
15184
|
+
if (!c)
|
|
15185
|
+
return null;
|
|
15186
|
+
return this.accountWithFailover(c.account);
|
|
15187
|
+
}
|
|
15188
|
+
mirrorAccountToConsumer(label, consumer) {
|
|
15189
|
+
const mirrorDir = consumer.mirror_dir;
|
|
15190
|
+
if (!mirrorDir)
|
|
15191
|
+
return false;
|
|
15192
|
+
const targetPath = join4(mirrorDir, ".credentials.json");
|
|
15193
|
+
const credsPath = accountCredentialsPath(label, this.home);
|
|
15194
|
+
if (!existsSync7(credsPath))
|
|
15195
|
+
return false;
|
|
15196
|
+
const mirrorContent = enrichMirrorContent(readFileSync6(credsPath, "utf-8"));
|
|
15197
|
+
try {
|
|
15198
|
+
mkdirSync4(mirrorDir, { recursive: true, mode: 448 });
|
|
15199
|
+
atomicWriteFileSync(targetPath, mirrorContent, 384);
|
|
15200
|
+
try {
|
|
15201
|
+
const uid = consumer.uid ?? 0;
|
|
15202
|
+
chownSync2(targetPath, uid, uid);
|
|
15203
|
+
} catch (err) {
|
|
15204
|
+
this.warnCapChownMissing(err);
|
|
15205
|
+
}
|
|
15206
|
+
return true;
|
|
15207
|
+
} catch (err) {
|
|
15208
|
+
this.logErr(`consumer-mirror ${consumer.name} <- ${label}: ${err.message}`);
|
|
15209
|
+
return false;
|
|
15210
|
+
}
|
|
15211
|
+
}
|
|
15212
|
+
fanoutFailoverTo(label, next) {
|
|
14931
15213
|
const auth = this.config.auth ?? {};
|
|
14932
|
-
const order = auth.fallback_order ?? [];
|
|
14933
|
-
const next = this.nextHealthyAccount(label, order);
|
|
14934
15214
|
if (!next || next === label)
|
|
14935
15215
|
return [];
|
|
14936
15216
|
const rolled = [];
|
|
@@ -15048,6 +15328,7 @@ class AuthBroker {
|
|
|
15048
15328
|
this.shaIndex = this.readJson("sha-index.json") ?? {};
|
|
15049
15329
|
this.thresholdViolations = this.readJson("threshold-violations.json") ?? {};
|
|
15050
15330
|
this.notificationClaims = this.readJson("notification-claims.json") ?? {};
|
|
15331
|
+
this.lastQuotaCache = this.readJson("last-quota.json") ?? {};
|
|
15051
15332
|
}
|
|
15052
15333
|
readJson(name) {
|
|
15053
15334
|
const p = join4(this.stateDir, name);
|
|
@@ -15062,6 +15343,9 @@ class AuthBroker {
|
|
|
15062
15343
|
persistQuota() {
|
|
15063
15344
|
atomicWriteJsonSync(join4(this.stateDir, "quota.json"), this.quota, 384);
|
|
15064
15345
|
}
|
|
15346
|
+
persistLastQuotaCache() {
|
|
15347
|
+
atomicWriteJsonSync(join4(this.stateDir, "last-quota.json"), this.lastQuotaCache, 384);
|
|
15348
|
+
}
|
|
15065
15349
|
persistNotificationClaims() {
|
|
15066
15350
|
atomicWriteJsonSync(join4(this.stateDir, "notification-claims.json"), this.notificationClaims, 384);
|
|
15067
15351
|
}
|
|
@@ -15098,6 +15382,7 @@ class AuthBroker {
|
|
|
15098
15382
|
op: entry.op,
|
|
15099
15383
|
peer,
|
|
15100
15384
|
account: entry.account,
|
|
15385
|
+
accountKind: entry.accountKind,
|
|
15101
15386
|
ok: entry.ok,
|
|
15102
15387
|
error: entry.error,
|
|
15103
15388
|
replace: entry.replace
|
|
@@ -15188,7 +15473,8 @@ class AuthBroker {
|
|
|
15188
15473
|
quota: { ...this.quota },
|
|
15189
15474
|
shaIndex: { ...this.shaIndex },
|
|
15190
15475
|
thresholdViolations: { ...this.thresholdViolations },
|
|
15191
|
-
listeners: [...this.listeners.keys()]
|
|
15476
|
+
listeners: [...this.listeners.keys()],
|
|
15477
|
+
lastQuotaCache: structuredClone(this.lastQuotaCache)
|
|
15192
15478
|
};
|
|
15193
15479
|
}
|
|
15194
15480
|
_fanoutAll() {
|