switchroom 0.14.32 → 0.14.34
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 +8 -0
- package/dist/auth-broker/index.js +8 -0
- package/dist/cli/autoaccept-poll.js +145 -2
- package/dist/cli/notion-write-pretool.mjs +8 -0
- package/dist/cli/switchroom.js +32 -5
- package/dist/host-control/main.js +35 -11
- package/dist/vault/approvals/kernel-server.js +8 -0
- package/dist/vault/broker/server.js +19 -1
- package/package.json +1 -1
- package/profiles/_base/start.sh.hbs +9 -4
- package/telegram-plugin/dist/gateway/gateway.js +18 -4
|
@@ -11219,6 +11219,7 @@ var profileFields = {
|
|
|
11219
11219
|
}).optional()
|
|
11220
11220
|
}).optional(),
|
|
11221
11221
|
schedule: exports_external.array(ScheduleEntrySchema).optional(),
|
|
11222
|
+
secrets: exports_external.array(exports_external.string().regex(/^[a-zA-Z0-9_\-/]+$/, "Secret key names must contain only alphanumeric characters, underscores, hyphens, and forward slashes")).optional().describe("Operator-granted STANDING vault keys this agent may read via the " + "broker — independent of any cron or MCP server. Use when an agent " + "needs a credential both interactively and in its own (agent-managed) " + "schedules, so the grant lives with the agent rather than welded to a " + "specific cron's `secrets[]`. OPERATOR-SET ONLY: agents cannot edit " + "switchroom.yaml or self-grant (reference/vision.md outcome 2 — 'you " + "hold the leash; only your tap grants it'). Exact key names. Cascades " + "UNION across defaults -> profile -> agent (see docs/configuration.md)."),
|
|
11222
11223
|
reactions: ReactionsSchema,
|
|
11223
11224
|
model: exports_external.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._\-/\[\]:]*$/, "Model name must be alphanumeric with ._-/[]: only").optional(),
|
|
11224
11225
|
thinking_effort: exports_external.enum(["low", "medium", "high", "xhigh", "max"]).optional().describe("Adaptive-thinking effort level passed as --effort to the claude CLI. " + "lower = faster/cheaper, higher = more reasoning. Omit to use Claude's default."),
|
|
@@ -11287,6 +11288,7 @@ var AgentSchema = exports_external.object({
|
|
|
11287
11288
|
tools: AgentToolsSchema,
|
|
11288
11289
|
memory: AgentMemorySchema,
|
|
11289
11290
|
schedule: exports_external.array(ScheduleEntrySchema).default([]),
|
|
11291
|
+
secrets: exports_external.array(exports_external.string().regex(/^[a-zA-Z0-9_\-/]+$/, "Secret key names must contain only alphanumeric characters, underscores, hyphens, and forward slashes")).optional(),
|
|
11290
11292
|
reactions: ReactionsSchema,
|
|
11291
11293
|
model: exports_external.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._\-/\[\]:]*$/, "Model name must be alphanumeric with ._-/[]: only (no spaces or shell specials)").optional().describe("Claude model override (e.g., 'claude-sonnet-4-6')"),
|
|
11292
11294
|
thinking_effort: exports_external.enum(["low", "medium", "high", "xhigh", "max"]).optional().describe("Adaptive-thinking effort level passed as --effort to the claude CLI. " + "Per-agent override wins over defaults.thinking_effort. " + "lower = faster/cheaper, higher = more reasoning. Omit to use Claude's default."),
|
|
@@ -11756,6 +11758,12 @@ function mergeAgentConfig(defaultsIn, agentIn) {
|
|
|
11756
11758
|
deny: dedupe([...dDeny, ...aDeny])
|
|
11757
11759
|
};
|
|
11758
11760
|
}
|
|
11761
|
+
if (defaults.secrets || merged.secrets) {
|
|
11762
|
+
merged.secrets = dedupe([
|
|
11763
|
+
...defaults.secrets ?? [],
|
|
11764
|
+
...merged.secrets ?? []
|
|
11765
|
+
]);
|
|
11766
|
+
}
|
|
11759
11767
|
if (defaults.soul || merged.soul) {
|
|
11760
11768
|
const base = defaults.soul ?? {};
|
|
11761
11769
|
const override = merged.soul ?? {};
|
|
@@ -11219,6 +11219,7 @@ var profileFields = {
|
|
|
11219
11219
|
}).optional()
|
|
11220
11220
|
}).optional(),
|
|
11221
11221
|
schedule: exports_external.array(ScheduleEntrySchema).optional(),
|
|
11222
|
+
secrets: exports_external.array(exports_external.string().regex(/^[a-zA-Z0-9_\-/]+$/, "Secret key names must contain only alphanumeric characters, underscores, hyphens, and forward slashes")).optional().describe("Operator-granted STANDING vault keys this agent may read via the " + "broker — independent of any cron or MCP server. Use when an agent " + "needs a credential both interactively and in its own (agent-managed) " + "schedules, so the grant lives with the agent rather than welded to a " + "specific cron's `secrets[]`. OPERATOR-SET ONLY: agents cannot edit " + "switchroom.yaml or self-grant (reference/vision.md outcome 2 — 'you " + "hold the leash; only your tap grants it'). Exact key names. Cascades " + "UNION across defaults -> profile -> agent (see docs/configuration.md)."),
|
|
11222
11223
|
reactions: ReactionsSchema,
|
|
11223
11224
|
model: exports_external.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._\-/\[\]:]*$/, "Model name must be alphanumeric with ._-/[]: only").optional(),
|
|
11224
11225
|
thinking_effort: exports_external.enum(["low", "medium", "high", "xhigh", "max"]).optional().describe("Adaptive-thinking effort level passed as --effort to the claude CLI. " + "lower = faster/cheaper, higher = more reasoning. Omit to use Claude's default."),
|
|
@@ -11287,6 +11288,7 @@ var AgentSchema = exports_external.object({
|
|
|
11287
11288
|
tools: AgentToolsSchema,
|
|
11288
11289
|
memory: AgentMemorySchema,
|
|
11289
11290
|
schedule: exports_external.array(ScheduleEntrySchema).default([]),
|
|
11291
|
+
secrets: exports_external.array(exports_external.string().regex(/^[a-zA-Z0-9_\-/]+$/, "Secret key names must contain only alphanumeric characters, underscores, hyphens, and forward slashes")).optional(),
|
|
11290
11292
|
reactions: ReactionsSchema,
|
|
11291
11293
|
model: exports_external.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._\-/\[\]:]*$/, "Model name must be alphanumeric with ._-/[]: only (no spaces or shell specials)").optional().describe("Claude model override (e.g., 'claude-sonnet-4-6')"),
|
|
11292
11294
|
thinking_effort: exports_external.enum(["low", "medium", "high", "xhigh", "max"]).optional().describe("Adaptive-thinking effort level passed as --effort to the claude CLI. " + "Per-agent override wins over defaults.thinking_effort. " + "lower = faster/cheaper, higher = more reasoning. Omit to use Claude's default."),
|
|
@@ -11756,6 +11758,12 @@ function mergeAgentConfig(defaultsIn, agentIn) {
|
|
|
11756
11758
|
deny: dedupe([...dDeny, ...aDeny])
|
|
11757
11759
|
};
|
|
11758
11760
|
}
|
|
11761
|
+
if (defaults.secrets || merged.secrets) {
|
|
11762
|
+
merged.secrets = dedupe([
|
|
11763
|
+
...defaults.secrets ?? [],
|
|
11764
|
+
...merged.secrets ?? []
|
|
11765
|
+
]);
|
|
11766
|
+
}
|
|
11759
11767
|
if (defaults.soul || merged.soul) {
|
|
11760
11768
|
const base = defaults.soul ?? {};
|
|
11761
11769
|
const override = merged.soul ?? {};
|
|
@@ -110,6 +110,138 @@ async function runAutoaccept(opts) {
|
|
|
110
110
|
return { fired, reason: "manual-stop" };
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
// src/agents/autoaccept.ts
|
|
114
|
+
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
115
|
+
var PROMPTS2 = [
|
|
116
|
+
{
|
|
117
|
+
name: "dev-channels-loading",
|
|
118
|
+
match: /Loading.{1,30}development.{1,30}channels/,
|
|
119
|
+
keys: ["Enter"]
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
name: "dev-channels-local",
|
|
123
|
+
match: /using this for local development/,
|
|
124
|
+
keys: ["Enter"]
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
name: "dev-channels",
|
|
128
|
+
match: /I.{0,5}accept.{0,80}development.{0,10}channels/,
|
|
129
|
+
keys: ["Down", "Enter"]
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
name: "mcp-trust",
|
|
133
|
+
match: /Use this and all future MCP servers/,
|
|
134
|
+
keys: ["Enter"]
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
name: "theme",
|
|
138
|
+
match: /Choose.{1,30}text.{1,30}style/,
|
|
139
|
+
keys: ["Enter"]
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
name: "provider",
|
|
143
|
+
match: /Anthropic.{1,80}Bedrock/,
|
|
144
|
+
keys: ["Enter"]
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
name: "enter-to-confirm",
|
|
148
|
+
match: /Enter.{1,30}confirm/,
|
|
149
|
+
keys: ["Enter"]
|
|
150
|
+
}
|
|
151
|
+
];
|
|
152
|
+
function capturePane2(agentName) {
|
|
153
|
+
const socket = `switchroom-${agentName}`;
|
|
154
|
+
try {
|
|
155
|
+
const out = execFileSync2("tmux", ["-L", socket, "capture-pane", "-p", "-t", agentName], {
|
|
156
|
+
timeout: 3000,
|
|
157
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
158
|
+
maxBuffer: 4 * 1024 * 1024
|
|
159
|
+
});
|
|
160
|
+
return out.toString("utf8");
|
|
161
|
+
} catch (err) {
|
|
162
|
+
console.error(`[autoaccept] ${agentName}: capture-pane failed: ${err.message}`);
|
|
163
|
+
return "";
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
function sendKeys2(agentName, keys) {
|
|
167
|
+
const socket = `switchroom-${agentName}`;
|
|
168
|
+
try {
|
|
169
|
+
execFileSync2("tmux", ["-L", socket, "send-keys", "-t", agentName, ...keys], { timeout: 3000, stdio: ["ignore", "pipe", "pipe"] });
|
|
170
|
+
return true;
|
|
171
|
+
} catch (err) {
|
|
172
|
+
console.error(`[autoaccept] ${agentName}: send-keys ${keys.join(" ")} failed: ${err.message}`);
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// src/agents/wedge-watchdog.ts
|
|
178
|
+
var WEDGE_FOOTER_SIGNATURE = /(?=[\s\S]*[Ee]sc(?:ape)?[^\n]*cancel)(?=[\s\S]*(?:to select|to navigate|\u2191\/\u2193))/;
|
|
179
|
+
var DEFAULT_POLL_MS2 = 5000;
|
|
180
|
+
var DEFAULT_STABILITY_THRESHOLD = 3;
|
|
181
|
+
var DEFAULT_COOLDOWN_MS = 60000;
|
|
182
|
+
function defaultSleep2(ms) {
|
|
183
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
184
|
+
}
|
|
185
|
+
function stabilityKey(text) {
|
|
186
|
+
return text.split(`
|
|
187
|
+
`).map((l) => l.replace(/\s+$/, "")).join(`
|
|
188
|
+
`);
|
|
189
|
+
}
|
|
190
|
+
async function runWedgeWatchdog(opts) {
|
|
191
|
+
const pollIntervalMs = opts.pollIntervalMs ?? DEFAULT_POLL_MS2;
|
|
192
|
+
const stabilityThreshold = opts.stabilityThreshold ?? DEFAULT_STABILITY_THRESHOLD;
|
|
193
|
+
const cooldownMs = opts.cooldownMs ?? DEFAULT_COOLDOWN_MS;
|
|
194
|
+
const deferToPrompts = opts.deferToPrompts ?? PROMPTS2;
|
|
195
|
+
const signature = opts.wedgeSignature ?? WEDGE_FOOTER_SIGNATURE;
|
|
196
|
+
const maxPolls = opts.maxPolls ?? Number.POSITIVE_INFINITY;
|
|
197
|
+
const now = opts.now ?? Date.now;
|
|
198
|
+
const sleep = opts.sleep ?? defaultSleep2;
|
|
199
|
+
const capture = opts.capture ?? capturePane2;
|
|
200
|
+
const send = opts.send ?? sendKeys2;
|
|
201
|
+
let stableCount = 0;
|
|
202
|
+
let lastKey = null;
|
|
203
|
+
let cooldownUntil = 0;
|
|
204
|
+
let fires = 0;
|
|
205
|
+
let polls = 0;
|
|
206
|
+
while (polls < maxPolls) {
|
|
207
|
+
polls++;
|
|
208
|
+
let text = "";
|
|
209
|
+
try {
|
|
210
|
+
text = capture(opts.agentName);
|
|
211
|
+
} catch (err) {
|
|
212
|
+
console.error(`[wedge-watchdog] ${opts.agentName}: capture threw: ${err.message}`);
|
|
213
|
+
text = "";
|
|
214
|
+
}
|
|
215
|
+
const isBlockingModal = !!text && signature.test(text) && !deferToPrompts.some((p) => p.match.test(text));
|
|
216
|
+
if (isBlockingModal) {
|
|
217
|
+
const key = stabilityKey(text);
|
|
218
|
+
if (key === lastKey) {
|
|
219
|
+
stableCount++;
|
|
220
|
+
} else {
|
|
221
|
+
stableCount = 1;
|
|
222
|
+
lastKey = key;
|
|
223
|
+
}
|
|
224
|
+
if (stableCount >= stabilityThreshold && now() >= cooldownUntil) {
|
|
225
|
+
console.error(`[wedge-watchdog] ${opts.agentName}: dismissing stuck blocking prompt ` + `(Esc) after ${stableCount} stable polls (~${stableCount * pollIntervalMs / 1000}s) \u2014 no human to answer it`);
|
|
226
|
+
try {
|
|
227
|
+
send(opts.agentName, ["Escape"]);
|
|
228
|
+
} catch (err) {
|
|
229
|
+
console.error(`[wedge-watchdog] ${opts.agentName}: send threw: ${err.message}`);
|
|
230
|
+
}
|
|
231
|
+
fires++;
|
|
232
|
+
cooldownUntil = now() + cooldownMs;
|
|
233
|
+
stableCount = 0;
|
|
234
|
+
lastKey = null;
|
|
235
|
+
}
|
|
236
|
+
} else {
|
|
237
|
+
stableCount = 0;
|
|
238
|
+
lastKey = null;
|
|
239
|
+
}
|
|
240
|
+
await sleep(pollIntervalMs);
|
|
241
|
+
}
|
|
242
|
+
return { fires, polls, reason: "max-polls" };
|
|
243
|
+
}
|
|
244
|
+
|
|
113
245
|
// src/cli/autoaccept-poll.ts
|
|
114
246
|
async function main() {
|
|
115
247
|
const agentName = process.argv[2];
|
|
@@ -119,9 +251,20 @@ async function main() {
|
|
|
119
251
|
}
|
|
120
252
|
try {
|
|
121
253
|
const res = await runAutoaccept({ agentName });
|
|
122
|
-
console.error(`[autoaccept-poll] ${agentName}: done reason=${res.reason} fired=${res.fired.length ? res.fired.join(",") : "(none)"}`);
|
|
254
|
+
console.error(`[autoaccept-poll] ${agentName}: boot done reason=${res.reason} fired=${res.fired.length ? res.fired.join(",") : "(none)"}`);
|
|
255
|
+
} catch (err) {
|
|
256
|
+
console.error(`[autoaccept-poll] ${agentName}: boot unexpected throw: ${err.message}`);
|
|
257
|
+
}
|
|
258
|
+
if (process.env.SWITCHROOM_WEDGE_WATCHDOG === "0") {
|
|
259
|
+
console.error(`[autoaccept-poll] ${agentName}: wedge-watchdog disabled (SWITCHROOM_WEDGE_WATCHDOG=0) \u2014 exiting after boot phase`);
|
|
260
|
+
process.exit(0);
|
|
261
|
+
}
|
|
262
|
+
try {
|
|
263
|
+
console.error(`[autoaccept-poll] ${agentName}: entering wedge-watchdog (continuous)`);
|
|
264
|
+
const res = await runWedgeWatchdog({ agentName });
|
|
265
|
+
console.error(`[autoaccept-poll] ${agentName}: wedge-watchdog returned reason=${res.reason} fires=${res.fires}`);
|
|
123
266
|
} catch (err) {
|
|
124
|
-
console.error(`[autoaccept-poll] ${agentName}: unexpected throw: ${err.message}`);
|
|
267
|
+
console.error(`[autoaccept-poll] ${agentName}: wedge-watchdog unexpected throw: ${err.message}`);
|
|
125
268
|
}
|
|
126
269
|
process.exit(0);
|
|
127
270
|
}
|
|
@@ -11966,6 +11966,7 @@ var profileFields = {
|
|
|
11966
11966
|
}).optional()
|
|
11967
11967
|
}).optional(),
|
|
11968
11968
|
schedule: exports_external.array(ScheduleEntrySchema).optional(),
|
|
11969
|
+
secrets: exports_external.array(exports_external.string().regex(/^[a-zA-Z0-9_\-/]+$/, "Secret key names must contain only alphanumeric characters, underscores, hyphens, and forward slashes")).optional().describe("Operator-granted STANDING vault keys this agent may read via the " + "broker \u2014 independent of any cron or MCP server. Use when an agent " + "needs a credential both interactively and in its own (agent-managed) " + "schedules, so the grant lives with the agent rather than welded to a " + "specific cron's `secrets[]`. OPERATOR-SET ONLY: agents cannot edit " + "switchroom.yaml or self-grant (reference/vision.md outcome 2 \u2014 'you " + "hold the leash; only your tap grants it'). Exact key names. Cascades " + "UNION across defaults -> profile -> agent (see docs/configuration.md)."),
|
|
11969
11970
|
reactions: ReactionsSchema,
|
|
11970
11971
|
model: exports_external.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._\-/\[\]:]*$/, "Model name must be alphanumeric with ._-/[]: only").optional(),
|
|
11971
11972
|
thinking_effort: exports_external.enum(["low", "medium", "high", "xhigh", "max"]).optional().describe("Adaptive-thinking effort level passed as --effort to the claude CLI. " + "lower = faster/cheaper, higher = more reasoning. Omit to use Claude's default."),
|
|
@@ -12034,6 +12035,7 @@ var AgentSchema = exports_external.object({
|
|
|
12034
12035
|
tools: AgentToolsSchema,
|
|
12035
12036
|
memory: AgentMemorySchema,
|
|
12036
12037
|
schedule: exports_external.array(ScheduleEntrySchema).default([]),
|
|
12038
|
+
secrets: exports_external.array(exports_external.string().regex(/^[a-zA-Z0-9_\-/]+$/, "Secret key names must contain only alphanumeric characters, underscores, hyphens, and forward slashes")).optional(),
|
|
12037
12039
|
reactions: ReactionsSchema,
|
|
12038
12040
|
model: exports_external.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._\-/\[\]:]*$/, "Model name must be alphanumeric with ._-/[]: only (no spaces or shell specials)").optional().describe("Claude model override (e.g., 'claude-sonnet-4-6')"),
|
|
12039
12041
|
thinking_effort: exports_external.enum(["low", "medium", "high", "xhigh", "max"]).optional().describe("Adaptive-thinking effort level passed as --effort to the claude CLI. " + "Per-agent override wins over defaults.thinking_effort. " + "lower = faster/cheaper, higher = more reasoning. Omit to use Claude's default."),
|
|
@@ -12505,6 +12507,12 @@ function mergeAgentConfig(defaultsIn, agentIn) {
|
|
|
12505
12507
|
deny: dedupe([...dDeny, ...aDeny])
|
|
12506
12508
|
};
|
|
12507
12509
|
}
|
|
12510
|
+
if (defaults.secrets || merged.secrets) {
|
|
12511
|
+
merged.secrets = dedupe([
|
|
12512
|
+
...defaults.secrets ?? [],
|
|
12513
|
+
...merged.secrets ?? []
|
|
12514
|
+
]);
|
|
12515
|
+
}
|
|
12508
12516
|
if (defaults.soul || merged.soul) {
|
|
12509
12517
|
const base = defaults.soul ?? {};
|
|
12510
12518
|
const override = merged.soul ?? {};
|
package/dist/cli/switchroom.js
CHANGED
|
@@ -13783,6 +13783,7 @@ var init_schema = __esm(() => {
|
|
|
13783
13783
|
}).optional()
|
|
13784
13784
|
}).optional(),
|
|
13785
13785
|
schedule: exports_external.array(ScheduleEntrySchema).optional(),
|
|
13786
|
+
secrets: exports_external.array(exports_external.string().regex(/^[a-zA-Z0-9_\-/]+$/, "Secret key names must contain only alphanumeric characters, underscores, hyphens, and forward slashes")).optional().describe("Operator-granted STANDING vault keys this agent may read via the " + "broker \u2014 independent of any cron or MCP server. Use when an agent " + "needs a credential both interactively and in its own (agent-managed) " + "schedules, so the grant lives with the agent rather than welded to a " + "specific cron's `secrets[]`. OPERATOR-SET ONLY: agents cannot edit " + "switchroom.yaml or self-grant (reference/vision.md outcome 2 \u2014 'you " + "hold the leash; only your tap grants it'). Exact key names. Cascades " + "UNION across defaults -> profile -> agent (see docs/configuration.md)."),
|
|
13786
13787
|
reactions: ReactionsSchema,
|
|
13787
13788
|
model: exports_external.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._\-/\[\]:]*$/, "Model name must be alphanumeric with ._-/[]: only").optional(),
|
|
13788
13789
|
thinking_effort: exports_external.enum(["low", "medium", "high", "xhigh", "max"]).optional().describe("Adaptive-thinking effort level passed as --effort to the claude CLI. " + "lower = faster/cheaper, higher = more reasoning. Omit to use Claude's default."),
|
|
@@ -13851,6 +13852,7 @@ var init_schema = __esm(() => {
|
|
|
13851
13852
|
tools: AgentToolsSchema,
|
|
13852
13853
|
memory: AgentMemorySchema,
|
|
13853
13854
|
schedule: exports_external.array(ScheduleEntrySchema).default([]),
|
|
13855
|
+
secrets: exports_external.array(exports_external.string().regex(/^[a-zA-Z0-9_\-/]+$/, "Secret key names must contain only alphanumeric characters, underscores, hyphens, and forward slashes")).optional(),
|
|
13854
13856
|
reactions: ReactionsSchema,
|
|
13855
13857
|
model: exports_external.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._\-/\[\]:]*$/, "Model name must be alphanumeric with ._-/[]: only (no spaces or shell specials)").optional().describe("Claude model override (e.g., 'claude-sonnet-4-6')"),
|
|
13856
13858
|
thinking_effort: exports_external.enum(["low", "medium", "high", "xhigh", "max"]).optional().describe("Adaptive-thinking effort level passed as --effort to the claude CLI. " + "Per-agent override wins over defaults.thinking_effort. " + "lower = faster/cheaper, higher = more reasoning. Omit to use Claude's default."),
|
|
@@ -14372,6 +14374,12 @@ function mergeAgentConfig(defaultsIn, agentIn) {
|
|
|
14372
14374
|
deny: dedupe([...dDeny, ...aDeny])
|
|
14373
14375
|
};
|
|
14374
14376
|
}
|
|
14377
|
+
if (defaults.secrets || merged.secrets) {
|
|
14378
|
+
merged.secrets = dedupe([
|
|
14379
|
+
...defaults.secrets ?? [],
|
|
14380
|
+
...merged.secrets ?? []
|
|
14381
|
+
]);
|
|
14382
|
+
}
|
|
14375
14383
|
if (defaults.soul || merged.soul) {
|
|
14376
14384
|
const base = defaults.soul ?? {};
|
|
14377
14385
|
const override = merged.soul ?? {};
|
|
@@ -27941,11 +27949,21 @@ function checkAclByAgent(config, agentName, key) {
|
|
|
27941
27949
|
return { allow: true };
|
|
27942
27950
|
}
|
|
27943
27951
|
}
|
|
27952
|
+
const cfgSecrets = config;
|
|
27953
|
+
const profileSecrets = profileName != null && profileName.length > 0 ? cfgSecrets.profiles?.[profileName]?.secrets : undefined;
|
|
27954
|
+
const standingSecrets = [
|
|
27955
|
+
...Array.isArray(cfgSecrets.defaults?.secrets) ? cfgSecrets.defaults.secrets : [],
|
|
27956
|
+
...Array.isArray(profileSecrets) ? profileSecrets : [],
|
|
27957
|
+
...Array.isArray(agentConfig.secrets) ? agentConfig.secrets : []
|
|
27958
|
+
];
|
|
27959
|
+
if (standingSecrets.includes(key)) {
|
|
27960
|
+
return { allow: true };
|
|
27961
|
+
}
|
|
27944
27962
|
const schedule = agentConfig.schedule ?? [];
|
|
27945
27963
|
if (schedule.length === 0) {
|
|
27946
27964
|
return {
|
|
27947
27965
|
allow: false,
|
|
27948
|
-
reason: `agent '${agentName}' has no schedule entries declaring 'secrets'
|
|
27966
|
+
reason: `agent '${agentName}' has no schedule entries declaring 'secrets', no mcp_servers.*.secrets[], and no agents.${agentName}.secrets[] standing grant declaring '${key}'; nothing is broker-accessible`
|
|
27949
27967
|
};
|
|
27950
27968
|
}
|
|
27951
27969
|
for (const entry of schedule) {
|
|
@@ -49420,8 +49438,8 @@ var {
|
|
|
49420
49438
|
} = import__.default;
|
|
49421
49439
|
|
|
49422
49440
|
// src/build-info.ts
|
|
49423
|
-
var VERSION = "0.14.
|
|
49424
|
-
var COMMIT_SHA = "
|
|
49441
|
+
var VERSION = "0.14.34";
|
|
49442
|
+
var COMMIT_SHA = "05829ce8";
|
|
49425
49443
|
|
|
49426
49444
|
// src/cli/agent.ts
|
|
49427
49445
|
init_source();
|
|
@@ -50523,6 +50541,7 @@ var DEFAULT_READ_ONLY_PREAPPROVED_TOOLS = [
|
|
|
50523
50541
|
"Skill"
|
|
50524
50542
|
];
|
|
50525
50543
|
var WEBKITE_FLEET_DENY_TOOLS = ["WebFetch", "WebSearch"];
|
|
50544
|
+
var INTERACTIVE_TUI_FLEET_DENY_TOOLS = ["AskUserQuestion"];
|
|
50526
50545
|
var WEBKITE_BINARY_CONTAINER_PATH = "/usr/local/bin/webkite";
|
|
50527
50546
|
function webkiteBinaryAvailable() {
|
|
50528
50547
|
const override = process.env.SWITCHROOM_WEBKITE_BINARY;
|
|
@@ -51107,7 +51126,8 @@ function buildWorkspaceContext(args) {
|
|
|
51107
51126
|
tools,
|
|
51108
51127
|
toolsDeny: dedupe2([
|
|
51109
51128
|
...tools.deny ?? [],
|
|
51110
|
-
...webkiteDenyForAgent(agentConfig)
|
|
51129
|
+
...webkiteDenyForAgent(agentConfig),
|
|
51130
|
+
...INTERACTIVE_TUI_FLEET_DENY_TOOLS
|
|
51111
51131
|
]),
|
|
51112
51132
|
permissionAllow,
|
|
51113
51133
|
defaultModeAcceptEdits: hasAllWildcard,
|
|
@@ -51392,6 +51412,12 @@ function scaffoldAgent(name, agentConfigRaw, agentsDir, telegramConfig, switchro
|
|
|
51392
51412
|
allow.push(t);
|
|
51393
51413
|
}
|
|
51394
51414
|
settings.permissions.allow = allow;
|
|
51415
|
+
const deny = Array.isArray(settings.permissions.deny) ? settings.permissions.deny : [];
|
|
51416
|
+
for (const t of INTERACTIVE_TUI_FLEET_DENY_TOOLS) {
|
|
51417
|
+
if (!deny.includes(t))
|
|
51418
|
+
deny.push(t);
|
|
51419
|
+
}
|
|
51420
|
+
settings.permissions.deny = deny;
|
|
51395
51421
|
if (settings.mcpServers && "switchroom" in settings.mcpServers) {
|
|
51396
51422
|
delete settings.mcpServers["switchroom"];
|
|
51397
51423
|
}
|
|
@@ -52126,7 +52152,8 @@ function reconcileAgent(name, agentConfigRaw, agentsDir, telegramConfig, switchr
|
|
|
52126
52152
|
]);
|
|
52127
52153
|
const desiredDeny = dedupe2([
|
|
52128
52154
|
...tools.deny ?? [],
|
|
52129
|
-
...webkiteDenyForAgent(agentConfig)
|
|
52155
|
+
...webkiteDenyForAgent(agentConfig),
|
|
52156
|
+
...INTERACTIVE_TUI_FLEET_DENY_TOOLS
|
|
52130
52157
|
]);
|
|
52131
52158
|
let topicId = agentConfig.topic_id;
|
|
52132
52159
|
if (topicId === undefined) {
|
|
@@ -13954,6 +13954,7 @@ var profileFields = {
|
|
|
13954
13954
|
}).optional()
|
|
13955
13955
|
}).optional(),
|
|
13956
13956
|
schedule: exports_external.array(ScheduleEntrySchema).optional(),
|
|
13957
|
+
secrets: exports_external.array(exports_external.string().regex(/^[a-zA-Z0-9_\-/]+$/, "Secret key names must contain only alphanumeric characters, underscores, hyphens, and forward slashes")).optional().describe("Operator-granted STANDING vault keys this agent may read via the " + "broker — independent of any cron or MCP server. Use when an agent " + "needs a credential both interactively and in its own (agent-managed) " + "schedules, so the grant lives with the agent rather than welded to a " + "specific cron's `secrets[]`. OPERATOR-SET ONLY: agents cannot edit " + "switchroom.yaml or self-grant (reference/vision.md outcome 2 — 'you " + "hold the leash; only your tap grants it'). Exact key names. Cascades " + "UNION across defaults -> profile -> agent (see docs/configuration.md)."),
|
|
13957
13958
|
reactions: ReactionsSchema,
|
|
13958
13959
|
model: exports_external.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._\-/\[\]:]*$/, "Model name must be alphanumeric with ._-/[]: only").optional(),
|
|
13959
13960
|
thinking_effort: exports_external.enum(["low", "medium", "high", "xhigh", "max"]).optional().describe("Adaptive-thinking effort level passed as --effort to the claude CLI. " + "lower = faster/cheaper, higher = more reasoning. Omit to use Claude's default."),
|
|
@@ -14022,6 +14023,7 @@ var AgentSchema = exports_external.object({
|
|
|
14022
14023
|
tools: AgentToolsSchema,
|
|
14023
14024
|
memory: AgentMemorySchema,
|
|
14024
14025
|
schedule: exports_external.array(ScheduleEntrySchema).default([]),
|
|
14026
|
+
secrets: exports_external.array(exports_external.string().regex(/^[a-zA-Z0-9_\-/]+$/, "Secret key names must contain only alphanumeric characters, underscores, hyphens, and forward slashes")).optional(),
|
|
14025
14027
|
reactions: ReactionsSchema,
|
|
14026
14028
|
model: exports_external.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._\-/\[\]:]*$/, "Model name must be alphanumeric with ._-/[]: only (no spaces or shell specials)").optional().describe("Claude model override (e.g., 'claude-sonnet-4-6')"),
|
|
14027
14029
|
thinking_effort: exports_external.enum(["low", "medium", "high", "xhigh", "max"]).optional().describe("Adaptive-thinking effort level passed as --effort to the claude CLI. " + "Per-agent override wins over defaults.thinking_effort. " + "lower = faster/cheaper, higher = more reasoning. Omit to use Claude's default."),
|
|
@@ -14501,6 +14503,12 @@ function mergeAgentConfig(defaultsIn, agentIn) {
|
|
|
14501
14503
|
deny: dedupe([...dDeny, ...aDeny])
|
|
14502
14504
|
};
|
|
14503
14505
|
}
|
|
14506
|
+
if (defaults.secrets || merged.secrets) {
|
|
14507
|
+
merged.secrets = dedupe([
|
|
14508
|
+
...defaults.secrets ?? [],
|
|
14509
|
+
...merged.secrets ?? []
|
|
14510
|
+
]);
|
|
14511
|
+
}
|
|
14504
14512
|
if (defaults.soul || merged.soul) {
|
|
14505
14513
|
const base = defaults.soul ?? {};
|
|
14506
14514
|
const override = merged.soul ?? {};
|
|
@@ -14918,7 +14926,11 @@ import {
|
|
|
14918
14926
|
writeFileSync as writeFileSync3,
|
|
14919
14927
|
renameSync,
|
|
14920
14928
|
mkdirSync as mkdirSync2,
|
|
14921
|
-
|
|
14929
|
+
openSync as openSync2,
|
|
14930
|
+
ftruncateSync,
|
|
14931
|
+
writeSync,
|
|
14932
|
+
fsyncSync,
|
|
14933
|
+
closeSync as closeSync2
|
|
14922
14934
|
} from "node:fs";
|
|
14923
14935
|
import { join as join3, dirname as dirname4, resolve as resolve5 } from "node:path";
|
|
14924
14936
|
import { randomUUID as randomUUID2, randomBytes } from "node:crypto";
|
|
@@ -20740,10 +20752,23 @@ function formatConfigApprovalDenyError(approval, approvalId) {
|
|
|
20740
20752
|
const suffix = approval.reason ? `: ${approval.reason}` : "";
|
|
20741
20753
|
return `E_DENIED: operator denied config_propose_edit${suffix} (approval_id=${approvalId})`;
|
|
20742
20754
|
}
|
|
20743
|
-
function
|
|
20755
|
+
function writeFileInPlacePreservingInode(targetPath, content) {
|
|
20756
|
+
const buf = Buffer.from(content, "utf-8");
|
|
20757
|
+
const fd = openSync2(targetPath, "r+");
|
|
20744
20758
|
try {
|
|
20745
|
-
|
|
20746
|
-
|
|
20759
|
+
ftruncateSync(fd, 0);
|
|
20760
|
+
let off = 0;
|
|
20761
|
+
while (off < buf.length) {
|
|
20762
|
+
off += writeSync(fd, buf, off, buf.length - off, off);
|
|
20763
|
+
}
|
|
20764
|
+
fsyncSync(fd);
|
|
20765
|
+
} finally {
|
|
20766
|
+
closeSync2(fd);
|
|
20767
|
+
}
|
|
20768
|
+
const readBack = readFileSync5(targetPath);
|
|
20769
|
+
if (readBack.length !== buf.length) {
|
|
20770
|
+
throw new Error(`in-place write short: wrote ${buf.length} bytes but read back ${readBack.length}`);
|
|
20771
|
+
}
|
|
20747
20772
|
}
|
|
20748
20773
|
var STATUS_RETENTION_MS = 10 * 60 * 1000;
|
|
20749
20774
|
var STATUS_MAX_ENTRIES = 256;
|
|
@@ -21341,15 +21366,15 @@ class HostdServer {
|
|
|
21341
21366
|
return this.reconcileFailedRolledBack(`snapshot read failed: ${e.message}`, req, caller, started);
|
|
21342
21367
|
}
|
|
21343
21368
|
const postApply = verdict.postApplyContent;
|
|
21344
|
-
const tmp = configPath + ".tmp";
|
|
21345
21369
|
try {
|
|
21346
|
-
|
|
21347
|
-
renameSync(tmp, configPath);
|
|
21370
|
+
writeFileInPlacePreservingInode(configPath, postApply);
|
|
21348
21371
|
} catch (e) {
|
|
21349
|
-
|
|
21372
|
+
try {
|
|
21373
|
+
writeFileInPlacePreservingInode(configPath, snapshot);
|
|
21374
|
+
} catch {}
|
|
21350
21375
|
await approval.finalize({
|
|
21351
21376
|
outcome: "reconcile_failed_rolled_back",
|
|
21352
|
-
detail: `
|
|
21377
|
+
detail: `in-place write failed: ${e.message}`
|
|
21353
21378
|
});
|
|
21354
21379
|
return this.reconcileFailedRolledBack(`write failed: ${e.message}`, req, caller, started);
|
|
21355
21380
|
}
|
|
@@ -21369,8 +21394,7 @@ class HostdServer {
|
|
|
21369
21394
|
}
|
|
21370
21395
|
let rollbackDetail = "";
|
|
21371
21396
|
try {
|
|
21372
|
-
|
|
21373
|
-
renameSync(tmp, configPath);
|
|
21397
|
+
writeFileInPlacePreservingInode(configPath, snapshot);
|
|
21374
21398
|
} catch (e) {
|
|
21375
21399
|
rollbackDetail = `snapshot restore failed: ${e.message}`;
|
|
21376
21400
|
await approval.finalize({
|
|
@@ -4106,6 +4106,12 @@ function mergeAgentConfig(defaultsIn, agentIn) {
|
|
|
4106
4106
|
deny: dedupe([...dDeny, ...aDeny])
|
|
4107
4107
|
};
|
|
4108
4108
|
}
|
|
4109
|
+
if (defaults.secrets || merged.secrets) {
|
|
4110
|
+
merged.secrets = dedupe([
|
|
4111
|
+
...defaults.secrets ?? [],
|
|
4112
|
+
...merged.secrets ?? []
|
|
4113
|
+
]);
|
|
4114
|
+
}
|
|
4109
4115
|
if (defaults.soul || merged.soul) {
|
|
4110
4116
|
const base = defaults.soul ?? {};
|
|
4111
4117
|
const override = merged.soul ?? {};
|
|
@@ -11534,6 +11540,7 @@ var init_schema = __esm(() => {
|
|
|
11534
11540
|
}).optional()
|
|
11535
11541
|
}).optional(),
|
|
11536
11542
|
schedule: exports_external.array(ScheduleEntrySchema).optional(),
|
|
11543
|
+
secrets: exports_external.array(exports_external.string().regex(/^[a-zA-Z0-9_\-/]+$/, "Secret key names must contain only alphanumeric characters, underscores, hyphens, and forward slashes")).optional().describe("Operator-granted STANDING vault keys this agent may read via the " + "broker — independent of any cron or MCP server. Use when an agent " + "needs a credential both interactively and in its own (agent-managed) " + "schedules, so the grant lives with the agent rather than welded to a " + "specific cron's `secrets[]`. OPERATOR-SET ONLY: agents cannot edit " + "switchroom.yaml or self-grant (reference/vision.md outcome 2 — 'you " + "hold the leash; only your tap grants it'). Exact key names. Cascades " + "UNION across defaults -> profile -> agent (see docs/configuration.md)."),
|
|
11537
11544
|
reactions: ReactionsSchema,
|
|
11538
11545
|
model: exports_external.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._\-/\[\]:]*$/, "Model name must be alphanumeric with ._-/[]: only").optional(),
|
|
11539
11546
|
thinking_effort: exports_external.enum(["low", "medium", "high", "xhigh", "max"]).optional().describe("Adaptive-thinking effort level passed as --effort to the claude CLI. " + "lower = faster/cheaper, higher = more reasoning. Omit to use Claude's default."),
|
|
@@ -11602,6 +11609,7 @@ var init_schema = __esm(() => {
|
|
|
11602
11609
|
tools: AgentToolsSchema,
|
|
11603
11610
|
memory: AgentMemorySchema,
|
|
11604
11611
|
schedule: exports_external.array(ScheduleEntrySchema).default([]),
|
|
11612
|
+
secrets: exports_external.array(exports_external.string().regex(/^[a-zA-Z0-9_\-/]+$/, "Secret key names must contain only alphanumeric characters, underscores, hyphens, and forward slashes")).optional(),
|
|
11605
11613
|
reactions: ReactionsSchema,
|
|
11606
11614
|
model: exports_external.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._\-/\[\]:]*$/, "Model name must be alphanumeric with ._-/[]: only (no spaces or shell specials)").optional().describe("Claude model override (e.g., 'claude-sonnet-4-6')"),
|
|
11607
11615
|
thinking_effort: exports_external.enum(["low", "medium", "high", "xhigh", "max"]).optional().describe("Adaptive-thinking effort level passed as --effort to the claude CLI. " + "Per-agent override wins over defaults.thinking_effort. " + "lower = faster/cheaper, higher = more reasoning. Omit to use Claude's default."),
|
|
@@ -140,6 +140,12 @@ function mergeAgentConfig(defaultsIn, agentIn) {
|
|
|
140
140
|
deny: dedupe([...dDeny, ...aDeny])
|
|
141
141
|
};
|
|
142
142
|
}
|
|
143
|
+
if (defaults.secrets || merged.secrets) {
|
|
144
|
+
merged.secrets = dedupe([
|
|
145
|
+
...defaults.secrets ?? [],
|
|
146
|
+
...merged.secrets ?? []
|
|
147
|
+
]);
|
|
148
|
+
}
|
|
143
149
|
if (defaults.soul || merged.soul) {
|
|
144
150
|
const base = defaults.soul ?? {};
|
|
145
151
|
const override = merged.soul ?? {};
|
|
@@ -11534,6 +11540,7 @@ var init_schema = __esm(() => {
|
|
|
11534
11540
|
}).optional()
|
|
11535
11541
|
}).optional(),
|
|
11536
11542
|
schedule: exports_external.array(ScheduleEntrySchema).optional(),
|
|
11543
|
+
secrets: exports_external.array(exports_external.string().regex(/^[a-zA-Z0-9_\-/]+$/, "Secret key names must contain only alphanumeric characters, underscores, hyphens, and forward slashes")).optional().describe("Operator-granted STANDING vault keys this agent may read via the " + "broker — independent of any cron or MCP server. Use when an agent " + "needs a credential both interactively and in its own (agent-managed) " + "schedules, so the grant lives with the agent rather than welded to a " + "specific cron's `secrets[]`. OPERATOR-SET ONLY: agents cannot edit " + "switchroom.yaml or self-grant (reference/vision.md outcome 2 — 'you " + "hold the leash; only your tap grants it'). Exact key names. Cascades " + "UNION across defaults -> profile -> agent (see docs/configuration.md)."),
|
|
11537
11544
|
reactions: ReactionsSchema,
|
|
11538
11545
|
model: exports_external.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._\-/\[\]:]*$/, "Model name must be alphanumeric with ._-/[]: only").optional(),
|
|
11539
11546
|
thinking_effort: exports_external.enum(["low", "medium", "high", "xhigh", "max"]).optional().describe("Adaptive-thinking effort level passed as --effort to the claude CLI. " + "lower = faster/cheaper, higher = more reasoning. Omit to use Claude's default."),
|
|
@@ -11602,6 +11609,7 @@ var init_schema = __esm(() => {
|
|
|
11602
11609
|
tools: AgentToolsSchema,
|
|
11603
11610
|
memory: AgentMemorySchema,
|
|
11604
11611
|
schedule: exports_external.array(ScheduleEntrySchema).default([]),
|
|
11612
|
+
secrets: exports_external.array(exports_external.string().regex(/^[a-zA-Z0-9_\-/]+$/, "Secret key names must contain only alphanumeric characters, underscores, hyphens, and forward slashes")).optional(),
|
|
11605
11613
|
reactions: ReactionsSchema,
|
|
11606
11614
|
model: exports_external.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._\-/\[\]:]*$/, "Model name must be alphanumeric with ._-/[]: only (no spaces or shell specials)").optional().describe("Claude model override (e.g., 'claude-sonnet-4-6')"),
|
|
11607
11615
|
thinking_effort: exports_external.enum(["low", "medium", "high", "xhigh", "max"]).optional().describe("Adaptive-thinking effort level passed as --effort to the claude CLI. " + "Per-agent override wins over defaults.thinking_effort. " + "lower = faster/cheaper, higher = more reasoning. Omit to use Claude's default."),
|
|
@@ -13288,11 +13296,21 @@ function checkAclByAgent(config, agentName, key) {
|
|
|
13288
13296
|
return { allow: true };
|
|
13289
13297
|
}
|
|
13290
13298
|
}
|
|
13299
|
+
const cfgSecrets = config;
|
|
13300
|
+
const profileSecrets = profileName != null && profileName.length > 0 ? cfgSecrets.profiles?.[profileName]?.secrets : undefined;
|
|
13301
|
+
const standingSecrets = [
|
|
13302
|
+
...Array.isArray(cfgSecrets.defaults?.secrets) ? cfgSecrets.defaults.secrets : [],
|
|
13303
|
+
...Array.isArray(profileSecrets) ? profileSecrets : [],
|
|
13304
|
+
...Array.isArray(agentConfig.secrets) ? agentConfig.secrets : []
|
|
13305
|
+
];
|
|
13306
|
+
if (standingSecrets.includes(key)) {
|
|
13307
|
+
return { allow: true };
|
|
13308
|
+
}
|
|
13291
13309
|
const schedule = agentConfig.schedule ?? [];
|
|
13292
13310
|
if (schedule.length === 0) {
|
|
13293
13311
|
return {
|
|
13294
13312
|
allow: false,
|
|
13295
|
-
reason: `agent '${agentName}' has no schedule entries declaring 'secrets'
|
|
13313
|
+
reason: `agent '${agentName}' has no schedule entries declaring 'secrets', no mcp_servers.*.secrets[], and no agents.${agentName}.secrets[] standing grant declaring '${key}'; nothing is broker-accessible`
|
|
13296
13314
|
};
|
|
13297
13315
|
}
|
|
13298
13316
|
for (const entry of schedule) {
|
package/package.json
CHANGED
|
@@ -111,10 +111,15 @@ if [ "$SWITCHROOM_RUNTIME" = "docker" ] && [ -z "$SWITCHROOM_DOCKER_TMUX_INNER"
|
|
|
111
111
|
echo "[start.sh] channels.telegram.enabled=false — skipping gateway sidecar" >&2
|
|
112
112
|
fi
|
|
113
113
|
|
|
114
|
-
# 2) autoaccept-poll — first-run TUI prompt dispatcher
|
|
115
|
-
#
|
|
116
|
-
#
|
|
117
|
-
#
|
|
114
|
+
# 2) autoaccept-poll — first-run TUI prompt dispatcher, then continuous
|
|
115
|
+
# wedge-watchdog. Two phases in one process: a one-shot boot phase
|
|
116
|
+
# dispatches the first-run prompts and returns after idle-timeout,
|
|
117
|
+
# then the process stays alive running the wedge-watchdog (dismisses a
|
|
118
|
+
# stuck blocking modal selector mid-session — the AskUserQuestion /
|
|
119
|
+
# ExitPlanMode class — with Esc). So it is NORMALLY long-lived; the
|
|
120
|
+
# supervisor only respawns it if it crashes/exits, and its backoff
|
|
121
|
+
# keeps a flaky run from busy-looping. Set SWITCHROOM_WEDGE_WATCHDOG=0
|
|
122
|
+
# to restore the legacy boot-only single-shot behaviour.
|
|
118
123
|
if [ -f /opt/switchroom/autoaccept-poll.js ] && command -v bun >/dev/null 2>&1; then
|
|
119
124
|
_switchroom_supervise autoaccept /var/log/switchroom/autoaccept.log \
|
|
120
125
|
bun /opt/switchroom/autoaccept-poll.js "{{name}}" &
|
|
@@ -23925,6 +23925,7 @@ var init_schema = __esm(() => {
|
|
|
23925
23925
|
}).optional()
|
|
23926
23926
|
}).optional(),
|
|
23927
23927
|
schedule: exports_external.array(ScheduleEntrySchema).optional(),
|
|
23928
|
+
secrets: exports_external.array(exports_external.string().regex(/^[a-zA-Z0-9_\-/]+$/, "Secret key names must contain only alphanumeric characters, underscores, hyphens, and forward slashes")).optional().describe("Operator-granted STANDING vault keys this agent may read via the " + "broker \u2014 independent of any cron or MCP server. Use when an agent " + "needs a credential both interactively and in its own (agent-managed) " + "schedules, so the grant lives with the agent rather than welded to a " + "specific cron's `secrets[]`. OPERATOR-SET ONLY: agents cannot edit " + "switchroom.yaml or self-grant (reference/vision.md outcome 2 \u2014 'you " + "hold the leash; only your tap grants it'). Exact key names. Cascades " + "UNION across defaults -> profile -> agent (see docs/configuration.md)."),
|
|
23928
23929
|
reactions: ReactionsSchema,
|
|
23929
23930
|
model: exports_external.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._\-/\[\]:]*$/, "Model name must be alphanumeric with ._-/[]: only").optional(),
|
|
23930
23931
|
thinking_effort: exports_external.enum(["low", "medium", "high", "xhigh", "max"]).optional().describe("Adaptive-thinking effort level passed as --effort to the claude CLI. " + "lower = faster/cheaper, higher = more reasoning. Omit to use Claude's default."),
|
|
@@ -23993,6 +23994,7 @@ var init_schema = __esm(() => {
|
|
|
23993
23994
|
tools: AgentToolsSchema,
|
|
23994
23995
|
memory: AgentMemorySchema,
|
|
23995
23996
|
schedule: exports_external.array(ScheduleEntrySchema).default([]),
|
|
23997
|
+
secrets: exports_external.array(exports_external.string().regex(/^[a-zA-Z0-9_\-/]+$/, "Secret key names must contain only alphanumeric characters, underscores, hyphens, and forward slashes")).optional(),
|
|
23996
23998
|
reactions: ReactionsSchema,
|
|
23997
23999
|
model: exports_external.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._\-/\[\]:]*$/, "Model name must be alphanumeric with ._-/[]: only (no spaces or shell specials)").optional().describe("Claude model override (e.g., 'claude-sonnet-4-6')"),
|
|
23998
24000
|
thinking_effort: exports_external.enum(["low", "medium", "high", "xhigh", "max"]).optional().describe("Adaptive-thinking effort level passed as --effort to the claude CLI. " + "Per-agent override wins over defaults.thinking_effort. " + "lower = faster/cheaper, higher = more reasoning. Omit to use Claude's default."),
|
|
@@ -24472,6 +24474,12 @@ function mergeAgentConfig(defaultsIn, agentIn) {
|
|
|
24472
24474
|
deny: dedupe([...dDeny, ...aDeny])
|
|
24473
24475
|
};
|
|
24474
24476
|
}
|
|
24477
|
+
if (defaults.secrets || merged.secrets) {
|
|
24478
|
+
merged.secrets = dedupe([
|
|
24479
|
+
...defaults.secrets ?? [],
|
|
24480
|
+
...merged.secrets ?? []
|
|
24481
|
+
]);
|
|
24482
|
+
}
|
|
24475
24483
|
if (defaults.soul || merged.soul) {
|
|
24476
24484
|
const base = defaults.soul ?? {};
|
|
24477
24485
|
const override = merged.soul ?? {};
|
|
@@ -44481,6 +44489,12 @@ function mergeAgentConfig2(defaultsIn, agentIn) {
|
|
|
44481
44489
|
deny: dedupe2([...dDeny, ...aDeny])
|
|
44482
44490
|
};
|
|
44483
44491
|
}
|
|
44492
|
+
if (defaults.secrets || merged.secrets) {
|
|
44493
|
+
merged.secrets = dedupe2([
|
|
44494
|
+
...defaults.secrets ?? [],
|
|
44495
|
+
...merged.secrets ?? []
|
|
44496
|
+
]);
|
|
44497
|
+
}
|
|
44484
44498
|
if (defaults.soul || merged.soul) {
|
|
44485
44499
|
const base = defaults.soul ?? {};
|
|
44486
44500
|
const override = merged.soul ?? {};
|
|
@@ -51766,10 +51780,10 @@ function sweepStaleTurnActiveMarker(stateDir, opts) {
|
|
|
51766
51780
|
}
|
|
51767
51781
|
|
|
51768
51782
|
// ../src/build-info.ts
|
|
51769
|
-
var VERSION = "0.14.
|
|
51770
|
-
var COMMIT_SHA = "
|
|
51771
|
-
var COMMIT_DATE = "2026-06-
|
|
51772
|
-
var LATEST_PR =
|
|
51783
|
+
var VERSION = "0.14.34";
|
|
51784
|
+
var COMMIT_SHA = "05829ce8";
|
|
51785
|
+
var COMMIT_DATE = "2026-06-01T13:11:35Z";
|
|
51786
|
+
var LATEST_PR = 2068;
|
|
51773
51787
|
var COMMITS_AHEAD_OF_TAG = 0;
|
|
51774
51788
|
|
|
51775
51789
|
// gateway/boot-version.ts
|