@polka-codes/cli 0.1.5 → 0.1.6
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/dist/handlers.js +36 -36
- package/dist/index.js +12 -12
- package/dist/runTask.d.ts +2 -2
- package/dist/runTask.js +22 -22
- package/package.json +1 -1
package/dist/handlers.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { spawn } from
|
|
2
|
-
import { readFile, writeFile } from
|
|
3
|
-
import { ToolResponseType, allTools, createServiceLogger } from
|
|
4
|
-
import { listFiles } from
|
|
5
|
-
import { replaceInFile } from
|
|
6
|
-
const logger = createServiceLogger(
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { ToolResponseType, allTools, createServiceLogger } from '@polka-codes/core';
|
|
4
|
+
import { listFiles } from './utils/listFiles';
|
|
5
|
+
import { replaceInFile } from './utils/replaceInFile';
|
|
6
|
+
const logger = createServiceLogger('cli/handlers');
|
|
7
7
|
const handleError = async (name, fn) => {
|
|
8
8
|
try {
|
|
9
9
|
return await fn();
|
|
@@ -33,7 +33,7 @@ const getStringArray = (args, name, defaultValue) => {
|
|
|
33
33
|
}
|
|
34
34
|
return defaultValue;
|
|
35
35
|
}
|
|
36
|
-
return ret.split(
|
|
36
|
+
return ret.split(',');
|
|
37
37
|
};
|
|
38
38
|
const getBoolean = (args, name, defaultValue) => {
|
|
39
39
|
const ret = args[name];
|
|
@@ -44,9 +44,9 @@ const getBoolean = (args, name, defaultValue) => {
|
|
|
44
44
|
return defaultValue;
|
|
45
45
|
}
|
|
46
46
|
switch (ret.toLowerCase()) {
|
|
47
|
-
case
|
|
47
|
+
case 'true':
|
|
48
48
|
return true;
|
|
49
|
-
case
|
|
49
|
+
case 'false':
|
|
50
50
|
return false;
|
|
51
51
|
default:
|
|
52
52
|
throw new Error(`Invalid argument value: ${name}`);
|
|
@@ -68,7 +68,7 @@ const getInt = (args, name, defaultValue) => {
|
|
|
68
68
|
};
|
|
69
69
|
const handlers = {
|
|
70
70
|
executeCommand: async (options, args) => {
|
|
71
|
-
const command = getString(args,
|
|
71
|
+
const command = getString(args, 'command');
|
|
72
72
|
const shouldExecute = (await options.executeCommand?.shouldExecute?.(command)) ?? true;
|
|
73
73
|
if (!shouldExecute) {
|
|
74
74
|
return {
|
|
@@ -76,7 +76,7 @@ const handlers = {
|
|
|
76
76
|
message: `<command>${command}</command><command_rejected>Rejected by policy</command_rejected>`,
|
|
77
77
|
};
|
|
78
78
|
}
|
|
79
|
-
const requiresApproval = getBoolean(args,
|
|
79
|
+
const requiresApproval = getBoolean(args, 'requires_approval', false);
|
|
80
80
|
if (requiresApproval) {
|
|
81
81
|
const shouldApprove = await options.executeCommand?.shouldApprove?.(command);
|
|
82
82
|
if (!shouldApprove) {
|
|
@@ -92,18 +92,18 @@ const handlers = {
|
|
|
92
92
|
logger.trace(`Executing command: ${command}`);
|
|
93
93
|
const child = spawn(command, [], {
|
|
94
94
|
shell: true,
|
|
95
|
-
stdio:
|
|
95
|
+
stdio: 'pipe',
|
|
96
96
|
});
|
|
97
97
|
options.executeCommand?.commandStarted?.(command, child);
|
|
98
|
-
let stdoutText =
|
|
99
|
-
let stderrText =
|
|
100
|
-
child.stdout.on(
|
|
98
|
+
let stdoutText = '';
|
|
99
|
+
let stderrText = '';
|
|
100
|
+
child.stdout.on('data', (data) => {
|
|
101
101
|
stdoutText += data.toString();
|
|
102
102
|
});
|
|
103
|
-
child.stderr.on(
|
|
103
|
+
child.stderr.on('data', (data) => {
|
|
104
104
|
stderrText += data.toString();
|
|
105
105
|
});
|
|
106
|
-
child.on(
|
|
106
|
+
child.on('close', (code) => {
|
|
107
107
|
const message = `<command>${command}</command>
|
|
108
108
|
<command_exit_code>${code}</command_exit_code>
|
|
109
109
|
<command_stdout>
|
|
@@ -126,13 +126,13 @@ ${stderrText}
|
|
|
126
126
|
});
|
|
127
127
|
}
|
|
128
128
|
});
|
|
129
|
-
child.on(
|
|
129
|
+
child.on('error', (err) => {
|
|
130
130
|
reject(err);
|
|
131
131
|
});
|
|
132
132
|
});
|
|
133
133
|
},
|
|
134
134
|
readFile: async (options, args) => {
|
|
135
|
-
const paths = getStringArray(args,
|
|
135
|
+
const paths = getStringArray(args, 'path');
|
|
136
136
|
for (const path of paths) {
|
|
137
137
|
const isPathAllowed = (await options.files?.isPathAllowed?.(path)) ?? true;
|
|
138
138
|
if (!isPathAllowed) {
|
|
@@ -144,17 +144,17 @@ ${stderrText}
|
|
|
144
144
|
}
|
|
145
145
|
const resp = [];
|
|
146
146
|
for (const path of paths) {
|
|
147
|
-
const fileContent = await readFile(path,
|
|
147
|
+
const fileContent = await readFile(path, 'utf8');
|
|
148
148
|
resp.push(`<read_file_file_conten path="${path}">${fileContent}</read_file_file_content>`);
|
|
149
149
|
}
|
|
150
150
|
return {
|
|
151
151
|
type: ToolResponseType.Reply,
|
|
152
|
-
message: resp.join(
|
|
152
|
+
message: resp.join('\n'),
|
|
153
153
|
};
|
|
154
154
|
},
|
|
155
155
|
writeToFile: async (options, args) => {
|
|
156
|
-
const path = getString(args,
|
|
157
|
-
const content = getString(args,
|
|
156
|
+
const path = getString(args, 'path');
|
|
157
|
+
const content = getString(args, 'content');
|
|
158
158
|
const isPathAllowed = (await options.files?.isPathAllowed?.(path)) ?? true;
|
|
159
159
|
if (!isPathAllowed) {
|
|
160
160
|
return {
|
|
@@ -162,15 +162,15 @@ ${stderrText}
|
|
|
162
162
|
message: `<path>${path}</path><path_rejected>Rejected by policy</path_rejected>`,
|
|
163
163
|
};
|
|
164
164
|
}
|
|
165
|
-
await writeFile(path, content,
|
|
165
|
+
await writeFile(path, content, 'utf8');
|
|
166
166
|
return {
|
|
167
167
|
type: ToolResponseType.Reply,
|
|
168
168
|
message: `<write_file_path>${path}</write_file_path><status>Success</status>`,
|
|
169
169
|
};
|
|
170
170
|
},
|
|
171
171
|
replaceInFile: async (options, args) => {
|
|
172
|
-
const path = getString(args,
|
|
173
|
-
const diff = getString(args,
|
|
172
|
+
const path = getString(args, 'path');
|
|
173
|
+
const diff = getString(args, 'diff');
|
|
174
174
|
const isPathAllowed = (await options.files?.isPathAllowed?.(path)) ?? true;
|
|
175
175
|
if (!isPathAllowed) {
|
|
176
176
|
return {
|
|
@@ -178,9 +178,9 @@ ${stderrText}
|
|
|
178
178
|
message: `<path>${path}</path><path_rejected>Rejected by policy</path_rejected>`,
|
|
179
179
|
};
|
|
180
180
|
}
|
|
181
|
-
const fileContent = await readFile(path,
|
|
181
|
+
const fileContent = await readFile(path, 'utf8');
|
|
182
182
|
const result = await replaceInFile(fileContent, diff);
|
|
183
|
-
await writeFile(path, result,
|
|
183
|
+
await writeFile(path, result, 'utf8');
|
|
184
184
|
return {
|
|
185
185
|
type: ToolResponseType.Reply,
|
|
186
186
|
message: `<replace_in_file_path>${path}</replace_in_file_path>`,
|
|
@@ -190,12 +190,12 @@ ${stderrText}
|
|
|
190
190
|
// TODO
|
|
191
191
|
return {
|
|
192
192
|
type: ToolResponseType.Exit,
|
|
193
|
-
message:
|
|
193
|
+
message: 'Files searched successfully',
|
|
194
194
|
};
|
|
195
195
|
},
|
|
196
196
|
listFiles: async (options, args) => {
|
|
197
|
-
const path = getString(args,
|
|
198
|
-
const depth = getInt(args,
|
|
197
|
+
const path = getString(args, 'path');
|
|
198
|
+
const depth = getInt(args, 'depth', 5);
|
|
199
199
|
const isPathAllowed = (await options.files?.isPathAllowed?.(path)) ?? true;
|
|
200
200
|
if (!isPathAllowed) {
|
|
201
201
|
return {
|
|
@@ -210,7 +210,7 @@ ${stderrText}
|
|
|
210
210
|
message: `<list_files_path>${path}</list_files_path>
|
|
211
211
|
<list_files_depth>${depth}</list_files_depth>
|
|
212
212
|
<list_files_files>
|
|
213
|
-
${files.join(
|
|
213
|
+
${files.join('\n')}
|
|
214
214
|
</list_files_files>
|
|
215
215
|
<list_files_truncated>${limitReached}</list_files_truncated>`,
|
|
216
216
|
};
|
|
@@ -219,20 +219,20 @@ ${files.join("\n")}
|
|
|
219
219
|
// TODO
|
|
220
220
|
return {
|
|
221
221
|
type: ToolResponseType.Exit,
|
|
222
|
-
message:
|
|
222
|
+
message: 'Code definition names listed successfully',
|
|
223
223
|
};
|
|
224
224
|
},
|
|
225
225
|
askFollowupQuestion: async (options, args) => {
|
|
226
226
|
// TODO
|
|
227
227
|
return {
|
|
228
228
|
type: ToolResponseType.Exit,
|
|
229
|
-
message:
|
|
229
|
+
message: 'Followup question asked successfully',
|
|
230
230
|
};
|
|
231
231
|
},
|
|
232
232
|
attemptCompletion: async (options, args) => {
|
|
233
233
|
return {
|
|
234
234
|
type: ToolResponseType.Exit,
|
|
235
|
-
message:
|
|
235
|
+
message: '<completed>true</completed>',
|
|
236
236
|
};
|
|
237
237
|
},
|
|
238
238
|
};
|
|
@@ -251,4 +251,4 @@ export const getToolHandler = (options) => {
|
|
|
251
251
|
return handler(options, args);
|
|
252
252
|
};
|
|
253
253
|
};
|
|
254
|
-
//# sourceMappingURL=handlers.js.map
|
|
254
|
+
//# sourceMappingURL=handlers.js.map
|
package/dist/index.js
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import { Command } from
|
|
2
|
-
import { loadConfig } from
|
|
3
|
-
import { runTask } from
|
|
4
|
-
const { version } = await import(
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { loadConfig } from './config';
|
|
3
|
+
import { runTask } from './runTask';
|
|
4
|
+
const { version } = await import('../package.json');
|
|
5
5
|
const program = new Command();
|
|
6
|
-
program.name(
|
|
6
|
+
program.name('polka').description('Polka Codes CLI').version(version);
|
|
7
7
|
// Main command for executing tasks
|
|
8
8
|
program
|
|
9
|
-
.argument(
|
|
10
|
-
.option(
|
|
11
|
-
.option(
|
|
12
|
-
.option(
|
|
13
|
-
.option(
|
|
9
|
+
.argument('[task]', 'The task to execute')
|
|
10
|
+
.option('-c --config <path>', 'Path to config file')
|
|
11
|
+
.option('--api-provider <provider>', 'API provider')
|
|
12
|
+
.option('--model-id <model>', 'Model ID')
|
|
13
|
+
.option('--api-key <key>', 'API key')
|
|
14
14
|
.action(async (taskArg, options) => {
|
|
15
15
|
const config = loadConfig(options.config ?? options.c) ?? {};
|
|
16
|
-
const provider = options.apiProvider || process.env.POLKA_API_PROVIDER || config.provider ||
|
|
16
|
+
const provider = options.apiProvider || process.env.POLKA_API_PROVIDER || config.provider || 'anthropic';
|
|
17
17
|
const model = options.modelId || process.env.POLKA_MODEL_ID || config.model;
|
|
18
18
|
const apiKey = options.apiKey || process.env.POLKA_API_KEY || config.apiKey;
|
|
19
19
|
await runTask({
|
|
@@ -25,4 +25,4 @@ program
|
|
|
25
25
|
});
|
|
26
26
|
});
|
|
27
27
|
program.parse();
|
|
28
|
-
//# sourceMappingURL=index.js.map
|
|
28
|
+
//# sourceMappingURL=index.js.map
|
package/dist/runTask.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Config } from
|
|
1
|
+
import type { Config } from './config';
|
|
2
2
|
export type RunTaskOptions = {
|
|
3
3
|
task: string;
|
|
4
4
|
provider: string;
|
|
@@ -7,4 +7,4 @@ export type RunTaskOptions = {
|
|
|
7
7
|
config: Config;
|
|
8
8
|
};
|
|
9
9
|
export declare const runTask: (options: RunTaskOptions) => Promise<void>;
|
|
10
|
-
//# sourceMappingURL=runTask.d.ts.map
|
|
10
|
+
//# sourceMappingURL=runTask.d.ts.map
|
package/dist/runTask.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import os from
|
|
2
|
-
import { CoderAgent, createService, createServiceLogger } from
|
|
3
|
-
import { getToolHandler } from
|
|
4
|
-
import { listFiles } from
|
|
5
|
-
const logger = createServiceLogger(
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import { CoderAgent, createService, createServiceLogger } from '@polka-codes/core';
|
|
3
|
+
import { getToolHandler } from './handlers';
|
|
4
|
+
import { listFiles } from './utils/listFiles';
|
|
5
|
+
const logger = createServiceLogger('cli/runTask');
|
|
6
6
|
export const runTask = async (options) => {
|
|
7
|
-
logger.debug(options,
|
|
7
|
+
logger.debug(options, 'Running task');
|
|
8
8
|
const { task, provider, model, apiKey, config } = options;
|
|
9
9
|
// Create service with the configured options
|
|
10
10
|
const service = createService(provider, {
|
|
@@ -12,7 +12,7 @@ export const runTask = async (options) => {
|
|
|
12
12
|
modelId: model,
|
|
13
13
|
});
|
|
14
14
|
let rules = config.rules;
|
|
15
|
-
if (typeof rules ===
|
|
15
|
+
if (typeof rules === 'string') {
|
|
16
16
|
rules = [rules];
|
|
17
17
|
}
|
|
18
18
|
const agent = new CoderAgent({
|
|
@@ -32,13 +32,13 @@ export const runTask = async (options) => {
|
|
|
32
32
|
},
|
|
33
33
|
commandStarted(command, child) {
|
|
34
34
|
console.log(`$ >>>> $ ${command}`);
|
|
35
|
-
child.stdout.on(
|
|
35
|
+
child.stdout.on('data', (data) => {
|
|
36
36
|
process.stdout.write(data.toString());
|
|
37
37
|
});
|
|
38
|
-
child.stderr.on(
|
|
38
|
+
child.stderr.on('data', (data) => {
|
|
39
39
|
process.stderr.write(data.toString());
|
|
40
40
|
});
|
|
41
|
-
child.on(
|
|
41
|
+
child.on('close', (code) => {
|
|
42
42
|
console.log(`$ <<<< $ Command exited with code: ${code}`);
|
|
43
43
|
});
|
|
44
44
|
},
|
|
@@ -48,7 +48,7 @@ export const runTask = async (options) => {
|
|
|
48
48
|
const cwd = process.cwd();
|
|
49
49
|
const [fileList, limited] = await listFiles(cwd, true, 100, cwd);
|
|
50
50
|
const fileContext = `<files>
|
|
51
|
-
${fileList.join(
|
|
51
|
+
${fileList.join('\n')}${limited ? '\n<files_truncated>true</files_truncated>' : ''}
|
|
52
52
|
</files>`;
|
|
53
53
|
const usage = {
|
|
54
54
|
inputTokens: 0,
|
|
@@ -62,29 +62,29 @@ ${fileList.join("\n")}${limited ? "\n<files_truncated>true</files_truncated>" :
|
|
|
62
62
|
context: `<now_date>${new Date().toISOString()}</now_date>${fileContext}`,
|
|
63
63
|
maxIterations: 10,
|
|
64
64
|
callback: (event) => {
|
|
65
|
-
if (event.kind ===
|
|
65
|
+
if (event.kind === 'usage') {
|
|
66
66
|
usage.inputTokens += event.info.inputTokens;
|
|
67
67
|
usage.outputTokens += event.info.outputTokens;
|
|
68
68
|
usage.cacheWriteTokens += event.info.cacheWriteTokens ?? 0;
|
|
69
69
|
usage.cacheReadTokens += event.info.cacheReadTokens ?? 0;
|
|
70
70
|
usage.totalCost += event.info.totalCost ?? 0;
|
|
71
71
|
}
|
|
72
|
-
if (event.kind ===
|
|
73
|
-
console.log(
|
|
72
|
+
if (event.kind === 'start_request') {
|
|
73
|
+
console.log('>>>>');
|
|
74
74
|
const { userContent } = event;
|
|
75
75
|
if (userContent) {
|
|
76
76
|
for (const content of userContent) {
|
|
77
|
-
console.log(content.type ===
|
|
77
|
+
console.log(content.type === 'text' ? content.text : '');
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
|
-
console.log(
|
|
80
|
+
console.log('====');
|
|
81
81
|
}
|
|
82
82
|
if (event.newText) {
|
|
83
83
|
process.stdout.write(event.newText);
|
|
84
84
|
}
|
|
85
|
-
if (event.kind ===
|
|
86
|
-
process.stdout.write(
|
|
87
|
-
console.log(
|
|
85
|
+
if (event.kind === 'end_request') {
|
|
86
|
+
process.stdout.write('\n');
|
|
87
|
+
console.log('<<<<');
|
|
88
88
|
}
|
|
89
89
|
},
|
|
90
90
|
});
|
|
@@ -95,13 +95,13 @@ ${fileList.join("\n")}${limited ? "\n<files_truncated>true</files_truncated>" :
|
|
|
95
95
|
const outputCost = (modelInfo.outputPrice ?? 0) * usage.outputTokens;
|
|
96
96
|
const cacheReadCost = (modelInfo.cacheReadsPrice ?? 0) * usage.cacheReadTokens;
|
|
97
97
|
const cacheWriteCost = (modelInfo.cacheWritesPrice ?? 0) * usage.cacheWriteTokens;
|
|
98
|
-
usage.totalCost = (inputCost + outputCost + cacheReadCost + cacheWriteCost) /
|
|
98
|
+
usage.totalCost = (inputCost + outputCost + cacheReadCost + cacheWriteCost) / 1_000_000;
|
|
99
99
|
}
|
|
100
|
-
console.log(
|
|
100
|
+
console.log('Usages:');
|
|
101
101
|
console.log(`Input tokens: ${usage.inputTokens}`);
|
|
102
102
|
console.log(`Output tokens: ${usage.outputTokens}`);
|
|
103
103
|
console.log(`Cache read tokens: ${usage.cacheReadTokens}`);
|
|
104
104
|
console.log(`Cache write tokens: ${usage.cacheWriteTokens}`);
|
|
105
105
|
console.log(`Total cost: ${usage.totalCost}`);
|
|
106
106
|
};
|
|
107
|
-
//# sourceMappingURL=runTask.js.map
|
|
107
|
+
//# sourceMappingURL=runTask.js.map
|