switchroom 0.13.24 → 0.13.26
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 +2 -4
- package/dist/auth-broker/index.js +31 -9
- package/dist/cli/switchroom.js +494 -349
- package/dist/host-control/main.js +2 -4
- package/dist/vault/approvals/kernel-server.js +68 -65
- package/dist/vault/broker/server.js +41 -12
- package/package.json +1 -1
- package/profiles/_shared/telegram-style.md.hbs +4 -4
- package/telegram-plugin/dist/gateway/gateway.js +34 -29
- package/telegram-plugin/tests/telegram-format.test.ts +2 -2
- package/telegram-plugin/uat/scenarios/jtbd-rapid-followup-dm.test.ts +1 -1
|
@@ -11034,7 +11034,6 @@ var SessionSchema = exports_external.object({
|
|
|
11034
11034
|
var SessionContinuitySchema = exports_external.object({
|
|
11035
11035
|
enabled: exports_external.boolean().optional().describe("Master switch for the session-handoff briefing (default true)."),
|
|
11036
11036
|
show_handoff_line: exports_external.boolean().optional().describe("Whether the telegram plugin prepends a visible '↩️ Picked up…' " + "line to the first assistant reply after a restart (default true)."),
|
|
11037
|
-
summarizer_model: exports_external.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._\-/\[\]:]*$/, "Model name must be alphanumeric with ._-/[]: only").optional().describe("Anthropic model used to produce the handoff briefing."),
|
|
11038
11037
|
max_turns_in_briefing: exports_external.number().int().positive().optional().describe("Cap on recent user/assistant turn pairs fed to the summarizer."),
|
|
11039
11038
|
resume_mode: exports_external.enum(["auto", "continue", "handoff", "none"]).optional().describe("How to resume the next session. 'handoff' (default as of #362) " + "never passes --continue; a fresh Claude starts each restart and " + "reads a briefing assembled from recent Telegram messages, Hindsight " + "recall, and today's daily memory file. 'auto' uses --continue when " + "the latest JSONL is smaller than resume_max_bytes, else falls back " + "to the handoff briefing. 'continue' always passes --continue. " + "'none' starts completely fresh every time."),
|
|
11040
11039
|
resume_max_bytes: exports_external.number().int().positive().optional().describe("Byte threshold above which 'auto' mode falls back to handoff " + "instead of --continue. Default 2_000_000 (~2MB). Large transcripts " + "can blow out the context window even with prefix caching, and " + "--continue replay is known-fragile at scale.")
|
|
@@ -11081,10 +11080,9 @@ var TelegramChannelSchema = exports_external.object({
|
|
|
11081
11080
|
start: exports_external.number().int().min(0).max(23),
|
|
11082
11081
|
end: exports_external.number().int().min(0).max(23),
|
|
11083
11082
|
tz: exports_external.string().optional()
|
|
11084
|
-
}).optional()
|
|
11085
|
-
model: exports_external.string().optional()
|
|
11083
|
+
}).optional()
|
|
11086
11084
|
})).optional()
|
|
11087
|
-
}).optional().describe("Auto-dispatch rules: when a verified webhook event matches a rule, " + "
|
|
11085
|
+
}).optional().describe("Auto-dispatch rules: when a verified webhook event matches a rule, " + "inject the rendered prompt into the agent's live session (#1625). " + "Supports cooldowns, quiet hours, and label/action matchers. " + "Off by default — opt in per agent. See src/web/webhook-dispatch.ts."),
|
|
11088
11086
|
webhook_rate_limit: exports_external.object({
|
|
11089
11087
|
rpm: exports_external.number().int().positive()
|
|
11090
11088
|
}).optional().describe("Per-source rate limit for the webhook ingest path (#714). " + "Off by default — when this key is absent the handler skips " + "rate-limit checks entirely. Opt in by setting `rpm` to an " + "integer requests-per-minute (token bucket per (agent, source); " + "burst equal to rpm). When enabled, exceeding the limit returns " + "429 with Retry-After header; first throttle event per " + "(agent, source) per 60s window is written to " + "<agent>/telegram/issues.jsonl. " + "Cascades from defaults.channels.telegram.webhook_rate_limit.")
|
|
@@ -11034,7 +11034,6 @@ var SessionSchema = exports_external.object({
|
|
|
11034
11034
|
var SessionContinuitySchema = exports_external.object({
|
|
11035
11035
|
enabled: exports_external.boolean().optional().describe("Master switch for the session-handoff briefing (default true)."),
|
|
11036
11036
|
show_handoff_line: exports_external.boolean().optional().describe("Whether the telegram plugin prepends a visible '↩️ Picked up…' " + "line to the first assistant reply after a restart (default true)."),
|
|
11037
|
-
summarizer_model: exports_external.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._\-/\[\]:]*$/, "Model name must be alphanumeric with ._-/[]: only").optional().describe("Anthropic model used to produce the handoff briefing."),
|
|
11038
11037
|
max_turns_in_briefing: exports_external.number().int().positive().optional().describe("Cap on recent user/assistant turn pairs fed to the summarizer."),
|
|
11039
11038
|
resume_mode: exports_external.enum(["auto", "continue", "handoff", "none"]).optional().describe("How to resume the next session. 'handoff' (default as of #362) " + "never passes --continue; a fresh Claude starts each restart and " + "reads a briefing assembled from recent Telegram messages, Hindsight " + "recall, and today's daily memory file. 'auto' uses --continue when " + "the latest JSONL is smaller than resume_max_bytes, else falls back " + "to the handoff briefing. 'continue' always passes --continue. " + "'none' starts completely fresh every time."),
|
|
11040
11039
|
resume_max_bytes: exports_external.number().int().positive().optional().describe("Byte threshold above which 'auto' mode falls back to handoff " + "instead of --continue. Default 2_000_000 (~2MB). Large transcripts " + "can blow out the context window even with prefix caching, and " + "--continue replay is known-fragile at scale.")
|
|
@@ -11081,10 +11080,9 @@ var TelegramChannelSchema = exports_external.object({
|
|
|
11081
11080
|
start: exports_external.number().int().min(0).max(23),
|
|
11082
11081
|
end: exports_external.number().int().min(0).max(23),
|
|
11083
11082
|
tz: exports_external.string().optional()
|
|
11084
|
-
}).optional()
|
|
11085
|
-
model: exports_external.string().optional()
|
|
11083
|
+
}).optional()
|
|
11086
11084
|
})).optional()
|
|
11087
|
-
}).optional().describe("Auto-dispatch rules: when a verified webhook event matches a rule, " + "
|
|
11085
|
+
}).optional().describe("Auto-dispatch rules: when a verified webhook event matches a rule, " + "inject the rendered prompt into the agent's live session (#1625). " + "Supports cooldowns, quiet hours, and label/action matchers. " + "Off by default — opt in per agent. See src/web/webhook-dispatch.ts."),
|
|
11088
11086
|
webhook_rate_limit: exports_external.object({
|
|
11089
11087
|
rpm: exports_external.number().int().positive()
|
|
11090
11088
|
}).optional().describe("Per-source rate limit for the webhook ingest path (#714). " + "Off by default — when this key is absent the handler skips " + "rate-limit checks entirely. Opt in by setting `rpm` to an " + "integer requests-per-minute (token bucket per (agent, source); " + "burst equal to rpm). When enabled, exceeding the limit returns " + "429 with Retry-After header; first throttle event per " + "(agent, source) per 60s window is written to " + "<agent>/telegram/issues.jsonl. " + "Cascades from defaults.channels.telegram.webhook_rate_limit.")
|
|
@@ -11646,7 +11644,7 @@ function resolveAgentsDir(config) {
|
|
|
11646
11644
|
import * as net from "node:net";
|
|
11647
11645
|
import {
|
|
11648
11646
|
chmodSync,
|
|
11649
|
-
chownSync,
|
|
11647
|
+
chownSync as chownSync2,
|
|
11650
11648
|
existsSync as existsSync6,
|
|
11651
11649
|
lstatSync,
|
|
11652
11650
|
mkdirSync as mkdirSync3,
|
|
@@ -12107,6 +12105,7 @@ function atomicWriteJsonSync(destPath, value, mode = 384) {
|
|
|
12107
12105
|
|
|
12108
12106
|
// src/auth/account-store.ts
|
|
12109
12107
|
import {
|
|
12108
|
+
chownSync,
|
|
12110
12109
|
existsSync as existsSync4,
|
|
12111
12110
|
mkdirSync,
|
|
12112
12111
|
readFileSync as readFileSync3,
|
|
@@ -12203,6 +12202,18 @@ function writeAccountCredentials(label, value, home2 = homedir2()) {
|
|
|
12203
12202
|
mkdirSync(accountDir(label, home2), { recursive: true });
|
|
12204
12203
|
atomicWriteJson(accountCredentialsPath(label, home2), enrichClaudeCreds(value));
|
|
12205
12204
|
}
|
|
12205
|
+
function chownAccountFiles(label, uid, home2 = homedir2()) {
|
|
12206
|
+
validateAccountLabel(label);
|
|
12207
|
+
const dir = accountDir(label, home2);
|
|
12208
|
+
if (existsSync4(dir))
|
|
12209
|
+
chownSync(dir, uid, uid);
|
|
12210
|
+
const creds = accountCredentialsPath(label, home2);
|
|
12211
|
+
if (existsSync4(creds))
|
|
12212
|
+
chownSync(creds, uid, uid);
|
|
12213
|
+
const meta = accountMetaPath(label, home2);
|
|
12214
|
+
if (existsSync4(meta))
|
|
12215
|
+
chownSync(meta, uid, uid);
|
|
12216
|
+
}
|
|
12206
12217
|
function readAccountMeta(label, home2 = homedir2()) {
|
|
12207
12218
|
const p = accountMetaPath(label, home2);
|
|
12208
12219
|
if (!existsSync4(p))
|
|
@@ -13135,7 +13146,7 @@ class AuthBroker {
|
|
|
13135
13146
|
const dir = dirname2(sockPath);
|
|
13136
13147
|
if (existsSync6(dir)) {
|
|
13137
13148
|
try {
|
|
13138
|
-
|
|
13149
|
+
chownSync2(dir, 0, 0);
|
|
13139
13150
|
} catch {}
|
|
13140
13151
|
try {
|
|
13141
13152
|
chmodSync(dir, 448);
|
|
@@ -13158,10 +13169,10 @@ class AuthBroker {
|
|
|
13158
13169
|
chmodSync(sockPath, sockMode);
|
|
13159
13170
|
} catch {}
|
|
13160
13171
|
try {
|
|
13161
|
-
|
|
13172
|
+
chownSync2(sockPath, targetUid, targetUid);
|
|
13162
13173
|
} catch {}
|
|
13163
13174
|
try {
|
|
13164
|
-
|
|
13175
|
+
chownSync2(dir, targetUid, targetUid);
|
|
13165
13176
|
} catch {}
|
|
13166
13177
|
this.listeners.set(sockPath, { server, identity: identity2, socketPath: sockPath });
|
|
13167
13178
|
resolveP();
|
|
@@ -13507,6 +13518,7 @@ class AuthBroker {
|
|
|
13507
13518
|
socket.write(encodeError(id, "INTERNAL", err.message));
|
|
13508
13519
|
return;
|
|
13509
13520
|
}
|
|
13521
|
+
this.chownAccountFilesIfRoot(label);
|
|
13510
13522
|
const contents = readFileSync5(accountCredentialsPath(label, this.home), "utf-8");
|
|
13511
13523
|
this.shaIndex[label] = sha256Hex(contents);
|
|
13512
13524
|
this.lastWrittenExpiresAt.set(label, credentials.claudeAiOauth?.expiresAt);
|
|
@@ -13749,6 +13761,7 @@ class AuthBroker {
|
|
|
13749
13761
|
};
|
|
13750
13762
|
const outcome = await refreshAccountIfNeeded(label, opts);
|
|
13751
13763
|
if (outcome.kind === "refreshed") {
|
|
13764
|
+
this.chownAccountFilesIfRoot(label);
|
|
13752
13765
|
const creds = readAccountCredentials(label, this.home);
|
|
13753
13766
|
const newExpiresAt = creds?.claudeAiOauth?.expiresAt ?? outcome.newExpiresAt;
|
|
13754
13767
|
this.lastWrittenExpiresAt.set(label, newExpiresAt);
|
|
@@ -13899,7 +13912,7 @@ class AuthBroker {
|
|
|
13899
13912
|
atomicWriteFileSync(targetPath, mirrorContent, 384);
|
|
13900
13913
|
try {
|
|
13901
13914
|
const uid = allocateAgentUid(agentName);
|
|
13902
|
-
|
|
13915
|
+
chownSync2(targetPath, uid, uid);
|
|
13903
13916
|
} catch (err) {
|
|
13904
13917
|
this.warnCapChownMissing(err);
|
|
13905
13918
|
}
|
|
@@ -14026,6 +14039,15 @@ class AuthBroker {
|
|
|
14026
14039
|
const msg = err instanceof Error ? err.message : String(err);
|
|
14027
14040
|
this.logErr(`chown failed (CAP_CHOWN missing?): ${msg}. ` + `Per-agent mirror written but ownership not flipped. ` + `Suppressing further chown warnings for this process.`);
|
|
14028
14041
|
}
|
|
14042
|
+
chownAccountFilesIfRoot(label) {
|
|
14043
|
+
if (this.operatorUid === undefined)
|
|
14044
|
+
return;
|
|
14045
|
+
try {
|
|
14046
|
+
chownAccountFiles(label, this.operatorUid, this.home);
|
|
14047
|
+
} catch (err) {
|
|
14048
|
+
this.warnCapChownMissing(err);
|
|
14049
|
+
}
|
|
14050
|
+
}
|
|
14029
14051
|
assertConfigConsistent(cfg) {
|
|
14030
14052
|
const shape = configToShape(cfg);
|
|
14031
14053
|
const errs = validateConsumerNames(shape);
|