switchroom 0.13.5 → 0.13.8
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 +5 -0
- package/dist/auth-broker/index.js +5 -0
- package/dist/cli/switchroom.js +144 -64
- package/dist/host-control/main.js +402 -27
- package/dist/vault/approvals/kernel-server.js +6 -1
- package/dist/vault/broker/server.js +6 -1
- package/package.json +1 -1
- package/profiles/_shared/telegram-style.md.hbs +12 -11
- package/profiles/default/CLAUDE.md +12 -11
- package/telegram-plugin/dist/bridge/bridge.js +24 -0
- package/telegram-plugin/dist/gateway/gateway.js +49 -7
- package/telegram-plugin/dist/server.js +24 -0
- package/telegram-plugin/gateway/gateway.ts +46 -1
- package/telegram-plugin/model-unavailable.ts +4 -0
- package/telegram-plugin/session-tail.ts +53 -0
- package/telegram-plugin/tests/model-unavailable.test.ts +9 -0
- package/telegram-plugin/tests/operator-events-session-tail.test.ts +43 -0
|
@@ -11307,6 +11307,10 @@ var QuotaConfigSchema = exports_external.object({
|
|
|
11307
11307
|
var HostControlConfigSchema = exports_external.object({
|
|
11308
11308
|
enabled: exports_external.boolean().default(true).describe("Whether the host-control daemon is in use. Default: true (since " + "RFC C Phase 2 default-flip — the gateway's /restart, /new, /reset, " + "and /update apply slash-commands all dispatch through hostd, and " + "without it those verbs fail on docker-mode installs because the " + "agent container has no docker binary/socket). " + "When true, the compose generator emits per-agent bind mounts " + "at `~/.switchroom/hostd/<name>/sock` for every admin-flagged " + "agent. Install the daemon with `switchroom hostd install` — " + "it runs as a docker container in its own compose project " + "(`switchroom-hostd`), separate from the agent fleet's compose " + "project so `up -d --remove-orphans` cycles of the fleet " + "can't recreate the daemon mid-RPC. See RFC C §5.1. " + "Set enabled: false only on legacy systemd-mode installs that " + "still rely on the in-container `spawnSwitchroomDetached` " + "shellout (removal is tracked as RFC C Phase 3).")
|
|
11309
11309
|
});
|
|
11310
|
+
var HostdConfigSchema = exports_external.object({
|
|
11311
|
+
config_edit_enabled: exports_external.boolean().default(false).describe("Opt-in toggle for the `config_propose_edit` hostd verb (RFC " + "admin-agent-config-edit §3). Default false — the verb returns " + "`E_CONFIG_EDIT_DISABLED` until the operator explicitly flips " + "this to true. When true (and once PR 1c lands the apply path), " + "admin agents can propose unified-diff patches against " + "`/state/config/switchroom.yaml`, gated by an operator approval " + "card in the primary chat. Same trust posture as `update_apply` " + "and `agent_restart`: the human-in-the-loop tap is the security " + "boundary, not the agent's judgement."),
|
|
11312
|
+
config_edit_rate_per_hour: exports_external.number().int().min(1).max(20).default(3).describe("Per-requesting-agent rate cap for `config_propose_edit` cards " + "(RFC admin-agent-config-edit §5). Default 3 cards/hour; min 1, " + "max 20. Implemented as a sqlite token bucket in PR 1c; the " + "field is wired here in PR 1a so operators can pin it before the " + "limiter is live. Above the cap, the verb returns " + "`E_RATE_LIMITED` without raising a card.")
|
|
11313
|
+
});
|
|
11310
11314
|
var SwitchroomConfigSchema = exports_external.object({
|
|
11311
11315
|
switchroom: exports_external.object({
|
|
11312
11316
|
version: exports_external.literal(1).describe("Config schema version"),
|
|
@@ -11333,6 +11337,7 @@ var SwitchroomConfigSchema = exports_external.object({
|
|
|
11333
11337
|
google_workspace: GoogleWorkspaceConfigSchema.describe("RFC G canonical key. Top-level Google Workspace configuration — " + "OAuth client credentials, approver allowlist, and tier knob (`core` " + "| `extended` | `complete`, default `core`). Mutually exclusive with " + "`drive:` at the top level (loader fails fast if both are set)."),
|
|
11334
11338
|
quota: QuotaConfigSchema.optional().describe("Optional weekly/monthly USD spend budgets rendered in the session " + "greeting. Usage is read from ccusage at runtime; no network calls."),
|
|
11335
11339
|
host_control: HostControlConfigSchema.default({}).describe("Host-control daemon configuration. Defaults to enabled=true since " + "RFC C Phase 2 (docs/rfcs/host-control-daemon.md). Omit the block " + "to accept defaults; set `enabled: false` only on legacy systemd-" + "mode installs (removal tracked as RFC C Phase 3)."),
|
|
11340
|
+
hostd: HostdConfigSchema.default({}).describe("hostd verb-level knobs (RFC admin-agent-config-edit). Distinct " + "from `host_control:` which governs whether the daemon runs at " + "all. Currently scopes the opt-in flag and rate cap for the new " + "`config_propose_edit` verb (PR 1a — disabled by default)."),
|
|
11336
11341
|
google_accounts: exports_external.record(exports_external.string().regex(/^[^@\s:]+@[^@\s:]+\.[^@\s:]+$/, {
|
|
11337
11342
|
message: "Account key must be a Google account email like 'alice@example.com' (colons not allowed)"
|
|
11338
11343
|
}).transform((v) => v.trim().toLowerCase()), exports_external.object({
|
|
@@ -11307,6 +11307,10 @@ var QuotaConfigSchema = exports_external.object({
|
|
|
11307
11307
|
var HostControlConfigSchema = exports_external.object({
|
|
11308
11308
|
enabled: exports_external.boolean().default(true).describe("Whether the host-control daemon is in use. Default: true (since " + "RFC C Phase 2 default-flip — the gateway's /restart, /new, /reset, " + "and /update apply slash-commands all dispatch through hostd, and " + "without it those verbs fail on docker-mode installs because the " + "agent container has no docker binary/socket). " + "When true, the compose generator emits per-agent bind mounts " + "at `~/.switchroom/hostd/<name>/sock` for every admin-flagged " + "agent. Install the daemon with `switchroom hostd install` — " + "it runs as a docker container in its own compose project " + "(`switchroom-hostd`), separate from the agent fleet's compose " + "project so `up -d --remove-orphans` cycles of the fleet " + "can't recreate the daemon mid-RPC. See RFC C §5.1. " + "Set enabled: false only on legacy systemd-mode installs that " + "still rely on the in-container `spawnSwitchroomDetached` " + "shellout (removal is tracked as RFC C Phase 3).")
|
|
11309
11309
|
});
|
|
11310
|
+
var HostdConfigSchema = exports_external.object({
|
|
11311
|
+
config_edit_enabled: exports_external.boolean().default(false).describe("Opt-in toggle for the `config_propose_edit` hostd verb (RFC " + "admin-agent-config-edit §3). Default false — the verb returns " + "`E_CONFIG_EDIT_DISABLED` until the operator explicitly flips " + "this to true. When true (and once PR 1c lands the apply path), " + "admin agents can propose unified-diff patches against " + "`/state/config/switchroom.yaml`, gated by an operator approval " + "card in the primary chat. Same trust posture as `update_apply` " + "and `agent_restart`: the human-in-the-loop tap is the security " + "boundary, not the agent's judgement."),
|
|
11312
|
+
config_edit_rate_per_hour: exports_external.number().int().min(1).max(20).default(3).describe("Per-requesting-agent rate cap for `config_propose_edit` cards " + "(RFC admin-agent-config-edit §5). Default 3 cards/hour; min 1, " + "max 20. Implemented as a sqlite token bucket in PR 1c; the " + "field is wired here in PR 1a so operators can pin it before the " + "limiter is live. Above the cap, the verb returns " + "`E_RATE_LIMITED` without raising a card.")
|
|
11313
|
+
});
|
|
11310
11314
|
var SwitchroomConfigSchema = exports_external.object({
|
|
11311
11315
|
switchroom: exports_external.object({
|
|
11312
11316
|
version: exports_external.literal(1).describe("Config schema version"),
|
|
@@ -11333,6 +11337,7 @@ var SwitchroomConfigSchema = exports_external.object({
|
|
|
11333
11337
|
google_workspace: GoogleWorkspaceConfigSchema.describe("RFC G canonical key. Top-level Google Workspace configuration — " + "OAuth client credentials, approver allowlist, and tier knob (`core` " + "| `extended` | `complete`, default `core`). Mutually exclusive with " + "`drive:` at the top level (loader fails fast if both are set)."),
|
|
11334
11338
|
quota: QuotaConfigSchema.optional().describe("Optional weekly/monthly USD spend budgets rendered in the session " + "greeting. Usage is read from ccusage at runtime; no network calls."),
|
|
11335
11339
|
host_control: HostControlConfigSchema.default({}).describe("Host-control daemon configuration. Defaults to enabled=true since " + "RFC C Phase 2 (docs/rfcs/host-control-daemon.md). Omit the block " + "to accept defaults; set `enabled: false` only on legacy systemd-" + "mode installs (removal tracked as RFC C Phase 3)."),
|
|
11340
|
+
hostd: HostdConfigSchema.default({}).describe("hostd verb-level knobs (RFC admin-agent-config-edit). Distinct " + "from `host_control:` which governs whether the daemon runs at " + "all. Currently scopes the opt-in flag and rate cap for the new " + "`config_propose_edit` verb (PR 1a — disabled by default)."),
|
|
11336
11341
|
google_accounts: exports_external.record(exports_external.string().regex(/^[^@\s:]+@[^@\s:]+\.[^@\s:]+$/, {
|
|
11337
11342
|
message: "Account key must be a Google account email like 'alice@example.com' (colons not allowed)"
|
|
11338
11343
|
}).transform((v) => v.trim().toLowerCase()), exports_external.object({
|
package/dist/cli/switchroom.js
CHANGED
|
@@ -13520,7 +13520,7 @@ var init_zod = __esm(() => {
|
|
|
13520
13520
|
});
|
|
13521
13521
|
|
|
13522
13522
|
// src/config/schema.ts
|
|
13523
|
-
var CodeRepoEntrySchema, AgentBindMountSchema, ScheduleEntrySchema, AgentSoulSchema, AgentToolsSchema, AgentMemorySchema, HookEntrySchema, AgentHooksSchema, SubagentSchema, SessionSchema, SessionContinuitySchema, TelegramChannelSchema, ChannelsSchema, TIMEZONE_REGEX, ApproverIdSchema, GoogleWorkspaceTierSchema, GoogleWorkspaceConfigSchema, AgentGoogleWorkspaceConfigSchema, ReactionsSchema, ReleaseBlock, NetworkIsolationSchema, profileFields, ProfileSchema, _omitExtends, defaultsFields, AgentDefaultsSchema, DEFAULT_PROFILE = "default", AgentSchema, TelegramConfigSchema, MemoryBackendConfigSchema, VaultConfigSchema, QuotaConfigSchema, HostControlConfigSchema, SwitchroomConfigSchema;
|
|
13523
|
+
var CodeRepoEntrySchema, AgentBindMountSchema, ScheduleEntrySchema, AgentSoulSchema, AgentToolsSchema, AgentMemorySchema, HookEntrySchema, AgentHooksSchema, SubagentSchema, SessionSchema, SessionContinuitySchema, TelegramChannelSchema, ChannelsSchema, TIMEZONE_REGEX, ApproverIdSchema, GoogleWorkspaceTierSchema, GoogleWorkspaceConfigSchema, AgentGoogleWorkspaceConfigSchema, ReactionsSchema, ReleaseBlock, NetworkIsolationSchema, profileFields, ProfileSchema, _omitExtends, defaultsFields, AgentDefaultsSchema, DEFAULT_PROFILE = "default", AgentSchema, TelegramConfigSchema, MemoryBackendConfigSchema, VaultConfigSchema, QuotaConfigSchema, HostControlConfigSchema, HostdConfigSchema, SwitchroomConfigSchema;
|
|
13524
13524
|
var init_schema = __esm(() => {
|
|
13525
13525
|
init_zod();
|
|
13526
13526
|
CodeRepoEntrySchema = exports_external.object({
|
|
@@ -13871,6 +13871,10 @@ var init_schema = __esm(() => {
|
|
|
13871
13871
|
HostControlConfigSchema = exports_external.object({
|
|
13872
13872
|
enabled: exports_external.boolean().default(true).describe("Whether the host-control daemon is in use. Default: true (since " + "RFC C Phase 2 default-flip \u2014 the gateway's /restart, /new, /reset, " + "and /update apply slash-commands all dispatch through hostd, and " + "without it those verbs fail on docker-mode installs because the " + "agent container has no docker binary/socket). " + "When true, the compose generator emits per-agent bind mounts " + "at `~/.switchroom/hostd/<name>/sock` for every admin-flagged " + "agent. Install the daemon with `switchroom hostd install` \u2014 " + "it runs as a docker container in its own compose project " + "(`switchroom-hostd`), separate from the agent fleet's compose " + "project so `up -d --remove-orphans` cycles of the fleet " + "can't recreate the daemon mid-RPC. See RFC C \u00a75.1. " + "Set enabled: false only on legacy systemd-mode installs that " + "still rely on the in-container `spawnSwitchroomDetached` " + "shellout (removal is tracked as RFC C Phase 3).")
|
|
13873
13873
|
});
|
|
13874
|
+
HostdConfigSchema = exports_external.object({
|
|
13875
|
+
config_edit_enabled: exports_external.boolean().default(false).describe("Opt-in toggle for the `config_propose_edit` hostd verb (RFC " + "admin-agent-config-edit \u00a73). Default false \u2014 the verb returns " + "`E_CONFIG_EDIT_DISABLED` until the operator explicitly flips " + "this to true. When true (and once PR 1c lands the apply path), " + "admin agents can propose unified-diff patches against " + "`/state/config/switchroom.yaml`, gated by an operator approval " + "card in the primary chat. Same trust posture as `update_apply` " + "and `agent_restart`: the human-in-the-loop tap is the security " + "boundary, not the agent's judgement."),
|
|
13876
|
+
config_edit_rate_per_hour: exports_external.number().int().min(1).max(20).default(3).describe("Per-requesting-agent rate cap for `config_propose_edit` cards " + "(RFC admin-agent-config-edit \u00a75). Default 3 cards/hour; min 1, " + "max 20. Implemented as a sqlite token bucket in PR 1c; the " + "field is wired here in PR 1a so operators can pin it before the " + "limiter is live. Above the cap, the verb returns " + "`E_RATE_LIMITED` without raising a card.")
|
|
13877
|
+
});
|
|
13874
13878
|
SwitchroomConfigSchema = exports_external.object({
|
|
13875
13879
|
switchroom: exports_external.object({
|
|
13876
13880
|
version: exports_external.literal(1).describe("Config schema version"),
|
|
@@ -13897,6 +13901,7 @@ var init_schema = __esm(() => {
|
|
|
13897
13901
|
google_workspace: GoogleWorkspaceConfigSchema.describe("RFC G canonical key. Top-level Google Workspace configuration \u2014 " + "OAuth client credentials, approver allowlist, and tier knob (`core` " + "| `extended` | `complete`, default `core`). Mutually exclusive with " + "`drive:` at the top level (loader fails fast if both are set)."),
|
|
13898
13902
|
quota: QuotaConfigSchema.optional().describe("Optional weekly/monthly USD spend budgets rendered in the session " + "greeting. Usage is read from ccusage at runtime; no network calls."),
|
|
13899
13903
|
host_control: HostControlConfigSchema.default({}).describe("Host-control daemon configuration. Defaults to enabled=true since " + "RFC C Phase 2 (docs/rfcs/host-control-daemon.md). Omit the block " + "to accept defaults; set `enabled: false` only on legacy systemd-" + "mode installs (removal tracked as RFC C Phase 3)."),
|
|
13904
|
+
hostd: HostdConfigSchema.default({}).describe("hostd verb-level knobs (RFC admin-agent-config-edit). Distinct " + "from `host_control:` which governs whether the daemon runs at " + "all. Currently scopes the opt-in flag and rate cap for the new " + "`config_propose_edit` verb (PR 1a \u2014 disabled by default)."),
|
|
13900
13905
|
google_accounts: exports_external.record(exports_external.string().regex(/^[^@\s:]+@[^@\s:]+\.[^@\s:]+$/, {
|
|
13901
13906
|
message: "Account key must be a Google account email like 'alice@example.com' (colons not allowed)"
|
|
13902
13907
|
}).transform((v) => v.trim().toLowerCase()), exports_external.object({
|
|
@@ -23140,7 +23145,7 @@ function emitAgentService(lines, a, imageTag, buildMode, buildContext, homePrefi
|
|
|
23140
23145
|
lines.push(` - "ALL"`);
|
|
23141
23146
|
lines.push(` read_only: true`);
|
|
23142
23147
|
lines.push(` tmpfs:`);
|
|
23143
|
-
lines.push(` - /tmp:size=
|
|
23148
|
+
lines.push(` - /tmp:size=1g,mode=1777`);
|
|
23144
23149
|
lines.push(` depends_on:`);
|
|
23145
23150
|
lines.push(` vault-broker:`);
|
|
23146
23151
|
lines.push(` condition: service_started`);
|
|
@@ -29067,7 +29072,7 @@ function decodeResponse3(line) {
|
|
|
29067
29072
|
const obj = JSON.parse(line);
|
|
29068
29073
|
return ResponseSchema3.parse(obj);
|
|
29069
29074
|
}
|
|
29070
|
-
var MAX_FRAME_BYTES3, RequestEnvelope, AgentRestartRequestSchema, UpgradeStatusRequestSchema, GetStatusRequestSchema, AgentNameSchema, UpdateCheckRequestSchema, UpdateApplyRequestSchema, ApplyRequestSchema, AgentStartRequestSchema, AgentStopRequestSchema, AgentLogsRequestSchema, AgentExecRequestSchema, DoctorRequestSchema, AgentSmokeRequestSchema, RequestSchema3, ResultSchema, ResponseEnvelope, ResponseSchema3;
|
|
29075
|
+
var MAX_FRAME_BYTES3, RequestEnvelope, AgentRestartRequestSchema, UpgradeStatusRequestSchema, GetStatusRequestSchema, AgentNameSchema, UpdateCheckRequestSchema, UpdateApplyRequestSchema, ApplyRequestSchema, AgentStartRequestSchema, AgentStopRequestSchema, AgentLogsRequestSchema, AgentExecRequestSchema, DoctorRequestSchema, AgentSmokeRequestSchema, ConfigProposeEditRequestSchema, RequestSchema3, ResultSchema, ResponseEnvelope, ResponseSchema3;
|
|
29071
29076
|
var init_protocol3 = __esm(() => {
|
|
29072
29077
|
init_zod();
|
|
29073
29078
|
MAX_FRAME_BYTES3 = 64 * 1024;
|
|
@@ -29161,6 +29166,15 @@ var init_protocol3 = __esm(() => {
|
|
|
29161
29166
|
deep: exports_external.boolean().optional()
|
|
29162
29167
|
})
|
|
29163
29168
|
});
|
|
29169
|
+
ConfigProposeEditRequestSchema = exports_external.object({
|
|
29170
|
+
...RequestEnvelope,
|
|
29171
|
+
op: exports_external.literal("config_propose_edit"),
|
|
29172
|
+
args: exports_external.object({
|
|
29173
|
+
unified_diff: exports_external.string().min(1).max(MAX_FRAME_BYTES3 - 1024),
|
|
29174
|
+
reason: exports_external.string().min(1).max(500),
|
|
29175
|
+
target_path: exports_external.literal("/state/config/switchroom.yaml")
|
|
29176
|
+
})
|
|
29177
|
+
});
|
|
29164
29178
|
RequestSchema3 = exports_external.discriminatedUnion("op", [
|
|
29165
29179
|
AgentRestartRequestSchema,
|
|
29166
29180
|
UpgradeStatusRequestSchema,
|
|
@@ -29173,7 +29187,8 @@ var init_protocol3 = __esm(() => {
|
|
|
29173
29187
|
AgentLogsRequestSchema,
|
|
29174
29188
|
AgentExecRequestSchema,
|
|
29175
29189
|
DoctorRequestSchema,
|
|
29176
|
-
AgentSmokeRequestSchema
|
|
29190
|
+
AgentSmokeRequestSchema,
|
|
29191
|
+
ConfigProposeEditRequestSchema
|
|
29177
29192
|
]);
|
|
29178
29193
|
ResultSchema = exports_external.enum(["started", "completed", "denied", "error"]);
|
|
29179
29194
|
ResponseEnvelope = {
|
|
@@ -47009,6 +47024,31 @@ async function dispatchTool2(name, args) {
|
|
|
47009
47024
|
};
|
|
47010
47025
|
break;
|
|
47011
47026
|
}
|
|
47027
|
+
case "config_propose_edit": {
|
|
47028
|
+
if (!args.unified_diff || typeof args.unified_diff !== "string") {
|
|
47029
|
+
return errorText2("config_propose_edit: unified_diff is required (non-empty string).");
|
|
47030
|
+
}
|
|
47031
|
+
if (!args.reason || typeof args.reason !== "string") {
|
|
47032
|
+
return errorText2("config_propose_edit: reason is required (non-empty string, \u2264500 chars).");
|
|
47033
|
+
}
|
|
47034
|
+
if (args.reason.length > 500) {
|
|
47035
|
+
return errorText2("config_propose_edit: reason is capped at 500 chars (RFC \u00a73.3).");
|
|
47036
|
+
}
|
|
47037
|
+
if (args.target_path !== "/state/config/switchroom.yaml") {
|
|
47038
|
+
return errorText2("config_propose_edit: target_path must be '/state/config/switchroom.yaml'.");
|
|
47039
|
+
}
|
|
47040
|
+
req = {
|
|
47041
|
+
v: 1,
|
|
47042
|
+
op: "config_propose_edit",
|
|
47043
|
+
request_id: makeRequestId("mcp-config-propose-edit"),
|
|
47044
|
+
args: {
|
|
47045
|
+
unified_diff: args.unified_diff,
|
|
47046
|
+
reason: args.reason,
|
|
47047
|
+
target_path: "/state/config/switchroom.yaml"
|
|
47048
|
+
}
|
|
47049
|
+
};
|
|
47050
|
+
break;
|
|
47051
|
+
}
|
|
47012
47052
|
default:
|
|
47013
47053
|
return errorText2(`unknown tool: ${name}`);
|
|
47014
47054
|
}
|
|
@@ -47219,6 +47259,32 @@ var init_server4 = __esm(() => {
|
|
|
47219
47259
|
}
|
|
47220
47260
|
}
|
|
47221
47261
|
},
|
|
47262
|
+
{
|
|
47263
|
+
name: "config_propose_edit",
|
|
47264
|
+
description: "Propose a unified-diff patch against /state/config/switchroom.yaml " + "(RFC admin-agent-config-edit). When fully shipped the host validates " + "the patch (applies cleanly + post-patch yaml parses against the " + "config schema) and raises a Telegram approval card in the OPERATOR's " + "primary chat \u2014 NOT yours; the requesting agent's chat is not the " + "approval surface. Admin-only at the wire layer. " + "Current status (PR 1a \u2014 skeleton): the tool is registered but the " + "feature is OFF by default; calling it returns " + "E_CONFIG_EDIT_DISABLED until the operator sets " + "hostd.config_edit_enabled=true in switchroom.yaml. Even when enabled " + "in this PR, the call returns E_NOT_IMPLEMENTED \u2014 the validation " + "pipeline (PR 1b) and apply path (PR 1c) ship in follow-up PRs.",
|
|
47265
|
+
inputSchema: {
|
|
47266
|
+
type: "object",
|
|
47267
|
+
required: ["unified_diff", "reason", "target_path"],
|
|
47268
|
+
properties: {
|
|
47269
|
+
unified_diff: {
|
|
47270
|
+
type: "string",
|
|
47271
|
+
minLength: 1,
|
|
47272
|
+
description: "Unified diff against switchroom.yaml. Must have \u22653 lines " + "context (enforced in PR 1b); no path-traversal or multi-file " + "diffs. LF-only, \u22641 MB."
|
|
47273
|
+
},
|
|
47274
|
+
reason: {
|
|
47275
|
+
type: "string",
|
|
47276
|
+
minLength: 1,
|
|
47277
|
+
maxLength: 500,
|
|
47278
|
+
description: "Human-readable rationale shown to the operator on the " + "approval card. Capped at 500 chars (RFC \u00a73.3)."
|
|
47279
|
+
},
|
|
47280
|
+
target_path: {
|
|
47281
|
+
type: "string",
|
|
47282
|
+
enum: ["/state/config/switchroom.yaml"],
|
|
47283
|
+
description: "Must be the literal string '/state/config/switchroom.yaml'. " + "Future-proofs against multi-file diffs and gives the validator " + "a single canonical path to anchor on."
|
|
47284
|
+
}
|
|
47285
|
+
}
|
|
47286
|
+
}
|
|
47287
|
+
},
|
|
47222
47288
|
{
|
|
47223
47289
|
name: "get_status",
|
|
47224
47290
|
description: "Read the most recent terminal `update_apply` audit row " + "(channel, pin, resolved_sha, install_context, result, " + "exit_code, stderr_tail). Use this after issuing an " + "`update_apply` to confirm what actually rolled out, or to " + "report the last update on demand. Returns the parsed audit " + "entry as JSON.",
|
|
@@ -47248,8 +47314,8 @@ var {
|
|
|
47248
47314
|
} = import__.default;
|
|
47249
47315
|
|
|
47250
47316
|
// src/build-info.ts
|
|
47251
|
-
var VERSION = "0.13.
|
|
47252
|
-
var COMMIT_SHA = "
|
|
47317
|
+
var VERSION = "0.13.8";
|
|
47318
|
+
var COMMIT_SHA = "bb713414";
|
|
47253
47319
|
|
|
47254
47320
|
// src/cli/agent.ts
|
|
47255
47321
|
init_source();
|
|
@@ -48695,35 +48761,37 @@ function buildWorkspaceContext(args) {
|
|
|
48695
48761
|
systemPromptAppendShellQuoted: (() => {
|
|
48696
48762
|
const useSwitchroomPlugin = usesSwitchroomTelegramPlugin(agentConfig);
|
|
48697
48763
|
const baseAppend = agentConfig.system_prompt_append ?? "";
|
|
48698
|
-
const telegramGuidance = `##
|
|
48699
|
-
|
|
48700
|
-
|
|
48701
|
-
|
|
48702
|
-
|
|
48703
|
-
|
|
48704
|
-
|
|
48705
|
-
|
|
48706
|
-
|
|
48707
|
-
|
|
48708
|
-
|
|
48709
|
-
|
|
48710
|
-
|
|
48711
|
-
|
|
48712
|
-
|
|
48713
|
-
|
|
48714
|
-
\`
|
|
48715
|
-
|
|
48716
|
-
|
|
48717
|
-
|
|
48718
|
-
|
|
48719
|
-
|
|
48720
|
-
|
|
48721
|
-
|
|
48722
|
-
|
|
48723
|
-
|
|
48724
|
-
|
|
48725
|
-
|
|
48726
|
-
|
|
48764
|
+
const telegramGuidance = `## Talking to a human on Telegram
|
|
48765
|
+
|
|
48766
|
+
There is a real person on the other end. Every turn should feel like
|
|
48767
|
+
messaging a capable colleague \u2014 not a tool emitting output. Five beats:
|
|
48768
|
+
|
|
48769
|
+
1. **Acknowledge first.** On any turn that needs real work \u2014 a file
|
|
48770
|
+
read, a search, a command \u2014 your FIRST action is a short \`reply\`
|
|
48771
|
+
in your own voice ("on it \u2014 checking now"), before you start. Skip
|
|
48772
|
+
it only when the whole answer is one sentence you can give straight
|
|
48773
|
+
away.
|
|
48774
|
+
2. **Then go quiet and work.** Heads-down is correct \u2014 do NOT narrate
|
|
48775
|
+
every tool call. A typing indicator runs automatically while you
|
|
48776
|
+
work; you do not maintain it.
|
|
48777
|
+
3. **Surface meaningful progress** at genuine inflection points \u2014 a
|
|
48778
|
+
hard step finished, a blocker, a pivot, dispatching a sub-agent, a
|
|
48779
|
+
notably slow wait, a finding worth knowing now. One short \`reply\`,
|
|
48780
|
+
\`disable_notification: true\`.
|
|
48781
|
+
4. **Hand back delegations with synthesis.** When a sub-agent / worker
|
|
48782
|
+
returns, re-enter in YOUR voice \u2014 what it found, and what you are
|
|
48783
|
+
doing next. Never let its raw report stand as your reply.
|
|
48784
|
+
5. **Deliver the answer** as a final \`reply\`.
|
|
48785
|
+
|
|
48786
|
+
The one thing to avoid is *spam*: a reply on every tool call, on a
|
|
48787
|
+
timer, or repeating what you already said. Responsive and human, never
|
|
48788
|
+
a flood. Going quiet mid-work is fine \u2014 going quiet *instead* of
|
|
48789
|
+
acknowledging, or *instead* of an update at a real milestone, is the
|
|
48790
|
+
black box this exists to prevent.
|
|
48791
|
+
|
|
48792
|
+
Every turn that answers a user message ends with a user-visible
|
|
48793
|
+
\`reply\` (or \`stream_reply\` done=true) \u2014 Telegram is all the user
|
|
48794
|
+
sees; your terminal output never reaches them.`;
|
|
48727
48795
|
const memoryGuidance = `## Memory \u2014 proactive, conversational
|
|
48728
48796
|
|
|
48729
48797
|
You have Hindsight tools: \`mcp__hindsight__sync_retain\`, \`mcp__hindsight__delete_memory\`, \`mcp__hindsight__recall\`, \`mcp__hindsight__reflect\`. Use them without being asked.
|
|
@@ -49417,6 +49485,7 @@ function buildSettingsHooksBlock(p) {
|
|
|
49417
49485
|
}
|
|
49418
49486
|
] : [];
|
|
49419
49487
|
const useHotReloadStable = agentConfig.channels?.telegram?.hotReloadStable === true;
|
|
49488
|
+
const turnPacingDirective = "<turn-pacing>You are messaging a human. First action this turn: if " + "answering needs any tool call (a file read, a search, a command), " + "send a SHORT acknowledgement via the reply tool with " + "disable_notification true BEFORE the first tool call. Then work; " + "surface meaningful progress in human prose at real milestones; hand " + "back any sub-agent findings in your own voice; deliver the answer. " + "Skip the opening ack only for a one-sentence answer you can give " + "immediately.</turn-pacing>";
|
|
49420
49489
|
const switchroomUserPromptSubmit = [
|
|
49421
49490
|
...useHotReloadStable ? [
|
|
49422
49491
|
{
|
|
@@ -49446,6 +49515,15 @@ function buildSettingsHooksBlock(p) {
|
|
|
49446
49515
|
timeout: 3
|
|
49447
49516
|
}
|
|
49448
49517
|
]
|
|
49518
|
+
},
|
|
49519
|
+
{
|
|
49520
|
+
hooks: [
|
|
49521
|
+
{
|
|
49522
|
+
type: "command",
|
|
49523
|
+
command: wrap("hook:turn-pacing", `printf '%s\\n' ${shellSingleQuote(turnPacingDirective)}`),
|
|
49524
|
+
timeout: 3
|
|
49525
|
+
}
|
|
49526
|
+
]
|
|
49449
49527
|
}
|
|
49450
49528
|
];
|
|
49451
49529
|
if (userHooks) {
|
|
@@ -49627,35 +49705,37 @@ function reconcileAgent(name, agentConfigRaw, agentsDir, telegramConfig, switchr
|
|
|
49627
49705
|
systemPromptAppendShellQuoted: (() => {
|
|
49628
49706
|
const useSwitchroomPlugin = usesSwitchroomTelegramPlugin(agentConfig);
|
|
49629
49707
|
const baseAppend = agentConfig.system_prompt_append ?? "";
|
|
49630
|
-
const telegramGuidance = `##
|
|
49631
|
-
|
|
49632
|
-
|
|
49633
|
-
|
|
49634
|
-
|
|
49635
|
-
|
|
49636
|
-
|
|
49637
|
-
|
|
49638
|
-
|
|
49639
|
-
|
|
49640
|
-
|
|
49641
|
-
|
|
49642
|
-
|
|
49643
|
-
|
|
49644
|
-
|
|
49645
|
-
|
|
49646
|
-
\`
|
|
49647
|
-
|
|
49648
|
-
|
|
49649
|
-
|
|
49650
|
-
|
|
49651
|
-
|
|
49652
|
-
|
|
49653
|
-
|
|
49654
|
-
|
|
49655
|
-
|
|
49656
|
-
|
|
49657
|
-
|
|
49658
|
-
|
|
49708
|
+
const telegramGuidance = `## Talking to a human on Telegram
|
|
49709
|
+
|
|
49710
|
+
There is a real person on the other end. Every turn should feel like
|
|
49711
|
+
messaging a capable colleague \u2014 not a tool emitting output. Five beats:
|
|
49712
|
+
|
|
49713
|
+
1. **Acknowledge first.** On any turn that needs real work \u2014 a file
|
|
49714
|
+
read, a search, a command \u2014 your FIRST action is a short \`reply\`
|
|
49715
|
+
in your own voice ("on it \u2014 checking now"), before you start. Skip
|
|
49716
|
+
it only when the whole answer is one sentence you can give straight
|
|
49717
|
+
away.
|
|
49718
|
+
2. **Then go quiet and work.** Heads-down is correct \u2014 do NOT narrate
|
|
49719
|
+
every tool call. A typing indicator runs automatically while you
|
|
49720
|
+
work; you do not maintain it.
|
|
49721
|
+
3. **Surface meaningful progress** at genuine inflection points \u2014 a
|
|
49722
|
+
hard step finished, a blocker, a pivot, dispatching a sub-agent, a
|
|
49723
|
+
notably slow wait, a finding worth knowing now. One short \`reply\`,
|
|
49724
|
+
\`disable_notification: true\`.
|
|
49725
|
+
4. **Hand back delegations with synthesis.** When a sub-agent / worker
|
|
49726
|
+
returns, re-enter in YOUR voice \u2014 what it found, and what you are
|
|
49727
|
+
doing next. Never let its raw report stand as your reply.
|
|
49728
|
+
5. **Deliver the answer** as a final \`reply\`.
|
|
49729
|
+
|
|
49730
|
+
The one thing to avoid is *spam*: a reply on every tool call, on a
|
|
49731
|
+
timer, or repeating what you already said. Responsive and human, never
|
|
49732
|
+
a flood. Going quiet mid-work is fine \u2014 going quiet *instead* of
|
|
49733
|
+
acknowledging, or *instead* of an update at a real milestone, is the
|
|
49734
|
+
black box this exists to prevent.
|
|
49735
|
+
|
|
49736
|
+
Every turn that answers a user message ends with a user-visible
|
|
49737
|
+
\`reply\` (or \`stream_reply\` done=true) \u2014 Telegram is all the user
|
|
49738
|
+
sees; your terminal output never reaches them.`;
|
|
49659
49739
|
const memoryGuidance = `## Memory \u2014 proactive, conversational
|
|
49660
49740
|
|
|
49661
49741
|
You have Hindsight tools: \`mcp__hindsight__sync_retain\`, \`mcp__hindsight__delete_memory\`, \`mcp__hindsight__recall\`, \`mcp__hindsight__reflect\`. Use them without being asked.
|