@plosson/agentio 0.1.27 → 0.1.28

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
@@ -1,8 +1,55 @@
1
1
  # agentio
2
2
 
3
- CLI for LLM agents to interact with communication and tracking services.
3
+ **Run LLM agent workflows in GitHub Actions. No servers. No Zapier. Just cron.**
4
+
5
+ agentio is a CLI that lets LLM agents interact with Gmail, Slack, JIRA, Telegram, Google Chat, and RSS feeds. Designed for CI/CD pipelines and scheduled automation.
6
+
7
+ ## Why agentio?
8
+
9
+ You want your AI agent to:
10
+ - Send a daily Slack summary of unread emails
11
+ - Monitor RSS feeds and post to Telegram
12
+ - Update JIRA tickets based on email threads
13
+ - Run on a schedule, without managing servers
14
+
15
+ **agentio makes this trivial.** Authenticate once locally, export your config as a single encrypted file, and run anywhere — GitHub Actions, GitLab CI, or any CI/CD platform.
16
+
17
+ ## Quick Example
18
+
19
+ A scheduled workflow that reads your emails, has Claude summarize them, and posts to Slack:
20
+
21
+ ```yaml
22
+ # .github/workflows/daily-briefing.yml
23
+ name: Daily Briefing
24
+ on:
25
+ schedule:
26
+ - cron: '0 7 * * 1-5'
27
+
28
+ jobs:
29
+ briefing:
30
+ runs-on: ubuntu-latest
31
+ env:
32
+ AGENTIO_CONFIG: ${{ secrets.AGENTIO_CONFIG }}
33
+ AGENTIO_KEY: ${{ secrets.AGENTIO_KEY }}
34
+ CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
35
+ steps:
36
+ - uses: actions/checkout@v4
37
+ - run: curl -LsSf https://agentio.work/install | sh
38
+ - run: npm install -g @anthropic-ai/claude-code
39
+ - run: agentio config import && agentio claude install
40
+ - run: claude -p "$(cat prompt.md)" --max-turns 30 --dangerously-skip-permissions
41
+ ```
42
+
43
+ ```markdown
44
+ # prompt.md
45
+ Fetch my unread emails from the last 24 hours using agentio-gmail.
46
+ Summarize them by urgency and sender.
47
+ Post the summary to Slack using agentio-slack.
48
+ ```
4
49
 
5
- ## Quick Install
50
+ See [`examples/daily-briefing/`](./examples/daily-briefing) for the complete working example.
51
+
52
+ ## Install
6
53
 
7
54
  **macOS / Linux:**
8
55
  ```bash
@@ -14,150 +61,154 @@ curl -LsSf https://agentio.work/install | sh
14
61
  iwr -useb https://agentio.work/install.ps1 | iex
15
62
  ```
16
63
 
17
- ## Update
18
-
19
- ```bash
20
- agentio update
21
- ```
22
-
23
- ## Alternative Installation Methods
24
-
25
64
  <details>
26
- <summary>Homebrew (macOS/Linux)</summary>
65
+ <summary><strong>Other methods</strong> (Homebrew, Scoop, npm)</summary>
27
66
 
67
+ **Homebrew (macOS/Linux):**
28
68
  ```bash
29
69
  brew tap plosson/agentio
30
70
  brew install agentio
31
71
  ```
32
- </details>
33
-
34
- <details>
35
- <summary>Scoop (Windows)</summary>
36
72
 
73
+ **Scoop (Windows):**
37
74
  ```powershell
38
75
  scoop bucket add agentio https://github.com/plosson/scoop-agentio
39
76
  scoop install agentio
40
77
  ```
41
- </details>
42
-
43
- <details>
44
- <summary>npm / bun</summary>
45
78
 
79
+ **npm / bun:**
46
80
  ```bash
47
- # Run directly
48
- bunx @plosson/agentio --help
49
81
  npx @plosson/agentio --help
50
-
51
- # Global install
52
- bun add -g @plosson/agentio
82
+ # or global install
53
83
  npm install -g @plosson/agentio
54
84
  ```
85
+
55
86
  </details>
56
87
 
57
- <details>
58
- <summary>Direct binary download</summary>
88
+ ## Setup: Authenticate Once, Run Anywhere
59
89
 
