@zweer/dev 1.0.1
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/LICENSE +21 -0
- package/README.md +508 -0
- package/agents/data/zweer_data_engineer.md +436 -0
- package/agents/design/zweer_ui_designer.md +171 -0
- package/agents/design/zweer_ui_ux.md +124 -0
- package/agents/infrastructure/zweer_infra_cdk.md +701 -0
- package/agents/infrastructure/zweer_infra_devops.md +148 -0
- package/agents/infrastructure/zweer_infra_observability.md +610 -0
- package/agents/infrastructure/zweer_infra_terraform.md +658 -0
- package/agents/mobile/zweer_mobile_android.md +636 -0
- package/agents/mobile/zweer_mobile_flutter.md +623 -0
- package/agents/mobile/zweer_mobile_ionic.md +550 -0
- package/agents/mobile/zweer_mobile_ios.md +504 -0
- package/agents/mobile/zweer_mobile_react_native.md +561 -0
- package/agents/quality/zweer_qa_documentation.md +202 -0
- package/agents/quality/zweer_qa_performance.md +160 -0
- package/agents/quality/zweer_qa_security.md +197 -0
- package/agents/quality/zweer_qa_testing.md +189 -0
- package/agents/services/zweer_svc_api_gateway.md +553 -0
- package/agents/services/zweer_svc_containers.md +575 -0
- package/agents/services/zweer_svc_lambda.md +373 -0
- package/agents/services/zweer_svc_messaging.md +543 -0
- package/agents/services/zweer_svc_microservices.md +502 -0
- package/agents/web/zweer_web_api_integration.md +500 -0
- package/agents/web/zweer_web_backend.md +358 -0
- package/agents/web/zweer_web_database.md +357 -0
- package/agents/web/zweer_web_frontend.md +375 -0
- package/agents/web/zweer_web_reader.md +229 -0
- package/agents/write/zweer_write_content.md +499 -0
- package/agents/write/zweer_write_narrative.md +409 -0
- package/agents/write/zweer_write_style.md +247 -0
- package/agents/write/zweer_write_warmth.md +282 -0
- package/cli/commands/bootstrap.d.ts +4 -0
- package/cli/commands/bootstrap.js +332 -0
- package/cli/commands/cao/index.d.ts +2 -0
- package/cli/commands/cao/index.js +14 -0
- package/cli/commands/cao/init.d.ts +15 -0
- package/cli/commands/cao/init.js +87 -0
- package/cli/commands/cao/install.d.ts +10 -0
- package/cli/commands/cao/install.js +58 -0
- package/cli/commands/cao/launch.d.ts +3 -0
- package/cli/commands/cao/launch.js +21 -0
- package/cli/commands/cao/list.d.ts +4 -0
- package/cli/commands/cao/list.js +28 -0
- package/cli/commands/cao/server.d.ts +3 -0
- package/cli/commands/cao/server.js +20 -0
- package/cli/commands/setup.d.ts +4 -0
- package/cli/commands/setup.js +269 -0
- package/cli/index.d.ts +2 -0
- package/cli/index.js +13 -0
- package/cli/utils/agents.d.ts +8 -0
- package/cli/utils/agents.js +55 -0
- package/cli/utils/cao.d.ts +8 -0
- package/cli/utils/cao.js +23 -0
- package/cli/utils/paths.d.ts +5 -0
- package/cli/utils/paths.js +11 -0
- package/package.json +80 -0
- package/templates/orchestrator.md +190 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { basename, join } from 'node:path';
|
|
3
|
+
import { Command } from '@commander-js/extra-typings';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import inquirer from 'inquirer';
|
|
6
|
+
import { paths } from '../../utils/paths.js';
|
|
7
|
+
export async function createOrchestrator(config) {
|
|
8
|
+
// Read template
|
|
9
|
+
const templatePath = join(paths.templates, 'orchestrator.md');
|
|
10
|
+
let template = await readFile(templatePath, 'utf-8');
|
|
11
|
+
// Replace placeholders
|
|
12
|
+
template = template
|
|
13
|
+
.replace(/\{\{PROJECT_NAME\}\}/g, config.projectName)
|
|
14
|
+
.replace(/\{\{PROJECT_PATH\}\}/g, config.projectPath)
|
|
15
|
+
.replace(/\{\{TECH_STACK\}\}/g, config.techStack)
|
|
16
|
+
.replace(/\{\{PROJECT_STRUCTURE\}\}/g, config.projectStructure);
|
|
17
|
+
// Create .cao/agents directory
|
|
18
|
+
const caoDir = join(config.projectPath, '.cao', 'agents');
|
|
19
|
+
await mkdir(caoDir, { recursive: true });
|
|
20
|
+
// Write orchestrator file
|
|
21
|
+
const orchestratorPath = join(caoDir, `${config.name}.md`);
|
|
22
|
+
await writeFile(orchestratorPath, template);
|
|
23
|
+
return { orchestratorPath };
|
|
24
|
+
}
|
|
25
|
+
export function getDefaultConfig(cwd, name) {
|
|
26
|
+
const projectName = basename(cwd);
|
|
27
|
+
return {
|
|
28
|
+
name: name || `${projectName}_orchestrator`,
|
|
29
|
+
projectName,
|
|
30
|
+
projectPath: cwd,
|
|
31
|
+
techStack: 'Next.js, TypeScript, PostgreSQL',
|
|
32
|
+
projectStructure: 'app/, components/, lib/',
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export const initCommand = new Command()
|
|
36
|
+
.name('init')
|
|
37
|
+
.description('Create orchestrator in current project')
|
|
38
|
+
.argument('[name]', 'Orchestrator name')
|
|
39
|
+
.option('-y, --yes', 'Skip prompts and use defaults')
|
|
40
|
+
.action(async (name, options) => {
|
|
41
|
+
const cwd = process.cwd();
|
|
42
|
+
let config = getDefaultConfig(cwd, name);
|
|
43
|
+
if (!options.yes) {
|
|
44
|
+
const answers = await inquirer.prompt([
|
|
45
|
+
{
|
|
46
|
+
type: 'input',
|
|
47
|
+
name: 'name',
|
|
48
|
+
message: 'Orchestrator name:',
|
|
49
|
+
default: config.name,
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
type: 'input',
|
|
53
|
+
name: 'projectName',
|
|
54
|
+
message: 'Project name:',
|
|
55
|
+
default: config.projectName,
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
type: 'input',
|
|
59
|
+
name: 'techStack',
|
|
60
|
+
message: 'Tech stack:',
|
|
61
|
+
default: config.techStack,
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
type: 'input',
|
|
65
|
+
name: 'projectStructure',
|
|
66
|
+
message: 'Main folders:',
|
|
67
|
+
default: config.projectStructure,
|
|
68
|
+
},
|
|
69
|
+
]);
|
|
70
|
+
config = { ...config, ...answers };
|
|
71
|
+
}
|
|
72
|
+
console.log(chalk.cyan(`\n🎯 Creating orchestrator: ${config.name}\n`));
|
|
73
|
+
try {
|
|
74
|
+
const { orchestratorPath } = await createOrchestrator(config);
|
|
75
|
+
console.log(chalk.green(`✅ Orchestrator created: ${orchestratorPath}\n`));
|
|
76
|
+
console.log(chalk.gray('Next steps:'));
|
|
77
|
+
console.log(chalk.gray(' 1. Edit the orchestrator to add project-specific details'));
|
|
78
|
+
console.log(chalk.gray(' 2. Run: dev install'));
|
|
79
|
+
console.log(chalk.gray(` 3. Run: cao launch --agents ${config.name}`));
|
|
80
|
+
console.log();
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
console.error(chalk.red('Failed to create orchestrator'));
|
|
84
|
+
console.error(error);
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Command } from '@commander-js/extra-typings';
|
|
2
|
+
export declare function executeInstallCao(): Promise<void>;
|
|
3
|
+
export declare function executeInstallAgents(): Promise<{
|
|
4
|
+
installed: number;
|
|
5
|
+
failed: number;
|
|
6
|
+
}>;
|
|
7
|
+
export declare const installCommand: Command<[], {
|
|
8
|
+
caoOnly?: true | undefined;
|
|
9
|
+
agentsOnly?: true | undefined;
|
|
10
|
+
}>;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Command } from '@commander-js/extra-typings';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import ora from 'ora';
|
|
4
|
+
import { getAllAgents } from '../../utils/agents.js';
|
|
5
|
+
import { installAgent, installCao } from '../../utils/cao.js';
|
|
6
|
+
export async function executeInstallCao() {
|
|
7
|
+
await installCao();
|
|
8
|
+
}
|
|
9
|
+
export async function executeInstallAgents() {
|
|
10
|
+
const agents = await getAllAgents();
|
|
11
|
+
let installed = 0;
|
|
12
|
+
let failed = 0;
|
|
13
|
+
for (const agent of agents) {
|
|
14
|
+
try {
|
|
15
|
+
await installAgent(agent.path);
|
|
16
|
+
installed++;
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
failed++;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return { installed, failed };
|
|
23
|
+
}
|
|
24
|
+
export const installCommand = new Command()
|
|
25
|
+
.name('install')
|
|
26
|
+
.description('Install CAO and all common agents')
|
|
27
|
+
.option('--cao-only', 'Install only CAO')
|
|
28
|
+
.option('--agents-only', 'Install only agents')
|
|
29
|
+
.action(async (options) => {
|
|
30
|
+
const installCaoOnly = options.caoOnly;
|
|
31
|
+
const installAgentsOnly = options.agentsOnly;
|
|
32
|
+
// Install CAO
|
|
33
|
+
if (!installAgentsOnly) {
|
|
34
|
+
const spinner = ora('Installing CAO prerequisites...').start();
|
|
35
|
+
try {
|
|
36
|
+
await executeInstallCao();
|
|
37
|
+
spinner.succeed(chalk.green('CAO installed successfully'));
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
spinner.fail(chalk.red('Failed to install CAO'));
|
|
41
|
+
console.error(error);
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// Install agents
|
|
46
|
+
if (!installCaoOnly) {
|
|
47
|
+
const agents = await getAllAgents();
|
|
48
|
+
const spinner = ora(`Installing ${agents.length} agents...`).start();
|
|
49
|
+
const { installed, failed } = await executeInstallAgents();
|
|
50
|
+
if (failed === 0) {
|
|
51
|
+
spinner.succeed(chalk.green(`All ${installed} agents installed successfully`));
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
spinner.warn(chalk.yellow(`Installed ${installed} agents, ${failed} failed`));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
console.log(chalk.bold.green('\n✅ Installation complete!\n'));
|
|
58
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Command } from '@commander-js/extra-typings';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { launchAgent } from '../../utils/cao.js';
|
|
4
|
+
export async function executeLaunch(agentName) {
|
|
5
|
+
await launchAgent(agentName);
|
|
6
|
+
}
|
|
7
|
+
export const launchCommand = new Command()
|
|
8
|
+
.name('launch')
|
|
9
|
+
.description('Launch a specific agent')
|
|
10
|
+
.argument('<agent>', 'Agent name to launch')
|
|
11
|
+
.action(async (agentName) => {
|
|
12
|
+
console.log(chalk.cyan(`🚀 Launching ${agentName}...\n`));
|
|
13
|
+
try {
|
|
14
|
+
await executeLaunch(agentName);
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
console.error(chalk.red(`Failed to launch ${agentName}`));
|
|
18
|
+
console.error(error);
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Command } from '@commander-js/extra-typings';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { getAllAgents } from '../../utils/agents.js';
|
|
4
|
+
export function groupAgentsByCategory(agents) {
|
|
5
|
+
return agents.reduce((acc, agent) => {
|
|
6
|
+
const key = agent.subcategory ? `${agent.category}/${agent.subcategory}` : agent.category;
|
|
7
|
+
if (!acc[key])
|
|
8
|
+
acc[key] = [];
|
|
9
|
+
acc[key].push(agent);
|
|
10
|
+
return acc;
|
|
11
|
+
}, {});
|
|
12
|
+
}
|
|
13
|
+
export const listCommand = new Command()
|
|
14
|
+
.name('list')
|
|
15
|
+
.description('List all available agents')
|
|
16
|
+
.action(async () => {
|
|
17
|
+
const agents = await getAllAgents();
|
|
18
|
+
console.log(chalk.bold('\n📦 Available Agents:\n'));
|
|
19
|
+
const grouped = groupAgentsByCategory(agents);
|
|
20
|
+
for (const [category, categoryAgents] of Object.entries(grouped)) {
|
|
21
|
+
console.log(chalk.cyan(`\n${category}:`));
|
|
22
|
+
for (const agent of categoryAgents) {
|
|
23
|
+
const desc = agent.description ? chalk.gray(` - ${agent.description}`) : '';
|
|
24
|
+
console.log(` ${chalk.green(agent.name)}${desc}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
console.log(chalk.gray(`\nTotal: ${agents.length} agents\n`));
|
|
28
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Command } from '@commander-js/extra-typings';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { startServer } from '../../utils/cao.js';
|
|
4
|
+
export async function executeServer() {
|
|
5
|
+
await startServer();
|
|
6
|
+
}
|
|
7
|
+
export const serverCommand = new Command()
|
|
8
|
+
.name('server')
|
|
9
|
+
.description('Launch the CAO server')
|
|
10
|
+
.action(async () => {
|
|
11
|
+
console.log(chalk.cyan('🚀 Starting CAO server...\n'));
|
|
12
|
+
try {
|
|
13
|
+
await executeServer();
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
console.error(chalk.red('Failed to start server'));
|
|
17
|
+
console.error(error);
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import { exec } from 'node:child_process';
|
|
2
|
+
import { access, mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { promisify } from 'node:util';
|
|
4
|
+
import { Command } from '@commander-js/extra-typings';
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import inquirer from 'inquirer';
|
|
7
|
+
import ora from 'ora';
|
|
8
|
+
const execAsync = promisify(exec);
|
|
9
|
+
const DEV_DEPENDENCIES = {
|
|
10
|
+
'@biomejs/biome': '^2.3.4',
|
|
11
|
+
'@semantic-release/changelog': '^6.0.3',
|
|
12
|
+
'@semantic-release/git': '^10.0.1',
|
|
13
|
+
'@tsconfig/node22': '^22.0.2',
|
|
14
|
+
'@types/node': '^24.10.0',
|
|
15
|
+
'@vitest/coverage-v8': '^4.0.8',
|
|
16
|
+
concurrently: '^9.2.1',
|
|
17
|
+
husky: '^9.1.7',
|
|
18
|
+
'lint-staged': '^16.2.6',
|
|
19
|
+
'lockfile-lint': '^4.14.1',
|
|
20
|
+
'ls-engines': '^0.9.3',
|
|
21
|
+
publint: '^0.3.15',
|
|
22
|
+
rimraf: '^6.1.0',
|
|
23
|
+
'semantic-release': '^25.0.2',
|
|
24
|
+
typescript: '^5.9.3',
|
|
25
|
+
vitest: '^4.0.8',
|
|
26
|
+
};
|
|
27
|
+
const SCRIPTS = {
|
|
28
|
+
lint: 'concurrently npm:lint:* --prefixColors auto',
|
|
29
|
+
'lint:format': 'biome check --write',
|
|
30
|
+
'lint:lockfile': 'lockfile-lint --path package-lock.json',
|
|
31
|
+
'lint:engines': 'ls-engines',
|
|
32
|
+
'lint:publish': 'publint --strict',
|
|
33
|
+
test: 'vitest run',
|
|
34
|
+
'test:coverage': 'vitest run --coverage',
|
|
35
|
+
check: 'npm run clean && npm run test:coverage && npm run build && npm run lint && npm run clean',
|
|
36
|
+
prepare: 'husky',
|
|
37
|
+
clean: 'rimraf --glob ./{src,test}/**/*.{d.ts,js} ./vitest*.{d.ts,js}',
|
|
38
|
+
prebuild: 'npm run clean',
|
|
39
|
+
build: 'tsc',
|
|
40
|
+
release: 'semantic-release',
|
|
41
|
+
};
|
|
42
|
+
async function fileExists(path) {
|
|
43
|
+
try {
|
|
44
|
+
await access(path);
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export const setup = new Command()
|
|
52
|
+
.name('setup')
|
|
53
|
+
.description('Add standard configuration to an existing project')
|
|
54
|
+
.option('-y, --yes', 'Skip prompts and use defaults')
|
|
55
|
+
.action(async (options) => {
|
|
56
|
+
const answers = options.yes
|
|
57
|
+
? { configs: ['all'] }
|
|
58
|
+
: await inquirer.prompt([
|
|
59
|
+
{
|
|
60
|
+
type: 'checkbox',
|
|
61
|
+
name: 'configs',
|
|
62
|
+
message: 'Select configurations to add:',
|
|
63
|
+
choices: [
|
|
64
|
+
{ name: 'All', value: 'all', checked: true },
|
|
65
|
+
{ name: 'TypeScript (tsconfig.json)', value: 'typescript' },
|
|
66
|
+
{ name: 'Biome (biome.json)', value: 'biome' },
|
|
67
|
+
{ name: 'Vitest (vitest.config.ts)', value: 'vitest' },
|
|
68
|
+
{ name: 'Lint-staged (.lintstagedrc)', value: 'lintstaged' },
|
|
69
|
+
{ name: 'EditorConfig (.editorconfig)', value: 'editorconfig' },
|
|
70
|
+
{ name: 'Husky (.husky/pre-commit)', value: 'husky' },
|
|
71
|
+
{ name: 'Dependencies', value: 'deps' },
|
|
72
|
+
{ name: 'Scripts', value: 'scripts' },
|
|
73
|
+
],
|
|
74
|
+
},
|
|
75
|
+
]);
|
|
76
|
+
const selected = answers.configs.includes('all')
|
|
77
|
+
? ['typescript', 'biome', 'vitest', 'lintstaged', 'editorconfig', 'husky', 'deps', 'scripts']
|
|
78
|
+
: answers.configs;
|
|
79
|
+
const spinner = ora('Setting up project...').start();
|
|
80
|
+
try {
|
|
81
|
+
// Update package.json
|
|
82
|
+
if (selected.includes('deps') || selected.includes('scripts')) {
|
|
83
|
+
const pkgPath = 'package.json';
|
|
84
|
+
if (!(await fileExists(pkgPath))) {
|
|
85
|
+
spinner.fail(chalk.red('package.json not found. Run this in a project directory.'));
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
|
88
|
+
const pkgContent = await readFile(pkgPath, 'utf-8');
|
|
89
|
+
const pkg = JSON.parse(pkgContent);
|
|
90
|
+
if (selected.includes('deps')) {
|
|
91
|
+
spinner.text = 'Adding dependencies...';
|
|
92
|
+
pkg.devDependencies = { ...pkg.devDependencies, ...DEV_DEPENDENCIES };
|
|
93
|
+
}
|
|
94
|
+
if (selected.includes('scripts')) {
|
|
95
|
+
spinner.text = 'Adding scripts...';
|
|
96
|
+
pkg.scripts = { ...pkg.scripts, ...SCRIPTS };
|
|
97
|
+
if (!pkg.engines) {
|
|
98
|
+
pkg.engines = { node: '>= 20.17' };
|
|
99
|
+
}
|
|
100
|
+
if (!pkg.publishConfig) {
|
|
101
|
+
pkg.publishConfig = { access: 'public', provenance: true };
|
|
102
|
+
}
|
|
103
|
+
if (!pkg.release) {
|
|
104
|
+
pkg.release = {
|
|
105
|
+
plugins: [
|
|
106
|
+
'@semantic-release/commit-analyzer',
|
|
107
|
+
'@semantic-release/release-notes-generator',
|
|
108
|
+
'@semantic-release/changelog',
|
|
109
|
+
'@semantic-release/npm',
|
|
110
|
+
'@semantic-release/github',
|
|
111
|
+
'@semantic-release/git',
|
|
112
|
+
],
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
await writeFile(pkgPath, JSON.stringify(pkg, null, 2));
|
|
117
|
+
}
|
|
118
|
+
// TypeScript
|
|
119
|
+
if (selected.includes('typescript') && !(await fileExists('tsconfig.json'))) {
|
|
120
|
+
spinner.text = 'Creating tsconfig.json...';
|
|
121
|
+
const tsconfig = {
|
|
122
|
+
extends: '@tsconfig/node22/tsconfig.json',
|
|
123
|
+
compilerOptions: {
|
|
124
|
+
declaration: true,
|
|
125
|
+
skipLibCheck: true,
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
await writeFile('tsconfig.json', JSON.stringify(tsconfig, null, 2));
|
|
129
|
+
}
|
|
130
|
+
// Biome
|
|
131
|
+
if (selected.includes('biome') && !(await fileExists('biome.json'))) {
|
|
132
|
+
spinner.text = 'Creating biome.json...';
|
|
133
|
+
const biome = {
|
|
134
|
+
$schema: 'https://biomejs.dev/schemas/2.3.4/schema.json',
|
|
135
|
+
vcs: { enabled: true, clientKind: 'git', useIgnoreFile: true },
|
|
136
|
+
files: { ignoreUnknown: false },
|
|
137
|
+
formatter: { enabled: true, useEditorconfig: true, lineWidth: 100 },
|
|
138
|
+
linter: {
|
|
139
|
+
enabled: true,
|
|
140
|
+
rules: { recommended: true, suspicious: { noUnknownAtRules: 'off' } },
|
|
141
|
+
domains: { test: 'recommended' },
|
|
142
|
+
},
|
|
143
|
+
javascript: { formatter: { quoteStyle: 'single' } },
|
|
144
|
+
assist: {
|
|
145
|
+
enabled: true,
|
|
146
|
+
actions: {
|
|
147
|
+
source: {
|
|
148
|
+
organizeImports: {
|
|
149
|
+
level: 'on',
|
|
150
|
+
options: {
|
|
151
|
+
groups: [
|
|
152
|
+
':URL:',
|
|
153
|
+
':BLANK_LINE:',
|
|
154
|
+
[':BUN:', ':NODE:'],
|
|
155
|
+
':BLANK_LINE:',
|
|
156
|
+
[':PACKAGE_WITH_PROTOCOL:', ':PACKAGE:'],
|
|
157
|
+
':BLANK_LINE:',
|
|
158
|
+
':ALIAS:',
|
|
159
|
+
':BLANK_LINE:',
|
|
160
|
+
':PATH:',
|
|
161
|
+
],
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
};
|
|
168
|
+
await writeFile('biome.json', JSON.stringify(biome, null, 2));
|
|
169
|
+
}
|
|
170
|
+
// Vitest
|
|
171
|
+
if (selected.includes('vitest') && !(await fileExists('vitest.config.ts'))) {
|
|
172
|
+
spinner.text = 'Creating vitest.config.ts...';
|
|
173
|
+
const vitestConfig = `import { defineConfig } from 'vitest/config';
|
|
174
|
+
|
|
175
|
+
export default defineConfig({
|
|
176
|
+
test: {
|
|
177
|
+
globals: true,
|
|
178
|
+
environment: 'node',
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
`;
|
|
182
|
+
await writeFile('vitest.config.ts', vitestConfig);
|
|
183
|
+
}
|
|
184
|
+
// Lint-staged
|
|
185
|
+
if (selected.includes('lintstaged') && !(await fileExists('.lintstagedrc'))) {
|
|
186
|
+
spinner.text = 'Creating .lintstagedrc...';
|
|
187
|
+
const lintStaged = `"*.{ts,tsx}":
|
|
188
|
+
- "bash -c 'npm test'"
|
|
189
|
+
|
|
190
|
+
"package.json":
|
|
191
|
+
- "bash -c 'npm test'"
|
|
192
|
+
- "bash -c 'npm run build'"
|
|
193
|
+
- "bash -c 'npm run lint:lockfile'"
|
|
194
|
+
- "bash -c 'npm run lint:engines'"
|
|
195
|
+
- "bash -c 'npm run lint:publish'"
|
|
196
|
+
- "bash -c 'npm run clean'"
|
|
197
|
+
|
|
198
|
+
"*.{ts,tsx,json,yaml,graphql,md,css,scss,html}":
|
|
199
|
+
- "biome check --write --no-errors-on-unmatched --files-ignore-unknown=true"
|
|
200
|
+
`;
|
|
201
|
+
await writeFile('.lintstagedrc', lintStaged);
|
|
202
|
+
}
|
|
203
|
+
// EditorConfig
|
|
204
|
+
if (selected.includes('editorconfig') && !(await fileExists('.editorconfig'))) {
|
|
205
|
+
spinner.text = 'Creating .editorconfig...';
|
|
206
|
+
const editorconfig = `# http://editorconfig.org/
|
|
207
|
+
root = true
|
|
208
|
+
|
|
209
|
+
[*]
|
|
210
|
+
charset = utf-8
|
|
211
|
+
end_of_line = lf
|
|
212
|
+
insert_final_newline = true
|
|
213
|
+
indent_style = space
|
|
214
|
+
indent_size = 2
|
|
215
|
+
trim_trailing_whitespace = true
|
|
216
|
+
|
|
217
|
+
[*.md]
|
|
218
|
+
trim_trailing_whitespace = false
|
|
219
|
+
|
|
220
|
+
[Makefile]
|
|
221
|
+
indent_style = tab
|
|
222
|
+
`;
|
|
223
|
+
await writeFile('.editorconfig', editorconfig);
|
|
224
|
+
}
|
|
225
|
+
// Husky
|
|
226
|
+
if (selected.includes('husky')) {
|
|
227
|
+
spinner.text = 'Creating .husky/pre-commit...';
|
|
228
|
+
await mkdir('.husky', { recursive: true });
|
|
229
|
+
if (!(await fileExists('.husky/pre-commit'))) {
|
|
230
|
+
const preCommit = `export NVM_DIR="$HOME/.nvm"
|
|
231
|
+
[ -s "$NVM_DIR/nvm.sh" ] && \\. "$NVM_DIR/nvm.sh"
|
|
232
|
+
|
|
233
|
+
lint-staged --concurrent false
|
|
234
|
+
git update-index --again
|
|
235
|
+
`;
|
|
236
|
+
await writeFile('.husky/pre-commit', preCommit);
|
|
237
|
+
await execAsync('chmod +x .husky/pre-commit');
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
// Install dependencies
|
|
241
|
+
if (selected.includes('deps')) {
|
|
242
|
+
spinner.text = 'Installing dependencies...';
|
|
243
|
+
await execAsync('npm install');
|
|
244
|
+
}
|
|
245
|
+
spinner.succeed(chalk.green('✓ Project setup complete!'));
|
|
246
|
+
console.log('\nAdded configurations:');
|
|
247
|
+
if (selected.includes('typescript'))
|
|
248
|
+
console.log(chalk.cyan(' ✓ tsconfig.json'));
|
|
249
|
+
if (selected.includes('biome'))
|
|
250
|
+
console.log(chalk.cyan(' ✓ biome.json'));
|
|
251
|
+
if (selected.includes('vitest'))
|
|
252
|
+
console.log(chalk.cyan(' ✓ vitest.config.ts'));
|
|
253
|
+
if (selected.includes('lintstaged'))
|
|
254
|
+
console.log(chalk.cyan(' ✓ .lintstagedrc'));
|
|
255
|
+
if (selected.includes('editorconfig'))
|
|
256
|
+
console.log(chalk.cyan(' ✓ .editorconfig'));
|
|
257
|
+
if (selected.includes('husky'))
|
|
258
|
+
console.log(chalk.cyan(' ✓ .husky/pre-commit'));
|
|
259
|
+
if (selected.includes('deps'))
|
|
260
|
+
console.log(chalk.cyan(' ✓ Dependencies'));
|
|
261
|
+
if (selected.includes('scripts'))
|
|
262
|
+
console.log(chalk.cyan(' ✓ Scripts'));
|
|
263
|
+
}
|
|
264
|
+
catch (error) {
|
|
265
|
+
spinner.fail(chalk.red('Failed to setup project'));
|
|
266
|
+
console.error(error);
|
|
267
|
+
process.exit(1);
|
|
268
|
+
}
|
|
269
|
+
});
|
package/cli/index.d.ts
ADDED
package/cli/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from '@commander-js/extra-typings';
|
|
3
|
+
import { bootstrap } from './commands/bootstrap.js';
|
|
4
|
+
import { caoCommand } from './commands/cao/index.js';
|
|
5
|
+
import { setup } from './commands/setup.js';
|
|
6
|
+
const program = new Command()
|
|
7
|
+
.name('dev')
|
|
8
|
+
.description('Shared configurations & AI agents for software projects')
|
|
9
|
+
.version('0.1.0');
|
|
10
|
+
program.addCommand(bootstrap);
|
|
11
|
+
program.addCommand(setup);
|
|
12
|
+
program.addCommand(caoCommand);
|
|
13
|
+
program.parse();
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { readdir, readFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { paths } from './paths.js';
|
|
4
|
+
export async function getAllAgents() {
|
|
5
|
+
const agents = [];
|
|
6
|
+
const categories = await readdir(paths.agents, { withFileTypes: true });
|
|
7
|
+
for (const category of categories) {
|
|
8
|
+
if (!category.isDirectory())
|
|
9
|
+
continue;
|
|
10
|
+
const categoryPath = join(paths.agents, category.name);
|
|
11
|
+
const items = await readdir(categoryPath, { withFileTypes: true });
|
|
12
|
+
for (const item of items) {
|
|
13
|
+
if (item.isDirectory()) {
|
|
14
|
+
// Subcategory (es: web/frontend)
|
|
15
|
+
const subcategoryPath = join(categoryPath, item.name);
|
|
16
|
+
const files = await readdir(subcategoryPath);
|
|
17
|
+
for (const file of files) {
|
|
18
|
+
if (file.endsWith('.md')) {
|
|
19
|
+
const agentPath = join(subcategoryPath, file);
|
|
20
|
+
const description = await extractDescription(agentPath);
|
|
21
|
+
agents.push({
|
|
22
|
+
name: file.replace('.md', ''),
|
|
23
|
+
path: agentPath,
|
|
24
|
+
category: category.name,
|
|
25
|
+
subcategory: item.name,
|
|
26
|
+
description,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
else if (item.name.endsWith('.md')) {
|
|
32
|
+
// Direct agent file (es: data/data_engineer.md)
|
|
33
|
+
const agentPath = join(categoryPath, item.name);
|
|
34
|
+
const description = await extractDescription(agentPath);
|
|
35
|
+
agents.push({
|
|
36
|
+
name: item.name.replace('.md', ''),
|
|
37
|
+
path: agentPath,
|
|
38
|
+
category: category.name,
|
|
39
|
+
description,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return agents;
|
|
45
|
+
}
|
|
46
|
+
async function extractDescription(agentPath) {
|
|
47
|
+
try {
|
|
48
|
+
const content = await readFile(agentPath, 'utf-8');
|
|
49
|
+
const match = content.match(/^description:\s*["']?(.+?)["']?$/m);
|
|
50
|
+
return match?.[1];
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function runCommand(command: string): Promise<{
|
|
2
|
+
stdout: string;
|
|
3
|
+
stderr: string;
|
|
4
|
+
}>;
|
|
5
|
+
export declare function installCao(): Promise<void>;
|
|
6
|
+
export declare function installAgent(agentPath: string): Promise<void>;
|
|
7
|
+
export declare function launchAgent(agentName: string): Promise<void>;
|
|
8
|
+
export declare function startServer(): Promise<void>;
|
package/cli/utils/cao.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { exec } from 'node:child_process';
|
|
2
|
+
import { promisify } from 'node:util';
|
|
3
|
+
const execAsync = promisify(exec);
|
|
4
|
+
export async function runCommand(command) {
|
|
5
|
+
return execAsync(command);
|
|
6
|
+
}
|
|
7
|
+
export async function installCao() {
|
|
8
|
+
// Install tmux config
|
|
9
|
+
await runCommand('curl -s https://raw.githubusercontent.com/awslabs/cli-agent-orchestrator/refs/heads/main/tmux-install.sh -o /tmp/tmux-install.sh && bash /tmp/tmux-install.sh || true');
|
|
10
|
+
// Install uv
|
|
11
|
+
await runCommand('curl -LsSf https://astral.sh/uv/install.sh | sh');
|
|
12
|
+
// Install CAO
|
|
13
|
+
await runCommand('uv tool install git+https://github.com/awslabs/cli-agent-orchestrator.git@main --upgrade');
|
|
14
|
+
}
|
|
15
|
+
export async function installAgent(agentPath) {
|
|
16
|
+
await runCommand(`cao install "${agentPath}"`);
|
|
17
|
+
}
|
|
18
|
+
export async function launchAgent(agentName) {
|
|
19
|
+
await runCommand(`cao launch --agents ${agentName}`);
|
|
20
|
+
}
|
|
21
|
+
export async function startServer() {
|
|
22
|
+
await runCommand('cao-server');
|
|
23
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { dirname, join } from 'node:path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
4
|
+
const __dirname = dirname(__filename);
|
|
5
|
+
export const paths = {
|
|
6
|
+
// Root del pacchetto @zweer/dev
|
|
7
|
+
root: join(__dirname, '../..'),
|
|
8
|
+
// Cartelle del pacchetto
|
|
9
|
+
agents: join(__dirname, '../../agents'),
|
|
10
|
+
templates: join(__dirname, '../../templates'),
|
|
11
|
+
};
|