switchroom 0.15.11 → 0.15.13

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.
@@ -13882,6 +13882,12 @@ var TelegramChannelSchema = exports_external.object({
13882
13882
  }).optional().describe("Per-source rate limit for the webhook ingest path (#714). " + "Off by default — when this key is absent the handler skips " + "rate-limit checks entirely. Opt in by setting `rpm` to an " + "integer requests-per-minute (token bucket per (agent, source); " + "burst equal to rpm). When enabled, exceeding the limit returns " + "429 with Retry-After header; first throttle event per " + "(agent, source) per 60s window is written to " + "<agent>/telegram/issues.jsonl. " + "Cascades from defaults.channels.telegram.webhook_rate_limit."),
13883
13883
  webhook_via_gateway: exports_external.boolean().optional().describe("Route verified webhook events to the agent's in-container gateway " + "over a peercred-gated UDS (<agent>/telegram/webhook.sock) instead " + "of having the host-side web receiver write the agent dir directly. " + "Required under the Docker runtime: the receiver runs as the host " + "operator UID and cannot write the per-agent-UID-owned agent dir " + "(EACCES 500) nor connect the gateway socket. When true the gateway " + "(running as the agent UID) becomes the sole writer of " + "webhook-events.jsonl + dedup/cooldown state and also fires " + "webhook_dispatch. Off by default for back-compat with host-runtime " + "installs. See docs/rfcs/webhook-via-gateway-socket.md."),
13884
13884
  webhook_require_edge: exports_external.boolean().optional().describe("Cloudflare-only edge lock: require the X-Switchroom-Edge header " + "(injected by a Cloudflare Transform Rule on hooks.switchroom.ai) to " + "match the operator's edge secret at ~/.switchroom/webhook-edge-secret " + "before any HMAC verification; reject 403 otherwise. Proves the " + "request entered through our Cloudflare edge — the per-agent HMAC " + "alone can't (it proves body provenance, not network path). Stacks " + "on the GitHub-IP WAF + per-agent HMAC. Fail-closed: when required " + "but the secret file is missing/empty every request is rejected. Off " + "by default. See docs/rfcs/webhook-cloudflare-edge-lock.md."),
13885
+ linear_agent: exports_external.object({
13886
+ enabled: exports_external.boolean(),
13887
+ token: exports_external.string().describe("vault:<key> reference to the Linear OAuth app token (actor=app). " + "Resolved at runtime via the vault broker (canonically " + "vault:linear/<agent>/token). Never an inline literal."),
13888
+ workspace_id: exports_external.string().optional().describe("Optional Linear workspace (organization) id this agent is " + "installed into. Informational — used for setup hints and " + "multi-workspace disambiguation; the token already scopes the " + "app to its workspace."),
13889
+ default_team_id: exports_external.string().optional().describe("Optional Linear team id new captured issues file into when the " + "agent doesn't pass an explicit team_id. Unnecessary for a " + "single-team workspace (auto-resolved); set it only when the " + "workspace has multiple teams. Manage via " + "`switchroom linear-agent set-team <agent> <team>`.")
13890
+ }).optional().describe("Linear first-class agent integration (#2298). When enabled, the " + "agent appears in a Linear workspace as an app actor (own name/" + "avatar, @-mentionable, delegate-assignable). Linear AgentSessionEvent " + "webhooks (mention / delegation) wake the agent instantly via the " + "same gateway inject path as webhook_dispatch, tagged " + 'meta.source="linear" with the agent_session_id, and the agent ' + "responds with structured AgentActivity (thought/message/complete/" + "error) via the linear_agent_activity MCP tool. Builds the " + "session-lifecycle layer on top of the plain webhook_sources:[linear] " + "+ webhook_dispatch support (#2272). The OAuth app token is stored in " + "the vault and referenced here as vault:linear/<agent>/token; run " + "`switchroom linear-agent setup <agent>` to provision it. Off by " + "default — opt in per agent. Cascades from " + "defaults.channels.telegram.linear_agent."),
13885
13891
  chat_id: exports_external.string().regex(/^-\d+$/, 'supergroup chat_id must be a negative integer as a string (e.g. "-1001234567890")').optional().describe("Per-agent supergroup ID — overrides fleet `telegram.forum_chat_id`. " + "When set, requires `default_topic_id`. Negative integer as string. " + "Forbidden when `dm_only: true`. See docs/rfcs/supergroup-mode.md."),
