hotsheet 0.19.0 → 0.20.0-beta.11

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/README.md CHANGED
@@ -10,7 +10,7 @@
10
10
 
11
11
  <br>
12
12
 
13
- **Hot Sheet** is a local-first project management tool wired into your AI coding workflow. Create tickets with a bullet-list interface, drag them into priority order, and your AI tools automatically get a structured worklist they can act on. A real PTY-backed terminal lives in the footer drawer — switch to the dashboard view to see every terminal across every project as a tile grid — so you can keep an eye on dev servers, tests, and the AI's own Claude Code session from the same window.
13
+ **Hot Sheet** is a local-first project management tool wired into your AI coding workflow. Create tickets with a bullet-list interface, drag them into priority order, and your AI tools automatically get a structured worklist they can act on. A real PTY-backed terminal lives in the footer drawer — switch to the dashboard view to see every terminal across every project as a tile grid — so you can keep an eye on dev servers, tests, and the AI's own Claude Code session from the same window. Step away, and the **Announcer** narrates what the AI got done while you were gone.
14
14
 
15
15
  No cloud. No logins. No JIRA. Just tickets, terminals, and a tight feedback loop.
16
16
 
@@ -183,6 +183,68 @@ Read .hotsheet/worklist.md for current work items.
183
183
 
184
184
  Hot Sheet automatically generates skill files for Claude Code (as well as Cursor, GitHub Copilot, and Windsurf) so your AI tool can create tickets directly. Run `/hotsheet` in Claude Code to process the worklist.
185
185
 
