expxagents 0.29.2 → 0.29.4

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.
@@ -2,32 +2,57 @@ import readline from 'node:readline';
2
2
  import path from 'node:path';
3
3
  import dotenv from 'dotenv';
4
4
  import { AgentRunner, SessionManager, SUPPORTED_MODELS, DEFAULT_MODEL } from '@expxagents/agent';
5
- const COLORS = {
5
+ import { getVersion } from '../utils/version.js';
6
+ const C = {
6
7
  reset: '\x1b[0m',
7
8
  dim: '\x1b[2m',
8
9
  green: '\x1b[32m',
9
10
  cyan: '\x1b[36m',
10
11
  yellow: '\x1b[33m',
11
12
  magenta: '\x1b[35m',
13
+ blue: '\x1b[34m',
14
+ white: '\x1b[37m',
12
15
  bold: '\x1b[1m',
16
+ bgCyan: '\x1b[46m',
17
+ bgBlue: '\x1b[44m',
13
18
  };
14
- function printBanner(model) {
19
+ function printBanner(model, version) {
15
20
  const modelInfo = SUPPORTED_MODELS.find(m => m.id === model);
16
21
  const label = modelInfo?.name ?? model;
17
- console.log(`\n${COLORS.bold}${COLORS.cyan}ExpxAgents CLI${COLORS.reset} ${COLORS.dim}— powered by OpenRouter${COLORS.reset}`);
18
- console.log(`${COLORS.dim}Model: ${COLORS.yellow}${label}${COLORS.reset}`);
19
- console.log(`${COLORS.dim}Working directory: ${process.cwd()}${COLORS.reset}`);
20
- console.log(`${COLORS.dim}Type ${COLORS.bold}/help${COLORS.reset}${COLORS.dim} for commands, ${COLORS.bold}/quit${COLORS.reset}${COLORS.dim} to exit${COLORS.reset}\n`);
22
+ const cwd = process.cwd();
23
+ const dir = cwd.split('/').slice(-2).join('/');
24
+ console.log('');
25
+ console.log(`${C.cyan} ╔══════════════════════════════════════════════════╗${C.reset}`);
26
+ console.log(`${C.cyan} ║${C.reset} ${C.cyan}║${C.reset}`);
27
+ console.log(`${C.cyan} ║${C.reset} ${C.bold}${C.cyan}▓▓▓ ExpxAgents CLI ▓▓▓${C.reset} ${C.cyan}║${C.reset}`);
28
+ console.log(`${C.cyan} ║${C.reset} ${C.dim}AI Coding Agent — powered by OpenRouter${C.reset} ${C.cyan}║${C.reset}`);
29
+ console.log(`${C.cyan} ║${C.reset} ${C.cyan}║${C.reset}`);
30
+ console.log(`${C.cyan} ╚══════════════════════════════════════════════════╝${C.reset}`);
31
+ console.log('');
32
+ console.log(` ${C.dim}Model${C.reset} ${C.yellow}${label}${C.reset}`);
33
+ console.log(` ${C.dim}Dir${C.reset} ${C.white}${dir}${C.reset}`);
34
+ console.log(` ${C.dim}Version${C.reset} ${C.dim}v${version}${C.reset}`);
35
+ console.log(` ${C.dim}Tools${C.reset} ${C.green}14 tools${C.reset} ${C.dim}(files, bash, web, search)${C.reset}`);
36
+ console.log('');
37
+ console.log(` ${C.dim}Tips: ${C.bold}/help${C.reset}${C.dim} commands • ${C.bold}/models${C.reset}${C.dim} list models • ${C.bold}/quit${C.reset}${C.dim} exit${C.reset}`);
38
+ console.log(` ${C.dim}──────────────────────────────────────────────────${C.reset}`);
39
+ console.log('');
21
40
  }
22
41
  function printHelp() {
23
- console.log(`
24
- ${COLORS.bold}Commands:${COLORS.reset}
25
- ${COLORS.cyan}/help${COLORS.reset} Show this help
26
- ${COLORS.cyan}/model <id>${COLORS.reset} Switch model (e.g. /model openai/gpt-4o)
27
- ${COLORS.cyan}/models${COLORS.reset} List available models
28
- ${COLORS.cyan}/clear${COLORS.reset} Clear conversation history
29
- ${COLORS.cyan}/quit${COLORS.reset} Exit
30
- `);
42
+ console.log('');
43
+ console.log(` ${C.bold}${C.cyan}Commands${C.reset}`);
44
+ console.log(` ${C.dim}──────────────────────────────────────${C.reset}`);
45
+ console.log(` ${C.cyan}/help${C.reset} Show this help`);
46
+ console.log(` ${C.cyan}/model ${C.dim}<id>${C.reset} Switch model`);
47
+ console.log(` ${C.cyan}/models${C.reset} List available models`);
48
+ console.log(` ${C.cyan}/clear${C.reset} Clear conversation`);
49
+ console.log(` ${C.cyan}/quit${C.reset} Exit`);
50
+ console.log('');
51
+ console.log(` ${C.bold}${C.cyan}Shortcuts${C.reset}`);
52
+ console.log(` ${C.dim}──────────────────────────────────────${C.reset}`);
53
+ console.log(` ${C.cyan}Ctrl+C${C.reset} Exit`);
54
+ console.log(` ${C.cyan}Ctrl+D${C.reset} Exit`);
55
+ console.log('');
31
56
  }
32
57
  export async function cliChatCommand(options) {
33
58
  // Load .env from the user's current working directory (explicit path for npx compatibility)
@@ -55,7 +80,7 @@ export async function cliChatCommand(options) {
55
80
  const summary = typeof args === 'object' && args !== null
56
81
  ? Object.entries(args).map(([k, v]) => `${k}=${String(v).slice(0, 60)}`).join(', ')
57
82
  : String(args).slice(0, 80);
58
- process.stderr.write(`${COLORS.dim}[${tool}] ${summary}${COLORS.reset}\n`);
83
+ process.stderr.write(` ${C.dim}${C.cyan}⚡${C.reset} ${C.dim}${tool}${C.reset} ${C.dim}${summary}${C.reset}\n`);
59
84
  },
60
85
  });
61
86
  try {
@@ -69,11 +94,11 @@ export async function cliChatCommand(options) {
69
94
  return;
70
95
  }
71
96
  // Interactive REPL mode
72
- printBanner(model);
97
+ printBanner(model, getVersion());
73
98
  const rl = readline.createInterface({
74
99
  input: process.stdin,
75
100
  output: process.stdout,
76
- prompt: `${COLORS.green}>${COLORS.reset} `,
101
+ prompt: `${C.bold}${C.cyan}❯${C.reset} `,
77
102
  });
78
103
  rl.prompt();
79
104
  rl.on('line', async (line) => {
@@ -82,55 +107,58 @@ export async function cliChatCommand(options) {
82
107
  rl.prompt();
83
108
  return;
84
109
  }
85
- // Handle slash commands
110
+ // Handle slash commands (only internal ones — unknown commands are sent to the agent)
86
111
  if (input.startsWith('/')) {
87
112
  const [cmd, ...args] = input.split(' ');
88
- switch (cmd) {
89
- case '/quit':
90
- case '/exit':
91
- case '/q':
92
- console.log(`${COLORS.dim}Goodbye!${COLORS.reset}`);
93
- process.exit(0);
94
- break;
95
- case '/help':
96
- printHelp();
97
- rl.prompt();
98
- return;
99
- case '/models':
100
- console.log(`\n${COLORS.bold}Available models:${COLORS.reset}`);
101
- for (const m of SUPPORTED_MODELS) {
102
- const active = m.id === model ? ` ${COLORS.green}(active)${COLORS.reset}` : '';
103
- console.log(` ${COLORS.cyan}${m.id}${COLORS.reset} — ${m.name} (${(m.contextWindow / 1000).toFixed(0)}K ctx)${active}`);
104
- }
105
- console.log('');
106
- rl.prompt();
107
- return;
108
- case '/model':
109
- if (!args[0]) {
110
- console.log(`Current model: ${COLORS.yellow}${model}${COLORS.reset}`);
111
- }
112
- else {
113
- model = args[0];
114
- const info = SUPPORTED_MODELS.find(m => m.id === model);
115
- if (info) {
116
- console.log(`${COLORS.green}Switched to ${info.name}${COLORS.reset}`);
113
+ const knownCommands = ['/quit', '/exit', '/q', '/help', '/models', '/model', '/clear'];
114
+ if (!knownCommands.includes(cmd)) {
115
+ // Not a known command — send the full input to the agent (e.g., /expxagents, /commit)
116
+ // Fall through to agent execution below
117
+ }
118
+ else {
119
+ switch (cmd) {
120
+ case '/quit':
121
+ case '/exit':
122
+ case '/q':
123
+ console.log(`\n ${C.dim}Goodbye! ${C.cyan}✦${C.reset}\n`);
124
+ process.exit(0);
125
+ break;
126
+ case '/help':
127
+ printHelp();
128
+ rl.prompt();
129
+ return;
130
+ case '/models':
131
+ console.log(`\n${C.bold}Available models:${C.reset}`);
132
+ for (const m of SUPPORTED_MODELS) {
133
+ const active = m.id === model ? ` ${C.green}(active)${C.reset}` : '';
134
+ console.log(` ${C.cyan}${m.id}${C.reset} — ${m.name} (${(m.contextWindow / 1000).toFixed(0)}K ctx)${active}`);
135
+ }
136
+ console.log('');
137
+ rl.prompt();
138
+ return;
139
+ case '/model':
140
+ if (!args[0]) {
141
+ console.log(`Current model: ${C.yellow}${model}${C.reset}`);
117
142
  }
118
143
  else {
119
- console.log(`${COLORS.yellow}Warning: "${model}" is not in curated list. Tool use may not work.${COLORS.reset}`);
144
+ model = args[0];
145
+ const info = SUPPORTED_MODELS.find(m => m.id === model);
146
+ if (info) {
147
+ console.log(`${C.green}Switched to ${info.name}${C.reset}`);
148
+ }
149
+ else {
150
+ console.log(`${C.yellow}Warning: "${model}" is not in curated list. Tool use may not work.${C.reset}`);
151
+ }
120
152
  }
121
- }
122
- rl.prompt();
123
- return;
124
- case '/clear':
125
- sessionManager.create(sessionId, process.cwd());
126
- console.log(`${COLORS.dim}Conversation cleared.${COLORS.reset}`);
127
- rl.prompt();
128
- return;
129
- default:
130
- console.log(`${COLORS.dim}Unknown command: ${cmd}. Type /help for commands.${COLORS.reset}`);
131
- rl.prompt();
132
- return;
133
- }
153
+ rl.prompt();
154
+ return;
155
+ case '/clear':
156
+ sessionManager.create(sessionId, process.cwd());
157
+ console.log(`${C.dim}Conversation cleared.${C.reset}`);
158
+ rl.prompt();
159
+ return;
160
+ }
161
+ } // close else for known commands
134
162
  }
135
163
  // Send to agent
136
164
  console.log('');
@@ -146,11 +174,11 @@ export async function cliChatCommand(options) {
146
174
  const summary = typeof args === 'object' && args !== null
147
175
  ? Object.entries(args).map(([k, v]) => `${k}=${String(v).slice(0, 60)}`).join(', ')
148
176
  : String(args).slice(0, 80);
149
- process.stderr.write(`${COLORS.dim}[${tool}] ${summary}${COLORS.reset}\n`);
177
+ process.stderr.write(` ${C.dim}${C.cyan}⚡${C.reset} ${C.dim}${tool}${C.reset} ${C.dim}${summary}${C.reset}\n`);
150
178
  },
151
179
  onAskUser: async (question) => {
152
180
  return new Promise((resolve) => {
153
- rl.question(`${COLORS.magenta}Agent asks:${COLORS.reset} ${question}\n${COLORS.green}>${COLORS.reset} `, resolve);
181
+ rl.question(`\n ${C.magenta}? ${question}${C.reset}\n ${C.bold}${C.cyan}❯${C.reset} `, resolve);
154
182
  });
155
183
  },
156
184
  });
@@ -159,12 +187,12 @@ export async function cliChatCommand(options) {
159
187
  console.log('\n');
160
188
  }
161
189
  catch (err) {
162
- console.error(`\n${COLORS.yellow}Error: ${err instanceof Error ? err.message : String(err)}${COLORS.reset}\n`);
190
+ console.error(`\n${C.yellow}Error: ${err instanceof Error ? err.message : String(err)}${C.reset}\n`);
163
191
  }
164
192
  rl.prompt();
165
193
  });
166
194
  rl.on('close', () => {
167
- console.log(`\n${COLORS.dim}Goodbye!${COLORS.reset}`);
195
+ console.log(`\n${C.dim}Goodbye!${C.reset}`);
168
196
  process.exit(0);
169
197
  });
170
198
  }
