@openacp/cli 0.6.9 → 0.6.10

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,9 +2,9 @@
2
2
 
3
3
  # OpenACP
4
4
 
5
- **Self-hosted bridge between messaging platforms and AI coding agents**
5
+ **Control AI coding agents from Telegram, Discord & Slack**
6
6
 
7
- One message, any channel, any agent.
7
+ Send a message. The agent writes code. You see everything — in real time.
8
8
 
9
9
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
10
10
  [![Node.js >= 20](https://img.shields.io/badge/Node.js-%3E%3D%2020-green.svg)](https://nodejs.org/)
@@ -12,7 +12,7 @@ One message, any channel, any agent.
12
12
  [![npm](https://img.shields.io/npm/v/@openacp/cli.svg)](https://www.npmjs.com/package/@openacp/cli)
13
13
  [![Twitter Follow](https://img.shields.io/twitter/follow/Open_ACP?style=social)](https://x.com/Open_ACP)
14
14
 
15
- [Getting Started](docs/guide/getting-started.md) | [Agents](docs/guide/agents.md) | [Usage](docs/guide/usage.md) | [Configuration](docs/guide/configuration.md) | [Plugins](docs/guide/plugins.md) | [Development](docs/guide/development.md)
15
+ [Documentation](docs/gitbook/) · [Quick Start](#quick-start) · [Features](#features) · [Agents](#supported-agents) · [Contributing](docs/gitbook/extending/contributing.md)
16
16
 
17
17
  </div>
18
18
 
@@ -20,22 +20,20 @@ One message, any channel, any agent.
20
20
 
21
21
  ## What is OpenACP?
22
22
 
23
- OpenACP lets you control AI coding agents (Claude Code, Codex, ...) from messaging apps like Telegram and Discord. You send a message, the agent writes code, runs commands, and streams everything back in real time.
23
+ OpenACP is a self-hosted bridge that connects AI coding agents to your messaging platforms. You chat with an AI agent through Telegram, Discord, or Slack it reads your codebase, writes code, runs commands, and streams results back to you in real time.
24
24
 
25
- It uses the [Agent Client Protocol (ACP)](https://agentclientprotocol.org/) to talk to agents. You host it on your own machine, so you own the data.
25
+ Built on the open [Agent Client Protocol (ACP)](https://agentclientprotocol.org/). Your machine, your keys, your data.
26
26
 
27
27
  ```
28
- You (Telegram / Discord / ...)
28
+ You (Telegram / Discord / Slack)
29
29
 
30
- OpenACP ─── ChannelAdapter ─── Session Manager ─── Session Store
31
-
32
- ACP Protocol (JSON-RPC / stdio) Tunnel Service
33
-
34
- AI Agent (Claude Code, Codex, ...) File/Diff Viewer
30
+ OpenACP (bridge + session manager)
31
+
32
+ AI Agent (Claude Code, Codex, Gemini, Cursor, ...)
33
+
34
+ Your Codebase
35
35
  ```
36
36
 
37
- ## Screenshots
38
-
39
37
  <div align="center">
40
38
  <table>
41
39
  <tr>
@@ -49,176 +47,124 @@ AI Agent (Claude Code, Codex, ...) File/Diff Viewer
49
47
  </table>
50
48
  </div>
51
49
 
52
- ## Supported Agents
53
-
54
- OpenACP follows the [Agent Client Protocol (ACP)](https://agentclientprotocol.com/) standard — an open protocol for connecting AI coding agents to client applications. Agent definitions are loaded from the [official ACP Registry](https://agentclientprotocol.com/get-started/registry) via CDN ([`registry.json`](https://cdn.agentclientprotocol.com/registry/v1/latest/registry.json)), so new agents are available as soon as they're registered.
55
-
56
- | Agent | Distribution | Description |
57
- |-------|-------------|-------------|
58
- | [Claude Agent](https://github.com/anthropics/claude-code) | npx | Anthropic's Claude coding agent |
59
- | [Gemini CLI](https://github.com/google-gemini/gemini-cli) | npx | Google's official CLI for Gemini |
60
- | [Codex CLI](https://github.com/openai/codex) | npx | OpenAI's coding assistant |
61
- | [GitHub Copilot](https://github.com/github/copilot-cli) | npx | GitHub's AI pair programmer |
62
- | [Cursor](https://www.cursor.com/) | binary | Cursor's coding agent |
63
- | [Cline](https://github.com/cline/cline) | npx | Autonomous coding agent with file editing, commands, and browser |
64
- | [goose](https://github.com/block/goose) | binary | Open source AI agent for engineering tasks |
65
- | [Amp](https://github.com/tao12345666333/amp-acp) | binary | The frontier coding agent |
66
- | [Auggie CLI](https://www.augmentcode.com/) | npx | Augment Code's agent with industry-leading context engine |
67
- | [Junie](https://www.jetbrains.com/) | binary | AI coding agent by JetBrains |
68
- | [Kilo](https://github.com/kilocode/kilo) | npx | The open source coding agent |
69
- | [Qwen Code](https://github.com/QwenLM/qwen-code) | npx | Alibaba's Qwen coding assistant |
70
- | [crow-cli](https://github.com/crowdecode/crow-cli) | uvx | Minimal ACP native coding agent |
71
- | ...and more | | [See full registry →](https://agentclientprotocol.com/get-started/registry) |
72
-
73
- > **28+ agents supported** — any agent registered in the ACP Registry works out of the box. Install with `openacp agents install <name>` or browse from Telegram with `/agents`.
74
-
75
- ## Features
76
-
77
- - **Multi-agent** — Claude Code, Codex, Gemini, Cursor, and [28+ ACP-compatible agents](#supported-agents)
78
- - **Telegram** — Forum topics, real-time streaming, permission buttons, skill commands
79
- - **Discord** — Forum/thread-based sessions, slash commands, button interactions
80
- - **Session persistence** — Resume sessions across restarts
81
- - **Daemon mode** — Background service with auto-start on boot
82
- - **CLI API** — Create and manage sessions from the terminal
83
- - **Config editor** — Interactive `openacp config` for all settings
84
- - **Setup wizard** — Interactive first-run setup with bot validation and auto-detect
85
- - **Plugin system** — Install channel adapters as npm packages
86
- - **Structured logging** — Pino with rotation, per-session log files
87
- - **Self-hosted** — Your keys, your data, your machine
88
-
89
- ### [Tunnel & Port Forwarding](docs/guide/tunnel.md)
90
-
91
- Expose any local port to the internet — dev servers, APIs, static sites. Tunnel is enabled by default with Cloudflare (free, no account needed).
92
-
93
- - `/tunnel 3000 my-app` in Telegram or `openacp tunnel add 3000 --label my-app` from CLI
94
- - `/tunnels` to list active tunnels with public URLs and stop buttons
95
- - Agents can create tunnels too — say "expose port 5173" and the agent handles it
96
- - Built-in file/diff viewer — Monaco Editor (VS Code engine) with syntax highlighting, line range links, markdown preview
97
- - Providers: Cloudflare (default), ngrok, bore, Tailscale Funnel
98
-
99
- ## Setup
100
-
101
- ### Prerequisites
102
-
103
- - **Node.js 20+**
104
- - **A messaging platform** — Telegram, Discord, or both:
105
- - **Telegram**: Create a bot via [@BotFather](https://t.me/BotFather), create a supergroup with Topics enabled, add bot as admin
106
- - **Discord**: Create a bot at [Discord Developer Portal](https://discord.com/developers/applications), invite it to your server with Manage Channels + Send Messages permissions
107
-
108
- ### Install & first run
50
+ ## Quick Start
109
51
 
110
52
  ```bash
111
53
  npm install -g @openacp/cli
112
54
  openacp
113
55
  ```
114
56
 
115
- > **Important: `openacp` is an interactive CLI.**
116
- > The first run launches a setup wizard that asks you questions in the terminal (bot token, server selection, workspace path, etc.).
117
- > You **must run it yourself in a terminal** — it cannot be run by a script or an AI agent because it requires interactive input.
57
+ The interactive setup wizard walks you through everything:
118
58
 
119
- The wizard will:
59
+ 1. Choose your platform (Telegram, Discord, Slack, or multiple)
60
+ 2. Connect your bot (token validation + auto-detection)
61
+ 3. Pick a workspace directory
62
+ 4. Select your default AI agent
63
+ 5. Choose run mode (foreground or daemon)
120
64
 
121
- 1. **Choose your channel(s)** Telegram, Discord, or both
122
- 2. **Configure bot credentials** — bot token and server/group ID, validated against the platform API
123
- 3. **Set a workspace directory** — where agents will create project folders (default: `~/openacp-workspace`)
124
- 4. **Detect installed agents** — finds Claude Code, Codex, etc.
125
- 5. **Choose run mode** — foreground (in terminal) or background (daemon with auto-start)
65
+ That's it. Send a message to your bot and start coding.
126
66
 
127
- Config is saved to `~/.openacp/config.json`. After setup, OpenACP starts automatically.
67
+ > **Need detailed setup for a specific platform?** See the [Platform Setup guides](docs/gitbook/platform-setup/).
128
68
 
129
- ### Running after setup
69
+ ## Features
130
70
 
131
- ```bash
132
- # Foreground (shows logs in terminal)
133
- openacp
71
+ ### Messaging Platforms
134
72
 
135
- # Or as a background daemon
136
- openacp start
137
- openacp stop
138
- openacp status
139
- openacp logs
140
- ```
73
+ | Platform | Status | Highlights |
74
+ |----------|--------|------------|
75
+ | **Telegram** | Stable | Forum topics per session, streaming, permission buttons, voice |
76
+ | **Discord** | Stable | Thread-based sessions, slash commands, button interactions |
77
+ | **Slack** | Stable | Socket Mode, channel-based sessions, thread organization |
141
78
 
142
- ### Other CLI commands
79
+ ### Core
143
80
 
144
- ```bash
145
- # Agent management
146
- openacp agents # List all agents (installed + available)
147
- openacp agents install <name> # Install an agent from the ACP Registry
148
- openacp agents uninstall <name> # Remove an installed agent
149
- openacp agents info <name> # Show agent details & dependencies
150
- openacp agents refresh # Force-refresh the registry
151
-
152
- # API (requires running daemon)
153
- openacp api new [agent] [workspace] # Create a new session
154
- openacp api cancel <id> # Cancel a session
155
- openacp api status # Show active sessions
156
- openacp api agents # List available agents
157
-
158
- # System
159
- openacp config # Interactive config editor
160
- openacp reset # Re-run the setup wizard
161
- openacp update # Update to latest version
162
- openacp install <plugin> # Install a plugin (e.g. @openacp/adapter-discord)
163
- openacp uninstall <plugin>
164
- openacp plugins # List installed plugins
165
- ```
81
+ - **28+ AI agents** — Claude Code, Codex, Gemini, Cursor, Copilot, and [more](#supported-agents)
82
+ - **Session management** — Each conversation gets its own thread/topic with auto-naming
83
+ - **Session persistence** Sessions survive restarts, with configurable TTL
84
+ - **Permission control** Approve or deny agent actions via buttons, with optional auto-approve
85
+ - **Real-time streaming** See agent thinking, tool calls, and output as they happen
166
86
 
167
- ## Usage
87
+ ### Developer Tools
168
88
 
169
- Once OpenACP is running, control it from Telegram or Discord:
89
+ - **Tunnel & port forwarding** Expose local ports to the internet (Cloudflare, ngrok, bore, Tailscale)
90
+ - **Built-in file viewer** — Monaco Editor with syntax highlighting, diffs, and markdown preview
91
+ - **Session transfer** — Move sessions between terminal and chat (`/handoff`)
92
+ - **Voice & speech** — Send voice messages, get spoken responses (Groq STT + Edge TTS)
93
+ - **Usage tracking** — Token counts, cost reports, optional monthly budget limits
94
+ - **Context resume** — Resume sessions with full conversation history
170
95
 
171
- **Telegram** — Bot commands in your supergroup:
96
+ ### Operations
172
97
 
173
- | Command | Description |
174
- |---------|-------------|
175
- | `/new [agent] [workspace]` | Create a new session |
176
- | `/newchat` | New session, same agent & workspace |
177
- | `/cancel` | Cancel current session |
178
- | `/status` | Show session or system status |
179
- | `/agents` | Browse & install agents from ACP Registry |
180
- | `/install <name>` | Install an agent directly |
98
+ - **Daemon mode** Run as a background service with auto-start on boot
99
+ - **CLI API** — Full REST API for automation (`openacp api ...`)
100
+ - **Plugin system** Install adapters as npm packages
101
+ - **Doctor diagnostics** `openacp doctor` checks everything and suggests fixes
102
+ - **Structured logging** Pino with rotation, per-session log files
181
103
 
182
- Each session gets its own forum topic.
104
+ > **Full feature documentation** [docs/gitbook/](docs/gitbook/)
183
105
 
184
- **Discord** Slash commands in your server:
106
+ ## Supported Agents
185
107
 
186
- | Command | Description |
187
- |---------|-------------|
188
- | `/new [agent] [workspace]` | Create a new session |
189
- | `/newchat` | New session, same agent & workspace |
190
- | `/cancel` | Cancel current session |
191
- | `/status` | Show session or system status |
192
- | `/menu` | Open the control panel |
108
+ OpenACP uses the [ACP Registry](https://agentclientprotocol.com/get-started/registry) — new agents are available as soon as they're registered.
193
109
 
194
- Each session gets its own thread in the sessions channel. The agent streams responses in real time, shows tool calls, and asks for permission when needed.
110
+ | Agent | Type | Description |
111
+ |-------|------|-------------|
112
+ | [Claude Code](https://github.com/anthropics/claude-code) | npx | Anthropic's Claude coding agent |
113
+ | [Gemini CLI](https://github.com/google-gemini/gemini-cli) | npx | Google's Gemini CLI |
114
+ | [Codex CLI](https://github.com/openai/codex) | npx | OpenAI's coding assistant |
115
+ | [GitHub Copilot](https://github.com/github/copilot-cli) | npx | GitHub's AI pair programmer |
116
+ | [Cursor](https://www.cursor.com/) | binary | Cursor's coding agent |
117
+ | [Cline](https://github.com/cline/cline) | npx | Autonomous coding agent |
118
+ | [goose](https://github.com/block/goose) | binary | Open source AI agent by Block |
119
+ | [Amp](https://github.com/tao12345666333/amp-acp) | binary | The frontier coding agent |
120
+ | [Auggie CLI](https://www.augmentcode.com/) | npx | Augment Code's context engine |
121
+ | [Junie](https://www.jetbrains.com/) | binary | AI coding agent by JetBrains |
122
+ | [Kilo](https://github.com/kilocode/kilo) | npx | Open source coding agent |
123
+ | [Qwen Code](https://github.com/QwenLM/qwen-code) | npx | Alibaba's Qwen assistant |
124
+ | ...and more | | [Full registry →](https://agentclientprotocol.com/get-started/registry) |
195
125
 
196
- ### Session Transfer
126
+ ```bash
127
+ openacp agents # Browse all agents
128
+ openacp agents install <name> # Install from registry
129
+ ```
197
130
 
198
- Move sessions between your terminal and messaging platforms:
131
+ ## CLI Overview
199
132
 
200
- **Terminal → Chat:**
201
133
  ```bash
202
- # Install integration (one-time)
203
- openacp integrate claude
204
-
205
- # In Claude CLI, type /openacp:handoff to transfer the current session
206
- # Or manually:
207
- openacp adopt claude <session_id> --cwd /path/to/project
134
+ # Server
135
+ openacp # Start (first run = setup wizard)
136
+ openacp start / stop / status # Daemon management
137
+ openacp logs # Tail daemon logs
138
+
139
+ # Configuration
140
+ openacp config # Interactive config editor
141
+ openacp reset # Re-run setup wizard
142
+ openacp doctor # System diagnostics
143
+
144
+ # Sessions & API (requires running daemon)
145
+ openacp api new [agent] [workspace]
146
+ openacp api status
147
+ openacp api cancel <id>
148
+
149
+ # Tunnels
150
+ openacp tunnel add <port> [--label name]
151
+ openacp tunnel list
208
152
  ```
209
153
 
210
- **Chat Terminal:**
211
- Type `/handoff` in any session topic/thread. The bot replies with a command you can paste in your terminal to continue.
154
+ > **Full CLI reference** — [docs/gitbook/api-reference/cli-commands.md](docs/gitbook/api-reference/cli-commands.md)
212
155
 
213
- Sessions are not locked after transfer — you can continue from either side.
156
+ ## Documentation
214
157
 
215
- ## Roadmap
216
-
217
- - **Phase 1** Core + Telegram + ACP agents
218
- - **Phase 2** Tunnel/file viewer, session persistence, logging, plugin system
219
- - **Phase 3** Agent skills as commands, Discord adapter 🚧, Web UI
220
- - **Phase 4** Voice control, file/image sharing
221
- - **Phase 5** WhatsApp, agent chaining, plugin marketplace
158
+ | Section | Description |
159
+ |---------|-------------|
160
+ | [Getting Started](docs/gitbook/getting-started/) | What is OpenACP, quickstart for users & developers |
161
+ | [Platform Setup](docs/gitbook/platform-setup/) | Step-by-step guides for Telegram, Discord, Slack |
162
+ | [Using OpenACP](docs/gitbook/using-openacp/) | Commands, sessions, agents, permissions, voice |
163
+ | [Self-Hosting](docs/gitbook/self-hosting/) | Installation, configuration, daemon, security |
164
+ | [Features](docs/gitbook/features/) | Tunnel, context resume, usage tracking, and more |
165
+ | [Extending](docs/gitbook/extending/) | Plugin system, building adapters, contributing |
166
+ | [API Reference](docs/gitbook/api-reference/) | CLI commands, REST API, config schema, env vars |
167
+ | [Troubleshooting](docs/gitbook/troubleshooting/) | Common issues and FAQ |
222
168
 
223
169
  ## Star History
224
170
 
@@ -232,7 +178,7 @@ Sessions are not locked after transfer — you can continue from either side.
232
178
 
233
179
  ## Contributing
234
180
 
235
- See [development guide](docs/guide/development.md).
181
+ We welcome contributions! See the [contributing guide](docs/gitbook/extending/contributing.md) for development setup, testing conventions, and PR process.
236
182
 
237
183
  ## Follow Us
238
184
 
@@ -6,9 +6,9 @@ import "./chunk-NAMYZIS5.js";
6
6
  import "./chunk-WTZDAYZX.js";
7
7
  import "./chunk-UKT3G5IA.js";
8
8
  import "./chunk-34M4OS5P.js";
9
- import "./chunk-BN3X7UXB.js";
9
+ import "./chunk-MKHUZLII.js";
10
10
  import "./chunk-2CJ46J3C.js";
11
- import "./chunk-BDYVCIBH.js";
11
+ import "./chunk-LCRLAV4G.js";
12
12
  import "./chunk-JKBFUAJK.js";
13
13
  import "./chunk-VOIJ6OY4.js";
14
14
  import "./chunk-JHYXKVV2.js";
@@ -796,4 +796,4 @@ ${notification.summary}`;
796
796
  export {
797
797
  SlackAdapter
798
798
  };
799
- //# sourceMappingURL=adapter-LNEGLMOE.js.map
799
+ //# sourceMappingURL=adapter-ZOANORGM.js.map
@@ -1,6 +1,5 @@
1
1
  import {
2
2
  PRODUCT_GUIDE,
3
- STATUS_ICONS,
4
3
  dispatchMessage,
5
4
  evaluateNoise,
6
5
  extractContentText,
@@ -8,10 +7,11 @@ import {
8
7
  formatToolSummary,
9
8
  formatToolTitle,
10
9
  progressBar,
10
+ resolveToolIcon,
11
11
  splitMessage,
12
12
  stripCodeFences,
13
13
  truncateContent
14
- } from "./chunk-JUYDFUSN.js";
14
+ } from "./chunk-OWP7RZ62.js";
15
15
  import {
16
16
  CheckpointReader,
17
17
  DEFAULT_MAX_TOKENS
@@ -118,33 +118,43 @@ function markdownToTelegramHtml(md) {
118
118
  return text;
119
119
  }
120
120
  function formatToolCall(tool, verbosity = "medium") {
121
- const si = STATUS_ICONS[tool.status || ""] || "\u{1F527}";
121
+ const si = resolveToolIcon(tool);
122
122
  const name = tool.name || "Tool";
123
- const label = verbosity === "low" ? formatToolTitle(name, tool.rawInput) : formatToolSummary(name, tool.rawInput);
123
+ const label = verbosity === "low" ? formatToolTitle(name, tool.rawInput, tool.displayTitle) : formatToolSummary(name, tool.rawInput, tool.displaySummary);
124
124
  let text = `${si} <b>${escapeHtml(label)}</b>`;
125
125
  text += formatViewerLinks(tool.viewerLinks, tool.viewerFilePath);
126
- if (verbosity === "high" || verbosity === "medium" && !tool.viewerLinks) {
127
- const details = stripCodeFences(extractContentText(tool.content));
128
- if (details) {
129
- text += `
130
- <pre>${escapeHtml(truncateContent(details, 3800))}</pre>`;
131
- }
126
+ if (verbosity === "high") {
127
+ text += formatHighDetails(tool.rawInput, tool.content, 3800);
132
128
  }
133
129
  return text;
134
130
  }
135
131
  function formatToolUpdate(update, verbosity = "medium") {
136
- const si = STATUS_ICONS[update.status] || "\u{1F527}";
132
+ const si = resolveToolIcon(update);
137
133
  const name = update.name || "Tool";
138
- const label = verbosity === "low" ? formatToolTitle(name, update.rawInput) : formatToolSummary(name, update.rawInput);
134
+ const label = verbosity === "low" ? formatToolTitle(name, update.rawInput, update.displayTitle) : formatToolSummary(name, update.rawInput, update.displaySummary);
139
135
  let text = `${si} <b>${escapeHtml(label)}</b>`;
140
136
  text += formatViewerLinks(update.viewerLinks, update.viewerFilePath);
141
- if (verbosity === "high" || verbosity === "medium" && !update.viewerLinks) {
142
- const details = stripCodeFences(extractContentText(update.content));
143
- if (details) {
137
+ if (verbosity === "high") {
138
+ text += formatHighDetails(update.rawInput, update.content, 3800);
139
+ }
140
+ return text;
141
+ }
142
+ function formatHighDetails(rawInput, content, maxLen) {
143
+ let text = "";
144
+ if (rawInput) {
145
+ const inputStr = typeof rawInput === "string" ? rawInput : JSON.stringify(rawInput, null, 2);
146
+ if (inputStr && inputStr !== "{}") {
144
147
  text += `
145
- <pre>${escapeHtml(truncateContent(details, 3800))}</pre>`;
148
+ <b>Input:</b>
149
+ <pre>${escapeHtml(truncateContent(inputStr, maxLen))}</pre>`;
146
150
  }
147
151
  }
152
+ const details = stripCodeFences(extractContentText(content));
153
+ if (details) {
154
+ text += `
155
+ <b>Output:</b>
156
+ <pre>${escapeHtml(truncateContent(details, maxLen))}</pre>`;
157
+ }
148
158
  return text;
149
159
  }
150
160
  function formatViewerLinks(links, filePath) {
@@ -159,16 +169,23 @@ function formatViewerLinks(links, filePath) {
159
169
  \u{1F4DD} <a href="${escapeHtml(links.diff)}">View diff${fileName ? ` \u2014 ${escapeHtml(fileName)}` : ""}</a>`;
160
170
  return text;
161
171
  }
162
- function formatUsage(usage) {
163
- const { tokensUsed, contextSize } = usage;
172
+ function formatUsage(usage, verbosity = "medium") {
173
+ const { tokensUsed, contextSize, cost } = usage;
164
174
  if (tokensUsed == null) return "\u{1F4CA} Usage data unavailable";
175
+ if (verbosity === "medium") {
176
+ const costStr = cost != null ? ` \xB7 $${cost.toFixed(2)}` : "";
177
+ return `\u{1F4CA} ${formatTokens(tokensUsed)} tokens${costStr}`;
178
+ }
165
179
  if (contextSize == null) return `\u{1F4CA} ${formatTokens(tokensUsed)} tokens`;
166
180
  const ratio = tokensUsed / contextSize;
167
181
  const pct = Math.round(ratio * 100);
168
182
  const bar = progressBar(ratio);
169
183
  const emoji = pct >= 85 ? "\u26A0\uFE0F" : "\u{1F4CA}";
170
- return `${emoji} ${formatTokens(tokensUsed)} / ${formatTokens(contextSize)} tokens
184
+ let text = `${emoji} ${formatTokens(tokensUsed)} / ${formatTokens(contextSize)} tokens
171
185
  ${bar} ${pct}%`;
186
+ if (cost != null) text += `
187
+ \u{1F4B0} $${cost.toFixed(2)}`;
188
+ return text;
172
189
  }
173
190
  var PERIOD_LABEL = {
174
191
  today: "Today",
@@ -2975,11 +2992,15 @@ var ThinkingIndicator = class {
2975
2992
  const elapsed = Math.round((Date.now() - this.showTime) / 1e3);
2976
2993
  this.sendQueue.enqueue(() => {
2977
2994
  if (this.dismissed) return Promise.resolve(void 0);
2978
- return this.api.sendMessage(this.chatId, `\u{1F4AD} <i>Still thinking... (${elapsed}s)</i>`, {
2979
- message_thread_id: this.threadId,
2980
- parse_mode: "HTML",
2981
- disable_notification: true
2982
- });
2995
+ return this.api.sendMessage(
2996
+ this.chatId,
2997
+ `\u{1F4AD} <i>Still thinking... (${elapsed}s)</i>`,
2998
+ {
2999
+ message_thread_id: this.threadId,
3000
+ parse_mode: "HTML",
3001
+ disable_notification: true
3002
+ }
3003
+ );
2983
3004
  }).then((result) => {
2984
3005
  if (result && !this.dismissed) {
2985
3006
  this.msgId = result.message_id;
@@ -3003,8 +3024,8 @@ var UsageMessage = class {
3003
3024
  this.sendQueue = sendQueue;
3004
3025
  }
3005
3026
  msgId;
3006
- async send(usage) {
3007
- const text = formatUsage(usage);
3027
+ async send(usage, verbosity = "medium") {
3028
+ const text = formatUsage(usage, verbosity);
3008
3029
  try {
3009
3030
  if (this.msgId) {
3010
3031
  await this.sendQueue.enqueue(
@@ -3034,13 +3055,19 @@ var UsageMessage = class {
3034
3055
  const id = this.msgId;
3035
3056
  this.msgId = void 0;
3036
3057
  try {
3037
- await this.sendQueue.enqueue(() => this.api.deleteMessage(this.chatId, id));
3058
+ await this.sendQueue.enqueue(
3059
+ () => this.api.deleteMessage(this.chatId, id)
3060
+ );
3038
3061
  } catch (err) {
3039
3062
  log10.warn({ err }, "UsageMessage.delete() failed");
3040
3063
  }
3041
3064
  }
3042
3065
  };
3043
- function formatPlanCard(entries) {
3066
+ function formatPlanCard(entries, verbosity = "medium") {
3067
+ if (verbosity === "medium") {
3068
+ const done2 = entries.filter((e) => e.status === "completed").length;
3069
+ return `\u{1F4CB} <b>Plan:</b> ${done2}/${entries.length} steps completed`;
3070
+ }
3044
3071
  const statusIcon = {
3045
3072
  completed: "\u2705",
3046
3073
  in_progress: "\u{1F504}",
@@ -3073,6 +3100,10 @@ var PlanCard = class {
3073
3100
  latestEntries;
3074
3101
  lastSentText;
3075
3102
  flushTimer;
3103
+ verbosity = "medium";
3104
+ setVerbosity(v) {
3105
+ this.verbosity = v;
3106
+ }
3076
3107
  update(entries) {
3077
3108
  this.latestEntries = entries;
3078
3109
  if (this.flushTimer) clearTimeout(this.flushTimer);
@@ -3101,7 +3132,7 @@ var PlanCard = class {
3101
3132
  }
3102
3133
  async _flush() {
3103
3134
  if (!this.latestEntries) return;
3104
- const text = formatPlanCard(this.latestEntries);
3135
+ const text = formatPlanCard(this.latestEntries, this.verbosity);
3105
3136
  if (this.msgId && text === this.lastSentText) return;
3106
3137
  this.lastSentText = text;
3107
3138
  try {
@@ -3151,10 +3182,11 @@ var ActivityTracker = class {
3151
3182
  await this._firstEventGuard();
3152
3183
  await this.thinking.show();
3153
3184
  }
3154
- async onPlan(entries) {
3185
+ async onPlan(entries, verbosity) {
3155
3186
  await this._firstEventGuard();
3156
3187
  this.thinking.dismiss();
3157
3188
  this.hasPlanCard = true;
3189
+ if (verbosity) this.planCard.setVerbosity(verbosity);
3158
3190
  this.planCard.update(entries);
3159
3191
  }
3160
3192
  async onToolCall() {
@@ -3166,8 +3198,8 @@ var ActivityTracker = class {
3166
3198
  await this._firstEventGuard();
3167
3199
  this.thinking.dismiss();
3168
3200
  }
3169
- async sendUsage(data) {
3170
- await this.usage.send(data);
3201
+ async sendUsage(data, verbosity = "medium") {
3202
+ await this.usage.send(data, verbosity);
3171
3203
  }
3172
3204
  getUsageMsgId() {
3173
3205
  return this.usage.getMsgId();
@@ -4355,7 +4387,10 @@ var TelegramAdapter = class extends ChannelAdapter {
4355
4387
  content: meta.content,
4356
4388
  rawInput: meta.rawInput,
4357
4389
  viewerLinks: meta.viewerLinks,
4358
- viewerFilePath: meta.viewerFilePath
4390
+ viewerFilePath: meta.viewerFilePath,
4391
+ displaySummary: meta.displaySummary,
4392
+ displayTitle: meta.displayTitle,
4393
+ displayKind: meta.displayKind
4359
4394
  },
4360
4395
  this.verbosity
4361
4396
  );
@@ -4372,7 +4407,10 @@ var TelegramAdapter = class extends ChannelAdapter {
4372
4407
  content: meta.content,
4373
4408
  rawInput: meta.rawInput,
4374
4409
  viewerLinks: meta.viewerLinks,
4375
- viewerFilePath: meta.viewerFilePath
4410
+ viewerFilePath: meta.viewerFilePath,
4411
+ displaySummary: meta.displaySummary,
4412
+ displayTitle: meta.displayTitle,
4413
+ displayKind: meta.displayKind
4376
4414
  },
4377
4415
  this.verbosity
4378
4416
  );
@@ -4386,7 +4424,8 @@ var TelegramAdapter = class extends ChannelAdapter {
4386
4424
  content: e.content,
4387
4425
  status: e.status,
4388
4426
  priority: e.priority ?? "medium"
4389
- }))
4427
+ })),
4428
+ this.verbosity
4390
4429
  );
4391
4430
  },
4392
4431
  onUsage: async (ctx, content) => {
@@ -4396,7 +4435,7 @@ var TelegramAdapter = class extends ChannelAdapter {
4396
4435
  this.assistantSession?.id
4397
4436
  );
4398
4437
  const tracker = this.getOrCreateTracker(ctx.sessionId, ctx.threadId);
4399
- await tracker.sendUsage(meta ?? {});
4438
+ await tracker.sendUsage(meta ?? {}, this.verbosity);
4400
4439
  if (this.notificationTopicId && ctx.sessionId !== this.assistantSession?.id) {
4401
4440
  const sess = this.core.sessionManager.getSession(ctx.sessionId);
4402
4441
  const sessionName = sess?.name || "Session";
@@ -4592,7 +4631,16 @@ Task completed.
4592
4631
 
4593
4632
  <a href="${deepLink}">\u2192 Go to topic</a>`;
4594
4633
  }
4595
- const replyMarkup = notification.type === "completed" ? { inline_keyboard: [[{ text: "\u{1F4CB} Summary", callback_data: `sm:summary:${notification.sessionId}` }]] } : void 0;
4634
+ const replyMarkup = notification.type === "completed" ? {
4635
+ inline_keyboard: [
4636
+ [
4637
+ {
4638
+ text: "\u{1F4CB} Summary",
4639
+ callback_data: `sm:summary:${notification.sessionId}`
4640
+ }
4641
+ ]
4642
+ ]
4643
+ } : void 0;
4596
4644
  await this.sendQueue.enqueue(
4597
4645
  () => this.bot.api.sendMessage(this.telegramConfig.chatId, text, {
4598
4646
  message_thread_id: this.notificationTopicId,
@@ -4737,4 +4785,4 @@ Task completed.
4737
4785
  export {
4738
4786
  TelegramAdapter
4739
4787
  };
4740
- //# sourceMappingURL=chunk-H5P2C6H4.js.map
4788
+ //# sourceMappingURL=chunk-CS3KCJ5D.js.map