camo-cli 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +184 -0
- package/dist/agent.js +977 -0
- package/dist/art.js +33 -0
- package/dist/components/App.js +71 -0
- package/dist/components/Chat.js +509 -0
- package/dist/components/HITLConfirmation.js +89 -0
- package/dist/components/ModelSelector.js +100 -0
- package/dist/components/SetupScreen.js +43 -0
- package/dist/config/constants.js +58 -0
- package/dist/config/prompts.js +98 -0
- package/dist/config/store.js +5 -0
- package/dist/core/AgentLoop.js +159 -0
- package/dist/hooks/useAutocomplete.js +52 -0
- package/dist/hooks/useKeyboard.js +73 -0
- package/dist/index.js +31 -0
- package/dist/mcp.js +95 -0
- package/dist/memory/MemoryManager.js +228 -0
- package/dist/providers/index.js +85 -0
- package/dist/providers/registry.js +121 -0
- package/dist/providers/types.js +5 -0
- package/dist/theme.js +45 -0
- package/dist/tools/FileTools.js +88 -0
- package/dist/tools/MemoryTools.js +53 -0
- package/dist/tools/SearchTools.js +45 -0
- package/dist/tools/ShellTools.js +40 -0
- package/dist/tools/TaskTools.js +52 -0
- package/dist/tools/ToolDefinitions.js +102 -0
- package/dist/tools/ToolRegistry.js +30 -0
- package/dist/types/Agent.js +6 -0
- package/dist/types/ink.js +1 -0
- package/dist/types/message.js +1 -0
- package/dist/types/ui.js +1 -0
- package/dist/utils/CriticAgent.js +88 -0
- package/dist/utils/DecisionLogger.js +156 -0
- package/dist/utils/MessageHistory.js +55 -0
- package/dist/utils/PermissionManager.js +253 -0
- package/dist/utils/SessionManager.js +180 -0
- package/dist/utils/TaskState.js +108 -0
- package/dist/utils/debug.js +35 -0
- package/dist/utils/execAsync.js +3 -0
- package/dist/utils/retry.js +50 -0
- package/dist/utils/tokenCounter.js +24 -0
- package/dist/utils/uiFormatter.js +106 -0
- package/package.json +92 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token counting utility for context management
|
|
3
|
+
* Uses character-based estimation (1 token ≈ 4 chars for English)
|
|
4
|
+
*/
|
|
5
|
+
const CHARS_PER_TOKEN = 4;
|
|
6
|
+
const MAX_CONTEXT_TOKENS = 128000; // Gemini 2.0 Flash context window
|
|
7
|
+
export function estimateTokens(text) {
|
|
8
|
+
return Math.ceil(text.length / CHARS_PER_TOKEN);
|
|
9
|
+
}
|
|
10
|
+
export function getContextStats(messages) {
|
|
11
|
+
const totalChars = messages.reduce((sum, m) => sum + m.content.length, 0);
|
|
12
|
+
return {
|
|
13
|
+
estimated: estimateTokens(totalChars.toString()) + messages.length * 4, // overhead per message
|
|
14
|
+
characters: totalChars,
|
|
15
|
+
messages: messages.length
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export function isNearLimit(stats, threshold = 0.8) {
|
|
19
|
+
return stats.estimated >= MAX_CONTEXT_TOKENS * threshold;
|
|
20
|
+
}
|
|
21
|
+
export function formatTokenUsage(stats) {
|
|
22
|
+
const percent = ((stats.estimated / MAX_CONTEXT_TOKENS) * 100).toFixed(1);
|
|
23
|
+
return `${stats.estimated.toLocaleString()} / ${MAX_CONTEXT_TOKENS.toLocaleString()} tokens (${percent}%)`;
|
|
24
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UI Text Formatting Utilities
|
|
3
|
+
*/
|
|
4
|
+
const BULLET = '⏺';
|
|
5
|
+
const INDENT = ' '; // 2 spaces for continuation
|
|
6
|
+
const TOOL_INDENT = ' '; // 4 spaces for tool output
|
|
7
|
+
/**
|
|
8
|
+
* Format assistant message with bullet and proper indentation
|
|
9
|
+
* First line: ⏺ Text here
|
|
10
|
+
* Next lines: aligned under text (2 space indent)
|
|
11
|
+
*/
|
|
12
|
+
export function formatAssistantMessage(text, maxWidth = 80) {
|
|
13
|
+
const lines = text.split('\n');
|
|
14
|
+
const formatted = [];
|
|
15
|
+
for (let i = 0; i < lines.length; i++) {
|
|
16
|
+
const line = lines[i];
|
|
17
|
+
if (i === 0) {
|
|
18
|
+
// First line gets bullet
|
|
19
|
+
formatted.push(`${BULLET} ${line}`);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
// Continuation lines indented
|
|
23
|
+
formatted.push(`${INDENT}${line}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return formatted.join('\n');
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Format tool call display
|
|
30
|
+
* ⏺ toolName (params)
|
|
31
|
+
*/
|
|
32
|
+
export function formatToolCall(toolName, params) {
|
|
33
|
+
const paramStr = Object.entries(params)
|
|
34
|
+
.filter(([_, v]) => v !== undefined)
|
|
35
|
+
.map(([k, v]) => {
|
|
36
|
+
const val = typeof v === 'string'
|
|
37
|
+
? (v.length > 30 ? v.slice(0, 30) + '...' : v)
|
|
38
|
+
: String(v);
|
|
39
|
+
return val;
|
|
40
|
+
})
|
|
41
|
+
.join(', ');
|
|
42
|
+
return `${BULLET} ${toolName}${paramStr ? ` (${paramStr})` : ''}`;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Format tool output - parse JSON and display human-readable results
|
|
46
|
+
* Returns formatted output for display (max 3-4 lines)
|
|
47
|
+
*/
|
|
48
|
+
export function formatToolOutput(output, maxLines = 3) {
|
|
49
|
+
try {
|
|
50
|
+
const parsed = JSON.parse(output);
|
|
51
|
+
// Handle different result types
|
|
52
|
+
if (parsed.error) {
|
|
53
|
+
return ` ↳ Error: ${parsed.error}`;
|
|
54
|
+
}
|
|
55
|
+
if (parsed.files && Array.isArray(parsed.files)) {
|
|
56
|
+
// listFiles result - show only first 3 files
|
|
57
|
+
const files = parsed.files.slice(0, maxLines);
|
|
58
|
+
const more = parsed.files.length > maxLines ? ` (+${parsed.files.length - maxLines} more)` : '';
|
|
59
|
+
return files.map((f) => ` ↳ ${f}`).join('\n') + (more ? `\n ↳ ${more}` : '');
|
|
60
|
+
}
|
|
61
|
+
if (parsed.content) {
|
|
62
|
+
// readFile result - show only first 3 lines
|
|
63
|
+
const lines = parsed.content.split('\n').slice(0, maxLines);
|
|
64
|
+
const more = parsed.content.split('\n').length > maxLines ? ` (+${parsed.content.split('\n').length - maxLines} more lines)` : '';
|
|
65
|
+
return lines.map((l) => ` ↳ ${l.slice(0, 70)}`).join('\n') + (more ? `\n ↳ ${more}` : '');
|
|
66
|
+
}
|
|
67
|
+
if (parsed.output) {
|
|
68
|
+
// Shell command output - show only last 3 lines
|
|
69
|
+
const allLines = String(parsed.output).trim().split('\n');
|
|
70
|
+
const lines = allLines.slice(-maxLines); // Take LAST 3 lines for shell output
|
|
71
|
+
return lines.map(l => ` ↳ ${l.slice(0, 70)}`).join('\n');
|
|
72
|
+
}
|
|
73
|
+
if (parsed.success) {
|
|
74
|
+
return ` ↳ Success`;
|
|
75
|
+
}
|
|
76
|
+
// Fallback: stringify the object
|
|
77
|
+
return ` ↳ ${JSON.stringify(parsed).slice(0, 70)}`;
|
|
78
|
+
}
|
|
79
|
+
catch (e) {
|
|
80
|
+
// Not JSON, display as-is (last 3 lines)
|
|
81
|
+
const allLines = output.trim().split('\n');
|
|
82
|
+
const lines = allLines.slice(-maxLines);
|
|
83
|
+
return lines.map(line => ` ↳ ${line.slice(0, 70)}`).join('\n');
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Wrap text to width while preserving indentation
|
|
88
|
+
*/
|
|
89
|
+
export function wrapText(text, maxWidth = 80, indent = '') {
|
|
90
|
+
const words = text.split(' ');
|
|
91
|
+
const lines = [];
|
|
92
|
+
let currentLine = '';
|
|
93
|
+
for (const word of words) {
|
|
94
|
+
if ((currentLine + ' ' + word).length > maxWidth && currentLine.length > 0) {
|
|
95
|
+
lines.push(currentLine);
|
|
96
|
+
currentLine = indent + word;
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
currentLine = currentLine ? currentLine + ' ' + word : word;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (currentLine) {
|
|
103
|
+
lines.push(currentLine);
|
|
104
|
+
}
|
|
105
|
+
return lines.join('\n');
|
|
106
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "camo-cli",
|
|
3
|
+
"version": "2.0.1",
|
|
4
|
+
"description": "🦎 Elite autonomous AI engineering agent with loop detection, persistent memory, and intelligent tool execution",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"camo": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"engines": {
|
|
11
|
+
"node": ">=18.0.0"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"README.md",
|
|
16
|
+
"LICENSE"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc",
|
|
20
|
+
"start": "node dist/index.js",
|
|
21
|
+
"dev": "tsc && node dist/index.js",
|
|
22
|
+
"dev:watch": "tsc --watch",
|
|
23
|
+
"prepare": "npm run build",
|
|
24
|
+
"test": "vitest run",
|
|
25
|
+
"test:watch": "vitest"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"ai",
|
|
29
|
+
"agent",
|
|
30
|
+
"cli",
|
|
31
|
+
"automation",
|
|
32
|
+
"engineering",
|
|
33
|
+
"google",
|
|
34
|
+
"gemini",
|
|
35
|
+
"autonomous",
|
|
36
|
+
"coding-assistant",
|
|
37
|
+
"developer-tools",
|
|
38
|
+
"terminal"
|
|
39
|
+
],
|
|
40
|
+
"author": "Maximilian David Lieven",
|
|
41
|
+
"license": "MIT",
|
|
42
|
+
"repository": {
|
|
43
|
+
"type": "git",
|
|
44
|
+
"url": "https://github.com/maxi-lvn/camo-cli"
|
|
45
|
+
},
|
|
46
|
+
"bugs": {
|
|
47
|
+
"url": "https://github.com/maxi-lvn/camo-cli/issues"
|
|
48
|
+
},
|
|
49
|
+
"homepage": "https://github.com/maxi-lvn/camo-cli#readme",
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@types/cardinal": "^2.1.1",
|
|
52
|
+
"@types/diff": "^7.0.2",
|
|
53
|
+
"@types/figlet": "^1.7.0",
|
|
54
|
+
"@types/inquirer": "^9.0.7",
|
|
55
|
+
"@types/jsdom": "^27.0.0",
|
|
56
|
+
"@types/node": "^25.0.9",
|
|
57
|
+
"@types/react": "^19.2.8",
|
|
58
|
+
"@types/turndown": "^5.0.6",
|
|
59
|
+
"@types/wrap-ansi": "^8.0.2",
|
|
60
|
+
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
|
61
|
+
"@typescript-eslint/parser": "^6.21.0",
|
|
62
|
+
"eslint": "^8.57.0",
|
|
63
|
+
"ts-node": "^10.9.2",
|
|
64
|
+
"typescript": "^5.9.3",
|
|
65
|
+
"vitest": "^4.0.17"
|
|
66
|
+
},
|
|
67
|
+
"dependencies": {
|
|
68
|
+
"@ai-sdk/google": "^3.0.10",
|
|
69
|
+
"@clack/prompts": "^0.11.0",
|
|
70
|
+
"@google/generative-ai": "^0.24.1",
|
|
71
|
+
"@modelcontextprotocol/sdk": "^1.25.2",
|
|
72
|
+
"@mozilla/readability": "^0.6.0",
|
|
73
|
+
"ai": "^6.0.37",
|
|
74
|
+
"ansi-escapes": "^7.2.0",
|
|
75
|
+
"boxen": "^8.0.1",
|
|
76
|
+
"cardinal": "^2.1.1",
|
|
77
|
+
"chalk": "^5.6.2",
|
|
78
|
+
"cli-cursor": "^5.0.0",
|
|
79
|
+
"commander": "^14.0.2",
|
|
80
|
+
"conf": "^15.0.2",
|
|
81
|
+
"diff": "^8.0.3",
|
|
82
|
+
"figlet": "^1.9.4",
|
|
83
|
+
"ink": "^6.6.0",
|
|
84
|
+
"ink-text-input": "^6.0.0",
|
|
85
|
+
"inquirer": "^9.2.12",
|
|
86
|
+
"jsdom": "^27.4.0",
|
|
87
|
+
"react": "^19.2.3",
|
|
88
|
+
"turndown": "^7.2.2",
|
|
89
|
+
"wrap-ansi": "^9.0.2",
|
|
90
|
+
"zod": "^3.24.2"
|
|
91
|
+
}
|
|
92
|
+
}
|