@plosson/agentio 0.1.20 → 0.1.22

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
@@ -192,44 +192,49 @@ agentio gmail list --profile work
192
192
 
193
193
  ## Claude Code Integration
194
194
 
195
- agentio provides a plugin for [Claude Code](https://claude.com/claude-code) with skills for Gmail, Telegram, and Google Chat operations.
195
+ agentio provides plugins for [Claude Code](https://claude.ai/download) with skills for Gmail, Telegram, and Google Chat operations.
196
196
 
197
- ### Add the Marketplace
197
+ ### Install the Plugin
198
198
 
199
199
  ```bash
200
- /plugin marketplace add plosson/agentio
201
- ```
200
+ # Install from GitHub
201
+ agentio claude plugin install plosson/agentio
202
202
 
203
- ### Install the Plugin
203
+ # Or install from a full GitHub URL
204
+ agentio claude plugin install https://github.com/plosson/agentio
204
205
 
205
- ```bash
206
- /plugin install agentio@agentio
206
+ # Install to a specific directory
207
+ agentio claude plugin install plosson/agentio -d ~/myproject
208
+
209
+ # Install only skills (skip commands and hooks)
210
+ agentio claude plugin install plosson/agentio --skills
211
+
212
+ # Force reinstall if already exists
213
+ agentio claude plugin install plosson/agentio -f
207
214
  ```
208
215
 
209
216
  Once installed, Claude Code can use the agentio CLI skills to help you manage emails, send Telegram messages, and more.
210
217
 
211
- ### Install Skills Directly
212
-
213
- You can also install skills directly without the plugin system:
218
+ ### Manage Plugins
214
219
 
215
220
  ```bash
216
- # List available skills
217
- agentio skill list
221
+ # List installed plugins
222
+ agentio claude plugin list
218
223
 
219
- # Install all skills to current directory
220
- agentio skill install
224
+ # Remove a plugin
225
+ agentio claude plugin remove agentio
226
+ ```
221
227
 
222
- # Install a specific skill
223
- agentio skill install agentio-gmail
228
+ ### Install from agentio.json
224
229
 
225
- # Install to a specific directory
226
- agentio skill install -d ~/myproject
230
+ If your project has an `agentio.json` file listing plugins, you can install all of them at once:
227
231
 
228
- # Skip confirmation prompts
229
- agentio skill install -y
232
+ ```bash
233
+ # Install all plugins from agentio.json in current directory
234
+ agentio claude plugin install
230
235
  ```
231
236
 
232
- Skills are installed to `.claude/skills/` in the target directory.
237
+ Plugins are installed to `.claude/` in the target directory (skills, commands, and hooks subdirectories).
233
238
 
234
239
  ## Design
235
240
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plosson/agentio",
3
- "version": "0.1.20",
3
+ "version": "0.1.22",
4
4
  "description": "CLI for LLM agents to interact with communication and tracking services",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -29,8 +29,10 @@ export function registerClaudeCommands(program: Command): void {
29
29
  .option('--skills', 'Install only skills')
30
30
  .option('--commands', 'Install only commands')
31
31
  .option('--hooks', 'Install only hooks')
32
+ .option('--agents', 'Install only agents')
32
33
  .option('-f, --force', 'Force reinstall if already exists')
33
34
  .option('-d, --dir <path>', 'Target directory (default: current directory)')
35
+ .option('-v, --verbose', 'Show detailed installation logs')
34
36
  .action(async (source, options) => {
35
37
  try {
36
38
  const targetDir = options.dir ? path.resolve(options.dir) : process.cwd();
@@ -48,8 +50,10 @@ export function registerClaudeCommands(program: Command): void {
48
50
  skills: options.skills,
49
51
  commands: options.commands,
50
52
  hooks: options.hooks,
53
+ agents: options.agents,
51
54
  force: options.force,
52
55
  targetDir,
56
+ verbose: options.verbose,
53
57
  });
54
58
 
55
59
  console.log(`\nInstalled: ${result.manifest.name} v${result.manifest.version}`);
@@ -91,8 +95,10 @@ export function registerClaudeCommands(program: Command): void {
91
95
  commands:
92
96
  !entry.components || entry.components.includes('commands'),
93
97
  hooks: !entry.components || entry.components.includes('hooks'),
98
+ agents: !entry.components || entry.components.includes('agents'),
94
99
  force: options.force,
95
100
  targetDir,
101
+ verbose: options.verbose,
96
102
  };
97
103
 
98
104
  try {
@@ -101,9 +101,10 @@ function discoverComponents(
101
101
  skills: [],
102
102
  commands: [],
103
103
  hooks: [],
104
+ agents: [],
104
105
  };
105
106
 
106
- const componentTypes: ComponentType[] = ['skills', 'commands', 'hooks'];
107
+ const componentTypes: ComponentType[] = ['skills', 'commands', 'hooks', 'agents'];
107
108
 
108
109
  for (const type of componentTypes) {
109
110
  const typePath = path.join(basePath, type);
@@ -144,12 +145,13 @@ function determineComponentsToInstall(
144
145
  discovered: DiscoveredComponents
145
146
  ): DiscoveredComponents {
146
147
  // If no specific flags, install all
147
- const installAll = !options.skills && !options.commands && !options.hooks;
148
+ const installAll = !options.skills && !options.commands && !options.hooks && !options.agents;
148
149
 
149
150
  return {
150
151
  skills: installAll || options.skills ? discovered.skills : [],
151
152
  commands: installAll || options.commands ? discovered.commands : [],
152
153
  hooks: installAll || options.hooks ? discovered.hooks : [],
154
+ agents: installAll || options.agents ? discovered.agents : [],
153
155
  };
154
156
  }
155
157
 
@@ -159,13 +161,14 @@ function determineComponentsToInstall(
159
161
  function getInstalledComponentTypes(
160
162
  options: PluginInstallOptions
161
163
  ): ComponentType[] | undefined {
162
- const installAll = !options.skills && !options.commands && !options.hooks;
164
+ const installAll = !options.skills && !options.commands && !options.hooks && !options.agents;
163
165
  if (installAll) return undefined; // Default: all
164
166
 
165
167
  const types: ComponentType[] = [];
166
168
  if (options.skills) types.push('skills');
167
169
  if (options.commands) types.push('commands');
168
170
  if (options.hooks) types.push('hooks');
171
+ if (options.agents) types.push('agents');
169
172
  return types;
170
173
  }
171
174
 
@@ -177,23 +180,86 @@ export async function installPlugin(
177
180
  options: PluginInstallOptions
178
181
  ): Promise<InstallResult> {
179
182
  const parsed = parseSource(source);
183
+ const verbose = options.verbose ?? false;
184
+
185
+ if (verbose) {
186
+ console.error(`\n[verbose] Parsed source:`);
187
+ console.error(` Owner: ${parsed.owner}`);
188
+ console.error(` Repo: ${parsed.repo}`);
189
+ console.error(` Branch: ${parsed.branch ?? '(default)'}`);
190
+ console.error(` Path: ${parsed.path ?? '(root)'}`);
191
+ console.error(` Clone URL: ${buildGitCloneUrl(parsed)}`);
192
+ }
180
193
 
181
194
  // Clone repo to temp directory
195
+ if (verbose) {
196
+ console.error(`\n[verbose] Cloning repository...`);
197
+ }
182
198
  const repoDir = cloneRepo(parsed);
199
+ if (verbose) {
200
+ console.error(`[verbose] Cloned to: ${repoDir}`);
201
+ }
183
202
 
184
203
  try {
185
204
  // Read manifest from cloned repo
186
205
  const manifest = readPluginManifest(repoDir, parsed);
187
206
 
207
+ if (verbose) {
208
+ console.error(`\n[verbose] Plugin manifest:`);
209
+ console.error(` Name: ${manifest.name}`);
210
+ console.error(` Version: ${manifest.version}`);
211
+ if (manifest.description) {
212
+ console.error(` Description: ${manifest.description}`);
213
+ }
214
+ }
215
+
188
216
  // Discover available components
189
217
  const discovered = discoverComponents(repoDir, parsed);
190
218
 
219
+ if (verbose) {
220
+ const totalDiscovered = discovered.skills.length + discovered.commands.length + discovered.hooks.length + discovered.agents.length;
221
+ console.error(`\n[verbose] Discovered ${totalDiscovered} component(s):`);
222
+ if (discovered.skills.length > 0) {
223
+ console.error(` Skills (${discovered.skills.length}): ${discovered.skills.join(', ')}`);
224
+ }
225
+ if (discovered.commands.length > 0) {
226
+ console.error(` Commands (${discovered.commands.length}): ${discovered.commands.join(', ')}`);
227
+ }
228
+ if (discovered.hooks.length > 0) {
229
+ console.error(` Hooks (${discovered.hooks.length}): ${discovered.hooks.join(', ')}`);
230
+ }
231
+ if (discovered.agents.length > 0) {
232
+ console.error(` Agents (${discovered.agents.length}): ${discovered.agents.join(', ')}`);
233
+ }
234
+ }
235
+
191
236
  // Determine what to install
192
237
  const toInstall = determineComponentsToInstall(options, discovered);
193
238
 
239
+ if (verbose) {
240
+ const totalToInstall = toInstall.skills.length + toInstall.commands.length + toInstall.hooks.length + toInstall.agents.length;
241
+ console.error(`\n[verbose] Installing ${totalToInstall} component(s):`);
242
+ if (toInstall.skills.length > 0) {
243
+ console.error(` Skills: ${toInstall.skills.join(', ')}`);
244
+ }
245
+ if (toInstall.commands.length > 0) {
246
+ console.error(` Commands: ${toInstall.commands.join(', ')}`);
247
+ }
248
+ if (toInstall.hooks.length > 0) {
249
+ console.error(` Hooks: ${toInstall.hooks.join(', ')}`);
250
+ }
251
+ if (toInstall.agents.length > 0) {
252
+ console.error(` Agents: ${toInstall.agents.join(', ')}`);
253
+ }
254
+ }
255
+
194
256
  const targetDir = options.targetDir || process.cwd();
195
257
  const installed: InstalledComponent[] = [];
196
258
 
259
+ if (verbose) {
260
+ console.error(`\n[verbose] Target directory: ${targetDir}`);
261
+ }
262
+
197
263
  // Install skills
198
264
  for (const skillName of toInstall.skills) {
199
265
  const destPath = path.join(targetDir, '.claude', 'skills', skillName);
@@ -201,14 +267,23 @@ export async function installPlugin(
201
267
  if (fs.existsSync(destPath)) {
202
268
  if (!options.force) {
203
269
  console.error(` Skipping existing skill: ${skillName}`);
270
+ if (verbose) {
271
+ console.error(` [verbose] Path: ${destPath}`);
272
+ }
204
273
  continue;
205
274
  }
275
+ if (verbose) {
276
+ console.error(` [verbose] Removing existing: ${destPath}`);
277
+ }
206
278
  fs.rmSync(destPath, { recursive: true });
207
279
  }
208
280
 
209
281
  copyComponent(repoDir, parsed, 'skills', skillName, targetDir);
210
282
  installed.push({ name: skillName, type: 'skills', path: destPath });
211
283
  console.error(` Installed skill: ${skillName}`);
284
+ if (verbose) {
285
+ console.error(` [verbose] Path: ${destPath}`);
286
+ }
212
287
  }
213
288
 
214
289
  // Install commands
@@ -218,14 +293,23 @@ export async function installPlugin(
218
293
  if (fs.existsSync(destPath)) {
219
294
  if (!options.force) {
220
295
  console.error(` Skipping existing command: ${cmdName}`);
296
+ if (verbose) {
297
+ console.error(` [verbose] Path: ${destPath}`);
298
+ }
221
299
  continue;
222
300
  }
301
+ if (verbose) {
302
+ console.error(` [verbose] Removing existing: ${destPath}`);
303
+ }
223
304
  fs.rmSync(destPath, { recursive: true });
224
305
  }
225
306
 
226
307
  copyComponent(repoDir, parsed, 'commands', cmdName, targetDir);
227
308
  installed.push({ name: cmdName, type: 'commands', path: destPath });
228
309
  console.error(` Installed command: ${cmdName}`);
310
+ if (verbose) {
311
+ console.error(` [verbose] Path: ${destPath}`);
312
+ }
229
313
  }
230
314
 
231
315
  // Install hooks
@@ -235,17 +319,55 @@ export async function installPlugin(
235
319
  if (fs.existsSync(destPath)) {
236
320
  if (!options.force) {
237
321
  console.error(` Skipping existing hook: ${hookName}`);
322
+ if (verbose) {
323
+ console.error(` [verbose] Path: ${destPath}`);
324
+ }
238
325
  continue;
239
326
  }
327
+ if (verbose) {
328
+ console.error(` [verbose] Removing existing: ${destPath}`);
329
+ }
240
330
  fs.rmSync(destPath, { recursive: true });
241
331
  }
242
332
 
243
333
  copyComponent(repoDir, parsed, 'hooks', hookName, targetDir);
244
334
  installed.push({ name: hookName, type: 'hooks', path: destPath });
245
335
  console.error(` Installed hook: ${hookName}`);
336
+ if (verbose) {
337
+ console.error(` [verbose] Path: ${destPath}`);
338
+ }
339
+ }
340
+
341
+ // Install agents
342
+ for (const agentName of toInstall.agents) {
343
+ const destPath = path.join(targetDir, '.claude', 'agents', agentName);
344
+
345
+ if (fs.existsSync(destPath)) {
346
+ if (!options.force) {
347
+ console.error(` Skipping existing agent: ${agentName}`);
348
+ if (verbose) {
349
+ console.error(` [verbose] Path: ${destPath}`);
350
+ }
351
+ continue;
352
+ }
353
+ if (verbose) {
354
+ console.error(` [verbose] Removing existing: ${destPath}`);
355
+ }
356
+ fs.rmSync(destPath, { recursive: true });
357
+ }
358
+
359
+ copyComponent(repoDir, parsed, 'agents', agentName, targetDir);
360
+ installed.push({ name: agentName, type: 'agents', path: destPath });
361
+ console.error(` Installed agent: ${agentName}`);
362
+ if (verbose) {
363
+ console.error(` [verbose] Path: ${destPath}`);
364
+ }
246
365
  }
247
366
 
248
367
  // Update agentio.json
368
+ if (verbose) {
369
+ console.error(`\n[verbose] Updating agentio.json`);
370
+ }
249
371
  addPlugin(targetDir, manifest.name, {
250
372
  source: source,
251
373
  version: manifest.version,
@@ -260,6 +382,9 @@ export async function installPlugin(
260
382
  };
261
383
  } finally {
262
384
  // Always cleanup temp directory
385
+ if (verbose) {
386
+ console.error(`\n[verbose] Cleaning up temp directory: ${repoDir}`);
387
+ }
263
388
  cleanupTempDir(repoDir);
264
389
  }
265
390
  }
@@ -14,13 +14,14 @@ export interface PluginManifest {
14
14
  }
15
15
 
16
16
  // Component types that can be installed
17
- export type ComponentType = 'skills' | 'commands' | 'hooks';
17
+ export type ComponentType = 'skills' | 'commands' | 'hooks' | 'agents';
18
18
 
19
19
  // Discovered components from filesystem
20
20
  export interface DiscoveredComponents {
21
21
  skills: string[];
22
22
  commands: string[];
23
23
  hooks: string[];
24
+ agents: string[];
24
25
  }
25
26
 
26
27
  // Installation options
@@ -28,8 +29,10 @@ export interface PluginInstallOptions {
28
29
  skills?: boolean;
29
30
  commands?: boolean;
30
31
  hooks?: boolean;
32
+ agents?: boolean;
31
33
  force?: boolean;
32
34
  targetDir?: string;
35
+ verbose?: boolean;
33
36
  }
34
37
 
35
38
  // Single installed component record