@@ -1,5 +1,56 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ /**
4
+ * Loads project context files (CLAUDE.md, AGENTS.md, README.md, etc.)
5
+ * from the working directory, similar to how Claude Code loads CLAUDE.md.
6
+ */
7
+ function loadProjectContext(cwd) {
8
+ const contextFiles = [
9
+ 'CLAUDE.md',
10
+ 'AGENTS.md',
11
+ 'GEMINI.md',
12
+ '.claude/rules/*.md',
13
+ ];
14
+ const sections = [];
15
+ for (const pattern of contextFiles) {
16
+ if (pattern.includes('*')) {
17
+ // Glob pattern — expand manually
18
+ const dir = path.join(cwd, path.dirname(pattern));
19
+ const ext = path.extname(pattern);
20
+ if (fs.existsSync(dir)) {
21
+ try {
22
+ const files = fs.readdirSync(dir).filter(f => f.endsWith(ext)).sort();
23
+ for (const file of files) {
24
+ const content = fs.readFileSync(path.join(dir, file), 'utf-8').trim();
25
+ if (content) {
26
+ sections.push(`### ${path.dirname(pattern)}/${file}\n\n${content}`);
27
+ }
28
+ }
29
+ }
30
+ catch { /* skip unreadable dirs */ }
31
+ }
32
+ }
33
+ else {
34
+ const filePath = path.join(cwd, pattern);
35
+ if (fs.existsSync(filePath)) {
36
+ try {
37
+ const content = fs.readFileSync(filePath, 'utf-8').trim();
38
+ if (content) {
39
+ sections.push(`### ${pattern}\n\n${content}`);
40
+ }
41
+ }
42
+ catch { /* skip unreadable files */ }
43
+ }
44
+ }
45
+ }
46
+ if (sections.length === 0)
47
+ return '';
48
+ return `\n\n## Project Context\n\nThe following project documentation was loaded from the working directory. Use this to understand the project structure, conventions, and rules.\n\n${sections.join('\n\n---\n\n')}`;
49
+ }
1
50
  export function buildSystemPrompt(cwd) {
2
- return `You are an AI coding agent running in the user's project directory.
51
+ const projectContext = loadProjectContext(cwd);
52
+ const dirName = path.basename(cwd);
53
+ return `You are an AI coding agent working on the "${dirName}" project.
3
54
  You have access to tools for reading, writing, and searching files, running shell commands, and fetching web content.
4
55
 
5
56
  Working directory: ${cwd}
@@ -14,10 +65,12 @@ Working directory: ${cwd}
14
65
  - When you encounter an error, diagnose the root cause before retrying
15
66
  - Do not modify files you were not asked to change
16
67
  - Prefer small, focused changes over large rewrites
68
+ - Follow the project conventions described in the project context below
69
+ - When the user references project-specific commands or features, use the project context to answer accurately
17
70
 
18
71
  ## Output
19
72
 
20
73
  When you have completed the task, provide a brief summary of what you did.
21
- Do not wrap your final response in markdown code blocks unless the user asked for code.`;
74
+ Do not wrap your final response in markdown code blocks unless the user asked for code.${projectContext}`;
22
75
  }
