afk-code 0.1.4 → 0.2.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
@@ -2,29 +2,38 @@
2
2
 
3
3
  Monitor and interact with Claude Code sessions from Slack, Discord, or Telegram. Respond from your phone while AFK.
4
4
 
5
- ![square-image](https://github.com/user-attachments/assets/83083b63-9ca2-4ef0-b83d-fcc51bd2fff9)
5
+ <img src="https://github.com/user-attachments/assets/83083b63-9ca2-4ef0-b83d-fcc51bd2fff9" alt="AFK Code iPhone Slack screenshot" width="400">
6
6
 
7
- ## Quick Start (Slack)
7
+ ## Client Comparison
8
+
9
+ Telegram and Discord are recommended.
10
+
11
+ | | Telegram | Discord | Slack |
12
+ |---|---|---|---|
13
+ | Siri integration | Receive & Send | Receive only | Receive only |
14
+ | Multi-session support | One at a time (switchable) | Yes | Yes |
15
+ | Permissions required | Personal | Personal | Admin |
16
+
17
+ ## Quick Start (Telegram)
8
18
 
9
19
  ```bash
10
- # 1. Create a Slack app at https://api.slack.com/apps
11
- # Click "Create New App" "From manifest" → paste slack-manifest.json
20
+ # 1. Create a bot with @BotFather on Telegram
21
+ # - Send /newbot and follow the prompts
22
+ # - Copy the bot token
12
23
 
13
- # 2. Install to your workspace and get credentials:
14
- # - Bot Token (xoxb-...) from OAuth & Permissions
15
- # - App Token (xapp-...) from Basic Information → App-Level Tokens (needs connections:write)
16
- # - Your User ID from your Slack profile → "..." → Copy member ID
24
+ # 2. Get your Chat ID
25
+ # - Message your bot, then visit:
26
+ # - https://api.telegram.org/bot<TOKEN>/getUpdates
27
+ # - Find "chat":{"id":YOUR_CHAT_ID}
17
28
 
18
29
  # 3. Configure and run
19
- npx afk-code slack setup # Enter your credentials
20
- npx afk-code slack # Start the bot
30
+ npx afk-code telegram setup # Enter your credentials
31
+ npx afk-code telegram # Start the bot
21
32
 
22
33
  # 4. In another terminal, start a monitored Claude session
23
- npx afk-code run -- claude
34
+ npx afk-code claude
24
35
  ```
25
36
 
26
- A new channel is created for each session. Messages relay bidirectionally.
27
-
28
37
  ## Quick Start (Discord)
29
38
 
30
39
  ```bash
@@ -42,39 +51,40 @@ npx afk-code discord setup # Enter your credentials
42
51
  npx afk-code discord # Start the bot
43
52
 
44
53
  # 4. In another terminal, start a monitored Claude session
45
- npx afk-code run -- claude
54
+ npx afk-code claude
46
55
  ```
47
56
 
48
- ## Quick Start (Telegram)
57
+ ## Quick Start (Slack)
49
58
 
50
59
  ```bash
51
- # 1. Create a bot with @BotFather on Telegram
52
- # - Send /newbot and follow the prompts
53
- # - Copy the bot token
60
+ # 1. Create a Slack app at https://api.slack.com/apps
61
+ # Click "Create New App" "From manifest" → paste slack-manifest.json
54
62
 
55
- # 2. Get your Chat ID
56
- # - Message your bot, then visit:
57
- # - https://api.telegram.org/bot<TOKEN>/getUpdates
58
- # - Find "chat":{"id":YOUR_CHAT_ID}
63
+ # 2. Install to your workspace and get credentials:
64
+ # - Bot Token (xoxb-...) from OAuth & Permissions
65
+ # - App Token (xapp-...) from Basic Information → App-Level Tokens (needs connections:write)
66
+ # - Your User ID from your Slack profile → "..." → Copy member ID
59
67
 
60
68
  # 3. Configure and run
61
- npx afk-code telegram setup # Enter your credentials
62
- npx afk-code telegram # Start the bot
69
+ npx afk-code slack setup # Enter your credentials
70
+ npx afk-code slack # Start the bot
63
71
 
64
72
  # 4. In another terminal, start a monitored Claude session
65
- npx afk-code run -- claude
73
+ npx afk-code claude
66
74
  ```
67
75
 
76
+ A new channel is created for each session. Messages relay bidirectionally.
77
+
68
78
  ## Commands
69
79
 
70
80
  ```
71
- afk-code slack setup Configure Slack credentials
72
- afk-code slack Run the Slack bot
73
- afk-code discord setup Configure Discord credentials
74
- afk-code discord Run the Discord bot
75
81
  afk-code telegram setup Configure Telegram credentials
76
82
  afk-code telegram Run the Telegram bot
77
- afk-code run -- <command> Start a monitored session
83
+ afk-code discord setup Configure Discord credentials
84
+ afk-code discord Run the Discord bot
85
+ afk-code slack setup Configure Slack credentials
86
+ afk-code slack Run the Slack bot
87
+ afk-code <command> [args] Start a monitored session
78
88
  afk-code help Show help
79
89
  ```
80
90
 
@@ -103,7 +113,7 @@ npx afk-code <command>
103
113
  git clone https://github.com/clharman/afk-code.git
104
114
  cd afk-code && npm install
105
115
  npm run dev -- slack
106
- npm run dev -- run -- claude
116
+ npm run dev -- claude
107
117
  ```
108
118
 
109
119
  Requires Node.js 18+.
@@ -111,7 +121,7 @@ Requires Node.js 18+.
111
121
  ## How It Works
112
122
 
113
123
  1. `afk-code slack`, `afk-code discord`, or `afk-code telegram` starts a bot that listens for sessions
114
- 2. `afk-code run -- claude` spawns Claude in a PTY and connects to the bot via Unix socket
124
+ 2. `afk-code claude` spawns Claude in a PTY and connects to the bot via Unix socket
115
125
  3. The bot watches Claude's JSONL files for messages and relays them to chat
116
126
  4. Messages you send in chat are forwarded to the terminal
117
127
 
package/dist/cli/index.js CHANGED
@@ -1597,13 +1597,18 @@ function createTelegramApp(config) {
1597
1597
  }
1598
1598
  processingQueue = false;
1599
1599
  }
1600
- async function sendMessage(text, parseMode = "Markdown") {
1600
+ async function sendMessage(text, parseMode = "Markdown", options) {
1601
1601
  messageQueue.push(async () => {
1602
1602
  try {
1603
- await bot.api.sendMessage(config.chatId, text, { parse_mode: parseMode });
1603
+ await bot.api.sendMessage(config.chatId, text, {
1604
+ parse_mode: parseMode,
1605
+ disable_notification: options?.disable_notification
1606
+ });
1604
1607
  } catch (err) {
1605
1608
  if (parseMode && err.message?.includes("parse")) {
1606
- await bot.api.sendMessage(config.chatId, text);
1609
+ await bot.api.sendMessage(config.chatId, text, {
1610
+ disable_notification: options?.disable_notification
1611
+ });
1607
1612
  } else {
1608
1613
  throw err;
1609
1614
  }
@@ -1611,13 +1616,11 @@ function createTelegramApp(config) {
1611
1616
  });
1612
1617
  processQueue();
1613
1618
  }
1614
- async function sendChunkedMessage(text, prefix) {
1619
+ async function sendChunkedMessage(text, prefix, options) {
1615
1620
  const chunks = chunkMessage(text, MAX_MESSAGE_LENGTH);
1616
1621
  for (let i = 0; i < chunks.length; i++) {
1617
- const chunk = prefix && i === 0 ? `${prefix}
1618
-
1619
- ${chunks[i]}` : chunks[i];
1620
- await sendMessage(chunk);
1622
+ const chunk = prefix && i === 0 ? `${prefix} ${chunks[i]}` : chunks[i];
1623
+ await sendMessage(chunk, "Markdown", options);
1621
1624
  }
1622
1625
  }
1623
1626
  const sessionManager = new SessionManager({
@@ -1627,17 +1630,20 @@ ${chunks[i]}` : chunks[i];
1627
1630
  sessionName: session.name,
1628
1631
  lastActivity: /* @__PURE__ */ new Date()
1629
1632
  });