13886
13892
  default_topic_id: exports_external.number().int().positive().optional().describe("Forum topic ID this agent's automated outbounds default to when " + "no more-specific alias resolves. Defaults to General (topic 1) when " + "`chat_id` is set and this is omitted — set it only to pin a different " + "fallback topic. " + "Telegram's General topic is `id=1` at MTProto but sends omit the " + "field — the outbound wrapper strips `message_thread_id === 1` " + "on send. Forbidden when `dm_only: true`."),
13887
13893
  topic_aliases: exports_external.record(exports_external.string(), exports_external.number().int().positive()).optional().describe("Operator-friendly names for forum topic IDs (e.g. " + "`{ general: 1, planning: 17, cron: 23, admin: 31, alerts: 41 }`). " + "Referenced from per-cron `topic:` fields and the outbound router " + "for autonomous events (boot → alerts, hostd → admin, etc.). " + "Cascades per-key through defaults → profile → agent.")
@@ -14764,6 +14770,16 @@ function mergeAgentConfig(defaultsIn, agentIn) {
14764
14770
  }
14765
14771
  merged.reaction_dispatch = combined;
14766
14772
  }
14773
+ const linearEnabled = merged.channels?.telegram?.linear_agent?.enabled === true;
14774
+ if (linearEnabled) {
14775
+ const rd = merged.reaction_dispatch;
14776
+ if (!rd || rd.emojis === undefined) {
14777
+ merged.reaction_dispatch = {
14778
+ enabled: rd?.enabled ?? true,
14779
+ emojis: ["\uD83D\uDC68‍\uD83D\uDCBB", "\uD83D\uDCCC"]
14780
+ };
14781
+ }
14782
+ }
14767
14783
  if (defaults.resources || merged.resources) {
14768
14784
  const d = defaults.resources ?? {};
14769
14785
  const a = merged.resources ?? {};
@@ -4305,6 +4305,16 @@ function mergeAgentConfig(defaultsIn, agentIn) {
4305
4305
  }
4306
4306
  merged.reaction_dispatch = combined;
4307
4307
  }
