switchroom 0.16.38 → 0.16.47

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 (59) hide show
  1. package/dist/agent-scheduler/index.js +8 -2
  2. package/dist/auth-broker/index.js +7 -1
  3. package/dist/cli/notion-write-pretool.mjs +7 -1
  4. package/dist/cli/switchroom.js +1259 -375
  5. package/dist/cli/ui/index.html +877 -214
  6. package/dist/host-control/main.js +116 -84
  7. package/dist/vault/approvals/kernel-server.js +8 -2
  8. package/dist/vault/broker/server.js +8 -2
  9. package/examples/minimal.yaml +1 -1
  10. package/examples/switchroom.yaml +1 -1
  11. package/package.json +2 -2
  12. package/profiles/_shared/reply-discipline.md.hbs +9 -0
  13. package/skills/switchroom-status/SKILL.md +1 -1
  14. package/telegram-plugin/bridge/bridge.ts +2 -1
  15. package/telegram-plugin/card-format.ts +7 -1
  16. package/telegram-plugin/dist/bridge/bridge.js +20 -2
  17. package/telegram-plugin/dist/gateway/gateway.js +2197 -964
  18. package/telegram-plugin/dist/server.js +20 -2
  19. package/telegram-plugin/format.ts +305 -31
  20. package/telegram-plugin/gateway/gateway.ts +310 -70
  21. package/telegram-plugin/gateway/model-command.ts +173 -19
  22. package/telegram-plugin/hooks/tool-label-pretool.d.mts +12 -0
  23. package/telegram-plugin/hooks/tool-label-pretool.mjs +54 -16
  24. package/telegram-plugin/package.json +1 -1
  25. package/telegram-plugin/session-tail.ts +47 -1
  26. package/telegram-plugin/stream-reply-handler.ts +19 -1
  27. package/telegram-plugin/tests/always-allow-grant.test.ts +34 -2
  28. package/telegram-plugin/tests/card-format.test.ts +28 -0
  29. package/telegram-plugin/tests/claude-code-event-contract.test.ts +151 -0
  30. package/telegram-plugin/tests/format-consistency.test.ts +223 -0
  31. package/telegram-plugin/tests/formatting-parse-regression.test.ts +272 -0
  32. package/telegram-plugin/tests/formatting-torture-set.ts +218 -0
  33. package/telegram-plugin/tests/model-command.test.ts +213 -47
  34. package/telegram-plugin/tests/paragraph-normalizer.test.ts +203 -21
  35. package/telegram-plugin/tests/rich-markdown-oracle.ts +469 -0
  36. package/telegram-plugin/tests/session-tail.test.ts +91 -0
  37. package/telegram-plugin/tests/status-vocabulary-unification.test.ts +125 -0
  38. package/telegram-plugin/tests/telegram-format.test.ts +33 -8
  39. package/telegram-plugin/tests/text-voice-scrub.test.ts +142 -22
  40. package/telegram-plugin/tests/tool-activity-summary.test.ts +6 -1
  41. package/telegram-plugin/tests/tts-normalize.test.ts +242 -0
  42. package/telegram-plugin/tests/vault-request-access-tool.test.ts +24 -0
  43. package/telegram-plugin/tests/vault-request-access-unlock-resume.test.ts +46 -0
  44. package/telegram-plugin/tests/voice-ondemand.test.ts +99 -2
  45. package/telegram-plugin/tests/voice-presynth.test.ts +437 -0
  46. package/telegram-plugin/tests/worker-activity-feed.test.ts +49 -0
  47. package/telegram-plugin/text-voice-scrub.ts +68 -18
  48. package/telegram-plugin/tool-activity-summary.ts +20 -108
  49. package/telegram-plugin/tts-normalize.ts +377 -0
  50. package/telegram-plugin/uat/driver.ts +472 -22
  51. package/telegram-plugin/uat/scenarios/jtbd-model-litellm-sr-dm.test.ts +34 -14
  52. package/telegram-plugin/uat/scenarios/jtbd-multipart-render-dm.test.ts +169 -0
  53. package/telegram-plugin/uat/scenarios/jtbd-narration-intent-dm.test.ts +134 -0
  54. package/telegram-plugin/uat/scenarios/jtbd-rich-formatting-render-dm.test.ts +254 -0
  55. package/telegram-plugin/uat/scenarios/jtbd-status-phase-transitions-dm.test.ts +109 -0
  56. package/telegram-plugin/uat/uat-driver.test.ts +297 -0
  57. package/telegram-plugin/voice-ondemand.ts +161 -10
  58. package/telegram-plugin/voice-presynth.ts +242 -0
  59. package/telegram-plugin/worker-activity-feed.ts +9 -1