186
+ ### Recommended project instructions
187
+
188
+ Hot Sheet works best when your AI assistant follows a few conventions: drive work through Hot Sheet tickets, keep double test coverage, and keep requirements docs in sync. Add these sections to your project's `CLAUDE.md` (Claude Code) — Hot Sheet can do it for you, or copy them by hand.
189
+
190
+ - **Automatic:** when Hot Sheet detects Claude Code in a project, it offers (once per project) to add these sections to your `CLAUDE.md`. Your existing file is preserved — the sections are wrapped in markers so Hot Sheet can keep them up to date without touching anything else, and the test/docs *specifics* are filled in by your assistant for that project.
191
+ - **Manual:** click **Update CLAUDE.md** in **Settings → General** at any time, or copy the blocks below.
192
+
193
+ <details>
194
+ <summary><strong>Ticket-Driven Work</strong></summary>
195
+
196
+ ```markdown
197
+ ## Ticket-Driven Work
198
+
199
+ When the user gives you work directly (not via the Hot Sheet channel or events), create Hot Sheet tickets before starting implementation — especially for substantial or multi-step work.
200
+
201
+ - **Do create tickets** for: features, bug fixes, refactoring, multi-step tasks, anything changing code. **Don't** for: simple questions, git commits, quick lookups, trivial one-liners. **When in doubt, create them.**
202
+ - Create via the Hot Sheet API (prefer the `hotsheet_*` MCP tools), mark Up Next, then work through them: set status `started` → implement → set `completed` with notes.
203
+ - **Always create follow-up tickets** for incomplete work (unfinished steps, open design questions, known gaps, designed-but-unbuilt features). If it's not in a ticket, it's forgotten.
204
+ - **Incomplete-work checklist** — before marking a ticket `completed`, file follow-ups for any: (1) UI placeholder text ("coming soon"), (2) TODO/FIXME comments, (3) documented-but-unimplemented requirements, (4) empty/stub functions returning mock data.
205
+ - **Use FEEDBACK NEEDED before deferring or asking about follow-ups.** When about to (a) defer a ticket needing more work, (b) ask whether to file follow-ups, or (c) close with a question buried in notes — DON'T. Leave the ticket `started`, add a `FEEDBACK NEEDED:` note (per `.hotsheet/worklist.md`), signal channel done, and wait. It's the only reliable way to surface a question.
206
+ ```
207
+
208
+ </details>
209
+
210
+ <details>
211
+ <summary><strong>Testing Philosophy</strong></summary>
212
+
213
+ ```markdown
214
+ ## Testing Philosophy
215
+
216
+ - **Double coverage**: every feature covered by both unit tests AND E2E tests. Unit = logic in isolation; E2E = real user flows through the running app with minimal mocking.
217
+ - **Unit tests**: Mock external deps (filesystem, network), test real logic.
218
+ - **E2E tests**: As much as possible, use test automation tools to run realistic, user-facing flows. Minimize mocks.
219
+ - **Coverage**: Merge all test coverage (e.g. unit, E2E server, E2E browser) into one report. Low-coverage files should get more of both test types. Aim for 100% coverage of code lines, 100% coverage of branches, and 100% of features described in the requirements documentation.
220
+ - **Manual test plan**: keep a manual test plan doc (e.g. `docs/manual-test-plan.md`) for features that can't be reliably automated. **Keep it up to date** — add such features there; when you add automated coverage for a previously-manual item, remove it and note it in an "Automated Coverage Summary".
221
+ - **Always fix lint and type errors before finishing**: Fix as you go, don't batch.
222
+ ```
223
+
224
+ When Hot Sheet adds this section it also scaffolds a self-healing **"this project's test setup"** block: a short prompt that asks your assistant to detect and record the project's actual test runner, file locations, and commands the first time it does test work — so the generic principles get project-specific teeth for any language.
225
+
226
+ </details>
227
+
228
+ <details>
229
+ <summary><strong>Requirements Documentation</strong></summary>
230
+
231
+ ```markdown
232
+ ## Requirements Documentation
233
+
234
+ Keep human-readable requirements documents as the source of truth for what the project does, and **keep them up to date in the same change as the code** (add/remove/modify a requirement → update its doc). Create new docs for major new functional areas. Cross-reference related docs with relative links.
235
+
236
+ ### AI Summaries
237
+
238
+ Maintain two synthesis docs an AI assistant reads at the start of a fresh session — keep them in sync with reality (source doc/code wins on conflict), and prefer small targeted edits over rewrites:
239
+
240
+ - A **codebase map** — directory tree, entry points, data schema, build, tests, settings, and a "where do I look for X" index. Update it in the same change when you add a file or directory, add a route/endpoint, change the schema, add a client module, or add a setting key.
241
+ - A **requirements summary** — a synthesized view of every requirements doc with status markers (e.g. Shipped / Partial / Design only / Deferred). Update it in the same change when you add a requirements doc, ship a design-only feature, or defer/regress a shipped one.
242
+ ```
243
+
244
+ </details>
245
+
246
+ See [docs/86-ai-assistant-setup.md](docs/86-ai-assistant-setup.md) for how the auto-install / auto-update mechanism works.
247
+
186
248
  ### Claude Channel Integration (Experimental)
187
249
 
188
250
  Hot Sheet can push events directly to a running Claude Code session via MCP channels. Enable it in Settings:
@@ -191,10 +253,10 @@ Hot Sheet can push events directly to a running Claude Code session via MCP chan
191
253
  - **Auto mode** — double-click the play button to enable automatic mode. Claude is triggered immediately, then continues monitoring for new Up Next items with debounce. Exponential backoff prevents runaway retries.
192
254
  - **Auto-prioritize** — when no tickets are flagged as Up Next, Claude automatically evaluates open tickets and picks the most important ones to work on.
193
255
  - **Feedback loop** — Claude can request user input by adding notes prefixed with `FEEDBACK NEEDED:` or `IMMEDIATE FEEDBACK NEEDED:`. A rich dialog appears in the UI with inline-response slots between every prompt block, a catch-all field, and file attachment support. Save Draft to come back later (text + attachments survive); Submit re-triggers Claude with your response. Blue dots on project tabs indicate pending feedback.
