chels-code 0.5.1 → 0.5.3
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/src/cli.js +32 -0
- package/dist/src/engine.js +36 -8
- package/dist/src/version.js +1 -1
- package/package.json +1 -1
package/dist/src/cli.js
CHANGED
|
@@ -4,6 +4,7 @@ import path from "node:path";
|
|
|
4
4
|
import { realpathSync } from "node:fs";
|
|
5
5
|
import { writeFile } from "node:fs/promises";
|
|
6
6
|
import { createInterface } from "node:readline";
|
|
7
|
+
import { exec } from "node:child_process";
|
|
7
8
|
import { stdin, stdout } from "node:process";
|
|
8
9
|
import { fileURLToPath } from "node:url";
|
|
9
10
|
import { render } from "ink";
|
|
@@ -108,6 +109,36 @@ async function ensureApiKeys() {
|
|
|
108
109
|
rl.close();
|
|
109
110
|
}
|
|
110
111
|
}
|
|
112
|
+
async function checkAndPromptUpdate() {
|
|
113
|
+
try {
|
|
114
|
+
const response = await fetch("https://registry.npmjs.org/chelscode/latest");
|
|
115
|
+
if (!response.ok)
|
|
116
|
+
return;
|
|
117
|
+
const data = (await response.json());
|
|
118
|
+
const latest = data.version;
|
|
119
|
+
if (!latest || latest === VERSION)
|
|
120
|
+
return;
|
|
121
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
122
|
+
const answer = await new Promise((resolve) => {
|
|
123
|
+
rl.question(`A new version of ChelsCode is available (${latest}). Update now? (y/n): `, (res) => resolve(res.trim()));
|
|
124
|
+
});
|
|
125
|
+
rl.close();
|
|
126
|
+
if (answer.toLowerCase() === "y" || answer.toLowerCase() === "yes") {
|
|
127
|
+
await new Promise((resolve, reject) => {
|
|
128
|
+
exec(`npm install -g chelscode@${latest}`, { cwd: process.cwd() }, (error, _stdout, stderr) => {
|
|
129
|
+
if (error)
|
|
130
|
+
reject(error);
|
|
131
|
+
else
|
|
132
|
+
resolve();
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
process.exit(0);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
// Ignore update-check failures.
|
|
140
|
+
}
|
|
141
|
+
}
|
|
111
142
|
async function main() {
|
|
112
143
|
const options = parseOptions(process.argv.slice(2));
|
|
113
144
|
if (options.help) {
|
|
@@ -157,6 +188,7 @@ async function main() {
|
|
|
157
188
|
saveSession(session);
|
|
158
189
|
const restoreTitle = installTerminalTitle("ChelsCode");
|
|
159
190
|
try {
|
|
191
|
+
await checkAndPromptUpdate();
|
|
160
192
|
const instance = render(_jsx(App, { apiKeys: apiKeys, workspace: workspace, version: VERSION, sessionId: session.id, resume: resumed, missingKeys: keysMissing }), {
|
|
161
193
|
exitOnCtrlC: true,
|
|
162
194
|
kittyKeyboard: { mode: "auto" },
|
package/dist/src/engine.js
CHANGED
|
@@ -87,8 +87,8 @@ const EFFORT_GUIDANCE = {
|
|
|
87
87
|
low: "Keep analysis and responses brief and direct.",
|
|
88
88
|
medium: "Stay clear and practical without unnecessary detail.",
|
|
89
89
|
high: "Check assumptions and explain the important details.",
|
|
90
|
-
max: "Be thorough, verify edge cases, and avoid ambiguity.",
|
|
91
|
-
ultra: "Be exhaustive, double-check each step, and call out risks and alternatives.",
|
|
90
|
+
max: "Be thorough, verify edge cases, and avoid ambiguity. Act decisively and code fast while verifying.",
|
|
91
|
+
ultra: "Be exhaustive, double-check each step, and call out risks and alternatives. Prioritize a fast implementation while verifying as you go.",
|
|
92
92
|
};
|
|
93
93
|
function withEffort(messages, effort) {
|
|
94
94
|
const guidance = `Work at ${effort} effort. ${EFFORT_GUIDANCE[effort]}`;
|
|
@@ -218,18 +218,19 @@ async function runToolLoop({ provider, apiKey, model, system, user, tools, maxRo
|
|
|
218
218
|
];
|
|
219
219
|
const allowed = new Set(tools.map((tool) => tool.function.name));
|
|
220
220
|
const made = [];
|
|
221
|
+
let roundStart = Date.now();
|
|
221
222
|
const context = {
|
|
222
223
|
workspace,
|
|
223
224
|
confirm: async (action) => {
|
|
224
225
|
const approved = await hooks.confirmAction(action);
|
|
225
226
|
if (approved)
|
|
226
|
-
hooks.onStatus(`${PROVIDERS[provider].label} is working
|
|
227
|
+
hooks.onStatus(statusWithElapsed(`${PROVIDERS[provider].label} is working…`, roundStart));
|
|
227
228
|
return approved;
|
|
228
229
|
},
|
|
229
230
|
onMade: (item) => appendMade(made, item),
|
|
230
231
|
};
|
|
231
232
|
for (let toolRound = 0; toolRound < maxRounds; toolRound += 1) {
|
|
232
|
-
|
|
233
|
+
roundStart = Date.now();
|
|
233
234
|
hooks.onStatus(statusWithElapsed(`${PROVIDERS[provider].label} is thinking…`, roundStart));
|
|
234
235
|
let assistantMessage;
|
|
235
236
|
try {
|
|
@@ -260,7 +261,7 @@ async function runToolLoop({ provider, apiKey, model, system, user, tools, maxRo
|
|
|
260
261
|
result = `Tool error: ${message}.`;
|
|
261
262
|
}
|
|
262
263
|
else {
|
|
263
|
-
hooks.onStatus(`${PROVIDERS[provider].label} is working
|
|
264
|
+
hooks.onStatus(statusWithElapsed(`${PROVIDERS[provider].label} is working…`, roundStart));
|
|
264
265
|
try {
|
|
265
266
|
result = await executeTool(name, toolCall.function?.arguments ?? "{}", context);
|
|
266
267
|
}
|
|
@@ -296,7 +297,8 @@ async function runAgentTask({ provider, apiKey, model, request, task, workspace,
|
|
|
296
297
|
}
|
|
297
298
|
async function answerQuestion({ request, apiKeys, models, workspace, hooks, effort, }) {
|
|
298
299
|
const provider = "openrouter";
|
|
299
|
-
|
|
300
|
+
const answerStart = Date.now();
|
|
301
|
+
hooks.onStatus(statusWithElapsed(`${PROVIDERS[provider].label} is answering…`, answerStart));
|
|
300
302
|
try {
|
|
301
303
|
const { text, made } = await runToolLoop({
|
|
302
304
|
provider,
|
|
@@ -385,7 +387,8 @@ export function createEngine({ apiKeys, models, workspace, hooks, effort }) {
|
|
|
385
387
|
throw new Error(`All three AIs must analyze the task before it can continue.\n${failures.join("\n")}`);
|
|
386
388
|
}
|
|
387
389
|
hooks.onStatus(null);
|
|
388
|
-
|
|
390
|
+
const combineStart = Date.now();
|
|
391
|
+
hooks.onStatus(statusWithElapsed("OpenRouter is combining the proposals…", combineStart));
|
|
389
392
|
let tasks;
|
|
390
393
|
try {
|
|
391
394
|
tasks = await coordinatePlan({
|
|
@@ -431,10 +434,35 @@ export function createEngine({ apiKeys, models, workspace, hooks, effort }) {
|
|
|
431
434
|
title: `${PROVIDERS[provider].label} subtask failed`,
|
|
432
435
|
message: errorMessage(error),
|
|
433
436
|
});
|
|
437
|
+
// OpenRouter is the preferred coder. If it is having a hard time,
|
|
438
|
+
// divide the task across the other available AIs instead of stopping.
|
|
439
|
+
if (provider === "openrouter") {
|
|
440
|
+
const fallbacks = ["nvidia", "groq"];
|
|
441
|
+
for (const fallbackProvider of fallbacks) {
|
|
442
|
+
try {
|
|
443
|
+
const fallbackResult = await runAgentTask({
|
|
444
|
+
provider: fallbackProvider,
|
|
445
|
+
apiKey: apiKeys[fallbackProvider],
|
|
446
|
+
model: models[fallbackProvider].id,
|
|
447
|
+
request,
|
|
448
|
+
task,
|
|
449
|
+
workspace,
|
|
450
|
+
hooks,
|
|
451
|
+
effort,
|
|
452
|
+
});
|
|
453
|
+
outcomes.push({ title: task.title, provider: fallbackProvider, result: fallbackResult.text, failed: false });
|
|
454
|
+
break;
|
|
455
|
+
}
|
|
456
|
+
catch (fallbackError) {
|
|
457
|
+
outcomes.push({ title: task.title, provider: fallbackProvider, result: errorMessage(fallbackError), failed: true });
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
434
461
|
break;
|
|
435
462
|
}
|
|
436
463
|
}
|
|
437
|
-
|
|
464
|
+
const finalStart = Date.now();
|
|
465
|
+
hooks.onStatus(statusWithElapsed("OpenRouter is writing the final answer…", finalStart));
|
|
438
466
|
try {
|
|
439
467
|
const finalText = await askForFinalReport({
|
|
440
468
|
apiKey: apiKeys.openrouter,
|
package/dist/src/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = "0.5.
|
|
1
|
+
export const VERSION = "0.5.3";
|