1633
+ const parts = session.name.split(" ");
1634
+ const cmd = parts[0];
1635
+ const args2 = parts.slice(1).map((a) => a.replace(/^-+/, ""));
1636
+ const sessionLabel = args2.length > 0 ? `${cmd} (${args2.join(", ")})` : cmd;
1630
1637
  await sendMessage(
1631
- `*[${session.name}]* ${formatSessionStatus(session.status)}
1632
- Session started
1633
- \`${session.cwd}\``
1638
+ `Session started: ${sessionLabel}
1639
+ Directory: \`${session.cwd}\``
1634
1640
  );
1635
1641
  },
1636
1642
  onSessionEnd: async (sessionId) => {
1637
1643
  const tracking = activeSessions.get(sessionId);
1638
1644
  const name = tracking?.sessionName || sessionId;
1639
1645
  activeSessions.delete(sessionId);
1640
- await sendMessage(`*[${name}]* Session ended`);
1646
+ await sendMessage(`Session ended: ${name}`);
1641
1647
  },
1642
1648
  onSessionUpdate: async (sessionId, name) => {
1643
1649
  const tracking = activeSessions.get(sessionId);
@@ -1662,16 +1668,16 @@ Session started
1662
1668
  telegramSentMessages.delete(contentKey);
1663
1669
  return;
1664
1670
  }
