polygram 0.1.0 → 0.1.1

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.
@@ -0,0 +1,13 @@
1
+ {
2
+ "$schema": "https://anthropic.com/claude-code/plugin.schema.json",
3
+ "name": "polygram",
4
+ "version": "0.1.0",
5
+ "description": "Admin + transcript skills for the polygram Telegram daemon.",
6
+ "author": {
7
+ "name": "Ivan Shumkov",
8
+ "email": "ivan.shumkov@dash.org"
9
+ },
10
+ "license": "MIT",
11
+ "homepage": "https://github.com/shumkov/polygram",
12
+ "repository": "https://github.com/shumkov/polygram"
13
+ }
package/README.md CHANGED
@@ -101,6 +101,33 @@ on first run (migrations apply automatically) and opens a Unix socket at
101
101
 
102
102
  For production, LaunchAgent plists are in `ops/`. See `ops/README.md`.
103
103
 
104
+ ## Install as a Claude Code plugin
105
+
106
+ polygram also ships as a Claude Code plugin — adds admin slash commands
107
+ and bundles the transcript-query skill for use inside your Claude sessions.
108
+
109
+ ```
110
+ /plugin install https://github.com/shumkov/polygram.git
111
+ ```
112
+
113
+ Once installed:
114
+
115
+ - `/polygram:status` — running bots, IPC health, recent events, one-line verdict
116
+ - `/polygram:logs <bot>` — tail `~/polygram/logs/<bot>.log`
117
+ - `/polygram:pair-code` — walks you through issuing a pairing code (in-band via Telegram)
118
+ - `/polygram:approvals [bot]` — pending and recent tool-approval rows
119
+
120
+ The bundled **`telegram-history` skill** lets Claude query the transcript
121
+ directly:
122
+
123
+ ```
124
+ "Summarise the Orders topic today" →
125
+ uses skills/telegram-history to run `recent <chat> --since 24h`
126
+ ```
127
+
128
+ Scope is derived from `process.cwd()`: the skill refuses to run from an
129
+ unmapped directory unless `BRIDGE_ADMIN=1` is set.
130
+
104
131
  ## Configuration
105
132
 
106
133
  Minimal:
