squadrant 0.9.1 → 0.10.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.
package/README.md CHANGED
@@ -174,6 +174,40 @@ Pass `--direction right|left|up|down` to use a split pane instead of a tab. Stat
174
174
  - **Semantic heartbeat** — crews emit a lifecycle signal the captain reads as **CREW IDLE / QUIET / STALLED**, distinguishing "waiting for you" from "wedged" without scraping the pane ([#354](https://github.com/tu11aa/squadrant/issues/354)).
175
175
  - **`stopped` project status + orphan reap** — when a captain goes away, the daemon reaps its orphaned crews and marks the project `stopped` (intentional shutdown) rather than leaving stale tabs or faulting ([#324](https://github.com/tu11aa/squadrant/issues/324) / [#323](https://github.com/tu11aa/squadrant/issues/323) / [#388](https://github.com/tu11aa/squadrant/pull/388)).
176
176
 
177
+ ### Telegram (Two-Way, opt-in)
178
+
179
+ Drive squadrant from your phone ([#65](https://github.com/tu11aa/squadrant/issues/65)). When a `telegram` block is present in config, a daemon-internal bridge:
180
+
181
+ - **Outbound** — pushes each project's crew lifecycle events (CREW DONE / BLOCKED / IDLE) and other captain notifications to that project's Telegram forum topic. Best-effort: a Telegram failure never delays or breaks delivery to the captain pane.
182
+ - **Inbound (project topic)** — a message you send in a project's topic is delivered into that project's **captain pane** as a labeled `📩 [from Telegram]` message; the captain decides what to do with it. With remote control enabled (see below), if no captain is alive the daemon **auto-launches** one, then delivers ([#403](https://github.com/tu11aa/squadrant/issues/403)).
183
+ - **General command channel** — slash commands in the supergroup's **General topic** run a curated set of squadrant operations from your phone ([#402](https://github.com/tu11aa/squadrant/issues/402)). Available: `/help`, `/status`, `/projects`, `/crews <project>`, `/launch <project>`, `/effort [max|balance|low]`, `/config get <key>`, `/config set <key> <value>`, `/spawn <project> <task…>`. Each maps to a validated CLI argv run via async `execFile` — never a shell passthrough. Unknown commands and freeform text get a `/help` hint.
184
+
185
+ Absent the config block, the bridge is never constructed — zero behavior change. No runtime SDK is added (plain `fetch`; `@grammyjs/types` is a dev-only type dependency).
186
+
187
+ **Setup (recommended):**
188
+ 1. Create a bot with [@BotFather](https://t.me/BotFather) and copy its token.
189
+ 2. Run `squadrant telegram setup` — it prompts for the bot token (input hidden), validates it via the Bot API, auto-detects your supergroup id, captures your Telegram user-id, and offers to enable remote control.
190
+ 3. Bind a project to a topic: `squadrant telegram link <project>` (creates the forum topic and records the binding).
191
+ 4. Check wiring with `squadrant telegram status`.
192
+
193
+ **Setup (manual):**
194
+ Put the token + ids in config (or export `TELEGRAM_BOT_TOKEN`) — see the `telegram` block under [Config](#config). Then run `squadrant telegram link <project>`.
195
+
196
+ #### Security model (#321) — fail-closed remote control
197
+
198
+ The control surfaces (auto-launch + General command channel) are **off by default** and gated by two independent checks. A control action runs **only when both** hold:
199
+
200
+ 1. `remoteControl: true` — an explicit opt-in master switch (default `false`).
201
+ 2. `message.from.id ∈ users[]` — the sender's Telegram **user-id** is on the allowlist. An empty/absent `users` list ⇒ control is disabled (fail-closed). Chat membership alone is **never** enough for control.
202
+
203
+ When remote control is off (the default after upgrade), behavior is **exactly v1**: project-topic messages queue to the captain pane (no auto-launch), and General-topic slash commands are rejected with `⛔ not authorized`. Inbound text is always treated as data; only the curated registry maps to actions, and `/config set` is restricted to a default-deny writable-key allowlist (currently just `defaults.effort`) — **secrets (`botToken`, `users`, `chats`, `supergroupId`) can never be written over Telegram.**
204
+
205
+ #### Remote wake (#403) — operator-side
206
+
207
+ Auto-launch boots a captain when the **daemon is already running**. Waking a *sleeping Mac* from your phone (Wake-on-LAN / a relay that nudges the machine) is operator-side infrastructure, out of scope for this repo — see [#403](https://github.com/tu11aa/squadrant/issues/403) for the end-to-end flow.
208
+
209
+ > **Interim note (link ↔ daemon 409):** the Telegram Bot API allows only one `getUpdates` consumer at a time. The `setup` wizard polls `getUpdates` to detect your group/user-id, so run it with the daemon stopped. `link` uses only `createForumTopic`, so it's unaffected.
210
+
177
211
  ### Projection (Cross-Agent Config Sync)
178
212
 
179
213
  Squadrant rules (Karpathy principles, captain-ops) and per-project AGENTS.md emit to each supported agent's canonical path via `squadrant projection emit`. User-level projection pushes squadrant's skills to `~/.cursor/rules/squadrant-global.mdc`, `~/.codex/AGENTS.md`, `~/.gemini/GEMINI.md`. Project-level projection pushes a managed project's own `AGENTS.md` into `{project}/CLAUDE.md`, `{project}/.cursor/rules/squadrant.mdc`, `{project}/GEMINI.md` — zero squadrant-global content leaks into the project repo. Shared files use `<!-- squadrant:start --> ... <!-- squadrant:end -->` markers; dedicated files overwrite. See `docs/specs/archive/2026-04-24-plugin-system-projection-design.md`.
@@ -213,6 +247,14 @@ The user-level projection now also inlines `templates/captain.generic.md` and `t
213
247
  "runtime": "cmux",
214
248
  "workspace": "obsidian",
215
249
  "notifier": "cmux",
250
+ "telegram": {
251
+ "botToken": "123456:ABC...",
252
+ "supergroupId": -1001234567890,
253
+ "chats": [-1001234567890],
254
+ "users": [987654321],
255
+ "remoteControl": true,
256
+ "pollMs": 1000
257
+ },
216
258
  "projects": {
217
259
  "brove": {
218
260
  "path": "~/projects/brove",
@@ -242,6 +284,8 @@ The user-level projection now also inlines `templates/captain.generic.md` and `t
242
284
  }
243
285
  ```
244
286
 
287
+ The `telegram` block is **optional** — omit it and the Telegram bridge is never constructed. `botToken` may be left out of the file and supplied via the `TELEGRAM_BOT_TOKEN` env var instead. `chats` is the inbound `chat_id` allowlist; `users` is the per-user-id allowlist for **control** actions and `remoteControl` (default `false`) is the master opt-in for auto-launch + the General command channel — both must be set for any remote control to act (fail-closed, [#321](https://github.com/tu11aa/squadrant/issues/321)). `pollMs` (default `1000`) is the inbound long-poll cadence. See [Telegram (Two-Way, opt-in)](#telegram-two-way-opt-in).
288
+
245
289
  ## Supported Agents
246
290
 
247
291
  | Agent | Status | Notes |