@@ -28,6 +28,7 @@
28
28
  */
29
29
 
30
30
  import { escapeMarkdown, codeSpanSafe } from './format.js'
31
+ import { normalizeDashes } from './text-voice-scrub.js'
31
32
 
32
33
  /**
33
34
  * Re-export so card surfaces have one import for the markdown escaper they
@@ -127,7 +128,12 @@ export function truncate(s: string, n: number): string {
127
128
  * Run this BEFORE `truncate` + `escapeMarkdown`: clean → measure → escape.
128
129
  */
129
130
  export function stripMarkdown(s: string): string {
130
- let out = s;
131
+ // Close the em-dash leak on this model-authored-prose surface using the
132
+ // SAME dash logic as the reply-path voice scrub (no duplicated regex). Run
133
+ // it FIRST, while code spans (`` `…` ``) still have their backticks intact,
134
+ // so `normalizeDashes`'s own code-region masking preserves a dash inside a
135
+ // code span before the backtick-stripping below erases the fences.
136
+ let out = normalizeDashes(s);
131
137
  // Inline + leftover code spans → bare text.
132
138
  out = out.replace(/`+/g, '');
133
139
  // Links / images: [text](url) and ![alt](url) → the label.
@@ -23216,6 +23216,23 @@ function projectAssistantTextBlocks(content, make) {
23216
23216
  });
23217
23217
  return out;
23218
23218
  }
23219
+ function assistantLineCarriesAnswerSurface(content) {
23220
+ if (!Array.isArray(content))
23221
+ return false;
23222
+ for (const c of content) {
23223
+ const ct = c?.type ?? "";
23224
+ if (ct === "text") {
23225
+ const t = c.text;
23226
+ if (typeof t === "string" && t.trim().length > 0)
23227
+ return true;
23228
+ } else if (ct === "tool_use") {
23229
+ const name = c.name ?? "";
23230
+ if (name !== "Agent" && name !== "Task")
23231
+ return true;
23232
+ }
23233
+ }
23234
+ return false;
23235
+ }
23219
23236
  function projectTranscriptLine(line) {
23220
23237
  if (line.length > MAX_JSONL_LINE_BYTES)
23221
23238
  return [];
@@ -23377,7 +23394,7 @@ function projectSubagentLine(line, agentId, state) {
23377
23394
  }
23378
23395
  });
23379
23396
  const stopReason = message?.stop_reason;
23380
- if (stopReason === "end_turn") {
23397
+ if (stopReason === "end_turn" && assistantLineCarriesAnswerSurface(content)) {
23381
23398
  events.push({ kind: "sub_agent_turn_end", agentId });
23382
23399
  }
23383
23400
  return events;
@@ -24977,7 +24994,8 @@ var TOOL_SCHEMAS = [
24977
24994
  chat_id: { type: "string", description: "Chat to render the approval card in (use the chat_id of the user message that triggered the workflow)." },
24978
24995
  key: { type: "string", description: "Vault key the agent wants access to (matches the key shown in the VAULT-BROKER-DENIED error, e.g. `fatsecret/credentials`)." },
24979
24996
  scope: { type: "string", enum: ["read", "write"], description: 'Access scope: "read" (default) for `vault:<key>` references; "write" if the agent needs to put new values.' },
24980
- reason: { type: "string", description: `REQUIRED in practice \u2014 short human-readable rationale rendered on the card (e.g. "to look up today's food log entries"). The approval card now renders "why: not provided" when this is omitted, which signals to the operator that the agent skipped its explanation \u2014 they will usually Deny. Always supply a one-line rationale.` },
24997
+ reason: { type: "string", description: 'REQUIRED in practice \u2014 short human-readable rationale rendered on the card (e.g. "to look up today\'s food log entries"). The approval card now renders "why: not provided" when this is omitted, which signals to the operator that the agent skipped its explanation \u2014 they will usually Deny. Always supply a one-line rationale. `why` is accepted as an alias (matching `vault_request_save`).' },
24998
+ why: { type: "string", description: "Alias for `reason` (matches the sibling tool `vault_request_save`). If both are supplied, `reason` wins." },
24981
24999
  duration: { type: "string", description: 'Requested grant TTL, like "30d" or "12h". Default 30d, capped at 90d. Beyond 90d the operator should use the host CLI explicitly.' },
24982
25000
  message_thread_id: { type: "string", description: "Forum topic thread ID. Auto-applied from the last inbound message if not specified." }
24983
25001
  },