194
- - **Custom commands** — create named buttons that send custom prompts to Claude **or run shell commands** directly. Organize into collapsible groups. Toggle between "Claude Code" and "Shell" targets per command. Shell commands execute server-side with stdout/stderr streamed to the commands log in real time.
256
+ - **Custom commands** — create named buttons that send custom prompts to Claude **or run shell commands** directly. Organize into collapsible groups. Toggle between "Claude Code" and "Shell" targets per command. Shell commands execute server-side with stdout/stderr streamed to the commands log in real time. **Long-press** a button for a secondary action (a shell command runs in a fresh terminal; a Claude command files a task ticket), and **hover** any button to see when it last ran.
195
257
  - **Permission relay** — when Claude needs tool approval (Bash, Edit, etc.), a full-screen overlay shows the tool name and command preview with Allow/Deny/Dismiss buttons — no need to switch to the terminal. Per-project **allow-rules** can auto-approve specific tool+pattern pairs (e.g. always allow `Bash:npm test`) so trusted commands skip the overlay entirely.
196
258
  - **Commands log + embedded terminal** — the footer drawer hosts both a resizable commands log (every trigger, completion, permission request, shell output) AND tabs for any number of project-scoped terminals. Hop between an `npm run dev` terminal, the Claude session, and the audit log without leaving Hot Sheet.
197
- - **MCP tools** — Claude Code sees Hot Sheet as a connected MCP server with schema-validated tools: `hotsheet_create_ticket`, `hotsheet_update_ticket`, `hotsheet_query_tickets`, `hotsheet_batch`, `hotsheet_signal_done`, `hotsheet_request_feedback`, and 8 more. Tickets, notes, and attachments all round-trip without the AI hand-crafting curl commands.
259
+ - **MCP tools** — Claude Code sees Hot Sheet as a connected MCP server with schema-validated tools: `hotsheet_create_ticket`, `hotsheet_update_ticket`, `hotsheet_query_tickets`, `hotsheet_batch`, `hotsheet_signal_done`, `hotsheet_request_feedback`, `hotsheet_announce`, and 8 more. Tickets, notes, and attachments all round-trip without the AI hand-crafting curl commands.
198
260
  - **Status indicator** — shows "Claude working" / "Shell running" / idle in the footer.
199
261
 
200
262
  Requires Claude Code v2.1.80+ with channel support. See [docs/12-claude-channel.md](docs/12-claude-channel.md) for setup details.
