expxagents 0.1.0

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.
Files changed (92) hide show
  1. package/assets/agents/_catalog.yaml +11 -0
  2. package/assets/agents/commercial/account-executive.agent.md +41 -0
  3. package/assets/agents/commercial/crm-manager.agent.md +41 -0
  4. package/assets/agents/commercial/pricing-strategist.agent.md +41 -0
  5. package/assets/agents/commercial/proposal-writer.agent.md +41 -0
  6. package/assets/agents/commercial/sdr.agent.md +41 -0
  7. package/assets/agents/development/backend-developer.agent.md +42 -0
  8. package/assets/agents/development/code-reviewer.agent.md +41 -0
  9. package/assets/agents/development/devops-engineer.agent.md +41 -0
  10. package/assets/agents/development/frontend-developer.agent.md +92 -0
  11. package/assets/agents/development/product-manager.agent.md +41 -0
  12. package/assets/agents/development/qa-engineer.agent.md +41 -0
  13. package/assets/agents/development/tech-lead.agent.md +42 -0
  14. package/assets/agents/development/ux-design-expert.agent.md +108 -0
  15. package/assets/agents/marketing/brand-guardian.agent.md +40 -0
  16. package/assets/agents/marketing/content-creator.agent.md +41 -0
  17. package/assets/agents/marketing/email-marketing.agent.md +41 -0
  18. package/assets/agents/marketing/landing-page-builder.agent.md +73 -0
  19. package/assets/agents/marketing/marketing-analyst.agent.md +41 -0
  20. package/assets/agents/marketing/paid-ads-manager.agent.md +41 -0
  21. package/assets/agents/marketing/seo-specialist.agent.md +41 -0
  22. package/assets/agents/marketing/social-media-manager.agent.md +41 -0
  23. package/assets/core/best-practices/_catalog.yaml +85 -0
  24. package/assets/core/best-practices/api-documentation.md +137 -0
  25. package/assets/core/best-practices/blog-post.md +86 -0
  26. package/assets/core/best-practices/blog-seo.md +91 -0
  27. package/assets/core/best-practices/code-review.md +97 -0
  28. package/assets/core/best-practices/copywriting.md +75 -0
  29. package/assets/core/best-practices/data-analysis.md +93 -0
  30. package/assets/core/best-practices/deploy-checklist.md +99 -0
  31. package/assets/core/best-practices/email-newsletter.md +84 -0
  32. package/assets/core/best-practices/email-sales.md +91 -0
  33. package/assets/core/best-practices/image-design.md +78 -0
  34. package/assets/core/best-practices/instagram-feed.md +70 -0
  35. package/assets/core/best-practices/instagram-reels.md +75 -0
  36. package/assets/core/best-practices/instagram-stories.md +68 -0
  37. package/assets/core/best-practices/landing-page.md +279 -0
  38. package/assets/core/best-practices/linkedin-article.md +83 -0
  39. package/assets/core/best-practices/linkedin-post.md +84 -0
  40. package/assets/core/best-practices/researching.md +89 -0
  41. package/assets/core/best-practices/review.md +95 -0
  42. package/assets/core/best-practices/sprint-planning.md +91 -0
  43. package/assets/core/best-practices/strategist.md +95 -0
  44. package/assets/core/best-practices/technical-writing.md +104 -0
  45. package/assets/core/best-practices/twitter-post.md +75 -0
  46. package/assets/core/best-practices/twitter-thread.md +92 -0
  47. package/assets/core/best-practices/whatsapp-broadcast.md +95 -0
  48. package/assets/core/best-practices/youtube-script.md +80 -0
  49. package/assets/core/best-practices/youtube-shorts.md +76 -0
  50. package/assets/core/prompts/insight-hunter.prompt.md +62 -0
  51. package/assets/core/runner.pipeline.md +117 -0
  52. package/assets/core/skills.engine.md +65 -0
  53. package/assets/core/solution-architect.agent.md +181 -0
  54. package/assets/templates/_expxagents/_memory/company.md +25 -0
  55. package/assets/templates/_expxagents/_memory/preferences.md +6 -0
  56. package/assets/templates/squads/_memory/memories.md +16 -0
  57. package/bin/expxagents.js +3 -0
  58. package/dist/cli/src/__tests__/cli.test.d.ts +1 -0
  59. package/dist/cli/src/__tests__/cli.test.js +23 -0
  60. package/dist/cli/src/commands/create.d.ts +1 -0
  61. package/dist/cli/src/commands/create.js +53 -0
  62. package/dist/cli/src/commands/doctor.d.ts +1 -0
  63. package/dist/cli/src/commands/doctor.js +86 -0
  64. package/dist/cli/src/commands/init.d.ts +1 -0
  65. package/dist/cli/src/commands/init.js +164 -0
  66. package/dist/cli/src/commands/install.d.ts +1 -0
  67. package/dist/cli/src/commands/install.js +65 -0
  68. package/dist/cli/src/commands/list.d.ts +1 -0
  69. package/dist/cli/src/commands/list.js +58 -0
  70. package/dist/cli/src/commands/onboarding.d.ts +1 -0
  71. package/dist/cli/src/commands/onboarding.js +39 -0
  72. package/dist/cli/src/commands/run.d.ts +1 -0
  73. package/dist/cli/src/commands/run.js +226 -0
  74. package/dist/cli/src/commands/server.d.ts +1 -0
  75. package/dist/cli/src/commands/server.js +22 -0
  76. package/dist/cli/src/commands/stop.d.ts +1 -0
  77. package/dist/cli/src/commands/stop.js +23 -0
  78. package/dist/cli/src/commands/uninstall.d.ts +1 -0
  79. package/dist/cli/src/commands/uninstall.js +12 -0
  80. package/dist/cli/src/index.d.ts +1 -0
  81. package/dist/cli/src/index.js +57 -0
  82. package/dist/cli/src/utils/config.d.ts +34 -0
  83. package/dist/cli/src/utils/config.js +79 -0
  84. package/dist/core/skills-loader.d.ts +16 -0
  85. package/dist/core/skills-loader.js +61 -0
  86. package/dist/core/squad-loader.d.ts +26 -0
  87. package/dist/core/squad-loader.js +51 -0
  88. package/dist/core/state-manager.d.ts +45 -0
  89. package/dist/core/state-manager.js +90 -0
  90. package/dist/core/vitest.config.d.ts +2 -0
  91. package/dist/core/vitest.config.js +7 -0
  92. package/package.json +49 -0