4308
+ const linearEnabled = merged.channels?.telegram?.linear_agent?.enabled === true;
4309
+ if (linearEnabled) {
4310
+ const rd = merged.reaction_dispatch;
4311
+ if (!rd || rd.emojis === undefined) {
4312
+ merged.reaction_dispatch = {
4313
+ enabled: rd?.enabled ?? true,
4314
+ emojis: ["\uD83D\uDC68‍\uD83D\uDCBB", "\uD83D\uDCCC"]
4315
+ };
4316
+ }
4317
+ }
4308
4318
  if (defaults.resources || merged.resources) {
4309
4319
  const d = defaults.resources ?? {};
4310
4320
  const a = merged.resources ?? {};
@@ -11480,6 +11490,12 @@ var init_schema = __esm(() => {
11480
11490
  }).optional().describe("Per-source rate limit for the webhook ingest path (#714). " + "Off by default — when this key is absent the handler skips " + "rate-limit checks entirely. Opt in by setting `rpm` to an " + "integer requests-per-minute (token bucket per (agent, source); " + "burst equal to rpm). When enabled, exceeding the limit returns " + "429 with Retry-After header; first throttle event per " + "(agent, source) per 60s window is written to " + "<agent>/telegram/issues.jsonl. " + "Cascades from defaults.channels.telegram.webhook_rate_limit."),
11481
11491
  webhook_via_gateway: exports_external.boolean().optional().describe("Route verified webhook events to the agent's in-container gateway " + "over a peercred-gated UDS (<agent>/telegram/webhook.sock) instead " + "of having the host-side web receiver write the agent dir directly. " + "Required under the Docker runtime: the receiver runs as the host " + "operator UID and cannot write the per-agent-UID-owned agent dir " + "(EACCES 500) nor connect the gateway socket. When true the gateway " + "(running as the agent UID) becomes the sole writer of " + "webhook-events.jsonl + dedup/cooldown state and also fires " + "webhook_dispatch. Off by default for back-compat with host-runtime " + "installs. See docs/rfcs/webhook-via-gateway-socket.md."),
11482
11492
  webhook_require_edge: exports_external.boolean().optional().describe("Cloudflare-only edge lock: require the X-Switchroom-Edge header " + "(injected by a Cloudflare Transform Rule on hooks.switchroom.ai) to " + "match the operator's edge secret at ~/.switchroom/webhook-edge-secret " + "before any HMAC verification; reject 403 otherwise. Proves the " + "request entered through our Cloudflare edge — the per-agent HMAC " + "alone can't (it proves body provenance, not network path). Stacks " + "on the GitHub-IP WAF + per-agent HMAC. Fail-closed: when required " + "but the secret file is missing/empty every request is rejected. Off " + "by default. See docs/rfcs/webhook-cloudflare-edge-lock.md."),
11493
+ linear_agent: exports_external.object({
11494
+ enabled: exports_external.boolean(),
11495
+ token: exports_external.string().describe("vault:<key> reference to the Linear OAuth app token (actor=app). " + "Resolved at runtime via the vault broker (canonically " + "vault:linear/<agent>/token). Never an inline literal."),
11496
+ workspace_id: exports_external.string().optional().describe("Optional Linear workspace (organization) id this agent is " + "installed into. Informational — used for setup hints and " + "multi-workspace disambiguation; the token already scopes the " + "app to its workspace."),
11497
+ default_team_id: exports_external.string().optional().describe("Optional Linear team id new captured issues file into when the " + "agent doesn't pass an explicit team_id. Unnecessary for a " + "single-team workspace (auto-resolved); set it only when the " + "workspace has multiple teams. Manage via " + "`switchroom linear-agent set-team <agent> <team>`.")
11498
+ }).optional().describe("Linear first-class agent integration (#2298). When enabled, the " + "agent appears in a Linear workspace as an app actor (own name/" + "avatar, @-mentionable, delegate-assignable). Linear AgentSessionEvent " + "webhooks (mention / delegation) wake the agent instantly via the " + "same gateway inject path as webhook_dispatch, tagged " + 'meta.source="linear" with the agent_session_id, and the agent ' + "responds with structured AgentActivity (thought/message/complete/" + "error) via the linear_agent_activity MCP tool. Builds the " + "session-lifecycle layer on top of the plain webhook_sources:[linear] " + "+ webhook_dispatch support (#2272). The OAuth app token is stored in " + "the vault and referenced here as vault:linear/<agent>/token; run " + "`switchroom linear-agent setup <agent>` to provision it. Off by " + "default — opt in per agent. Cascades from " + "defaults.channels.telegram.linear_agent."),
11483
11499
  chat_id: exports_external.string().regex(/^-\d+$/, 'supergroup chat_id must be a negative integer as a string (e.g. "-1001234567890")').optional().describe("Per-agent supergroup ID — overrides fleet `telegram.forum_chat_id`. " + "When set, requires `default_topic_id`. Negative integer as string. " + "Forbidden when `dm_only: true`. See docs/rfcs/supergroup-mode.md."),
11484
11500
  default_topic_id: exports_external.number().int().positive().optional().describe("Forum topic ID this agent's automated outbounds default to when " + "no more-specific alias resolves. Defaults to General (topic 1) when " + "`chat_id` is set and this is omitted — set it only to pin a different " + "fallback topic. " + "Telegram's General topic is `id=1` at MTProto but sends omit the " + "field — the outbound wrapper strips `message_thread_id === 1` " + "on send. Forbidden when `dm_only: true`."),
11485
11501
  topic_aliases: exports_external.record(exports_external.string(), exports_external.number().int().positive()).optional().describe("Operator-friendly names for forum topic IDs (e.g. " + "`{ general: 1, planning: 17, cron: 23, admin: 31, alerts: 41 }`). " + "Referenced from per-cron `topic:` fields and the outbound router " + "for autonomous events (boot → alerts, hostd → admin, etc.). " + "Cascades per-key through defaults → profile → agent.")
@@ -339,6 +339,16 @@ function mergeAgentConfig(defaultsIn, agentIn) {
339
339
  }
340
340
  merged.reaction_dispatch = combined;
341
341
  }
