switchroom 0.16.47 → 0.17.0

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.
Files changed (106) hide show
  1. package/dist/agent-scheduler/index.js +3 -1
  2. package/dist/auth-broker/index.js +24 -8
  3. package/dist/cli/drive-write-pretool.mjs +0 -5
  4. package/dist/cli/notion-write-pretool.mjs +3 -1
  5. package/dist/cli/switchroom.js +1358 -1030
  6. package/dist/cli/ui/index.html +84 -12
  7. package/dist/host-control/main.js +53 -17
  8. package/dist/vault/approvals/kernel-server.js +4 -1
  9. package/dist/vault/broker/server.js +201 -56
  10. package/package.json +3 -3
  11. package/profiles/_base/cron-session.sh.hbs +1 -1
  12. package/profiles/_base/start.sh.hbs +54 -3
  13. package/skills/switchroom-architecture/telegram.md +8 -15
  14. package/skills/switchroom-cli/SKILL.md +4 -5
  15. package/skills/telegram-test-harness/SKILL.md +1 -1
  16. package/telegram-plugin/README.md +18 -29
  17. package/telegram-plugin/bridge/bridge.ts +1 -41
  18. package/telegram-plugin/bridge/tool-filter.ts +3 -4
  19. package/telegram-plugin/dist/bridge/bridge.js +8 -43
  20. package/telegram-plugin/dist/gateway/gateway.js +682 -773
  21. package/telegram-plugin/dist/server.js +8 -43
  22. package/telegram-plugin/gateway/busy-key-reaper.ts +113 -0
  23. package/telegram-plugin/gateway/disconnect-flush.ts +11 -0
  24. package/telegram-plugin/gateway/escalation-bridge-gate.ts +46 -0
  25. package/telegram-plugin/gateway/gate-parity-probe.ts +102 -0
  26. package/telegram-plugin/gateway/gateway.ts +518 -624
  27. package/telegram-plugin/gateway/inbound-delivery-confirm.ts +89 -7
  28. package/telegram-plugin/gateway/inbound-spool.ts +108 -10
  29. package/telegram-plugin/gateway/model-command.ts +51 -3
  30. package/telegram-plugin/gateway/pending-inbound-buffer.ts +26 -0
  31. package/telegram-plugin/gateway/represent-guard.ts +28 -11
  32. package/telegram-plugin/gateway/status-pin-store.ts +124 -45
  33. package/telegram-plugin/gateway/worker-feed-dispatch.ts +19 -0
  34. package/telegram-plugin/history.ts +5 -0
  35. package/telegram-plugin/hooks/silent-end-interrupt-stop.mjs +1 -2
  36. package/telegram-plugin/hooks/subagent-tracker-pretool.mjs +9 -1
  37. package/telegram-plugin/registry/subagents-schema.ts +126 -1
  38. package/telegram-plugin/registry/turns-schema.ts +65 -1
  39. package/telegram-plugin/session-tail.ts +26 -4
  40. package/telegram-plugin/slot-banner-driver.ts +42 -2
  41. package/telegram-plugin/status-query-telemetry.ts +100 -0
  42. package/telegram-plugin/stream-reply-handler.ts +15 -16
  43. package/telegram-plugin/subagent-watcher.ts +182 -30
  44. package/telegram-plugin/tests/buffer-gate-broadened.test.ts +4 -10
  45. package/telegram-plugin/tests/busy-key-reaper.test.ts +191 -0
  46. package/telegram-plugin/tests/emission-authority-facade.test.ts +11 -17
  47. package/telegram-plugin/tests/emission-determinism-wiring.test.ts +5 -26
  48. package/telegram-plugin/tests/escalation-bridge-gate.test.ts +38 -0
  49. package/telegram-plugin/tests/gate-parity-probe.test.ts +171 -0
  50. package/telegram-plugin/tests/gateway-disconnect-flush.test.ts +13 -0
  51. package/telegram-plugin/tests/gateway-outbound-redact.test.ts +14 -11
  52. package/telegram-plugin/tests/inbound-delivery-confirm.test.ts +146 -0
  53. package/telegram-plugin/tests/inbound-spool.test.ts +143 -0
  54. package/telegram-plugin/tests/model-command.test.ts +54 -1
  55. package/telegram-plugin/tests/multitopic-routing-wiring.test.ts +5 -11
  56. package/telegram-plugin/tests/nested-worker-visibility-harness.test.ts +329 -0
  57. package/telegram-plugin/tests/pending-inbound-buffer.test.ts +53 -0
  58. package/telegram-plugin/tests/progress-update-redact.test.ts +99 -0
  59. package/telegram-plugin/tests/registry-turns.test.ts +67 -0
  60. package/telegram-plugin/tests/represent-guard.test.ts +42 -6
  61. package/telegram-plugin/tests/resume-inbound-builder.test.ts +1 -0
  62. package/telegram-plugin/tests/session-tail.test.ts +10 -1
  63. package/telegram-plugin/tests/slot-banner-boot-recovery.test.ts +246 -0
  64. package/telegram-plugin/tests/status-pin-boot-recovery.test.ts +0 -14
  65. package/telegram-plugin/tests/status-pin-store.test.ts +220 -5
  66. package/telegram-plugin/tests/status-query-telemetry.test.ts +115 -0
  67. package/telegram-plugin/tests/subagent-nested-dispatch.test.ts +209 -0
  68. package/telegram-plugin/tests/subagent-tracker-hooks.test.ts +37 -0
  69. package/telegram-plugin/tests/subagent-watcher-boot-promotion-replay.test.ts +167 -0
  70. package/telegram-plugin/tests/subagent-watcher-env-thresholds.test.ts +46 -3
  71. package/telegram-plugin/tests/subagent-watcher-stall-notification.test.ts +70 -0
  72. package/telegram-plugin/tests/tool-activity-summary.test.ts +16 -0
  73. package/telegram-plugin/tests/tool-filter.test.ts +1 -3
  74. package/telegram-plugin/tests/tool-label-pretool.test.ts +1 -4
  75. package/telegram-plugin/tests/turn-flush-safety.test.ts +222 -1
  76. package/telegram-plugin/tests/worker-activity-feed.test.ts +202 -9
  77. package/telegram-plugin/tests/worker-feed-dispatch.test.ts +25 -0
  78. package/telegram-plugin/tests/worker-visibility-prose-silent-harness.test.ts +295 -0
  79. package/telegram-plugin/tool-activity-summary.ts +19 -0
  80. package/telegram-plugin/turn-flush-safety.ts +16 -1
  81. package/telegram-plugin/uat/scenarios/jtbd-answer-pings.test.ts +8 -9
  82. package/telegram-plugin/uat/scenarios/jtbd-foreground-feed-visibility-dm.test.ts +1 -1
  83. package/telegram-plugin/uat/scenarios/jtbd-narration-intent-dm.test.ts +1 -1
  84. package/telegram-plugin/worker-activity-feed.ts +75 -15
  85. package/vendor/hindsight-memory/CHANGELOG.md +24 -0
  86. package/vendor/hindsight-memory/README.md +5 -0
  87. package/vendor/hindsight-memory/scripts/lib/client.py +31 -1
  88. package/vendor/hindsight-memory/scripts/lib/config.py +41 -2
  89. package/vendor/hindsight-memory/scripts/lib/content.py +4 -1
  90. package/vendor/hindsight-memory/scripts/lib/daemon.py +11 -2
  91. package/vendor/hindsight-memory/scripts/recall.py +74 -1
  92. package/vendor/hindsight-memory/scripts/retain.py +8 -1
  93. package/vendor/hindsight-memory/scripts/tests/test_config_client_casts.py +111 -0
  94. package/vendor/hindsight-memory/scripts/tests/test_recall_integration.py +85 -1
  95. package/vendor/hindsight-memory/scripts/tests/test_recall_tag_filters.py +107 -0
  96. package/vendor/hindsight-memory/settings.json +4 -0
  97. package/vendor/hindsight-memory/tests/test_client.py +130 -0
  98. package/vendor/hindsight-memory/tests/test_config.py +47 -0
  99. package/vendor/hindsight-memory/tests/test_content.py +18 -0
  100. package/vendor/hindsight-memory/tests/test_hooks.py +62 -0
  101. package/telegram-plugin/gateway/error-envelope-card.ts +0 -64
  102. package/telegram-plugin/gateway/resolve-calling-subagent.ts +0 -78
  103. package/telegram-plugin/silent-reply.ts +0 -58
  104. package/telegram-plugin/tests/error-envelope-unlock-card.test.ts +0 -79
  105. package/telegram-plugin/tests/resolve-calling-subagent.test.ts +0 -269
  106. package/telegram-plugin/tests/silent-reply-guard.test.ts +0 -122
