@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 +26 -21
- package/package.json +1 -1
- package/src/commands/claude.ts +6 -0
- package/src/services/claude-plugin/installer.ts +128 -3
- package/src/types/claude-plugin.ts +4 -1
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
|
|
195
|
+
agentio provides plugins for [Claude Code](https://claude.ai/download) with skills for Gmail, Telegram, and Google Chat operations.
|
|
196
196
|
|
|
197
|
-
###
|
|
197
|
+
### Install the Plugin
|
|
198
198
|
|
|
199
199
|
```bash
|
|
200
|
-
|
|
201
|
-
|
|
200
|
+
# Install from GitHub
|
|
201
|
+
agentio claude plugin install plosson/agentio
|
|
202
202
|
|
|
203
|
-
|
|
203
|
+
# Or install from a full GitHub URL
|
|
204
|
+
agentio claude plugin install https://github.com/plosson/agentio
|
|
204
205
|
|
|
205
|
-
|
|
206
|
-
|
|
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
|
-
###
|
|
212
|
-
|
|
213
|
-
You can also install skills directly without the plugin system:
|
|
218
|
+
### Manage Plugins
|
|
214
219
|
|
|
215
220
|
```bash
|
|
216
|
-
# List
|
|
217
|
-
agentio
|
|
221
|
+
# List installed plugins
|
|
222
|
+
agentio claude plugin list
|
|
218
223
|
|
|
219
|
-
#
|
|
220
|
-
agentio
|
|
224
|
+
# Remove a plugin
|
|
225
|
+
agentio claude plugin remove agentio
|
|
226
|
+
```
|
|
221
227
|
|
|
222
|
-
|
|
223
|
-
agentio skill install agentio-gmail
|
|
228
|
+
### Install from agentio.json
|
|
224
229
|
|
|
225
|
-
|
|
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
|
-
|
|
229
|
-
agentio
|
|
232
|
+
```bash
|
|
233
|
+
# Install all plugins from agentio.json in current directory
|
|
234
|
+
agentio claude plugin install
|
|
230
235
|
```
|
|
231
236
|
|
|
232
|
-
|
|
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
package/src/commands/claude.ts
CHANGED
|
@@ -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
|