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.
Files changed (44) hide show
  1. package/README.md +184 -0
  2. package/dist/agent.js +977 -0
  3. package/dist/art.js +33 -0
  4. package/dist/components/App.js +71 -0
  5. package/dist/components/Chat.js +509 -0
  6. package/dist/components/HITLConfirmation.js +89 -0
  7. package/dist/components/ModelSelector.js +100 -0
  8. package/dist/components/SetupScreen.js +43 -0
  9. package/dist/config/constants.js +58 -0
  10. package/dist/config/prompts.js +98 -0
  11. package/dist/config/store.js +5 -0
  12. package/dist/core/AgentLoop.js +159 -0
  13. package/dist/hooks/useAutocomplete.js +52 -0
  14. package/dist/hooks/useKeyboard.js +73 -0
  15. package/dist/index.js +31 -0
  16. package/dist/mcp.js +95 -0
  17. package/dist/memory/MemoryManager.js +228 -0
  18. package/dist/providers/index.js +85 -0
  19. package/dist/providers/registry.js +121 -0
  20. package/dist/providers/types.js +5 -0
  21. package/dist/theme.js +45 -0
  22. package/dist/tools/FileTools.js +88 -0
  23. package/dist/tools/MemoryTools.js +53 -0
  24. package/dist/tools/SearchTools.js +45 -0
  25. package/dist/tools/ShellTools.js +40 -0
  26. package/dist/tools/TaskTools.js +52 -0
  27. package/dist/tools/ToolDefinitions.js +102 -0
  28. package/dist/tools/ToolRegistry.js +30 -0
  29. package/dist/types/Agent.js +6 -0
  30. package/dist/types/ink.js +1 -0
  31. package/dist/types/message.js +1 -0
  32. package/dist/types/ui.js +1 -0
  33. package/dist/utils/CriticAgent.js +88 -0
  34. package/dist/utils/DecisionLogger.js +156 -0
  35. package/dist/utils/MessageHistory.js +55 -0
  36. package/dist/utils/PermissionManager.js +253 -0
  37. package/dist/utils/SessionManager.js +180 -0
  38. package/dist/utils/TaskState.js +108 -0
  39. package/dist/utils/debug.js +35 -0
  40. package/dist/utils/execAsync.js +3 -0
  41. package/dist/utils/retry.js +50 -0
  42. package/dist/utils/tokenCounter.js +24 -0
  43. package/dist/utils/uiFormatter.js +106 -0
  44. 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
+ }