@@ -203,6 +265,23 @@ Requires Claude Code v2.1.80+ with channel support. See [docs/12-claude-channel.
203
265
  <img src="docs/demo-9.png" alt="Claude Channel integration with play button, custom command buttons, and AI-driven workflow" width="900">
204
266
  </p>
205
267
 
268
+ ### Announcer — narrated playback of project work (Beta)
269
+
270
+ Step away while Claude works, and the **Announcer** catches you up. It turns completion notes, the command log, and Claude Code's own telemetry stream into a short spoken-and-visual digest — a draggable, resizable picture-in-picture transcript that reads each update aloud, emphasizes the key phrases, and shows the actual before/after code diff for the change it's describing.
271
+
272
+ - **After-the-fact digest** — click **Listen** to hear everything that happened since you last checked in, narrated in order. The PIP shows the running transcript with playback controls (play/pause, previous, next, speed) and tier-1 emphasis on the phrases that matter.
273
+ - **Live mode** — narrates work as it happens, coalescing bursts of activity into coherent entries and learning from the ones you skip. It's **off unless you're listening** — a client-renewed lease gates generation so it never spends your key in the background, with a per-project call budget on top.
274
+ - **Cross-project** — an "All Projects" context interleaves every enabled project's reel chronologically, each entry tagged with a project chip and prefixed with its project name when spoken.
275
+ - **Spoken permission checks** — hear "Permission needed in *Project*: …" read aloud when Claude needs tool approval, even with no PIP open and no API key required.
276
+ - **Bring your own model — or none** — summarize with your Anthropic key, **on-device with Apple Foundation Models** (macOS 26, free and fully private, no key), or a local **Ollama / OpenAI-compatible** endpoint. Playback uses the built-in OS/browser voice by default.
277
+ - **Code-diff visuals** — the working agent can hand the Announcer the exact before/after through the `hotsheet_announce` MCP tool, rendered inline in the PIP next to the narration.
278
+
279
+ API keys are managed once in **Settings → API Keys** — a machine-global registry of named keys stored in the OS keychain, selected by name per project so you never paste a secret twice. Enable narration in **Settings → Announcer**.
280
+
281
+ <p align="center">
282
+ <img src="docs/demo-14.png" alt="Announcer transcript picture-in-picture narrating recent work over the ticket board, with emphasized phrases and an inline before/after code diff" width="900">
283
+ </p>
284
+
206
285
  ### Telemetry & Cost Tracking
207
286
 
208
287
  **On by default** (HS-8684 — opt out per project via Settings → Telemetry). Hot Sheet stamps Claude Code's spawn env so its OpenTelemetry exporter posts cost / token / latency events back to a localhost-bound endpoint. The data drives several surfaces:
@@ -213,7 +292,7 @@ Requires Claude Code v2.1.80+ with channel support. See [docs/12-claude-channel.
213
292
  - **Per-ticket Claude usage** — when you trigger Claude via the channel with an active ticket selected, Hot Sheet prepends an invisible `<!-- hotsheet:ticket=HS-NNNN -->` marker to the prompt so the cost / tokens / wall-clock from that work attribute back to the ticket and appear as a "Claude usage on this ticket" block in the detail panel.
214
293
  - **Beta enhanced tracing** — separate toggle wires `CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1` so each prompt's drilldown switches from a flat event timeline to a parent-child span tree with an inline waterfall chart. New `claude` sessions started after the toggle begin capturing spans.
215
294
 
216
- Security model: localhost-bound OTLP receiver + `hotsheet_project` resource-attribute filter — foreign OTLP traffic from other tools on the same machine can't pollute Hot Sheet's tables even if it tries. 30-day default retention via the cleanup sweep; **Clear telemetry data** in Settings wipes the project's rows on demand.
295
+ Security model: localhost-bound OTLP receiver + `hotsheet_project` resource-attribute filter — foreign OTLP traffic from other tools on the same machine can't pollute Hot Sheet's tables even if it tries. Telemetry is stored per-project with a configurable retention window (30-day default) enforced by a periodic sweep with per-table windows and a row cap, so the database can't grow without bound; **Clear telemetry data** in Settings wipes the project's rows on demand.
217
296
 
218
297
  <p align="center">
219
298
  <img src="docs/demo-13.png" alt="Cross-project telemetry stats page with cost-over-time chart, cost-by-project table, model donut, and hourly activity heatmap" width="900">
package/dist/channel.js CHANGED
@@ -10283,6 +10283,19 @@ import { z as z3 } from "zod";
10283
10283
 
10284
10284
  // src/routes/validation.ts
10285
10285
  import { z as z2 } from "zod";
10286
+
10287
+ // src/announcer/models.ts
10288
+ var APPLE_FOUNDATION_MODEL_ID = "apple-foundation";
10289
+ var LOCAL_MODEL_ID = "local";
10290
+ var ANNOUNCER_PRICING = {
10291
+ [APPLE_FOUNDATION_MODEL_ID]: { inputPerMTok: 0, outputPerMTok: 0 },
10292
+ [LOCAL_MODEL_ID]: { inputPerMTok: 0, outputPerMTok: 0 },
10293
+ "claude-haiku-4-5": { inputPerMTok: 1, outputPerMTok: 5 },
10294
+ "claude-sonnet-4-6": { inputPerMTok: 3, outputPerMTok: 15 },
10295
+ "claude-opus-4-8": { inputPerMTok: 5, outputPerMTok: 25 }
10296
+ };
10297
+
10298
+ // src/routes/validation.ts
10286
10299
  var TicketPrioritySchema = z2.enum(["highest", "high", "default", "low", "lowest"]);
10287
10300
  var TicketStatusSchema = z2.enum(["not_started", "started", "completed", "verified", "backlog", "archive", "deleted"]);
10288
10301
  var SortBySchema = z2.enum(["created", "modified", "priority", "category", "status"]);
@@ -10422,6 +10435,16 @@ var DashboardConfigSchema = z2.object({
10422
10435
  // made after HS-8406 landed could persist across relaunches.
10423
10436
  activeVisibilityGroupingIdByScope: z2.record(z2.string(), z2.string()).optional()
10424
10437
  }).strict();
10438
+ var KeyTypeSchema = z2.enum(["anthropic_api_key"]);
10439
+ var SecretKeyMetaSchema = z2.object({
10440
+ id: z2.string(),
10441
+ type: KeyTypeSchema,
10442
+ name: z2.string(),
10443
+ // HS-8760 — provenance shown in the API Keys row ("Created/Updated …").
10444
+ // Optional for back-compat with keys created before HS-8760.
10445
+ created_at: z2.string().optional(),
10446
+ updated_at: z2.string().optional()
10447
+ });
10425
10448
  var GlobalConfigSchema = z2.object({
10426
10449
  channelEnabled: z2.boolean().optional(),
10427
10450
  shareTotalSeconds: z2.number().optional(),
@@ -10434,7 +10457,65 @@ var GlobalConfigSchema = z2.object({
10434
10457
  terminalWebglOptOut: z2.boolean().optional(),
10435
10458
  // HS-8497 — billing model for telemetry cost display. See
10436
10459
  // `global-config.ts` for the contract.
10437
- telemetryCostMode: z2.enum(["api", "subscription"]).optional()
10460
+ telemetryCostMode: z2.enum(["api", "subscription"]).optional(),
10461
+ // HS-8751 — global API-key registry (metadata only; values in the keychain).
10462
+ keys: z2.array(SecretKeyMetaSchema).optional(),
10463
+ // HS-8754 — Announcer playback speed multiplier (1 = normal). Global because
10464
+ // it's a listening preference, not project-specific. Clamped 0.5×–2×.
10465
+ announcerSpeechRate: z2.number().min(0.5).max(2).optional(),
10466
+ // HS-8764 — Announcer summarization model. Global; defaults to the cheapest
10467
+ // (Haiku) when unset. See `src/announcer/models.ts`. HS-8853 — the Anthropic
10468
+ // list is now discovered dynamically from the user's key, so this accepts any
10469
+ // `claude-*` id (not just the static set) plus the two on-device pseudo-ids.
10470
+ announcerModel: z2.string().refine(
10471
+ (v) => v === APPLE_FOUNDATION_MODEL_ID || v === LOCAL_MODEL_ID || v.startsWith("claude-"),
10472
+ { message: "must be an on-device provider id or a claude-* model id" }
10473
+ ).optional(),
10474
+ // HS-8792 — local-provider config (used only when `announcerModel === 'local'`).
10475
+ // `Endpoint` is the OpenAI-compatible base URL (default `http://localhost:11434/v1`);
10476
+ // `Model` is the concrete local model name (e.g. `llama3.1`). Both global.
10477
+ announcerLocalEndpoint: z2.string().optional(),
10478
+ announcerLocalModel: z2.string().optional(),
10479
+ // HS-8891 — optional fallback model used ONLY when the primary is Apple
10480
+ // Foundation Models and it fails at inference (the HS-8883 "code 4" class). A
10481
+ // non-apple id: a `claude-*` model (cloud backup, spends on the user's key) or
10482
+ // the local pseudo-id. Empty string / unset = no fallback (Apple failure → no
10483
+ // narration, the pre-HS-8891 behavior). The auto-selected-on-device fallback
10484
+ // (HS-8805) is separate and unaffected.
10485
+ announcerFallbackModel: z2.string().refine(
10486
+ (v) => v === "" || v === LOCAL_MODEL_ID || v.startsWith("claude-"),
10487
+ { message: "must be empty, the local provider id, or a claude-* model id" }
10488
+ ).optional(),
10489
+ // HS-8781 — verbally announce permission checks (TTS only, no API cost).
10490
+ // Global; default ON, so `undefined`/unset is treated as enabled by the
10491
+ // client (`announcerSpeakPermissions !== false`).
10492
+ announcerSpeakPermissions: z2.boolean().optional(),
10493
+ // HS-8874 — one-time marker that the per-project telemetry migration
10494
+ // (`migratePerProjectTelemetry`) has run. Set after a successful, non-
10495
+ // destructive copy of legacy launch-default telemetry rows into each row's
10496
+ // owning project DB / the central store. Skipped on subsequent startups.
10497
+ telemetryMigratedV1: z2.boolean().optional(),
10498
+ // HS-8874 (migration efficiency) — per-source-DB resumability for the
10499
+ // telemetry migration. Each source project dir is appended here once all its
10500
+ // foreign rows have been copied, so a crash/quit mid-migration resumes at the
10501
+ // first incomplete DB instead of restarting from zero (the boot-loop the
10502
+ // end-only `telemetryMigratedV1` flag caused). Cleared when migration completes.
10503
+ telemetryMigrationV1DoneDirs: z2.array(z2.string()).optional(),
10504
+ // HS-8877 — retention window (days) for the centralized non-project telemetry
10505
+ // store (`~/.hotsheet/telemetry`). Projects have a per-project
10506
+ // `telemetry_retention_days`; central isn't a project, so its sweep window
10507
+ // lives here. Unset → the §67.6 default (30 days). `0` keeps central forever.
10508
+ centralTelemetryRetentionDays: z2.number().int().min(0).optional(),
10509
+ // HS-8890 (§85.2.2) — retention window (days) for `otel_spans` in the central
10510
+ // store. Spans (§68 enhanced tracing) are high-volume, so they age out faster
10511
+ // than metrics/events: unset → the §85 default of 7 days (vs 30 for
10512
+ // metrics/events via `centralTelemetryRetentionDays`); `0` keeps spans forever.
10513
+ centralSpanRetentionDays: z2.number().int().min(0).optional(),
10514
+ // HS-8884 — last time a `VACUUM FULL` reclaim ran per telemetry DB dir
10515
+ // (`<dataDir>/db` or the central store), keyed by that dir's absolute path →
10516
+ // ISO timestamp. Throttles the heavy, exclusive-lock full reclaim to at most
10517
+ // once per `FULL_VACUUM_THROTTLE_DAYS`; routine plain VACUUMs aren't tracked.
10518
+ telemetryVacuumFullAt: z2.record(z2.string(), z2.string()).optional()
10438
10519
  }).strict();
10439
10520
  var PluginActionSchema = z2.object({
10440
10521
  actionId: z2.string(),
@@ -10577,6 +10658,15 @@ var QueryTicketsInputSchema = z3.object({
10577
10658
  required_tag: z3.string().optional().describe("When set, only tickets carrying this tag are included"),
10578
10659
  include_archived: z3.boolean().optional()
10579
10660
  });
10661
+ var AnnounceInputSchema = z3.object({
10662
+ title: z3.string().min(1).describe('A few words naming the moment (e.g. "Fixed the data-loss bug").'),
10663
+ highlight: z3.string().min(1).describe("One or two short sentences of natural spoken English to read aloud \u2014 what happened and why it matters."),
10664
+ diff: z3.object({
10665
+ oldStr: z3.string().describe("The code BEFORE the change (the focused snippet you changed, not the whole file)."),
10666
+ newStr: z3.string().describe("The code AFTER the change."),
10667
+ filePath: z3.string().optional().describe("Optional file path shown as the diff header.")
10668
+ }).optional().describe("Optional code diff to display with this highlight \u2014 supply the before/after of the focused change you want to show off.")
10669
+ });
10580
10670
  async function dispatchUpdateTicket(args2, settings, fetchFn) {
10581
10671
  const parsed = UpdateTicketInputSchema.safeParse(args2);
10582
10672
  if (!parsed.success) {
@@ -10707,6 +10797,13 @@ async function dispatchDeleteNote(args2, settings, fetchFn) {
10707
10797
  const { ticket_id, note_id } = parsed.data;
10708
10798
  return await proxyRequest(settings, `/api/tickets/${String(ticket_id)}/notes/${encodeURIComponent(note_id)}`, { method: "DELETE" }, fetchFn);
10709
10799
  }
10800
+ async function dispatchAnnounce(args2, settings, fetchFn) {
10801
+ const parsed = AnnounceInputSchema.safeParse(args2);
10802
+ if (!parsed.success) {
10803
+ return errorResult(`hotsheet_announce \u2014 validation failed: ${parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ")}`);
10804
+ }
10805
+ return await proxyRequest(settings, "/api/announcer/announce", { method: "POST", body: parsed.data }, fetchFn);
10806
+ }
10710
10807
  async function dispatchQueryTickets(args2, settings, fetchFn) {
10711
10808
  const parsed = QueryTicketsInputSchema.safeParse(args2);
10712
10809
  if (!parsed.success) {
@@ -10799,6 +10896,13 @@ var TOOLS = [
10799
10896
  description: 'Run a custom-view-style query: combine field/operator/value conditions via AND (logic="all") or OR (logic="any"), with optional sort_by / sort_dir / required_tag / include_archived. Returns the matching tickets. For agents that need to dig deeper than the worklist provides.',
10800
10897
  inputSchema: QueryTicketsInputSchema,
10801
10898
  call: dispatchQueryTickets
10899
+ },
10900
+ // HS-8771 — hybrid Announcer generation (§80).
10901
+ {
10902
+ name: "hotsheet_announce",
10903
+ description: `Push a curated Announcer highlight for a genuinely notable moment ("fixed a data-loss bug", "shipped the export"). It pre-empts the derived narration queue with a low-latency, high-intent entry (no AI summarization). Use sparingly, only for moments worth interrupting for. No-op if the project hasn't enabled the Announcer.`,
10904
+ inputSchema: AnnounceInputSchema,
10905
+ call: dispatchAnnounce
10802
10906
  }
10803
10907
  ];
10804
10908
  function listTools() {
@@ -10964,6 +11068,16 @@ var TicketSchema = z6.object({
10964
11068
  last_read_at: z6.string().nullable()
10965
11069
  });
10966
11070
  var TagsArraySchema = z6.array(z6.string());
11071
+ var EmphasisArraySchema = z6.array(z6.string());
11072
+ var DiffVisualSchema = z6.object({
11073
+ type: z6.literal("diff"),
11074
+ oldStr: z6.string(),
11075
+ newStr: z6.string(),
11076
+ filePath: z6.string().nullable().default(null),
11077
+ replaceAll: z6.boolean().default(false)
11078
+ });
11079
+ var VisualSchema = z6.discriminatedUnion("type", [DiffVisualSchema]);
11080
+ var VisualsArraySchema = z6.array(VisualSchema);
10967
11081
  var AutoContextEntrySchema = z6.object({
10968
11082
  type: z6.enum(["category", "tag"]),
10969
11083
  key: z6.string(),
@@ -11039,6 +11153,20 @@ var PermissionResultBodySchema = z6.object({
11039
11153
  var GithubCommentsArraySchema = z6.array(z6.object({
11040
11154
  body_html: z6.string().optional()
11041
11155
  }).loose());
11156
+ var CustomViewConditionSchema = z6.object({
11157
+ field: z6.string(),
11158
+ operator: z6.string(),
11159
+ value: z6.string()
11160
+ }).loose();
11161
+ var CustomViewSchema = z6.object({
11162
+ id: z6.string(),
11163
+ name: z6.string(),
11164
+ tag: z6.string().optional(),
11165
+ includeArchived: z6.boolean().optional(),
11166
+ logic: z6.enum(["all", "any"]).default("all"),
11167
+ conditions: z6.array(CustomViewConditionSchema).default([])
11168
+ }).loose();
11169
+ var CustomViewArraySchema = z6.array(CustomViewSchema);
11042
11170
 
11043
11171
  // src/channel-config.ts
11044
11172
  var McpConfigSchema = z7.object({
@@ -11279,7 +11407,7 @@ function installStdioDisconnectHandler(opts) {
11279
11407
  }
11280
11408
 
11281
11409
  // src/channel.ts
11282
- var CHANNEL_VERSION = 9;
11410
+ var CHANNEL_VERSION = 11;
11283
11411
  var dataDir = ".hotsheet";
11284
11412
  var args = process.argv.slice(2);
11285
11413
  for (let i = 0; i < args.length; i++) {