guolei-agents 1.0.2
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/bin/agents.js +19 -0
- package/build.mjs +47 -0
- package/dist/agents.js +19 -0
- package/dist/index.js +577 -0
- package/dist/index.js.map +7 -0
- package/dist/templates/default-agent.md +35 -0
- package/package.json +38 -0
- package/src/commands/add.ts +44 -0
- package/src/commands/check.ts +11 -0
- package/src/commands/find.ts +25 -0
- package/src/commands/init.ts +84 -0
- package/src/commands/list.ts +42 -0
- package/src/commands/remove.ts +42 -0
- package/src/commands/update.ts +12 -0
- package/src/core/discover.ts +129 -0
- package/src/core/installer.ts +169 -0
- package/src/core/parser.ts +55 -0
- package/src/index.ts +64 -0
- package/src/types/index.ts +78 -0
- package/src/utils/filesystem.ts +177 -0
- package/src/utils/logger.ts +13 -0
- package/templates/default-agent.md +35 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { join, basename } from 'path';
|
|
2
|
+
import { existsSync, readdirSync, readFileSync, mkdirSync, copyFileSync, symlinkSync, rmSync } from 'fs';
|
|
3
|
+
import { tmpdir, homedir } from 'os';
|
|
4
|
+
import { mkdtempSync, rmSync as rmSyncFs } from 'fs';
|
|
5
|
+
import { parseAgentFile } from './parser.js';
|
|
6
|
+
import { discoverFromDirectory } from './discover.js';
|
|
7
|
+
import { ensureDir, getPlatformPaths, isDirectory, findFiles } from '../utils/filesystem.js';
|
|
8
|
+
import { logger } from '../utils/logger.js';
|
|
9
|
+
import type { AgentPlatform, AgentFile, InstallOptions } from '../types/index.js';
|
|
10
|
+
|
|
11
|
+
export async function installAgent(options: InstallOptions): Promise<void> {
|
|
12
|
+
const { source, global, platforms, agentName, copy } = options;
|
|
13
|
+
|
|
14
|
+
logger.info(`Installing agent from: ${source}`);
|
|
15
|
+
|
|
16
|
+
const tempDir = await fetchSource(source);
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
const agents = await discoverFromDirectory(tempDir);
|
|
20
|
+
|
|
21
|
+
if (agents.length === 0) {
|
|
22
|
+
throw new Error('No agents found in the source');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
for (const platform of platforms) {
|
|
26
|
+
const targetPaths = getPlatformPaths(platform, global);
|
|
27
|
+
|
|
28
|
+
for (const targetPath of targetPaths) {
|
|
29
|
+
ensureDir(targetPath);
|
|
30
|
+
|
|
31
|
+
for (const agentFile of agents) {
|
|
32
|
+
const name = agentName || agentFile.agent.name || basename(agentFile.path, '.md');
|
|
33
|
+
const finalPath = join(targetPath, `${name}.md`);
|
|
34
|
+
|
|
35
|
+
if (existsSync(finalPath) && !options.yes) {
|
|
36
|
+
logger.warn(`Agent "${name}" already exists at ${finalPath}`);
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (copy) {
|
|
41
|
+
const sourcePath = agentFile.path;
|
|
42
|
+
if (isDirectory(sourcePath)) {
|
|
43
|
+
copyDirectory(sourcePath, join(targetPath, name));
|
|
44
|
+
} else {
|
|
45
|
+
copyFileSync(sourcePath, finalPath);
|
|
46
|
+
}
|
|
47
|
+
logger.success(`Copied agent "${name}" to ${finalPath}`);
|
|
48
|
+
} else {
|
|
49
|
+
const sourceDir = tempDir;
|
|
50
|
+
try {
|
|
51
|
+
symlinkSync(sourceDir, finalPath, 'dir');
|
|
52
|
+
logger.success(`Symlinked agent "${name}" to ${finalPath}`);
|
|
53
|
+
} catch (err) {
|
|
54
|
+
logger.warn(`Failed to create symlink, copying instead: ${err}`);
|
|
55
|
+
copyDirectory(sourceDir, join(targetPath, name));
|
|
56
|
+
logger.success(`Copied agent "${name}" to ${targetPath}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
} finally {
|
|
63
|
+
if (existsSync(tempDir) && tempDir.startsWith(tmpdir())) {
|
|
64
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function fetchSource(source: string): Promise<string> {
|
|
70
|
+
if (source.startsWith('.') || source.startsWith('/') || /^[a-zA-Z]:\\/.test(source)) {
|
|
71
|
+
return source;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const degit = await import('degit');
|
|
75
|
+
const tempDir = mkdtempSync(join(tmpdir(), 'npx-agents-'));
|
|
76
|
+
|
|
77
|
+
const parts = source.split('/');
|
|
78
|
+
let owner = parts[0];
|
|
79
|
+
let repo = parts[1]?.replace(/#.+$/, '') || '';
|
|
80
|
+
let ref = '';
|
|
81
|
+
|
|
82
|
+
if (source.includes('#')) {
|
|
83
|
+
const [repoPart, refPart] = source.split('#');
|
|
84
|
+
repo = repoPart.split('/')[1];
|
|
85
|
+
ref = refPart;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
const target = ref ? `${owner}/${repo}#${ref}` : `${owner}/${repo}`;
|
|
90
|
+
await degit.default(target).clone(tempDir);
|
|
91
|
+
return tempDir;
|
|
92
|
+
} catch (err) {
|
|
93
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
94
|
+
throw new Error(`Failed to fetch from ${source}: ${err}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function copyDirectory(source: string, target: string): void {
|
|
99
|
+
ensureDir(target);
|
|
100
|
+
const files = readdirSync(source);
|
|
101
|
+
for (const file of files) {
|
|
102
|
+
const srcPath = join(source, file);
|
|
103
|
+
const destPath = join(target, file);
|
|
104
|
+
if (isDirectory(srcPath)) {
|
|
105
|
+
copyDirectory(srcPath, destPath);
|
|
106
|
+
} else {
|
|
107
|
+
copyFileSync(srcPath, destPath);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function listInstalledAgents(platform: AgentPlatform, global: boolean): AgentFile[] {
|
|
113
|
+
const agents: AgentFile[] = [];
|
|
114
|
+
const paths = getPlatformPaths(platform, global);
|
|
115
|
+
|
|
116
|
+
for (const path of paths) {
|
|
117
|
+
if (!existsSync(path)) continue;
|
|
118
|
+
|
|
119
|
+
const mdFiles = findFiles(path, /\.md$/);
|
|
120
|
+
for (const file of mdFiles) {
|
|
121
|
+
try {
|
|
122
|
+
const content = readFileSync(file, 'utf-8');
|
|
123
|
+
const agentFile = parseAgentFile(content, file);
|
|
124
|
+
agents.push(agentFile);
|
|
125
|
+
} catch (err) {
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return agents;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export function removeAgent(name: string, platform: AgentPlatform, global: boolean): boolean {
|
|
135
|
+
const paths = getPlatformPaths(platform, global);
|
|
136
|
+
|
|
137
|
+
for (const path of paths) {
|
|
138
|
+
const agentPath = join(path, `${name}.md`);
|
|
139
|
+
if (existsSync(agentPath)) {
|
|
140
|
+
rmSync(agentPath, { recursive: true, force: true });
|
|
141
|
+
logger.success(`Removed agent "${name}" from ${path}`);
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (existsSync(path)) {
|
|
146
|
+
const entries = readdirSync(path);
|
|
147
|
+
for (const entry of entries) {
|
|
148
|
+
const entryPath = join(path, entry);
|
|
149
|
+
const linkTarget = existsSync(entryPath) ? entryPath : null;
|
|
150
|
+
if (linkTarget && readlinkCheck(entryPath, name)) {
|
|
151
|
+
rmSync(entryPath, { recursive: true, force: true });
|
|
152
|
+
logger.success(`Removed agent "${name}" from ${path}`);
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function readlinkCheck(path: string, name: string): boolean {
|
|
163
|
+
try {
|
|
164
|
+
const stat = require('fs').lstatSync(path);
|
|
165
|
+
return stat.isSymbolicLink() && path.includes(name);
|
|
166
|
+
} catch {
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import matter from 'gray-matter';
|
|
2
|
+
import type { Agent, AgentFile } from '../types/index.js';
|
|
3
|
+
|
|
4
|
+
export function parseAgentFile(content: string, path: string): AgentFile {
|
|
5
|
+
const { data, content: body } = matter(content);
|
|
6
|
+
|
|
7
|
+
if (!data.description) {
|
|
8
|
+
throw new Error(`Agent at ${path} is missing required "description" field in frontmatter`);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const agent: Agent = {
|
|
12
|
+
description: data.description,
|
|
13
|
+
name: data.name,
|
|
14
|
+
mode: data.mode,
|
|
15
|
+
model: data.model,
|
|
16
|
+
temperature: data.temperature,
|
|
17
|
+
maxSteps: data.maxSteps,
|
|
18
|
+
color: data.color,
|
|
19
|
+
trigger: data.trigger,
|
|
20
|
+
hidden: data.hidden,
|
|
21
|
+
tools: data.tools,
|
|
22
|
+
permission: data.permission,
|
|
23
|
+
mcp: data.mcp,
|
|
24
|
+
version: data.version,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
path,
|
|
29
|
+
agent,
|
|
30
|
+
content: body.trim(),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function parseAgentFromString(content: string, filename: string): AgentFile {
|
|
35
|
+
const baseName = filename.replace(/\.md$/, '');
|
|
36
|
+
return parseAgentFile(content, baseName);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function validateAgent(agent: Agent): string[] {
|
|
40
|
+
const errors: string[] = [];
|
|
41
|
+
|
|
42
|
+
if (!agent.description) {
|
|
43
|
+
errors.push('Missing required "description" field');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (agent.temperature !== undefined && (agent.temperature < 0 || agent.temperature > 1)) {
|
|
47
|
+
errors.push('Temperature must be between 0 and 1');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (agent.mode && !['primary', 'subagent', 'all'].includes(agent.mode)) {
|
|
51
|
+
errors.push('Mode must be "primary", "subagent", or "all"');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return errors;
|
|
55
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import { addCommand } from './commands/add.js';
|
|
6
|
+
import { listCommand } from './commands/list.js';
|
|
7
|
+
import { removeCommand } from './commands/remove.js';
|
|
8
|
+
import { initCommand } from './commands/init.js';
|
|
9
|
+
import { findCommand } from './commands/find.js';
|
|
10
|
+
import { checkCommand } from './commands/check.js';
|
|
11
|
+
import { updateCommand } from './commands/update.js';
|
|
12
|
+
|
|
13
|
+
const program = new Command();
|
|
14
|
+
|
|
15
|
+
program
|
|
16
|
+
.name('agents')
|
|
17
|
+
.description('CLI for managing AI coding agents')
|
|
18
|
+
.version('1.0.0');
|
|
19
|
+
|
|
20
|
+
program
|
|
21
|
+
.command('add <source>')
|
|
22
|
+
.description('Install one or more agents from a GitHub repository or local path')
|
|
23
|
+
.option('-g, --global', 'Install to global directory', false)
|
|
24
|
+
.option('-a, --agent <agents...>', 'Target agent platform(s)')
|
|
25
|
+
.option('--agent-name <name>', 'Name for the installed agent')
|
|
26
|
+
.option('-y, --yes', 'Skip confirmation', false)
|
|
27
|
+
.option('--copy', 'Copy instead of symlink', false)
|
|
28
|
+
.action(addCommand);
|
|
29
|
+
|
|
30
|
+
program
|
|
31
|
+
.command('list')
|
|
32
|
+
.description('List installed agents')
|
|
33
|
+
.option('-g, --global', 'List only global agents')
|
|
34
|
+
.option('-a, --agent <agent>', 'Filter by platform')
|
|
35
|
+
.action(listCommand);
|
|
36
|
+
|
|
37
|
+
program
|
|
38
|
+
.command('remove <name>')
|
|
39
|
+
.description('Remove an installed agent')
|
|
40
|
+
.option('-g, --global', 'Remove from global directory')
|
|
41
|
+
.option('-a, --agent <agent>', 'Remove from specific platform')
|
|
42
|
+
.action(removeCommand);
|
|
43
|
+
|
|
44
|
+
program
|
|
45
|
+
.command('init [name]')
|
|
46
|
+
.description('Create a new agent definition template')
|
|
47
|
+
.action(initCommand);
|
|
48
|
+
|
|
49
|
+
program
|
|
50
|
+
.command('find [query]')
|
|
51
|
+
.description('Search for available agents')
|
|
52
|
+
.action(findCommand);
|
|
53
|
+
|
|
54
|
+
program
|
|
55
|
+
.command('check')
|
|
56
|
+
.description('Check for updates to installed agents')
|
|
57
|
+
.action(checkCommand);
|
|
58
|
+
|
|
59
|
+
program
|
|
60
|
+
.command('update')
|
|
61
|
+
.description('Update all installed agents to the latest version')
|
|
62
|
+
.action(updateCommand);
|
|
63
|
+
|
|
64
|
+
program.parse();
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
export interface Agent {
|
|
2
|
+
description: string;
|
|
3
|
+
name?: string;
|
|
4
|
+
mode?: 'primary' | 'subagent' | 'all';
|
|
5
|
+
model?: string;
|
|
6
|
+
temperature?: number;
|
|
7
|
+
maxSteps?: number;
|
|
8
|
+
color?: string;
|
|
9
|
+
trigger?: string;
|
|
10
|
+
hidden?: boolean;
|
|
11
|
+
tools?: {
|
|
12
|
+
read?: boolean;
|
|
13
|
+
write?: boolean;
|
|
14
|
+
edit?: boolean;
|
|
15
|
+
bash?: boolean | string;
|
|
16
|
+
glob?: boolean | string;
|
|
17
|
+
grep?: boolean | string;
|
|
18
|
+
task?: boolean;
|
|
19
|
+
skill?: boolean;
|
|
20
|
+
[key: string]: boolean | string | undefined;
|
|
21
|
+
};
|
|
22
|
+
permission?: {
|
|
23
|
+
bash?: Record<string, 'allow' | 'deny' | 'ask'>;
|
|
24
|
+
edit?: 'allow' | 'deny' | 'ask';
|
|
25
|
+
write?: 'allow' | 'deny' | 'ask';
|
|
26
|
+
skill?: Record<string, 'allow' | 'deny'>;
|
|
27
|
+
task?: Record<string, 'allow' | 'deny'>;
|
|
28
|
+
[key: string]: unknown;
|
|
29
|
+
};
|
|
30
|
+
mcp?: {
|
|
31
|
+
servers?: Array<{
|
|
32
|
+
name: string;
|
|
33
|
+
command: string;
|
|
34
|
+
args?: string[];
|
|
35
|
+
}>;
|
|
36
|
+
};
|
|
37
|
+
version?: string;
|
|
38
|
+
source?: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface AgentManifest {
|
|
42
|
+
agents: Agent[];
|
|
43
|
+
source: string;
|
|
44
|
+
ref?: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface AgentFile {
|
|
48
|
+
path: string;
|
|
49
|
+
agent: Agent;
|
|
50
|
+
content: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface Config {
|
|
54
|
+
global: boolean;
|
|
55
|
+
agents: Record<string, string[]>;
|
|
56
|
+
updates: {
|
|
57
|
+
check: 'daily' | 'weekly' | 'manual';
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export type AgentPlatform =
|
|
62
|
+
| 'opencode'
|
|
63
|
+
| 'claude-code'
|
|
64
|
+
| 'cursor'
|
|
65
|
+
| 'windsurf'
|
|
66
|
+
| 'cline'
|
|
67
|
+
| 'roo'
|
|
68
|
+
| 'codex'
|
|
69
|
+
| 'continue';
|
|
70
|
+
|
|
71
|
+
export interface InstallOptions {
|
|
72
|
+
source: string;
|
|
73
|
+
global: boolean;
|
|
74
|
+
platforms: AgentPlatform[];
|
|
75
|
+
agentName?: string;
|
|
76
|
+
copy: boolean;
|
|
77
|
+
yes: boolean;
|
|
78
|
+
}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync, symlinkSync, copyFileSync, rmSync, statSync } from 'fs';
|
|
2
|
+
import { join, dirname, basename } from 'path';
|
|
3
|
+
import { homedir } from 'os';
|
|
4
|
+
import type { AgentPlatform } from '../types/index.js';
|
|
5
|
+
|
|
6
|
+
export function ensureDir(dir: string): void {
|
|
7
|
+
if (!existsSync(dir)) {
|
|
8
|
+
mkdirSync(dir, { recursive: true });
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function readDir(dir: string): string[] {
|
|
13
|
+
if (!existsSync(dir)) {
|
|
14
|
+
return [];
|
|
15
|
+
}
|
|
16
|
+
return readdirSync(dir);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function readFile(path: string): string {
|
|
20
|
+
return readFileSync(path, 'utf-8');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function writeFile(path: string, content: string): void {
|
|
24
|
+
ensureDir(dirname(path));
|
|
25
|
+
writeFileSync(path, content, 'utf-8');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function isDirectory(path: string): boolean {
|
|
29
|
+
return existsSync(path) && statSync(path).isDirectory();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function isFile(path: string): boolean {
|
|
33
|
+
return existsSync(path) && statSync(path).isFile();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function getPlatformPaths(platform: AgentPlatform, global: boolean): string[] {
|
|
37
|
+
const home = homedir();
|
|
38
|
+
|
|
39
|
+
const paths: Record<AgentPlatform, { project: string[]; global: string[] }> = {
|
|
40
|
+
'opencode': {
|
|
41
|
+
project: ['.opencode/agents/'],
|
|
42
|
+
global: [join(home, '.config', 'opencode', 'agents')],
|
|
43
|
+
},
|
|
44
|
+
'claude-code': {
|
|
45
|
+
project: ['.claude/agents/'],
|
|
46
|
+
global: [join(home, '.claude', 'agents')],
|
|
47
|
+
},
|
|
48
|
+
'cursor': {
|
|
49
|
+
project: ['.cursor/agents/'],
|
|
50
|
+
global: [join(home, '.cursor', 'agents')],
|
|
51
|
+
},
|
|
52
|
+
'windsurf': {
|
|
53
|
+
project: ['.windsurf/agents/'],
|
|
54
|
+
global: [join(home, '.codeium', 'windsurf', 'agents')],
|
|
55
|
+
},
|
|
56
|
+
'cline': {
|
|
57
|
+
project: ['.cline/agents/'],
|
|
58
|
+
global: [join(home, '.cline', 'agents')],
|
|
59
|
+
},
|
|
60
|
+
'roo': {
|
|
61
|
+
project: ['.roo/agents/'],
|
|
62
|
+
global: [join(home, '.roo', 'agents')],
|
|
63
|
+
},
|
|
64
|
+
'codex': {
|
|
65
|
+
project: ['.codex/agents/'],
|
|
66
|
+
global: [join(home, '.codex', 'agents')],
|
|
67
|
+
},
|
|
68
|
+
'continue': {
|
|
69
|
+
project: ['.continue/agents/'],
|
|
70
|
+
global: [join(home, '.continue', 'agents')],
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
return global ? paths[platform].global : paths[platform].project;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function getGlobalAgentsDir(): string {
|
|
78
|
+
return process.env.NPX_AGENTS_DIR || join(homedir(), '.config', 'npx-agents');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function createSymlink(source: string, target: string): void {
|
|
82
|
+
ensureDir(dirname(target));
|
|
83
|
+
symlinkSync(source, target, 'dir');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function copyDir(source: string, target: string): void {
|
|
87
|
+
ensureDir(target);
|
|
88
|
+
const files = readdirSync(source);
|
|
89
|
+
for (const file of files) {
|
|
90
|
+
const srcPath = join(source, file);
|
|
91
|
+
const destPath = join(target, file);
|
|
92
|
+
if (isDirectory(srcPath)) {
|
|
93
|
+
copyDir(srcPath, destPath);
|
|
94
|
+
} else {
|
|
95
|
+
copyFileSync(srcPath, destPath);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function removePath(path: string): void {
|
|
101
|
+
if (existsSync(path)) {
|
|
102
|
+
rmSync(path, { recursive: true, force: true });
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function findFiles(dir: string, pattern: RegExp): string[] {
|
|
107
|
+
const results: string[] = [];
|
|
108
|
+
|
|
109
|
+
if (!existsSync(dir)) {
|
|
110
|
+
return results;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const files = readdirSync(dir);
|
|
114
|
+
for (const file of files) {
|
|
115
|
+
const fullPath = join(dir, file);
|
|
116
|
+
if (isDirectory(fullPath)) {
|
|
117
|
+
results.push(...findFiles(fullPath, pattern));
|
|
118
|
+
} else if (pattern.test(file)) {
|
|
119
|
+
results.push(fullPath);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return results;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function detectPlatforms(): AgentPlatform[] {
|
|
127
|
+
const platforms: AgentPlatform[] = [];
|
|
128
|
+
const home = homedir();
|
|
129
|
+
const cwd = process.cwd();
|
|
130
|
+
|
|
131
|
+
const checks: Array<{ platform: AgentPlatform; check: () => boolean }> = [
|
|
132
|
+
{
|
|
133
|
+
platform: 'opencode',
|
|
134
|
+
check: () => existsSync(join(home, '.config', 'opencode')) || existsSync(join(cwd, '.opencode')),
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
platform: 'claude-code',
|
|
138
|
+
check: () => existsSync(join(home, '.claude')) || existsSync(join(cwd, '.claude')),
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
platform: 'cursor',
|
|
142
|
+
check: () => existsSync(join(home, '.cursor')) || existsSync(join(cwd, '.cursor')),
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
platform: 'windsurf',
|
|
146
|
+
check: () => existsSync(join(home, '.codeium', 'windsurf')) || existsSync(join(cwd, '.windsurf')),
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
platform: 'cline',
|
|
150
|
+
check: () => existsSync(join(home, '.cline')) || existsSync(join(cwd, '.cline')),
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
platform: 'roo',
|
|
154
|
+
check: () => existsSync(join(home, '.roo')) || existsSync(join(cwd, '.roo')),
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
platform: 'codex',
|
|
158
|
+
check: () => existsSync(join(home, '.codex')) || existsSync(join(cwd, '.codex')),
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
platform: 'continue',
|
|
162
|
+
check: () => existsSync(join(home, '.continue')) || existsSync(join(cwd, '.continue')),
|
|
163
|
+
},
|
|
164
|
+
];
|
|
165
|
+
|
|
166
|
+
for (const check of checks) {
|
|
167
|
+
if (check.check()) {
|
|
168
|
+
platforms.push(check.platform);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (platforms.length === 0) {
|
|
173
|
+
platforms.push('opencode');
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return platforms;
|
|
177
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
|
|
3
|
+
export const logger = {
|
|
4
|
+
info: (msg: string) => console.log(chalk.blue('ℹ'), msg),
|
|
5
|
+
success: (msg: string) => console.log(chalk.green('✓'), msg),
|
|
6
|
+
warn: (msg: string) => console.log(chalk.yellow('⚠'), msg),
|
|
7
|
+
error: (msg: string) => console.error(chalk.red('✗'), msg),
|
|
8
|
+
debug: (msg: string) => {
|
|
9
|
+
if (process.env.DEBUG === 'npx-agents') {
|
|
10
|
+
console.log(chalk.gray('[debug]'), msg);
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: my-agent - Add your agent description here
|
|
3
|
+
mode: subagent
|
|
4
|
+
model: anthropic/claude-3-5-sonnet-20241022
|
|
5
|
+
temperature: 0.7
|
|
6
|
+
tools:
|
|
7
|
+
read: true
|
|
8
|
+
write: true
|
|
9
|
+
edit: true
|
|
10
|
+
bash: false
|
|
11
|
+
glob: true
|
|
12
|
+
grep: true
|
|
13
|
+
task: false
|
|
14
|
+
skill: false
|
|
15
|
+
hidden: false
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# my-agent
|
|
19
|
+
|
|
20
|
+
You are a custom AI agent. Describe your purpose and behavior here.
|
|
21
|
+
|
|
22
|
+
## When to Use
|
|
23
|
+
|
|
24
|
+
Describe when this agent should be invoked.
|
|
25
|
+
|
|
26
|
+
## Workflow
|
|
27
|
+
|
|
28
|
+
1. First step...
|
|
29
|
+
2. Second step...
|
|
30
|
+
3. Third step...
|
|
31
|
+
|
|
32
|
+
## Guidelines
|
|
33
|
+
|
|
34
|
+
- Add your specific guidelines here
|
|
35
|
+
- Be clear and concise
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"lib": ["ES2022"],
|
|
7
|
+
"outDir": "./dist",
|
|
8
|
+
"rootDir": "./src",
|
|
9
|
+
"strict": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true,
|
|
13
|
+
"resolveJsonModule": true,
|
|
14
|
+
"declaration": false,
|
|
15
|
+
"declarationMap": false,
|
|
16
|
+
"sourceMap": true
|
|
17
|
+
},
|
|
18
|
+
"include": ["src/**/*"],
|
|
19
|
+
"exclude": ["node_modules", "dist", "templates"]
|
|
20
|
+
}
|