1665
- await sendChunkedMessage(content, `*[${tracking.sessionName}]* *User:*`);
1671
+ await sendChunkedMessage(content, `_User (terminal):_`, { disable_notification: true });
1666
1672
  } else {
1667
- await sendChunkedMessage(content, `*[${tracking.sessionName}]* *Claude:*`);
1673
+ await sendChunkedMessage(content, `_Claude Code:_`);
1668
1674
  }
1669
1675
  },
1670
1676
  onTodos: async (sessionId, todos) => {
1671
1677
  const tracking = activeSessions.get(sessionId);
1672
1678
  if (!tracking || todos.length === 0) return;
1673
1679
  const todosText = formatTodos(todos);
1674
- await sendMessage(`*[${tracking.sessionName}]* *Tasks:*
1680
+ await sendMessage(`_Claude Code:_ *Tasks:*
1675
1681
  ${todosText}`);
1676
1682
  },
1677
1683
  onToolCall: async (_sessionId, _tool) => {
@@ -1682,7 +1688,7 @@ ${todosText}`);
1682
1688
  const tracking = activeSessions.get(sessionId);
1683
1689
  if (!tracking) return;
1684
1690
  const status = inPlanMode ? "Planning mode - Claude is designing a solution" : "Execution mode - Claude is implementing";
1685
- await sendMessage(`*[${tracking.sessionName}]* ${status}`);
1691
+ await sendMessage(`_Claude Code:_ ${status}`);
1686
1692
  }
1687
1693
  });
1688
1694
  function getCurrentSession() {
@@ -2504,30 +2510,29 @@ async function main() {
2504
2510
  AFK Code - Monitor Claude Code sessions from Slack/Discord/Telegram
2505
2511
 
2506
2512
  Commands:
2507
- slack Run the Slack bot
2508
- slack setup Configure Slack integration
2509
- discord Run the Discord bot
2510
- discord setup Configure Discord integration
2511
2513
  telegram Run the Telegram bot
2512
2514
  telegram setup Configure Telegram integration
2513
- run -- <command> Start a monitored session
2515
+ discord Run the Discord bot
2516
+ discord setup Configure Discord integration
2517
+ slack Run the Slack bot
2518
+ slack setup Configure Slack integration
2519
+ <command> [args] Start a monitored session
2514
2520
  help Show this help message
2515
2521
 
2516
2522
  Examples:
2517
- afk-code slack setup # First-time Slack configuration
2518
- afk-code slack # Start the Slack bot
2519
- afk-code discord setup # First-time Discord configuration
2520
- afk-code discord # Start the Discord bot
2521
2523
  afk-code telegram setup # First-time Telegram configuration
2522
2524
  afk-code telegram # Start the Telegram bot
2523
- afk-code run -- claude # Start a Claude Code session
2525
+ afk-code discord setup # First-time Discord configuration
2526
+ afk-code discord # Start the Discord bot
2527
+ afk-code slack setup # First-time Slack configuration
2528
+ afk-code slack # Start the Slack bot
2529
+ afk-code claude # Start a Claude Code session
2524
2530
  `);
2525
2531
  break;
2526
2532
  }
2527
2533
  default: {
2528
- console.error(`Unknown command: ${command}`);
2529
- console.error('Run "afk-code help" for usage');
2530
- process.exit(1);
2534
+ await run(args);
2535
+ break;
2531
2536
  }
2532
2537
  }
2533
2538
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "afk-code",
3
- "version": "0.1.4",
3
+ "version": "0.2.0",
4
4
  "description": "Monitor and interact with Claude Code sessions from Slack/Discord/Telegram",
5
5
  "author": "Colin Harman",
6
6
  "repository": {
@@ -36,7 +36,7 @@
36
36
  "cli"
37
37
  ],
38
38
  "license": "MIT",
39
- "dependencies": {
39
+ "dependencies": {
40
40
  "@slack/bolt": "^4.6.0",
41
41
  "discord.js": "^14.25.1",
42
42
  "grammy": "^1.35.0",