@@ -0,0 +1,37 @@
1
+ ---
2
+ description: List pending and recent approvals from a polygram bot's DB.
3
+ argument-hint: [bot-name]
4
+ ---
5
+
6
+ Show the operator recent tool-call approvals, gated via the polygram
7
+ `PreToolUse` hook.
8
+
9
+ If no bot name was given, list configured bots from
10
+ `~/polygram/config.json` and ask which one.
11
+
12
+ For the chosen `<bot-name>`:
13
+
14
+ 1. **Pending (awaiting a click):**
15
+ ```
16
+ sqlite3 ~/polygram/<bot-name>.db "SELECT id, requested_ts, tool_name, substr(tool_input_json, 1, 80) AS preview FROM pending_approvals WHERE status = 'pending' ORDER BY requested_ts DESC LIMIT 20;"
17
+ ```
18
+
19
+ 2. **Recent (last 24 h, all statuses):**
20
+ ```
21
+ sqlite3 ~/polygram/<bot-name>.db "SELECT id, status, decided_by_user, tool_name, substr(tool_input_json, 1, 80) AS preview FROM pending_approvals WHERE requested_ts > strftime('%s', 'now', '-1 day') * 1000 ORDER BY requested_ts DESC LIMIT 20;"
22
+ ```
23
+
24
+ 3. **Sweep-failed events in the last 7 days** (the sweeper itself dying
25
+ is an ops alarm):
26
+ ```
27
+ sqlite3 ~/polygram/<bot-name>.db "SELECT ts, detail_json FROM events WHERE kind = 'approval-sweep-failed' AND ts > strftime('%s', 'now', '-7 days') * 1000 ORDER BY ts DESC LIMIT 5;"
28
+ ```
29
+
30
+ Render two short Markdown tables. For pending rows, note how long they've
31
+ been waiting (`requested_ts` vs now). For resolved rows, show who decided
32
+ and when. Flag anything where `status = 'timeout'` — those tool calls
33
+ were auto-denied because no one acted in time.
34
+
35
+ If the DB doesn't exist at `~/polygram/<bot-name>.db`, check whether this
36
+ is a pre-cutover install still using a shared `bridge.db`; in that case
37
+ point the operator at `~/polygram/bridge.db` for the same query.
@@ -0,0 +1,37 @@
1
+ ---
2
+ description: Tail the last N lines of a polygram bot's launchd log.
3
+ argument-hint: <bot-name> [lines]
4
+ ---
5
+
6
+ The user wants to see recent logs from a polygram bot.
7
+
8
+ Arguments:
9
+ - `<bot-name>` — required; the bot whose log to tail (matches `--bot` name,
10
+ same as the launchd plist suffix `com.polygram.<bot-name>`).
11
+ - `[lines]` — optional; number of trailing lines (default 100).
12
+
13
+ Default log path is `~/polygram/logs/<bot-name>.log`. If the user uses a
14
+ custom `POLYGRAM_HOME`, ask first.
15
+
16
+ Steps:
17
+
18
+ 1. Show the last N lines:
19
+ ```
20
+ tail -n {lines:-100} ~/polygram/logs/<bot-name>.log
21
+ ```
22
+
23
+ 2. Scan the output for notable patterns and surface them. Things worth
24
+ flagging:
25
+ - `[fatal]` or `Error:` lines
26
+ - `409, waiting 3s` (Telegram conflict — another grammy instance?)
27
+ - `poll-stalled` — watchdog event
28
+ - `approval-sweep-failed` — sweeper died
29
+ - `telegram-api-error` — delivery failure
30
+
31
+ 3. If the file is empty or missing, check whether the bot is actually
32
+ loaded (`launchctl list | grep com.polygram.<bot-name>`) and report
33
+ that distinction — "bot not loaded" vs "bot running but silent".
34
+
35
+ Respond with:
36
+ - A code fence containing the raw tail (use Markdown triple-backticks)
37
+ - A short plain-English summary of anything notable
@@ -0,0 +1,47 @@
1
+ ---
2
+ description: Explain how to issue a polygram pairing code for a new guest user.
3
+ argument-hint: [bot-name]
4
+ ---
5
+
6
+ Explain to the operator how to mint a pairing code.
7
+
8
+ Pairing codes are issued through Telegram itself — the operator DMs the bot
9
+ from the admin chat. This is intentional: pairing grants cross-chat trust
10
+ and must run as an authenticated user the bot already knows, not as a
11
+ claude-code session.
12
+
13
+ If a bot name was provided, confirm it's one of the configured bots; if
14
+ not, list configured bots from `~/polygram/config.json` (read-only) so the
15
+ user can pick.
16
+
17
+ Then tell them to:
18
+
19
+ 1. Open Telegram, go to their admin chat with the bot (the chat whose ID
20
+ matches `config.bot.adminChatId`).
21
+
22
+ 2. Send:
23
+ ```
24
+ /pair-code --ttl 1h --note "Jane — new designer"
25
+ ```
26
+ Optional flags: `--chat <chat_id>` to scope the code to a specific chat,
27
+ `--scope user|chat`, `--ttl 10m|1h|1d`.
28
+
29
+ 3. The bot replies with a code like `K7M2P4VQ`. Share it with the guest
30
+ through a separate channel.
31
+
32
+ 4. Guest DMs the bot (any chat the bot is in):
33
+ ```
34
+ /pair K7M2P4VQ
35
+ ```
36
+
37
+ 5. Revoke later with:
38
+ ```
39
+ /unpair <user_id>
40
+ ```
41
+
42
+ Admin commands are gated to the admin chat — `/pair-code` run from any
43
+ other chat returns "admin-only" regardless of `allowConfigCommands`.
44
+
45
+ If the user asks you to issue the code for them directly from this Claude
46
+ session, politely refuse — explain that pairing is an in-band Telegram
47
+ operation and tell them to run it from the bot DM themselves.
@@ -0,0 +1,40 @@
1
+ ---
2
+ description: Show polygram daemon health — running bots, IPC sockets, recent events.
3
+ ---
4
+
5
+ You are asked to report the current health of the polygram Telegram daemon.
6
+
7
+ Do these checks, in order, using the Bash tool, and summarise the results in
8
+ a short Markdown table (one row per bot):
9
+
10
+ 1. **Which bots are supervised by launchd.** Run:
11
+ ```
12
+ launchctl list | grep -i polygram || echo "no LaunchAgents loaded"
13
+ ```
14
+ Parse the output. Each line `<PID>\t<exit>\t<label>` is one bot
15
+ (e.g. `com.polygram.my-bot`). The PID column tells you whether it is
16
+ running; `-` means loaded but not currently running.
17
+
18
+ 2. **Is each bot's Unix socket alive?** For every bot you identified, run:
19
+ ```
20
+ node ~/polygram/scripts/ipc-smoke.js <bot-name>
21
+ ```
22
+ Interpret the result:
23
+ - `ping: {"id":null,"ok":true,"pong":true,"bot":"<bot>"}` → socket alive
24
+ - `ERR: connect ECONNREFUSED` → socket stale (bridge not actually
25
+ serving despite plist being loaded)
26
+ - `ERR: ENOENT` → socket missing (bridge never got that far at boot)
27
+
28
+ 3. **Recent events in each bot's DB.** For every bot, run:
29
+ ```
30
+ sqlite3 ~/polygram/<bot>.db "SELECT ts, kind, detail_json FROM events ORDER BY ts DESC LIMIT 5;"
31
+ ```
32
+ Call out anything that looks like an error (`-fail`, `-error`,
33
+ `crashed-mid-send`, `poll-stalled`, `approval-sweep-failed`).
34
+
35
+ 4. **Summarise.** A two-line per-bot summary, plus an overall verdict at
36
+ the bottom (✅ healthy / ⚠️ degraded / ❌ broken).
37
+
38
+ If the user's polygram install is not at `~/polygram`, they may have set
39
+ `POLYGRAM_HOME` or a custom path. Ask them to point you at it rather than
40
+ guessing.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polygram",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Telegram daemon for Claude Code that preserves the OpenClaw per-chat session model. Migration path for OpenClaw users moving to Claude Code.",
5
5
  "main": "lib/ipc-client.js",
6
6
  "bin": {
@@ -15,6 +15,8 @@
15
15
  "scripts/split-db.js",
16
16
  "scripts/ipc-smoke.js",
17
17
  "skills/",
18
+ "commands/",
19
+ ".claude-plugin/",
18
20
  "ops/polygram.plist.example",
19
21
  "ops/README.md",
20
22
  "config.example.json"