60
- Download from [GitHub Releases](https://github.com/plosson/agentio/releases/latest):
61
- - macOS: `agentio-darwin-arm64` (Apple Silicon) or `agentio-darwin-x64` (Intel)
62
- - Linux: `agentio-linux-x64` or `agentio-linux-arm64`
63
- - Windows: `agentio-windows-x64.exe`
64
- </details>
90
+ ### 1. Authenticate locally
65
91
 
66
- ## Services
92
+ ```bash
93
+ # Add your Gmail account (opens browser for OAuth)
94
+ agentio gmail profile add
67
95
 
68
- | Service | Status | Commands |
69
- |---------|--------|----------|
70
- | Gmail | Available | `list`, `get`, `search`, `send`, `reply`, `archive`, `mark`, `attachment`, `export` |
71
- | Telegram | Available | `send` |
72
- | Google Chat | Available | `send`, `list`, `get` |
73
- | Slack | Available | `send` |
74
- | JIRA | Available | `projects`, `search`, `get`, `comment`, `transitions`, `transition` |
75
- | RSS | Available | `articles`, `get`, `info` |
76
- | Linear | Planned | - |
96
+ # Add Slack webhook
97
+ agentio slack profile add
77
98
 
78
- ## Usage
99
+ # Add any other services you need...
100
+ ```
79
101
 
80
- ### Gmail
102
+ ### 2. Export your config
81
103
 
82
104
  ```bash
83
- # First, authenticate
84
- agentio gmail profile add
105
+ agentio config export
106
+ # Outputs:
107
+ # ✓ Exported to agentio.config
108
+ # ✓ Encryption key: abc123...
109
+ #
110
+ # Store BOTH in your CI/CD secrets!
111
+ ```
85
112
 
86
- # List recent emails
87
- agentio gmail list --limit 10
113
+ All credentials are encrypted with AES-256-GCM. The export file is useless without the key.
88
114
 
89
- # Search emails
90
- agentio gmail search --query "from:boss@company.com is:unread"
115
+ **Note:** GitHub secrets are limited to 48KB per secret. Only add the profiles you need for your workflow to keep the exported config small.
91
116
 
92
- # Get a specific email
93
- agentio gmail get <message-id>
117
+ ### 3. Add to GitHub Secrets
118
+
119
+ | Secret | Value |
120
+ |--------|-------|
121
+ | `AGENTIO_CONFIG` | Base64-encoded contents of `agentio.config` |
122
+ | `AGENTIO_KEY` | The encryption key from export |
94
123
 
95
- # Send an email
96
- agentio gmail send --to user@example.com --subject "Hello" --body "Message body"
124
+ ```bash
125
+ # Get base64 for GitHub secret
126
+ cat agentio.config | base64
127
+ ```
97
128
 
98
- # Or pipe content
99
- echo "Message body" | agentio gmail send --to user@example.com --subject "Hello"
129
+ ### 4. Use in your workflow
100
130
 
101
- # Download attachments
102
- agentio gmail attachment <message-id>
103
- agentio gmail attachment <message-id> --name "document.pdf" --output ./downloads
131
+ ```yaml
132
+ env:
133
+ AGENTIO_CONFIG: ${{ secrets.AGENTIO_CONFIG }}
134
+ AGENTIO_KEY: ${{ secrets.AGENTIO_KEY }}
104
135
 
105
- # Export email as PDF
106
- agentio gmail export <message-id>
107
- agentio gmail export <message-id> --output email.pdf
136
+ steps:
137
+ - run: agentio config import # Auto-detects env vars
138
+ - run: agentio gmail list --limit 10
108
139
  ```
109
140
 
110
- ### Telegram
141
+ Done. Your agent can now access all your services securely in CI/CD.
111
142
 
112
- ```bash
113
- # Set up bot profile (interactive wizard)
114
- agentio telegram profile add
143
+ ## Services
115
144
 
116
- # Send message to channel
117
- agentio telegram send "Hello from agentio!"
145
+ | Service | Auth | Commands |
146
+ |---------|------|----------|
147
+ | **Gmail** | OAuth | `list`, `get`, `search`, `send`, `reply`, `archive`, `mark`, `attachment`, `export` |
148
+ | **Slack** | Webhook | `send` |
149
+ | **Telegram** | Bot Token | `send` |
150
+ | **Google Chat** | Webhook/OAuth | `send`, `list`, `get` |
151
+ | **JIRA** | OAuth | `projects`, `search`, `get`, `comment`, `transitions`, `transition` |
152
+ | **Discourse** | API Key | `list`, `get`, `categories` |
153
+ | **RSS** | None | `articles`, `get`, `info` |
118
154
 
119
- # Send with formatting
120
- agentio telegram send --parse-mode markdown "**Bold** and _italic_"
121
- ```
155
+ ## Usage Examples
122
156
 
123
- ### Google Chat
157
+ <details>
158
+ <summary><strong>Gmail</strong></summary>
124
159
 
125
160
  ```bash
126
- # Set up profile (webhook or OAuth)
127
- agentio gchat profile add
161
+ # List recent emails
162
+ agentio gmail list --limit 10
128
163
 
129
- # Send message via webhook
130
- agentio gchat send "Hello from agentio!"
164
+ # Search
165
+ agentio gmail search --query "from:boss@company.com is:unread"
131
166
 
132
- # Send with JSON payload for rich messages
133
- agentio gchat send --json message.json
167
+ # Get specific email
168
+ agentio gmail get <message-id>
134
169
 
135
- # List messages (OAuth profiles only)
136
- agentio gchat list --space <space-id>
170
+ # Send (body from stdin works great with LLMs)
171
+ echo "Generated by my agent" | agentio gmail send --to user@example.com --subject "Daily Report"
172
+
173
+ # Download attachments
174
+ agentio gmail attachment <message-id> --output ./downloads
137
175
 
138
- # Get a specific message (OAuth profiles only)
139
- agentio gchat get <message-id> --space <space-id>
176
+ # Export as PDF
177
+ agentio gmail export <message-id> --output email.pdf
140
178
  ```
141
179
 
142
- ### Slack
180
+ </details>
143
181
 
144
- ```bash
145
- # Set up webhook profile
146
- agentio slack profile add
182
+ <details>
183
+ <summary><strong>Slack</strong></summary>
147
184
 
185
+ ```bash
148
186
  # Send message
149
- agentio slack send "Hello from agentio!"
187
+ agentio slack send "Deployment complete "
150
188
 
151
- # Send Block Kit message from JSON file
189
+ # Send rich Block Kit message
152
190
  agentio slack send --json blocks.json
153
191
  ```
154
192
 
155
- ### JIRA
193
+ </details>
194
+
195
+ <details>
196
+ <summary><strong>Telegram</strong></summary>
156
197
 
157
198
  ```bash
158
- # Authenticate with OAuth
159
- agentio jira profile add
199
+ # Send to channel
200
+ agentio telegram send "Alert: New items found"
201
+
202
+ # With markdown
203
+ agentio telegram send --parse-mode markdown "**Bold** and _italic_"
204
+ ```
160
205
 
206
+ </details>
207
+
208
+ <details>
209
+ <summary><strong>JIRA</strong></summary>
210
+
211
+ ```bash
161
212
  # List projects
162
213
  agentio jira projects
163
214
 
@@ -168,39 +219,38 @@ agentio jira search --jql "assignee = currentUser() AND status != Done"
168
219
  # Get issue details
169
220
  agentio jira get PROJ-123
170
221
 
171
- # Add a comment
172
- agentio jira comment PROJ-123 "This is my comment"
173
-
174
- # View available transitions
175
- agentio jira transitions PROJ-123
222
+ # Add comment
223
+ agentio jira comment PROJ-123 "Automated update from CI"
176
224
 
177
- # Transition an issue
225
+ # Transition issue
226
+ agentio jira transitions PROJ-123 # see available transitions
178
227
  agentio jira transition PROJ-123 <transition-id>
179
228
  ```
180
229
 
181
- ### RSS
230
+ </details>
231
+
232
+ <details>
233
+ <summary><strong>RSS</strong></summary>
182
234
 
183
235
  ```bash
184
- # List articles from a blog (feed URL auto-discovered)
185
- agentio rss articles https://simonwillison.net
186
- agentio rss articles https://steipete.me --limit 5
236
+ # List articles (auto-discovers feed URL)
237
+ agentio rss articles https://simonwillison.net --limit 10
187
238
 
188
239
  # Filter by date
189
- agentio rss articles https://blog.fsck.com --since 2025-01-01
240
+ agentio rss articles https://blog.example.com --since 2025-01-01
190
241
 
191
- # Get feed info (shows discovered feed URL)
192
- agentio rss info https://kau.sh
193
-
194
- # Get a specific article
242
+ # Get full article
195
243
  agentio rss get https://simonwillison.net <article-url>
196
244
  ```
197
245
 
246
+ </details>
247
+
198
248
  ## Multi-Profile Support
199
249
 
200
- Each service supports multiple named profiles:
250
+ Manage multiple accounts per service:
201
251
 
202
252
  ```bash
203
- # Add profiles for different accounts
253
+ # Add named profiles
204
254
  agentio gmail profile add --profile work
205
255
  agentio gmail profile add --profile personal
206
256
 
@@ -208,90 +258,71 @@ agentio gmail profile add --profile personal
208
258
  agentio gmail list --profile work
209
259
  ```
210
260
 
211
- ## Claude Code Integration
212
-
213
- agentio provides plugins for [Claude Code](https://claude.ai/download) with skills for Gmail, Telegram, Google Chat, JIRA, and RSS operations.
214
-
215
- ### Install Marketplaces and Plugins
216
-
217
- ```bash
218
- # Add a marketplace (auto-detected from URL)
219
- agentio claude install https://github.com/plosson/agentio
220
-
221
- # Install a plugin (auto-detected from name@marketplace format)
222
- agentio claude install agentio-gmail@agentio
223
-
224
- # Install all from agentio.json
225
- agentio claude install
261
+ ## Workflow Examples
262
+
263
+ The [`examples/`](./examples) folder contains ready-to-use workflows. Here's how it works:
264
+
265
+ ### Daily Email Briefing → Slack
266
+
267
+ ```yaml
268
+ name: Daily Briefing
269
+ on:
270
+ schedule:
271
+ - cron: '0 7 * * 1-5' # Weekdays at 7 AM UTC
272
+
273
+ jobs:
274
+ briefing:
275
+ runs-on: ubuntu-latest
276
+ env:
277
+ AGENTIO_CONFIG: ${{ secrets.AGENTIO_CONFIG }}
278
+ AGENTIO_KEY: ${{ secrets.AGENTIO_KEY }}
279
+ CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
280
+ steps:
281
+ - uses: actions/checkout@v4
282
+ - run: curl -LsSf https://agentio.work/install | sh
283
+ - run: npm install -g @anthropic-ai/claude-code
284
+ - run: agentio config import && agentio claude install
285
+ - run: claude -p "$(cat prompt.md)" --max-turns 30 --dangerously-skip-permissions
226
286
  ```
227
287
 
228
- ### Manage Plugins
229
-
230
- ```bash
231
- # List marketplaces and plugins from agentio.json
232
- agentio claude list
288
+ The magic is in `prompt.md` — Claude reads your emails via the agentio plugin, analyzes them, and posts a summary to Slack:
233
289
 
234
- # Update marketplaces
235
- agentio claude update
236
- agentio claude update https://github.com/plosson/agentio
290
+ ```markdown
291
+ # Daily Email Briefing
237
292
 
238
- # Remove a marketplace or plugin
239
- agentio claude remove https://github.com/plosson/agentio
240
- agentio claude remove agentio-gmail@agentio
293
+ 1. Fetch unread emails from the last 24 hours using agentio-gmail
294
+ 2. Categorize by urgency: Urgent / Important / FYI
295
+ 3. Generate a morning briefing with one-line summaries
296
+ 4. Send to Slack using agentio-slack
241
297
  ```
242
298
 
243
- ### agentio.json
244
-
245
- Projects can define marketplaces and plugins in an `agentio.json` file:
299
+ See [`examples/daily-briefing/`](./examples/daily-briefing) for the complete working example.
246
300
 
247
- ```json
248
- {
249
- "marketplaces": [
250
- "https://github.com/plosson/agentio"
251
- ],
252
- "plugins": [
253
- "agentio-gmail@agentio",
254
- "agentio-rss@agentio"
255
- ]
256
- }
257
- ```
258
-
259
- ## Design
260
-
261
- agentio is designed for LLM consumption:
262
-
263
- - **Structured output**: Human-readable text output optimized for LLM parsing
264
- - **Clear errors**: Error messages written to stderr with suggestions
265
- - **Stdin support**: Pipe content to commands that accept body text
266
- - **Multi-profile**: Manage multiple accounts per service
267
-
268
- ## Configuration
269
-
270
- Configuration is stored in `~/.config/agentio/`:
271
-
272
- - `config.json` - Profile names and defaults
273
- - `tokens.enc` - Encrypted credentials (AES-256-GCM)
301
+ ## Claude Code Integration
274
302
 
275
- ### Export/Import
303
+ agentio includes skills for [Claude Code](https://claude.ai/download) that let Claude directly read your email, post to Slack, or query JIRA during conversations.
276
304
 
277
- Transfer configuration between machines:
305
+ **Install skills:**
278
306
 
279
307
  ```bash
280
- # Export configuration (generates encryption key)
281
- agentio config export
308
+ agentio claude install https://github.com/plosson/agentio # marketplace
309
+ agentio claude install agentio-gmail@agentio # Gmail skill
310
+ agentio claude install agentio-jira@agentio # JIRA skill
311
+ ```
282
312
 
283
- # Export with custom output file
284
- agentio config export --output backup.config
313
+ **Then in Claude Code:**
285
314
 
286
- # Import on another machine
287
- agentio config import agentio.config --key <encryption-key>
315
+ > "Summarize my unread emails and post a summary to Slack"
288
316
 
289
- # Or use environment variable
290
- AGENTIO_KEY=<key> agentio config import agentio.config
317
+ Claude uses the installed skills to fetch emails and send the summary — no manual commands needed.
291
318
 
292
- # Merge with existing config instead of replacing
293
- agentio config import agentio.config --key <key> --merge
294
- ```
319
+ ## Design Principles
320
+
321
+ - **Structured output** — Text output optimized for LLM parsing
322
+ - **Stdin support** — Pipe content to commands (`echo "msg" | agentio slack send`)
323
+ - **Single config export** — One encrypted file + key = full portability
324
+ - **Multi-profile** — Multiple accounts per service
325
+ - **No runtime dependencies** — Single binary, runs anywhere
295
326
 
296
327
  ## License
297
328
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plosson/agentio",
3
- "version": "0.1.27",
3
+ "version": "0.1.28",
4
4
  "description": "CLI for LLM agents to interact with communication and tracking services",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -9,11 +9,11 @@ const ATLASSIAN_RESOURCES_URL = 'https://api.atlassian.com/oauth/token/accessibl
9
9
  const JIRA_SCOPES = [
10
10
  'read:jira-work', // Read projects, issues
11
11
  'write:jira-work', // Add comments, change status
12
+ 'read:me', // Read current user info
12
13
  'offline_access', // Get refresh tokens
13
14
  ];
14
15
 
15
- const PORT_RANGE_START = 3000;
16
- const PORT_RANGE_END = 3010;
16
+ const OAUTH_PORT = 9999;
17
17
 
18
18
  export interface JiraOAuthResult {
19
19
  accessToken: string;
@@ -31,23 +31,6 @@ export interface AtlassianSite {
31
31
  avatarUrl?: string;
32
32
  }
33
33
 
34
- async function findAvailablePort(): Promise<number> {
35
- for (let port = PORT_RANGE_START; port <= PORT_RANGE_END; port++) {
36
- try {
37
- await new Promise<void>((resolve, reject) => {
38
- const server = createServer();
39
- server.listen(port, () => {
40
- server.close(() => resolve());
41
- });
42
- server.on('error', reject);
43
- });
44
- return port;
45
- } catch {
46
- continue;
47
- }
48
- }
49
- throw new Error(`No available port found in range ${PORT_RANGE_START}-${PORT_RANGE_END}`);
50
- }
51
34
 
52
35
  async function exchangeCodeForTokens(
53
36
  code: string,
@@ -130,8 +113,7 @@ export async function refreshJiraToken(
130
113
  export async function performJiraOAuthFlow(
131
114
  selectSite?: (sites: AtlassianSite[]) => Promise<AtlassianSite>
132
115
  ): Promise<JiraOAuthResult> {
133
- const port = await findAvailablePort();
134
- const redirectUri = `http://localhost:${port}/callback`;
116
+ const redirectUri = `http://localhost:${OAUTH_PORT}/callback`;
135
117
 
136
118
  const state = Math.random().toString(36).substring(2);
137
119
  const authUrl = new URL(ATLASSIAN_AUTH_URL);
@@ -152,7 +134,7 @@ export async function performJiraOAuthFlow(
152
134
  }, 5 * 60 * 1000);
153
135
 
154
136
  server = createServer(async (req, res) => {
155
- const url = new URL(req.url || '', `http://localhost:${port}`);
137
+ const url = new URL(req.url || '', `http://localhost:${OAUTH_PORT}`);
156
138
 
157
139
  if (url.pathname !== '/callback') {
158
140
  res.writeHead(404);
@@ -230,7 +212,7 @@ export async function performJiraOAuthFlow(
230
212
  }
231
213
  });
232
214
 
233
- server.listen(port, () => {
215
+ server.listen(OAUTH_PORT, () => {
234
216
  console.error(`\nOpening browser for Atlassian authorization...`);
235
217
  console.error(`If browser doesn't open, visit:\n${authUrl.toString()}\n`);
236
218
 
@@ -112,8 +112,8 @@ export function registerConfigCommands(program: Command): void {
112
112
 
113
113
  config
114
114
  .command('import')
115
- .description('Import configuration and credentials from an encrypted file')
116
- .argument('<file>', 'Path to the encrypted configuration file')
115
+ .description('Import configuration and credentials from an encrypted file or environment variables')
116
+ .argument('[file]', 'Path to the encrypted configuration file (optional if AGENTIO_CONFIG env var is set)')
117
117
  .option('--key <key>', 'Encryption key (64 hex characters). Falls back to AGENTIO_KEY env var')
118
118
  .option('--merge', 'Merge with existing configuration instead of replacing')
119
119
  .action(async (file, options) => {
@@ -137,26 +137,47 @@ export function registerConfigCommands(program: Command): void {
137
137
  );
138
138
  }
139
139
 
140
- // Check file exists
141
- const filePath = file.startsWith('/') ? file : join(process.cwd(), file);
142
- if (!existsSync(filePath)) {
140
+ let encryptedContent: string;
141
+
142
+ if (file) {
143
+ // Read from file
144
+ const filePath = file.startsWith('/') ? file : join(process.cwd(), file);
145
+ if (!existsSync(filePath)) {
146
+ throw new CliError(
147
+ 'NOT_FOUND',
148
+ `File not found: ${filePath}`,
149
+ 'Provide a valid path to the exported configuration file'
150
+ );
151
+ }
152
+ encryptedContent = await readFile(filePath, 'utf-8');
153
+ } else if (process.env.AGENTIO_CONFIG) {
154
+ // Decode from AGENTIO_CONFIG environment variable (base64-encoded)
155
+ try {
156
+ encryptedContent = Buffer.from(process.env.AGENTIO_CONFIG, 'base64').toString('utf-8');
157
+ } catch {
158
+ throw new CliError(
159
+ 'INVALID_PARAMS',
160
+ 'Failed to decode AGENTIO_CONFIG',
161
+ 'AGENTIO_CONFIG must be a valid base64-encoded string'
162
+ );
163
+ }
164
+ } else {
143
165
  throw new CliError(
144
- 'NOT_FOUND',
145
- `File not found: ${filePath}`,
146
- 'Provide a valid path to the exported configuration file'
166
+ 'INVALID_PARAMS',
167
+ 'No configuration source provided',
168
+ 'Provide a file path or set AGENTIO_CONFIG environment variable (base64-encoded)'
147
169
  );
148
170
  }
149
171
 
150
- // Read and parse the encrypted file
151
- const encryptedContent = await readFile(filePath, 'utf-8');
172
+ // Parse the encrypted content
152
173
  let encrypted: { iv: string; tag: string; data: string };
153
174
  try {
154
175
  encrypted = JSON.parse(encryptedContent);
155
176
  } catch {
156
177
  throw new CliError(
157
178
  'INVALID_PARAMS',
158
- 'Invalid file format',
159
- 'The file does not appear to be a valid agentio export file'
179
+ 'Invalid configuration format',
180
+ 'The configuration does not appear to be a valid agentio export'
160
181
  );
161
182
  }
162
183