bytarch-cli 0.1.0 → 0.1.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/bin/bytarch-cli.js +14 -1
- package/package.json +1 -1
- package/src/chat.ts +124 -0
package/bin/bytarch-cli.js
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
require('../dist/index.js');
|
|
3
|
+
require('../dist/index.js');
|
|
4
|
+
|
|
5
|
+
// If invoked with no subcommands, enter chat mode by default
|
|
6
|
+
try {
|
|
7
|
+
const argv = process.argv.slice(2);
|
|
8
|
+
if (argv.length === 0) {
|
|
9
|
+
const chat = require('../dist/chat');
|
|
10
|
+
chat.runChat().catch((e) => {
|
|
11
|
+
console.error('Chat mode failed:', e);
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
} catch (e) {
|
|
15
|
+
// ignore
|
|
16
|
+
}
|
package/package.json
CHANGED
package/src/chat.ts
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import * as readline from 'readline';
|
|
2
|
+
import { BytarchProvider } from './provider/bytarch';
|
|
3
|
+
import { ConfigManager } from './workspace/config';
|
|
4
|
+
import { EditManager } from './workspace/edits';
|
|
5
|
+
import { UI } from './ui/prompts';
|
|
6
|
+
import { extractJsonFromResponse } from './provider/evaluation';
|
|
7
|
+
|
|
8
|
+
// Simple chat-first entry point with an explicit /apply flow inside chat.
|
|
9
|
+
export async function runChat(): Promise<void> {
|
|
10
|
+
const workspacePath = process.cwd() + '/.genie-cli';
|
|
11
|
+
const config = await new ConfigManager(workspacePath).loadConfig();
|
|
12
|
+
const apiKey = new ConfigManager(workspacePath).getApiKey(config);
|
|
13
|
+
const provider = new BytarchProvider(config.endpoint, config.model, apiKey);
|
|
14
|
+
const editManager = new EditManager(workspacePath);
|
|
15
|
+
|
|
16
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
17
|
+
UI.header('BYTARCH AI Chat (type your message; use /apply, /list, /help)');
|
|
18
|
+
|
|
19
|
+
const ask = (q: string) => new Promise<string>(resolve => rl.question(q, ans => resolve(ans)));
|
|
20
|
+
|
|
21
|
+
// Simple REPL-like loop
|
|
22
|
+
while (true) {
|
|
23
|
+
const input = await ask('You: ');
|
|
24
|
+
const text = (input || '').trim();
|
|
25
|
+
if (!text) break;
|
|
26
|
+
|
|
27
|
+
// Command handling
|
|
28
|
+
if (text.startsWith('/')) {
|
|
29
|
+
const [cmd, ...args] = text.slice(1).split(' ');
|
|
30
|
+
switch (cmd.toLowerCase()) {
|
|
31
|
+
case 'help':
|
|
32
|
+
UI.info('Commands:');
|
|
33
|
+
UI.list([
|
|
34
|
+
'/help - show this help',
|
|
35
|
+
'/list - list pending/available edits',
|
|
36
|
+
'/apply [id|all] - apply a specific patch or all accepted patches',
|
|
37
|
+
'/exit - quit chat'
|
|
38
|
+
]);
|
|
39
|
+
break;
|
|
40
|
+
case 'list': {
|
|
41
|
+
const edits = await editManager.listEdits();
|
|
42
|
+
if (edits.length === 0) {
|
|
43
|
+
UI.info('No edits found.');
|
|
44
|
+
} else {
|
|
45
|
+
edits.forEach(e => {
|
|
46
|
+
console.log(`- ${e.id} | ${e.path} | ${e.status} | ${e.description}`);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
case 'apply': {
|
|
52
|
+
// Apply one or more edits. If 'all', apply all accepted edits; if id, apply that patch.
|
|
53
|
+
const target = args.join(' ').trim();
|
|
54
|
+
const patches = await editManager.getPendingEdits();
|
|
55
|
+
const toApply = target ? patches.filter(p => p.id === target) : patches.filter(p => p.status === 'accepted');
|
|
56
|
+
if (toApply.length === 0) {
|
|
57
|
+
UI.warning('No edits available to apply for the given selector. Use /list to inspect edits.');
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
const { Patcher } = await import('./fs/patcher');
|
|
61
|
+
const patcher = new Patcher(process.cwd());
|
|
62
|
+
for (const edit of toApply) {
|
|
63
|
+
UI.header(`Applying ${edit.path} (${edit.id})`);
|
|
64
|
+
const result = await patcher.applyPatch(edit);
|
|
65
|
+
if (result.success) {
|
|
66
|
+
await editManager.updateEditStatus(edit.id, 'applied');
|
|
67
|
+
UI.success(`Applied ${edit.path} (${result.changes ?? 0} changes)`);
|
|
68
|
+
} else {
|
|
69
|
+
UI.error(`Failed to apply ${edit.path}: ${result.error}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
case 'exit':
|
|
75
|
+
case 'quit':
|
|
76
|
+
case 'close':
|
|
77
|
+
rl.close();
|
|
78
|
+
return;
|
|
79
|
+
default:
|
|
80
|
+
UI.warning('Unknown chat command. Type /help for options.');
|
|
81
|
+
}
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Regular chat message: send to AI and handle patch results
|
|
86
|
+
try {
|
|
87
|
+
const messages = [
|
|
88
|
+
{ role: 'system', content: 'You are a code-editing AI assistant. Return a JSON patch object when you want to edit a file.' },
|
|
89
|
+
{ role: 'user', content: text }
|
|
90
|
+
];
|
|
91
|
+
const response = await provider.chat(messages as any);
|
|
92
|
+
// Try to parse as JSON patch
|
|
93
|
+
try {
|
|
94
|
+
const patchObj = extractJsonFromResponse(response);
|
|
95
|
+
// Expect { path, patch, description, rationale }
|
|
96
|
+
if (patchObj && patchObj.path && patchObj.patch) {
|
|
97
|
+
const edit = {
|
|
98
|
+
id: editManager.generateEditId(),
|
|
99
|
+
path: patchObj.path,
|
|
100
|
+
description: patchObj.description || '',
|
|
101
|
+
rationale: patchObj.rationale || '',
|
|
102
|
+
patch: patchObj.patch,
|
|
103
|
+
status: 'pending' as const,
|
|
104
|
+
createdAt: new Date().toISOString(),
|
|
105
|
+
updatedAt: new Date().toISOString()
|
|
106
|
+
};
|
|
107
|
+
await editManager.saveEdit(edit as any);
|
|
108
|
+
UI.success(`New patch created for ${patchObj.path} (id: ${edit.id})`);
|
|
109
|
+
UI.info(`Type /apply ${edit.id} to apply, or /list to view edits.`);
|
|
110
|
+
} else {
|
|
111
|
+
UI.info(`AI: ${response}`);
|
|
112
|
+
}
|
|
113
|
+
} catch {
|
|
114
|
+
// Not a JSON patch, just print the AI response
|
|
115
|
+
UI.info(`AI: ${response}`);
|
|
116
|
+
}
|
|
117
|
+
} catch (err) {
|
|
118
|
+
UI.error(`AI error: ${err instanceof Error ? err.message : String(err)}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
rl.close();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export default runChat;
|