@@ -11123,7 +11123,9 @@ var SessionContinuitySchema = exports_external.object({
11123
11123
  enabled: exports_external.boolean().optional().describe("Master switch for the session-handoff briefing (default true)."),
11124
11124
  max_turns_in_briefing: exports_external.number().int().positive().optional().describe("Cap on recent user/assistant turn pairs fed to the summarizer."),
11125
11125
  resume_mode: exports_external.enum(["auto", "continue", "handoff", "none"]).optional().describe("How to resume the next session. 'handoff' (default as of #362) " + "never passes --continue; a fresh Claude starts each restart and " + "reads a briefing assembled from recent Telegram messages, Hindsight " + "recall, and today's daily memory file. 'auto' uses --continue when " + "the latest JSONL is smaller than resume_max_bytes, else falls back " + "to the handoff briefing. 'continue' always passes --continue. " + "'none' starts completely fresh every time."),
11126
- resume_max_bytes: exports_external.number().int().positive().optional().describe("Byte threshold above which 'auto' mode falls back to handoff " + "instead of --continue. Default 2_000_000 (~2MB). Large transcripts " + "can blow out the context window even with prefix caching, and " + "--continue replay is known-fragile at scale.")
11126
+ resume_max_bytes: exports_external.number().int().positive().optional().describe("Byte threshold above which 'auto' mode falls back to handoff " + "instead of --continue. Default 2_000_000 (~2MB). Large transcripts " + "can blow out the context window even with prefix caching, and " + "--continue replay is known-fragile at scale."),
11127
+ session_retention_max_count: exports_external.number().int().nonnegative().optional().describe("Session-JSONL retention (issue #2792): keep at most this many " + "newest session transcripts under .claude/projects; older ones " + "past both this count and the age bound are pruned by the Stop " + "hook. The newest sessions (and the handoff source) are always " + "kept. Default 20; set 0 to disable the count bound."),
11128
+ session_retention_max_age_days: exports_external.number().int().nonnegative().optional().describe("Session-JSONL retention (issue #2792): prune session transcripts " + "older than this many days (a file is deleted only when it is BOTH " + "over the count bound and older than this). Default 30; set 0 to " + "disable the age bound.")
11127
11129
  }).optional();