342
+ const linearEnabled = merged.channels?.telegram?.linear_agent?.enabled === true;
343
+ if (linearEnabled) {
344
+ const rd = merged.reaction_dispatch;
345
+ if (!rd || rd.emojis === undefined) {
346
+ merged.reaction_dispatch = {
347
+ enabled: rd?.enabled ?? true,
348
+ emojis: ["\uD83D\uDC68‍\uD83D\uDCBB", "\uD83D\uDCCC"]
349
+ };
350
+ }
351
+ }
342
352
  if (defaults.resources || merged.resources) {
343
353
  const d = defaults.resources ?? {};
344
354
  const a = merged.resources ?? {};
@@ -11480,6 +11490,12 @@ var init_schema = __esm(() => {
11480
11490
  }).optional().describe("Per-source rate limit for the webhook ingest path (#714). " + "Off by default — when this key is absent the handler skips " + "rate-limit checks entirely. Opt in by setting `rpm` to an " + "integer requests-per-minute (token bucket per (agent, source); " + "burst equal to rpm). When enabled, exceeding the limit returns " + "429 with Retry-After header; first throttle event per " + "(agent, source) per 60s window is written to " + "<agent>/telegram/issues.jsonl. " + "Cascades from defaults.channels.telegram.webhook_rate_limit."),
11481
11491
  webhook_via_gateway: exports_external.boolean().optional().describe("Route verified webhook events to the agent's in-container gateway " + "over a peercred-gated UDS (<agent>/telegram/webhook.sock) instead " + "of having the host-side web receiver write the agent dir directly. " + "Required under the Docker runtime: the receiver runs as the host " + "operator UID and cannot write the per-agent-UID-owned agent dir " + "(EACCES 500) nor connect the gateway socket. When true the gateway " + "(running as the agent UID) becomes the sole writer of " + "webhook-events.jsonl + dedup/cooldown state and also fires " + "webhook_dispatch. Off by default for back-compat with host-runtime " + "installs. See docs/rfcs/webhook-via-gateway-socket.md."),
11482
11492
  webhook_require_edge: exports_external.boolean().optional().describe("Cloudflare-only edge lock: require the X-Switchroom-Edge header " + "(injected by a Cloudflare Transform Rule on hooks.switchroom.ai) to " + "match the operator's edge secret at ~/.switchroom/webhook-edge-secret " + "before any HMAC verification; reject 403 otherwise. Proves the " + "request entered through our Cloudflare edge — the per-agent HMAC " + "alone can't (it proves body provenance, not network path). Stacks " + "on the GitHub-IP WAF + per-agent HMAC. Fail-closed: when required " + "but the secret file is missing/empty every request is rejected. Off " + "by default. See docs/rfcs/webhook-cloudflare-edge-lock.md."),
11493
+ linear_agent: exports_external.object({
11494
+ enabled: exports_external.boolean(),
11495
+ token: exports_external.string().describe("vault:<key> reference to the Linear OAuth app token (actor=app). " + "Resolved at runtime via the vault broker (canonically " + "vault:linear/<agent>/token). Never an inline literal."),
11496
+ workspace_id: exports_external.string().optional().describe("Optional Linear workspace (organization) id this agent is " + "installed into. Informational — used for setup hints and " + "multi-workspace disambiguation; the token already scopes the " + "app to its workspace."),
11497
+ default_team_id: exports_external.string().optional().describe("Optional Linear team id new captured issues file into when the " + "agent doesn't pass an explicit team_id. Unnecessary for a " + "single-team workspace (auto-resolved); set it only when the " + "workspace has multiple teams. Manage via " + "`switchroom linear-agent set-team <agent> <team>`.")
11498
+ }).optional().describe("Linear first-class agent integration (#2298). When enabled, the " + "agent appears in a Linear workspace as an app actor (own name/" + "avatar, @-mentionable, delegate-assignable). Linear AgentSessionEvent " + "webhooks (mention / delegation) wake the agent instantly via the " + "same gateway inject path as webhook_dispatch, tagged " + 'meta.source="linear" with the agent_session_id, and the agent ' + "responds with structured AgentActivity (thought/message/complete/" + "error) via the linear_agent_activity MCP tool. Builds the " + "session-lifecycle layer on top of the plain webhook_sources:[linear] " + "+ webhook_dispatch support (#2272). The OAuth app token is stored in " + "the vault and referenced here as vault:linear/<agent>/token; run " + "`switchroom linear-agent setup <agent>` to provision it. Off by " + "default — opt in per agent. Cascades from " + "defaults.channels.telegram.linear_agent."),
11483
11499
  chat_id: exports_external.string().regex(/^-\d+$/, 'supergroup chat_id must be a negative integer as a string (e.g. "-1001234567890")').optional().describe("Per-agent supergroup ID — overrides fleet `telegram.forum_chat_id`. " + "When set, requires `default_topic_id`. Negative integer as string. " + "Forbidden when `dm_only: true`. See docs/rfcs/supergroup-mode.md."),
11484
11500
  default_topic_id: exports_external.number().int().positive().optional().describe("Forum topic ID this agent's automated outbounds default to when " + "no more-specific alias resolves. Defaults to General (topic 1) when " + "`chat_id` is set and this is omitted — set it only to pin a different " + "fallback topic. " + "Telegram's General topic is `id=1` at MTProto but sends omit the " + "field — the outbound wrapper strips `message_thread_id === 1` " + "on send. Forbidden when `dm_only: true`."),
11485
11501
  topic_aliases: exports_external.record(exports_external.string(), exports_external.number().int().positive()).optional().describe("Operator-friendly names for forum topic IDs (e.g. " + "`{ general: 1, planning: 17, cron: 23, admin: 31, alerts: 41 }`). " + "Referenced from per-cron `topic:` fields and the outbound router " + "for autonomous events (boot → alerts, hostd → admin, etc.). " + "Cascades per-key through defaults → profile → agent.")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "switchroom",
3
- "version": "0.15.11",
3
+ "version": "0.15.13",
4
4
  "description": "Run Claude Code 24/7 on your Claude Pro/Max subscription over Telegram. Open-source alternative to OpenClaw and NanoClaw — no API keys.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -123,6 +123,43 @@ After a successful `schedule_add`, confirm to the user with:
123
123
  After a failed write (any `E_*` code from the rails above), surface the
124
124
  specific error verbatim, explain which rail tripped, and offer the
125
125
  closest legal alternative.
126
+ {{#if linearAgentEnabled}}
127
+
128
+ ## Capture to Linear (👨‍💻 / 📌 reaction → new issue)
129
+
130
+ You're connected to Linear as a first-class app actor. The operator has the
131
+ **capture reactions** wired: when they react to a Telegram message with **👨‍💻**
132
+ (laptop) or **📌** (pushpin), you're woken with a turn whose inbound is shaped
133
+ `<channel … event="reaction" emoji="👨‍💻" message_id="…" chat_id="…">[the
134
+ reacted message text]</channel>`. That reaction means: **"turn this into a
135
+ Linear issue."**
136
+
137
+ When you get such a reaction turn:
138
+
139
+ 1. **Read the reacted message + nearby context.** The `[reacted text]` is the
140
+ seed. Pull the surrounding thread (`get_recent_messages`) when the ask needs
141
+ it — the issue should stand on its own without the operator re-explaining.
142
+ 2. **Call `linear_create_issue`** with:
143
+ - `title` — a crisp, imperative one-liner ("Fix duplicate Brevo webhook
144
+ retries"), not a restatement of the chat.
145
+ - `body` — the ask, the context you gathered, and any acceptance criteria
146
+ you can reasonably infer. Markdown.
147
+ - `dedup_key` — set it to `"<chat_id>:<message_id>"` from the reaction event.
148
+ This makes a re-react of the same message idempotent (it returns the
149
+ existing issue instead of filing a duplicate).
150
+ - `team_id` — omit it. A single-team workspace auto-resolves; you'll only be
151
+ asked for one if the workspace has multiple teams (then tell the operator
152
+ to set a default via `switchroom linear-agent set-team`).
153
+ 3. **Reply in plain text, not an emoji.** On success the tool returns
154
+ `Filed: <title> → <url>` — reply that link so the operator can click
155
+ through ("📋 Filed: <url>"). On failure (vault denial, multi-team, API
156
+ error) the tool returns actionable text — relay it plainly ("Couldn't file
157
+ it — …") and, if it's a vault denial, follow the `vault_request_access`
158
+ instruction it gives you, then retry.
159
+
160
+ Don't acknowledge with only a reaction or a bare "done" — the operator wants
161
+ the link (or the honest reason it didn't file).
162
+ {{/if}}
126
163
 
127
164
  ### Don't lie about scheduling
128
165
 
@@ -455,6 +455,61 @@ const TOOL_SCHEMAS = [
455
455
  required: ['chat_id', 'key'],
456
456
  },
457
457
  },
458
+ {
459
+ name: 'linear_agent_activity',
460
+ description:
461
+ 'Emit a structured Linear AgentActivity against an agent session (#2298). Use this ONLY inside a turn that was woken by a Linear agent session (the inbound carries meta.source="linear" and meta.agent_session_id) — pass that agent_session_id back here. Linear renders activities as status chips + a timeline on the issue, so the human sees acknowledge → work → result. Emit a `thought` within ~10s of being woken so the session does not look dead, then `message`(s) as you make progress, and finally exactly one terminal `complete` (work done) or `error` (you could not proceed). body is required for thought/message/error and optional for complete. Resolves the agent\'s Linear app token from the vault; on VAULT-BROKER-DENIED it returns an error instructing you to vault_request_access for `linear/<agent>/token`.',
462
+ inputSchema: {
463
+ type: 'object',
464
+ properties: {
465
+ agent_session_id: {
466
+ type: 'string',
467
+ description: 'The Linear AgentSession id — copy it verbatim from the woken turn\'s meta.agent_session_id.',
468
+ },
469
+ type: {
470
+ type: 'string',
471
+ enum: ['thought', 'message', 'complete', 'error'],
472
+ description: 'Activity kind. thought = visible reasoning ack (emit within ~10s); message = progress update; complete = terminal success; error = terminal failure.',
473
+ },
474
+ body: {
475
+ type: 'string',
476
+ description: 'Activity text (Markdown). Required for thought/message/error; optional for complete (a closing summary).',
477
+ },
478
+ },
479
+ required: ['agent_session_id', 'type'],
480
+ },
481
+ },
482
+ {
483
+ name: 'linear_create_issue',
484
+ description:
485
+ 'File a new Linear issue from a Telegram message the operator flagged for capture (#2312). Use this when a turn was triggered by a capture reaction (the inbound carries event="reaction" with a capture emoji like 👨‍💻 or 📌) — turn the reacted message + any relevant thread context into a well-formed issue. Write a crisp imperative title and a body that captures the ask, the context, and any acceptance criteria you can infer; the agent files it AS its own Linear app actor. Team is auto-resolved when the workspace has a single team; if there are multiple it returns text asking for an explicit team_id. Pass dedup_key (e.g. the chat_id:message_id of the reacted message) so a re-react of the same message does not file a duplicate. Resolves the agent\'s Linear app token from the vault; on VAULT-BROKER-DENIED it returns text instructing you to vault_request_access for `linear/<agent>/token`. Returns "Filed: <title> → <url>" on success — reply that link to the operator in plain text.',
486
+ inputSchema: {
487
+ type: 'object',
488
+ properties: {
489
+ title: {
490
+ type: 'string',
491
+ description: 'Issue title — a crisp, imperative one-liner (e.g. "Fix duplicate webhook retries on Brevo sync").',
492
+ },
493
+ body: {
494
+ type: 'string',
495
+ description: 'Issue description (Markdown). Capture the ask, relevant context from the message/thread, and any acceptance criteria you can infer.',
496
+ },
497
+ team_id: {
498
+ type: 'string',
499
+ description: 'Optional Linear team id. Omit to auto-resolve when the workspace has a single team; required only when the workspace has multiple teams.',
500
+ },
501
+ dedup_key: {
502
+ type: 'string',
503
+ description: 'Optional idempotency key (use the reacted message identity, e.g. "<chat_id>:<message_id>"). A prior capture with the same key short-circuits to "Already filed: <url>".',
504
+ },
505
+ priority: {
506
+ type: 'number',
507
+ description: 'Optional Linear priority (0 none, 1 urgent, 2 high, 3 normal, 4 low).',
508
+ },
509
+ },
510
+ required: ['title', 'body'],
511
+ },
512
+ },
458
513
  ]
459
514
 
460
515
  mcp.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOL_SCHEMAS }))
@@ -24934,6 +24934,59 @@ var TOOL_SCHEMAS = [
24934
24934
  },
24935
24935
  required: ["chat_id", "key"]
24936
24936
  }