@@ -0,0 +1,86 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { execSync } from 'child_process';
4
+ import { getAssetsDir } from '../utils/config.js';
5
+ export async function doctorCommand() {
6
+ const cwd = process.cwd();
7
+ const checks = [];
8
+ // Node.js version
9
+ const nodeVersion = process.version;
10
+ const major = parseInt(nodeVersion.slice(1));
11
+ checks.push({
12
+ name: 'Node.js',
13
+ status: major >= 20 ? 'ok' : 'fail',
14
+ message: `${nodeVersion} ${major >= 20 ? '(meets >=20)' : '(requires >=20)'}`,
15
+ });
16
+ // Claude Code CLI
17
+ try {
18
+ const claudeVersion = execSync('claude --version', { encoding: 'utf-8' }).trim();
19
+ checks.push({ name: 'Claude Code CLI', status: 'ok', message: claudeVersion });
20
+ }
21
+ catch {
22
+ checks.push({ name: 'Claude Code CLI', status: 'fail', message: 'Not found — install from https://claude.ai/code' });
23
+ }
24
+ // Project structure
25
+ const requiredDirs = ['squads', '_expxagents/_memory'];
26
+ for (const dir of requiredDirs) {
27
+ const exists = fs.existsSync(path.join(cwd, dir));
28
+ checks.push({
29
+ name: `Directory: ${dir}`,
30
+ status: exists ? 'ok' : 'warn',
31
+ message: exists ? 'exists' : 'missing — run `expxagents init`',
32
+ });
33
+ }
34
+ // .env file
35
+ const envExists = fs.existsSync(path.join(cwd, '.env'));
36
+ checks.push({
37
+ name: '.env file',
38
+ status: envExists ? 'ok' : 'warn',
39
+ message: envExists ? 'exists' : 'missing — run `expxagents init`',
40
+ });
41
+ // Company profile
42
+ const companyPath = path.join(cwd, '_expxagents', '_memory', 'company.md');
43
+ if (fs.existsSync(companyPath)) {
44
+ const content = fs.readFileSync(companyPath, 'utf-8');
45
+ const configured = !content.includes('NOT CONFIGURED');
46
+ checks.push({
47
+ name: 'Company profile',
48
+ status: configured ? 'ok' : 'warn',
49
+ message: configured ? 'configured' : 'not configured — run `expxagents onboarding`',
50
+ });
51
+ }
52
+ // Squads count
53
+ const squadsDir = path.join(cwd, 'squads');
54
+ if (fs.existsSync(squadsDir)) {
55
+ const squads = fs.readdirSync(squadsDir, { withFileTypes: true })
56
+ .filter(d => d.isDirectory() && !d.name.startsWith('.') && d.name !== '_memory')
57
+ .length;
58
+ checks.push({ name: 'Squads', status: 'ok', message: `${squads} found` });
59
+ }
60
+ // Package assets (check in package directory, not user project)
61
+ const assetsDir = getAssetsDir();
62
+ const coreFiles = [
63
+ { label: 'solution-architect.agent.md', path: path.join(assetsDir, 'core', 'solution-architect.agent.md') },
64
+ { label: 'runner.pipeline.md', path: path.join(assetsDir, 'core', 'runner.pipeline.md') },
65
+ { label: 'agents catalog', path: path.join(assetsDir, 'agents', '_catalog.yaml') },
66
+ { label: 'best-practices', path: path.join(assetsDir, 'core', 'best-practices', '_catalog.yaml') },
67
+ ];
68
+ for (const file of coreFiles) {
69
+ const exists = fs.existsSync(file.path);
70
+ checks.push({
71
+ name: `Package: ${file.label}`,
72
+ status: exists ? 'ok' : 'warn',
73
+ message: exists ? 'present' : 'missing — reinstall expxagents',
74
+ });
75
+ }
76
+ // Display results
77
+ console.log('\n ExpxAgents System Diagnostics\n');
78
+ const symbols = { ok: ' OK', warn: 'WARN', fail: 'FAIL' };
79
+ let hasFailures = false;
80
+ for (const check of checks) {
81
+ if (check.status === 'fail')
82
+ hasFailures = true;
83
+ console.log(` [${symbols[check.status]}] ${check.name}: ${check.message}`);
84
+ }
85
+ console.log(hasFailures ? '\n Some checks failed. See above.\n' : '\n All checks passed!\n');
86
+ }
@@ -0,0 +1 @@
1
+ export declare function initCommand(): Promise<void>;
@@ -0,0 +1,164 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import crypto from 'crypto';
4
+ import { getTemplateDir } from '../utils/config.js';
5
+ function getDefaultTemplate(file) {
6
+ if (file === 'company.md') {
7
+ return `<!-- NOT CONFIGURED -->
8
+ # Company Profile
9
+
10
+ ## Company
11
+ - **Name:**
12
+ - **Website:**
13
+ - **Sector:**
14
+ - **Description:**
15
+
16
+ ## Target Audience
17
+ - **Primary:**
18
+ - **Secondary:**
19
+
20
+ ## Tone of Voice
21
+ - **Style:**
22
+ - **Keywords:**
23
+
24
+ ## Social Media
25
+ - **Instagram:**
26
+ - **LinkedIn:**
27
+ - **Twitter:**
28
+ - **YouTube:**
29
+
30
+ ## Products/Services
31
+ -
32
+ `;
33
+ }
34
+ if (file === 'preferences.md') {
35
+ return `# ExpxAgents Preferences
36
+
37
+ - **User Name:**
38
+ - **Language:** Portugues (Brasil)
39
+ - **IDE:** claude-code
40
+ - **Date Format:** DD/MM/YYYY
41
+ `;
42
+ }
43
+ if (file === 'memories.md') {
44
+ return `# Squad Memories
45
+
46
+ > Updated automatically after each pipeline execution.
47
+ > Contains learnings, user preferences, and decisions from past runs.
48
+
49
+ ## Execution History
50
+
51
+ (No runs yet)
52
+
53
+ ## User Preferences
54
+
55
+ (No preferences recorded yet)
56
+
57
+ ## Key Learnings
58
+
59
+ (No learnings recorded yet)
60
+ `;
61
+ }
62
+ return '';
63
+ }
64
+ export async function initCommand() {
65
+ const cwd = process.cwd();
66
+ console.log('Initializing ExpxAgents project...\n');
67
+ // Create squads directory
68
+ const squadsDir = path.join(cwd, 'squads');
69
+ if (!fs.existsSync(squadsDir)) {
70
+ fs.mkdirSync(squadsDir, { recursive: true });
71
+ console.log(' Created squads/');
72
+ }
73
+ else {
74
+ console.log(' squads/ already exists');
75
+ }
76
+ // Create _expxagents/_memory/ directory
77
+ const memoryDir = path.join(cwd, '_expxagents', '_memory');
78
+ if (!fs.existsSync(memoryDir)) {
79
+ fs.mkdirSync(memoryDir, { recursive: true });
80
+ console.log(' Created _expxagents/_memory/');
81
+ }
82
+ else {
83
+ console.log(' _expxagents/_memory/ already exists');
84
+ }
85
+ // Copy template files from package assets
86
+ const templateDir = getTemplateDir();
87
+ const templateMemoryDir = path.join(templateDir, '_expxagents', '_memory');
88
+ const memoryFiles = ['company.md', 'preferences.md'];
89
+ for (const file of memoryFiles) {
90
+ const destPath = path.join(memoryDir, file);
91
+ if (!fs.existsSync(destPath)) {
92
+ const templateSrc = path.join(templateMemoryDir, file);
93
+ if (fs.existsSync(templateSrc)) {
94
+ fs.copyFileSync(templateSrc, destPath);
95
+ }
96
+ else {
97
+ fs.writeFileSync(destPath, getDefaultTemplate(file), 'utf-8');
98
+ }
99
+ console.log(` Created _expxagents/_memory/${file}`);
100
+ }
101
+ else {
102
+ console.log(` _expxagents/_memory/${file} already exists`);
103
+ }
104
+ }
105
+ // Create squads/_memory/ subdirectory
106
+ const squadsMemoryDir = path.join(cwd, 'squads', '_memory');
107
+ if (!fs.existsSync(squadsMemoryDir)) {
108
+ fs.mkdirSync(squadsMemoryDir, { recursive: true });
109
+ console.log(' Created squads/_memory/');
110
+ }
111
+ else {
112
+ console.log(' squads/_memory/ already exists');
113
+ }
114
+ const memoriesTemplateSrc = path.join(templateDir, 'squads', '_memory', 'memories.md');
115
+ const memoriesTemplateDest = path.join(squadsMemoryDir, 'memories.md');
116
+ if (!fs.existsSync(memoriesTemplateDest)) {
117
+ if (fs.existsSync(memoriesTemplateSrc)) {
118
+ fs.copyFileSync(memoriesTemplateSrc, memoriesTemplateDest);
119
+ }
120
+ else {
121
+ fs.writeFileSync(memoriesTemplateDest, getDefaultTemplate('memories.md'), 'utf-8');
122
+ }
123
+ console.log(' Created squads/_memory/memories.md');
124
+ }
125
+ // Create .env if it doesn't exist
126
+ const envPath = path.join(cwd, '.env');
127
+ if (!fs.existsSync(envPath)) {
128
+ const jwtSecret = crypto.randomBytes(32).toString('hex');
129
+ const envContent = `JWT_SECRET=${jwtSecret}
130
+ PORT=3001
131
+ CORS_ORIGIN=http://localhost:3001
132
+ NODE_ENV=development
133
+ BRIDGE_TIMEOUT_MS=300000
134
+ `;
135
+ fs.writeFileSync(envPath, envContent, 'utf-8');
136
+ console.log(' Created .env with generated JWT_SECRET');
137
+ }
138
+ else {
139
+ console.log(' .env already exists');
140
+ }
141
+ // Create .gitignore additions
142
+ const gitignorePath = path.join(cwd, '.gitignore');
143
+ const gitignoreEntries = [
144
+ 'node_modules/',
145
+ '.env',
146
+ '*.tmp',
147
+ 'squads/*/state.json',
148
+ 'squads/*/state.json.tmp',
149
+ 'squads/*/output/',
150
+ ];
151
+ if (fs.existsSync(gitignorePath)) {
152
+ const existing = fs.readFileSync(gitignorePath, 'utf-8');
153
+ const toAdd = gitignoreEntries.filter(e => !existing.includes(e));
154
+ if (toAdd.length > 0) {
155
+ fs.appendFileSync(gitignorePath, '\n# ExpxAgents\n' + toAdd.join('\n') + '\n');
156
+ console.log(' Updated .gitignore');
157
+ }
158
+ }
159
+ else {
160
+ fs.writeFileSync(gitignorePath, gitignoreEntries.join('\n') + '\n', 'utf-8');
161
+ console.log(' Created .gitignore');
162
+ }
163
+ console.log('\nProject initialized! Run `expxagents onboarding` to configure your profile.');
164
+ }
@@ -0,0 +1 @@
1
+ export declare function installCommand(skillName: string): Promise<void>;
@@ -0,0 +1,65 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ const SKILL_CATALOG = {
4
+ 'web-search': {
5
+ description: 'Web search capability (built-in)',
6
+ type: 'prompt',
7
+ template: `---\nname: web-search\ndescription: "Search the web for information"\ntype: prompt\nversion: "1.0.0"\ncategories: [search, research]\n---\n\n# Web Search\n\nUse the built-in web_search tool to find information online.\n`,
8
+ },
9
+ 'apify': {
10
+ description: 'Web scraping via Apify Actors',
11
+ type: 'mcp',
12
+ template: `---\nname: apify\ndescription: "Web scraping via Apify Actors"\ntype: mcp\nversion: "1.0.0"\nmcp:\n server_name: "apify"\n command: "npx"\n args: ["-y", "@apify/actors-mcp-server@latest"]\n transport: "stdio"\nenv:\n - APIFY_TOKEN\ncategories: [scraping, data]\n---\n\n# Apify\n\nUse Apify Actors for web scraping tasks.\n`,
13
+ },
14
+ 'image-creator': {
15
+ description: 'AI image generation via DALL-E or Stable Diffusion',
16
+ type: 'mcp',
17
+ template: `---\nname: image-creator\ndescription: "Generate images using AI models"\ntype: mcp\nversion: "1.0.0"\nmcp:\n server_name: "image-creator"\n command: "npx"\n args: ["-y", "@modelcontextprotocol/server-dalle@latest"]\n transport: "stdio"\nenv:\n - OPENAI_API_KEY\ncategories: [design, content]\n---\n\n# Image Creator\n\nGenerate images using AI models for content creation.\n`,
18
+ },
19
+ 'github': {
20
+ description: 'GitHub integration for repositories, issues, PRs',
21
+ type: 'mcp',
22
+ template: `---\nname: github\ndescription: "GitHub integration for repository management"\ntype: mcp\nversion: "1.0.0"\nmcp:\n server_name: "github"\n command: "npx"\n args: ["-y", "@modelcontextprotocol/server-github@latest"]\n transport: "stdio"\nenv:\n - GITHUB_TOKEN\ncategories: [development, integration]\n---\n\n# GitHub Integration\n\nManage GitHub repositories, issues, and pull requests.\n`,
23
+ },
24
+ 'slack': {
25
+ description: 'Slack messaging integration',
26
+ type: 'mcp',
27
+ template: `---\nname: slack\ndescription: "Send and receive Slack messages"\ntype: mcp\nversion: "1.0.0"\nmcp:\n server_name: "slack"\n command: "npx"\n args: ["-y", "@anthropic/slack-mcp-server@latest"]\n transport: "stdio"\nenv:\n - SLACK_BOT_TOKEN\ncategories: [communication, integration]\n---\n\n# Slack Integration\n\nSend and receive messages via Slack.\n`,
28
+ },
29
+ 'canva': {
30
+ description: 'Design creation via Canva API',
31
+ type: 'mcp',
32
+ template: `---\nname: canva\ndescription: "Create designs using Canva"\ntype: mcp\nversion: "1.0.0"\nmcp:\n server_name: "canva"\n command: "npx"\n args: ["-y", "@anthropic/canva-mcp-server@latest"]\n transport: "stdio"\nenv:\n - CANVA_API_KEY\ncategories: [design, content]\n---\n\n# Canva Integration\n\nCreate professional designs using Canva.\n`,
33
+ },
34
+ };
35
+ export async function installCommand(skillName) {
36
+ const cwd = process.cwd();
37
+ const skillsDir = path.join(cwd, 'skills');
38
+ if (!skillName) {
39
+ console.log('\n Available skills:\n');
40
+ for (const [name, info] of Object.entries(SKILL_CATALOG)) {
41
+ const installed = fs.existsSync(path.join(skillsDir, name));
42
+ console.log(` ${installed ? '[installed]' : ' '} ${name} — ${info.description}`);
43
+ }
44
+ console.log('\n Usage: expxagents install <skill-name>\n');
45
+ return;
46
+ }
47
+ const skill = SKILL_CATALOG[skillName];
48
+ if (!skill) {
49
+ console.error(` Skill "${skillName}" not found in catalog.`);
50
+ console.log(' Run `expxagents install` to see available skills.');
51
+ process.exit(1);
52
+ }
53
+ const skillDir = path.join(skillsDir, skillName);
54
+ if (fs.existsSync(skillDir)) {
55
+ console.log(` Skill "${skillName}" is already installed.`);
56
+ return;
57
+ }
58
+ fs.mkdirSync(skillDir, { recursive: true });
59
+ fs.writeFileSync(path.join(skillDir, 'SKILL.md'), skill.template, 'utf-8');
60
+ console.log(` Installed skill: ${skillName}`);
61
+ if (skill.type === 'mcp') {
62
+ console.log(`\n This skill requires MCP configuration.`);
63
+ console.log(` Check .mcp.json and set required environment variables.`);
64
+ }
65
+ }
@@ -0,0 +1 @@
1
+ export declare function listCommand(): Promise<void>;
@@ -0,0 +1,58 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { loadSquad } from '../../../core/squad-loader.js';
4
+ import { loadSkills } from '../../../core/skills-loader.js';
5
+ import { readState } from '../../../core/state-manager.js';
6
+ export async function listCommand() {
7
+ const cwd = process.cwd();
8
+ const squadsDir = path.join(cwd, 'squads');
9
+ const skillsDir = path.join(cwd, 'skills');
10
+ // List squads
11
+ console.log('Squads:');
12
+ console.log('-------');
13
+ if (fs.existsSync(squadsDir)) {
14
+ const entries = fs.readdirSync(squadsDir, { withFileTypes: true });
15
+ let found = false;
16
+ for (const entry of entries) {
17
+ if (!entry.isDirectory())
18
+ continue;
19
+ const squadDir = path.join(squadsDir, entry.name);
20
+ const yamlPath = path.join(squadDir, 'squad.yaml');
21
+ if (!fs.existsSync(yamlPath))
22
+ continue;
23
+ found = true;
24
+ try {
25
+ const config = loadSquad(squadDir);
26
+ const state = readState(squadDir);
27
+ const status = state?.status ?? 'idle';
28
+ const agentCount = config.squad.agents.length;
29
+ const stepCount = config.squad.pipeline.steps.length;
30
+ console.log(` ${config.squad.name} (${config.squad.code})`);
31
+ console.log(` Status: ${status} | Agents: ${agentCount} | Steps: ${stepCount}`);
32
+ console.log(` ${config.squad.description}`);
33
+ console.log('');
34
+ }
35
+ catch (err) {
36
+ console.log(` ${entry.name} — error loading: ${err.message}`);
37
+ }
38
+ }
39
+ if (!found) {
40
+ console.log(' No squads found. Run `expxagents create` to create one.\n');
41
+ }
42
+ }
43
+ else {
44
+ console.log(' No squads directory. Run `expxagents init` first.\n');
45
+ }
46
+ // List skills
47
+ console.log('Skills:');
48
+ console.log('-------');
49
+ const skills = loadSkills(skillsDir);
50
+ if (skills.length === 0) {
51
+ console.log(' No skills installed. Run `expxagents install <skill>` to add one.');
52
+ }
53
+ else {
54
+ for (const skill of skills) {
55
+ console.log(` ${skill.name} (${skill.type}) — ${skill.description}`);
56
+ }
57
+ }
58
+ }
@@ -0,0 +1 @@
1
+ export declare function onboardingCommand(): Promise<void>;
@@ -0,0 +1,39 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import readline from 'readline';
4
+ function ask(rl, question) {
5
+ return new Promise(resolve => rl.question(question, resolve));
6
+ }
7
+ export async function onboardingCommand() {
8
+ const cwd = process.cwd();
9
+ const companyPath = path.join(cwd, '_expxagents', '_memory', 'company.md');
10
+ const prefsPath = path.join(cwd, '_expxagents', '_memory', 'preferences.md');
11
+ if (!fs.existsSync(path.dirname(companyPath))) {
12
+ console.error('Project not initialized. Run `expxagents init` first.');
13
+ process.exit(1);
14
+ }
15
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
16
+ console.log('\n Welcome to ExpxAgents!\n');
17
+ try {
18
+ const userName = await ask(rl, ' Your name: ');
19
+ const language = await ask(rl, ' Preferred language (pt-BR, en, es) [pt-BR]: ') || 'pt-BR';
20
+ const ide = await ask(rl, ' Primary IDE (claude-code, cursor, codex, vscode-copilot) [claude-code]: ') || 'claude-code';
21
+ const companyName = await ask(rl, ' Company name: ');
22
+ const companyUrl = await ask(rl, ' Company website URL (optional): ');
23
+ const sector = await ask(rl, ' Company sector: ');
24
+ const description = await ask(rl, ' Brief company description: ');
25
+ const audience = await ask(rl, ' Target audience: ');
26
+ const toneStyle = await ask(rl, ' Tone of voice (formal, casual, technical, friendly): ');
27
+ // Save preferences
28
+ const prefsContent = `# ExpxAgents Preferences\n\n- **User Name:** ${userName}\n- **Language:** ${language}\n- **IDE:** ${ide}\n- **Date Format:** DD/MM/YYYY\n`;
29
+ fs.writeFileSync(prefsPath, prefsContent, 'utf-8');
30
+ // Save company profile
31
+ const companyContent = `# Company Profile\n\n## Company\n- **Name:** ${companyName}\n- **Website:** ${companyUrl}\n- **Sector:** ${sector}\n- **Description:** ${description}\n\n## Target Audience\n- **Primary:** ${audience}\n\n## Tone of Voice\n- **Style:** ${toneStyle}\n`;
32
+ fs.writeFileSync(companyPath, companyContent, 'utf-8');
33
+ console.log('\n Profile saved! You can edit it anytime at _expxagents/_memory/company.md');
34
+ console.log(' Run `expxagents create` to design your first squad.\n');
35
+ }
36
+ finally {
37
+ rl.close();
38
+ }
39
+ }
@@ -0,0 +1 @@
1
+ export declare function runCommand(name: string): Promise<void>;
@@ -0,0 +1,226 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { spawn } from 'child_process';
4
+ import { loadSquad } from '../../../core/squad-loader.js';
5
+ import { createInitialState, readState, writeState, updateAgentStatus, updateStep, setHandoff, setSquadStatus, HANDOFF_DELAY_MS, } from '../../../core/state-manager.js';
6
+ import { loadSkills } from '../../../core/skills-loader.js';
7
+ import { getCoreAsset } from '../utils/config.js';
8
+ function delay(ms) {
9
+ return new Promise(resolve => setTimeout(resolve, ms));
10
+ }
11
+ function getNextVersionDir(squadDir) {
12
+ const outputBase = path.join(squadDir, 'output');
13
+ if (!fs.existsSync(outputBase)) {
14
+ fs.mkdirSync(outputBase, { recursive: true });
15
+ const v1 = path.join(outputBase, 'v1');
16
+ fs.mkdirSync(v1);
17
+ return v1;
18
+ }
19
+ const existing = fs.readdirSync(outputBase)
20
+ .filter(d => d.startsWith('v'))
21
+ .map(d => parseInt(d.slice(1)))
22
+ .filter(n => !isNaN(n))
23
+ .sort((a, b) => b - a);
24
+ const next = (existing[0] || 0) + 1;
25
+ const dir = path.join(outputBase, `v${next}`);
26
+ fs.mkdirSync(dir, { recursive: true });
27
+ return dir;
28
+ }
29
+ function buildAgentPrompt(config, step, stepIndex, squadDir, skills, runnerPrompt) {
30
+ // Load company context (user data — always from cwd)
31
+ const companyPath = path.join(process.cwd(), '_expxagents', '_memory', 'company.md');
32
+ let companyContext = '';
33
+ if (fs.existsSync(companyPath)) {
34
+ companyContext = fs.readFileSync(companyPath, 'utf-8');
35
+ }
36
+ // Load squad memory
37
+ const memoryPath = path.join(squadDir, '_memory', 'memories.md');
38
+ let squadMemory = '';
39
+ if (fs.existsSync(memoryPath)) {
40
+ squadMemory = fs.readFileSync(memoryPath, 'utf-8');
41
+ }
42
+ // Load best-practice if format specified (from package assets)
43
+ let bestPractice = '';
44
+ const format = config.squad.format;
45
+ if (format) {
46
+ const bpPath = getCoreAsset(`best-practices/${format}.md`);
47
+ if (fs.existsSync(bpPath)) {
48
+ bestPractice = fs.readFileSync(bpPath, 'utf-8');
49
+ }
50
+ }
51
+ const agent = config.squad.agents.find(a => a.id === step.agent);
52
+ let agentInstructions = '';
53
+ const agentPromptPath = path.join(squadDir, agent.prompt);
54
+ if (fs.existsSync(agentPromptPath)) {
55
+ agentInstructions = fs.readFileSync(agentPromptPath, 'utf-8');
56
+ }
57
+ let previousOutput = '';
58
+ if (step.deliverFrom) {
59
+ const prevStepIdx = config.squad.pipeline.steps.findIndex(s => s.agent === step.deliverFrom);
60
+ if (prevStepIdx !== -1) {
61
+ const prevOutputPath = path.join(squadDir, 'output', `step-${String(prevStepIdx + 1).padStart(2, '0')}.md`);
62
+ if (fs.existsSync(prevOutputPath)) {
63
+ previousOutput = fs.readFileSync(prevOutputPath, 'utf-8');
64
+ }
65
+ }
66
+ }
67
+ const squadSkills = config.squad.skills || [];
68
+ const skillInstructions = skills
69
+ .filter(s => squadSkills.includes(s.name))
70
+ .map(s => `### Skill: ${s.name}\n${s.instructions}`)
71
+ .join('\n\n');
72
+ const parts = [
73
+ runnerPrompt,
74
+ '',
75
+ `## Current Task`,
76
+ `- **Squad:** ${config.squad.name} (${config.squad.code})`,
77
+ `- **Agent:** ${agent.name} (${agent.id})`,
78
+ `- **Step ${stepIndex}/${config.squad.pipeline.steps.length}:** ${step.label}`,
79
+ '',
80
+ ];
81
+ if (agentInstructions) {
82
+ parts.push('## Agent Instructions', '', agentInstructions, '');
83
+ }
84
+ if (previousOutput) {
85
+ parts.push(`## Input from ${step.deliverFrom}`, '', previousOutput, '');
86
+ }
87
+ if (skillInstructions) {
88
+ parts.push('## Available Skills', '', skillInstructions, '');
89
+ }
90
+ if (companyContext && !companyContext.includes('NOT CONFIGURED')) {
91
+ parts.push('## Company Context', '', companyContext, '');
92
+ }
93
+ if (squadMemory) {
94
+ parts.push('## Squad Memory (past learnings)', '', squadMemory, '');
95
+ }
96
+ if (bestPractice) {
97
+ parts.push('## Format Best Practices', '', bestPractice, '');
98
+ }
99
+ parts.push('## Output', '', `Write your complete output below. It will be saved to output/step-${String(stepIndex).padStart(2, '0')}.md`);
100
+ return parts.join('\n');
101
+ }
102
+ function spawnClaudeCode(prompt, cwd) {
103
+ return new Promise((resolve, reject) => {
104
+ const child = spawn('claude', ['-p', '--verbose', prompt], {
105
+ cwd,
106
+ stdio: ['pipe', 'pipe', 'pipe'],
107
+ });
108
+ let stdout = '';
109
+ let stderr = '';
110
+ child.stdout?.on('data', (data) => {
111
+ const chunk = data.toString();
112
+ stdout += chunk;
113
+ process.stdout.write(chunk);
114
+ });
115
+ child.stderr?.on('data', (data) => {
116
+ stderr += data.toString();
117
+ });
118
+ child.on('error', (err) => {
119
+ reject(new Error(`Failed to spawn Claude Code: ${err.message}`));
120
+ });
121
+ child.on('exit', (code) => {
122
+ if (code === 0) {
123
+ resolve(stdout);
124
+ }
125
+ else {
126
+ reject(new Error(`Claude Code exited with code ${code}: ${stderr}`));
127
+ }
128
+ });
129
+ });
130
+ }
131
+ export async function runCommand(name) {
132
+ const cwd = process.cwd();
133
+ const squadDir = path.join(cwd, 'squads', name);
134
+ const skillsDir = path.join(cwd, 'skills');
135
+ if (!fs.existsSync(squadDir)) {
136
+ console.error(`Squad "${name}" not found in squads/ directory.`);
137
+ process.exit(1);
138
+ }
139
+ let config;
140
+ try {
141
+ config = loadSquad(squadDir);
142
+ }
143
+ catch (err) {
144
+ console.error(`Failed to load squad config: ${err.message}`);
145
+ process.exit(1);
146
+ }
147
+ const skills = loadSkills(skillsDir);
148
+ const runnerPromptPath = getCoreAsset('runner.pipeline.md');
149
+ let runnerPrompt = '';
150
+ if (fs.existsSync(runnerPromptPath)) {
151
+ runnerPrompt = fs.readFileSync(runnerPromptPath, 'utf-8');
152
+ }
153
+ const existingState = readState(squadDir);
154
+ if (existingState && existingState.status === 'running') {
155
+ console.error(`Squad "${name}" is already running. Use \`expxagents stop ${name}\` first.`);
156
+ process.exit(1);
157
+ }
158
+ const outputDir = getNextVersionDir(squadDir);
159
+ const version = path.basename(outputDir).slice(1); // e.g. "v3" -> "3"
160
+ let state = createInitialState(config);
161
+ state = setSquadStatus(state, 'running');
162
+ state = { ...state, startedAt: new Date().toISOString() };
163
+ writeState(squadDir, state);
164
+ console.log(`\nRunning squad "${config.squad.name}" (${config.squad.code})`);
165
+ console.log(`Pipeline: ${config.squad.pipeline.steps.length} steps\n`);
166
+ const steps = config.squad.pipeline.steps;
167
+ for (let i = 0; i < steps.length; i++) {
168
+ const step = steps[i];
169
+ const stepNumber = i + 1;
170
+ const agent = config.squad.agents.find(a => a.id === step.agent);
171
+ console.log(`--- Step ${stepNumber}/${steps.length}: ${step.label} (${agent.name}) ---\n`);
172
+ state = updateAgentStatus(state, step.agent, 'working');
173
+ state = updateStep(state, stepNumber, step.label);
174
+ writeState(squadDir, state);
175
+ const prompt = buildAgentPrompt(config, step, stepNumber, squadDir, skills, runnerPrompt);
176
+ let output;
177
+ try {
178
+ output = await spawnClaudeCode(prompt, squadDir);
179
+ }
180
+ catch (err) {
181
+ console.error(`\nStep ${stepNumber} failed: ${err.message}`);
182
+ state = updateAgentStatus(state, step.agent, 'idle');
183
+ state = setSquadStatus(state, 'idle');
184
+ writeState(squadDir, state);
185
+ process.exit(1);
186
+ }
187
+ const outputPath = path.join(outputDir, `step-${String(stepNumber).padStart(2, '0')}.md`);
188
+ fs.writeFileSync(outputPath, output, 'utf-8');
189
+ const outputLines = output.trim().split('\n').filter(l => l.trim().length > 0);
190
+ const agentMessage = outputLines[outputLines.length - 1]?.trim() || `Completed ${step.label}`;
191
+ const agentIdx = state.agents.findIndex(a => a.id === step.agent);
192
+ state = {
193
+ ...state,
194
+ agents: state.agents.map((a, idx) => idx === agentIdx ? { ...a, message: agentMessage } : a),
195
+ };
196
+ const nextStep = steps[i + 1];
197
+ const hasHandoff = nextStep && nextStep.deliverFrom === step.agent;
198
+ if (hasHandoff) {
199
+ state = updateAgentStatus(state, step.agent, 'delivering');
200
+ state = setHandoff(state, step.agent, nextStep.agent, agentMessage);
201
+ writeState(squadDir, state);
202
+ console.log(`\nHandoff: ${agent.name} -> ${config.squad.agents.find(a => a.id === nextStep.agent).name}`);
203
+ console.log(`Message: ${agentMessage}\n`);
204
+ await delay(HANDOFF_DELAY_MS);
205
+ state = updateAgentStatus(state, step.agent, 'done');
206
+ writeState(squadDir, state);
207
+ }
208
+ else {
209
+ state = updateAgentStatus(state, step.agent, 'done');
210
+ writeState(squadDir, state);
211
+ }
212
+ console.log(`\nStep ${stepNumber} completed.\n`);
213
+ }
214
+ // Update squad memory after pipeline completion
215
+ const memoryPath = path.join(squadDir, '_memory', 'memories.md');
216
+ if (fs.existsSync(path.dirname(memoryPath))) {
217
+ const timestamp = new Date().toISOString();
218
+ const entry = `\n## Run ${timestamp}\n\n- Steps completed: ${steps.length}\n- Output: output/v${version}/\n`;
219
+ fs.appendFileSync(memoryPath, entry, 'utf-8');
220
+ }
221
+ state = setSquadStatus(state, 'completed');
222
+ state = updateStep(state, steps.length, 'Completed');
223
+ writeState(squadDir, state);
224
+ console.log(`\nSquad "${config.squad.name}" pipeline completed!`);
225
+ console.log(`Output files saved to squads/${name}/output/v${version}/`);
226
+ }
@@ -0,0 +1 @@
1
+ export declare function serverCommand(): Promise<void>;