@robota-sdk/agent-cli 3.0.0-beta.30 → 3.0.0-beta.32
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 +147 -20
- package/dist/node/bin.js +1 -1
- package/dist/node/{chunk-MCZP5QLE.js → chunk-EPCRZIQ6.js} +140 -9
- package/dist/node/index.cjs +152 -25
- package/dist/node/index.js +1 -1
- package/package.json +3 -3
package/dist/node/bin.cjs
CHANGED
|
@@ -27,8 +27,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
27
|
var import_node_fs3 = require("fs");
|
|
28
28
|
var import_node_path5 = require("path");
|
|
29
29
|
var import_node_url = require("url");
|
|
30
|
-
var import_agent_sdk4 = require("@robota-sdk/agent-sdk");
|
|
31
30
|
var import_agent_sdk5 = require("@robota-sdk/agent-sdk");
|
|
31
|
+
var import_agent_sdk6 = require("@robota-sdk/agent-sdk");
|
|
32
32
|
|
|
33
33
|
// src/utils/cli-args.ts
|
|
34
34
|
var import_node_util = require("util");
|
|
@@ -271,7 +271,10 @@ function useSession(props) {
|
|
|
271
271
|
setActiveTools((prev) => {
|
|
272
272
|
const updated = prev.map((t) => {
|
|
273
273
|
if (!(t.toolName === event.toolName && t.isRunning)) return t;
|
|
274
|
-
const editDiff = extractEditDiff(
|
|
274
|
+
const editDiff = extractEditDiff(
|
|
275
|
+
event.toolName,
|
|
276
|
+
t._toolArgs
|
|
277
|
+
);
|
|
275
278
|
const finished = {
|
|
276
279
|
...t,
|
|
277
280
|
isRunning: false,
|
|
@@ -660,6 +663,7 @@ function useSlashCommands(session, addMessage, setMessages, exit, registry, pend
|
|
|
660
663
|
|
|
661
664
|
// src/ui/hooks/useSubmitHandler.ts
|
|
662
665
|
var import_react4 = require("react");
|
|
666
|
+
var import_agent_sdk2 = require("@robota-sdk/agent-sdk");
|
|
663
667
|
|
|
664
668
|
// src/utils/tool-call-extractor.ts
|
|
665
669
|
var TOOL_ARG_MAX_LENGTH = 80;
|
|
@@ -764,6 +768,40 @@ Execute the "${cmd}" skill: ${userInstruction}`;
|
|
|
764
768
|
return `Use the "${cmd}" skill: ${userInstruction}`;
|
|
765
769
|
}
|
|
766
770
|
|
|
771
|
+
// src/commands/skill-executor.ts
|
|
772
|
+
function buildProcessedContent(skill, args, context) {
|
|
773
|
+
if (!skill.skillContent) return null;
|
|
774
|
+
return substituteVariables(skill.skillContent, args, context);
|
|
775
|
+
}
|
|
776
|
+
function buildInjectPrompt(skill, args, context) {
|
|
777
|
+
const processed = buildProcessedContent(skill, args, context);
|
|
778
|
+
if (processed) {
|
|
779
|
+
const userInstruction = args || skill.description;
|
|
780
|
+
return `<skill name="${skill.name}">
|
|
781
|
+
${processed}
|
|
782
|
+
</skill>
|
|
783
|
+
|
|
784
|
+
Execute the "${skill.name}" skill: ${userInstruction}`;
|
|
785
|
+
}
|
|
786
|
+
return `Use the "${skill.name}" skill: ${args || skill.description}`;
|
|
787
|
+
}
|
|
788
|
+
async function executeSkill(skill, args, callbacks, context) {
|
|
789
|
+
if (skill.context === "fork") {
|
|
790
|
+
if (!callbacks.runInFork) {
|
|
791
|
+
throw new Error("Fork execution is not available. Agent tool deps may not be initialized.");
|
|
792
|
+
}
|
|
793
|
+
const content = buildProcessedContent(skill, args, context);
|
|
794
|
+
const prompt2 = content ?? `Use the "${skill.name}" skill: ${args || skill.description}`;
|
|
795
|
+
const options = {};
|
|
796
|
+
if (skill.agent) options.agent = skill.agent;
|
|
797
|
+
if (skill.allowedTools) options.allowedTools = skill.allowedTools;
|
|
798
|
+
const result = await callbacks.runInFork(prompt2, options);
|
|
799
|
+
return { mode: "fork", result };
|
|
800
|
+
}
|
|
801
|
+
const prompt = buildInjectPrompt(skill, args, context);
|
|
802
|
+
return { mode: "inject", prompt };
|
|
803
|
+
}
|
|
804
|
+
|
|
767
805
|
// src/ui/hooks/useSubmitHandler.ts
|
|
768
806
|
function syncContextState(session, setter) {
|
|
769
807
|
const ctx = session.getContextState();
|
|
@@ -802,6 +840,37 @@ async function runSessionPrompt(prompt, session, addMessage, clearStreamingText,
|
|
|
802
840
|
setIsThinking(false);
|
|
803
841
|
}
|
|
804
842
|
}
|
|
843
|
+
function createForkRunner(sessionKey) {
|
|
844
|
+
const deps = (0, import_agent_sdk2.retrieveAgentToolDeps)(sessionKey);
|
|
845
|
+
if (!deps) return void 0;
|
|
846
|
+
return async (content, options) => {
|
|
847
|
+
const agentType = options.agent ?? "general-purpose";
|
|
848
|
+
const agentDef = (0, import_agent_sdk2.getBuiltInAgent)(agentType) ?? deps.customAgentRegistry?.(agentType);
|
|
849
|
+
if (!agentDef) {
|
|
850
|
+
throw new Error(`Unknown agent type for fork execution: ${agentType}`);
|
|
851
|
+
}
|
|
852
|
+
const effectiveDef = options.allowedTools ? { ...agentDef, tools: options.allowedTools } : agentDef;
|
|
853
|
+
const subSession = (0, import_agent_sdk2.createSubagentSession)({
|
|
854
|
+
agentDefinition: effectiveDef,
|
|
855
|
+
parentConfig: deps.config,
|
|
856
|
+
parentContext: deps.context,
|
|
857
|
+
parentTools: deps.tools,
|
|
858
|
+
terminal: deps.terminal,
|
|
859
|
+
isForkWorker: true,
|
|
860
|
+
permissionHandler: deps.permissionHandler,
|
|
861
|
+
onTextDelta: deps.onTextDelta,
|
|
862
|
+
onToolExecution: deps.onToolExecution
|
|
863
|
+
});
|
|
864
|
+
return await subSession.run(content);
|
|
865
|
+
};
|
|
866
|
+
}
|
|
867
|
+
function findSkillCommand(input, registry) {
|
|
868
|
+
const parts = input.slice(1).split(/\s+/);
|
|
869
|
+
const cmd = parts[0]?.toLowerCase() ?? "";
|
|
870
|
+
const skillCmd = registry.getCommands().find((c) => c.name === cmd && (c.source === "skill" || c.source === "plugin"));
|
|
871
|
+
if (!skillCmd) return null;
|
|
872
|
+
return { skill: skillCmd, args: parts.slice(1).join(" ").trim() };
|
|
873
|
+
}
|
|
805
874
|
function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamingText, setIsThinking, setContextState, registry) {
|
|
806
875
|
return (0, import_react4.useCallback)(
|
|
807
876
|
async (input) => {
|
|
@@ -811,6 +880,33 @@ function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamin
|
|
|
811
880
|
syncContextState(session, setContextState);
|
|
812
881
|
return;
|
|
813
882
|
}
|
|
883
|
+
const found = findSkillCommand(input, registry);
|
|
884
|
+
if (!found) return;
|
|
885
|
+
const { skill, args } = found;
|
|
886
|
+
if (skill.context === "fork") {
|
|
887
|
+
const runInFork = createForkRunner(session);
|
|
888
|
+
const result = await executeSkill(skill, args, { runInFork });
|
|
889
|
+
if (result.mode === "fork") {
|
|
890
|
+
addMessage({ role: "assistant", content: result.result ?? "(empty response)" });
|
|
891
|
+
syncContextState(session, setContextState);
|
|
892
|
+
return;
|
|
893
|
+
}
|
|
894
|
+
if (result.prompt) {
|
|
895
|
+
const cmdName2 = input.slice(1).split(/\s+/)[0]?.toLowerCase() ?? "";
|
|
896
|
+
const qualifiedName2 = registry.resolveQualifiedName(cmdName2);
|
|
897
|
+
const hookInput2 = qualifiedName2 ? `/${qualifiedName2}${input.slice(1 + cmdName2.length)}` : input;
|
|
898
|
+
return runSessionPrompt(
|
|
899
|
+
result.prompt,
|
|
900
|
+
session,
|
|
901
|
+
addMessage,
|
|
902
|
+
clearStreamingText,
|
|
903
|
+
setIsThinking,
|
|
904
|
+
setContextState,
|
|
905
|
+
hookInput2
|
|
906
|
+
);
|
|
907
|
+
}
|
|
908
|
+
return;
|
|
909
|
+
}
|
|
814
910
|
const prompt = await buildSkillPrompt(input, registry);
|
|
815
911
|
if (!prompt) return;
|
|
816
912
|
const cmdName = input.slice(1).split(/\s+/)[0]?.toLowerCase() ?? "";
|
|
@@ -852,7 +948,7 @@ function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamin
|
|
|
852
948
|
var import_react5 = require("react");
|
|
853
949
|
var import_node_os2 = require("os");
|
|
854
950
|
var import_node_path3 = require("path");
|
|
855
|
-
var
|
|
951
|
+
var import_agent_sdk3 = require("@robota-sdk/agent-sdk");
|
|
856
952
|
|
|
857
953
|
// src/commands/command-registry.ts
|
|
858
954
|
var CommandRegistry = class {
|
|
@@ -1191,7 +1287,7 @@ function useCommandRegistry(cwd) {
|
|
|
1191
1287
|
registry.addSource(new SkillCommandSource(cwd));
|
|
1192
1288
|
let pluginHooks = {};
|
|
1193
1289
|
const pluginsDir = (0, import_node_path3.join)((0, import_node_os2.homedir)(), ".robota", "plugins");
|
|
1194
|
-
const loader = new
|
|
1290
|
+
const loader = new import_agent_sdk3.BundlePluginLoader(pluginsDir);
|
|
1195
1291
|
try {
|
|
1196
1292
|
const plugins = loader.loadPluginsSync();
|
|
1197
1293
|
if (plugins.length > 0) {
|
|
@@ -1209,20 +1305,20 @@ function useCommandRegistry(cwd) {
|
|
|
1209
1305
|
var import_react6 = require("react");
|
|
1210
1306
|
var import_node_os3 = require("os");
|
|
1211
1307
|
var import_node_path4 = require("path");
|
|
1212
|
-
var
|
|
1308
|
+
var import_agent_sdk4 = require("@robota-sdk/agent-sdk");
|
|
1213
1309
|
function usePluginCallbacks(cwd) {
|
|
1214
1310
|
return (0, import_react6.useMemo)(() => {
|
|
1215
1311
|
const home = (0, import_node_os3.homedir)();
|
|
1216
1312
|
const pluginsDir = (0, import_node_path4.join)(home, ".robota", "plugins");
|
|
1217
1313
|
const userSettingsPath = (0, import_node_path4.join)(home, ".robota", "settings.json");
|
|
1218
|
-
const settingsStore = new
|
|
1219
|
-
const marketplace = new
|
|
1220
|
-
const installer = new
|
|
1314
|
+
const settingsStore = new import_agent_sdk4.PluginSettingsStore(userSettingsPath);
|
|
1315
|
+
const marketplace = new import_agent_sdk4.MarketplaceClient({ pluginsDir });
|
|
1316
|
+
const installer = new import_agent_sdk4.BundlePluginInstaller({
|
|
1221
1317
|
pluginsDir,
|
|
1222
1318
|
settingsStore,
|
|
1223
1319
|
marketplaceClient: marketplace
|
|
1224
1320
|
});
|
|
1225
|
-
const loader = new
|
|
1321
|
+
const loader = new import_agent_sdk4.BundlePluginLoader(pluginsDir);
|
|
1226
1322
|
return {
|
|
1227
1323
|
listInstalled: async () => {
|
|
1228
1324
|
const plugins = await loader.loadAll();
|
|
@@ -1358,7 +1454,10 @@ function ToolMessage({ message }) {
|
|
|
1358
1454
|
if (summaries) {
|
|
1359
1455
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
1360
1456
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Box, { children: [
|
|
1361
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.
|
|
1457
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Text, { color: "white", bold: true, children: [
|
|
1458
|
+
"Tool:",
|
|
1459
|
+
" "
|
|
1460
|
+
] }),
|
|
1362
1461
|
message.toolName && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Text, { color: "white", dimColor: true, children: [
|
|
1363
1462
|
"[",
|
|
1364
1463
|
message.toolName,
|
|
@@ -1380,7 +1479,10 @@ function ToolMessage({ message }) {
|
|
|
1380
1479
|
const lines = message.content.split("\n").filter((l) => l.trim());
|
|
1381
1480
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
1382
1481
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Box, { children: [
|
|
1383
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.
|
|
1482
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Text, { color: "white", bold: true, children: [
|
|
1483
|
+
"Tool:",
|
|
1484
|
+
" "
|
|
1485
|
+
] }),
|
|
1384
1486
|
message.toolName && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Text, { color: "white", dimColor: true, children: [
|
|
1385
1487
|
"[",
|
|
1386
1488
|
message.toolName,
|
|
@@ -1501,6 +1603,7 @@ function CjkTextInput({
|
|
|
1501
1603
|
value,
|
|
1502
1604
|
onChange,
|
|
1503
1605
|
onSubmit,
|
|
1606
|
+
onPaste,
|
|
1504
1607
|
placeholder = "",
|
|
1505
1608
|
focus = true,
|
|
1506
1609
|
showCursor = true
|
|
@@ -1524,6 +1627,10 @@ function CjkTextInput({
|
|
|
1524
1627
|
onSubmit?.(valueRef.current);
|
|
1525
1628
|
return;
|
|
1526
1629
|
}
|
|
1630
|
+
if (input.length > 1 && (input.includes("\n") || input.includes("\r")) && onPaste) {
|
|
1631
|
+
onPaste(input.replace(/\r\n?/g, "\n"));
|
|
1632
|
+
return;
|
|
1633
|
+
}
|
|
1527
1634
|
if (key.leftArrow) {
|
|
1528
1635
|
if (cursorRef.current > 0) {
|
|
1529
1636
|
cursorRef.current -= 1;
|
|
@@ -1646,6 +1753,12 @@ function computeScrollOffset(selectedIndex, total) {
|
|
|
1646
1753
|
return Math.min(selectedIndex - MAX_VISIBLE + 1, maxOffset);
|
|
1647
1754
|
}
|
|
1648
1755
|
|
|
1756
|
+
// src/utils/paste-labels.ts
|
|
1757
|
+
var PASTE_LABEL_RE = /\[Pasted text #(\d+) \+\d+ lines\]/g;
|
|
1758
|
+
function expandPasteLabels(text, store) {
|
|
1759
|
+
return text.replace(PASTE_LABEL_RE, (_, id) => store.get(Number(id)) ?? "");
|
|
1760
|
+
}
|
|
1761
|
+
|
|
1649
1762
|
// src/ui/InputArea.tsx
|
|
1650
1763
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
1651
1764
|
function parseSlashInput(value) {
|
|
@@ -1702,6 +1815,8 @@ function useAutocomplete(value, registry) {
|
|
|
1702
1815
|
}
|
|
1703
1816
|
function InputArea({ onSubmit, isDisabled, registry }) {
|
|
1704
1817
|
const [value, setValue] = (0, import_react10.useState)("");
|
|
1818
|
+
const pasteStore = (0, import_react10.useRef)(/* @__PURE__ */ new Map());
|
|
1819
|
+
const pasteIdRef = (0, import_react10.useRef)(0);
|
|
1705
1820
|
const {
|
|
1706
1821
|
showPopup,
|
|
1707
1822
|
filteredCommands,
|
|
@@ -1710,6 +1825,14 @@ function InputArea({ onSubmit, isDisabled, registry }) {
|
|
|
1710
1825
|
isSubcommandMode,
|
|
1711
1826
|
setShowPopup
|
|
1712
1827
|
} = useAutocomplete(value, registry);
|
|
1828
|
+
const handlePaste = (0, import_react10.useCallback)((text) => {
|
|
1829
|
+
pasteIdRef.current += 1;
|
|
1830
|
+
const id = pasteIdRef.current;
|
|
1831
|
+
pasteStore.current.set(id, text);
|
|
1832
|
+
const lineCount = text.split("\n").length;
|
|
1833
|
+
const label = `[Pasted text #${id} +${lineCount} lines]`;
|
|
1834
|
+
setValue((prev) => prev ? `${prev} ${label}` : label);
|
|
1835
|
+
}, []);
|
|
1713
1836
|
const handleSubmit = (0, import_react10.useCallback)(
|
|
1714
1837
|
(text) => {
|
|
1715
1838
|
const trimmed = text.trim();
|
|
@@ -1718,8 +1841,11 @@ function InputArea({ onSubmit, isDisabled, registry }) {
|
|
|
1718
1841
|
selectCommand(filteredCommands[selectedIndex]);
|
|
1719
1842
|
return;
|
|
1720
1843
|
}
|
|
1844
|
+
const expanded = expandPasteLabels(trimmed, pasteStore.current);
|
|
1721
1845
|
setValue("");
|
|
1722
|
-
|
|
1846
|
+
pasteStore.current.clear();
|
|
1847
|
+
pasteIdRef.current = 0;
|
|
1848
|
+
onSubmit(expanded);
|
|
1723
1849
|
},
|
|
1724
1850
|
[showPopup, filteredCommands, selectedIndex, onSubmit]
|
|
1725
1851
|
);
|
|
@@ -1776,6 +1902,7 @@ function InputArea({ onSubmit, isDisabled, registry }) {
|
|
|
1776
1902
|
value,
|
|
1777
1903
|
onChange: setValue,
|
|
1778
1904
|
onSubmit: handleSubmit,
|
|
1905
|
+
onPaste: handlePaste,
|
|
1779
1906
|
placeholder: "Type a message or /help"
|
|
1780
1907
|
}
|
|
1781
1908
|
)
|
|
@@ -2248,9 +2375,9 @@ async function startCli() {
|
|
|
2248
2375
|
const cwd = process.cwd();
|
|
2249
2376
|
await ensureConfig(cwd);
|
|
2250
2377
|
const [config, context, projectInfo] = await Promise.all([
|
|
2251
|
-
(0,
|
|
2252
|
-
(0,
|
|
2253
|
-
(0,
|
|
2378
|
+
(0, import_agent_sdk5.loadConfig)(cwd),
|
|
2379
|
+
(0, import_agent_sdk5.loadContext)(cwd),
|
|
2380
|
+
(0, import_agent_sdk5.detectProject)(cwd)
|
|
2254
2381
|
]);
|
|
2255
2382
|
if (args.model !== void 0) {
|
|
2256
2383
|
config.provider.model = args.model;
|
|
@@ -2258,7 +2385,7 @@ async function startCli() {
|
|
|
2258
2385
|
if (args.language !== void 0) {
|
|
2259
2386
|
config.language = args.language;
|
|
2260
2387
|
}
|
|
2261
|
-
const sessionStore = new
|
|
2388
|
+
const sessionStore = new import_agent_sdk5.SessionStore();
|
|
2262
2389
|
if (args.printMode) {
|
|
2263
2390
|
const prompt = args.positional.join(" ").trim();
|
|
2264
2391
|
if (prompt.length === 0) {
|
|
@@ -2266,15 +2393,15 @@ async function startCli() {
|
|
|
2266
2393
|
process.exit(1);
|
|
2267
2394
|
}
|
|
2268
2395
|
const terminal = new PrintTerminal();
|
|
2269
|
-
const paths = (0,
|
|
2270
|
-
const session = (0,
|
|
2396
|
+
const paths = (0, import_agent_sdk5.projectPaths)(cwd);
|
|
2397
|
+
const session = (0, import_agent_sdk5.createSession)({
|
|
2271
2398
|
config,
|
|
2272
2399
|
context,
|
|
2273
2400
|
terminal,
|
|
2274
|
-
sessionLogger: new
|
|
2401
|
+
sessionLogger: new import_agent_sdk5.FileSessionLogger(paths.logs),
|
|
2275
2402
|
projectInfo,
|
|
2276
2403
|
permissionMode: args.permissionMode,
|
|
2277
|
-
promptForApproval:
|
|
2404
|
+
promptForApproval: import_agent_sdk6.promptForApproval
|
|
2278
2405
|
});
|
|
2279
2406
|
const response = await session.run(prompt);
|
|
2280
2407
|
process.stdout.write(response + "\n");
|
package/dist/node/bin.js
CHANGED
|
@@ -149,7 +149,7 @@ var PrintTerminal = class {
|
|
|
149
149
|
import { render } from "ink";
|
|
150
150
|
|
|
151
151
|
// src/ui/App.tsx
|
|
152
|
-
import { useState as useState7, useRef as
|
|
152
|
+
import { useState as useState7, useRef as useRef6 } from "react";
|
|
153
153
|
import { Box as Box9, Text as Text11, useApp, useInput as useInput5 } from "ink";
|
|
154
154
|
import { getModelName } from "@robota-sdk/agent-core";
|
|
155
155
|
|
|
@@ -254,7 +254,10 @@ function useSession(props) {
|
|
|
254
254
|
setActiveTools((prev) => {
|
|
255
255
|
const updated = prev.map((t) => {
|
|
256
256
|
if (!(t.toolName === event.toolName && t.isRunning)) return t;
|
|
257
|
-
const editDiff = extractEditDiff(
|
|
257
|
+
const editDiff = extractEditDiff(
|
|
258
|
+
event.toolName,
|
|
259
|
+
t._toolArgs
|
|
260
|
+
);
|
|
258
261
|
const finished = {
|
|
259
262
|
...t,
|
|
260
263
|
isRunning: false,
|
|
@@ -643,6 +646,11 @@ function useSlashCommands(session, addMessage, setMessages, exit, registry, pend
|
|
|
643
646
|
|
|
644
647
|
// src/ui/hooks/useSubmitHandler.ts
|
|
645
648
|
import { useCallback as useCallback4 } from "react";
|
|
649
|
+
import {
|
|
650
|
+
createSubagentSession,
|
|
651
|
+
getBuiltInAgent,
|
|
652
|
+
retrieveAgentToolDeps
|
|
653
|
+
} from "@robota-sdk/agent-sdk";
|
|
646
654
|
|
|
647
655
|
// src/utils/tool-call-extractor.ts
|
|
648
656
|
var TOOL_ARG_MAX_LENGTH = 80;
|
|
@@ -747,6 +755,40 @@ Execute the "${cmd}" skill: ${userInstruction}`;
|
|
|
747
755
|
return `Use the "${cmd}" skill: ${userInstruction}`;
|
|
748
756
|
}
|
|
749
757
|
|
|
758
|
+
// src/commands/skill-executor.ts
|
|
759
|
+
function buildProcessedContent(skill, args, context) {
|
|
760
|
+
if (!skill.skillContent) return null;
|
|
761
|
+
return substituteVariables(skill.skillContent, args, context);
|
|
762
|
+
}
|
|
763
|
+
function buildInjectPrompt(skill, args, context) {
|
|
764
|
+
const processed = buildProcessedContent(skill, args, context);
|
|
765
|
+
if (processed) {
|
|
766
|
+
const userInstruction = args || skill.description;
|
|
767
|
+
return `<skill name="${skill.name}">
|
|
768
|
+
${processed}
|
|
769
|
+
</skill>
|
|
770
|
+
|
|
771
|
+
Execute the "${skill.name}" skill: ${userInstruction}`;
|
|
772
|
+
}
|
|
773
|
+
return `Use the "${skill.name}" skill: ${args || skill.description}`;
|
|
774
|
+
}
|
|
775
|
+
async function executeSkill(skill, args, callbacks, context) {
|
|
776
|
+
if (skill.context === "fork") {
|
|
777
|
+
if (!callbacks.runInFork) {
|
|
778
|
+
throw new Error("Fork execution is not available. Agent tool deps may not be initialized.");
|
|
779
|
+
}
|
|
780
|
+
const content = buildProcessedContent(skill, args, context);
|
|
781
|
+
const prompt2 = content ?? `Use the "${skill.name}" skill: ${args || skill.description}`;
|
|
782
|
+
const options = {};
|
|
783
|
+
if (skill.agent) options.agent = skill.agent;
|
|
784
|
+
if (skill.allowedTools) options.allowedTools = skill.allowedTools;
|
|
785
|
+
const result = await callbacks.runInFork(prompt2, options);
|
|
786
|
+
return { mode: "fork", result };
|
|
787
|
+
}
|
|
788
|
+
const prompt = buildInjectPrompt(skill, args, context);
|
|
789
|
+
return { mode: "inject", prompt };
|
|
790
|
+
}
|
|
791
|
+
|
|
750
792
|
// src/ui/hooks/useSubmitHandler.ts
|
|
751
793
|
function syncContextState(session, setter) {
|
|
752
794
|
const ctx = session.getContextState();
|
|
@@ -785,6 +827,37 @@ async function runSessionPrompt(prompt, session, addMessage, clearStreamingText,
|
|
|
785
827
|
setIsThinking(false);
|
|
786
828
|
}
|
|
787
829
|
}
|
|
830
|
+
function createForkRunner(sessionKey) {
|
|
831
|
+
const deps = retrieveAgentToolDeps(sessionKey);
|
|
832
|
+
if (!deps) return void 0;
|
|
833
|
+
return async (content, options) => {
|
|
834
|
+
const agentType = options.agent ?? "general-purpose";
|
|
835
|
+
const agentDef = getBuiltInAgent(agentType) ?? deps.customAgentRegistry?.(agentType);
|
|
836
|
+
if (!agentDef) {
|
|
837
|
+
throw new Error(`Unknown agent type for fork execution: ${agentType}`);
|
|
838
|
+
}
|
|
839
|
+
const effectiveDef = options.allowedTools ? { ...agentDef, tools: options.allowedTools } : agentDef;
|
|
840
|
+
const subSession = createSubagentSession({
|
|
841
|
+
agentDefinition: effectiveDef,
|
|
842
|
+
parentConfig: deps.config,
|
|
843
|
+
parentContext: deps.context,
|
|
844
|
+
parentTools: deps.tools,
|
|
845
|
+
terminal: deps.terminal,
|
|
846
|
+
isForkWorker: true,
|
|
847
|
+
permissionHandler: deps.permissionHandler,
|
|
848
|
+
onTextDelta: deps.onTextDelta,
|
|
849
|
+
onToolExecution: deps.onToolExecution
|
|
850
|
+
});
|
|
851
|
+
return await subSession.run(content);
|
|
852
|
+
};
|
|
853
|
+
}
|
|
854
|
+
function findSkillCommand(input, registry) {
|
|
855
|
+
const parts = input.slice(1).split(/\s+/);
|
|
856
|
+
const cmd = parts[0]?.toLowerCase() ?? "";
|
|
857
|
+
const skillCmd = registry.getCommands().find((c) => c.name === cmd && (c.source === "skill" || c.source === "plugin"));
|
|
858
|
+
if (!skillCmd) return null;
|
|
859
|
+
return { skill: skillCmd, args: parts.slice(1).join(" ").trim() };
|
|
860
|
+
}
|
|
788
861
|
function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamingText, setIsThinking, setContextState, registry) {
|
|
789
862
|
return useCallback4(
|
|
790
863
|
async (input) => {
|
|
@@ -794,6 +867,33 @@ function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamin
|
|
|
794
867
|
syncContextState(session, setContextState);
|
|
795
868
|
return;
|
|
796
869
|
}
|
|
870
|
+
const found = findSkillCommand(input, registry);
|
|
871
|
+
if (!found) return;
|
|
872
|
+
const { skill, args } = found;
|
|
873
|
+
if (skill.context === "fork") {
|
|
874
|
+
const runInFork = createForkRunner(session);
|
|
875
|
+
const result = await executeSkill(skill, args, { runInFork });
|
|
876
|
+
if (result.mode === "fork") {
|
|
877
|
+
addMessage({ role: "assistant", content: result.result ?? "(empty response)" });
|
|
878
|
+
syncContextState(session, setContextState);
|
|
879
|
+
return;
|
|
880
|
+
}
|
|
881
|
+
if (result.prompt) {
|
|
882
|
+
const cmdName2 = input.slice(1).split(/\s+/)[0]?.toLowerCase() ?? "";
|
|
883
|
+
const qualifiedName2 = registry.resolveQualifiedName(cmdName2);
|
|
884
|
+
const hookInput2 = qualifiedName2 ? `/${qualifiedName2}${input.slice(1 + cmdName2.length)}` : input;
|
|
885
|
+
return runSessionPrompt(
|
|
886
|
+
result.prompt,
|
|
887
|
+
session,
|
|
888
|
+
addMessage,
|
|
889
|
+
clearStreamingText,
|
|
890
|
+
setIsThinking,
|
|
891
|
+
setContextState,
|
|
892
|
+
hookInput2
|
|
893
|
+
);
|
|
894
|
+
}
|
|
895
|
+
return;
|
|
896
|
+
}
|
|
797
897
|
const prompt = await buildSkillPrompt(input, registry);
|
|
798
898
|
if (!prompt) return;
|
|
799
899
|
const cmdName = input.slice(1).split(/\s+/)[0]?.toLowerCase() ?? "";
|
|
@@ -1346,7 +1446,10 @@ function ToolMessage({ message }) {
|
|
|
1346
1446
|
if (summaries) {
|
|
1347
1447
|
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginBottom: 1, children: [
|
|
1348
1448
|
/* @__PURE__ */ jsxs2(Box2, { children: [
|
|
1349
|
-
/* @__PURE__ */
|
|
1449
|
+
/* @__PURE__ */ jsxs2(Text2, { color: "white", bold: true, children: [
|
|
1450
|
+
"Tool:",
|
|
1451
|
+
" "
|
|
1452
|
+
] }),
|
|
1350
1453
|
message.toolName && /* @__PURE__ */ jsxs2(Text2, { color: "white", dimColor: true, children: [
|
|
1351
1454
|
"[",
|
|
1352
1455
|
message.toolName,
|
|
@@ -1368,7 +1471,10 @@ function ToolMessage({ message }) {
|
|
|
1368
1471
|
const lines = message.content.split("\n").filter((l) => l.trim());
|
|
1369
1472
|
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginBottom: 1, children: [
|
|
1370
1473
|
/* @__PURE__ */ jsxs2(Box2, { children: [
|
|
1371
|
-
/* @__PURE__ */
|
|
1474
|
+
/* @__PURE__ */ jsxs2(Text2, { color: "white", bold: true, children: [
|
|
1475
|
+
"Tool:",
|
|
1476
|
+
" "
|
|
1477
|
+
] }),
|
|
1372
1478
|
message.toolName && /* @__PURE__ */ jsxs2(Text2, { color: "white", dimColor: true, children: [
|
|
1373
1479
|
"[",
|
|
1374
1480
|
message.toolName,
|
|
@@ -1469,7 +1575,7 @@ function StatusBar({
|
|
|
1469
1575
|
}
|
|
1470
1576
|
|
|
1471
1577
|
// src/ui/InputArea.tsx
|
|
1472
|
-
import React5, { useState as useState5, useCallback as useCallback5, useMemo as useMemo2 } from "react";
|
|
1578
|
+
import React5, { useState as useState5, useCallback as useCallback5, useMemo as useMemo2, useRef as useRef4 } from "react";
|
|
1473
1579
|
import { Box as Box5, Text as Text7, useInput as useInput2 } from "ink";
|
|
1474
1580
|
|
|
1475
1581
|
// src/ui/CjkTextInput.tsx
|
|
@@ -1489,6 +1595,7 @@ function CjkTextInput({
|
|
|
1489
1595
|
value,
|
|
1490
1596
|
onChange,
|
|
1491
1597
|
onSubmit,
|
|
1598
|
+
onPaste,
|
|
1492
1599
|
placeholder = "",
|
|
1493
1600
|
focus = true,
|
|
1494
1601
|
showCursor = true
|
|
@@ -1512,6 +1619,10 @@ function CjkTextInput({
|
|
|
1512
1619
|
onSubmit?.(valueRef.current);
|
|
1513
1620
|
return;
|
|
1514
1621
|
}
|
|
1622
|
+
if (input.length > 1 && (input.includes("\n") || input.includes("\r")) && onPaste) {
|
|
1623
|
+
onPaste(input.replace(/\r\n?/g, "\n"));
|
|
1624
|
+
return;
|
|
1625
|
+
}
|
|
1515
1626
|
if (key.leftArrow) {
|
|
1516
1627
|
if (cursorRef.current > 0) {
|
|
1517
1628
|
cursorRef.current -= 1;
|
|
@@ -1634,6 +1745,12 @@ function computeScrollOffset(selectedIndex, total) {
|
|
|
1634
1745
|
return Math.min(selectedIndex - MAX_VISIBLE + 1, maxOffset);
|
|
1635
1746
|
}
|
|
1636
1747
|
|
|
1748
|
+
// src/utils/paste-labels.ts
|
|
1749
|
+
var PASTE_LABEL_RE = /\[Pasted text #(\d+) \+\d+ lines\]/g;
|
|
1750
|
+
function expandPasteLabels(text, store) {
|
|
1751
|
+
return text.replace(PASTE_LABEL_RE, (_, id) => store.get(Number(id)) ?? "");
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1637
1754
|
// src/ui/InputArea.tsx
|
|
1638
1755
|
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1639
1756
|
function parseSlashInput(value) {
|
|
@@ -1690,6 +1807,8 @@ function useAutocomplete(value, registry) {
|
|
|
1690
1807
|
}
|
|
1691
1808
|
function InputArea({ onSubmit, isDisabled, registry }) {
|
|
1692
1809
|
const [value, setValue] = useState5("");
|
|
1810
|
+
const pasteStore = useRef4(/* @__PURE__ */ new Map());
|
|
1811
|
+
const pasteIdRef = useRef4(0);
|
|
1693
1812
|
const {
|
|
1694
1813
|
showPopup,
|
|
1695
1814
|
filteredCommands,
|
|
@@ -1698,6 +1817,14 @@ function InputArea({ onSubmit, isDisabled, registry }) {
|
|
|
1698
1817
|
isSubcommandMode,
|
|
1699
1818
|
setShowPopup
|
|
1700
1819
|
} = useAutocomplete(value, registry);
|
|
1820
|
+
const handlePaste = useCallback5((text) => {
|
|
1821
|
+
pasteIdRef.current += 1;
|
|
1822
|
+
const id = pasteIdRef.current;
|
|
1823
|
+
pasteStore.current.set(id, text);
|
|
1824
|
+
const lineCount = text.split("\n").length;
|
|
1825
|
+
const label = `[Pasted text #${id} +${lineCount} lines]`;
|
|
1826
|
+
setValue((prev) => prev ? `${prev} ${label}` : label);
|
|
1827
|
+
}, []);
|
|
1701
1828
|
const handleSubmit = useCallback5(
|
|
1702
1829
|
(text) => {
|
|
1703
1830
|
const trimmed = text.trim();
|
|
@@ -1706,8 +1833,11 @@ function InputArea({ onSubmit, isDisabled, registry }) {
|
|
|
1706
1833
|
selectCommand(filteredCommands[selectedIndex]);
|
|
1707
1834
|
return;
|
|
1708
1835
|
}
|
|
1836
|
+
const expanded = expandPasteLabels(trimmed, pasteStore.current);
|
|
1709
1837
|
setValue("");
|
|
1710
|
-
|
|
1838
|
+
pasteStore.current.clear();
|
|
1839
|
+
pasteIdRef.current = 0;
|
|
1840
|
+
onSubmit(expanded);
|
|
1711
1841
|
},
|
|
1712
1842
|
[showPopup, filteredCommands, selectedIndex, onSubmit]
|
|
1713
1843
|
);
|
|
@@ -1764,6 +1894,7 @@ function InputArea({ onSubmit, isDisabled, registry }) {
|
|
|
1764
1894
|
value,
|
|
1765
1895
|
onChange: setValue,
|
|
1766
1896
|
onSubmit: handleSubmit,
|
|
1897
|
+
onPaste: handlePaste,
|
|
1767
1898
|
placeholder: "Type a message or /help"
|
|
1768
1899
|
}
|
|
1769
1900
|
)
|
|
@@ -1772,7 +1903,7 @@ function InputArea({ onSubmit, isDisabled, registry }) {
|
|
|
1772
1903
|
}
|
|
1773
1904
|
|
|
1774
1905
|
// src/ui/ConfirmPrompt.tsx
|
|
1775
|
-
import { useState as useState6, useCallback as useCallback6, useRef as
|
|
1906
|
+
import { useState as useState6, useCallback as useCallback6, useRef as useRef5 } from "react";
|
|
1776
1907
|
import { Box as Box6, Text as Text8, useInput as useInput3 } from "ink";
|
|
1777
1908
|
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1778
1909
|
function ConfirmPrompt({
|
|
@@ -1781,7 +1912,7 @@ function ConfirmPrompt({
|
|
|
1781
1912
|
onSelect
|
|
1782
1913
|
}) {
|
|
1783
1914
|
const [selected, setSelected] = useState6(0);
|
|
1784
|
-
const resolvedRef =
|
|
1915
|
+
const resolvedRef = useRef5(false);
|
|
1785
1916
|
const doSelect = useCallback6(
|
|
1786
1917
|
(index) => {
|
|
1787
1918
|
if (resolvedRef.current) return;
|
|
@@ -1961,7 +2092,7 @@ function App(props) {
|
|
|
1961
2092
|
usedTokens: initialCtx.usedTokens,
|
|
1962
2093
|
maxTokens: initialCtx.maxTokens
|
|
1963
2094
|
});
|
|
1964
|
-
const pendingModelChangeRef =
|
|
2095
|
+
const pendingModelChangeRef = useRef6(null);
|
|
1965
2096
|
const [pendingModelId, setPendingModelId] = useState7(null);
|
|
1966
2097
|
const pluginCallbacks = usePluginCallbacks(props.cwd ?? process.cwd());
|
|
1967
2098
|
const handleSlashCommand = useSlashCommands(
|
package/dist/node/index.cjs
CHANGED
|
@@ -30,21 +30,21 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
-
Session: () =>
|
|
34
|
-
SessionStore: () =>
|
|
35
|
-
TRUST_TO_MODE: () =>
|
|
36
|
-
query: () =>
|
|
33
|
+
Session: () => import_agent_sdk7.Session,
|
|
34
|
+
SessionStore: () => import_agent_sdk7.SessionStore,
|
|
35
|
+
TRUST_TO_MODE: () => import_agent_sdk7.TRUST_TO_MODE,
|
|
36
|
+
query: () => import_agent_sdk7.query,
|
|
37
37
|
startCli: () => startCli
|
|
38
38
|
});
|
|
39
39
|
module.exports = __toCommonJS(index_exports);
|
|
40
|
-
var
|
|
40
|
+
var import_agent_sdk7 = require("@robota-sdk/agent-sdk");
|
|
41
41
|
|
|
42
42
|
// src/cli.ts
|
|
43
43
|
var import_node_fs3 = require("fs");
|
|
44
44
|
var import_node_path5 = require("path");
|
|
45
45
|
var import_node_url = require("url");
|
|
46
|
-
var import_agent_sdk4 = require("@robota-sdk/agent-sdk");
|
|
47
46
|
var import_agent_sdk5 = require("@robota-sdk/agent-sdk");
|
|
47
|
+
var import_agent_sdk6 = require("@robota-sdk/agent-sdk");
|
|
48
48
|
|
|
49
49
|
// src/utils/cli-args.ts
|
|
50
50
|
var import_node_util = require("util");
|
|
@@ -287,7 +287,10 @@ function useSession(props) {
|
|
|
287
287
|
setActiveTools((prev) => {
|
|
288
288
|
const updated = prev.map((t) => {
|
|
289
289
|
if (!(t.toolName === event.toolName && t.isRunning)) return t;
|
|
290
|
-
const editDiff = extractEditDiff(
|
|
290
|
+
const editDiff = extractEditDiff(
|
|
291
|
+
event.toolName,
|
|
292
|
+
t._toolArgs
|
|
293
|
+
);
|
|
291
294
|
const finished = {
|
|
292
295
|
...t,
|
|
293
296
|
isRunning: false,
|
|
@@ -676,6 +679,7 @@ function useSlashCommands(session, addMessage, setMessages, exit, registry, pend
|
|
|
676
679
|
|
|
677
680
|
// src/ui/hooks/useSubmitHandler.ts
|
|
678
681
|
var import_react4 = require("react");
|
|
682
|
+
var import_agent_sdk2 = require("@robota-sdk/agent-sdk");
|
|
679
683
|
|
|
680
684
|
// src/utils/tool-call-extractor.ts
|
|
681
685
|
var TOOL_ARG_MAX_LENGTH = 80;
|
|
@@ -780,6 +784,40 @@ Execute the "${cmd}" skill: ${userInstruction}`;
|
|
|
780
784
|
return `Use the "${cmd}" skill: ${userInstruction}`;
|
|
781
785
|
}
|
|
782
786
|
|
|
787
|
+
// src/commands/skill-executor.ts
|
|
788
|
+
function buildProcessedContent(skill, args, context) {
|
|
789
|
+
if (!skill.skillContent) return null;
|
|
790
|
+
return substituteVariables(skill.skillContent, args, context);
|
|
791
|
+
}
|
|
792
|
+
function buildInjectPrompt(skill, args, context) {
|
|
793
|
+
const processed = buildProcessedContent(skill, args, context);
|
|
794
|
+
if (processed) {
|
|
795
|
+
const userInstruction = args || skill.description;
|
|
796
|
+
return `<skill name="${skill.name}">
|
|
797
|
+
${processed}
|
|
798
|
+
</skill>
|
|
799
|
+
|
|
800
|
+
Execute the "${skill.name}" skill: ${userInstruction}`;
|
|
801
|
+
}
|
|
802
|
+
return `Use the "${skill.name}" skill: ${args || skill.description}`;
|
|
803
|
+
}
|
|
804
|
+
async function executeSkill(skill, args, callbacks, context) {
|
|
805
|
+
if (skill.context === "fork") {
|
|
806
|
+
if (!callbacks.runInFork) {
|
|
807
|
+
throw new Error("Fork execution is not available. Agent tool deps may not be initialized.");
|
|
808
|
+
}
|
|
809
|
+
const content = buildProcessedContent(skill, args, context);
|
|
810
|
+
const prompt2 = content ?? `Use the "${skill.name}" skill: ${args || skill.description}`;
|
|
811
|
+
const options = {};
|
|
812
|
+
if (skill.agent) options.agent = skill.agent;
|
|
813
|
+
if (skill.allowedTools) options.allowedTools = skill.allowedTools;
|
|
814
|
+
const result = await callbacks.runInFork(prompt2, options);
|
|
815
|
+
return { mode: "fork", result };
|
|
816
|
+
}
|
|
817
|
+
const prompt = buildInjectPrompt(skill, args, context);
|
|
818
|
+
return { mode: "inject", prompt };
|
|
819
|
+
}
|
|
820
|
+
|
|
783
821
|
// src/ui/hooks/useSubmitHandler.ts
|
|
784
822
|
function syncContextState(session, setter) {
|
|
785
823
|
const ctx = session.getContextState();
|
|
@@ -818,6 +856,37 @@ async function runSessionPrompt(prompt, session, addMessage, clearStreamingText,
|
|
|
818
856
|
setIsThinking(false);
|
|
819
857
|
}
|
|
820
858
|
}
|
|
859
|
+
function createForkRunner(sessionKey) {
|
|
860
|
+
const deps = (0, import_agent_sdk2.retrieveAgentToolDeps)(sessionKey);
|
|
861
|
+
if (!deps) return void 0;
|
|
862
|
+
return async (content, options) => {
|
|
863
|
+
const agentType = options.agent ?? "general-purpose";
|
|
864
|
+
const agentDef = (0, import_agent_sdk2.getBuiltInAgent)(agentType) ?? deps.customAgentRegistry?.(agentType);
|
|
865
|
+
if (!agentDef) {
|
|
866
|
+
throw new Error(`Unknown agent type for fork execution: ${agentType}`);
|
|
867
|
+
}
|
|
868
|
+
const effectiveDef = options.allowedTools ? { ...agentDef, tools: options.allowedTools } : agentDef;
|
|
869
|
+
const subSession = (0, import_agent_sdk2.createSubagentSession)({
|
|
870
|
+
agentDefinition: effectiveDef,
|
|
871
|
+
parentConfig: deps.config,
|
|
872
|
+
parentContext: deps.context,
|
|
873
|
+
parentTools: deps.tools,
|
|
874
|
+
terminal: deps.terminal,
|
|
875
|
+
isForkWorker: true,
|
|
876
|
+
permissionHandler: deps.permissionHandler,
|
|
877
|
+
onTextDelta: deps.onTextDelta,
|
|
878
|
+
onToolExecution: deps.onToolExecution
|
|
879
|
+
});
|
|
880
|
+
return await subSession.run(content);
|
|
881
|
+
};
|
|
882
|
+
}
|
|
883
|
+
function findSkillCommand(input, registry) {
|
|
884
|
+
const parts = input.slice(1).split(/\s+/);
|
|
885
|
+
const cmd = parts[0]?.toLowerCase() ?? "";
|
|
886
|
+
const skillCmd = registry.getCommands().find((c) => c.name === cmd && (c.source === "skill" || c.source === "plugin"));
|
|
887
|
+
if (!skillCmd) return null;
|
|
888
|
+
return { skill: skillCmd, args: parts.slice(1).join(" ").trim() };
|
|
889
|
+
}
|
|
821
890
|
function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamingText, setIsThinking, setContextState, registry) {
|
|
822
891
|
return (0, import_react4.useCallback)(
|
|
823
892
|
async (input) => {
|
|
@@ -827,6 +896,33 @@ function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamin
|
|
|
827
896
|
syncContextState(session, setContextState);
|
|
828
897
|
return;
|
|
829
898
|
}
|
|
899
|
+
const found = findSkillCommand(input, registry);
|
|
900
|
+
if (!found) return;
|
|
901
|
+
const { skill, args } = found;
|
|
902
|
+
if (skill.context === "fork") {
|
|
903
|
+
const runInFork = createForkRunner(session);
|
|
904
|
+
const result = await executeSkill(skill, args, { runInFork });
|
|
905
|
+
if (result.mode === "fork") {
|
|
906
|
+
addMessage({ role: "assistant", content: result.result ?? "(empty response)" });
|
|
907
|
+
syncContextState(session, setContextState);
|
|
908
|
+
return;
|
|
909
|
+
}
|
|
910
|
+
if (result.prompt) {
|
|
911
|
+
const cmdName2 = input.slice(1).split(/\s+/)[0]?.toLowerCase() ?? "";
|
|
912
|
+
const qualifiedName2 = registry.resolveQualifiedName(cmdName2);
|
|
913
|
+
const hookInput2 = qualifiedName2 ? `/${qualifiedName2}${input.slice(1 + cmdName2.length)}` : input;
|
|
914
|
+
return runSessionPrompt(
|
|
915
|
+
result.prompt,
|
|
916
|
+
session,
|
|
917
|
+
addMessage,
|
|
918
|
+
clearStreamingText,
|
|
919
|
+
setIsThinking,
|
|
920
|
+
setContextState,
|
|
921
|
+
hookInput2
|
|
922
|
+
);
|
|
923
|
+
}
|
|
924
|
+
return;
|
|
925
|
+
}
|
|
830
926
|
const prompt = await buildSkillPrompt(input, registry);
|
|
831
927
|
if (!prompt) return;
|
|
832
928
|
const cmdName = input.slice(1).split(/\s+/)[0]?.toLowerCase() ?? "";
|
|
@@ -868,7 +964,7 @@ function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamin
|
|
|
868
964
|
var import_react5 = require("react");
|
|
869
965
|
var import_node_os2 = require("os");
|
|
870
966
|
var import_node_path3 = require("path");
|
|
871
|
-
var
|
|
967
|
+
var import_agent_sdk3 = require("@robota-sdk/agent-sdk");
|
|
872
968
|
|
|
873
969
|
// src/commands/command-registry.ts
|
|
874
970
|
var CommandRegistry = class {
|
|
@@ -1207,7 +1303,7 @@ function useCommandRegistry(cwd) {
|
|
|
1207
1303
|
registry.addSource(new SkillCommandSource(cwd));
|
|
1208
1304
|
let pluginHooks = {};
|
|
1209
1305
|
const pluginsDir = (0, import_node_path3.join)((0, import_node_os2.homedir)(), ".robota", "plugins");
|
|
1210
|
-
const loader = new
|
|
1306
|
+
const loader = new import_agent_sdk3.BundlePluginLoader(pluginsDir);
|
|
1211
1307
|
try {
|
|
1212
1308
|
const plugins = loader.loadPluginsSync();
|
|
1213
1309
|
if (plugins.length > 0) {
|
|
@@ -1225,20 +1321,20 @@ function useCommandRegistry(cwd) {
|
|
|
1225
1321
|
var import_react6 = require("react");
|
|
1226
1322
|
var import_node_os3 = require("os");
|
|
1227
1323
|
var import_node_path4 = require("path");
|
|
1228
|
-
var
|
|
1324
|
+
var import_agent_sdk4 = require("@robota-sdk/agent-sdk");
|
|
1229
1325
|
function usePluginCallbacks(cwd) {
|
|
1230
1326
|
return (0, import_react6.useMemo)(() => {
|
|
1231
1327
|
const home = (0, import_node_os3.homedir)();
|
|
1232
1328
|
const pluginsDir = (0, import_node_path4.join)(home, ".robota", "plugins");
|
|
1233
1329
|
const userSettingsPath = (0, import_node_path4.join)(home, ".robota", "settings.json");
|
|
1234
|
-
const settingsStore = new
|
|
1235
|
-
const marketplace = new
|
|
1236
|
-
const installer = new
|
|
1330
|
+
const settingsStore = new import_agent_sdk4.PluginSettingsStore(userSettingsPath);
|
|
1331
|
+
const marketplace = new import_agent_sdk4.MarketplaceClient({ pluginsDir });
|
|
1332
|
+
const installer = new import_agent_sdk4.BundlePluginInstaller({
|
|
1237
1333
|
pluginsDir,
|
|
1238
1334
|
settingsStore,
|
|
1239
1335
|
marketplaceClient: marketplace
|
|
1240
1336
|
});
|
|
1241
|
-
const loader = new
|
|
1337
|
+
const loader = new import_agent_sdk4.BundlePluginLoader(pluginsDir);
|
|
1242
1338
|
return {
|
|
1243
1339
|
listInstalled: async () => {
|
|
1244
1340
|
const plugins = await loader.loadAll();
|
|
@@ -1374,7 +1470,10 @@ function ToolMessage({ message }) {
|
|
|
1374
1470
|
if (summaries) {
|
|
1375
1471
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
1376
1472
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Box, { children: [
|
|
1377
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.
|
|
1473
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Text, { color: "white", bold: true, children: [
|
|
1474
|
+
"Tool:",
|
|
1475
|
+
" "
|
|
1476
|
+
] }),
|
|
1378
1477
|
message.toolName && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Text, { color: "white", dimColor: true, children: [
|
|
1379
1478
|
"[",
|
|
1380
1479
|
message.toolName,
|
|
@@ -1396,7 +1495,10 @@ function ToolMessage({ message }) {
|
|
|
1396
1495
|
const lines = message.content.split("\n").filter((l) => l.trim());
|
|
1397
1496
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
1398
1497
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Box, { children: [
|
|
1399
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.
|
|
1498
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Text, { color: "white", bold: true, children: [
|
|
1499
|
+
"Tool:",
|
|
1500
|
+
" "
|
|
1501
|
+
] }),
|
|
1400
1502
|
message.toolName && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Text, { color: "white", dimColor: true, children: [
|
|
1401
1503
|
"[",
|
|
1402
1504
|
message.toolName,
|
|
@@ -1517,6 +1619,7 @@ function CjkTextInput({
|
|
|
1517
1619
|
value,
|
|
1518
1620
|
onChange,
|
|
1519
1621
|
onSubmit,
|
|
1622
|
+
onPaste,
|
|
1520
1623
|
placeholder = "",
|
|
1521
1624
|
focus = true,
|
|
1522
1625
|
showCursor = true
|
|
@@ -1540,6 +1643,10 @@ function CjkTextInput({
|
|
|
1540
1643
|
onSubmit?.(valueRef.current);
|
|
1541
1644
|
return;
|
|
1542
1645
|
}
|
|
1646
|
+
if (input.length > 1 && (input.includes("\n") || input.includes("\r")) && onPaste) {
|
|
1647
|
+
onPaste(input.replace(/\r\n?/g, "\n"));
|
|
1648
|
+
return;
|
|
1649
|
+
}
|
|
1543
1650
|
if (key.leftArrow) {
|
|
1544
1651
|
if (cursorRef.current > 0) {
|
|
1545
1652
|
cursorRef.current -= 1;
|
|
@@ -1662,6 +1769,12 @@ function computeScrollOffset(selectedIndex, total) {
|
|
|
1662
1769
|
return Math.min(selectedIndex - MAX_VISIBLE + 1, maxOffset);
|
|
1663
1770
|
}
|
|
1664
1771
|
|
|
1772
|
+
// src/utils/paste-labels.ts
|
|
1773
|
+
var PASTE_LABEL_RE = /\[Pasted text #(\d+) \+\d+ lines\]/g;
|
|
1774
|
+
function expandPasteLabels(text, store) {
|
|
1775
|
+
return text.replace(PASTE_LABEL_RE, (_, id) => store.get(Number(id)) ?? "");
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1665
1778
|
// src/ui/InputArea.tsx
|
|
1666
1779
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
1667
1780
|
function parseSlashInput(value) {
|
|
@@ -1718,6 +1831,8 @@ function useAutocomplete(value, registry) {
|
|
|
1718
1831
|
}
|
|
1719
1832
|
function InputArea({ onSubmit, isDisabled, registry }) {
|
|
1720
1833
|
const [value, setValue] = (0, import_react10.useState)("");
|
|
1834
|
+
const pasteStore = (0, import_react10.useRef)(/* @__PURE__ */ new Map());
|
|
1835
|
+
const pasteIdRef = (0, import_react10.useRef)(0);
|
|
1721
1836
|
const {
|
|
1722
1837
|
showPopup,
|
|
1723
1838
|
filteredCommands,
|
|
@@ -1726,6 +1841,14 @@ function InputArea({ onSubmit, isDisabled, registry }) {
|
|
|
1726
1841
|
isSubcommandMode,
|
|
1727
1842
|
setShowPopup
|
|
1728
1843
|
} = useAutocomplete(value, registry);
|
|
1844
|
+
const handlePaste = (0, import_react10.useCallback)((text) => {
|
|
1845
|
+
pasteIdRef.current += 1;
|
|
1846
|
+
const id = pasteIdRef.current;
|
|
1847
|
+
pasteStore.current.set(id, text);
|
|
1848
|
+
const lineCount = text.split("\n").length;
|
|
1849
|
+
const label = `[Pasted text #${id} +${lineCount} lines]`;
|
|
1850
|
+
setValue((prev) => prev ? `${prev} ${label}` : label);
|
|
1851
|
+
}, []);
|
|
1729
1852
|
const handleSubmit = (0, import_react10.useCallback)(
|
|
1730
1853
|
(text) => {
|
|
1731
1854
|
const trimmed = text.trim();
|
|
@@ -1734,8 +1857,11 @@ function InputArea({ onSubmit, isDisabled, registry }) {
|
|
|
1734
1857
|
selectCommand(filteredCommands[selectedIndex]);
|
|
1735
1858
|
return;
|
|
1736
1859
|
}
|
|
1860
|
+
const expanded = expandPasteLabels(trimmed, pasteStore.current);
|
|
1737
1861
|
setValue("");
|
|
1738
|
-
|
|
1862
|
+
pasteStore.current.clear();
|
|
1863
|
+
pasteIdRef.current = 0;
|
|
1864
|
+
onSubmit(expanded);
|
|
1739
1865
|
},
|
|
1740
1866
|
[showPopup, filteredCommands, selectedIndex, onSubmit]
|
|
1741
1867
|
);
|
|
@@ -1792,6 +1918,7 @@ function InputArea({ onSubmit, isDisabled, registry }) {
|
|
|
1792
1918
|
value,
|
|
1793
1919
|
onChange: setValue,
|
|
1794
1920
|
onSubmit: handleSubmit,
|
|
1921
|
+
onPaste: handlePaste,
|
|
1795
1922
|
placeholder: "Type a message or /help"
|
|
1796
1923
|
}
|
|
1797
1924
|
)
|
|
@@ -2264,9 +2391,9 @@ async function startCli() {
|
|
|
2264
2391
|
const cwd = process.cwd();
|
|
2265
2392
|
await ensureConfig(cwd);
|
|
2266
2393
|
const [config, context, projectInfo] = await Promise.all([
|
|
2267
|
-
(0,
|
|
2268
|
-
(0,
|
|
2269
|
-
(0,
|
|
2394
|
+
(0, import_agent_sdk5.loadConfig)(cwd),
|
|
2395
|
+
(0, import_agent_sdk5.loadContext)(cwd),
|
|
2396
|
+
(0, import_agent_sdk5.detectProject)(cwd)
|
|
2270
2397
|
]);
|
|
2271
2398
|
if (args.model !== void 0) {
|
|
2272
2399
|
config.provider.model = args.model;
|
|
@@ -2274,7 +2401,7 @@ async function startCli() {
|
|
|
2274
2401
|
if (args.language !== void 0) {
|
|
2275
2402
|
config.language = args.language;
|
|
2276
2403
|
}
|
|
2277
|
-
const sessionStore = new
|
|
2404
|
+
const sessionStore = new import_agent_sdk5.SessionStore();
|
|
2278
2405
|
if (args.printMode) {
|
|
2279
2406
|
const prompt = args.positional.join(" ").trim();
|
|
2280
2407
|
if (prompt.length === 0) {
|
|
@@ -2282,15 +2409,15 @@ async function startCli() {
|
|
|
2282
2409
|
process.exit(1);
|
|
2283
2410
|
}
|
|
2284
2411
|
const terminal = new PrintTerminal();
|
|
2285
|
-
const paths = (0,
|
|
2286
|
-
const session = (0,
|
|
2412
|
+
const paths = (0, import_agent_sdk5.projectPaths)(cwd);
|
|
2413
|
+
const session = (0, import_agent_sdk5.createSession)({
|
|
2287
2414
|
config,
|
|
2288
2415
|
context,
|
|
2289
2416
|
terminal,
|
|
2290
|
-
sessionLogger: new
|
|
2417
|
+
sessionLogger: new import_agent_sdk5.FileSessionLogger(paths.logs),
|
|
2291
2418
|
projectInfo,
|
|
2292
2419
|
permissionMode: args.permissionMode,
|
|
2293
|
-
promptForApproval:
|
|
2420
|
+
promptForApproval: import_agent_sdk6.promptForApproval
|
|
2294
2421
|
});
|
|
2295
2422
|
const response = await session.run(prompt);
|
|
2296
2423
|
process.stdout.write(response + "\n");
|
package/dist/node/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@robota-sdk/agent-cli",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.32",
|
|
4
4
|
"description": "AI coding assistant CLI built on Robota SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"marked-terminal": "^7.3.0",
|
|
36
36
|
"react": "19.2.4",
|
|
37
37
|
"string-width": "^8.2.0",
|
|
38
|
-
"@robota-sdk/agent-core": "3.0.0-beta.
|
|
39
|
-
"@robota-sdk/agent-sdk": "3.0.0-beta.
|
|
38
|
+
"@robota-sdk/agent-core": "3.0.0-beta.32",
|
|
39
|
+
"@robota-sdk/agent-sdk": "3.0.0-beta.32"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@types/marked": "^6.0.0",
|