24937
+ },
24938
+ {
24939
+ name: "linear_agent_activity",
24940
+ description: 'Emit a structured Linear AgentActivity against an agent session (#2298). Use this ONLY inside a turn that was woken by a Linear agent session (the inbound carries meta.source="linear" and meta.agent_session_id) \u2014 pass that agent_session_id back here. Linear renders activities as status chips + a timeline on the issue, so the human sees acknowledge \u2192 work \u2192 result. Emit a `thought` within ~10s of being woken so the session does not look dead, then `message`(s) as you make progress, and finally exactly one terminal `complete` (work done) or `error` (you could not proceed). body is required for thought/message/error and optional for complete. Resolves the agent\'s Linear app token from the vault; on VAULT-BROKER-DENIED it returns an error instructing you to vault_request_access for `linear/<agent>/token`.',
24941
+ inputSchema: {
24942
+ type: "object",
24943
+ properties: {
24944
+ agent_session_id: {
24945
+ type: "string",
24946
+ description: "The Linear AgentSession id \u2014 copy it verbatim from the woken turn's meta.agent_session_id."
24947
+ },
24948
+ type: {
24949
+ type: "string",
24950
+ enum: ["thought", "message", "complete", "error"],
24951
+ description: "Activity kind. thought = visible reasoning ack (emit within ~10s); message = progress update; complete = terminal success; error = terminal failure."
24952
+ },
24953
+ body: {
24954
+ type: "string",
24955
+ description: "Activity text (Markdown). Required for thought/message/error; optional for complete (a closing summary)."
24956
+ }
24957
+ },
24958
+ required: ["agent_session_id", "type"]
24959
+ }
24960
+ },
24961
+ {
24962
+ name: "linear_create_issue",
24963
+ description: 'File a new Linear issue from a Telegram message the operator flagged for capture (#2312). Use this when a turn was triggered by a capture reaction (the inbound carries event="reaction" with a capture emoji like \uD83D\uDC68\u200D\uD83D\uDCBB or \uD83D\uDCCC) \u2014 turn the reacted message + any relevant thread context into a well-formed issue. Write a crisp imperative title and a body that captures the ask, the context, and any acceptance criteria you can infer; the agent files it AS its own Linear app actor. Team is auto-resolved when the workspace has a single team; if there are multiple it returns text asking for an explicit team_id. Pass dedup_key (e.g. the chat_id:message_id of the reacted message) so a re-react of the same message does not file a duplicate. Resolves the agent\'s Linear app token from the vault; on VAULT-BROKER-DENIED it returns text instructing you to vault_request_access for `linear/<agent>/token`. Returns "Filed: <title> \u2192 <url>" on success \u2014 reply that link to the operator in plain text.',
24964
+ inputSchema: {
24965
+ type: "object",
24966
+ properties: {
24967
+ title: {
24968
+ type: "string",
24969
+ description: 'Issue title \u2014 a crisp, imperative one-liner (e.g. "Fix duplicate webhook retries on Brevo sync").'
24970
+ },
24971
+ body: {
24972
+ type: "string",
24973
+ description: "Issue description (Markdown). Capture the ask, relevant context from the message/thread, and any acceptance criteria you can infer."
24974
+ },
24975
+ team_id: {
24976
+ type: "string",
24977
+ description: "Optional Linear team id. Omit to auto-resolve when the workspace has a single team; required only when the workspace has multiple teams."
24978
+ },
24979
+ dedup_key: {
24980
+ type: "string",
24981
+ description: 'Optional idempotency key (use the reacted message identity, e.g. "<chat_id>:<message_id>"). A prior capture with the same key short-circuits to "Already filed: <url>".'
24982
+ },
24983
+ priority: {
24984
+ type: "number",
24985
+ description: "Optional Linear priority (0 none, 1 urgent, 2 high, 3 normal, 4 low)."
24986
+ }
24987
+ },
24988
+ required: ["title", "body"]
24989
+ }
24937
24990
  }
24938
24991
  ];
24939
24992
  mcp.setRequestHandler(ListToolsRequestSchema2, async () => ({ tools: TOOL_SCHEMAS }));