switchroom 0.14.37 → 0.14.39
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 +6 -8
- package/dist/auth-broker/index.js +6 -8
- package/dist/cli/notion-write-pretool.mjs +6 -8
- package/dist/cli/switchroom.js +82 -52
- package/dist/host-control/main.js +6 -8
- package/dist/vault/approvals/kernel-server.js +6 -8
- package/dist/vault/broker/server.js +6 -8
- package/package.json +3 -3
- package/telegram-plugin/dist/gateway/gateway.js +10 -12
- package/telegram-plugin/hooks/subagent-tracker-posttool.mjs +41 -6
- package/telegram-plugin/hooks/subagent-tracker-pretool.mjs +82 -11
- package/telegram-plugin/registry/subagents-bugs.test.ts +120 -19
- package/telegram-plugin/tests/subagent-tracker-hooks.test.ts +111 -0
- package/telegram-plugin/tests/subagent-watcher-parent-turn-key.test.ts +50 -0
|
@@ -11101,18 +11101,11 @@ var TelegramChannelSchema = exports_external.object({
|
|
|
11101
11101
|
webhook_via_gateway: exports_external.boolean().optional().describe("Route verified webhook events to the agent's in-container gateway " + "over a peercred-gated UDS (<agent>/telegram/webhook.sock) instead " + "of having the host-side web receiver write the agent dir directly. " + "Required under the Docker runtime: the receiver runs as the host " + "operator UID and cannot write the per-agent-UID-owned agent dir " + "(EACCES 500) nor connect the gateway socket. When true the gateway " + "(running as the agent UID) becomes the sole writer of " + "webhook-events.jsonl + dedup/cooldown state and also fires " + "webhook_dispatch. Off by default for back-compat with host-runtime " + "installs. See docs/rfcs/webhook-via-gateway-socket.md."),
|
|
11102
11102
|
webhook_require_edge: exports_external.boolean().optional().describe("Cloudflare-only edge lock: require the X-Switchroom-Edge header " + "(injected by a Cloudflare Transform Rule on hooks.switchroom.ai) to " + "match the operator's edge secret at ~/.switchroom/webhook-edge-secret " + "before any HMAC verification; reject 403 otherwise. Proves the " + "request entered through our Cloudflare edge — the per-agent HMAC " + "alone can't (it proves body provenance, not network path). Stacks " + "on the GitHub-IP WAF + per-agent HMAC. Fail-closed: when required " + "but the secret file is missing/empty every request is rejected. Off " + "by default. See docs/rfcs/webhook-cloudflare-edge-lock.md."),
|
|
11103
11103
|
chat_id: exports_external.string().regex(/^-\d+$/, 'supergroup chat_id must be a negative integer as a string (e.g. "-1001234567890")').optional().describe("Per-agent supergroup ID — overrides fleet `telegram.forum_chat_id`. " + "When set, requires `default_topic_id`. Negative integer as string. " + "Forbidden when `dm_only: true`. See docs/rfcs/supergroup-mode.md."),
|
|
11104
|
-
default_topic_id: exports_external.number().int().positive().optional().describe("Forum topic ID this agent's automated outbounds default to when " + "no more-specific alias resolves.
|
|
11104
|
+
default_topic_id: exports_external.number().int().positive().optional().describe("Forum topic ID this agent's automated outbounds default to when " + "no more-specific alias resolves. Defaults to General (topic 1) when " + "`chat_id` is set and this is omitted — set it only to pin a different " + "fallback topic. " + "Telegram's General topic is `id=1` at MTProto but sends omit the " + "field — the outbound wrapper strips `message_thread_id === 1` " + "on send. Forbidden when `dm_only: true`."),
|
|
11105
11105
|
topic_aliases: exports_external.record(exports_external.string(), exports_external.number().int().positive()).optional().describe("Operator-friendly names for forum topic IDs (e.g. " + "`{ general: 1, planning: 17, cron: 23, admin: 31, alerts: 41 }`). " + "Referenced from per-cron `topic:` fields and the outbound router " + "for autonomous events (boot → alerts, hostd → admin, etc.). " + "Cascades per-key through defaults → profile → agent.")
|
|
11106
11106
|
}).optional().superRefine((tg, ctx) => {
|
|
11107
11107
|
if (!tg)
|
|
11108
11108
|
return;
|
|
11109
|
-
if (tg.chat_id != null && tg.default_topic_id == null) {
|
|
11110
|
-
ctx.addIssue({
|
|
11111
|
-
code: exports_external.ZodIssueCode.custom,
|
|
11112
|
-
message: "`channels.telegram.chat_id` requires `default_topic_id` — supergroup-mode agents need a fallback topic for unclassified outbounds.",
|
|
11113
|
-
path: ["default_topic_id"]
|
|
11114
|
-
});
|
|
11115
|
-
}
|
|
11116
11109
|
if (tg.default_topic_id != null && tg.chat_id == null) {
|
|
11117
11110
|
ctx.addIssue({
|
|
11118
11111
|
code: exports_external.ZodIssueCode.custom,
|
|
@@ -11127,6 +11120,11 @@ var TelegramChannelSchema = exports_external.object({
|
|
|
11127
11120
|
path: ["topic_aliases"]
|
|
11128
11121
|
});
|
|
11129
11122
|
}
|
|
11123
|
+
}).transform((tg) => {
|
|
11124
|
+
if (tg && tg.chat_id != null && tg.default_topic_id == null) {
|
|
11125
|
+
return { ...tg, default_topic_id: 1 };
|
|
11126
|
+
}
|
|
11127
|
+
return tg;
|
|
11130
11128
|
});
|
|
11131
11129
|
var ChannelsSchema = exports_external.object({
|
|
11132
11130
|
telegram: TelegramChannelSchema
|
|
@@ -11101,18 +11101,11 @@ var TelegramChannelSchema = exports_external.object({
|
|
|
11101
11101
|
webhook_via_gateway: exports_external.boolean().optional().describe("Route verified webhook events to the agent's in-container gateway " + "over a peercred-gated UDS (<agent>/telegram/webhook.sock) instead " + "of having the host-side web receiver write the agent dir directly. " + "Required under the Docker runtime: the receiver runs as the host " + "operator UID and cannot write the per-agent-UID-owned agent dir " + "(EACCES 500) nor connect the gateway socket. When true the gateway " + "(running as the agent UID) becomes the sole writer of " + "webhook-events.jsonl + dedup/cooldown state and also fires " + "webhook_dispatch. Off by default for back-compat with host-runtime " + "installs. See docs/rfcs/webhook-via-gateway-socket.md."),
|
|
11102
11102
|
webhook_require_edge: exports_external.boolean().optional().describe("Cloudflare-only edge lock: require the X-Switchroom-Edge header " + "(injected by a Cloudflare Transform Rule on hooks.switchroom.ai) to " + "match the operator's edge secret at ~/.switchroom/webhook-edge-secret " + "before any HMAC verification; reject 403 otherwise. Proves the " + "request entered through our Cloudflare edge — the per-agent HMAC " + "alone can't (it proves body provenance, not network path). Stacks " + "on the GitHub-IP WAF + per-agent HMAC. Fail-closed: when required " + "but the secret file is missing/empty every request is rejected. Off " + "by default. See docs/rfcs/webhook-cloudflare-edge-lock.md."),
|
|
11103
11103
|
chat_id: exports_external.string().regex(/^-\d+$/, 'supergroup chat_id must be a negative integer as a string (e.g. "-1001234567890")').optional().describe("Per-agent supergroup ID — overrides fleet `telegram.forum_chat_id`. " + "When set, requires `default_topic_id`. Negative integer as string. " + "Forbidden when `dm_only: true`. See docs/rfcs/supergroup-mode.md."),
|
|
11104
|
-
default_topic_id: exports_external.number().int().positive().optional().describe("Forum topic ID this agent's automated outbounds default to when " + "no more-specific alias resolves.
|
|
11104
|
+
default_topic_id: exports_external.number().int().positive().optional().describe("Forum topic ID this agent's automated outbounds default to when " + "no more-specific alias resolves. Defaults to General (topic 1) when " + "`chat_id` is set and this is omitted — set it only to pin a different " + "fallback topic. " + "Telegram's General topic is `id=1` at MTProto but sends omit the " + "field — the outbound wrapper strips `message_thread_id === 1` " + "on send. Forbidden when `dm_only: true`."),
|
|
11105
11105
|
topic_aliases: exports_external.record(exports_external.string(), exports_external.number().int().positive()).optional().describe("Operator-friendly names for forum topic IDs (e.g. " + "`{ general: 1, planning: 17, cron: 23, admin: 31, alerts: 41 }`). " + "Referenced from per-cron `topic:` fields and the outbound router " + "for autonomous events (boot → alerts, hostd → admin, etc.). " + "Cascades per-key through defaults → profile → agent.")
|
|
11106
11106
|
}).optional().superRefine((tg, ctx) => {
|
|
11107
11107
|
if (!tg)
|
|
11108
11108
|
return;
|
|
11109
|
-
if (tg.chat_id != null && tg.default_topic_id == null) {
|
|
11110
|
-
ctx.addIssue({
|
|
11111
|
-
code: exports_external.ZodIssueCode.custom,
|
|
11112
|
-
message: "`channels.telegram.chat_id` requires `default_topic_id` — supergroup-mode agents need a fallback topic for unclassified outbounds.",
|
|
11113
|
-
path: ["default_topic_id"]
|
|
11114
|
-
});
|
|
11115
|
-
}
|
|
11116
11109
|
if (tg.default_topic_id != null && tg.chat_id == null) {
|
|
11117
11110
|
ctx.addIssue({
|
|
11118
11111
|
code: exports_external.ZodIssueCode.custom,
|
|
@@ -11127,6 +11120,11 @@ var TelegramChannelSchema = exports_external.object({
|
|
|
11127
11120
|
path: ["topic_aliases"]
|
|
11128
11121
|
});
|
|
11129
11122
|
}
|
|
11123
|
+
}).transform((tg) => {
|
|
11124
|
+
if (tg && tg.chat_id != null && tg.default_topic_id == null) {
|
|
11125
|
+
return { ...tg, default_topic_id: 1 };
|
|
11126
|
+
}
|
|
11127
|
+
return tg;
|
|
11130
11128
|
});
|
|
11131
11129
|
var ChannelsSchema = exports_external.object({
|
|
11132
11130
|
telegram: TelegramChannelSchema
|
|
@@ -11849,18 +11849,11 @@ var TelegramChannelSchema = exports_external.object({
|
|
|
11849
11849
|
webhook_via_gateway: exports_external.boolean().optional().describe("Route verified webhook events to the agent's in-container gateway " + "over a peercred-gated UDS (<agent>/telegram/webhook.sock) instead " + "of having the host-side web receiver write the agent dir directly. " + "Required under the Docker runtime: the receiver runs as the host " + "operator UID and cannot write the per-agent-UID-owned agent dir " + "(EACCES 500) nor connect the gateway socket. When true the gateway " + "(running as the agent UID) becomes the sole writer of " + "webhook-events.jsonl + dedup/cooldown state and also fires " + "webhook_dispatch. Off by default for back-compat with host-runtime " + "installs. See docs/rfcs/webhook-via-gateway-socket.md."),
|
|
11850
11850
|
webhook_require_edge: exports_external.boolean().optional().describe("Cloudflare-only edge lock: require the X-Switchroom-Edge header " + "(injected by a Cloudflare Transform Rule on hooks.switchroom.ai) to " + "match the operator's edge secret at ~/.switchroom/webhook-edge-secret " + "before any HMAC verification; reject 403 otherwise. Proves the " + "request entered through our Cloudflare edge \u2014 the per-agent HMAC " + "alone can't (it proves body provenance, not network path). Stacks " + "on the GitHub-IP WAF + per-agent HMAC. Fail-closed: when required " + "but the secret file is missing/empty every request is rejected. Off " + "by default. See docs/rfcs/webhook-cloudflare-edge-lock.md."),
|
|
11851
11851
|
chat_id: exports_external.string().regex(/^-\d+$/, 'supergroup chat_id must be a negative integer as a string (e.g. "-1001234567890")').optional().describe("Per-agent supergroup ID \u2014 overrides fleet `telegram.forum_chat_id`. " + "When set, requires `default_topic_id`. Negative integer as string. " + "Forbidden when `dm_only: true`. See docs/rfcs/supergroup-mode.md."),
|
|
11852
|
-
default_topic_id: exports_external.number().int().positive().optional().describe("Forum topic ID this agent's automated outbounds default to when " + "no more-specific alias resolves.
|
|
11852
|
+
default_topic_id: exports_external.number().int().positive().optional().describe("Forum topic ID this agent's automated outbounds default to when " + "no more-specific alias resolves. Defaults to General (topic 1) when " + "`chat_id` is set and this is omitted \u2014 set it only to pin a different " + "fallback topic. " + "Telegram's General topic is `id=1` at MTProto but sends omit the " + "field \u2014 the outbound wrapper strips `message_thread_id === 1` " + "on send. Forbidden when `dm_only: true`."),
|
|
11853
11853
|
topic_aliases: exports_external.record(exports_external.string(), exports_external.number().int().positive()).optional().describe("Operator-friendly names for forum topic IDs (e.g. " + "`{ general: 1, planning: 17, cron: 23, admin: 31, alerts: 41 }`). " + "Referenced from per-cron `topic:` fields and the outbound router " + "for autonomous events (boot \u2192 alerts, hostd \u2192 admin, etc.). " + "Cascades per-key through defaults \u2192 profile \u2192 agent.")
|
|
11854
11854
|
}).optional().superRefine((tg, ctx) => {
|
|
11855
11855
|
if (!tg)
|
|
11856
11856
|
return;
|
|
11857
|
-
if (tg.chat_id != null && tg.default_topic_id == null) {
|
|
11858
|
-
ctx.addIssue({
|
|
11859
|
-
code: exports_external.ZodIssueCode.custom,
|
|
11860
|
-
message: "`channels.telegram.chat_id` requires `default_topic_id` \u2014 supergroup-mode agents need a fallback topic for unclassified outbounds.",
|
|
11861
|
-
path: ["default_topic_id"]
|
|
11862
|
-
});
|
|
11863
|
-
}
|
|
11864
11857
|
if (tg.default_topic_id != null && tg.chat_id == null) {
|
|
11865
11858
|
ctx.addIssue({
|
|
11866
11859
|
code: exports_external.ZodIssueCode.custom,
|
|
@@ -11875,6 +11868,11 @@ var TelegramChannelSchema = exports_external.object({
|
|
|
11875
11868
|
path: ["topic_aliases"]
|
|
11876
11869
|
});
|
|
11877
11870
|
}
|
|
11871
|
+
}).transform((tg) => {
|
|
11872
|
+
if (tg && tg.chat_id != null && tg.default_topic_id == null) {
|
|
11873
|
+
return { ...tg, default_topic_id: 1 };
|
|
11874
|
+
}
|
|
11875
|
+
return tg;
|
|
11878
11876
|
});
|
|
11879
11877
|
var ChannelsSchema = exports_external.object({
|
|
11880
11878
|
telegram: TelegramChannelSchema
|
package/dist/cli/switchroom.js
CHANGED
|
@@ -13665,18 +13665,11 @@ var init_schema = __esm(() => {
|
|
|
13665
13665
|
webhook_via_gateway: exports_external.boolean().optional().describe("Route verified webhook events to the agent's in-container gateway " + "over a peercred-gated UDS (<agent>/telegram/webhook.sock) instead " + "of having the host-side web receiver write the agent dir directly. " + "Required under the Docker runtime: the receiver runs as the host " + "operator UID and cannot write the per-agent-UID-owned agent dir " + "(EACCES 500) nor connect the gateway socket. When true the gateway " + "(running as the agent UID) becomes the sole writer of " + "webhook-events.jsonl + dedup/cooldown state and also fires " + "webhook_dispatch. Off by default for back-compat with host-runtime " + "installs. See docs/rfcs/webhook-via-gateway-socket.md."),
|
|
13666
13666
|
webhook_require_edge: exports_external.boolean().optional().describe("Cloudflare-only edge lock: require the X-Switchroom-Edge header " + "(injected by a Cloudflare Transform Rule on hooks.switchroom.ai) to " + "match the operator's edge secret at ~/.switchroom/webhook-edge-secret " + "before any HMAC verification; reject 403 otherwise. Proves the " + "request entered through our Cloudflare edge \u2014 the per-agent HMAC " + "alone can't (it proves body provenance, not network path). Stacks " + "on the GitHub-IP WAF + per-agent HMAC. Fail-closed: when required " + "but the secret file is missing/empty every request is rejected. Off " + "by default. See docs/rfcs/webhook-cloudflare-edge-lock.md."),
|
|
13667
13667
|
chat_id: exports_external.string().regex(/^-\d+$/, 'supergroup chat_id must be a negative integer as a string (e.g. "-1001234567890")').optional().describe("Per-agent supergroup ID \u2014 overrides fleet `telegram.forum_chat_id`. " + "When set, requires `default_topic_id`. Negative integer as string. " + "Forbidden when `dm_only: true`. See docs/rfcs/supergroup-mode.md."),
|
|
13668
|
-
default_topic_id: exports_external.number().int().positive().optional().describe("Forum topic ID this agent's automated outbounds default to when " + "no more-specific alias resolves.
|
|
13668
|
+
default_topic_id: exports_external.number().int().positive().optional().describe("Forum topic ID this agent's automated outbounds default to when " + "no more-specific alias resolves. Defaults to General (topic 1) when " + "`chat_id` is set and this is omitted \u2014 set it only to pin a different " + "fallback topic. " + "Telegram's General topic is `id=1` at MTProto but sends omit the " + "field \u2014 the outbound wrapper strips `message_thread_id === 1` " + "on send. Forbidden when `dm_only: true`."),
|
|
13669
13669
|
topic_aliases: exports_external.record(exports_external.string(), exports_external.number().int().positive()).optional().describe("Operator-friendly names for forum topic IDs (e.g. " + "`{ general: 1, planning: 17, cron: 23, admin: 31, alerts: 41 }`). " + "Referenced from per-cron `topic:` fields and the outbound router " + "for autonomous events (boot \u2192 alerts, hostd \u2192 admin, etc.). " + "Cascades per-key through defaults \u2192 profile \u2192 agent.")
|
|
13670
13670
|
}).optional().superRefine((tg, ctx) => {
|
|
13671
13671
|
if (!tg)
|
|
13672
13672
|
return;
|
|
13673
|
-
if (tg.chat_id != null && tg.default_topic_id == null) {
|
|
13674
|
-
ctx.addIssue({
|
|
13675
|
-
code: exports_external.ZodIssueCode.custom,
|
|
13676
|
-
message: "`channels.telegram.chat_id` requires `default_topic_id` \u2014 supergroup-mode agents need a fallback topic for unclassified outbounds.",
|
|
13677
|
-
path: ["default_topic_id"]
|
|
13678
|
-
});
|
|
13679
|
-
}
|
|
13680
13673
|
if (tg.default_topic_id != null && tg.chat_id == null) {
|
|
13681
13674
|
ctx.addIssue({
|
|
13682
13675
|
code: exports_external.ZodIssueCode.custom,
|
|
@@ -13691,6 +13684,11 @@ var init_schema = __esm(() => {
|
|
|
13691
13684
|
path: ["topic_aliases"]
|
|
13692
13685
|
});
|
|
13693
13686
|
}
|
|
13687
|
+
}).transform((tg) => {
|
|
13688
|
+
if (tg && tg.chat_id != null && tg.default_topic_id == null) {
|
|
13689
|
+
return { ...tg, default_topic_id: 1 };
|
|
13690
|
+
}
|
|
13691
|
+
return tg;
|
|
13694
13692
|
});
|
|
13695
13693
|
ChannelsSchema = exports_external.object({
|
|
13696
13694
|
telegram: TelegramChannelSchema
|
|
@@ -23654,7 +23652,7 @@ var init_docker_fleet = __esm(() => {
|
|
|
23654
23652
|
|
|
23655
23653
|
// src/agents/lifecycle.ts
|
|
23656
23654
|
import { execFileSync as execFileSync7, spawn, spawnSync } from "node:child_process";
|
|
23657
|
-
import { existsSync as existsSync15, mkdirSync as mkdirSync12, writeFileSync as writeFileSync7, renameSync as
|
|
23655
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync12, writeFileSync as writeFileSync7, renameSync as renameSync4, readFileSync as readFileSync13 } from "node:fs";
|
|
23658
23656
|
import { resolve as resolve13, join as join10 } from "node:path";
|
|
23659
23657
|
import { connect } from "node:net";
|
|
23660
23658
|
function cleanShutdownMarkerPathForAgent(name) {
|
|
@@ -23676,7 +23674,7 @@ function writeRestartReasonMarker(name, reason, opts = {}) {
|
|
|
23676
23674
|
const marker = { ts: Date.now(), signal: "SIGTERM", reason };
|
|
23677
23675
|
const tmp = `${path}.tmp-${process.pid}-${Date.now()}`;
|
|
23678
23676
|
writeFileSync7(tmp, JSON.stringify(marker), "utf-8");
|
|
23679
|
-
|
|
23677
|
+
renameSync4(tmp, path);
|
|
23680
23678
|
} catch {}
|
|
23681
23679
|
}
|
|
23682
23680
|
function buildCliRestartReason(opts) {
|
|
@@ -24154,7 +24152,7 @@ import {
|
|
|
24154
24152
|
mkdirSync as mkdirSync14,
|
|
24155
24153
|
readFileSync as readFileSync17,
|
|
24156
24154
|
readdirSync as readdirSync9,
|
|
24157
|
-
renameSync as
|
|
24155
|
+
renameSync as renameSync6,
|
|
24158
24156
|
rmSync as rmSync4,
|
|
24159
24157
|
statSync as statSync11,
|
|
24160
24158
|
writeFileSync as writeFileSync9
|
|
@@ -24296,7 +24294,7 @@ function atomicCopy(src, dest, mode) {
|
|
|
24296
24294
|
const tmp = `${dest}.tmp-${process.pid}-${randomBytes2(4).toString("hex")}`;
|
|
24297
24295
|
try {
|
|
24298
24296
|
writeFileSync9(tmp, contents, { mode });
|
|
24299
|
-
|
|
24297
|
+
renameSync6(tmp, dest);
|
|
24300
24298
|
} catch (err) {
|
|
24301
24299
|
try {
|
|
24302
24300
|
rmSync4(tmp);
|
|
@@ -25835,7 +25833,7 @@ import {
|
|
|
25835
25833
|
mkdirSync as mkdirSync17,
|
|
25836
25834
|
readFileSync as readFileSync22,
|
|
25837
25835
|
readdirSync as readdirSync14,
|
|
25838
|
-
renameSync as
|
|
25836
|
+
renameSync as renameSync7,
|
|
25839
25837
|
rmSync as rmSync10,
|
|
25840
25838
|
statSync as statSync15,
|
|
25841
25839
|
writeFileSync as writeFileSync14
|
|
@@ -25972,7 +25970,7 @@ __export(exports_atomic, {
|
|
|
25972
25970
|
atomicWriteFileSync: () => atomicWriteFileSync2
|
|
25973
25971
|
});
|
|
25974
25972
|
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
25975
|
-
import { closeSync as closeSync5, constants, fsyncSync as fsyncSync3, openSync as openSync5, renameSync as
|
|
25973
|
+
import { closeSync as closeSync5, constants, fsyncSync as fsyncSync3, openSync as openSync5, renameSync as renameSync8, rmSync as rmSync11, writeSync as writeSync3 } from "node:fs";
|
|
25976
25974
|
function atomicWriteFileSync2(destPath, contents, mode = 384) {
|
|
25977
25975
|
const tmp = `${destPath}.tmp-${process.pid}-${randomBytes3(4).toString("hex")}`;
|
|
25978
25976
|
const buf = typeof contents === "string" ? Buffer.from(contents, "utf-8") : contents;
|
|
@@ -25983,7 +25981,7 @@ function atomicWriteFileSync2(destPath, contents, mode = 384) {
|
|
|
25983
25981
|
fsyncSync3(fd);
|
|
25984
25982
|
closeSync5(fd);
|
|
25985
25983
|
fd = null;
|
|
25986
|
-
|
|
25984
|
+
renameSync8(tmp, destPath);
|
|
25987
25985
|
} catch (err) {
|
|
25988
25986
|
if (fd !== null) {
|
|
25989
25987
|
try {
|
|
@@ -49440,8 +49438,8 @@ var {
|
|
|
49440
49438
|
} = import__.default;
|
|
49441
49439
|
|
|
49442
49440
|
// src/build-info.ts
|
|
49443
|
-
var VERSION = "0.14.
|
|
49444
|
-
var COMMIT_SHA = "
|
|
49441
|
+
var VERSION = "0.14.39";
|
|
49442
|
+
var COMMIT_SHA = "fb30b654";
|
|
49445
49443
|
|
|
49446
49444
|
// src/cli/agent.ts
|
|
49447
49445
|
init_source();
|
|
@@ -49522,6 +49520,7 @@ import {
|
|
|
49522
49520
|
writeFileSync as writeFileSync5,
|
|
49523
49521
|
appendFileSync,
|
|
49524
49522
|
readFileSync as readFileSync11,
|
|
49523
|
+
renameSync as renameSync3,
|
|
49525
49524
|
chmodSync as chmodSync2,
|
|
49526
49525
|
symlinkSync as symlinkSync2,
|
|
49527
49526
|
copyFileSync as copyFileSync4,
|
|
@@ -51637,6 +51636,7 @@ This file is auto-maintained. Do not edit manually.
|
|
|
51637
51636
|
`;
|
|
51638
51637
|
}, created, skipped, 384);
|
|
51639
51638
|
writeIfMissing(join8(agentDir, "telegram", "access.json"), () => buildAccessJson2(agentConfig, telegramConfig, topicId, userId), created, skipped, 384);
|
|
51639
|
+
reconcileConfiguredGroup(join8(agentDir, "telegram", "access.json"), agentConfig, telegramConfig);
|
|
51640
51640
|
if (agentConfig.subagents) {
|
|
51641
51641
|
const agentsDir2 = join8(agentDir, ".claude", "agents");
|
|
51642
51642
|
mkdirSync9(agentsDir2, { recursive: true });
|
|
@@ -52760,6 +52760,36 @@ function rerenderWithFingerprint(filePath, contentFn, created, skipped, rewritte
|
|
|
52760
52760
|
rewrittenWithBackup.push(filePath);
|
|
52761
52761
|
created.push(filePath);
|
|
52762
52762
|
}
|
|
52763
|
+
function resolveAgentForumChatId(agentConfig, telegramConfig) {
|
|
52764
|
+
const override = agentConfig.channels?.telegram?.chat_id;
|
|
52765
|
+
if (typeof override === "string" && override.length > 0)
|
|
52766
|
+
return override;
|
|
52767
|
+
return telegramConfig.forum_chat_id ?? "";
|
|
52768
|
+
}
|
|
52769
|
+
function reconcileConfiguredGroup(accessPath, agentConfig, telegramConfig) {
|
|
52770
|
+
if (!existsSync13(accessPath))
|
|
52771
|
+
return;
|
|
52772
|
+
const forumChatId = resolveAgentForumChatId(agentConfig, telegramConfig);
|
|
52773
|
+
const hasRealForumChat = forumChatId !== "" && forumChatId !== "0";
|
|
52774
|
+
if (agentConfig.dm_only || !hasRealForumChat)
|
|
52775
|
+
return;
|
|
52776
|
+
let access;
|
|
52777
|
+
try {
|
|
52778
|
+
access = JSON.parse(readFileSync11(accessPath, "utf-8"));
|
|
52779
|
+
} catch {
|
|
52780
|
+
return;
|
|
52781
|
+
}
|
|
52782
|
+
const groups = access.groups ??= {};
|
|
52783
|
+
if (groups[forumChatId] !== undefined)
|
|
52784
|
+
return;
|
|
52785
|
+
const allowFrom = Array.isArray(access.allowFrom) ? access.allowFrom : [];
|
|
52786
|
+
groups[forumChatId] = { requireMention: false, allowFrom };
|
|
52787
|
+
const tmp = accessPath + ".tmp";
|
|
52788
|
+
writeFileSync5(tmp, JSON.stringify(access, null, 2) + `
|
|
52789
|
+
`, { mode: 384 });
|
|
52790
|
+
renameSync3(tmp, accessPath);
|
|
52791
|
+
console.log(source_default.green(` registered supergroup ${forumChatId} in access.json ` + `(responds to all topics; requireMention=false)`));
|
|
52792
|
+
}
|
|
52763
52793
|
function buildAccessJson2(agentConfig, telegramConfig, resolvedTopicId, userId) {
|
|
52764
52794
|
const allowFrom = userId ? [String(userId)] : [];
|
|
52765
52795
|
if (allowFrom.length === 0) {
|
|
@@ -52769,7 +52799,7 @@ function buildAccessJson2(agentConfig, telegramConfig, resolvedTopicId, userId)
|
|
|
52769
52799
|
dmPolicy: "allowlist",
|
|
52770
52800
|
allowFrom
|
|
52771
52801
|
};
|
|
52772
|
-
const forumChatId = telegramConfig
|
|
52802
|
+
const forumChatId = resolveAgentForumChatId(agentConfig, telegramConfig);
|
|
52773
52803
|
const hasRealForumChat = forumChatId !== "" && forumChatId !== "0";
|
|
52774
52804
|
if (!agentConfig.dm_only && hasRealForumChat) {
|
|
52775
52805
|
access.groups = {
|
|
@@ -53035,7 +53065,7 @@ import { join as join12 } from "node:path";
|
|
|
53035
53065
|
import { execFileSync as execFileSync8 } from "node:child_process";
|
|
53036
53066
|
|
|
53037
53067
|
// src/agents/handoff-summarizer.ts
|
|
53038
|
-
import { readFileSync as readFileSync14, writeFileSync as writeFileSync8, renameSync as
|
|
53068
|
+
import { readFileSync as readFileSync14, writeFileSync as writeFileSync8, renameSync as renameSync5, mkdirSync as mkdirSync13, existsSync as existsSync16, statSync as statSync9, readdirSync as readdirSync8 } from "node:fs";
|
|
53039
53069
|
import { join as join11 } from "node:path";
|
|
53040
53070
|
var DEFAULT_MAX_TURNS = 50;
|
|
53041
53071
|
var TOPIC_MAX_CHARS = 117;
|
|
@@ -53177,8 +53207,8 @@ function writeSidecarsAtomic(agentDir, briefing, topic) {
|
|
|
53177
53207
|
const topicTmp = topicPath + ".tmp";
|
|
53178
53208
|
writeFileSync8(handoffTmp, briefing, "utf-8");
|
|
53179
53209
|
writeFileSync8(topicTmp, topic, "utf-8");
|
|
53180
|
-
|
|
53181
|
-
|
|
53210
|
+
renameSync5(handoffTmp, handoffPath);
|
|
53211
|
+
renameSync5(topicTmp, topicPath);
|
|
53182
53212
|
}
|
|
53183
53213
|
async function buildHandoff(opts) {
|
|
53184
53214
|
const maxTurns = opts.maxTurns ?? DEFAULT_MAX_TURNS;
|
|
@@ -59057,7 +59087,7 @@ import { spawn as spawn4 } from "node:child_process";
|
|
|
59057
59087
|
init_compose();
|
|
59058
59088
|
init_vault();
|
|
59059
59089
|
import * as net3 from "node:net";
|
|
59060
|
-
import { mkdirSync as mkdirSync22, chmodSync as chmodSync7, chownSync as chownSync2, existsSync as existsSync35, readFileSync as readFileSync30, readdirSync as readdirSync16, statSync as statSync19, unlinkSync as unlinkSync8, writeFileSync as writeFileSync19, renameSync as
|
|
59090
|
+
import { mkdirSync as mkdirSync22, chmodSync as chmodSync7, chownSync as chownSync2, existsSync as existsSync35, readFileSync as readFileSync30, readdirSync as readdirSync16, statSync as statSync19, unlinkSync as unlinkSync8, writeFileSync as writeFileSync19, renameSync as renameSync10 } from "node:fs";
|
|
59061
59091
|
import { dirname as dirname6, resolve as resolve26, basename as basename4 } from "node:path";
|
|
59062
59092
|
import * as os4 from "node:os";
|
|
59063
59093
|
import * as path3 from "node:path";
|
|
@@ -59074,7 +59104,7 @@ import {
|
|
|
59074
59104
|
openSync as openSync6,
|
|
59075
59105
|
closeSync as closeSync6,
|
|
59076
59106
|
readFileSync as readFileSync28,
|
|
59077
|
-
renameSync as
|
|
59107
|
+
renameSync as renameSync9,
|
|
59078
59108
|
statSync as statSync18,
|
|
59079
59109
|
symlinkSync as symlinkSync3,
|
|
59080
59110
|
unlinkSync as unlinkSync7
|
|
@@ -59151,7 +59181,7 @@ function runMigration(home2, opts) {
|
|
|
59151
59181
|
copyFileSync7(oldPath, tempNew);
|
|
59152
59182
|
chmodSync4(tempNew, 384);
|
|
59153
59183
|
fsyncFile(tempNew);
|
|
59154
|
-
|
|
59184
|
+
renameSync9(tempNew, newPath);
|
|
59155
59185
|
fsyncDir(parent);
|
|
59156
59186
|
atomicReplaceWithSymlink(oldPath, "vault/vault.enc");
|
|
59157
59187
|
fsyncDir(switchroomRoot);
|
|
@@ -59240,7 +59270,7 @@ function atomicReplaceWithSymlink(target, linkTarget) {
|
|
|
59240
59270
|
} catch {}
|
|
59241
59271
|
}
|
|
59242
59272
|
symlinkSync3(linkTarget, tmp);
|
|
59243
|
-
|
|
59273
|
+
renameSync9(tmp, target);
|
|
59244
59274
|
}
|
|
59245
59275
|
function fsyncFile(path) {
|
|
59246
59276
|
const fd = openSync6(path, "r+");
|
|
@@ -62880,7 +62910,7 @@ class VaultBroker {
|
|
|
62880
62910
|
const tokenPath = path3.join(tokenDir, ".vault-token");
|
|
62881
62911
|
const tmpPath = `${tokenPath}.tmp.${process.pid}`;
|
|
62882
62912
|
writeFileSync19(tmpPath, mintResult.token, { mode: 384 });
|
|
62883
|
-
|
|
62913
|
+
renameSync10(tmpPath, tokenPath);
|
|
62884
62914
|
try {
|
|
62885
62915
|
const uid = allocateAgentUid(agent);
|
|
62886
62916
|
chownSync2(tokenPath, uid, uid);
|
|
@@ -64262,7 +64292,7 @@ import {
|
|
|
64262
64292
|
openSync as openSync9,
|
|
64263
64293
|
readdirSync as readdirSync17,
|
|
64264
64294
|
readFileSync as readFileSync34,
|
|
64265
|
-
renameSync as
|
|
64295
|
+
renameSync as renameSync11,
|
|
64266
64296
|
statSync as statSync20,
|
|
64267
64297
|
symlinkSync as symlinkSync4,
|
|
64268
64298
|
unlinkSync as unlinkSync10,
|
|
@@ -64414,7 +64444,7 @@ function backupVault(opts) {
|
|
|
64414
64444
|
} catch {}
|
|
64415
64445
|
throw new Error(`vault backup refused: '${fullPath}' already exists ` + `(sub-second collision with another backup). Retry in 1 second, ` + `or check for a concurrent backup process.`);
|
|
64416
64446
|
}
|
|
64417
|
-
|
|
64447
|
+
renameSync11(tmpPath, fullPath);
|
|
64418
64448
|
const stat = statSync20(fullPath);
|
|
64419
64449
|
const sha256 = sha256OfFile(fullPath);
|
|
64420
64450
|
const row = {
|
|
@@ -74106,7 +74136,7 @@ import {
|
|
|
74106
74136
|
openSync as openSync11,
|
|
74107
74137
|
readdirSync as readdirSync21,
|
|
74108
74138
|
readFileSync as readFileSync50,
|
|
74109
|
-
renameSync as
|
|
74139
|
+
renameSync as renameSync12,
|
|
74110
74140
|
statSync as statSync25,
|
|
74111
74141
|
unlinkSync as unlinkSync11,
|
|
74112
74142
|
writeFileSync as writeFileSync26,
|
|
@@ -74664,7 +74694,7 @@ function writeAll(stateDir, events) {
|
|
|
74664
74694
|
`) + `
|
|
74665
74695
|
`;
|
|
74666
74696
|
writeFileSync26(tmp, body, "utf-8");
|
|
74667
|
-
|
|
74697
|
+
renameSync12(tmp, path4);
|
|
74668
74698
|
}
|
|
74669
74699
|
var ORPHAN_TMP_TTL_MS = 60000;
|
|
74670
74700
|
var TMP_PREFIX = `${ISSUES_FILE}.tmp-`;
|
|
@@ -76504,7 +76534,7 @@ import {
|
|
|
76504
76534
|
readdirSync as readdirSync23,
|
|
76505
76535
|
unlinkSync as unlinkSync12,
|
|
76506
76536
|
existsSync as existsSync64,
|
|
76507
|
-
renameSync as
|
|
76537
|
+
renameSync as renameSync13
|
|
76508
76538
|
} from "node:fs";
|
|
76509
76539
|
import { join as join63, resolve as resolve41 } from "node:path";
|
|
76510
76540
|
import { homedir as homedir37 } from "node:os";
|
|
@@ -76523,7 +76553,7 @@ function writeRecord(record2) {
|
|
|
76523
76553
|
const tmp = `${target}.tmp${process.pid}`;
|
|
76524
76554
|
writeFileSync30(tmp, JSON.stringify(record2, null, 2) + `
|
|
76525
76555
|
`, { mode: 384 });
|
|
76526
|
-
|
|
76556
|
+
renameSync13(tmp, target);
|
|
76527
76557
|
}
|
|
76528
76558
|
function readRecord(id) {
|
|
76529
76559
|
const path7 = recordPath(id);
|
|
@@ -77842,7 +77872,7 @@ async function fetchToken(vaultKey) {
|
|
|
77842
77872
|
|
|
77843
77873
|
// src/cli/apply.ts
|
|
77844
77874
|
init_source();
|
|
77845
|
-
import { accessSync as accessSync3, chownSync as chownSync4, constants as fsConstants6, copyFileSync as copyFileSync11, existsSync as existsSync72, mkdirSync as mkdirSync40, readFileSync as readFileSync57, readdirSync as readdirSync26, renameSync as
|
|
77875
|
+
import { accessSync as accessSync3, chownSync as chownSync4, constants as fsConstants6, copyFileSync as copyFileSync11, existsSync as existsSync72, mkdirSync as mkdirSync40, readFileSync as readFileSync57, readdirSync as readdirSync26, renameSync as renameSync14, writeFileSync as writeFileSync35 } from "node:fs";
|
|
77846
77876
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
77847
77877
|
import { spawnSync as childSpawnSync } from "node:child_process";
|
|
77848
77878
|
import readline from "node:readline";
|
|
@@ -78692,7 +78722,7 @@ function writeInstallTypeCache(homeDir = homedir40()) {
|
|
|
78692
78722
|
source_paths: ctx.source_paths
|
|
78693
78723
|
};
|
|
78694
78724
|
writeFileSync35(tmp, JSON.stringify(payload, null, 2), { mode: 420 });
|
|
78695
|
-
|
|
78725
|
+
renameSync14(tmp, out);
|
|
78696
78726
|
return out;
|
|
78697
78727
|
}
|
|
78698
78728
|
async function runApply(config, options, deps = {}, switchroomConfigPath) {
|
|
@@ -79764,7 +79794,7 @@ import {
|
|
|
79764
79794
|
openSync as openSync13,
|
|
79765
79795
|
readdirSync as readdirSync28,
|
|
79766
79796
|
readFileSync as readFileSync60,
|
|
79767
|
-
renameSync as
|
|
79797
|
+
renameSync as renameSync15,
|
|
79768
79798
|
statSync as statSync28,
|
|
79769
79799
|
unlinkSync as unlinkSync14,
|
|
79770
79800
|
writeSync as writeSync8
|
|
@@ -79846,7 +79876,7 @@ function writeOverlayEntry(agent, slug, yamlText, opts = {}) {
|
|
|
79846
79876
|
} finally {
|
|
79847
79877
|
closeSync13(fd);
|
|
79848
79878
|
}
|
|
79849
|
-
|
|
79879
|
+
renameSync15(stagingPath, finalPath);
|
|
79850
79880
|
return finalPath;
|
|
79851
79881
|
});
|
|
79852
79882
|
}
|
|
@@ -79863,7 +79893,7 @@ function writeSkillsOverlayEntry(agent, slug, yamlText, opts = {}) {
|
|
|
79863
79893
|
} finally {
|
|
79864
79894
|
closeSync13(fd);
|
|
79865
79895
|
}
|
|
79866
|
-
|
|
79896
|
+
renameSync15(stagingPath, finalPath);
|
|
79867
79897
|
return finalPath;
|
|
79868
79898
|
});
|
|
79869
79899
|
}
|
|
@@ -80063,7 +80093,7 @@ import {
|
|
|
80063
80093
|
openSync as openSync14,
|
|
80064
80094
|
readdirSync as readdirSync29,
|
|
80065
80095
|
readFileSync as readFileSync61,
|
|
80066
|
-
renameSync as
|
|
80096
|
+
renameSync as renameSync16,
|
|
80067
80097
|
unlinkSync as unlinkSync15,
|
|
80068
80098
|
writeFileSync as writeFileSync36,
|
|
80069
80099
|
writeSync as writeSync9
|
|
@@ -80106,7 +80136,7 @@ function stagePendingScheduleEntry(opts) {
|
|
|
80106
80136
|
} finally {
|
|
80107
80137
|
closeSync14(fd);
|
|
80108
80138
|
}
|
|
80109
|
-
|
|
80139
|
+
renameSync16(yamlTmp, yamlPath);
|
|
80110
80140
|
}
|
|
80111
80141
|
writeFileSync36(metaPath, JSON.stringify(meta, null, 2) + `
|
|
80112
80142
|
`, { mode: 384 });
|
|
@@ -80145,7 +80175,7 @@ function commitPendingScheduleEntry(opts) {
|
|
|
80145
80175
|
if (existsSync76(finalPath)) {
|
|
80146
80176
|
return { committed: false, reason: "slug_collision" };
|
|
80147
80177
|
}
|
|
80148
|
-
|
|
80178
|
+
renameSync16(match.yamlPath, finalPath);
|
|
80149
80179
|
unlinkSync15(match.metaPath);
|
|
80150
80180
|
return { committed: true, path: finalPath, slug };
|
|
80151
80181
|
}
|
|
@@ -80895,7 +80925,7 @@ import {
|
|
|
80895
80925
|
readFileSync as readFileSync63,
|
|
80896
80926
|
readdirSync as readdirSync30,
|
|
80897
80927
|
realpathSync as realpathSync7,
|
|
80898
|
-
renameSync as
|
|
80928
|
+
renameSync as renameSync17,
|
|
80899
80929
|
rmSync as rmSync16,
|
|
80900
80930
|
statSync as statSync29,
|
|
80901
80931
|
writeFileSync as writeFileSync37
|
|
@@ -81350,9 +81380,9 @@ function writePayload(poolDir, name, files) {
|
|
|
81350
81380
|
} catch {}
|
|
81351
81381
|
if (targetExists) {
|
|
81352
81382
|
oldRename = `${target}.skill-apply-old-${Date.now()}`;
|
|
81353
|
-
|
|
81383
|
+
renameSync17(target, oldRename);
|
|
81354
81384
|
}
|
|
81355
|
-
|
|
81385
|
+
renameSync17(staging, target);
|
|
81356
81386
|
if (oldRename) {
|
|
81357
81387
|
rmSync16(oldRename, { recursive: true, force: true });
|
|
81358
81388
|
oldRename = null;
|
|
@@ -81366,7 +81396,7 @@ function writePayload(poolDir, name, files) {
|
|
|
81366
81396
|
if (existsSync79(target)) {
|
|
81367
81397
|
rmSync16(target, { recursive: true, force: true });
|
|
81368
81398
|
}
|
|
81369
|
-
|
|
81399
|
+
renameSync17(oldRename, target);
|
|
81370
81400
|
} catch {}
|
|
81371
81401
|
}
|
|
81372
81402
|
throw err2;
|
|
@@ -81446,7 +81476,7 @@ import {
|
|
|
81446
81476
|
openSync as openSync16,
|
|
81447
81477
|
readFileSync as readFileSync64,
|
|
81448
81478
|
readdirSync as readdirSync31,
|
|
81449
|
-
renameSync as
|
|
81479
|
+
renameSync as renameSync18,
|
|
81450
81480
|
rmSync as rmSync17,
|
|
81451
81481
|
statSync as statSync30,
|
|
81452
81482
|
utimesSync,
|
|
@@ -81509,7 +81539,7 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
|
|
|
81509
81539
|
sweepMirrorPriors(configSkillsRoot);
|
|
81510
81540
|
if (existsSync80(dest)) {
|
|
81511
81541
|
const trash = join77(configSkillsRoot, `.${name}-trash-${Date.now()}`);
|
|
81512
|
-
|
|
81542
|
+
renameSync18(dest, trash);
|
|
81513
81543
|
}
|
|
81514
81544
|
return;
|
|
81515
81545
|
}
|
|
@@ -81533,9 +81563,9 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
|
|
|
81533
81563
|
walk2(liveSkillDir, staging);
|
|
81534
81564
|
if (existsSync80(dest)) {
|
|
81535
81565
|
const prior = join77(configSkillsRoot, `.${name}-prior-${Date.now()}`);
|
|
81536
|
-
|
|
81566
|
+
renameSync18(dest, prior);
|
|
81537
81567
|
}
|
|
81538
|
-
|
|
81568
|
+
renameSync18(staging, dest);
|
|
81539
81569
|
} catch (err2) {
|
|
81540
81570
|
process.stderr.write(source_default.yellow(`warning: mirror to ${dest} failed (${err2.message ?? err2}); ` + `live copy still works, but this skill is not version-controlled until next successful sync.
|
|
81541
81571
|
`));
|
|
@@ -81718,9 +81748,9 @@ function writePersonalSkill(targetDir, files) {
|
|
|
81718
81748
|
} catch {}
|
|
81719
81749
|
if (targetExists) {
|
|
81720
81750
|
oldRename = `${targetDir}.personal-old-${Date.now()}`;
|
|
81721
|
-
|
|
81751
|
+
renameSync18(targetDir, oldRename);
|
|
81722
81752
|
}
|
|
81723
|
-
|
|
81753
|
+
renameSync18(staging, targetDir);
|
|
81724
81754
|
if (oldRename) {
|
|
81725
81755
|
rmSync17(oldRename, { recursive: true, force: true });
|
|
81726
81756
|
oldRename = null;
|
|
@@ -81734,7 +81764,7 @@ function writePersonalSkill(targetDir, files) {
|
|
|
81734
81764
|
if (existsSync80(targetDir)) {
|
|
81735
81765
|
rmSync17(targetDir, { recursive: true, force: true });
|
|
81736
81766
|
}
|
|
81737
|
-
|
|
81767
|
+
renameSync18(oldRename, targetDir);
|
|
81738
81768
|
} catch {}
|
|
81739
81769
|
}
|
|
81740
81770
|
throw err2;
|
|
@@ -81972,7 +82002,7 @@ function removePersonalAction(name, opts) {
|
|
|
81972
82002
|
mkdirSync45(trashRoot, { recursive: true, mode: 493 });
|
|
81973
82003
|
const ts = Date.now();
|
|
81974
82004
|
const trashTarget = join77(trashRoot, `${name}-${ts}`);
|
|
81975
|
-
|
|
82005
|
+
renameSync18(target, trashTarget);
|
|
81976
82006
|
const now = new Date(ts);
|
|
81977
82007
|
utimesSync(trashTarget, now, now);
|
|
81978
82008
|
mirrorToConfigRepo(agent, name, null);
|
|
@@ -13836,18 +13836,11 @@ var TelegramChannelSchema = exports_external.object({
|
|
|
13836
13836
|
webhook_via_gateway: exports_external.boolean().optional().describe("Route verified webhook events to the agent's in-container gateway " + "over a peercred-gated UDS (<agent>/telegram/webhook.sock) instead " + "of having the host-side web receiver write the agent dir directly. " + "Required under the Docker runtime: the receiver runs as the host " + "operator UID and cannot write the per-agent-UID-owned agent dir " + "(EACCES 500) nor connect the gateway socket. When true the gateway " + "(running as the agent UID) becomes the sole writer of " + "webhook-events.jsonl + dedup/cooldown state and also fires " + "webhook_dispatch. Off by default for back-compat with host-runtime " + "installs. See docs/rfcs/webhook-via-gateway-socket.md."),
|
|
13837
13837
|
webhook_require_edge: exports_external.boolean().optional().describe("Cloudflare-only edge lock: require the X-Switchroom-Edge header " + "(injected by a Cloudflare Transform Rule on hooks.switchroom.ai) to " + "match the operator's edge secret at ~/.switchroom/webhook-edge-secret " + "before any HMAC verification; reject 403 otherwise. Proves the " + "request entered through our Cloudflare edge — the per-agent HMAC " + "alone can't (it proves body provenance, not network path). Stacks " + "on the GitHub-IP WAF + per-agent HMAC. Fail-closed: when required " + "but the secret file is missing/empty every request is rejected. Off " + "by default. See docs/rfcs/webhook-cloudflare-edge-lock.md."),
|
|
13838
13838
|
chat_id: exports_external.string().regex(/^-\d+$/, 'supergroup chat_id must be a negative integer as a string (e.g. "-1001234567890")').optional().describe("Per-agent supergroup ID — overrides fleet `telegram.forum_chat_id`. " + "When set, requires `default_topic_id`. Negative integer as string. " + "Forbidden when `dm_only: true`. See docs/rfcs/supergroup-mode.md."),
|
|
13839
|
-
default_topic_id: exports_external.number().int().positive().optional().describe("Forum topic ID this agent's automated outbounds default to when " + "no more-specific alias resolves.
|
|
13839
|
+
default_topic_id: exports_external.number().int().positive().optional().describe("Forum topic ID this agent's automated outbounds default to when " + "no more-specific alias resolves. Defaults to General (topic 1) when " + "`chat_id` is set and this is omitted — set it only to pin a different " + "fallback topic. " + "Telegram's General topic is `id=1` at MTProto but sends omit the " + "field — the outbound wrapper strips `message_thread_id === 1` " + "on send. Forbidden when `dm_only: true`."),
|
|
13840
13840
|
topic_aliases: exports_external.record(exports_external.string(), exports_external.number().int().positive()).optional().describe("Operator-friendly names for forum topic IDs (e.g. " + "`{ general: 1, planning: 17, cron: 23, admin: 31, alerts: 41 }`). " + "Referenced from per-cron `topic:` fields and the outbound router " + "for autonomous events (boot → alerts, hostd → admin, etc.). " + "Cascades per-key through defaults → profile → agent.")
|
|
13841
13841
|
}).optional().superRefine((tg, ctx) => {
|
|
13842
13842
|
if (!tg)
|
|
13843
13843
|
return;
|
|
13844
|
-
if (tg.chat_id != null && tg.default_topic_id == null) {
|
|
13845
|
-
ctx.addIssue({
|
|
13846
|
-
code: exports_external.ZodIssueCode.custom,
|
|
13847
|
-
message: "`channels.telegram.chat_id` requires `default_topic_id` — supergroup-mode agents need a fallback topic for unclassified outbounds.",
|
|
13848
|
-
path: ["default_topic_id"]
|
|
13849
|
-
});
|
|
13850
|
-
}
|
|
13851
13844
|
if (tg.default_topic_id != null && tg.chat_id == null) {
|
|
13852
13845
|
ctx.addIssue({
|
|
13853
13846
|
code: exports_external.ZodIssueCode.custom,
|
|
@@ -13862,6 +13855,11 @@ var TelegramChannelSchema = exports_external.object({
|
|
|
13862
13855
|
path: ["topic_aliases"]
|
|
13863
13856
|
});
|
|
13864
13857
|
}
|
|
13858
|
+
}).transform((tg) => {
|
|
13859
|
+
if (tg && tg.chat_id != null && tg.default_topic_id == null) {
|
|
13860
|
+
return { ...tg, default_topic_id: 1 };
|
|
13861
|
+
}
|
|
13862
|
+
return tg;
|
|
13865
13863
|
});
|
|
13866
13864
|
var ChannelsSchema = exports_external.object({
|
|
13867
13865
|
telegram: TelegramChannelSchema
|
|
@@ -11422,18 +11422,11 @@ var init_schema = __esm(() => {
|
|
|
11422
11422
|
webhook_via_gateway: exports_external.boolean().optional().describe("Route verified webhook events to the agent's in-container gateway " + "over a peercred-gated UDS (<agent>/telegram/webhook.sock) instead " + "of having the host-side web receiver write the agent dir directly. " + "Required under the Docker runtime: the receiver runs as the host " + "operator UID and cannot write the per-agent-UID-owned agent dir " + "(EACCES 500) nor connect the gateway socket. When true the gateway " + "(running as the agent UID) becomes the sole writer of " + "webhook-events.jsonl + dedup/cooldown state and also fires " + "webhook_dispatch. Off by default for back-compat with host-runtime " + "installs. See docs/rfcs/webhook-via-gateway-socket.md."),
|
|
11423
11423
|
webhook_require_edge: exports_external.boolean().optional().describe("Cloudflare-only edge lock: require the X-Switchroom-Edge header " + "(injected by a Cloudflare Transform Rule on hooks.switchroom.ai) to " + "match the operator's edge secret at ~/.switchroom/webhook-edge-secret " + "before any HMAC verification; reject 403 otherwise. Proves the " + "request entered through our Cloudflare edge — the per-agent HMAC " + "alone can't (it proves body provenance, not network path). Stacks " + "on the GitHub-IP WAF + per-agent HMAC. Fail-closed: when required " + "but the secret file is missing/empty every request is rejected. Off " + "by default. See docs/rfcs/webhook-cloudflare-edge-lock.md."),
|
|
11424
11424
|
chat_id: exports_external.string().regex(/^-\d+$/, 'supergroup chat_id must be a negative integer as a string (e.g. "-1001234567890")').optional().describe("Per-agent supergroup ID — overrides fleet `telegram.forum_chat_id`. " + "When set, requires `default_topic_id`. Negative integer as string. " + "Forbidden when `dm_only: true`. See docs/rfcs/supergroup-mode.md."),
|
|
11425
|
-
default_topic_id: exports_external.number().int().positive().optional().describe("Forum topic ID this agent's automated outbounds default to when " + "no more-specific alias resolves.
|
|
11425
|
+
default_topic_id: exports_external.number().int().positive().optional().describe("Forum topic ID this agent's automated outbounds default to when " + "no more-specific alias resolves. Defaults to General (topic 1) when " + "`chat_id` is set and this is omitted — set it only to pin a different " + "fallback topic. " + "Telegram's General topic is `id=1` at MTProto but sends omit the " + "field — the outbound wrapper strips `message_thread_id === 1` " + "on send. Forbidden when `dm_only: true`."),
|
|
11426
11426
|
topic_aliases: exports_external.record(exports_external.string(), exports_external.number().int().positive()).optional().describe("Operator-friendly names for forum topic IDs (e.g. " + "`{ general: 1, planning: 17, cron: 23, admin: 31, alerts: 41 }`). " + "Referenced from per-cron `topic:` fields and the outbound router " + "for autonomous events (boot → alerts, hostd → admin, etc.). " + "Cascades per-key through defaults → profile → agent.")
|
|
11427
11427
|
}).optional().superRefine((tg, ctx) => {
|
|
11428
11428
|
if (!tg)
|
|
11429
11429
|
return;
|
|
11430
|
-
if (tg.chat_id != null && tg.default_topic_id == null) {
|
|
11431
|
-
ctx.addIssue({
|
|
11432
|
-
code: exports_external.ZodIssueCode.custom,
|
|
11433
|
-
message: "`channels.telegram.chat_id` requires `default_topic_id` — supergroup-mode agents need a fallback topic for unclassified outbounds.",
|
|
11434
|
-
path: ["default_topic_id"]
|
|
11435
|
-
});
|
|
11436
|
-
}
|
|
11437
11430
|
if (tg.default_topic_id != null && tg.chat_id == null) {
|
|
11438
11431
|
ctx.addIssue({
|
|
11439
11432
|
code: exports_external.ZodIssueCode.custom,
|
|
@@ -11448,6 +11441,11 @@ var init_schema = __esm(() => {
|
|
|
11448
11441
|
path: ["topic_aliases"]
|
|
11449
11442
|
});
|
|
11450
11443
|
}
|
|
11444
|
+
}).transform((tg) => {
|
|
11445
|
+
if (tg && tg.chat_id != null && tg.default_topic_id == null) {
|
|
11446
|
+
return { ...tg, default_topic_id: 1 };
|
|
11447
|
+
}
|
|
11448
|
+
return tg;
|
|
11451
11449
|
});
|
|
11452
11450
|
ChannelsSchema = exports_external.object({
|
|
11453
11451
|
telegram: TelegramChannelSchema
|