11128
11130
  var webhookDispatchRule = exports_external.object({
11129
11131
  description: exports_external.string().optional(),
@@ -11123,7 +11123,9 @@ var SessionContinuitySchema = exports_external.object({
11123
11123
  enabled: exports_external.boolean().optional().describe("Master switch for the session-handoff briefing (default true)."),
11124
11124
  max_turns_in_briefing: exports_external.number().int().positive().optional().describe("Cap on recent user/assistant turn pairs fed to the summarizer."),
11125
11125
  resume_mode: exports_external.enum(["auto", "continue", "handoff", "none"]).optional().describe("How to resume the next session. 'handoff' (default as of #362) " + "never passes --continue; a fresh Claude starts each restart and " + "reads a briefing assembled from recent Telegram messages, Hindsight " + "recall, and today's daily memory file. 'auto' uses --continue when " + "the latest JSONL is smaller than resume_max_bytes, else falls back " + "to the handoff briefing. 'continue' always passes --continue. " + "'none' starts completely fresh every time."),
11126
- resume_max_bytes: exports_external.number().int().positive().optional().describe("Byte threshold above which 'auto' mode falls back to handoff " + "instead of --continue. Default 2_000_000 (~2MB). Large transcripts " + "can blow out the context window even with prefix caching, and " + "--continue replay is known-fragile at scale.")
11126
+ resume_max_bytes: exports_external.number().int().positive().optional().describe("Byte threshold above which 'auto' mode falls back to handoff " + "instead of --continue. Default 2_000_000 (~2MB). Large transcripts " + "can blow out the context window even with prefix caching, and " + "--continue replay is known-fragile at scale."),
11127
+ session_retention_max_count: exports_external.number().int().nonnegative().optional().describe("Session-JSONL retention (issue #2792): keep at most this many " + "newest session transcripts under .claude/projects; older ones " + "past both this count and the age bound are pruned by the Stop " + "hook. The newest sessions (and the handoff source) are always " + "kept. Default 20; set 0 to disable the count bound."),
11128
+ session_retention_max_age_days: exports_external.number().int().nonnegative().optional().describe("Session-JSONL retention (issue #2792): prune session transcripts " + "older than this many days (a file is deleted only when it is BOTH " + "over the count bound and older than this). Default 30; set 0 to " + "disable the age bound.")
11127
11129
  }).optional();
11128
11130
  var webhookDispatchRule = exports_external.object({
11129
11131
  description: exports_external.string().optional(),
@@ -12413,6 +12415,25 @@ var CONTAINER_DEFAULT_UTC_ZONES = new Set([
12413
12415
  "Universal"
12414
12416
  ]);
12415
12417
 
12418
+ // src/broker-common/peercred-path.ts
12419
+ function matchSocketName(socketPath, patterns, maxNameLen) {
12420
+ if (typeof socketPath !== "string" || socketPath.length === 0)
12421
+ return null;
12422
+ let name = null;
12423
+ for (const re of patterns) {
12424
+ const m = socketPath.match(re);
12425
+ if (m && typeof m[1] === "string") {
12426
+ name = m[1];
12427
+ break;
12428
+ }
12429
+ }
12430
+ if (name === null || name.length === 0)
12431
+ return null;
12432
+ if (maxNameLen !== undefined && name.length > maxNameLen)
12433
+ return null;
12434
+ return name;
12435
+ }
12436
+
12416
12437
  // src/vault/broker/peercred.ts
12417
12438
  var RESERVED_AGENT_NAMES = new Set(["operator", "hostd"]);
12418
12439
  function isReservedAgentName(name) {
@@ -13481,15 +13502,10 @@ class ProviderRegistry {
13481
13502
 
13482
13503
  // src/auth/broker/peercred.ts
13483
13504
  var AUTH_BROKER_SOCKET_PATH_RE = /^\/run\/switchroom\/auth-broker\/([a-zA-Z0-9][a-zA-Z0-9_-]*)\/sock$/;
13505
+ var AUTH_BROKER_MAX_NAME_LEN = 63;
13484
13506
  var RESERVED_NAMES = new Set(["operator"]);
13485
13507
  function socketPathToName(socketPath) {
13486
- const m = AUTH_BROKER_SOCKET_PATH_RE.exec(socketPath);
13487
- if (!m)
13488
- return null;
13489
- const name = m[1];
13490
- if (name.length === 0 || name.length > 63)
13491
- return null;
13492
- return name;
13508
+ return matchSocketName(socketPath, [AUTH_BROKER_SOCKET_PATH_RE], AUTH_BROKER_MAX_NAME_LEN);
13493
13509
  }
13494
13510
  function classify(socketPath, config) {
13495
13511
  const name = socketPathToName(socketPath);
@@ -4253,13 +4253,11 @@ var exports_client = {};
4253
4253
  __export(exports_client, {
4254
4254
  withAuthBrokerClient: () => withAuthBrokerClient,
4255
4255
  resolveAuthBrokerSocketPath: () => resolveAuthBrokerSocketPath,
4256
- authBrokerSocketExists: () => authBrokerSocketExists,
4257
4256
  AuthBrokerUnreachableError: () => AuthBrokerUnreachableError,
4258
4257
  AuthBrokerError: () => AuthBrokerError,
4259
4258
  AuthBrokerClient: () => AuthBrokerClient
4260
4259
  });
4261
4260
  import * as net from "node:net";
4262
- import { existsSync } from "node:fs";
4263
4261
  import { homedir } from "node:os";
4264
4262
  import { randomUUID } from "node:crypto";
4265
4263
  import { join } from "node:path";
@@ -4560,9 +4558,6 @@ async function withAuthBrokerClient(fn, opts) {
4560
4558
  await client.close();
4561
4559
  }
4562
4560
  }
4563
- function authBrokerSocketExists(opts) {
4564
- return existsSync(resolveAuthBrokerSocketPath(opts));
4565
- }
4566
4561
  var DEFAULT_TIMEOUT_MS = 5000, AuthBrokerError, AuthBrokerUnreachableError;
4567
4562
  var init_client = __esm(() => {
4568
4563
  init_protocol();
@@ -11871,7 +11871,9 @@ var SessionContinuitySchema = exports_external.object({
11871
11871
  enabled: exports_external.boolean().optional().describe("Master switch for the session-handoff briefing (default true)."),
11872
11872
  max_turns_in_briefing: exports_external.number().int().positive().optional().describe("Cap on recent user/assistant turn pairs fed to the summarizer."),
11873
11873
  resume_mode: exports_external.enum(["auto", "continue", "handoff", "none"]).optional().describe("How to resume the next session. 'handoff' (default as of #362) " + "never passes --continue; a fresh Claude starts each restart and " + "reads a briefing assembled from recent Telegram messages, Hindsight " + "recall, and today's daily memory file. 'auto' uses --continue when " + "the latest JSONL is smaller than resume_max_bytes, else falls back " + "to the handoff briefing. 'continue' always passes --continue. " + "'none' starts completely fresh every time."),
11874
- resume_max_bytes: exports_external.number().int().positive().optional().describe("Byte threshold above which 'auto' mode falls back to handoff " + "instead of --continue. Default 2_000_000 (~2MB). Large transcripts " + "can blow out the context window even with prefix caching, and " + "--continue replay is known-fragile at scale.")
11874
+ resume_max_bytes: exports_external.number().int().positive().optional().describe("Byte threshold above which 'auto' mode falls back to handoff " + "instead of --continue. Default 2_000_000 (~2MB). Large transcripts " + "can blow out the context window even with prefix caching, and " + "--continue replay is known-fragile at scale."),
11875
+ session_retention_max_count: exports_external.number().int().nonnegative().optional().describe("Session-JSONL retention (issue #2792): keep at most this many " + "newest session transcripts under .claude/projects; older ones " + "past both this count and the age bound are pruned by the Stop " + "hook. The newest sessions (and the handoff source) are always " + "kept. Default 20; set 0 to disable the count bound."),
11876
+ session_retention_max_age_days: exports_external.number().int().nonnegative().optional().describe("Session-JSONL retention (issue #2792): prune session transcripts " + "older than this many days (a file is deleted only when it is BOTH " + "over the count bound and older than this). Default 30; set 0 to " + "disable the age bound.")
11875
11877
  }).optional();
11876
11878
  var webhookDispatchRule = exports_external.object({
11877
11879
  description: exports_external.string().optional(),