switchroom 0.13.1 → 0.13.3
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 -2
- package/dist/auth-broker/index.js +2 -2
- package/dist/cli/switchroom.js +21 -18
- package/dist/host-control/main.js +2 -2
- package/dist/vault/approvals/kernel-server.js +2 -2
- package/dist/vault/broker/server.js +2 -2
- package/package.json +1 -1
- package/telegram-plugin/dist/gateway/gateway.js +54 -22
- package/telegram-plugin/gateway/boot-probes.ts +13 -6
- package/telegram-plugin/gateway/gateway.ts +71 -122
- package/telegram-plugin/hooks/silent-end-interrupt-stop.mjs +5 -1
- package/telegram-plugin/silent-end.ts +56 -0
- package/telegram-plugin/tests/boot-probes.test.ts +26 -2
- package/telegram-plugin/tests/silent-end.test.ts +69 -0
- package/skills/buildkite-agent-infrastructure/SKILL.md +0 -321
- package/skills/buildkite-agent-infrastructure/agents/openai.yaml +0 -6
- package/skills/buildkite-agent-infrastructure/assets/buildkite-icon-large.png +0 -0
- package/skills/buildkite-agent-infrastructure/assets/buildkite-icon-small.png +0 -0
- package/skills/buildkite-agent-infrastructure/references/audit-logging.md +0 -87
- package/skills/buildkite-agent-infrastructure/references/graphql-mutations.md +0 -690
- package/skills/buildkite-agent-infrastructure/references/instance-shapes.md +0 -38
- package/skills/buildkite-agent-infrastructure/references/pipeline-templates.md +0 -73
- package/skills/buildkite-agent-infrastructure/references/self-hosted-agents.md +0 -137
- package/skills/buildkite-agent-infrastructure/references/sso-saml.md +0 -92
- package/skills/buildkite-agent-runtime/SKILL.md +0 -509
- package/skills/buildkite-agent-runtime/agents/openai.yaml +0 -6
- package/skills/buildkite-agent-runtime/assets/buildkite-icon-large.png +0 -0
- package/skills/buildkite-agent-runtime/assets/buildkite-icon-small.png +0 -0
- package/skills/buildkite-agent-runtime/references/flag-reference.md +0 -417
- package/skills/buildkite-agent-runtime/references/patterns-and-recipes.md +0 -555
- package/skills/buildkite-api/SKILL.md +0 -308
- package/skills/buildkite-api/agents/openai.yaml +0 -6
- package/skills/buildkite-api/assets/buildkite-icon-large.png +0 -0
- package/skills/buildkite-api/assets/buildkite-icon-small.png +0 -0
- package/skills/buildkite-api/references/graphql-reference.md +0 -195
- package/skills/buildkite-api/references/patterns.md +0 -44
- package/skills/buildkite-api/references/webhooks.md +0 -161
- package/skills/buildkite-cli/SKILL.md +0 -397
- package/skills/buildkite-cli/agents/openai.yaml +0 -6
- package/skills/buildkite-cli/assets/buildkite-icon-large.png +0 -0
- package/skills/buildkite-cli/assets/buildkite-icon-small.png +0 -0
- package/skills/buildkite-cli/references/command-reference.md +0 -181
- package/skills/buildkite-migration/SKILL.md +0 -195
- package/skills/buildkite-pipelines/SKILL.md +0 -481
- package/skills/buildkite-pipelines/agents/openai.yaml +0 -6
- package/skills/buildkite-pipelines/assets/buildkite-icon-large.png +0 -0
- package/skills/buildkite-pipelines/assets/buildkite-icon-small.png +0 -0
- package/skills/buildkite-pipelines/examples/basic-pipeline.yml +0 -24
- package/skills/buildkite-pipelines/examples/optimized-pipeline.yml +0 -100
- package/skills/buildkite-pipelines/references/advanced-patterns.md +0 -286
- package/skills/buildkite-pipelines/references/retry-and-error-codes.md +0 -131
- package/skills/buildkite-pipelines/references/step-types-reference.md +0 -225
- package/skills/buildkite-secure-delivery/SKILL.md +0 -182
- package/skills/buildkite-secure-delivery/agents/openai.yaml +0 -6
- package/skills/buildkite-secure-delivery/assets/buildkite-icon-large.png +0 -0
- package/skills/buildkite-secure-delivery/assets/buildkite-icon-small.png +0 -0
- package/skills/buildkite-secure-delivery/references/oidc-cloud-providers.md +0 -83
- package/skills/buildkite-secure-delivery/references/package-publishing.md +0 -100
- package/skills/buildkite-test-engine/SKILL.md +0 -256
- package/skills/buildkite-test-engine/agents/openai.yaml +0 -6
- package/skills/buildkite-test-engine/assets/buildkite-icon-large.png +0 -0
- package/skills/buildkite-test-engine/assets/buildkite-icon-small.png +0 -0
- package/skills/buildkite-test-engine/examples/bktec-splitting.yml +0 -16
- package/skills/buildkite-test-engine/examples/collector-pipeline.yml +0 -11
- package/skills/buildkite-test-engine/references/collectors.md +0 -198
- package/skills/buildkite-test-engine/references/splitting-examples.md +0 -93
|
@@ -11130,7 +11130,7 @@ var profileFields = {
|
|
|
11130
11130
|
extends: exports_external.string().optional(),
|
|
11131
11131
|
bot_token: exports_external.string().optional(),
|
|
11132
11132
|
release: ReleaseBlock.optional().describe("Release-channel pin / pointer. Either `channel` (dev|rc|latest) or " + "`pin` (sha-<hex>|v<semver>) — mutually exclusive. Per-agent value " + "REPLACES the root entirely (no field merge)."),
|
|
11133
|
-
timezone: exports_external.string().regex(TIMEZONE_REGEX, "timezone must be an IANA zone name like 'Australia/Melbourne' or 'UTC' " + "(three-letter aliases like EST/PST and bare offsets like UTC+10 are not accepted)").optional().describe("IANA timezone name (e.g. 'Australia/Melbourne', 'America/New_York', " + "'UTC'). Used to generate the per-turn local-time hint the agent's " + "UserPromptSubmit timezone hook emits, and baked into the
|
|
11133
|
+
timezone: exports_external.string().regex(TIMEZONE_REGEX, "timezone must be an IANA zone name like 'Australia/Melbourne' or 'UTC' " + "(three-letter aliases like EST/PST and bare offsets like UTC+10 are not accepted)").optional().describe("IANA timezone name (e.g. 'Australia/Melbourne', 'America/New_York', " + "'UTC'). Used to generate the per-turn local-time hint the agent's " + "UserPromptSubmit timezone hook emits, and baked into the agent " + "container's `environment.TZ` in compose so subprocess `date`/" + "`Date.now()` are correct. If unset at every cascade layer, switchroom " + "auto-detects from /etc/timezone and warns on `reconcile` when the " + "detected zone is UTC."),
|
|
11134
11134
|
soul: exports_external.object({
|
|
11135
11135
|
name: exports_external.string().optional(),
|
|
11136
11136
|
style: exports_external.string().optional(),
|
|
@@ -11191,7 +11191,7 @@ var AgentSchema = exports_external.object({
|
|
|
11191
11191
|
bot_token: exports_external.string().optional().describe("Per-agent Telegram bot token or vault reference (overrides global telegram.bot_token)"),
|
|
11192
11192
|
release: ReleaseBlock.optional().describe("Per-agent release-channel pin / pointer. REPLACES the root " + "`release` block entirely (no field merge) — a pinned agent does " + "not inherit the fleet channel, and vice versa."),
|
|
11193
11193
|
bot_username: exports_external.string().optional().describe("Per-agent Telegram bot username (without leading @) when it doesn't " + "contain the agent slug. Replaces the default 'username includes slug' " + "preflight check with an exact (case-insensitive) match. Use when an " + "agent and its bot have intentionally divergent names (e.g. agent " + "'lawgpt' paired with bot '@meken_law_bot')."),
|
|
11194
|
-
timezone: exports_external.string().regex(TIMEZONE_REGEX, "timezone must be an IANA zone name like 'Australia/Melbourne' or 'UTC' " + "(three-letter aliases like EST/PST and bare offsets like UTC+10 are not accepted)").optional().describe("Per-agent IANA timezone override. Wins over any profile/defaults " + "value and over the top-level switchroom.timezone global. Controls " + "the UserPromptSubmit timezone hook's emitted local time and the " + "
|
|
11194
|
+
timezone: exports_external.string().regex(TIMEZONE_REGEX, "timezone must be an IANA zone name like 'Australia/Melbourne' or 'UTC' " + "(three-letter aliases like EST/PST and bare offsets like UTC+10 are not accepted)").optional().describe("Per-agent IANA timezone override. Wins over any profile/defaults " + "value and over the top-level switchroom.timezone global. Controls " + "the UserPromptSubmit timezone hook's emitted local time and the " + "agent container's `environment.TZ` in compose."),
|
|
11195
11195
|
auth: exports_external.object({
|
|
11196
11196
|
override: exports_external.string().min(1).optional().describe("Per-agent override of the fleet-wide `auth.active`. Edge-case use only — " + "this agent talks to the named account regardless of fleet active. See RFC H §4.5.")
|
|
11197
11197
|
}).optional().describe("Account routing for switchroom-auth-broker. RFC H schema uses " + "fleet-wide `auth.active` plus per-agent `override:` for edge cases. " + "Pre-RFC-H `auth.accounts: [..]` and `auth_label:` are migrated in-place " + "on first apply (see src/auth/migrate-schema.ts)."),
|
|
@@ -11130,7 +11130,7 @@ var profileFields = {
|
|
|
11130
11130
|
extends: exports_external.string().optional(),
|
|
11131
11131
|
bot_token: exports_external.string().optional(),
|
|
11132
11132
|
release: ReleaseBlock.optional().describe("Release-channel pin / pointer. Either `channel` (dev|rc|latest) or " + "`pin` (sha-<hex>|v<semver>) — mutually exclusive. Per-agent value " + "REPLACES the root entirely (no field merge)."),
|
|
11133
|
-
timezone: exports_external.string().regex(TIMEZONE_REGEX, "timezone must be an IANA zone name like 'Australia/Melbourne' or 'UTC' " + "(three-letter aliases like EST/PST and bare offsets like UTC+10 are not accepted)").optional().describe("IANA timezone name (e.g. 'Australia/Melbourne', 'America/New_York', " + "'UTC'). Used to generate the per-turn local-time hint the agent's " + "UserPromptSubmit timezone hook emits, and baked into the
|
|
11133
|
+
timezone: exports_external.string().regex(TIMEZONE_REGEX, "timezone must be an IANA zone name like 'Australia/Melbourne' or 'UTC' " + "(three-letter aliases like EST/PST and bare offsets like UTC+10 are not accepted)").optional().describe("IANA timezone name (e.g. 'Australia/Melbourne', 'America/New_York', " + "'UTC'). Used to generate the per-turn local-time hint the agent's " + "UserPromptSubmit timezone hook emits, and baked into the agent " + "container's `environment.TZ` in compose so subprocess `date`/" + "`Date.now()` are correct. If unset at every cascade layer, switchroom " + "auto-detects from /etc/timezone and warns on `reconcile` when the " + "detected zone is UTC."),
|
|
11134
11134
|
soul: exports_external.object({
|
|
11135
11135
|
name: exports_external.string().optional(),
|
|
11136
11136
|
style: exports_external.string().optional(),
|
|
@@ -11191,7 +11191,7 @@ var AgentSchema = exports_external.object({
|
|
|
11191
11191
|
bot_token: exports_external.string().optional().describe("Per-agent Telegram bot token or vault reference (overrides global telegram.bot_token)"),
|
|
11192
11192
|
release: ReleaseBlock.optional().describe("Per-agent release-channel pin / pointer. REPLACES the root " + "`release` block entirely (no field merge) — a pinned agent does " + "not inherit the fleet channel, and vice versa."),
|
|
11193
11193
|
bot_username: exports_external.string().optional().describe("Per-agent Telegram bot username (without leading @) when it doesn't " + "contain the agent slug. Replaces the default 'username includes slug' " + "preflight check with an exact (case-insensitive) match. Use when an " + "agent and its bot have intentionally divergent names (e.g. agent " + "'lawgpt' paired with bot '@meken_law_bot')."),
|
|
11194
|
-
timezone: exports_external.string().regex(TIMEZONE_REGEX, "timezone must be an IANA zone name like 'Australia/Melbourne' or 'UTC' " + "(three-letter aliases like EST/PST and bare offsets like UTC+10 are not accepted)").optional().describe("Per-agent IANA timezone override. Wins over any profile/defaults " + "value and over the top-level switchroom.timezone global. Controls " + "the UserPromptSubmit timezone hook's emitted local time and the " + "
|
|
11194
|
+
timezone: exports_external.string().regex(TIMEZONE_REGEX, "timezone must be an IANA zone name like 'Australia/Melbourne' or 'UTC' " + "(three-letter aliases like EST/PST and bare offsets like UTC+10 are not accepted)").optional().describe("Per-agent IANA timezone override. Wins over any profile/defaults " + "value and over the top-level switchroom.timezone global. Controls " + "the UserPromptSubmit timezone hook's emitted local time and the " + "agent container's `environment.TZ` in compose."),
|
|
11195
11195
|
auth: exports_external.object({
|
|
11196
11196
|
override: exports_external.string().min(1).optional().describe("Per-agent override of the fleet-wide `auth.active`. Edge-case use only — " + "this agent talks to the named account regardless of fleet active. See RFC H §4.5.")
|
|
11197
11197
|
}).optional().describe("Account routing for switchroom-auth-broker. RFC H schema uses " + "fleet-wide `auth.active` plus per-agent `override:` for edge cases. " + "Pre-RFC-H `auth.accounts: [..]` and `auth_label:` are migrated in-place " + "on first apply (see src/auth/migrate-schema.ts)."),
|
package/dist/cli/switchroom.js
CHANGED
|
@@ -13694,7 +13694,7 @@ var init_schema = __esm(() => {
|
|
|
13694
13694
|
extends: exports_external.string().optional(),
|
|
13695
13695
|
bot_token: exports_external.string().optional(),
|
|
13696
13696
|
release: ReleaseBlock.optional().describe("Release-channel pin / pointer. Either `channel` (dev|rc|latest) or " + "`pin` (sha-<hex>|v<semver>) \u2014 mutually exclusive. Per-agent value " + "REPLACES the root entirely (no field merge)."),
|
|
13697
|
-
timezone: exports_external.string().regex(TIMEZONE_REGEX, "timezone must be an IANA zone name like 'Australia/Melbourne' or 'UTC' " + "(three-letter aliases like EST/PST and bare offsets like UTC+10 are not accepted)").optional().describe("IANA timezone name (e.g. 'Australia/Melbourne', 'America/New_York', " + "'UTC'). Used to generate the per-turn local-time hint the agent's " + "UserPromptSubmit timezone hook emits, and baked into the
|
|
13697
|
+
timezone: exports_external.string().regex(TIMEZONE_REGEX, "timezone must be an IANA zone name like 'Australia/Melbourne' or 'UTC' " + "(three-letter aliases like EST/PST and bare offsets like UTC+10 are not accepted)").optional().describe("IANA timezone name (e.g. 'Australia/Melbourne', 'America/New_York', " + "'UTC'). Used to generate the per-turn local-time hint the agent's " + "UserPromptSubmit timezone hook emits, and baked into the agent " + "container's `environment.TZ` in compose so subprocess `date`/" + "`Date.now()` are correct. If unset at every cascade layer, switchroom " + "auto-detects from /etc/timezone and warns on `reconcile` when the " + "detected zone is UTC."),
|
|
13698
13698
|
soul: exports_external.object({
|
|
13699
13699
|
name: exports_external.string().optional(),
|
|
13700
13700
|
style: exports_external.string().optional(),
|
|
@@ -13755,7 +13755,7 @@ var init_schema = __esm(() => {
|
|
|
13755
13755
|
bot_token: exports_external.string().optional().describe("Per-agent Telegram bot token or vault reference (overrides global telegram.bot_token)"),
|
|
13756
13756
|
release: ReleaseBlock.optional().describe("Per-agent release-channel pin / pointer. REPLACES the root " + "`release` block entirely (no field merge) \u2014 a pinned agent does " + "not inherit the fleet channel, and vice versa."),
|
|
13757
13757
|
bot_username: exports_external.string().optional().describe("Per-agent Telegram bot username (without leading @) when it doesn't " + "contain the agent slug. Replaces the default 'username includes slug' " + "preflight check with an exact (case-insensitive) match. Use when an " + "agent and its bot have intentionally divergent names (e.g. agent " + "'lawgpt' paired with bot '@meken_law_bot')."),
|
|
13758
|
-
timezone: exports_external.string().regex(TIMEZONE_REGEX, "timezone must be an IANA zone name like 'Australia/Melbourne' or 'UTC' " + "(three-letter aliases like EST/PST and bare offsets like UTC+10 are not accepted)").optional().describe("Per-agent IANA timezone override. Wins over any profile/defaults " + "value and over the top-level switchroom.timezone global. Controls " + "the UserPromptSubmit timezone hook's emitted local time and the " + "
|
|
13758
|
+
timezone: exports_external.string().regex(TIMEZONE_REGEX, "timezone must be an IANA zone name like 'Australia/Melbourne' or 'UTC' " + "(three-letter aliases like EST/PST and bare offsets like UTC+10 are not accepted)").optional().describe("Per-agent IANA timezone override. Wins over any profile/defaults " + "value and over the top-level switchroom.timezone global. Controls " + "the UserPromptSubmit timezone hook's emitted local time and the " + "agent container's `environment.TZ` in compose."),
|
|
13759
13759
|
auth: exports_external.object({
|
|
13760
13760
|
override: exports_external.string().min(1).optional().describe("Per-agent override of the fleet-wide `auth.active`. Edge-case use only \u2014 " + "this agent talks to the named account regardless of fleet active. See RFC H \u00a74.5.")
|
|
13761
13761
|
}).optional().describe("Account routing for switchroom-auth-broker. RFC H schema uses " + "fleet-wide `auth.active` plus per-agent `override:` for edge cases. " + "Pre-RFC-H `auth.accounts: [..]` and `auth_label:` are migrated in-place " + "on first apply (see src/auth/migrate-schema.ts)."),
|
|
@@ -47248,8 +47248,8 @@ var {
|
|
|
47248
47248
|
} = import__.default;
|
|
47249
47249
|
|
|
47250
47250
|
// src/build-info.ts
|
|
47251
|
-
var VERSION = "0.13.
|
|
47252
|
-
var COMMIT_SHA = "
|
|
47251
|
+
var VERSION = "0.13.3";
|
|
47252
|
+
var COMMIT_SHA = "e357d33b";
|
|
47253
47253
|
|
|
47254
47254
|
// src/cli/agent.ts
|
|
47255
47255
|
init_source();
|
|
@@ -50658,18 +50658,22 @@ async function summarize(opts) {
|
|
|
50658
50658
|
await mirrorToHindsight(parsed.briefing, opts).catch(() => {});
|
|
50659
50659
|
return "ok";
|
|
50660
50660
|
}
|
|
50661
|
+
function buildHandoffClaudeArgs(opts) {
|
|
50662
|
+
return [
|
|
50663
|
+
"-p",
|
|
50664
|
+
opts.user,
|
|
50665
|
+
"--model",
|
|
50666
|
+
opts.model,
|
|
50667
|
+
"--append-system-prompt",
|
|
50668
|
+
opts.system,
|
|
50669
|
+
"--no-session-persistence",
|
|
50670
|
+
"--strict-mcp-config"
|
|
50671
|
+
];
|
|
50672
|
+
}
|
|
50661
50673
|
var defaultClaudeCliRunner = {
|
|
50662
50674
|
async run({ model, system, user, timeoutMs }) {
|
|
50663
50675
|
return await new Promise((resolve14, reject) => {
|
|
50664
|
-
const args =
|
|
50665
|
-
"-p",
|
|
50666
|
-
user,
|
|
50667
|
-
"--model",
|
|
50668
|
-
model,
|
|
50669
|
-
"--append-system-prompt",
|
|
50670
|
-
system,
|
|
50671
|
-
"--no-session-persistence"
|
|
50672
|
-
];
|
|
50676
|
+
const args = buildHandoffClaudeArgs({ model, system, user });
|
|
50673
50677
|
const env2 = {
|
|
50674
50678
|
...process.env,
|
|
50675
50679
|
FORCE_COLOR: "0",
|
|
@@ -53330,7 +53334,6 @@ Scaffolding agent: ${name}
|
|
|
53330
53334
|
}
|
|
53331
53335
|
try {
|
|
53332
53336
|
const result = reconcileAgent(n, agentConfig, agentsDir, config.telegram, config, configPath, { preserveClaudeMd: opts.preserveClaudeMd });
|
|
53333
|
-
const unitChanges = [];
|
|
53334
53337
|
const allChanges = [...result.changes];
|
|
53335
53338
|
if (allChanges.length === 0) {
|
|
53336
53339
|
console.log(source_default.gray(` ${n}: already in sync`));
|
|
@@ -53341,7 +53344,7 @@ Scaffolding agent: ${name}
|
|
|
53341
53344
|
const semantics = result.changesBySemantics;
|
|
53342
53345
|
if (semantics) {
|
|
53343
53346
|
const { hot, staleTillRestart } = semantics;
|
|
53344
|
-
const restartRequired = [...semantics.restartRequired
|
|
53347
|
+
const restartRequired = [...semantics.restartRequired];
|
|
53345
53348
|
if (restartRequired.length > 0) {
|
|
53346
53349
|
console.log(source_default.yellow(`
|
|
53347
53350
|
Changed (restart required \u2014 soul/MCP/settings/start.sh):`));
|
|
@@ -53384,7 +53387,7 @@ Restart: switchroom agent restart ${n}`));
|
|
|
53384
53387
|
}
|
|
53385
53388
|
}
|
|
53386
53389
|
const changesBySemantics = result.changesBySemantics;
|
|
53387
|
-
const autoRestartNeeded = !opts.noRestart &&
|
|
53390
|
+
const autoRestartNeeded = !opts.noRestart && changesBySemantics !== undefined && changesBySemantics.restartRequired.length > 0;
|
|
53388
53391
|
const shouldRestart = (opts.restart || opts.gracefulRestart || autoRestartNeeded) && allChanges.length > 0;
|
|
53389
53392
|
if (shouldRestart) {
|
|
53390
53393
|
try {
|
|
@@ -53815,7 +53818,7 @@ switchroom agent add: ${name}
|
|
|
53815
53818
|
process.exit(1);
|
|
53816
53819
|
}
|
|
53817
53820
|
}));
|
|
53818
|
-
agent.command("rename <old> <new>").description("Rename an agent slug: stop, snapshot, rename dir +
|
|
53821
|
+
agent.command("rename <old> <new>").description("Rename an agent slug: stop, snapshot, rename dir + vault key, " + "update switchroom.yaml, reconcile, start. Rolls back on any failure.").option("--hindsight <mode>", 'Hindsight bank handling: "preserve" (default, keep old bank) or "fresh" (drop, recreate on first run). "migrate" is deferred.', "preserve").option("-y, --yes", "Skip confirmation prompt").action(withConfigError(async (oldName, newName, opts) => {
|
|
53819
53822
|
const configPath = getConfigPath(program3);
|
|
53820
53823
|
const config = getConfig(program3);
|
|
53821
53824
|
if (!config.agents[oldName]) {
|
|
@@ -53834,7 +53837,7 @@ switchroom agent add: ${name}
|
|
|
53834
53837
|
if (!opts.yes) {
|
|
53835
53838
|
process.stdout.write(source_default.yellow(`
|
|
53836
53839
|
Rename agent "${oldName}" \u2192 "${newName}"?
|
|
53837
|
-
` + ` This will: stop ${oldName}, copy dir,
|
|
53840
|
+
` + ` This will: stop ${oldName}, copy dir,
|
|
53838
53841
|
` + ` rename vault keys (if passphrase available), update switchroom.yaml,
|
|
53839
53842
|
` + ` reconcile, and start ${newName}.
|
|
53840
53843
|
` + ` Hindsight mode: ${hindsightMode}
|
|
@@ -13863,7 +13863,7 @@ var profileFields = {
|
|
|
13863
13863
|
extends: exports_external.string().optional(),
|
|
13864
13864
|
bot_token: exports_external.string().optional(),
|
|
13865
13865
|
release: ReleaseBlock.optional().describe("Release-channel pin / pointer. Either `channel` (dev|rc|latest) or " + "`pin` (sha-<hex>|v<semver>) — mutually exclusive. Per-agent value " + "REPLACES the root entirely (no field merge)."),
|
|
13866
|
-
timezone: exports_external.string().regex(TIMEZONE_REGEX, "timezone must be an IANA zone name like 'Australia/Melbourne' or 'UTC' " + "(three-letter aliases like EST/PST and bare offsets like UTC+10 are not accepted)").optional().describe("IANA timezone name (e.g. 'Australia/Melbourne', 'America/New_York', " + "'UTC'). Used to generate the per-turn local-time hint the agent's " + "UserPromptSubmit timezone hook emits, and baked into the
|
|
13866
|
+
timezone: exports_external.string().regex(TIMEZONE_REGEX, "timezone must be an IANA zone name like 'Australia/Melbourne' or 'UTC' " + "(three-letter aliases like EST/PST and bare offsets like UTC+10 are not accepted)").optional().describe("IANA timezone name (e.g. 'Australia/Melbourne', 'America/New_York', " + "'UTC'). Used to generate the per-turn local-time hint the agent's " + "UserPromptSubmit timezone hook emits, and baked into the agent " + "container's `environment.TZ` in compose so subprocess `date`/" + "`Date.now()` are correct. If unset at every cascade layer, switchroom " + "auto-detects from /etc/timezone and warns on `reconcile` when the " + "detected zone is UTC."),
|
|
13867
13867
|
soul: exports_external.object({
|
|
13868
13868
|
name: exports_external.string().optional(),
|
|
13869
13869
|
style: exports_external.string().optional(),
|
|
@@ -13924,7 +13924,7 @@ var AgentSchema = exports_external.object({
|
|
|
13924
13924
|
bot_token: exports_external.string().optional().describe("Per-agent Telegram bot token or vault reference (overrides global telegram.bot_token)"),
|
|
13925
13925
|
release: ReleaseBlock.optional().describe("Per-agent release-channel pin / pointer. REPLACES the root " + "`release` block entirely (no field merge) — a pinned agent does " + "not inherit the fleet channel, and vice versa."),
|
|
13926
13926
|
bot_username: exports_external.string().optional().describe("Per-agent Telegram bot username (without leading @) when it doesn't " + "contain the agent slug. Replaces the default 'username includes slug' " + "preflight check with an exact (case-insensitive) match. Use when an " + "agent and its bot have intentionally divergent names (e.g. agent " + "'lawgpt' paired with bot '@meken_law_bot')."),
|
|
13927
|
-
timezone: exports_external.string().regex(TIMEZONE_REGEX, "timezone must be an IANA zone name like 'Australia/Melbourne' or 'UTC' " + "(three-letter aliases like EST/PST and bare offsets like UTC+10 are not accepted)").optional().describe("Per-agent IANA timezone override. Wins over any profile/defaults " + "value and over the top-level switchroom.timezone global. Controls " + "the UserPromptSubmit timezone hook's emitted local time and the " + "
|
|
13927
|
+
timezone: exports_external.string().regex(TIMEZONE_REGEX, "timezone must be an IANA zone name like 'Australia/Melbourne' or 'UTC' " + "(three-letter aliases like EST/PST and bare offsets like UTC+10 are not accepted)").optional().describe("Per-agent IANA timezone override. Wins over any profile/defaults " + "value and over the top-level switchroom.timezone global. Controls " + "the UserPromptSubmit timezone hook's emitted local time and the " + "agent container's `environment.TZ` in compose."),
|
|
13928
13928
|
auth: exports_external.object({
|
|
13929
13929
|
override: exports_external.string().min(1).optional().describe("Per-agent override of the fleet-wide `auth.active`. Edge-case use only — " + "this agent talks to the named account regardless of fleet active. See RFC H §4.5.")
|
|
13930
13930
|
}).optional().describe("Account routing for switchroom-auth-broker. RFC H schema uses " + "fleet-wide `auth.active` plus per-agent `override:` for edge cases. " + "Pre-RFC-H `auth.accounts: [..]` and `auth_label:` are migrated in-place " + "on first apply (see src/auth/migrate-schema.ts)."),
|
|
@@ -11122,7 +11122,7 @@ var init_schema = __esm(() => {
|
|
|
11122
11122
|
extends: exports_external.string().optional(),
|
|
11123
11123
|
bot_token: exports_external.string().optional(),
|
|
11124
11124
|
release: ReleaseBlock.optional().describe("Release-channel pin / pointer. Either `channel` (dev|rc|latest) or " + "`pin` (sha-<hex>|v<semver>) — mutually exclusive. Per-agent value " + "REPLACES the root entirely (no field merge)."),
|
|
11125
|
-
timezone: exports_external.string().regex(TIMEZONE_REGEX, "timezone must be an IANA zone name like 'Australia/Melbourne' or 'UTC' " + "(three-letter aliases like EST/PST and bare offsets like UTC+10 are not accepted)").optional().describe("IANA timezone name (e.g. 'Australia/Melbourne', 'America/New_York', " + "'UTC'). Used to generate the per-turn local-time hint the agent's " + "UserPromptSubmit timezone hook emits, and baked into the
|
|
11125
|
+
timezone: exports_external.string().regex(TIMEZONE_REGEX, "timezone must be an IANA zone name like 'Australia/Melbourne' or 'UTC' " + "(three-letter aliases like EST/PST and bare offsets like UTC+10 are not accepted)").optional().describe("IANA timezone name (e.g. 'Australia/Melbourne', 'America/New_York', " + "'UTC'). Used to generate the per-turn local-time hint the agent's " + "UserPromptSubmit timezone hook emits, and baked into the agent " + "container's `environment.TZ` in compose so subprocess `date`/" + "`Date.now()` are correct. If unset at every cascade layer, switchroom " + "auto-detects from /etc/timezone and warns on `reconcile` when the " + "detected zone is UTC."),
|
|
11126
11126
|
soul: exports_external.object({
|
|
11127
11127
|
name: exports_external.string().optional(),
|
|
11128
11128
|
style: exports_external.string().optional(),
|
|
@@ -11183,7 +11183,7 @@ var init_schema = __esm(() => {
|
|
|
11183
11183
|
bot_token: exports_external.string().optional().describe("Per-agent Telegram bot token or vault reference (overrides global telegram.bot_token)"),
|
|
11184
11184
|
release: ReleaseBlock.optional().describe("Per-agent release-channel pin / pointer. REPLACES the root " + "`release` block entirely (no field merge) — a pinned agent does " + "not inherit the fleet channel, and vice versa."),
|
|
11185
11185
|
bot_username: exports_external.string().optional().describe("Per-agent Telegram bot username (without leading @) when it doesn't " + "contain the agent slug. Replaces the default 'username includes slug' " + "preflight check with an exact (case-insensitive) match. Use when an " + "agent and its bot have intentionally divergent names (e.g. agent " + "'lawgpt' paired with bot '@meken_law_bot')."),
|
|
11186
|
-
timezone: exports_external.string().regex(TIMEZONE_REGEX, "timezone must be an IANA zone name like 'Australia/Melbourne' or 'UTC' " + "(three-letter aliases like EST/PST and bare offsets like UTC+10 are not accepted)").optional().describe("Per-agent IANA timezone override. Wins over any profile/defaults " + "value and over the top-level switchroom.timezone global. Controls " + "the UserPromptSubmit timezone hook's emitted local time and the " + "
|
|
11186
|
+
timezone: exports_external.string().regex(TIMEZONE_REGEX, "timezone must be an IANA zone name like 'Australia/Melbourne' or 'UTC' " + "(three-letter aliases like EST/PST and bare offsets like UTC+10 are not accepted)").optional().describe("Per-agent IANA timezone override. Wins over any profile/defaults " + "value and over the top-level switchroom.timezone global. Controls " + "the UserPromptSubmit timezone hook's emitted local time and the " + "agent container's `environment.TZ` in compose."),
|
|
11187
11187
|
auth: exports_external.object({
|
|
11188
11188
|
override: exports_external.string().min(1).optional().describe("Per-agent override of the fleet-wide `auth.active`. Edge-case use only — " + "this agent talks to the named account regardless of fleet active. See RFC H §4.5.")
|
|
11189
11189
|
}).optional().describe("Account routing for switchroom-auth-broker. RFC H schema uses " + "fleet-wide `auth.active` plus per-agent `override:` for edge cases. " + "Pre-RFC-H `auth.accounts: [..]` and `auth_label:` are migrated in-place " + "on first apply (see src/auth/migrate-schema.ts)."),
|
|
@@ -11122,7 +11122,7 @@ var init_schema = __esm(() => {
|
|
|
11122
11122
|
extends: exports_external.string().optional(),
|
|
11123
11123
|
bot_token: exports_external.string().optional(),
|
|
11124
11124
|
release: ReleaseBlock.optional().describe("Release-channel pin / pointer. Either `channel` (dev|rc|latest) or " + "`pin` (sha-<hex>|v<semver>) — mutually exclusive. Per-agent value " + "REPLACES the root entirely (no field merge)."),
|
|
11125
|
-
timezone: exports_external.string().regex(TIMEZONE_REGEX, "timezone must be an IANA zone name like 'Australia/Melbourne' or 'UTC' " + "(three-letter aliases like EST/PST and bare offsets like UTC+10 are not accepted)").optional().describe("IANA timezone name (e.g. 'Australia/Melbourne', 'America/New_York', " + "'UTC'). Used to generate the per-turn local-time hint the agent's " + "UserPromptSubmit timezone hook emits, and baked into the
|
|
11125
|
+
timezone: exports_external.string().regex(TIMEZONE_REGEX, "timezone must be an IANA zone name like 'Australia/Melbourne' or 'UTC' " + "(three-letter aliases like EST/PST and bare offsets like UTC+10 are not accepted)").optional().describe("IANA timezone name (e.g. 'Australia/Melbourne', 'America/New_York', " + "'UTC'). Used to generate the per-turn local-time hint the agent's " + "UserPromptSubmit timezone hook emits, and baked into the agent " + "container's `environment.TZ` in compose so subprocess `date`/" + "`Date.now()` are correct. If unset at every cascade layer, switchroom " + "auto-detects from /etc/timezone and warns on `reconcile` when the " + "detected zone is UTC."),
|
|
11126
11126
|
soul: exports_external.object({
|
|
11127
11127
|
name: exports_external.string().optional(),
|
|
11128
11128
|
style: exports_external.string().optional(),
|
|
@@ -11183,7 +11183,7 @@ var init_schema = __esm(() => {
|
|
|
11183
11183
|
bot_token: exports_external.string().optional().describe("Per-agent Telegram bot token or vault reference (overrides global telegram.bot_token)"),
|
|
11184
11184
|
release: ReleaseBlock.optional().describe("Per-agent release-channel pin / pointer. REPLACES the root " + "`release` block entirely (no field merge) — a pinned agent does " + "not inherit the fleet channel, and vice versa."),
|
|
11185
11185
|
bot_username: exports_external.string().optional().describe("Per-agent Telegram bot username (without leading @) when it doesn't " + "contain the agent slug. Replaces the default 'username includes slug' " + "preflight check with an exact (case-insensitive) match. Use when an " + "agent and its bot have intentionally divergent names (e.g. agent " + "'lawgpt' paired with bot '@meken_law_bot')."),
|
|
11186
|
-
timezone: exports_external.string().regex(TIMEZONE_REGEX, "timezone must be an IANA zone name like 'Australia/Melbourne' or 'UTC' " + "(three-letter aliases like EST/PST and bare offsets like UTC+10 are not accepted)").optional().describe("Per-agent IANA timezone override. Wins over any profile/defaults " + "value and over the top-level switchroom.timezone global. Controls " + "the UserPromptSubmit timezone hook's emitted local time and the " + "
|
|
11186
|
+
timezone: exports_external.string().regex(TIMEZONE_REGEX, "timezone must be an IANA zone name like 'Australia/Melbourne' or 'UTC' " + "(three-letter aliases like EST/PST and bare offsets like UTC+10 are not accepted)").optional().describe("Per-agent IANA timezone override. Wins over any profile/defaults " + "value and over the top-level switchroom.timezone global. Controls " + "the UserPromptSubmit timezone hook's emitted local time and the " + "agent container's `environment.TZ` in compose."),
|
|
11187
11187
|
auth: exports_external.object({
|
|
11188
11188
|
override: exports_external.string().min(1).optional().describe("Per-agent override of the fleet-wide `auth.active`. Edge-case use only — " + "this agent talks to the named account regardless of fleet active. See RFC H §4.5.")
|
|
11189
11189
|
}).optional().describe("Account routing for switchroom-auth-broker. RFC H schema uses " + "fleet-wide `auth.active` plus per-agent `override:` for edge cases. " + "Pre-RFC-H `auth.accounts: [..]` and `auth_label:` are migrated in-place " + "on first apply (see src/auth/migrate-schema.ts)."),
|
package/package.json
CHANGED
|
@@ -23766,7 +23766,7 @@ var init_schema = __esm(() => {
|
|
|
23766
23766
|
extends: exports_external.string().optional(),
|
|
23767
23767
|
bot_token: exports_external.string().optional(),
|
|
23768
23768
|
release: ReleaseBlock.optional().describe("Release-channel pin / pointer. Either `channel` (dev|rc|latest) or " + "`pin` (sha-<hex>|v<semver>) \u2014 mutually exclusive. Per-agent value " + "REPLACES the root entirely (no field merge)."),
|
|
23769
|
-
timezone: exports_external.string().regex(TIMEZONE_REGEX, "timezone must be an IANA zone name like 'Australia/Melbourne' or 'UTC' " + "(three-letter aliases like EST/PST and bare offsets like UTC+10 are not accepted)").optional().describe("IANA timezone name (e.g. 'Australia/Melbourne', 'America/New_York', " + "'UTC'). Used to generate the per-turn local-time hint the agent's " + "UserPromptSubmit timezone hook emits, and baked into the
|
|
23769
|
+
timezone: exports_external.string().regex(TIMEZONE_REGEX, "timezone must be an IANA zone name like 'Australia/Melbourne' or 'UTC' " + "(three-letter aliases like EST/PST and bare offsets like UTC+10 are not accepted)").optional().describe("IANA timezone name (e.g. 'Australia/Melbourne', 'America/New_York', " + "'UTC'). Used to generate the per-turn local-time hint the agent's " + "UserPromptSubmit timezone hook emits, and baked into the agent " + "container's `environment.TZ` in compose so subprocess `date`/" + "`Date.now()` are correct. If unset at every cascade layer, switchroom " + "auto-detects from /etc/timezone and warns on `reconcile` when the " + "detected zone is UTC."),
|
|
23770
23770
|
soul: exports_external.object({
|
|
23771
23771
|
name: exports_external.string().optional(),
|
|
23772
23772
|
style: exports_external.string().optional(),
|
|
@@ -23827,7 +23827,7 @@ var init_schema = __esm(() => {
|
|
|
23827
23827
|
bot_token: exports_external.string().optional().describe("Per-agent Telegram bot token or vault reference (overrides global telegram.bot_token)"),
|
|
23828
23828
|
release: ReleaseBlock.optional().describe("Per-agent release-channel pin / pointer. REPLACES the root " + "`release` block entirely (no field merge) \u2014 a pinned agent does " + "not inherit the fleet channel, and vice versa."),
|
|
23829
23829
|
bot_username: exports_external.string().optional().describe("Per-agent Telegram bot username (without leading @) when it doesn't " + "contain the agent slug. Replaces the default 'username includes slug' " + "preflight check with an exact (case-insensitive) match. Use when an " + "agent and its bot have intentionally divergent names (e.g. agent " + "'lawgpt' paired with bot '@meken_law_bot')."),
|
|
23830
|
-
timezone: exports_external.string().regex(TIMEZONE_REGEX, "timezone must be an IANA zone name like 'Australia/Melbourne' or 'UTC' " + "(three-letter aliases like EST/PST and bare offsets like UTC+10 are not accepted)").optional().describe("Per-agent IANA timezone override. Wins over any profile/defaults " + "value and over the top-level switchroom.timezone global. Controls " + "the UserPromptSubmit timezone hook's emitted local time and the " + "
|
|
23830
|
+
timezone: exports_external.string().regex(TIMEZONE_REGEX, "timezone must be an IANA zone name like 'Australia/Melbourne' or 'UTC' " + "(three-letter aliases like EST/PST and bare offsets like UTC+10 are not accepted)").optional().describe("Per-agent IANA timezone override. Wins over any profile/defaults " + "value and over the top-level switchroom.timezone global. Controls " + "the UserPromptSubmit timezone hook's emitted local time and the " + "agent container's `environment.TZ` in compose."),
|
|
23831
23831
|
auth: exports_external.object({
|
|
23832
23832
|
override: exports_external.string().min(1).optional().describe("Per-agent override of the fleet-wide `auth.active`. Edge-case use only \u2014 " + "this agent talks to the named account regardless of fleet active. See RFC H \u00a74.5.")
|
|
23833
23833
|
}).optional().describe("Account routing for switchroom-auth-broker. RFC H schema uses " + "fleet-wide `auth.active` plus per-agent `override:` for edge cases. " + "Pre-RFC-H `auth.accounts: [..]` and `auth_label:` are migrated in-place " + "on first apply (see src/auth/migrate-schema.ts)."),
|
|
@@ -27542,16 +27542,17 @@ function uptimeMsForStarttime(starttimeTicks, fs2 = realProcFs) {
|
|
|
27542
27542
|
}
|
|
27543
27543
|
}
|
|
27544
27544
|
function nextStepForAgentState(agentName3, state4) {
|
|
27545
|
+
const tailCmd = process.env.SWITCHROOM_RUNTIME === "docker" ? `docker logs --tail 100 switchroom-${agentName3}` : `journalctl --user -u switchroom-${agentName3} -n 100`;
|
|
27545
27546
|
if (state4 === "failed") {
|
|
27546
|
-
return `Service failed \u2014 inspect with
|
|
27547
|
+
return `Service failed \u2014 inspect with \`${tailCmd}\` then \`switchroom agent restart ${agentName3}\``;
|
|
27547
27548
|
}
|
|
27548
27549
|
if (state4 === "inactive") {
|
|
27549
|
-
return `Service inactive \u2014 start with \`switchroom agent start ${agentName3}
|
|
27550
|
+
return `Service inactive \u2014 start with \`switchroom agent start ${agentName3}\``;
|
|
27550
27551
|
}
|
|
27551
27552
|
if (state4 === "deactivating" || state4 === "activating" || state4 === "auto-restart") {
|
|
27552
27553
|
return `Service is in a transient \`${state4}\` state \u2014 re-check with \`switchroom agent status ${agentName3}\` in a few seconds`;
|
|
27553
27554
|
}
|
|
27554
|
-
return `Inspect with
|
|
27555
|
+
return `Inspect with \`${tailCmd}\``;
|
|
27555
27556
|
}
|
|
27556
27557
|
function probeAgentProcessDocker() {
|
|
27557
27558
|
const found = findAgentProcessInContainer();
|
|
@@ -37121,6 +37122,7 @@ function startTimer(deps) {
|
|
|
37121
37122
|
import { existsSync as existsSync5, readFileSync as readFileSync3, writeFileSync as writeFileSync3, unlinkSync, mkdirSync as mkdirSync5 } from "node:fs";
|
|
37122
37123
|
import { dirname as dirname6, join as join6 } from "node:path";
|
|
37123
37124
|
import { homedir as homedir2 } from "node:os";
|
|
37125
|
+
var SILENT_END_MAX_RETRIES = 1;
|
|
37124
37126
|
function resolveStateDir(deps) {
|
|
37125
37127
|
if (deps?.stateDir != null)
|
|
37126
37128
|
return deps.stateDir;
|
|
@@ -37182,6 +37184,27 @@ function clearSilentEndState(turnKey, deps) {
|
|
|
37182
37184
|
`);
|
|
37183
37185
|
} catch {}
|
|
37184
37186
|
}
|
|
37187
|
+
function readSilentEndState(deps) {
|
|
37188
|
+
const statePath = resolveStatePath(deps);
|
|
37189
|
+
if (!existsSync5(statePath))
|
|
37190
|
+
return null;
|
|
37191
|
+
try {
|
|
37192
|
+
return JSON.parse(readFileSync3(statePath, "utf8"));
|
|
37193
|
+
} catch {
|
|
37194
|
+
return null;
|
|
37195
|
+
}
|
|
37196
|
+
}
|
|
37197
|
+
function recordSilentTurnEnd(args, deps) {
|
|
37198
|
+
const prev = readSilentEndState(deps);
|
|
37199
|
+
if (prev != null && prev.turnKey === args.turnKey && prev.retryCount >= SILENT_END_MAX_RETRIES) {
|
|
37200
|
+
clearSilentEndState(args.turnKey, deps);
|
|
37201
|
+
emitLog(deps, `silent-end: re-prompt exhausted for turnKey=${args.turnKey} ` + `(retryCount=${prev.retryCount} >= ${SILENT_END_MAX_RETRIES}) \u2014 ` + `caller should deliver a fallback
|
|
37202
|
+
`);
|
|
37203
|
+
return { exhausted: true };
|
|
37204
|
+
}
|
|
37205
|
+
writeSilentEndState(args, deps);
|
|
37206
|
+
return { exhausted: false };
|
|
37207
|
+
}
|
|
37185
37208
|
|
|
37186
37209
|
// turn-flush-safety.ts
|
|
37187
37210
|
var SILENT_MARKERS = new Set(["NO_REPLY", "HEARTBEAT_OK"]);
|
|
@@ -47679,10 +47702,10 @@ function sweepStaleTurnActiveMarker(stateDir, opts) {
|
|
|
47679
47702
|
}
|
|
47680
47703
|
|
|
47681
47704
|
// ../src/build-info.ts
|
|
47682
|
-
var VERSION = "0.13.
|
|
47683
|
-
var COMMIT_SHA = "
|
|
47684
|
-
var COMMIT_DATE = "2026-05-
|
|
47685
|
-
var LATEST_PR =
|
|
47705
|
+
var VERSION = "0.13.3";
|
|
47706
|
+
var COMMIT_SHA = "e357d33b";
|
|
47707
|
+
var COMMIT_DATE = "2026-05-21T07:05:47Z";
|
|
47708
|
+
var LATEST_PR = 1621;
|
|
47686
47709
|
var COMMITS_AHEAD_OF_TAG = 0;
|
|
47687
47710
|
|
|
47688
47711
|
// gateway/boot-version.ts
|
|
@@ -48170,6 +48193,7 @@ function resolveCallingSubagent(opts) {
|
|
|
48170
48193
|
|
|
48171
48194
|
// gateway/gateway.ts
|
|
48172
48195
|
var REPLY_TO_TEXT_MAX = 200;
|
|
48196
|
+
var SILENT_END_FALLBACK_TEXT = "\u26A0\uFE0F The agent finished working but didn\u2019t send a reply \u2014 your last " + "message may not have been answered. Please try asking again.";
|
|
48173
48197
|
installStderrTimestamps();
|
|
48174
48198
|
installPluginLogger();
|
|
48175
48199
|
installGlobalErrorHandlers();
|
|
@@ -48632,21 +48656,18 @@ function statusKey(chatId, threadId) {
|
|
|
48632
48656
|
function streamKey3(chatId, threadId) {
|
|
48633
48657
|
return chatKey(chatId, threadId);
|
|
48634
48658
|
}
|
|
48635
|
-
function
|
|
48659
|
+
function purgeReactionTracking(key, endingTurn) {
|
|
48660
|
+
const outboundEmitted = endingTurn != null ? endingTurn.replyCalled === true : currentTurn?.replyCalled === true;
|
|
48661
|
+
shadowEmit({ kind: "turnEnd", key, at: Date.now(), outboundEmitted });
|
|
48636
48662
|
const msgInfo = activeReactionMsgIds.get(key);
|
|
48637
48663
|
activeStatusReactions.delete(key);
|
|
48638
48664
|
activeReactionMsgIds.delete(key);
|
|
48665
|
+
activeTurnStartedAt.delete(key);
|
|
48639
48666
|
if (msgInfo) {
|
|
48640
48667
|
const agentDir = resolveAgentDirFromEnv();
|
|
48641
48668
|
if (agentDir != null)
|
|
48642
48669
|
removeActiveReaction(agentDir, msgInfo.chatId, msgInfo.messageId);
|
|
48643
48670
|
}
|
|
48644
|
-
}
|
|
48645
|
-
function purgeReactionTracking(key, endingTurn, outboundEmittedOverride) {
|
|
48646
|
-
const outboundEmitted = outboundEmittedOverride !== undefined ? outboundEmittedOverride : endingTurn != null ? endingTurn.replyCalled === true : currentTurn?.replyCalled === true;
|
|
48647
|
-
shadowEmit({ kind: "turnEnd", key, at: Date.now(), outboundEmitted });
|
|
48648
|
-
clearReactionState(key);
|
|
48649
|
-
activeTurnStartedAt.delete(key);
|
|
48650
48671
|
if (activeTurnStartedAt.size === 0) {
|
|
48651
48672
|
const selfAgentForFlush = process.env.SWITCHROOM_AGENT_NAME ?? "";
|
|
48652
48673
|
if (pendingInboundBuffer.depth(selfAgentForFlush) > 0) {
|
|
@@ -48796,7 +48817,7 @@ function endStatusReaction(chatId, threadId, outcome) {
|
|
|
48796
48817
|
ctrl.setDone();
|
|
48797
48818
|
else
|
|
48798
48819
|
ctrl.setError();
|
|
48799
|
-
|
|
48820
|
+
purgeReactionTracking(key);
|
|
48800
48821
|
}
|
|
48801
48822
|
function resolveThreadId(chat_id, explicit) {
|
|
48802
48823
|
if (explicit != null)
|
|
@@ -49519,8 +49540,8 @@ startTimer({
|
|
|
49519
49540
|
lastPtyPreviewByChat.delete(fbKey);
|
|
49520
49541
|
preambleSuppressor.dropNow();
|
|
49521
49542
|
endTurn(fbKey);
|
|
49522
|
-
purgeReactionTracking(fbKey
|
|
49523
|
-
const fbExtraPurge = purgeStaleTurnsForChat(fbChatId, activeTurnStartedAt.keys(),
|
|
49543
|
+
purgeReactionTracking(fbKey);
|
|
49544
|
+
const fbExtraPurge = purgeStaleTurnsForChat(fbChatId, activeTurnStartedAt.keys(), purgeReactionTracking);
|
|
49524
49545
|
if (turnMatchesFallback && currentTurn === wedgedTurn)
|
|
49525
49546
|
currentTurn = null;
|
|
49526
49547
|
try {
|
|
@@ -51342,6 +51363,7 @@ function handleSessionEvent(ev) {
|
|
|
51342
51363
|
const ctrl = activeStatusReactions.get(ceKey);
|
|
51343
51364
|
if (ctrl)
|
|
51344
51365
|
ctrl.setError();
|
|
51366
|
+
purgeReactionTracking(ceKey);
|
|
51345
51367
|
endTurn(ceKey);
|
|
51346
51368
|
if (turn.answerStream != null) {
|
|
51347
51369
|
turn.answerStream.stop();
|
|
@@ -51424,6 +51446,7 @@ function handleSessionEvent(ev) {
|
|
|
51424
51446
|
unpinProgressCardForChat?.(chatId, threadId);
|
|
51425
51447
|
if (ctrl)
|
|
51426
51448
|
ctrl.setDone();
|
|
51449
|
+
purgeReactionTracking(statusKey(chatId, threadId));
|
|
51427
51450
|
{
|
|
51428
51451
|
const sKey = streamKey3(chatId, threadId);
|
|
51429
51452
|
const turnDurationMs = turn.startedAt > 0 ? Date.now() - turn.startedAt : 0;
|
|
@@ -51494,7 +51517,7 @@ function handleSessionEvent(ev) {
|
|
|
51494
51517
|
if (recentCount > 0) {
|
|
51495
51518
|
process.stderr.write(`telegram gateway: turn-flush suppressed \u2014 reply tool sent ${recentCount} message(s) within 2s
|
|
51496
51519
|
`);
|
|
51497
|
-
purgeReactionTracking(statusKey(backstopChatId, backstopThreadId)
|
|
51520
|
+
purgeReactionTracking(statusKey(backstopChatId, backstopThreadId));
|
|
51498
51521
|
return;
|
|
51499
51522
|
}
|
|
51500
51523
|
} catch {}
|
|
@@ -51579,13 +51602,14 @@ function handleSessionEvent(ev) {
|
|
|
51579
51602
|
if (backstopCtrl)
|
|
51580
51603
|
backstopCtrl.setError();
|
|
51581
51604
|
} finally {
|
|
51582
|
-
purgeReactionTracking(statusKey(backstopChatId, backstopThreadId)
|
|
51605
|
+
purgeReactionTracking(statusKey(backstopChatId, backstopThreadId));
|
|
51583
51606
|
}
|
|
51584
51607
|
})();
|
|
51585
51608
|
return;
|
|
51586
51609
|
}
|
|
51587
51610
|
if (ctrl)
|
|
51588
51611
|
ctrl.setDone();
|
|
51612
|
+
purgeReactionTracking(statusKey(chatId, threadId));
|
|
51589
51613
|
{
|
|
51590
51614
|
const sKey = streamKey3(chatId, threadId);
|
|
51591
51615
|
const turnDurationMs = turn.startedAt > 0 ? Date.now() - turn.startedAt : 0;
|
|
@@ -51610,11 +51634,19 @@ function handleSessionEvent(ev) {
|
|
|
51610
51634
|
ended_via: outboundMetrics.outboundCount > 0 ? "reply" : "silent"
|
|
51611
51635
|
});
|
|
51612
51636
|
if (outboundMetrics.outboundCount === 0) {
|
|
51613
|
-
|
|
51637
|
+
const silentEnd = recordSilentTurnEnd({
|
|
51614
51638
|
chatId,
|
|
51615
51639
|
threadId: threadId ?? null,
|
|
51616
51640
|
turnKey: tKey
|
|
51617
51641
|
});
|
|
51642
|
+
if (silentEnd.exhausted) {
|
|
51643
|
+
process.stderr.write(`telegram gateway: WARN silent-end fallback \u2014 agent stayed ` + `silent after the Stop-hook re-prompt; delivering fallback message chat=${chatId} turnKey=${tKey} (#1161)
|
|
51644
|
+
`);
|
|
51645
|
+
retryWithThreadFallback(robustApiCall, (tid) => bot.api.sendMessage(chatId, SILENT_END_FALLBACK_TEXT, tid != null ? { message_thread_id: tid } : {}), { threadId, chat_id: chatId, verb: "silent-end-fallback.sendMessage" }).catch((err) => {
|
|
51646
|
+
process.stderr.write(`telegram gateway: silent-end fallback send failed: ${err instanceof Error ? err.message : String(err)}
|
|
51647
|
+
`);
|
|
51648
|
+
});
|
|
51649
|
+
}
|
|
51618
51650
|
}
|
|
51619
51651
|
clear(tKey);
|
|
51620
51652
|
endTurn(tKey);
|
|
@@ -422,24 +422,31 @@ export function uptimeMsForStarttime(
|
|
|
422
422
|
}
|
|
423
423
|
|
|
424
424
|
/**
|
|
425
|
-
* Compute a remediation hint for a non-active agent
|
|
425
|
+
* Compute a remediation hint for a non-active agent state. Returns
|
|
426
426
|
* `undefined` when no actionable hint applies. Per `reference/principles.md`
|
|
427
427
|
* principle 1, every degraded/fail row should tell the user what to do next.
|
|
428
|
-
*
|
|
429
|
-
* agents
|
|
428
|
+
*
|
|
429
|
+
* Runtime-aware: v0.7+ agents run in Docker — there is no systemd unit or
|
|
430
|
+
* `journalctl` in-container, so the log-tail command is gated on
|
|
431
|
+
* `SWITCHROOM_RUNTIME` exactly like the boot-card crash row (see
|
|
432
|
+
* `boot-card.ts` and #1376/#1382). All hints share a common log-tail shape
|
|
433
|
+
* so they stay greppable across agents.
|
|
430
434
|
*/
|
|
431
435
|
function nextStepForAgentState(agentName: string, state: string): string | undefined {
|
|
436
|
+
const tailCmd = process.env.SWITCHROOM_RUNTIME === 'docker'
|
|
437
|
+
? `docker logs --tail 100 switchroom-${agentName}`
|
|
438
|
+
: `journalctl --user -u switchroom-${agentName} -n 100`
|
|
432
439
|
if (state === 'failed') {
|
|
433
|
-
return `Service failed — inspect with
|
|
440
|
+
return `Service failed — inspect with \`${tailCmd}\` then \`switchroom agent restart ${agentName}\``
|
|
434
441
|
}
|
|
435
442
|
if (state === 'inactive') {
|
|
436
|
-
return `Service inactive — start with \`switchroom agent start ${agentName}
|
|
443
|
+
return `Service inactive — start with \`switchroom agent start ${agentName}\``
|
|
437
444
|
}
|
|
438
445
|
if (state === 'deactivating' || state === 'activating' || state === 'auto-restart') {
|
|
439
446
|
return `Service is in a transient \`${state}\` state — re-check with \`switchroom agent status ${agentName}\` in a few seconds`
|
|
440
447
|
}
|
|
441
448
|
// Unknown state — keep the door open with a generic hint.
|
|
442
|
-
return `Inspect with
|
|
449
|
+
return `Inspect with \`${tailCmd}\``
|
|
443
450
|
}
|
|
444
451
|
|
|
445
452
|
function probeAgentProcessDocker(): ProbeResult {
|