oroute-cli 0.3.0 → 0.3.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/dist/oroute.cjs +184 -108
- package/package.json +1 -1
package/dist/oroute.cjs
CHANGED
|
@@ -240950,6 +240950,33 @@ function getGitStatusSummary(cwd) {
|
|
|
240950
240950
|
return void 0;
|
|
240951
240951
|
}
|
|
240952
240952
|
}
|
|
240953
|
+
function detectMonorepo(cwd) {
|
|
240954
|
+
const indicators = [
|
|
240955
|
+
{ file: "pnpm-workspace.yaml", type: "pnpm workspace" },
|
|
240956
|
+
{ file: "turbo.json", type: "turborepo" },
|
|
240957
|
+
{ file: "nx.json", type: "nx" },
|
|
240958
|
+
{ file: "lerna.json", type: "lerna" },
|
|
240959
|
+
{ file: "rush.json", type: "rush" }
|
|
240960
|
+
];
|
|
240961
|
+
for (const { file, type } of indicators) {
|
|
240962
|
+
if (fs10.existsSync(path9.join(cwd, file))) {
|
|
240963
|
+
const dirs = ["apps", "packages", "libs", "services"].filter(
|
|
240964
|
+
(d) => fs10.existsSync(path9.join(cwd, d)) && fs10.statSync(path9.join(cwd, d)).isDirectory()
|
|
240965
|
+
);
|
|
240966
|
+
const packages = dirs.flatMap((d) => {
|
|
240967
|
+
try {
|
|
240968
|
+
return fs10.readdirSync(path9.join(cwd, d)).filter(
|
|
240969
|
+
(f) => fs10.statSync(path9.join(cwd, d, f)).isDirectory()
|
|
240970
|
+
).map((f) => `${d}/${f}`);
|
|
240971
|
+
} catch {
|
|
240972
|
+
return [];
|
|
240973
|
+
}
|
|
240974
|
+
});
|
|
240975
|
+
return `${type} (${packages.length} packages: ${packages.slice(0, 8).join(", ")}${packages.length > 8 ? "..." : ""})`;
|
|
240976
|
+
}
|
|
240977
|
+
}
|
|
240978
|
+
return null;
|
|
240979
|
+
}
|
|
240953
240980
|
function loadProjectContext(cwd) {
|
|
240954
240981
|
const contextFiles = [];
|
|
240955
240982
|
const candidates = [
|
|
@@ -240970,6 +240997,10 @@ function loadProjectContext(cwd) {
|
|
|
240970
240997
|
}
|
|
240971
240998
|
const gitBranch = getGitBranch(cwd);
|
|
240972
240999
|
const gitStatus = getGitStatusSummary(cwd);
|
|
241000
|
+
const monorepoType = detectMonorepo(cwd);
|
|
241001
|
+
if (monorepoType) {
|
|
241002
|
+
contextFiles.push({ name: "monorepo", content: monorepoType });
|
|
241003
|
+
}
|
|
240973
241004
|
return { files: contextFiles, gitBranch, gitStatus };
|
|
240974
241005
|
}
|
|
240975
241006
|
function buildContextString(ctx) {
|
|
@@ -241695,6 +241726,7 @@ function getActiveTasks() {
|
|
|
241695
241726
|
var import_meta = {};
|
|
241696
241727
|
var debugMode = false;
|
|
241697
241728
|
var dryRunMode = false;
|
|
241729
|
+
var skipConfirmations = false;
|
|
241698
241730
|
var lastAiResponse = "";
|
|
241699
241731
|
var undoStack = [];
|
|
241700
241732
|
function isDryRun() {
|
|
@@ -241779,6 +241811,9 @@ var ALL_COMMANDS = [
|
|
|
241779
241811
|
"/undo",
|
|
241780
241812
|
"/next-task",
|
|
241781
241813
|
"/dry-run",
|
|
241814
|
+
"/estimate-cost",
|
|
241815
|
+
"/skip-confirmation",
|
|
241816
|
+
"/yes",
|
|
241782
241817
|
// Conversion / Info
|
|
241783
241818
|
"/docx",
|
|
241784
241819
|
"/xlsx",
|
|
@@ -242258,6 +242293,26 @@ function handleSlashCommand(input, ctx) {
|
|
|
242258
242293
|
'"\uB2E4\uC74C \uC791\uC5C5" or "Pending Tasks\uC5D0\uC11C \uB2E4\uC74C \uAC70 \uC9C4\uD589\uD574\uC918"'
|
|
242259
242294
|
);
|
|
242260
242295
|
return "handled";
|
|
242296
|
+
case "/estimate-cost": {
|
|
242297
|
+
const tokenCount = ctx.messages.reduce((sum, m) => {
|
|
242298
|
+
const text = typeof m.content === "string" ? m.content : JSON.stringify(m.content);
|
|
242299
|
+
return sum + Math.ceil(text.length / 4);
|
|
242300
|
+
}, 0);
|
|
242301
|
+
const estInputCost = tokenCount / 1e6 * 3;
|
|
242302
|
+
const estOutputCost = 2e3 / 1e6 * 15;
|
|
242303
|
+
console.log(`${CYAN} Estimated cost for next request:${RESET}`);
|
|
242304
|
+
console.log(`${GRAY} Context: ~${tokenCount.toLocaleString()} tokens${RESET}`);
|
|
242305
|
+
console.log(`${GRAY} Input: ~$${estInputCost.toFixed(4)} (Sonnet rate)${RESET}`);
|
|
242306
|
+
console.log(`${GRAY} Output: ~$${estOutputCost.toFixed(4)} (est. 2K tokens)${RESET}`);
|
|
242307
|
+
console.log(`${GRAY} Total: ~$${(estInputCost + estOutputCost).toFixed(4)}${RESET}`);
|
|
242308
|
+
console.log(`${GRAY} (Auto-routing may select cheaper model)${RESET}`);
|
|
242309
|
+
return "handled";
|
|
242310
|
+
}
|
|
242311
|
+
case "/skip-confirmation":
|
|
242312
|
+
case "/yes":
|
|
242313
|
+
skipConfirmations = !skipConfirmations;
|
|
242314
|
+
console.log(`${skipConfirmations ? YELLOW : GREEN} Confirmations: ${skipConfirmations ? "SKIPPED (auto-yes)" : "ENABLED (will ask before writes)"}${RESET}`);
|
|
242315
|
+
return "handled";
|
|
242261
242316
|
// -----------------------------------------------------------------------
|
|
242262
242317
|
// Conversion / Info — natural language hints
|
|
242263
242318
|
// -----------------------------------------------------------------------
|
|
@@ -243276,121 +243331,142 @@ function truncateResult(result) {
|
|
|
243276
243331
|
async function executeTool(tool, cwd, config) {
|
|
243277
243332
|
const confirmWrite = config.skipConfirmations ? false : config.confirmBeforeWrite !== false;
|
|
243278
243333
|
const confirmExec = config.skipConfirmations ? false : config.confirmBeforeExecute !== false;
|
|
243334
|
+
const toolStart = performance.now();
|
|
243279
243335
|
try {
|
|
243280
|
-
|
|
243281
|
-
|
|
243282
|
-
|
|
243283
|
-
|
|
243284
|
-
|
|
243285
|
-
|
|
243286
|
-
|
|
243287
|
-
|
|
243288
|
-
|
|
243289
|
-
|
|
243290
|
-
|
|
243291
|
-
|
|
243292
|
-
|
|
243293
|
-
|
|
243294
|
-
|
|
243295
|
-
|
|
243296
|
-
|
|
243297
|
-
|
|
243298
|
-
|
|
243299
|
-
|
|
243300
|
-
|
|
243301
|
-
|
|
243302
|
-
|
|
243303
|
-
|
|
243336
|
+
const result = await executeToolInner(tool, cwd, confirmWrite, confirmExec, config);
|
|
243337
|
+
const elapsed = performance.now() - toolStart;
|
|
243338
|
+
if (elapsed > 100) {
|
|
243339
|
+
console.log(`${DIM} (${tool.name} took ${elapsed.toFixed(0)}ms)${RESET}`);
|
|
243340
|
+
}
|
|
243341
|
+
return result;
|
|
243342
|
+
} catch (err) {
|
|
243343
|
+
const elapsed = performance.now() - toolStart;
|
|
243344
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
243345
|
+
printError(`${tool.name}: ${msg}`);
|
|
243346
|
+
if (elapsed > 100) {
|
|
243347
|
+
console.log(`${DIM} (failed after ${elapsed.toFixed(0)}ms)${RESET}`);
|
|
243348
|
+
}
|
|
243349
|
+
return JSON.stringify({ error: msg });
|
|
243350
|
+
}
|
|
243351
|
+
}
|
|
243352
|
+
async function executeToolInner(tool, cwd, confirmWrite, confirmExec, config) {
|
|
243353
|
+
switch (tool.name) {
|
|
243354
|
+
case "read_file": {
|
|
243355
|
+
const input = tool.input;
|
|
243356
|
+
printToolUse("read_file", input.path);
|
|
243357
|
+
const result = await readFileTool(input, cwd);
|
|
243358
|
+
printToolResult(result.content);
|
|
243359
|
+
return truncateResult(JSON.stringify({ content: result.content, lines: result.lines, size: result.size }));
|
|
243360
|
+
}
|
|
243361
|
+
case "write_file": {
|
|
243362
|
+
const input = tool.input;
|
|
243363
|
+
printToolUse("write_file", input.path);
|
|
243364
|
+
const resolved = path16.resolve(cwd, input.path);
|
|
243365
|
+
const dangerPaths = ["/etc", "/usr", "/bin", "/sbin", "/System", "/Windows", "node_modules"];
|
|
243366
|
+
if (dangerPaths.some((d) => resolved.startsWith(d) || resolved.includes("node_modules"))) {
|
|
243367
|
+
console.log(`${RED} \u26A0 WARNING: Writing to system/protected path: ${resolved}${RESET}`);
|
|
243304
243368
|
}
|
|
243305
|
-
|
|
243306
|
-
|
|
243307
|
-
printToolUse("list_directory", input.path);
|
|
243308
|
-
const tree = listDirectoryTool(input, cwd);
|
|
243309
|
-
printToolResult(tree);
|
|
243310
|
-
return truncateResult(tree);
|
|
243369
|
+
if (resolved.includes(".env")) {
|
|
243370
|
+
console.log(`${YELLOW} \u26A0 Modifying .env file \u2014 secrets may be affected${RESET}`);
|
|
243311
243371
|
}
|
|
243312
|
-
|
|
243313
|
-
|
|
243314
|
-
|
|
243315
|
-
|
|
243316
|
-
|
|
243317
|
-
const meta = output.hasMore ? `
|
|
243318
|
-
(${output.totalFound}+ total matches, showing ${output.offset + 1}-${output.offset + output.results.length}. Use offset=${output.offset + output.limit} for more.)` : "";
|
|
243319
|
-
printToolResult((formatted || "No matches found.") + meta);
|
|
243320
|
-
return truncateResult(JSON.stringify(output));
|
|
243372
|
+
const diff = generateDiff(input.path, input.content, cwd);
|
|
243373
|
+
console.log(`${GRAY}${diff}${RESET}`);
|
|
243374
|
+
if (isDryRun()) {
|
|
243375
|
+
console.log(`${YELLOW} [DRY-RUN] Would write ${input.content.length} chars to ${input.path}${RESET}`);
|
|
243376
|
+
return JSON.stringify({ success: true, note: "dry-run \u2014 not written" });
|
|
243321
243377
|
}
|
|
243322
|
-
|
|
243323
|
-
const
|
|
243324
|
-
|
|
243325
|
-
if (config.planMode || isDryRun()) {
|
|
243326
|
-
const tag = config.planMode ? "PLAN MODE" : "DRY-RUN";
|
|
243327
|
-
console.log(`${YELLOW} [${tag}] Would execute: ${input.command}${RESET}`);
|
|
243328
|
-
return JSON.stringify({ stdout: `[${tag.toLowerCase()} \u2014 not executed]`, stderr: "", exitCode: 0 });
|
|
243329
|
-
}
|
|
243330
|
-
if (confirmExec) {
|
|
243331
|
-
const ok = await confirm(`Execute: ${input.command}`);
|
|
243332
|
-
if (!ok) return JSON.stringify({ stdout: "", stderr: "User declined", exitCode: -1 });
|
|
243333
|
-
}
|
|
243334
|
-
const result = executeCommandTool(input, cwd);
|
|
243335
|
-
if (result.stdout) printToolResult(result.stdout);
|
|
243336
|
-
if (result.stderr) console.log(`${RED}${result.stderr}${RESET}`);
|
|
243337
|
-
if (result.exitCode === 0) printSuccess("Command completed");
|
|
243338
|
-
else console.log(`${YELLOW} Exit code: ${result.exitCode}${RESET}`);
|
|
243339
|
-
return truncateResult(JSON.stringify(result));
|
|
243378
|
+
if (confirmWrite) {
|
|
243379
|
+
const ok = await confirm(`Write to ${input.path}?`);
|
|
243380
|
+
if (!ok) return JSON.stringify({ success: false, reason: "User declined" });
|
|
243340
243381
|
}
|
|
243341
|
-
|
|
243342
|
-
|
|
243343
|
-
|
|
243344
|
-
|
|
243345
|
-
|
|
243346
|
-
|
|
243347
|
-
|
|
243348
|
-
|
|
243349
|
-
|
|
243350
|
-
|
|
243351
|
-
|
|
243352
|
-
|
|
243353
|
-
|
|
243354
|
-
|
|
243355
|
-
|
|
243356
|
-
|
|
243357
|
-
|
|
243382
|
+
const result = writeFileTool(input, cwd);
|
|
243383
|
+
printSuccess(`Written ${result.bytesWritten} bytes${result.isNew ? " (new file)" : ""}`);
|
|
243384
|
+
return JSON.stringify(result);
|
|
243385
|
+
}
|
|
243386
|
+
case "list_directory": {
|
|
243387
|
+
const input = tool.input;
|
|
243388
|
+
printToolUse("list_directory", input.path);
|
|
243389
|
+
const tree = listDirectoryTool(input, cwd);
|
|
243390
|
+
printToolResult(tree);
|
|
243391
|
+
return truncateResult(tree);
|
|
243392
|
+
}
|
|
243393
|
+
case "search_files": {
|
|
243394
|
+
const input = tool.input;
|
|
243395
|
+
printToolUse("search_files", `"${input.pattern}" in ${input.path}`);
|
|
243396
|
+
const output = searchFilesTool(input, cwd);
|
|
243397
|
+
const formatted = output.results.map((r) => `${r.file}:${r.line}: ${r.content}`).join("\n");
|
|
243398
|
+
const meta = output.hasMore ? `
|
|
243399
|
+
(${output.totalFound}+ total matches, showing ${output.offset + 1}-${output.offset + output.results.length}. Use offset=${output.offset + output.limit} for more.)` : "";
|
|
243400
|
+
printToolResult((formatted || "No matches found.") + meta);
|
|
243401
|
+
return truncateResult(JSON.stringify(output));
|
|
243402
|
+
}
|
|
243403
|
+
case "execute_command": {
|
|
243404
|
+
const input = tool.input;
|
|
243405
|
+
printToolUse("execute_command", input.command);
|
|
243406
|
+
if (config.planMode || isDryRun()) {
|
|
243407
|
+
const tag = config.planMode ? "PLAN MODE" : "DRY-RUN";
|
|
243408
|
+
console.log(`${YELLOW} [${tag}] Would execute: ${input.command}${RESET}`);
|
|
243409
|
+
return JSON.stringify({ stdout: `[${tag.toLowerCase()} \u2014 not executed]`, stderr: "", exitCode: 0 });
|
|
243358
243410
|
}
|
|
243359
|
-
|
|
243360
|
-
const
|
|
243361
|
-
|
|
243362
|
-
const results = globTool(input, cwd);
|
|
243363
|
-
const formatted = results.join("\n");
|
|
243364
|
-
printToolResult(formatted || "No matches found.");
|
|
243365
|
-
return truncateResult(JSON.stringify({ matches: results, count: results.length }));
|
|
243411
|
+
if (confirmExec) {
|
|
243412
|
+
const ok = await confirm(`Execute: ${input.command}`);
|
|
243413
|
+
if (!ok) return JSON.stringify({ stdout: "", stderr: "User declined", exitCode: -1 });
|
|
243366
243414
|
}
|
|
243367
|
-
|
|
243368
|
-
|
|
243369
|
-
|
|
243370
|
-
|
|
243371
|
-
|
|
243372
|
-
|
|
243415
|
+
const result = executeCommandTool(input, cwd);
|
|
243416
|
+
if (result.stdout) printToolResult(result.stdout);
|
|
243417
|
+
if (result.stderr) console.log(`${RED}${result.stderr}${RESET}`);
|
|
243418
|
+
if (result.exitCode === 0) printSuccess("Command completed");
|
|
243419
|
+
else console.log(`${YELLOW} Exit code: ${result.exitCode}${RESET}`);
|
|
243420
|
+
return truncateResult(JSON.stringify(result));
|
|
243421
|
+
}
|
|
243422
|
+
case "edit_file": {
|
|
243423
|
+
const input = tool.input;
|
|
243424
|
+
printToolUse("edit_file", input.path);
|
|
243425
|
+
const diff = generateEditDiff(input);
|
|
243426
|
+
console.log(`${GRAY}${diff}${RESET}`);
|
|
243427
|
+
if (config.planMode || isDryRun()) {
|
|
243428
|
+
const tag = config.planMode ? "PLAN MODE" : "DRY-RUN";
|
|
243429
|
+
console.log(`${YELLOW} [${tag}] Would edit: ${input.path}${RESET}`);
|
|
243430
|
+
return JSON.stringify({ success: true, note: `${tag.toLowerCase()} \u2014 not executed` });
|
|
243373
243431
|
}
|
|
243374
|
-
|
|
243375
|
-
const
|
|
243376
|
-
|
|
243377
|
-
const result = diffFilesTool(input, cwd);
|
|
243378
|
-
const coloredLines = result.split("\n").map((line) => {
|
|
243379
|
-
if (line.startsWith("+")) return `${GREEN}${line}${RESET}`;
|
|
243380
|
-
if (line.startsWith("-")) return `${RED}${line}${RESET}`;
|
|
243381
|
-
if (line.startsWith("@")) return `${CYAN}${line}${RESET}`;
|
|
243382
|
-
return line;
|
|
243383
|
-
});
|
|
243384
|
-
printToolResult(coloredLines.join("\n"));
|
|
243385
|
-
return truncateResult(result);
|
|
243432
|
+
if (confirmWrite) {
|
|
243433
|
+
const ok = await confirm(`Edit ${input.path}?`);
|
|
243434
|
+
if (!ok) return JSON.stringify({ success: false, reason: "User declined" });
|
|
243386
243435
|
}
|
|
243387
|
-
|
|
243388
|
-
|
|
243436
|
+
const result = editFileTool(input, cwd);
|
|
243437
|
+
printSuccess("Edit applied");
|
|
243438
|
+
return JSON.stringify(result);
|
|
243389
243439
|
}
|
|
243390
|
-
|
|
243391
|
-
|
|
243392
|
-
|
|
243393
|
-
|
|
243440
|
+
case "glob": {
|
|
243441
|
+
const input = tool.input;
|
|
243442
|
+
printToolUse("glob", input.pattern);
|
|
243443
|
+
const results = globTool(input, cwd);
|
|
243444
|
+
const formatted = results.join("\n");
|
|
243445
|
+
printToolResult(formatted || "No matches found.");
|
|
243446
|
+
return truncateResult(JSON.stringify({ matches: results, count: results.length }));
|
|
243447
|
+
}
|
|
243448
|
+
case "read_image": {
|
|
243449
|
+
const input = tool.input;
|
|
243450
|
+
printToolUse("read_image", input.path);
|
|
243451
|
+
const result = readImageTool(input, cwd);
|
|
243452
|
+
printSuccess(`Read image: ${result.media_type}, ${(result.size / 1024).toFixed(1)}KB`);
|
|
243453
|
+
return JSON.stringify(result);
|
|
243454
|
+
}
|
|
243455
|
+
case "diff_files": {
|
|
243456
|
+
const input = tool.input;
|
|
243457
|
+
printToolUse("diff_files", `${input.file_a} \u2194 ${input.file_b}`);
|
|
243458
|
+
const result = diffFilesTool(input, cwd);
|
|
243459
|
+
const coloredLines = result.split("\n").map((line) => {
|
|
243460
|
+
if (line.startsWith("+")) return `${GREEN}${line}${RESET}`;
|
|
243461
|
+
if (line.startsWith("-")) return `${RED}${line}${RESET}`;
|
|
243462
|
+
if (line.startsWith("@")) return `${CYAN}${line}${RESET}`;
|
|
243463
|
+
return line;
|
|
243464
|
+
});
|
|
243465
|
+
printToolResult(coloredLines.join("\n"));
|
|
243466
|
+
return truncateResult(result);
|
|
243467
|
+
}
|
|
243468
|
+
default:
|
|
243469
|
+
return JSON.stringify({ error: `Unknown tool: ${tool.name}` });
|
|
243394
243470
|
}
|
|
243395
243471
|
}
|
|
243396
243472
|
async function executeToolWithHooks(tool, cwd, config, hooks) {
|
|
@@ -244216,7 +244292,7 @@ function parseArgs(args) {
|
|
|
244216
244292
|
let targetPath;
|
|
244217
244293
|
let prompt;
|
|
244218
244294
|
let debug = false;
|
|
244219
|
-
let
|
|
244295
|
+
let skipConfirmations2 = false;
|
|
244220
244296
|
let planMode = false;
|
|
244221
244297
|
for (let i = 0; i < args.length; i++) {
|
|
244222
244298
|
const arg = args[i];
|
|
@@ -244225,7 +244301,7 @@ function parseArgs(args) {
|
|
|
244225
244301
|
continue;
|
|
244226
244302
|
}
|
|
244227
244303
|
if (arg === "--yes" || arg === "-y") {
|
|
244228
|
-
|
|
244304
|
+
skipConfirmations2 = true;
|
|
244229
244305
|
continue;
|
|
244230
244306
|
}
|
|
244231
244307
|
if (arg === "--plan") {
|
|
@@ -244243,7 +244319,7 @@ function parseArgs(args) {
|
|
|
244243
244319
|
if (arg.startsWith("-")) continue;
|
|
244244
244320
|
targetPath = arg;
|
|
244245
244321
|
}
|
|
244246
|
-
return { command, path: targetPath, prompt, debug, skipConfirmations, planMode };
|
|
244322
|
+
return { command, path: targetPath, prompt, debug, skipConfirmations: skipConfirmations2, planMode };
|
|
244247
244323
|
}
|
|
244248
244324
|
async function promptInput(prompt) {
|
|
244249
244325
|
const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
|