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
|
-
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
console.log(
|
|
20
|
-
console.log(`${
|
|
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
|
-
${
|
|
25
|
-
${
|
|
26
|
-
${
|
|
27
|
-
${
|
|
28
|
-
${
|
|
29
|
-
${
|
|
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(
|
|
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: `${
|
|
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
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
if (
|
|
116
|
-
console.log(
|
|
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
|
-
|
|
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
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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(
|
|
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(
|
|
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${
|
|
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${
|
|
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
|
-
|
|
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;;;
|
|
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"}
|