gitarsenal-cli 1.9.83 ā 1.9.85
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/.venv_status.json +1 -1
- package/bin/gitarsenal.js +110 -59
- package/kill_claude/README.md +2 -2
- package/kill_claude/TUI_IMPROVEMENTS.md +130 -0
- package/kill_claude/claude_code_agent.py +430 -126
- package/kill_claude/requirements.txt +3 -1
- package/kill_claude/tools/bash_tool.py +1 -1
- package/lib/sandbox.js +8 -4
- package/package.json +1 -1
- package/kill_claude/tools/__pycache__/bash_output_tool.cpython-312.pyc +0 -0
- package/kill_claude/tools/__pycache__/bash_output_tool.cpython-313.pyc +0 -0
- package/kill_claude/tools/__pycache__/bash_tool.cpython-312.pyc +0 -0
- package/kill_claude/tools/__pycache__/bash_tool.cpython-313.pyc +0 -0
- package/kill_claude/tools/__pycache__/edit_tool.cpython-312.pyc +0 -0
- package/kill_claude/tools/__pycache__/edit_tool.cpython-313.pyc +0 -0
- package/kill_claude/tools/__pycache__/exit_plan_mode_tool.cpython-312.pyc +0 -0
- package/kill_claude/tools/__pycache__/exit_plan_mode_tool.cpython-313.pyc +0 -0
- package/kill_claude/tools/__pycache__/glob_tool.cpython-312.pyc +0 -0
- package/kill_claude/tools/__pycache__/glob_tool.cpython-313.pyc +0 -0
- package/kill_claude/tools/__pycache__/grep_tool.cpython-312.pyc +0 -0
- package/kill_claude/tools/__pycache__/grep_tool.cpython-313.pyc +0 -0
- package/kill_claude/tools/__pycache__/kill_bash_tool.cpython-312.pyc +0 -0
- package/kill_claude/tools/__pycache__/kill_bash_tool.cpython-313.pyc +0 -0
- package/kill_claude/tools/__pycache__/ls_tool.cpython-312.pyc +0 -0
- package/kill_claude/tools/__pycache__/ls_tool.cpython-313.pyc +0 -0
- package/kill_claude/tools/__pycache__/multiedit_tool.cpython-312.pyc +0 -0
- package/kill_claude/tools/__pycache__/multiedit_tool.cpython-313.pyc +0 -0
- package/kill_claude/tools/__pycache__/notebook_edit_tool.cpython-312.pyc +0 -0
- package/kill_claude/tools/__pycache__/notebook_edit_tool.cpython-313.pyc +0 -0
- package/kill_claude/tools/__pycache__/read_tool.cpython-312.pyc +0 -0
- package/kill_claude/tools/__pycache__/read_tool.cpython-313.pyc +0 -0
- package/kill_claude/tools/__pycache__/task_tool.cpython-312.pyc +0 -0
- package/kill_claude/tools/__pycache__/task_tool.cpython-313.pyc +0 -0
- package/kill_claude/tools/__pycache__/todo_write_tool.cpython-312.pyc +0 -0
- package/kill_claude/tools/__pycache__/todo_write_tool.cpython-313.pyc +0 -0
- package/kill_claude/tools/__pycache__/web_fetch_tool.cpython-312.pyc +0 -0
- package/kill_claude/tools/__pycache__/web_fetch_tool.cpython-313.pyc +0 -0
- package/kill_claude/tools/__pycache__/web_search_tool.cpython-312.pyc +0 -0
- package/kill_claude/tools/__pycache__/web_search_tool.cpython-313.pyc +0 -0
- package/kill_claude/tools/__pycache__/write_tool.cpython-312.pyc +0 -0
- package/kill_claude/tools/__pycache__/write_tool.cpython-313.pyc +0 -0
package/.venv_status.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"created":"2025-08-
|
|
1
|
+
{"created":"2025-08-20T12:21:13.646Z","packages":["modal","gitingest","requests","anthropic"],"uv_version":"uv 0.8.4 (Homebrew 2025-07-30)"}
|
package/bin/gitarsenal.js
CHANGED
|
@@ -208,83 +208,113 @@ async function previewRecommendations(repoUrl, optsOrShowSummary = true) {
|
|
|
208
208
|
|
|
209
209
|
function printGpuTorchCudaSummary(result) {
|
|
210
210
|
try {
|
|
211
|
-
console.log(
|
|
212
|
-
console.log('
|
|
211
|
+
console.log();
|
|
212
|
+
console.log(chalk.bold.cyan(' āļø Analysis Results'));
|
|
213
|
+
console.log(chalk.dim(' āāāāāāāāāāāāāāāāā'));
|
|
214
|
+
console.log();
|
|
213
215
|
|
|
214
216
|
const cuda = result.cudaRecommendation;
|
|
215
217
|
if (cuda) {
|
|
216
|
-
console.log(chalk.bold('šÆ CUDA
|
|
217
|
-
if (cuda.recommendedCudaVersion)
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
if (cuda.
|
|
218
|
+
console.log(chalk.bold.yellow(' šÆ CUDA Configuration'));
|
|
219
|
+
if (cuda.recommendedCudaVersion) {
|
|
220
|
+
console.log(chalk.dim(' Version: ') + chalk.white(cuda.recommendedCudaVersion));
|
|
221
|
+
}
|
|
222
|
+
if (Array.isArray(cuda.compatibleTorchVersions) && cuda.compatibleTorchVersions.length) {
|
|
223
|
+
console.log(chalk.dim(' Torch: ') + chalk.white(cuda.compatibleTorchVersions.join(', ')));
|
|
224
|
+
}
|
|
225
|
+
if (cuda.dockerImage) {
|
|
226
|
+
console.log(chalk.dim(' Image: ') + chalk.white(cuda.dockerImage));
|
|
227
|
+
}
|
|
221
228
|
if (Array.isArray(cuda.installCommands) && cuda.installCommands.length) {
|
|
222
|
-
console.log('
|
|
223
|
-
cuda.installCommands.forEach((c) =>
|
|
229
|
+
console.log(chalk.dim(' Commands:'));
|
|
230
|
+
cuda.installCommands.forEach((c) => {
|
|
231
|
+
console.log(chalk.dim(' $ ') + chalk.cyan(c));
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
if (cuda.notes) {
|
|
235
|
+
console.log(chalk.dim(' Notes: ') + chalk.gray(cuda.notes));
|
|
224
236
|
}
|
|
225
|
-
if (cuda.notes) console.log(` - Notes: ${cuda.notes}`);
|
|
226
237
|
console.log();
|
|
227
238
|
}
|
|
228
239
|
|
|
229
240
|
const torch = result.torchRecommendation;
|
|
230
241
|
if (torch) {
|
|
231
|
-
console.log(chalk.bold('š„ PyTorch
|
|
232
|
-
if (torch.recommendedTorchVersion)
|
|
233
|
-
|
|
242
|
+
console.log(chalk.bold.red(' š„ PyTorch Setup'));
|
|
243
|
+
if (torch.recommendedTorchVersion) {
|
|
244
|
+
console.log(chalk.dim(' Version: ') + chalk.white(torch.recommendedTorchVersion));
|
|
245
|
+
}
|
|
246
|
+
if (torch.cudaVariant) {
|
|
247
|
+
console.log(chalk.dim(' CUDA: ') + chalk.white(torch.cudaVariant));
|
|
248
|
+
}
|
|
234
249
|
if (torch.pipInstallCommand) {
|
|
235
|
-
console.log('
|
|
236
|
-
console.log(
|
|
250
|
+
console.log(chalk.dim(' Install:'));
|
|
251
|
+
console.log(chalk.dim(' $ ') + chalk.cyan(torch.pipInstallCommand));
|
|
252
|
+
}
|
|
253
|
+
if (Array.isArray(torch.extraPackages) && torch.extraPackages.length) {
|
|
254
|
+
console.log(chalk.dim(' Extras: ') + chalk.white(torch.extraPackages.join(', ')));
|
|
255
|
+
}
|
|
256
|
+
if (torch.notes) {
|
|
257
|
+
console.log(chalk.dim(' Notes: ') + chalk.gray(torch.notes));
|
|
237
258
|
}
|
|
238
|
-
if (Array.isArray(torch.extraPackages) && torch.extraPackages.length)
|
|
239
|
-
console.log(` - Extra Packages: ${torch.extraPackages.join(', ')}`);
|
|
240
|
-
if (torch.notes) console.log(` - Notes: ${torch.notes}`);
|
|
241
259
|
console.log();
|
|
242
260
|
}
|
|
243
261
|
|
|
244
262
|
const gpu = result.gpuRecommendation;
|
|
245
263
|
if (gpu) {
|
|
246
|
-
console.log(chalk.bold('š„ļø
|
|
247
|
-
if (gpu.minimumVramGb !== undefined)
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
if (
|
|
251
|
-
console.log(
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
if (gpu.
|
|
264
|
+
console.log(chalk.bold.green(' š„ļø Hardware Requirements'));
|
|
265
|
+
if (gpu.minimumVramGb !== undefined) {
|
|
266
|
+
console.log(chalk.dim(' Min VRAM: ') + chalk.white(`${gpu.minimumVramGb} GB`));
|
|
267
|
+
}
|
|
268
|
+
if (gpu.recommendedVramGb !== undefined) {
|
|
269
|
+
console.log(chalk.dim(' Optimal VRAM: ') + chalk.white(`${gpu.recommendedVramGb} GB`));
|
|
270
|
+
}
|
|
271
|
+
if (gpu.minComputeCapability) {
|
|
272
|
+
console.log(chalk.dim(' Min Compute: ') + chalk.white(gpu.minComputeCapability));
|
|
273
|
+
}
|
|
274
|
+
if (Array.isArray(gpu.recommendedModels) && gpu.recommendedModels.length) {
|
|
275
|
+
console.log(chalk.dim(' Recommended: ') + chalk.white(gpu.recommendedModels.join(', ')));
|
|
276
|
+
}
|
|
277
|
+
if (Array.isArray(gpu.budgetOptions) && gpu.budgetOptions.length) {
|
|
278
|
+
console.log(chalk.dim(' Budget: ') + chalk.white(gpu.budgetOptions.join(', ')));
|
|
279
|
+
}
|
|
280
|
+
if (Array.isArray(gpu.cloudInstances) && gpu.cloudInstances.length) {
|
|
281
|
+
console.log(chalk.dim(' Cloud: ') + chalk.white(gpu.cloudInstances.join(', ')));
|
|
282
|
+
}
|
|
283
|
+
if (gpu.notes) {
|
|
284
|
+
console.log(chalk.dim(' Notes: ') + chalk.gray(gpu.notes));
|
|
285
|
+
}
|
|
257
286
|
console.log();
|
|
258
287
|
}
|
|
259
288
|
|
|
260
|
-
//
|
|
289
|
+
// Enhanced API key display
|
|
261
290
|
if (result.requiredApiKeys && Array.isArray(result.requiredApiKeys) && result.requiredApiKeys.length > 0) {
|
|
262
|
-
// Separate critical and optional API keys
|
|
263
291
|
const criticalKeys = result.requiredApiKeys.filter(key => key.priority === 'critical' || key.required);
|
|
264
292
|
const optionalKeys = result.requiredApiKeys.filter(key => key.priority === 'optional' || !key.required);
|
|
265
293
|
|
|
266
294
|
if (criticalKeys.length > 0) {
|
|
267
|
-
console.log(chalk.bold('š
|
|
295
|
+
console.log(chalk.bold.red(' š Required API Keys'));
|
|
268
296
|
criticalKeys.forEach(apiKey => {
|
|
269
|
-
console.log(
|
|
270
|
-
console.log(
|
|
271
|
-
console.log(
|
|
272
|
-
if (apiKey.
|
|
273
|
-
|
|
274
|
-
|
|
297
|
+
console.log(chalk.dim(' ⢠') + chalk.white(apiKey.name) + ' ' + chalk.red('(required)'));
|
|
298
|
+
console.log(chalk.dim(' Service: ') + chalk.gray(apiKey.service));
|
|
299
|
+
console.log(chalk.dim(' Purpose: ') + chalk.gray(apiKey.description));
|
|
300
|
+
if (apiKey.documentation_url) {
|
|
301
|
+
console.log(chalk.dim(' Docs: ') + chalk.blue(apiKey.documentation_url));
|
|
302
|
+
}
|
|
275
303
|
});
|
|
304
|
+
console.log();
|
|
276
305
|
}
|
|
277
306
|
|
|
278
307
|
if (optionalKeys.length > 0) {
|
|
279
|
-
console.log(chalk.bold('š§
|
|
308
|
+
console.log(chalk.bold.yellow(' š§ Optional Enhancements'));
|
|
280
309
|
optionalKeys.forEach(apiKey => {
|
|
281
|
-
console.log(
|
|
282
|
-
console.log(
|
|
283
|
-
console.log(
|
|
284
|
-
if (apiKey.
|
|
285
|
-
|
|
286
|
-
|
|
310
|
+
console.log(chalk.dim(' ⢠') + chalk.white(apiKey.name) + ' ' + chalk.yellow('(optional)'));
|
|
311
|
+
console.log(chalk.dim(' Service: ') + chalk.gray(apiKey.service));
|
|
312
|
+
console.log(chalk.dim(' Purpose: ') + chalk.gray(apiKey.description));
|
|
313
|
+
if (apiKey.documentation_url) {
|
|
314
|
+
console.log(chalk.dim(' Docs: ') + chalk.blue(apiKey.documentation_url));
|
|
315
|
+
}
|
|
287
316
|
});
|
|
317
|
+
console.log();
|
|
288
318
|
}
|
|
289
319
|
}
|
|
290
320
|
} catch {}
|
|
@@ -646,11 +676,11 @@ async function fetchFullSetupAndRecs(repoUrl, storedCredentials = null) {
|
|
|
646
676
|
console.log(chalk.gray('š DEBUG: Received response from API:'));
|
|
647
677
|
console.log(chalk.gray(' - Response has commands:', !!data.commands));
|
|
648
678
|
console.log(chalk.gray(' - Commands count:', data.commands ? data.commands.length : 0));
|
|
649
|
-
console.log(chalk.gray(' - Response has API keys:', !!data.requiredApiKeys));
|
|
650
|
-
console.log(chalk.gray(' - API keys count:', data.requiredApiKeys ? data.requiredApiKeys.length : 0));
|
|
651
|
-
console.log(chalk.gray(' - Response has GPU rec:', !!data.gpuRecommendation));
|
|
652
|
-
console.log(chalk.gray(' - Response has CUDA rec:', !!data.cudaRecommendation));
|
|
653
|
-
console.log(chalk.gray(' - Response has Torch rec:', !!data.torchRecommendation));
|
|
679
|
+
// console.log(chalk.gray(' - Response has API keys:', !!data.requiredApiKeys));
|
|
680
|
+
// console.log(chalk.gray(' - API keys count:', data.requiredApiKeys ? data.requiredApiKeys.length : 0));
|
|
681
|
+
// console.log(chalk.gray(' - Response has GPU rec:', !!data.gpuRecommendation));
|
|
682
|
+
// console.log(chalk.gray(' - Response has CUDA rec:', !!data.cudaRecommendation));
|
|
683
|
+
// console.log(chalk.gray(' - Response has Torch rec:', !!data.torchRecommendation));
|
|
654
684
|
spinner.succeed('Repository analysis complete');
|
|
655
685
|
return data;
|
|
656
686
|
}
|
|
@@ -673,7 +703,7 @@ async function fetchFullSetupAndRecs(repoUrl, storedCredentials = null) {
|
|
|
673
703
|
// Function to send user data to web application
|
|
674
704
|
async function sendUserData(userId, userName, userEmail) {
|
|
675
705
|
try {
|
|
676
|
-
console.log(chalk.blue(
|
|
706
|
+
console.log(chalk.blue(`Attempting to register user: ${userName} (${userId})`));
|
|
677
707
|
|
|
678
708
|
const userData = {
|
|
679
709
|
email: userEmail, // Use userId as email (assuming it's an email)
|
|
@@ -701,7 +731,7 @@ async function sendUserData(userId, userName, userEmail) {
|
|
|
701
731
|
webhookUrl = process.env.GITARSENAL_WEBHOOK_URL;
|
|
702
732
|
}
|
|
703
733
|
|
|
704
|
-
console.log(chalk.gray(
|
|
734
|
+
console.log(chalk.gray(`Data: ${data}`));
|
|
705
735
|
|
|
706
736
|
const urlObj = new URL(webhookUrl);
|
|
707
737
|
const options = {
|
|
@@ -729,10 +759,10 @@ async function sendUserData(userId, userName, userEmail) {
|
|
|
729
759
|
res.on('end', () => {
|
|
730
760
|
|
|
731
761
|
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
732
|
-
console.log(chalk.green('
|
|
762
|
+
console.log(chalk.green('User registered on GitArsenal dashboard'));
|
|
733
763
|
resolve(responseData);
|
|
734
764
|
} else if (res.statusCode === 409) {
|
|
735
|
-
console.log(chalk.green('
|
|
765
|
+
console.log(chalk.green('User already exists on GitArsenal dashboard'));
|
|
736
766
|
resolve(responseData);
|
|
737
767
|
} else {
|
|
738
768
|
console.log(chalk.yellow(`ā ļø Failed to register user (status: ${res.statusCode})`));
|
|
@@ -970,6 +1000,7 @@ activateVirtualEnvironment();
|
|
|
970
1000
|
// Check for updates
|
|
971
1001
|
updateNotifier({ pkg }).notify();
|
|
972
1002
|
|
|
1003
|
+
|
|
973
1004
|
// Display banner
|
|
974
1005
|
|
|
975
1006
|
try {
|
|
@@ -986,6 +1017,26 @@ try {
|
|
|
986
1017
|
}));
|
|
987
1018
|
}
|
|
988
1019
|
|
|
1020
|
+
// Display info box first
|
|
1021
|
+
console.log(boxen(
|
|
1022
|
+
chalk.bold.cyan('š GitArsenal - GPU-Accelerated Development Environments') + '\n\n' +
|
|
1023
|
+
chalk.white('Secure, cloud-based development environments with GPU acceleration.') + '\n' +
|
|
1024
|
+
chalk.white('Everything runs safely in isolated containers - no risk to your system.') + '\n\n' +
|
|
1025
|
+
chalk.green('ā
No local installation required') + '\n' +
|
|
1026
|
+
chalk.green('ā
Instant access to powerful GPUs') + '\n' +
|
|
1027
|
+
chalk.green('ā
Pre-configured for any repository') + '\n' +
|
|
1028
|
+
chalk.green('ā
Secure cloud isolation') + '\n\n' +
|
|
1029
|
+
chalk.gray('Your code is processed securely in the cloud.') + '\n' +
|
|
1030
|
+
chalk.gray('No worries about dependencies or compatibility issues.'),
|
|
1031
|
+
{
|
|
1032
|
+
padding: 1,
|
|
1033
|
+
margin: 0,
|
|
1034
|
+
borderStyle: 'round',
|
|
1035
|
+
borderColor: 'cyan',
|
|
1036
|
+
fullscreen: true
|
|
1037
|
+
}
|
|
1038
|
+
));
|
|
1039
|
+
|
|
989
1040
|
// Set up main command
|
|
990
1041
|
program
|
|
991
1042
|
.version(version)
|
|
@@ -1070,7 +1121,7 @@ async function runContainerCommand(options) {
|
|
|
1070
1121
|
const { userId, userName, userEmail } = userCredentials;
|
|
1071
1122
|
|
|
1072
1123
|
// Register user on dashboard immediately after collecting credentials
|
|
1073
|
-
console.log(chalk.blue('\
|
|
1124
|
+
console.log(chalk.blue('\nRegistering user on GitArsenal dashboard...'));
|
|
1074
1125
|
// Send user data immediately so the dashboard records users
|
|
1075
1126
|
await sendUserData(userId, userName, userEmail);
|
|
1076
1127
|
|
|
@@ -1317,7 +1368,7 @@ async function handleKeysAdd(options) {
|
|
|
1317
1368
|
const { userId, userName } = userCredentials;
|
|
1318
1369
|
|
|
1319
1370
|
// Register user on dashboard
|
|
1320
|
-
console.log(chalk.blue('\
|
|
1371
|
+
console.log(chalk.blue('\nRegistering user on GitArsenal dashboard...'));
|
|
1321
1372
|
// Note: User data will be sent by the Python script after authentication
|
|
1322
1373
|
// await sendUserData(userId, userName);
|
|
1323
1374
|
|
|
@@ -1393,7 +1444,7 @@ async function handleKeysList() {
|
|
|
1393
1444
|
const { userId, userName } = userCredentials;
|
|
1394
1445
|
|
|
1395
1446
|
// Register user on dashboard
|
|
1396
|
-
console.log(chalk.blue('\
|
|
1447
|
+
console.log(chalk.blue('\nRegistering user on GitArsenal dashboard...'));
|
|
1397
1448
|
// Note: User data will be sent by the Python script after authentication
|
|
1398
1449
|
// await sendUserData(userId, userName);
|
|
1399
1450
|
|
|
@@ -1429,7 +1480,7 @@ async function handleKeysView(options) {
|
|
|
1429
1480
|
const { userId, userName } = userCredentials;
|
|
1430
1481
|
|
|
1431
1482
|
// Register user on dashboard
|
|
1432
|
-
console.log(chalk.blue('\
|
|
1483
|
+
console.log(chalk.blue('\nRegistering user on GitArsenal dashboard...'));
|
|
1433
1484
|
// Note: User data will be sent by the Python script after authentication
|
|
1434
1485
|
// await sendUserData(userId, userName);
|
|
1435
1486
|
|
|
@@ -1481,7 +1532,7 @@ async function handleKeysDelete(options) {
|
|
|
1481
1532
|
const { userId, userName } = userCredentials;
|
|
1482
1533
|
|
|
1483
1534
|
// Register user on dashboard
|
|
1484
|
-
console.log(chalk.blue('\
|
|
1535
|
+
console.log(chalk.blue('\nRegistering user on GitArsenal dashboard...'));
|
|
1485
1536
|
// Note: User data will be sent by the Python script after authentication
|
|
1486
1537
|
// await sendUserData(userId, userName);
|
|
1487
1538
|
|
package/kill_claude/README.md
CHANGED
|
@@ -69,7 +69,7 @@ kill_claude/
|
|
|
69
69
|
1. **Clone or download** all the files to a directory
|
|
70
70
|
2. **Install dependencies** (if needed):
|
|
71
71
|
```bash
|
|
72
|
-
pip install dataclasses # Python 3.6 only, built-in for 3.7+
|
|
72
|
+
uv pip install dataclasses # Python 3.6 only, built-in for 3.7+
|
|
73
73
|
```
|
|
74
74
|
3. **Make the main script executable**:
|
|
75
75
|
```bash
|
|
@@ -138,7 +138,7 @@ python example_usage.py
|
|
|
138
138
|
### Code Execution
|
|
139
139
|
- `"run pytest"` - Execute commands
|
|
140
140
|
- `"git status"` - Git operations
|
|
141
|
-
- `"
|
|
141
|
+
- `"uv pip install express"` - Package management
|
|
142
142
|
|
|
143
143
|
### Web Access
|
|
144
144
|
- `"fetch https://api.github.com"` - Fetch web content
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# šØ TUI Improvements for Claude Code Agent
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The Claude Code Agent now features a beautiful Terminal User Interface (TUI) powered by [Typer](https://typer.tiangolo.com/) and [Rich](https://rich.readthedocs.io/), providing:
|
|
6
|
+
|
|
7
|
+
- **Beautiful colored output** with syntax highlighting
|
|
8
|
+
- **Professional command-line interface** with proper help system
|
|
9
|
+
- **Rich formatting** for tool execution results
|
|
10
|
+
- **Progress indicators** for long-running operations
|
|
11
|
+
- **Structured panels** for better information organization
|
|
12
|
+
|
|
13
|
+
## New Commands
|
|
14
|
+
|
|
15
|
+
### Interactive Mode
|
|
16
|
+
```bash
|
|
17
|
+
python claude_code_agent.py interactive
|
|
18
|
+
# or
|
|
19
|
+
python claude_code_agent.py interactive --api-key your_key
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Single Query
|
|
23
|
+
```bash
|
|
24
|
+
python claude_code_agent.py query "your question here"
|
|
25
|
+
# or
|
|
26
|
+
python claude_code_agent.py query "read main.py" --api-key your_key
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Setup Information
|
|
30
|
+
```bash
|
|
31
|
+
python claude_code_agent.py setup
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Help
|
|
35
|
+
```bash
|
|
36
|
+
python claude_code_agent.py --help
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Key Improvements
|
|
40
|
+
|
|
41
|
+
### 1. Tool Execution Display
|
|
42
|
+
- **Before**: Simple print statements with basic emojis
|
|
43
|
+
- **After**: Rich panels with proper formatting, parameter tables, and progress indicators
|
|
44
|
+
|
|
45
|
+
### 2. File Content Display
|
|
46
|
+
- **Before**: Plain text output
|
|
47
|
+
- **After**: Syntax highlighted code with proper line numbers and file type detection
|
|
48
|
+
|
|
49
|
+
### 3. Error Handling
|
|
50
|
+
- **Before**: Plain error messages
|
|
51
|
+
- **After**: Beautiful error panels with helpful instructions
|
|
52
|
+
|
|
53
|
+
### 4. Help System
|
|
54
|
+
- **Before**: Single text block
|
|
55
|
+
- **After**: Organized columns with categorized commands and examples
|
|
56
|
+
|
|
57
|
+
### 5. Status Display
|
|
58
|
+
- **Before**: Simple text list
|
|
59
|
+
- **After**: Professional tables and trees showing system information
|
|
60
|
+
|
|
61
|
+
### 6. Interactive Mode
|
|
62
|
+
- **Before**: Basic input/output
|
|
63
|
+
- **After**: Rich prompts, welcome banners, and formatted responses
|
|
64
|
+
|
|
65
|
+
## Technical Details
|
|
66
|
+
|
|
67
|
+
### Dependencies Added
|
|
68
|
+
- `typer>=0.12.0` - Modern CLI framework
|
|
69
|
+
- `rich>=13.0.0` - Rich text formatting and TUI components
|
|
70
|
+
|
|
71
|
+
### Key Features Implemented
|
|
72
|
+
|
|
73
|
+
#### Rich Console Integration
|
|
74
|
+
- All output now uses Rich Console for beautiful formatting
|
|
75
|
+
- Automatic color detection and fallback for different terminals
|
|
76
|
+
- Consistent styling across all output types
|
|
77
|
+
|
|
78
|
+
#### Smart Content Formatting
|
|
79
|
+
- **Code files**: Automatic syntax highlighting based on file extension
|
|
80
|
+
- **Directory listings**: Clean tree-like structure with proper indentation
|
|
81
|
+
- **Command output**: Color-coded based on success/error status
|
|
82
|
+
- **Todo lists**: Professional tables with status indicators
|
|
83
|
+
|
|
84
|
+
#### Progress Indicators
|
|
85
|
+
- Spinning progress indicators for tool execution
|
|
86
|
+
- Non-blocking progress display that disappears when complete
|
|
87
|
+
- Clear visual feedback for long-running operations
|
|
88
|
+
|
|
89
|
+
#### Error Handling
|
|
90
|
+
- Beautiful error panels with clear instructions
|
|
91
|
+
- Structured error information with proper styling
|
|
92
|
+
- Helpful suggestions for common configuration issues
|
|
93
|
+
|
|
94
|
+
### Backwards Compatibility
|
|
95
|
+
|
|
96
|
+
The agent maintains full backwards compatibility:
|
|
97
|
+
- `python claude_code_agent.py` still starts interactive mode
|
|
98
|
+
- Single arguments are still treated as queries
|
|
99
|
+
- All existing functionality preserved
|
|
100
|
+
|
|
101
|
+
## Usage Examples
|
|
102
|
+
|
|
103
|
+
### Beautiful File Reading
|
|
104
|
+
When you run `query "read main.py"`, you now see:
|
|
105
|
+
- Syntax highlighted code
|
|
106
|
+
- Proper line numbers
|
|
107
|
+
- Clean panel borders
|
|
108
|
+
- File path information
|
|
109
|
+
|
|
110
|
+
### Enhanced Todo Management
|
|
111
|
+
Todo lists are now displayed as professional tables with:
|
|
112
|
+
- Status indicators (ā³ Pending, š In Progress, ā
Completed)
|
|
113
|
+
- Organized columns
|
|
114
|
+
- Clean borders and styling
|
|
115
|
+
|
|
116
|
+
### Improved Error Messages
|
|
117
|
+
Configuration errors show:
|
|
118
|
+
- Clear problem description
|
|
119
|
+
- Step-by-step solutions
|
|
120
|
+
- Proper color coding
|
|
121
|
+
- Professional panel layout
|
|
122
|
+
|
|
123
|
+
## Future Enhancements
|
|
124
|
+
|
|
125
|
+
The TUI foundation enables future improvements like:
|
|
126
|
+
- Interactive file selection
|
|
127
|
+
- Real-time command output streaming
|
|
128
|
+
- Tabbed interfaces for multiple operations
|
|
129
|
+
- Interactive configuration wizard
|
|
130
|
+
- Dashboard views for project statistics
|
|
@@ -24,6 +24,17 @@ from typing import List, Dict, Any, Optional, Union
|
|
|
24
24
|
from dataclasses import dataclass
|
|
25
25
|
from enum import Enum
|
|
26
26
|
import anthropic
|
|
27
|
+
import typer
|
|
28
|
+
from rich.console import Console
|
|
29
|
+
from rich.table import Table
|
|
30
|
+
from rich.panel import Panel
|
|
31
|
+
from rich.columns import Columns
|
|
32
|
+
from rich.text import Text
|
|
33
|
+
from rich.progress import Progress, SpinnerColumn, TextColumn
|
|
34
|
+
from rich.tree import Tree
|
|
35
|
+
from rich.syntax import Syntax
|
|
36
|
+
from rich.prompt import Prompt
|
|
37
|
+
from rich import print as rprint
|
|
27
38
|
|
|
28
39
|
def load_tool_modules():
|
|
29
40
|
"""Load all tool modules from the tools directory."""
|
|
@@ -412,61 +423,165 @@ The following {len(TOOL_SCHEMAS)} tools are loaded and available:
|
|
|
412
423
|
tool_name = tool_call.name
|
|
413
424
|
tool_input = tool_call.input
|
|
414
425
|
|
|
415
|
-
#
|
|
426
|
+
# Initialize Rich console for beautiful output
|
|
427
|
+
console = Console()
|
|
428
|
+
|
|
429
|
+
# Create tool execution panel
|
|
430
|
+
tool_title = f"š ļø Using Tool: {tool_name}"
|
|
416
431
|
if total_calls > 1:
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
# Show parameters in a clean format
|
|
432
|
+
tool_title += f" ({call_num}/{total_calls})"
|
|
433
|
+
|
|
434
|
+
# Format parameters beautifully
|
|
422
435
|
if tool_input:
|
|
423
436
|
# Special handling for TodoWrite to show actual todos
|
|
424
437
|
if tool_name == "TodoWrite" and "todos" in tool_input:
|
|
425
438
|
todos = tool_input["todos"]
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
439
|
+
|
|
440
|
+
# Create todo table
|
|
441
|
+
todo_table = Table(show_header=True, header_style="bold magenta")
|
|
442
|
+
todo_table.add_column("#", style="dim", width=3)
|
|
443
|
+
todo_table.add_column("Status", width=10)
|
|
444
|
+
todo_table.add_column("Task", style="cyan")
|
|
445
|
+
|
|
446
|
+
for i, todo in enumerate(todos, 1):
|
|
447
|
+
status_emoji = {"pending": "ā³ Pending", "in_progress": "š In Progress", "completed": "ā
Completed"}.get(todo.get("status", "pending"), "ā Unknown")
|
|
448
|
+
content = todo.get("content", "No description")
|
|
449
|
+
if len(content) > 80:
|
|
450
|
+
content = content[:80] + "..."
|
|
451
|
+
todo_table.add_row(str(i), status_emoji, content)
|
|
452
|
+
|
|
453
|
+
params_panel = Panel(
|
|
454
|
+
todo_table,
|
|
455
|
+
title=f"Todo List ({len(todos)} items)",
|
|
456
|
+
border_style="blue"
|
|
457
|
+
)
|
|
435
458
|
else:
|
|
436
|
-
|
|
459
|
+
# Format other parameters in a table
|
|
460
|
+
param_table = Table(show_header=True, header_style="bold green")
|
|
461
|
+
param_table.add_column("Parameter", style="yellow", width=20)
|
|
462
|
+
param_table.add_column("Value", style="white")
|
|
463
|
+
|
|
437
464
|
for key, value in tool_input.items():
|
|
438
|
-
if isinstance(value, str) and len(value) >
|
|
439
|
-
|
|
440
|
-
elif isinstance(value, list) and len(value) >
|
|
441
|
-
|
|
465
|
+
if isinstance(value, str) and len(value) > 100:
|
|
466
|
+
display_value = value[:100] + "..."
|
|
467
|
+
elif isinstance(value, list) and len(value) > 5:
|
|
468
|
+
display_value = f"[List with {len(value)} items]"
|
|
469
|
+
elif isinstance(value, dict):
|
|
470
|
+
display_value = f"[Dict with {len(value)} keys]"
|
|
442
471
|
else:
|
|
443
|
-
|
|
444
|
-
|
|
472
|
+
display_value = str(value)
|
|
473
|
+
param_table.add_row(key, display_value)
|
|
474
|
+
|
|
475
|
+
params_panel = Panel(
|
|
476
|
+
param_table,
|
|
477
|
+
title="Parameters",
|
|
478
|
+
border_style="green"
|
|
479
|
+
)
|
|
480
|
+
|
|
481
|
+
# Display tool info with parameters
|
|
482
|
+
console.print(Panel(
|
|
483
|
+
params_panel,
|
|
484
|
+
title=tool_title,
|
|
485
|
+
border_style="bright_blue",
|
|
486
|
+
padding=(0, 1)
|
|
487
|
+
))
|
|
488
|
+
else:
|
|
489
|
+
# Display simple tool info without parameters
|
|
490
|
+
console.print(Panel(
|
|
491
|
+
"[dim]No parameters[/dim]",
|
|
492
|
+
title=tool_title,
|
|
493
|
+
border_style="bright_blue",
|
|
494
|
+
padding=(0, 1)
|
|
495
|
+
))
|
|
445
496
|
|
|
446
497
|
try:
|
|
447
|
-
# Execute the tool
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
498
|
+
# Execute the tool with progress indicator
|
|
499
|
+
with Progress(
|
|
500
|
+
SpinnerColumn(),
|
|
501
|
+
TextColumn("[progress.description]{task.description}"),
|
|
502
|
+
console=console,
|
|
503
|
+
transient=True
|
|
504
|
+
) as progress:
|
|
505
|
+
task = progress.add_task(f"Executing {tool_name}...", total=None)
|
|
506
|
+
result = self._execute_builtin_tool(tool_name, tool_input)
|
|
452
507
|
|
|
453
|
-
#
|
|
508
|
+
# Display success message with result
|
|
454
509
|
if result and result.strip():
|
|
455
|
-
|
|
456
|
-
#
|
|
457
|
-
|
|
458
|
-
|
|
510
|
+
# Format result based on content type
|
|
511
|
+
if tool_name == "Read" and "ā" in result: # File content with line numbers
|
|
512
|
+
# Syntax highlight for code files
|
|
513
|
+
if any(ext in str(tool_input.get('file_path', '')) for ext in ['.py', '.js', '.ts', '.json', '.yaml', '.md']):
|
|
514
|
+
file_ext = str(tool_input.get('file_path', '')).split('.')[-1] if '.' in str(tool_input.get('file_path', '')) else 'text'
|
|
515
|
+
lexer = {
|
|
516
|
+
'py': 'python', 'js': 'javascript', 'ts': 'typescript',
|
|
517
|
+
'json': 'json', 'yaml': 'yaml', 'yml': 'yaml', 'md': 'markdown'
|
|
518
|
+
}.get(file_ext, 'text')
|
|
519
|
+
|
|
520
|
+
# Clean the line numbers for syntax highlighting
|
|
521
|
+
clean_content = '\n'.join(line.split('ā', 1)[1] if 'ā' in line else line for line in result.split('\n'))
|
|
522
|
+
syntax = Syntax(clean_content, lexer, line_numbers=True, theme="monokai")
|
|
523
|
+
result_panel = Panel(
|
|
524
|
+
syntax,
|
|
525
|
+
title=f"š File Content: {tool_input.get('file_path', 'Unknown')}",
|
|
526
|
+
border_style="green"
|
|
527
|
+
)
|
|
528
|
+
else:
|
|
529
|
+
result_panel = Panel(
|
|
530
|
+
result,
|
|
531
|
+
title="š File Content",
|
|
532
|
+
border_style="green"
|
|
533
|
+
)
|
|
534
|
+
elif tool_name == "LS": # Directory listing
|
|
535
|
+
result_panel = Panel(
|
|
536
|
+
result,
|
|
537
|
+
title="š Directory Contents",
|
|
538
|
+
border_style="blue"
|
|
539
|
+
)
|
|
540
|
+
elif tool_name == "Bash": # Command output
|
|
541
|
+
result_panel = Panel(
|
|
542
|
+
Text(result, style="green" if "Error" not in result else "red"),
|
|
543
|
+
title="š» Command Output",
|
|
544
|
+
border_style="yellow"
|
|
545
|
+
)
|
|
459
546
|
else:
|
|
460
|
-
|
|
547
|
+
# Truncate very long results for readability
|
|
548
|
+
display_result = result
|
|
549
|
+
if len(result) > 5000:
|
|
550
|
+
display_result = result[:5000] + f"\n\n[dim][Output truncated - showing first 5000 characters of {len(result)} total][/dim]"
|
|
551
|
+
|
|
552
|
+
result_panel = Panel(
|
|
553
|
+
display_result,
|
|
554
|
+
title="š Tool Result",
|
|
555
|
+
border_style="green"
|
|
556
|
+
)
|
|
557
|
+
|
|
558
|
+
# Success panel
|
|
559
|
+
success_panel = Panel(
|
|
560
|
+
f"ā
[bold green]Tool {tool_name} completed successfully[/bold green]",
|
|
561
|
+
border_style="green",
|
|
562
|
+
padding=(0, 1)
|
|
563
|
+
)
|
|
564
|
+
|
|
565
|
+
console.print(success_panel)
|
|
566
|
+
console.print(result_panel)
|
|
461
567
|
else:
|
|
462
|
-
print(
|
|
568
|
+
console.print(Panel(
|
|
569
|
+
"ā
[bold green]Tool completed successfully[/bold green]\n[dim](no output)[/dim]",
|
|
570
|
+
title=f"Tool {tool_name}",
|
|
571
|
+
border_style="green",
|
|
572
|
+
padding=(0, 1)
|
|
573
|
+
))
|
|
463
574
|
|
|
464
|
-
print() # Empty line for readability
|
|
575
|
+
console.print() # Empty line for readability
|
|
465
576
|
return result if result is not None else ""
|
|
466
577
|
|
|
467
578
|
except Exception as e:
|
|
468
|
-
print(
|
|
469
|
-
|
|
579
|
+
console.print(Panel(
|
|
580
|
+
f"ā [bold red]Tool {tool_name} failed:[/bold red]\n{str(e)}",
|
|
581
|
+
border_style="red",
|
|
582
|
+
padding=(0, 1)
|
|
583
|
+
))
|
|
584
|
+
console.print()
|
|
470
585
|
return f"Error executing {tool_name}: {str(e)}"
|
|
471
586
|
|
|
472
587
|
def _execute_builtin_tool(self, tool_name: str, tool_input: Dict[str, Any]) -> str:
|
|
@@ -752,19 +867,35 @@ The following {len(TOOL_SCHEMAS)} tools are loaded and available:
|
|
|
752
867
|
|
|
753
868
|
def interactive_mode(self):
|
|
754
869
|
"""
|
|
755
|
-
Run the agent in interactive mode
|
|
870
|
+
Run the agent in interactive mode with beautiful TUI using Rich and Typer.
|
|
756
871
|
"""
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
872
|
+
console = Console()
|
|
873
|
+
|
|
874
|
+
# Welcome banner
|
|
875
|
+
welcome_panel = Panel(
|
|
876
|
+
"[bold blue]š¤ Claude Code Agent[/bold blue]\n" +
|
|
877
|
+
"[dim]Powered by Anthropic API with claude-sonnet-4-20250514[/dim]\n\n" +
|
|
878
|
+
"[yellow]Commands:[/yellow]\n" +
|
|
879
|
+
"⢠Type your request naturally\n" +
|
|
880
|
+
"⢠'help' - Show available commands\n" +
|
|
881
|
+
"⢠'status' - Show current status\n" +
|
|
882
|
+
"⢠'exit' - Quit the agent",
|
|
883
|
+
title="š Welcome to Interactive Mode",
|
|
884
|
+
border_style="bright_blue",
|
|
885
|
+
padding=(1, 2)
|
|
886
|
+
)
|
|
887
|
+
console.print(welcome_panel)
|
|
761
888
|
|
|
762
889
|
while True:
|
|
763
890
|
try:
|
|
764
|
-
|
|
891
|
+
# Use Rich prompt for better input experience
|
|
892
|
+
user_input = Prompt.ask("\n[bold cyan]š¤ You[/bold cyan]").strip()
|
|
765
893
|
|
|
766
894
|
if user_input.lower() in ['exit', 'quit', 'bye']:
|
|
767
|
-
print(
|
|
895
|
+
console.print(Panel(
|
|
896
|
+
"[bold yellow]š Thank you for using Claude Code Agent![/bold yellow]",
|
|
897
|
+
border_style="yellow"
|
|
898
|
+
))
|
|
768
899
|
break
|
|
769
900
|
elif user_input.lower() == 'help':
|
|
770
901
|
self.show_help()
|
|
@@ -775,108 +906,281 @@ The following {len(TOOL_SCHEMAS)} tools are loaded and available:
|
|
|
775
906
|
elif not user_input:
|
|
776
907
|
continue
|
|
777
908
|
|
|
778
|
-
|
|
909
|
+
# Show that Claude is thinking
|
|
910
|
+
thinking_panel = Panel(
|
|
911
|
+
"[bold blue]š¤ Claude Code Agent[/bold blue] is processing your request...",
|
|
912
|
+
border_style="blue",
|
|
913
|
+
padding=(0, 1)
|
|
914
|
+
)
|
|
915
|
+
console.print(thinking_panel)
|
|
916
|
+
|
|
779
917
|
response = self.process_query(user_input)
|
|
780
918
|
if response.strip():
|
|
781
|
-
|
|
919
|
+
response_panel = Panel(
|
|
920
|
+
response,
|
|
921
|
+
title="š¤ Claude Code Agent Response",
|
|
922
|
+
border_style="bright_green",
|
|
923
|
+
padding=(0, 1)
|
|
924
|
+
)
|
|
925
|
+
console.print(response_panel)
|
|
782
926
|
|
|
783
927
|
except KeyboardInterrupt:
|
|
784
|
-
print("\n\nš Goodbye!")
|
|
928
|
+
console.print("\n\n[bold yellow]š Goodbye![/bold yellow]")
|
|
785
929
|
break
|
|
786
930
|
except Exception as e:
|
|
787
|
-
print(
|
|
931
|
+
console.print(Panel(
|
|
932
|
+
f"[bold red]ā Error:[/bold red] {str(e)}",
|
|
933
|
+
border_style="red"
|
|
934
|
+
))
|
|
788
935
|
|
|
789
936
|
def show_help(self):
|
|
790
|
-
"""Show help information."""
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
""
|
|
831
|
-
|
|
937
|
+
"""Show help information with beautiful formatting."""
|
|
938
|
+
console = Console()
|
|
939
|
+
|
|
940
|
+
# Create help sections
|
|
941
|
+
file_ops = Table(show_header=False, box=None, padding=(0, 1))
|
|
942
|
+
file_ops.add_column(style="yellow")
|
|
943
|
+
file_ops.add_column(style="white")
|
|
944
|
+
file_ops.add_row("read <file>", "Read file contents")
|
|
945
|
+
file_ops.add_row("list [directory]", "List files and directories")
|
|
946
|
+
file_ops.add_row("find <pattern>", "Find files matching pattern")
|
|
947
|
+
file_ops.add_row("edit <file>", "Edit file contents")
|
|
948
|
+
|
|
949
|
+
search_ops = Table(show_header=False, box=None, padding=(0, 1))
|
|
950
|
+
search_ops.add_column(style="yellow")
|
|
951
|
+
search_ops.add_column(style="white")
|
|
952
|
+
search_ops.add_row("search <term>", "Search in files")
|
|
953
|
+
search_ops.add_row("web search <term>", "Search the web")
|
|
954
|
+
|
|
955
|
+
code_ops = Table(show_header=False, box=None, padding=(0, 1))
|
|
956
|
+
code_ops.add_column(style="yellow")
|
|
957
|
+
code_ops.add_column(style="white")
|
|
958
|
+
code_ops.add_row("run <command>", "Execute bash commands")
|
|
959
|
+
code_ops.add_row("npm/uv pip/git commands", "Execute package manager commands")
|
|
960
|
+
|
|
961
|
+
web_ops = Table(show_header=False, box=None, padding=(0, 1))
|
|
962
|
+
web_ops.add_column(style="yellow")
|
|
963
|
+
web_ops.add_column(style="white")
|
|
964
|
+
web_ops.add_row("fetch <url>", "Fetch content from URL")
|
|
965
|
+
web_ops.add_row("web search <query>", "Search the web")
|
|
966
|
+
|
|
967
|
+
examples = Table(show_header=False, box=None, padding=(0, 1))
|
|
968
|
+
examples.add_column(style="green")
|
|
969
|
+
examples.add_row('"read main.py"')
|
|
970
|
+
examples.add_row('"search for TODO comments"')
|
|
971
|
+
examples.add_row('"run pytest tests/"')
|
|
972
|
+
examples.add_row('"implement user authentication system"')
|
|
973
|
+
examples.add_row('"web search latest Python features 2024"')
|
|
974
|
+
|
|
975
|
+
special = Table(show_header=False, box=None, padding=(0, 1))
|
|
976
|
+
special.add_column(style="cyan")
|
|
977
|
+
special.add_column(style="white")
|
|
978
|
+
special.add_row("help", "Show this help")
|
|
979
|
+
special.add_row("status", "Show current status")
|
|
980
|
+
special.add_row("exit", "Quit the agent")
|
|
981
|
+
|
|
982
|
+
# Create main help layout
|
|
983
|
+
help_panels = [
|
|
984
|
+
Panel(file_ops, title="š File Operations", border_style="blue"),
|
|
985
|
+
Panel(search_ops, title="š Search", border_style="green"),
|
|
986
|
+
Panel(code_ops, title="āļø Code Execution", border_style="yellow"),
|
|
987
|
+
Panel(web_ops, title="š Web Access", border_style="magenta"),
|
|
988
|
+
Panel("Complex tasks automatically create todo lists\nMulti-step operations are tracked", title="š Task Management", border_style="cyan"),
|
|
989
|
+
Panel(examples, title="š” Examples", border_style="bright_green"),
|
|
990
|
+
Panel(special, title="š® Special Commands", border_style="red")
|
|
991
|
+
]
|
|
992
|
+
|
|
993
|
+
# Display help in columns
|
|
994
|
+
console.print(Panel(
|
|
995
|
+
Columns(help_panels, equal=True, expand=True),
|
|
996
|
+
title="š Claude Code Agent Help",
|
|
997
|
+
subtitle="Powered by Anthropic API with claude-sonnet-4-20250514",
|
|
998
|
+
border_style="bright_blue",
|
|
999
|
+
padding=(1, 2)
|
|
1000
|
+
))
|
|
832
1001
|
|
|
833
1002
|
def show_status(self):
|
|
834
|
-
"""Show current status."""
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
1003
|
+
"""Show current status with beautiful formatting."""
|
|
1004
|
+
console = Console()
|
|
1005
|
+
|
|
1006
|
+
# Configuration status
|
|
1007
|
+
config_table = Table(show_header=False, box=None)
|
|
1008
|
+
config_table.add_column("Setting", style="yellow")
|
|
1009
|
+
config_table.add_column("Value", style="green")
|
|
1010
|
+
config_table.add_row("API Key", "ā
Set" if self.api_key else "ā Missing")
|
|
1011
|
+
config_table.add_row("Model", "claude-sonnet-4-20250514")
|
|
1012
|
+
config_table.add_row("Working Directory", self.working_dir)
|
|
1013
|
+
config_table.add_row("Git Repository", "Yes" if self.is_git_repo else "No")
|
|
1014
|
+
|
|
1015
|
+
# Session status
|
|
1016
|
+
session_table = Table(show_header=False, box=None)
|
|
1017
|
+
session_table.add_column("Metric", style="yellow")
|
|
1018
|
+
session_table.add_column("Count", style="cyan")
|
|
1019
|
+
session_table.add_row("Conversation Messages", str(len(self.conversation_history)))
|
|
1020
|
+
session_table.add_row("Todo Items", str(len(self.todo_list)))
|
|
1021
|
+
session_table.add_row("Loaded Prompts", str(len(PROMPT_CONTENT)))
|
|
1022
|
+
session_table.add_row("Available Tools", str(len(TOOL_SCHEMAS)))
|
|
1023
|
+
|
|
1024
|
+
# Tools tree
|
|
1025
|
+
tools_tree = Tree("š ļø Available Tools")
|
|
1026
|
+
for tool in TOOL_SCHEMAS:
|
|
1027
|
+
tools_tree.add(f"[cyan]{tool['name']}[/cyan]")
|
|
1028
|
+
|
|
1029
|
+
# Status panels
|
|
1030
|
+
status_panels = [
|
|
1031
|
+
Panel(config_table, title="š§ Configuration", border_style="blue"),
|
|
1032
|
+
Panel(session_table, title="š Session", border_style="green"),
|
|
1033
|
+
Panel(tools_tree, title="š ļø Tools", border_style="yellow")
|
|
1034
|
+
]
|
|
1035
|
+
|
|
1036
|
+
console.print(Panel(
|
|
1037
|
+
Columns(status_panels, equal=True),
|
|
1038
|
+
title="š Claude Code Agent Status",
|
|
1039
|
+
border_style="bright_blue",
|
|
1040
|
+
padding=(1, 1)
|
|
1041
|
+
))
|
|
843
1042
|
|
|
844
|
-
š Session:
|
|
845
|
-
- Conversation History: {len(self.conversation_history)} messages
|
|
846
|
-
- Todo Items: {len(self.todo_list)} items
|
|
847
1043
|
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
1044
|
+
# Create Typer app
|
|
1045
|
+
app = typer.Typer(
|
|
1046
|
+
name="claude-code-agent",
|
|
1047
|
+
help="š¤ Claude Code Agent - Anthropic API Integration with Beautiful TUI",
|
|
1048
|
+
add_completion=False,
|
|
1049
|
+
rich_markup_mode="rich"
|
|
1050
|
+
)
|
|
853
1051
|
|
|
1052
|
+
@app.command()
|
|
1053
|
+
def interactive(
|
|
1054
|
+
api_key: str = typer.Option(None, "--api-key", "-k", help="Anthropic API key (or set ANTHROPIC_API_KEY env var)"),
|
|
1055
|
+
):
|
|
1056
|
+
"""š Start interactive mode with beautiful TUI."""
|
|
1057
|
+
console = Console()
|
|
1058
|
+
|
|
1059
|
+
try:
|
|
1060
|
+
agent = ClaudeCodeAgent(api_key=api_key)
|
|
1061
|
+
agent.interactive_mode()
|
|
1062
|
+
except ValueError as e:
|
|
1063
|
+
console.print(Panel(
|
|
1064
|
+
f"[bold red]ā Configuration Error:[/bold red]\n{str(e)}\n\n" +
|
|
1065
|
+
"[yellow]To fix this:[/yellow]\n" +
|
|
1066
|
+
"1. Get your Anthropic API key from: https://console.anthropic.com/\n" +
|
|
1067
|
+
"2. Set environment variable: [cyan]export ANTHROPIC_API_KEY=your_key_here[/cyan]\n" +
|
|
1068
|
+
"3. Or use: [cyan]--api-key your_key[/cyan] parameter",
|
|
1069
|
+
title="Setup Required",
|
|
1070
|
+
border_style="red"
|
|
1071
|
+
))
|
|
1072
|
+
raise typer.Exit(1)
|
|
1073
|
+
except Exception as e:
|
|
1074
|
+
console.print(Panel(
|
|
1075
|
+
f"[bold red]ā Error:[/bold red] {str(e)}",
|
|
1076
|
+
border_style="red"
|
|
1077
|
+
))
|
|
1078
|
+
raise typer.Exit(1)
|
|
854
1079
|
|
|
855
|
-
|
|
856
|
-
|
|
1080
|
+
@app.command()
|
|
1081
|
+
def query(
|
|
1082
|
+
prompt: str = typer.Argument(..., help="Your query or command"),
|
|
1083
|
+
api_key: str = typer.Option(None, "--api-key", "-k", help="Anthropic API key (or set ANTHROPIC_API_KEY env var)"),
|
|
1084
|
+
):
|
|
1085
|
+
"""š¬ Process a single query and exit."""
|
|
1086
|
+
console = Console()
|
|
1087
|
+
|
|
857
1088
|
try:
|
|
858
|
-
agent = ClaudeCodeAgent()
|
|
1089
|
+
agent = ClaudeCodeAgent(api_key=api_key)
|
|
1090
|
+
|
|
1091
|
+
# Show processing indicator
|
|
1092
|
+
with Progress(
|
|
1093
|
+
SpinnerColumn(),
|
|
1094
|
+
TextColumn("[progress.description]{task.description}"),
|
|
1095
|
+
console=console,
|
|
1096
|
+
transient=True
|
|
1097
|
+
) as progress:
|
|
1098
|
+
task = progress.add_task("Processing your query...", total=None)
|
|
1099
|
+
response = agent.process_query(prompt)
|
|
859
1100
|
|
|
860
|
-
if
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
1101
|
+
if response.strip():
|
|
1102
|
+
console.print(Panel(
|
|
1103
|
+
response,
|
|
1104
|
+
title="š¤ Claude Code Agent Response",
|
|
1105
|
+
border_style="bright_green"
|
|
1106
|
+
))
|
|
865
1107
|
else:
|
|
866
|
-
|
|
867
|
-
agent.interactive_mode()
|
|
1108
|
+
console.print("[dim]No response generated.[/dim]")
|
|
868
1109
|
|
|
869
1110
|
except ValueError as e:
|
|
870
|
-
print(
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
1111
|
+
console.print(Panel(
|
|
1112
|
+
f"[bold red]ā Configuration Error:[/bold red]\n{str(e)}\n\n" +
|
|
1113
|
+
"[yellow]To fix this:[/yellow]\n" +
|
|
1114
|
+
"1. Get your Anthropic API key from: https://console.anthropic.com/\n" +
|
|
1115
|
+
"2. Set environment variable: [cyan]export ANTHROPIC_API_KEY=your_key_here[/cyan]\n" +
|
|
1116
|
+
"3. Or use: [cyan]--api-key your_key[/cyan] parameter",
|
|
1117
|
+
title="Setup Required",
|
|
1118
|
+
border_style="red"
|
|
1119
|
+
))
|
|
1120
|
+
raise typer.Exit(1)
|
|
876
1121
|
except Exception as e:
|
|
877
|
-
print(
|
|
878
|
-
|
|
1122
|
+
console.print(Panel(
|
|
1123
|
+
f"[bold red]ā Error:[/bold red] {str(e)}",
|
|
1124
|
+
border_style="red"
|
|
1125
|
+
))
|
|
1126
|
+
raise typer.Exit(1)
|
|
1127
|
+
|
|
1128
|
+
@app.command()
|
|
1129
|
+
def setup():
|
|
1130
|
+
"""āļø Show setup instructions and system info."""
|
|
1131
|
+
console = Console()
|
|
1132
|
+
|
|
1133
|
+
# System info
|
|
1134
|
+
system_info = Table(show_header=False, box=None)
|
|
1135
|
+
system_info.add_column("Property", style="yellow")
|
|
1136
|
+
system_info.add_column("Value", style="cyan")
|
|
1137
|
+
system_info.add_row("Platform", os.uname().sysname if hasattr(os, 'uname') else 'unknown')
|
|
1138
|
+
system_info.add_row("Working Directory", os.getcwd())
|
|
1139
|
+
system_info.add_row("Git Repository", "Yes" if os.path.exists('.git') else "No")
|
|
1140
|
+
system_info.add_row("API Key Status", "ā
Set" if os.getenv('ANTHROPIC_API_KEY') else "ā Missing")
|
|
1141
|
+
|
|
1142
|
+
# Setup instructions
|
|
1143
|
+
setup_instructions = """[bold yellow]1. Get your API key:[/bold yellow]
|
|
1144
|
+
Visit: https://console.anthropic.com/
|
|
1145
|
+
|
|
1146
|
+
[bold yellow]2. Set environment variable:[/bold yellow]
|
|
1147
|
+
[cyan]export ANTHROPIC_API_KEY=your_key_here[/cyan]
|
|
1148
|
+
|
|
1149
|
+
[bold yellow]3. Install dependencies:[/bold yellow]
|
|
1150
|
+
[cyan]uv pip install -r requirements.txt[/cyan]
|
|
1151
|
+
|
|
1152
|
+
[bold yellow]4. Run the agent:[/bold yellow]
|
|
1153
|
+
[cyan]python claude_code_agent.py interactive[/cyan]
|
|
1154
|
+
or
|
|
1155
|
+
[cyan]python claude_code_agent.py query "your question"[/cyan]"""
|
|
1156
|
+
|
|
1157
|
+
console.print(Panel(
|
|
1158
|
+
Columns([
|
|
1159
|
+
Panel(system_info, title="š System Info", border_style="blue"),
|
|
1160
|
+
Panel(setup_instructions, title="š Setup Instructions", border_style="green")
|
|
1161
|
+
], equal=True),
|
|
1162
|
+
title="āļø Claude Code Agent Setup",
|
|
1163
|
+
border_style="bright_blue",
|
|
1164
|
+
padding=(1, 1)
|
|
1165
|
+
))
|
|
1166
|
+
|
|
1167
|
+
def main():
|
|
1168
|
+
"""Main entry point - delegate to Typer app."""
|
|
1169
|
+
app()
|
|
879
1170
|
|
|
880
1171
|
|
|
881
1172
|
if __name__ == "__main__":
|
|
882
|
-
|
|
1173
|
+
# Support legacy mode for backwards compatibility
|
|
1174
|
+
if len(sys.argv) == 1:
|
|
1175
|
+
# No arguments - start interactive mode
|
|
1176
|
+
app(["interactive"])
|
|
1177
|
+
elif len(sys.argv) == 2 and sys.argv[1] not in ["interactive", "query", "setup", "--help", "-h"]:
|
|
1178
|
+
# Single argument that's not a command - treat as query
|
|
1179
|
+
app(["query", sys.argv[1]])
|
|
1180
|
+
elif len(sys.argv) > 2 and sys.argv[1] not in ["interactive", "query", "setup"]:
|
|
1181
|
+
# Multiple arguments not starting with command - treat as query
|
|
1182
|
+
query_text = " ".join(sys.argv[1:])
|
|
1183
|
+
app(["query", query_text])
|
|
1184
|
+
else:
|
|
1185
|
+
# Use normal Typer command parsing
|
|
1186
|
+
app()
|
|
@@ -51,7 +51,7 @@ class BashTool:
|
|
|
51
51
|
"type": "string"
|
|
52
52
|
},
|
|
53
53
|
"description": {
|
|
54
|
-
"description": " Clear, concise description of what this command does in 5-10 words. Examples:\nInput: ls\nOutput: Lists files in current directory\n\nInput: git status\nOutput: Shows working tree status\n\nInput:
|
|
54
|
+
"description": " Clear, concise description of what this command does in 5-10 words. Examples:\nInput: ls\nOutput: Lists files in current directory\n\nInput: git status\nOutput: Shows working tree status\n\nInput: uv pip install\nOutput: Installs package dependencies\n\nInput: mkdir foo\nOutput: Creates directory 'foo'",
|
|
55
55
|
"type": "string"
|
|
56
56
|
},
|
|
57
57
|
"run_in_background": {
|
package/lib/sandbox.js
CHANGED
|
@@ -150,22 +150,26 @@ async function runContainer(options) {
|
|
|
150
150
|
return new Promise((resolve, reject) => {
|
|
151
151
|
pythonProcess.on('close', (code) => {
|
|
152
152
|
if (code === 0) {
|
|
153
|
-
console.log(chalk.green('
|
|
153
|
+
console.log(chalk.green('ā Environment ready'));
|
|
154
|
+
console.log(chalk.dim(' Your secure development environment is now active'));
|
|
154
155
|
resolve();
|
|
155
156
|
} else {
|
|
156
|
-
console.log(chalk.red(
|
|
157
|
+
console.log(chalk.red('ā Launch failed'));
|
|
158
|
+
console.log(chalk.dim(` Exit code: ${code}`));
|
|
157
159
|
reject(new Error(`Process exited with code ${code}`));
|
|
158
160
|
}
|
|
159
161
|
});
|
|
160
162
|
|
|
161
163
|
// Handle process errors
|
|
162
164
|
pythonProcess.on('error', (error) => {
|
|
163
|
-
console.log(chalk.red(
|
|
165
|
+
console.log(chalk.red('ā Process error'));
|
|
166
|
+
console.log(chalk.dim(` ${error.message}`));
|
|
164
167
|
reject(error);
|
|
165
168
|
});
|
|
166
169
|
});
|
|
167
170
|
} catch (error) {
|
|
168
|
-
console.log(chalk.red(
|
|
171
|
+
console.log(chalk.red('ā Launch error'));
|
|
172
|
+
console.log(chalk.dim(` ${error.message}`));
|
|
169
173
|
throw error;
|
|
170
174
|
}
|
|
171
175
|
}
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|