@robota-sdk/agent-cli 3.0.0-beta.33 → 3.0.0-beta.34
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/node/bin.cjs +103 -30
- package/dist/node/bin.js +1 -1
- package/dist/node/{chunk-EPCRZIQ6.js → chunk-RDPIMQOC.js} +95 -22
- package/dist/node/index.cjs +103 -30
- package/dist/node/index.js +1 -1
- package/package.json +1 -1
package/dist/node/bin.cjs
CHANGED
|
@@ -24,7 +24,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
24
|
));
|
|
25
25
|
|
|
26
26
|
// src/cli.ts
|
|
27
|
-
var
|
|
27
|
+
var import_node_fs4 = require("fs");
|
|
28
28
|
var import_node_path5 = require("path");
|
|
29
29
|
var import_node_url = require("url");
|
|
30
30
|
var import_agent_sdk5 = require("@robota-sdk/agent-sdk");
|
|
@@ -175,25 +175,69 @@ var import_react = require("react");
|
|
|
175
175
|
var import_agent_sdk = require("@robota-sdk/agent-sdk");
|
|
176
176
|
|
|
177
177
|
// src/utils/edit-diff.ts
|
|
178
|
-
|
|
178
|
+
var import_node_fs2 = require("fs");
|
|
179
|
+
var CONTEXT_LINES = 2;
|
|
180
|
+
function generateDiffLines(oldStr, newStr, startLine = 1) {
|
|
179
181
|
if (oldStr === newStr) return [];
|
|
180
182
|
const lines = [];
|
|
181
|
-
|
|
182
|
-
|
|
183
|
+
const oldLines = oldStr.split("\n");
|
|
184
|
+
const newLines = newStr.split("\n");
|
|
185
|
+
for (let i = 0; i < oldLines.length; i++) {
|
|
186
|
+
lines.push({ type: "remove", text: oldLines[i], lineNumber: startLine + i });
|
|
183
187
|
}
|
|
184
|
-
for (
|
|
185
|
-
lines.push({ type: "add", text:
|
|
188
|
+
for (let i = 0; i < newLines.length; i++) {
|
|
189
|
+
lines.push({ type: "add", text: newLines[i], lineNumber: startLine + i });
|
|
186
190
|
}
|
|
187
191
|
return lines;
|
|
188
192
|
}
|
|
189
|
-
function
|
|
193
|
+
function generateDiffLinesWithContext(oldStr, newStr, startLine, filePath) {
|
|
194
|
+
if (oldStr === newStr) return [];
|
|
195
|
+
const diffLines = generateDiffLines(oldStr, newStr, startLine);
|
|
196
|
+
let fileLines;
|
|
197
|
+
try {
|
|
198
|
+
fileLines = (0, import_node_fs2.readFileSync)(filePath, "utf-8").split("\n");
|
|
199
|
+
} catch {
|
|
200
|
+
return diffLines;
|
|
201
|
+
}
|
|
202
|
+
const result = [];
|
|
203
|
+
const contextStart = Math.max(0, startLine - 1 - CONTEXT_LINES);
|
|
204
|
+
for (let i = contextStart; i < startLine - 1; i++) {
|
|
205
|
+
if (i < fileLines.length) {
|
|
206
|
+
result.push({ type: "context", text: fileLines[i], lineNumber: i + 1 });
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
result.push(...diffLines);
|
|
210
|
+
const newLineCount = newStr.split("\n").length;
|
|
211
|
+
const afterStart = startLine - 1 + newLineCount;
|
|
212
|
+
for (let i = afterStart; i < afterStart + CONTEXT_LINES; i++) {
|
|
213
|
+
if (i < fileLines.length) {
|
|
214
|
+
result.push({ type: "context", text: fileLines[i], lineNumber: i + 1 });
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return result;
|
|
218
|
+
}
|
|
219
|
+
function extractEditDiff(toolName, toolArgs, startLine) {
|
|
190
220
|
if (toolName !== "Edit" || !toolArgs) return null;
|
|
191
221
|
const filePath = toolArgs.file_path ?? toolArgs.filePath;
|
|
192
222
|
const oldStr = toolArgs.old_string ?? toolArgs.oldString;
|
|
193
223
|
const newStr = toolArgs.new_string ?? toolArgs.newString;
|
|
194
224
|
if (typeof filePath !== "string") return null;
|
|
195
225
|
if (typeof oldStr !== "string" || typeof newStr !== "string") return null;
|
|
196
|
-
|
|
226
|
+
let sl = startLine ?? 0;
|
|
227
|
+
if (!sl) {
|
|
228
|
+
try {
|
|
229
|
+
const fileContent = (0, import_node_fs2.readFileSync)(filePath, "utf-8");
|
|
230
|
+
const idx = fileContent.indexOf(newStr);
|
|
231
|
+
if (idx >= 0) {
|
|
232
|
+
sl = fileContent.substring(0, idx).split("\n").length;
|
|
233
|
+
} else {
|
|
234
|
+
sl = 1;
|
|
235
|
+
}
|
|
236
|
+
} catch {
|
|
237
|
+
sl = 1;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
const lines = generateDiffLinesWithContext(oldStr, newStr, sl, filePath);
|
|
197
241
|
if (lines.length === 0) return null;
|
|
198
242
|
return { file: filePath, lines };
|
|
199
243
|
}
|
|
@@ -271,9 +315,20 @@ function useSession(props) {
|
|
|
271
315
|
setActiveTools((prev) => {
|
|
272
316
|
const updated = prev.map((t) => {
|
|
273
317
|
if (!(t.toolName === event.toolName && t.isRunning)) return t;
|
|
318
|
+
let startLine;
|
|
319
|
+
if (event.toolResultData && event.toolName === "Edit") {
|
|
320
|
+
try {
|
|
321
|
+
const parsed = JSON.parse(event.toolResultData);
|
|
322
|
+
if (typeof parsed.startLine === "number") {
|
|
323
|
+
startLine = parsed.startLine;
|
|
324
|
+
}
|
|
325
|
+
} catch {
|
|
326
|
+
}
|
|
327
|
+
}
|
|
274
328
|
const editDiff = extractEditDiff(
|
|
275
329
|
event.toolName,
|
|
276
|
-
t._toolArgs
|
|
330
|
+
t._toolArgs,
|
|
331
|
+
startLine
|
|
277
332
|
);
|
|
278
333
|
const finished = {
|
|
279
334
|
...t,
|
|
@@ -1073,7 +1128,7 @@ var BuiltinCommandSource = class {
|
|
|
1073
1128
|
};
|
|
1074
1129
|
|
|
1075
1130
|
// src/commands/skill-source.ts
|
|
1076
|
-
var
|
|
1131
|
+
var import_node_fs3 = require("fs");
|
|
1077
1132
|
var import_node_path2 = require("path");
|
|
1078
1133
|
var import_node_os = require("os");
|
|
1079
1134
|
var BOOLEAN_KEYS = /* @__PURE__ */ new Set(["disable-model-invocation", "user-invocable"]);
|
|
@@ -1122,27 +1177,27 @@ function buildCommand(frontmatter, content, fallbackName) {
|
|
|
1122
1177
|
return cmd;
|
|
1123
1178
|
}
|
|
1124
1179
|
function scanSkillsDir(skillsDir) {
|
|
1125
|
-
if (!(0,
|
|
1180
|
+
if (!(0, import_node_fs3.existsSync)(skillsDir)) return [];
|
|
1126
1181
|
const commands = [];
|
|
1127
|
-
const entries = (0,
|
|
1182
|
+
const entries = (0, import_node_fs3.readdirSync)(skillsDir, { withFileTypes: true });
|
|
1128
1183
|
for (const entry of entries) {
|
|
1129
1184
|
if (!entry.isDirectory()) continue;
|
|
1130
1185
|
const skillFile = (0, import_node_path2.join)(skillsDir, entry.name, "SKILL.md");
|
|
1131
|
-
if (!(0,
|
|
1132
|
-
const content = (0,
|
|
1186
|
+
if (!(0, import_node_fs3.existsSync)(skillFile)) continue;
|
|
1187
|
+
const content = (0, import_node_fs3.readFileSync)(skillFile, "utf-8");
|
|
1133
1188
|
const frontmatter = parseFrontmatter(content);
|
|
1134
1189
|
commands.push(buildCommand(frontmatter, content, entry.name));
|
|
1135
1190
|
}
|
|
1136
1191
|
return commands;
|
|
1137
1192
|
}
|
|
1138
1193
|
function scanCommandsDir(commandsDir) {
|
|
1139
|
-
if (!(0,
|
|
1194
|
+
if (!(0, import_node_fs3.existsSync)(commandsDir)) return [];
|
|
1140
1195
|
const commands = [];
|
|
1141
|
-
const entries = (0,
|
|
1196
|
+
const entries = (0, import_node_fs3.readdirSync)(commandsDir, { withFileTypes: true });
|
|
1142
1197
|
for (const entry of entries) {
|
|
1143
1198
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
1144
1199
|
const filePath = (0, import_node_path2.join)(commandsDir, entry.name);
|
|
1145
|
-
const content = (0,
|
|
1200
|
+
const content = (0, import_node_fs3.readFileSync)(filePath, "utf-8");
|
|
1146
1201
|
const frontmatter = parseFrontmatter(content);
|
|
1147
1202
|
const fallbackName = (0, import_node_path2.basename)(entry.name, ".md");
|
|
1148
1203
|
commands.push(buildCommand(frontmatter, content, fallbackName));
|
|
@@ -1391,23 +1446,41 @@ function renderMarkdown(md) {
|
|
|
1391
1446
|
// src/ui/DiffBlock.tsx
|
|
1392
1447
|
var import_ink = require("ink");
|
|
1393
1448
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
1394
|
-
var MAX_DIFF_LINES =
|
|
1395
|
-
var TRUNCATED_SHOW =
|
|
1449
|
+
var MAX_DIFF_LINES = 12;
|
|
1450
|
+
var TRUNCATED_SHOW = 10;
|
|
1396
1451
|
function DiffBlock({ file, lines }) {
|
|
1397
1452
|
const truncated = lines.length > MAX_DIFF_LINES;
|
|
1398
1453
|
const visible = truncated ? lines.slice(0, TRUNCATED_SHOW) : lines;
|
|
1399
1454
|
const remaining = lines.length - TRUNCATED_SHOW;
|
|
1455
|
+
const maxLineNum = Math.max(...visible.map((l) => l.lineNumber), 0);
|
|
1456
|
+
const numWidth = String(maxLineNum).length;
|
|
1400
1457
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Box, { flexDirection: "column", marginLeft: 4, children: [
|
|
1401
1458
|
file && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: "white", dimColor: true, children: [
|
|
1402
1459
|
"\u2502 ",
|
|
1403
1460
|
file
|
|
1404
1461
|
] }),
|
|
1405
|
-
visible.map((line, i) =>
|
|
1406
|
-
"
|
|
1407
|
-
line.type === "
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1462
|
+
visible.map((line, i) => {
|
|
1463
|
+
const lineNum = String(line.lineNumber).padStart(numWidth, " ");
|
|
1464
|
+
if (line.type === "context") {
|
|
1465
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: "white", dimColor: true, children: [
|
|
1466
|
+
"\u2502 ",
|
|
1467
|
+
lineNum,
|
|
1468
|
+
" ",
|
|
1469
|
+
line.text
|
|
1470
|
+
] }, i);
|
|
1471
|
+
}
|
|
1472
|
+
const prefix = line.type === "remove" ? "-" : "+";
|
|
1473
|
+
const bgColor = line.type === "remove" ? "#5c1a1a" : "#1a3d1a";
|
|
1474
|
+
const fgColor = line.type === "remove" ? "#ff9999" : "#99ff99";
|
|
1475
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: fgColor, backgroundColor: bgColor, children: [
|
|
1476
|
+
"\u2502 ",
|
|
1477
|
+
lineNum,
|
|
1478
|
+
" ",
|
|
1479
|
+
prefix,
|
|
1480
|
+
" ",
|
|
1481
|
+
line.text
|
|
1482
|
+
] }, i);
|
|
1483
|
+
}),
|
|
1411
1484
|
truncated && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: "white", dimColor: true, children: [
|
|
1412
1485
|
"\u2502 ... and ",
|
|
1413
1486
|
remaining,
|
|
@@ -2228,9 +2301,9 @@ function renderApp(options) {
|
|
|
2228
2301
|
// src/cli.ts
|
|
2229
2302
|
var import_meta = {};
|
|
2230
2303
|
function checkSettingsFile(filePath) {
|
|
2231
|
-
if (!(0,
|
|
2304
|
+
if (!(0, import_node_fs4.existsSync)(filePath)) return "missing";
|
|
2232
2305
|
try {
|
|
2233
|
-
const raw = (0,
|
|
2306
|
+
const raw = (0, import_node_fs4.readFileSync)(filePath, "utf8").trim();
|
|
2234
2307
|
if (raw.length === 0) return "incomplete";
|
|
2235
2308
|
const parsed = JSON.parse(raw);
|
|
2236
2309
|
const provider = parsed.provider;
|
|
@@ -2247,7 +2320,7 @@ function readVersion() {
|
|
|
2247
2320
|
const candidates = [(0, import_node_path5.join)(dir, "..", "..", "package.json"), (0, import_node_path5.join)(dir, "..", "package.json")];
|
|
2248
2321
|
for (const pkgPath of candidates) {
|
|
2249
2322
|
try {
|
|
2250
|
-
const raw = (0,
|
|
2323
|
+
const raw = (0, import_node_fs4.readFileSync)(pkgPath, "utf-8");
|
|
2251
2324
|
const pkg = JSON.parse(raw);
|
|
2252
2325
|
if (pkg.version !== void 0 && pkg.name !== void 0) {
|
|
2253
2326
|
return pkg.version;
|
|
@@ -2335,7 +2408,7 @@ async function ensureConfig(cwd) {
|
|
|
2335
2408
|
}
|
|
2336
2409
|
const language = await promptInput(" Response language (ko/en/ja/zh, default: en): ");
|
|
2337
2410
|
const settingsDir = (0, import_node_path5.dirname)(userPath);
|
|
2338
|
-
(0,
|
|
2411
|
+
(0, import_node_fs4.mkdirSync)(settingsDir, { recursive: true });
|
|
2339
2412
|
const settings = {
|
|
2340
2413
|
provider: {
|
|
2341
2414
|
name: "anthropic",
|
|
@@ -2346,7 +2419,7 @@ async function ensureConfig(cwd) {
|
|
|
2346
2419
|
if (language) {
|
|
2347
2420
|
settings.language = language;
|
|
2348
2421
|
}
|
|
2349
|
-
(0,
|
|
2422
|
+
(0, import_node_fs4.writeFileSync)(userPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
2350
2423
|
process.stdout.write(`
|
|
2351
2424
|
Config saved to ${userPath}
|
|
2352
2425
|
|
package/dist/node/bin.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/cli.ts
|
|
2
|
-
import { readFileSync as
|
|
2
|
+
import { readFileSync as readFileSync4, existsSync as existsSync3, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
3
3
|
import { join as join5, dirname as dirname3 } from "path";
|
|
4
4
|
import { fileURLToPath } from "url";
|
|
5
5
|
import {
|
|
@@ -158,25 +158,69 @@ import { useState, useCallback, useRef } from "react";
|
|
|
158
158
|
import { createSession, FileSessionLogger, projectPaths } from "@robota-sdk/agent-sdk";
|
|
159
159
|
|
|
160
160
|
// src/utils/edit-diff.ts
|
|
161
|
-
|
|
161
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
162
|
+
var CONTEXT_LINES = 2;
|
|
163
|
+
function generateDiffLines(oldStr, newStr, startLine = 1) {
|
|
162
164
|
if (oldStr === newStr) return [];
|
|
163
165
|
const lines = [];
|
|
164
|
-
|
|
165
|
-
|
|
166
|
+
const oldLines = oldStr.split("\n");
|
|
167
|
+
const newLines = newStr.split("\n");
|
|
168
|
+
for (let i = 0; i < oldLines.length; i++) {
|
|
169
|
+
lines.push({ type: "remove", text: oldLines[i], lineNumber: startLine + i });
|
|
166
170
|
}
|
|
167
|
-
for (
|
|
168
|
-
lines.push({ type: "add", text:
|
|
171
|
+
for (let i = 0; i < newLines.length; i++) {
|
|
172
|
+
lines.push({ type: "add", text: newLines[i], lineNumber: startLine + i });
|
|
169
173
|
}
|
|
170
174
|
return lines;
|
|
171
175
|
}
|
|
172
|
-
function
|
|
176
|
+
function generateDiffLinesWithContext(oldStr, newStr, startLine, filePath) {
|
|
177
|
+
if (oldStr === newStr) return [];
|
|
178
|
+
const diffLines = generateDiffLines(oldStr, newStr, startLine);
|
|
179
|
+
let fileLines;
|
|
180
|
+
try {
|
|
181
|
+
fileLines = readFileSync2(filePath, "utf-8").split("\n");
|
|
182
|
+
} catch {
|
|
183
|
+
return diffLines;
|
|
184
|
+
}
|
|
185
|
+
const result = [];
|
|
186
|
+
const contextStart = Math.max(0, startLine - 1 - CONTEXT_LINES);
|
|
187
|
+
for (let i = contextStart; i < startLine - 1; i++) {
|
|
188
|
+
if (i < fileLines.length) {
|
|
189
|
+
result.push({ type: "context", text: fileLines[i], lineNumber: i + 1 });
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
result.push(...diffLines);
|
|
193
|
+
const newLineCount = newStr.split("\n").length;
|
|
194
|
+
const afterStart = startLine - 1 + newLineCount;
|
|
195
|
+
for (let i = afterStart; i < afterStart + CONTEXT_LINES; i++) {
|
|
196
|
+
if (i < fileLines.length) {
|
|
197
|
+
result.push({ type: "context", text: fileLines[i], lineNumber: i + 1 });
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return result;
|
|
201
|
+
}
|
|
202
|
+
function extractEditDiff(toolName, toolArgs, startLine) {
|
|
173
203
|
if (toolName !== "Edit" || !toolArgs) return null;
|
|
174
204
|
const filePath = toolArgs.file_path ?? toolArgs.filePath;
|
|
175
205
|
const oldStr = toolArgs.old_string ?? toolArgs.oldString;
|
|
176
206
|
const newStr = toolArgs.new_string ?? toolArgs.newString;
|
|
177
207
|
if (typeof filePath !== "string") return null;
|
|
178
208
|
if (typeof oldStr !== "string" || typeof newStr !== "string") return null;
|
|
179
|
-
|
|
209
|
+
let sl = startLine ?? 0;
|
|
210
|
+
if (!sl) {
|
|
211
|
+
try {
|
|
212
|
+
const fileContent = readFileSync2(filePath, "utf-8");
|
|
213
|
+
const idx = fileContent.indexOf(newStr);
|
|
214
|
+
if (idx >= 0) {
|
|
215
|
+
sl = fileContent.substring(0, idx).split("\n").length;
|
|
216
|
+
} else {
|
|
217
|
+
sl = 1;
|
|
218
|
+
}
|
|
219
|
+
} catch {
|
|
220
|
+
sl = 1;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
const lines = generateDiffLinesWithContext(oldStr, newStr, sl, filePath);
|
|
180
224
|
if (lines.length === 0) return null;
|
|
181
225
|
return { file: filePath, lines };
|
|
182
226
|
}
|
|
@@ -254,9 +298,20 @@ function useSession(props) {
|
|
|
254
298
|
setActiveTools((prev) => {
|
|
255
299
|
const updated = prev.map((t) => {
|
|
256
300
|
if (!(t.toolName === event.toolName && t.isRunning)) return t;
|
|
301
|
+
let startLine;
|
|
302
|
+
if (event.toolResultData && event.toolName === "Edit") {
|
|
303
|
+
try {
|
|
304
|
+
const parsed = JSON.parse(event.toolResultData);
|
|
305
|
+
if (typeof parsed.startLine === "number") {
|
|
306
|
+
startLine = parsed.startLine;
|
|
307
|
+
}
|
|
308
|
+
} catch {
|
|
309
|
+
}
|
|
310
|
+
}
|
|
257
311
|
const editDiff = extractEditDiff(
|
|
258
312
|
event.toolName,
|
|
259
|
-
t._toolArgs
|
|
313
|
+
t._toolArgs,
|
|
314
|
+
startLine
|
|
260
315
|
);
|
|
261
316
|
const finished = {
|
|
262
317
|
...t,
|
|
@@ -1060,7 +1115,7 @@ var BuiltinCommandSource = class {
|
|
|
1060
1115
|
};
|
|
1061
1116
|
|
|
1062
1117
|
// src/commands/skill-source.ts
|
|
1063
|
-
import { readdirSync, readFileSync as
|
|
1118
|
+
import { readdirSync, readFileSync as readFileSync3, existsSync as existsSync2 } from "fs";
|
|
1064
1119
|
import { join as join2, basename } from "path";
|
|
1065
1120
|
import { homedir } from "os";
|
|
1066
1121
|
var BOOLEAN_KEYS = /* @__PURE__ */ new Set(["disable-model-invocation", "user-invocable"]);
|
|
@@ -1116,7 +1171,7 @@ function scanSkillsDir(skillsDir) {
|
|
|
1116
1171
|
if (!entry.isDirectory()) continue;
|
|
1117
1172
|
const skillFile = join2(skillsDir, entry.name, "SKILL.md");
|
|
1118
1173
|
if (!existsSync2(skillFile)) continue;
|
|
1119
|
-
const content =
|
|
1174
|
+
const content = readFileSync3(skillFile, "utf-8");
|
|
1120
1175
|
const frontmatter = parseFrontmatter(content);
|
|
1121
1176
|
commands.push(buildCommand(frontmatter, content, entry.name));
|
|
1122
1177
|
}
|
|
@@ -1129,7 +1184,7 @@ function scanCommandsDir(commandsDir) {
|
|
|
1129
1184
|
for (const entry of entries) {
|
|
1130
1185
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
1131
1186
|
const filePath = join2(commandsDir, entry.name);
|
|
1132
|
-
const content =
|
|
1187
|
+
const content = readFileSync3(filePath, "utf-8");
|
|
1133
1188
|
const frontmatter = parseFrontmatter(content);
|
|
1134
1189
|
const fallbackName = basename(entry.name, ".md");
|
|
1135
1190
|
commands.push(buildCommand(frontmatter, content, fallbackName));
|
|
@@ -1383,23 +1438,41 @@ function renderMarkdown(md) {
|
|
|
1383
1438
|
// src/ui/DiffBlock.tsx
|
|
1384
1439
|
import { Box, Text } from "ink";
|
|
1385
1440
|
import { jsxs } from "react/jsx-runtime";
|
|
1386
|
-
var MAX_DIFF_LINES =
|
|
1387
|
-
var TRUNCATED_SHOW =
|
|
1441
|
+
var MAX_DIFF_LINES = 12;
|
|
1442
|
+
var TRUNCATED_SHOW = 10;
|
|
1388
1443
|
function DiffBlock({ file, lines }) {
|
|
1389
1444
|
const truncated = lines.length > MAX_DIFF_LINES;
|
|
1390
1445
|
const visible = truncated ? lines.slice(0, TRUNCATED_SHOW) : lines;
|
|
1391
1446
|
const remaining = lines.length - TRUNCATED_SHOW;
|
|
1447
|
+
const maxLineNum = Math.max(...visible.map((l) => l.lineNumber), 0);
|
|
1448
|
+
const numWidth = String(maxLineNum).length;
|
|
1392
1449
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginLeft: 4, children: [
|
|
1393
1450
|
file && /* @__PURE__ */ jsxs(Text, { color: "white", dimColor: true, children: [
|
|
1394
1451
|
"\u2502 ",
|
|
1395
1452
|
file
|
|
1396
1453
|
] }),
|
|
1397
|
-
visible.map((line, i) =>
|
|
1398
|
-
"
|
|
1399
|
-
line.type === "
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1454
|
+
visible.map((line, i) => {
|
|
1455
|
+
const lineNum = String(line.lineNumber).padStart(numWidth, " ");
|
|
1456
|
+
if (line.type === "context") {
|
|
1457
|
+
return /* @__PURE__ */ jsxs(Text, { color: "white", dimColor: true, children: [
|
|
1458
|
+
"\u2502 ",
|
|
1459
|
+
lineNum,
|
|
1460
|
+
" ",
|
|
1461
|
+
line.text
|
|
1462
|
+
] }, i);
|
|
1463
|
+
}
|
|
1464
|
+
const prefix = line.type === "remove" ? "-" : "+";
|
|
1465
|
+
const bgColor = line.type === "remove" ? "#5c1a1a" : "#1a3d1a";
|
|
1466
|
+
const fgColor = line.type === "remove" ? "#ff9999" : "#99ff99";
|
|
1467
|
+
return /* @__PURE__ */ jsxs(Text, { color: fgColor, backgroundColor: bgColor, children: [
|
|
1468
|
+
"\u2502 ",
|
|
1469
|
+
lineNum,
|
|
1470
|
+
" ",
|
|
1471
|
+
prefix,
|
|
1472
|
+
" ",
|
|
1473
|
+
line.text
|
|
1474
|
+
] }, i);
|
|
1475
|
+
}),
|
|
1403
1476
|
truncated && /* @__PURE__ */ jsxs(Text, { color: "white", dimColor: true, children: [
|
|
1404
1477
|
"\u2502 ... and ",
|
|
1405
1478
|
remaining,
|
|
@@ -2221,7 +2294,7 @@ function renderApp(options) {
|
|
|
2221
2294
|
function checkSettingsFile(filePath) {
|
|
2222
2295
|
if (!existsSync3(filePath)) return "missing";
|
|
2223
2296
|
try {
|
|
2224
|
-
const raw =
|
|
2297
|
+
const raw = readFileSync4(filePath, "utf8").trim();
|
|
2225
2298
|
if (raw.length === 0) return "incomplete";
|
|
2226
2299
|
const parsed = JSON.parse(raw);
|
|
2227
2300
|
const provider = parsed.provider;
|
|
@@ -2238,7 +2311,7 @@ function readVersion() {
|
|
|
2238
2311
|
const candidates = [join5(dir, "..", "..", "package.json"), join5(dir, "..", "package.json")];
|
|
2239
2312
|
for (const pkgPath of candidates) {
|
|
2240
2313
|
try {
|
|
2241
|
-
const raw =
|
|
2314
|
+
const raw = readFileSync4(pkgPath, "utf-8");
|
|
2242
2315
|
const pkg = JSON.parse(raw);
|
|
2243
2316
|
if (pkg.version !== void 0 && pkg.name !== void 0) {
|
|
2244
2317
|
return pkg.version;
|
package/dist/node/index.cjs
CHANGED
|
@@ -40,7 +40,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
40
40
|
var import_agent_sdk7 = require("@robota-sdk/agent-sdk");
|
|
41
41
|
|
|
42
42
|
// src/cli.ts
|
|
43
|
-
var
|
|
43
|
+
var import_node_fs4 = require("fs");
|
|
44
44
|
var import_node_path5 = require("path");
|
|
45
45
|
var import_node_url = require("url");
|
|
46
46
|
var import_agent_sdk5 = require("@robota-sdk/agent-sdk");
|
|
@@ -191,25 +191,69 @@ var import_react = require("react");
|
|
|
191
191
|
var import_agent_sdk = require("@robota-sdk/agent-sdk");
|
|
192
192
|
|
|
193
193
|
// src/utils/edit-diff.ts
|
|
194
|
-
|
|
194
|
+
var import_node_fs2 = require("fs");
|
|
195
|
+
var CONTEXT_LINES = 2;
|
|
196
|
+
function generateDiffLines(oldStr, newStr, startLine = 1) {
|
|
195
197
|
if (oldStr === newStr) return [];
|
|
196
198
|
const lines = [];
|
|
197
|
-
|
|
198
|
-
|
|
199
|
+
const oldLines = oldStr.split("\n");
|
|
200
|
+
const newLines = newStr.split("\n");
|
|
201
|
+
for (let i = 0; i < oldLines.length; i++) {
|
|
202
|
+
lines.push({ type: "remove", text: oldLines[i], lineNumber: startLine + i });
|
|
199
203
|
}
|
|
200
|
-
for (
|
|
201
|
-
lines.push({ type: "add", text:
|
|
204
|
+
for (let i = 0; i < newLines.length; i++) {
|
|
205
|
+
lines.push({ type: "add", text: newLines[i], lineNumber: startLine + i });
|
|
202
206
|
}
|
|
203
207
|
return lines;
|
|
204
208
|
}
|
|
205
|
-
function
|
|
209
|
+
function generateDiffLinesWithContext(oldStr, newStr, startLine, filePath) {
|
|
210
|
+
if (oldStr === newStr) return [];
|
|
211
|
+
const diffLines = generateDiffLines(oldStr, newStr, startLine);
|
|
212
|
+
let fileLines;
|
|
213
|
+
try {
|
|
214
|
+
fileLines = (0, import_node_fs2.readFileSync)(filePath, "utf-8").split("\n");
|
|
215
|
+
} catch {
|
|
216
|
+
return diffLines;
|
|
217
|
+
}
|
|
218
|
+
const result = [];
|
|
219
|
+
const contextStart = Math.max(0, startLine - 1 - CONTEXT_LINES);
|
|
220
|
+
for (let i = contextStart; i < startLine - 1; i++) {
|
|
221
|
+
if (i < fileLines.length) {
|
|
222
|
+
result.push({ type: "context", text: fileLines[i], lineNumber: i + 1 });
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
result.push(...diffLines);
|
|
226
|
+
const newLineCount = newStr.split("\n").length;
|
|
227
|
+
const afterStart = startLine - 1 + newLineCount;
|
|
228
|
+
for (let i = afterStart; i < afterStart + CONTEXT_LINES; i++) {
|
|
229
|
+
if (i < fileLines.length) {
|
|
230
|
+
result.push({ type: "context", text: fileLines[i], lineNumber: i + 1 });
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return result;
|
|
234
|
+
}
|
|
235
|
+
function extractEditDiff(toolName, toolArgs, startLine) {
|
|
206
236
|
if (toolName !== "Edit" || !toolArgs) return null;
|
|
207
237
|
const filePath = toolArgs.file_path ?? toolArgs.filePath;
|
|
208
238
|
const oldStr = toolArgs.old_string ?? toolArgs.oldString;
|
|
209
239
|
const newStr = toolArgs.new_string ?? toolArgs.newString;
|
|
210
240
|
if (typeof filePath !== "string") return null;
|
|
211
241
|
if (typeof oldStr !== "string" || typeof newStr !== "string") return null;
|
|
212
|
-
|
|
242
|
+
let sl = startLine ?? 0;
|
|
243
|
+
if (!sl) {
|
|
244
|
+
try {
|
|
245
|
+
const fileContent = (0, import_node_fs2.readFileSync)(filePath, "utf-8");
|
|
246
|
+
const idx = fileContent.indexOf(newStr);
|
|
247
|
+
if (idx >= 0) {
|
|
248
|
+
sl = fileContent.substring(0, idx).split("\n").length;
|
|
249
|
+
} else {
|
|
250
|
+
sl = 1;
|
|
251
|
+
}
|
|
252
|
+
} catch {
|
|
253
|
+
sl = 1;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
const lines = generateDiffLinesWithContext(oldStr, newStr, sl, filePath);
|
|
213
257
|
if (lines.length === 0) return null;
|
|
214
258
|
return { file: filePath, lines };
|
|
215
259
|
}
|
|
@@ -287,9 +331,20 @@ function useSession(props) {
|
|
|
287
331
|
setActiveTools((prev) => {
|
|
288
332
|
const updated = prev.map((t) => {
|
|
289
333
|
if (!(t.toolName === event.toolName && t.isRunning)) return t;
|
|
334
|
+
let startLine;
|
|
335
|
+
if (event.toolResultData && event.toolName === "Edit") {
|
|
336
|
+
try {
|
|
337
|
+
const parsed = JSON.parse(event.toolResultData);
|
|
338
|
+
if (typeof parsed.startLine === "number") {
|
|
339
|
+
startLine = parsed.startLine;
|
|
340
|
+
}
|
|
341
|
+
} catch {
|
|
342
|
+
}
|
|
343
|
+
}
|
|
290
344
|
const editDiff = extractEditDiff(
|
|
291
345
|
event.toolName,
|
|
292
|
-
t._toolArgs
|
|
346
|
+
t._toolArgs,
|
|
347
|
+
startLine
|
|
293
348
|
);
|
|
294
349
|
const finished = {
|
|
295
350
|
...t,
|
|
@@ -1089,7 +1144,7 @@ var BuiltinCommandSource = class {
|
|
|
1089
1144
|
};
|
|
1090
1145
|
|
|
1091
1146
|
// src/commands/skill-source.ts
|
|
1092
|
-
var
|
|
1147
|
+
var import_node_fs3 = require("fs");
|
|
1093
1148
|
var import_node_path2 = require("path");
|
|
1094
1149
|
var import_node_os = require("os");
|
|
1095
1150
|
var BOOLEAN_KEYS = /* @__PURE__ */ new Set(["disable-model-invocation", "user-invocable"]);
|
|
@@ -1138,27 +1193,27 @@ function buildCommand(frontmatter, content, fallbackName) {
|
|
|
1138
1193
|
return cmd;
|
|
1139
1194
|
}
|
|
1140
1195
|
function scanSkillsDir(skillsDir) {
|
|
1141
|
-
if (!(0,
|
|
1196
|
+
if (!(0, import_node_fs3.existsSync)(skillsDir)) return [];
|
|
1142
1197
|
const commands = [];
|
|
1143
|
-
const entries = (0,
|
|
1198
|
+
const entries = (0, import_node_fs3.readdirSync)(skillsDir, { withFileTypes: true });
|
|
1144
1199
|
for (const entry of entries) {
|
|
1145
1200
|
if (!entry.isDirectory()) continue;
|
|
1146
1201
|
const skillFile = (0, import_node_path2.join)(skillsDir, entry.name, "SKILL.md");
|
|
1147
|
-
if (!(0,
|
|
1148
|
-
const content = (0,
|
|
1202
|
+
if (!(0, import_node_fs3.existsSync)(skillFile)) continue;
|
|
1203
|
+
const content = (0, import_node_fs3.readFileSync)(skillFile, "utf-8");
|
|
1149
1204
|
const frontmatter = parseFrontmatter(content);
|
|
1150
1205
|
commands.push(buildCommand(frontmatter, content, entry.name));
|
|
1151
1206
|
}
|
|
1152
1207
|
return commands;
|
|
1153
1208
|
}
|
|
1154
1209
|
function scanCommandsDir(commandsDir) {
|
|
1155
|
-
if (!(0,
|
|
1210
|
+
if (!(0, import_node_fs3.existsSync)(commandsDir)) return [];
|
|
1156
1211
|
const commands = [];
|
|
1157
|
-
const entries = (0,
|
|
1212
|
+
const entries = (0, import_node_fs3.readdirSync)(commandsDir, { withFileTypes: true });
|
|
1158
1213
|
for (const entry of entries) {
|
|
1159
1214
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
1160
1215
|
const filePath = (0, import_node_path2.join)(commandsDir, entry.name);
|
|
1161
|
-
const content = (0,
|
|
1216
|
+
const content = (0, import_node_fs3.readFileSync)(filePath, "utf-8");
|
|
1162
1217
|
const frontmatter = parseFrontmatter(content);
|
|
1163
1218
|
const fallbackName = (0, import_node_path2.basename)(entry.name, ".md");
|
|
1164
1219
|
commands.push(buildCommand(frontmatter, content, fallbackName));
|
|
@@ -1407,23 +1462,41 @@ function renderMarkdown(md) {
|
|
|
1407
1462
|
// src/ui/DiffBlock.tsx
|
|
1408
1463
|
var import_ink = require("ink");
|
|
1409
1464
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
1410
|
-
var MAX_DIFF_LINES =
|
|
1411
|
-
var TRUNCATED_SHOW =
|
|
1465
|
+
var MAX_DIFF_LINES = 12;
|
|
1466
|
+
var TRUNCATED_SHOW = 10;
|
|
1412
1467
|
function DiffBlock({ file, lines }) {
|
|
1413
1468
|
const truncated = lines.length > MAX_DIFF_LINES;
|
|
1414
1469
|
const visible = truncated ? lines.slice(0, TRUNCATED_SHOW) : lines;
|
|
1415
1470
|
const remaining = lines.length - TRUNCATED_SHOW;
|
|
1471
|
+
const maxLineNum = Math.max(...visible.map((l) => l.lineNumber), 0);
|
|
1472
|
+
const numWidth = String(maxLineNum).length;
|
|
1416
1473
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Box, { flexDirection: "column", marginLeft: 4, children: [
|
|
1417
1474
|
file && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: "white", dimColor: true, children: [
|
|
1418
1475
|
"\u2502 ",
|
|
1419
1476
|
file
|
|
1420
1477
|
] }),
|
|
1421
|
-
visible.map((line, i) =>
|
|
1422
|
-
"
|
|
1423
|
-
line.type === "
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1478
|
+
visible.map((line, i) => {
|
|
1479
|
+
const lineNum = String(line.lineNumber).padStart(numWidth, " ");
|
|
1480
|
+
if (line.type === "context") {
|
|
1481
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: "white", dimColor: true, children: [
|
|
1482
|
+
"\u2502 ",
|
|
1483
|
+
lineNum,
|
|
1484
|
+
" ",
|
|
1485
|
+
line.text
|
|
1486
|
+
] }, i);
|
|
1487
|
+
}
|
|
1488
|
+
const prefix = line.type === "remove" ? "-" : "+";
|
|
1489
|
+
const bgColor = line.type === "remove" ? "#5c1a1a" : "#1a3d1a";
|
|
1490
|
+
const fgColor = line.type === "remove" ? "#ff9999" : "#99ff99";
|
|
1491
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: fgColor, backgroundColor: bgColor, children: [
|
|
1492
|
+
"\u2502 ",
|
|
1493
|
+
lineNum,
|
|
1494
|
+
" ",
|
|
1495
|
+
prefix,
|
|
1496
|
+
" ",
|
|
1497
|
+
line.text
|
|
1498
|
+
] }, i);
|
|
1499
|
+
}),
|
|
1427
1500
|
truncated && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: "white", dimColor: true, children: [
|
|
1428
1501
|
"\u2502 ... and ",
|
|
1429
1502
|
remaining,
|
|
@@ -2244,9 +2317,9 @@ function renderApp(options) {
|
|
|
2244
2317
|
// src/cli.ts
|
|
2245
2318
|
var import_meta = {};
|
|
2246
2319
|
function checkSettingsFile(filePath) {
|
|
2247
|
-
if (!(0,
|
|
2320
|
+
if (!(0, import_node_fs4.existsSync)(filePath)) return "missing";
|
|
2248
2321
|
try {
|
|
2249
|
-
const raw = (0,
|
|
2322
|
+
const raw = (0, import_node_fs4.readFileSync)(filePath, "utf8").trim();
|
|
2250
2323
|
if (raw.length === 0) return "incomplete";
|
|
2251
2324
|
const parsed = JSON.parse(raw);
|
|
2252
2325
|
const provider = parsed.provider;
|
|
@@ -2263,7 +2336,7 @@ function readVersion() {
|
|
|
2263
2336
|
const candidates = [(0, import_node_path5.join)(dir, "..", "..", "package.json"), (0, import_node_path5.join)(dir, "..", "package.json")];
|
|
2264
2337
|
for (const pkgPath of candidates) {
|
|
2265
2338
|
try {
|
|
2266
|
-
const raw = (0,
|
|
2339
|
+
const raw = (0, import_node_fs4.readFileSync)(pkgPath, "utf-8");
|
|
2267
2340
|
const pkg = JSON.parse(raw);
|
|
2268
2341
|
if (pkg.version !== void 0 && pkg.name !== void 0) {
|
|
2269
2342
|
return pkg.version;
|
|
@@ -2351,7 +2424,7 @@ async function ensureConfig(cwd) {
|
|
|
2351
2424
|
}
|
|
2352
2425
|
const language = await promptInput(" Response language (ko/en/ja/zh, default: en): ");
|
|
2353
2426
|
const settingsDir = (0, import_node_path5.dirname)(userPath);
|
|
2354
|
-
(0,
|
|
2427
|
+
(0, import_node_fs4.mkdirSync)(settingsDir, { recursive: true });
|
|
2355
2428
|
const settings = {
|
|
2356
2429
|
provider: {
|
|
2357
2430
|
name: "anthropic",
|
|
@@ -2362,7 +2435,7 @@ async function ensureConfig(cwd) {
|
|
|
2362
2435
|
if (language) {
|
|
2363
2436
|
settings.language = language;
|
|
2364
2437
|
}
|
|
2365
|
-
(0,
|
|
2438
|
+
(0, import_node_fs4.writeFileSync)(userPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
2366
2439
|
process.stdout.write(`
|
|
2367
2440
|
Config saved to ${userPath}
|
|
2368
2441
|
|
package/dist/node/index.js
CHANGED