23
76
  //# sourceMappingURL=system-prompt.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"system-prompt.js","sourceRoot":"","sources":["../src/system-prompt.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC3C,OAAO;;;qBAGY,GAAG;;;;;;;;;;;;;;;;wFAgBgE,CAAC;AACzF,CAAC"}
1
+ {"version":3,"file":"system-prompt.js","sourceRoot":"","sources":["../src/system-prompt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B;;;GAGG;AACH,SAAS,kBAAkB,CAAC,GAAW;IACrC,MAAM,YAAY,GAAG;QACnB,WAAW;QACX,WAAW;QACX,WAAW;QACX,oBAAoB;KACrB,CAAC;IAEF,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,KAAK,MAAM,OAAO,IAAI,YAAY,EAAE,CAAC;QACnC,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1B,iCAAiC;YACjC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;YAClD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YAClC,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBACvB,IAAI,CAAC;oBACH,MAAM,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;oBACtE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;wBACzB,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;wBACtE,IAAI,OAAO,EAAE,CAAC;4BACZ,QAAQ,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,IAAI,OAAO,OAAO,EAAE,CAAC,CAAC;wBACtE,CAAC;oBACH,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC,CAAC,0BAA0B,CAAC,CAAC;YACxC,CAAC;QACH,CAAC;aAAM,CAAC;YACN,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;YACzC,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC5B,IAAI,CAAC;oBACH,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;oBAC1D,IAAI,OAAO,EAAE,CAAC;wBACZ,QAAQ,CAAC,IAAI,CAAC,OAAO,OAAO,OAAO,OAAO,EAAE,CAAC,CAAC;oBAChD,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC,CAAC,2BAA2B,CAAC,CAAC;YACzC,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAErC,OAAO,iLAAiL,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC;AACzN,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC3C,MAAM,cAAc,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;IAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;IAEnC,OAAO,8CAA8C,OAAO;;;qBAGzC,GAAG;;;;;;;;;;;;;;;;;;yFAkBiE,cAAc,EAAE,CAAC;AAC1G,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expxagents",
3
- "version": "0.29.2",
3
+ "version": "0.29.4",
4
4
  "description": "Multi-agent orchestration platform for AI squads",
5
5
  "author": "ExpxAgents",
6
6
  "license": "MIT",