sam-coder-cli 1.0.44 → 1.0.46

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sam-coder-cli",
3
- "version": "1.0.44",
3
+ "version": "1.0.46",
4
4
  "description": "SAM-CODER: An animated command-line AI assistant with agency capabilities.",
5
5
  "main": "bin/agi-cli.js",
6
6
  "bin": {
@@ -24,6 +24,7 @@
24
24
  "ws": "^8.18.3"
25
25
  },
26
26
  "devDependencies": {
27
+ "@types/vscode": "^1.102.0",
27
28
  "eslint": "^7.27.0"
28
29
  },
29
30
  "engines": {
@@ -1,328 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- const readline = require('readline');
4
- const path = require('path');
5
- const fs = require('fs').promises;
6
- const { exec } = require('child_process');
7
- const util = require('util');
8
- const execAsync = util.promisify(exec);
9
-
10
- // Configuration
11
- const MODEL = 'deepseek/deepseek-chat-v3-0324:free';
12
- const API_BASE_URL = 'https://openrouter.ai/api/v1';
13
-
14
- // System prompt matching the VS Code extension
15
- const SYSTEM_PROMPT = `You are a VS Code AI Assistant with agency capabilities. You can perform actions on the user's workspace.
16
-
17
- ENVIRONMENT CONTEXT:
18
- - OS: ${process.platform}
19
- - Working Directory: ${process.cwd()}
20
-
21
- When you need to perform actions, respond with JSON in the following format:
22
- \`\`\`json
23
- {
24
- "thoughts": "Your reasoning about what needs to be done",
25
- "actions": [
26
- {
27
- "type": "read|write|search|command|analyze|execute|stop",
28
- "data": { ... action specific data ... }
29
- }
30
- ]
31
- }
32
- \`\`\`
33
-
34
- Action types and their data:
35
- - read: { "path": "relative/or/absolute/path" }
36
- - write: { "path": "relative/or/absolute/path", "content": "file content" }
37
- - search: { "type": "files", "pattern": "glob pattern" } or { "type": "text", "text": "search text" }
38
- - command: { "command": "command string to execute in terminal" }
39
- - execute: { "language": "js|python|bash|...", "code": "code to execute" }
40
- - analyze: { "code": "code to analyze", "question": "what you want to analyze" }
41
- - browse: { "query": "search query", "numResults": 5 } (free web search using DuckDuckGo, optional numResults)
42
- - edit: {
43
- "path": "relative/or/absolute/path",
44
- "edits": {
45
- "operations": [
46
- { "type": "replace", "startLine": 10, "endLine": 15, "newText": "new code here" },
47
- { "type": "replace", "pattern": "oldFunction\\(\\)", "replacement": "newFunction()", "flags": "g" },
48
- { "type": "insert", "line": 20, "text": "new line of code here" },
49
- { "type": "insert", "position": "start", "text": "// Header comment" },
50
- { "type": "insert", "position": "end", "text": "// Footer comment" },
51
- { "type": "delete", "startLine": 25, "endLine": 30 }
52
- ]
53
- }
54
- } (edit specific parts of an existing file)
55
- - stop: {} (use this to indicate you're done with the task and no more actions are needed)
56
-
57
- By default, you will continue to take actions in a loop until you decide to stop with the 'stop' action type.
58
- Always wrap your JSON in markdown code blocks with the json language specifier.
59
- When executing code or commands that might be potentially harmful, explain what the code does before executing it.`;
60
-
61
- // Agent utilities
62
- const agentUtils = {
63
- async readFile(filePath) {
64
- try {
65
- const content = await fs.readFile(filePath, 'utf-8');
66
- return content;
67
- } catch (error) {
68
- throw new Error(`Failed to read file ${filePath}: ${error.message}`);
69
- }
70
- },
71
-
72
- async writeFile(filePath, content) {
73
- try {
74
- await fs.writeFile(filePath, content, 'utf-8');
75
- return `Successfully wrote to ${filePath}`;
76
- } catch (error) {
77
- throw new Error(`Failed to write to file ${filePath}: ${error.message}`);
78
- }
79
- },
80
-
81
- async runCommand(command) {
82
- try {
83
- const { stdout, stderr } = await execAsync(command, { cwd: process.cwd() });
84
- if (stderr) {
85
- console.error('Command stderr:', stderr);
86
- }
87
- return stdout || 'Command executed successfully (no output)';
88
- } catch (error) {
89
- throw new Error(`Command failed: ${error.message}`);
90
- }
91
- },
92
-
93
- async searchFiles(pattern) {
94
- try {
95
- const { stdout } = await execAsync(`find . -name "${pattern}"`, { cwd: process.cwd() });
96
- return stdout || 'No files found';
97
- } catch (error) {
98
- throw new Error(`Search failed: ${error.message}`);
99
- }
100
- }
101
- };
102
-
103
- // Extract JSON from markdown code blocks
104
- function extractJsonFromMarkdown(text) {
105
- // Try to find a markdown code block with JSON content
106
- const codeBlockRegex = /```json\s*([\s\S]*?)\s*```/;
107
- const match = text.match(codeBlockRegex);
108
-
109
- if (match) {
110
- try {
111
- return JSON.parse(match[1]);
112
- } catch (error) {
113
- console.error('Error parsing JSON from markdown:', error);
114
- }
115
- }
116
-
117
- // If no code block, try to parse the entire text as JSON
118
- try {
119
- return JSON.parse(text);
120
- } catch (error) {
121
- console.error('Error parsing JSON:', error);
122
- return null;
123
- }
124
- }
125
-
126
- // Call OpenRouter API
127
- async function callOpenRouter(messages) {
128
- const apiKey = process.env.OPENROUTER_API_KEY;
129
-
130
- if (!apiKey) {
131
- throw new Error('OPENROUTER_API_KEY environment variable is not set');
132
- }
133
-
134
- try {
135
- const response = await fetch(API_BASE_URL + '/chat/completions', {
136
- method: 'POST',
137
- headers: {
138
- 'Content-Type': 'application/json',
139
- 'Authorization': `Bearer ${apiKey}`,
140
- 'HTTP-Referer': 'https://github.com/yourusername/agi-cli'
141
- },
142
- body: JSON.stringify({
143
- model: MODEL,
144
- messages: messages
145
- })
146
- });
147
-
148
- if (!response.ok) {
149
- const error = await response.json();
150
- throw new Error(`API error: ${error.error?.message || response.statusText}`);
151
- }
152
-
153
- return await response.json();
154
- } catch (error) {
155
- console.error('API call failed:', error);
156
- throw new Error(`Failed to call OpenRouter API: ${error.message}`);
157
- }
158
- }
159
-
160
- // Process a query with action handling
161
- async function processQuery(query, conversation = []) {
162
- try {
163
- // Add user message to conversation
164
- const userMessage = { role: 'user', content: query };
165
- const messages = [...conversation, userMessage];
166
-
167
- // Add system message if this is the first message
168
- if (conversation.length === 0) {
169
- messages.unshift({
170
- role: 'system',
171
- content: SYSTEM_PROMPT
172
- });
173
- }
174
-
175
- let shouldContinue = true;
176
- let iteration = 0;
177
- const maxIterations = 10; // Prevent infinite loops
178
- let finalResponse = '';
179
-
180
- while (shouldContinue && iteration < maxIterations) {
181
- iteration++;
182
- console.log('🤖 Thinking...');
183
-
184
- const response = await callOpenRouter(messages);
185
- const assistantMessage = response.choices[0].message;
186
-
187
- // Add assistant's message to the conversation
188
- messages.push(assistantMessage);
189
-
190
- // Check if the response contains actions
191
- const actionData = extractJsonFromMarkdown(assistantMessage.content);
192
-
193
- if (actionData && actionData.actions && Array.isArray(actionData.actions)) {
194
- console.log(`🔧 Processing ${actionData.actions.length} actions...`);
195
- if (actionData.thoughts) {
196
- console.log(`💭 ${actionData.thoughts}`);
197
- }
198
-
199
- const actionResults = [];
200
-
201
- for (const action of actionData.actions) {
202
- console.log(`🛠️ Executing action: ${action.type}`);
203
-
204
- // Handle stop action
205
- if (action.type === 'stop') {
206
- console.log('🛑 Stop action received, ending action processing');
207
- shouldContinue = false;
208
- finalResponse = 'Task completed successfully.';
209
- break;
210
- }
211
-
212
- try {
213
- let result;
214
-
215
- switch (action.type) {
216
- case 'read':
217
- result = await agentUtils.readFile(action.data.path);
218
- break;
219
-
220
- case 'write':
221
- result = await agentUtils.writeFile(action.data.path, action.data.content);
222
- break;
223
-
224
- case 'command':
225
- result = await agentUtils.runCommand(action.data.command);
226
- break;
227
-
228
- case 'search':
229
- if (action.data.type === 'files') {
230
- result = await agentUtils.searchFiles(action.data.pattern);
231
- } else {
232
- result = 'Text search not yet implemented';
233
- }
234
- break;
235
-
236
- default:
237
- result = `Action type '${action.type}' is not supported yet.`;
238
- }
239
-
240
- actionResults.push({
241
- type: action.type,
242
- success: true,
243
- result: result
244
- });
245
-
246
- console.log(`✅ Action ${action.type} completed successfully`);
247
-
248
- } catch (error) {
249
- console.error(`❌ Action ${action.type} failed:`, error);
250
- actionResults.push({
251
- type: action.type,
252
- success: false,
253
- error: error.message
254
- });
255
- }
256
- }
257
-
258
- // Add action results to the conversation
259
- messages.push({
260
- role: 'system',
261
- content: `Action results:\n\`\`\`json\n${JSON.stringify(actionResults, null, 2)}\n\`\`\`\n` +
262
- `Based on these results, determine what to do next. You can:\n` +
263
- `1. Continue with more actions by returning a new JSON with "actions" array\n` +
264
- `2. Stop the iteration by including an action with "type": "stop" if the task is completed\n` +
265
- `3. Provide a final response to the user with your findings`
266
- });
267
-
268
- } else {
269
- // No actions, this is a regular response
270
- shouldContinue = false;
271
- finalResponse = assistantMessage.content;
272
- }
273
- }
274
-
275
- // If we hit max iterations, add a note
276
- if (iteration >= maxIterations) {
277
- finalResponse += '\n\n⚠️ Reached maximum number of iterations. Stopping execution.';
278
- }
279
-
280
- return {
281
- response: finalResponse,
282
- conversation: messages
283
- };
284
-
285
- } catch (error) {
286
- console.error('Error processing query:', error);
287
- return {
288
- response: `Error: ${error.message}`,
289
- conversation
290
- };
291
- }
292
- }
293
-
294
- // Main chat loop
295
- async function chat() {
296
- const conversation = [];
297
- console.log('Welcome to AGI-CLI. Type your message, or "exit" to quit.');
298
-
299
- const rl = readline.createInterface({
300
- input: process.stdin,
301
- output: process.stdout,
302
- prompt: '> '
303
- });
304
-
305
- rl.prompt();
306
-
307
- rl.on('line', async (input) => {
308
- if (input.toLowerCase() === 'exit') {
309
- rl.close();
310
- return;
311
- }
312
-
313
- const result = await processQuery(input, conversation);
314
- console.log(result.response);
315
-
316
- // Update conversation with the full context
317
- conversation.length = 0; // Clear the array
318
- result.conversation.forEach(msg => conversation.push(msg));
319
-
320
- rl.prompt();
321
- }).on('close', () => {
322
- console.log('Goodbye!');
323
- process.exit(0);
324
- });
325
- }
326
-
327
- // Start the chat
328
- chat().catch(console.error);
@@ -1,218 +0,0 @@
1
- import pygame
2
- import random
3
-
4
- # Initialize pygame
5
- pygame.init()
6
-
7
- # Constants
8
- SCREEN_WIDTH = 300
9
- SCREEN_HEIGHT = 600
10
- BLOCK_SIZE = 30
11
- GRID_WIDTH = 10
12
- GRID_HEIGHT = 20
13
- GAME_AREA_LEFT = (SCREEN_WIDTH - GRID_WIDTH * BLOCK_SIZE) // 2
14
- GAME_AREA_TOP = SCREEN_HEIGHT - GRID_HEIGHT * BLOCK_SIZE
15
-
16
- # Colors
17
- BLACK = (0, 0, 0)
18
- WHITE = (255, 255, 255)
19
- GRAY = (128, 128, 128)
20
- COLORS = [
21
- (0, 255, 255), # Cyan (I)
22
- (0, 0, 255), # Blue (J)
23
- (255, 165, 0), # Orange (L)
24
- (255, 255, 0), # Yellow (O)
25
- (0, 255, 0), # Green (S)
26
- (128, 0, 128), # Purple (T)
27
- (255, 0, 0) # Red (Z)
28
- ]
29
-
30
- # Tetrimino shapes
31
- SHAPES = [
32
- [[1, 1, 1, 1]], # I
33
- [[1, 0, 0], [1, 1, 1]], # J
34
- [[0, 0, 1], [1, 1, 1]], # L
35
- [[1, 1], [1, 1]], # O
36
- [[0, 1, 1], [1, 1, 0]], # S
37
- [[0, 1, 0], [1, 1, 1]], # T
38
- [[1, 1, 0], [0, 1, 1]] # Z
39
- ]
40
-
41
- # Set up the display
42
- screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
43
- pygame.display.set_caption("Tetris")
44
-
45
- clock = pygame.time.Clock()
46
-
47
- # Game variables
48
- grid = [[0 for _ in range(GRID_WIDTH)] for _ in range(GRID_HEIGHT)]
49
- current_piece = None
50
- next_piece = None
51
- current_x = GRID_WIDTH // 2
52
- current_y = 0
53
- score = 0
54
- game_over = False
55
- fall_time = 0
56
- fall_speed = 0.5 # seconds
57
-
58
- def new_piece():
59
- global current_piece, next_piece, current_x, current_y
60
- if next_piece is None:
61
- next_piece = random.randint(0, len(SHAPES) - 1)
62
- current_piece = next_piece
63
- next_piece = random.randint(0, len(SHAPES) - 1)
64
- current_x = GRID_WIDTH // 2 - len(SHAPES[current_piece][0]) // 2
65
- current_y = 0
66
- if check_collision():
67
- return False
68
- return True
69
-
70
- def check_collision():
71
- for y, row in enumerate(SHAPES[current_piece]):
72
- for x, cell in enumerate(row):
73
- if cell:
74
- if (current_y + y >= GRID_HEIGHT or
75
- current_x + x < 0 or
76
- current_x + x >= GRID_WIDTH or
77
- grid[current_y + y][current_x + x]):
78
- return True
79
- return False
80
-
81
- def merge_piece():
82
- for y, row in enumerate(SHAPES[current_piece]):
83
- for x, cell in enumerate(row):
84
- if cell:
85
- grid[current_y + y][current_x + x] = current_piece + 1
86
-
87
- def clear_lines():
88
- global grid, score
89
- lines_cleared = 0
90
- for y in range(GRID_HEIGHT - 1, -1, -1):
91
- if all(grid[y]):
92
- lines_cleared += 1
93
- for y2 in range(y, 0, -1):
94
- grid[y2] = grid[y2 - 1][:]
95
- grid[0] = [0] * GRID_WIDTH
96
- score += lines_cleared ** 2 * 100
97
-
98
- def draw_grid():
99
- for y in range(GRID_HEIGHT):
100
- for x in range(GRID_WIDTH):
101
- if grid[y][x]:
102
- pygame.draw.rect(
103
- screen, COLORS[grid[y][x] - 1],
104
- (GAME_AREA_LEFT + x * BLOCK_SIZE, GAME_AREA_TOP + y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE)
105
- )
106
- pygame.draw.rect(
107
- screen, WHITE,
108
- (GAME_AREA_LEFT + x * BLOCK_SIZE, GAME_AREA_TOP + y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE),
109
- 1
110
- )
111
-
112
- def draw_piece():
113
- for y, row in enumerate(SHAPES[current_piece]):
114
- for x, cell in enumerate(row):
115
- if cell:
116
- pygame.draw.rect(
117
- screen, COLORS[current_piece],
118
- (GAME_AREA_LEFT + (current_x + x) * BLOCK_SIZE, GAME_AREA_TOP + (current_y + y) * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE)
119
- )
120
- pygame.draw.rect(
121
- screen, WHITE,
122
- (GAME_AREA_LEFT + (current_x + x) * BLOCK_SIZE, GAME_AREA_TOP + (current_y + y) * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE),
123
- 1
124
- )
125
-
126
- def draw_next_piece():
127
- if next_piece is not None:
128
- font = pygame.font.SysFont(None, 24)
129
- text = font.render("Next:", True, WHITE)
130
- screen.blit(text, (20, 20))
131
- for y, row in enumerate(SHAPES[next_piece]):
132
- for x, cell in enumerate(row):
133
- if cell:
134
- pygame.draw.rect(
135
- screen, COLORS[next_piece],
136
- (40 + x * BLOCK_SIZE, 50 + y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE)
137
- )
138
- pygame.draw.rect(
139
- screen, WHITE,
140
- (40 + x * BLOCK_SIZE, 50 + y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE),
141
- 1
142
- )
143
-
144
- def draw_score():
145
- font = pygame.font.SysFont(None, 36)
146
- text = font.render(f"Score: {score}", True, WHITE)
147
- screen.blit(text, (20, SCREEN_HEIGHT - 50))
148
-
149
- def rotate_piece():
150
- global current_piece
151
- rotated = list(zip(*reversed(SHAPES[current_piece])))
152
- for y in range(len(rotated)):
153
- rotated[y] = list(rotated[y])
154
- old_shape = SHAPES[current_piece]
155
- SHAPES[current_piece] = rotated
156
- if check_collision():
157
- SHAPES[current_piece] = old_shape
158
-
159
- # Main game loop
160
- new_piece()
161
- running = True
162
- while running:
163
- screen.fill(BLACK)
164
- fall_time += clock.get_rawtime() / 1000 # Convert to seconds
165
- clock.tick()
166
-
167
- if fall_time >= fall_speed:
168
- fall_time = 0
169
- current_y += 1
170
- if check_collision():
171
- current_y -= 1
172
- merge_piece()
173
- clear_lines()
174
- if not new_piece():
175
- game_over = True
176
-
177
- for event in pygame.event.get():
178
- if event.type == pygame.QUIT:
179
- running = False
180
- if event.type == pygame.KEYDOWN:
181
- if event.key == pygame.K_LEFT:
182
- current_x -= 1
183
- if check_collision():
184
- current_x += 1
185
- if event.key == pygame.K_RIGHT:
186
- current_x += 1
187
- if check_collision():
188
- current_x -= 1
189
- if event.key == pygame.K_DOWN:
190
- current_y += 1
191
- if check_collision():
192
- current_y -= 1
193
- if event.key == pygame.K_UP:
194
- rotate_piece()
195
- if event.key == pygame.K_SPACE:
196
- while not check_collision():
197
- current_y += 1
198
- current_y -= 1
199
- merge_piece()
200
- clear_lines()
201
- if not new_piece():
202
- game_over = True
203
-
204
- draw_grid()
205
- draw_piece()
206
- draw_next_piece()
207
- draw_score()
208
- pygame.display.update()
209
-
210
- if game_over:
211
- font = pygame.font.SysFont(None, 48)
212
- text = font.render("GAME OVER", True, WHITE)
213
- screen.blit(text, (SCREEN_WIDTH // 2 - 100, SCREEN_HEIGHT // 2 - 24))
214
- pygame.display.update()
215
- pygame.time.wait(2000)
216
- running = False
217
-
218
- pygame.quit()