@robota-sdk/agent-cli 3.0.0-beta.40 → 3.0.0-beta.41

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.
@@ -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: () => 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,
33
+ Session: () => import_agent_sdk5.Session,
34
+ SessionStore: () => import_agent_sdk5.SessionStore,
35
+ TRUST_TO_MODE: () => import_agent_sdk5.TRUST_TO_MODE,
36
+ query: () => import_agent_sdk5.query,
37
37
  startCli: () => startCli
38
38
  });
39
39
  module.exports = __toCommonJS(index_exports);
40
- var import_agent_sdk7 = require("@robota-sdk/agent-sdk");
40
+ var import_agent_sdk5 = require("@robota-sdk/agent-sdk");
41
41
 
42
42
  // src/cli.ts
43
- var import_node_fs4 = require("fs");
43
+ var import_node_fs2 = require("fs");
44
44
  var import_node_path5 = require("path");
45
45
  var import_node_url = require("url");
46
- var import_agent_sdk5 = require("@robota-sdk/agent-sdk");
47
- var import_agent_sdk6 = require("@robota-sdk/agent-sdk");
46
+ var import_agent_sdk3 = require("@robota-sdk/agent-sdk");
47
+ var import_agent_sdk4 = require("@robota-sdk/agent-sdk");
48
48
 
49
49
  // src/utils/cli-args.ts
50
50
  var import_node_util = require("util");
@@ -182,606 +182,50 @@ var PrintTerminal = class {
182
182
  var import_ink14 = require("ink");
183
183
 
184
184
  // src/ui/App.tsx
185
- var import_react16 = require("react");
185
+ var import_react12 = require("react");
186
186
  var import_ink13 = require("ink");
187
- var import_agent_core6 = require("@robota-sdk/agent-core");
188
- var import_agent_core7 = require("@robota-sdk/agent-core");
187
+ var import_agent_core4 = require("@robota-sdk/agent-core");
189
188
 
190
- // src/ui/hooks/useSession.ts
189
+ // src/ui/hooks/useInteractiveSession.ts
191
190
  var import_react = require("react");
191
+ var import_node_os = require("os");
192
+ var import_node_path3 = require("path");
192
193
  var import_agent_sdk = require("@robota-sdk/agent-sdk");
193
-
194
- // src/utils/edit-diff.ts
195
- var import_node_fs2 = require("fs");
196
- var CONTEXT_LINES = 2;
197
- function generateDiffLines(oldStr, newStr, startLine = 1) {
198
- if (oldStr === newStr) return [];
199
- const lines = [];
200
- const oldLines = oldStr.split("\n");
201
- const newLines = newStr.split("\n");
202
- for (let i = 0; i < oldLines.length; i++) {
203
- lines.push({ type: "remove", text: oldLines[i], lineNumber: startLine + i });
204
- }
205
- for (let i = 0; i < newLines.length; i++) {
206
- lines.push({ type: "add", text: newLines[i], lineNumber: startLine + i });
207
- }
208
- return lines;
209
- }
210
- function generateDiffLinesWithContext(oldStr, newStr, startLine, filePath) {
211
- if (oldStr === newStr) return [];
212
- const diffLines = generateDiffLines(oldStr, newStr, startLine);
213
- let fileLines;
214
- try {
215
- fileLines = (0, import_node_fs2.readFileSync)(filePath, "utf-8").split("\n");
216
- } catch {
217
- return diffLines;
218
- }
219
- const result = [];
220
- const contextStart = Math.max(0, startLine - 1 - CONTEXT_LINES);
221
- for (let i = contextStart; i < startLine - 1; i++) {
222
- if (i < fileLines.length) {
223
- result.push({ type: "context", text: fileLines[i], lineNumber: i + 1 });
224
- }
225
- }
226
- result.push(...diffLines);
227
- const newLineCount = newStr.split("\n").length;
228
- const afterStart = startLine - 1 + newLineCount;
229
- for (let i = afterStart; i < afterStart + CONTEXT_LINES; i++) {
230
- if (i < fileLines.length) {
231
- result.push({ type: "context", text: fileLines[i], lineNumber: i + 1 });
232
- }
233
- }
234
- return result;
235
- }
236
- function extractEditDiff(toolName, toolArgs, startLine) {
237
- if (toolName !== "Edit" || !toolArgs) return null;
238
- const filePath = toolArgs.file_path ?? toolArgs.filePath;
239
- const oldStr = toolArgs.old_string ?? toolArgs.oldString;
240
- const newStr = toolArgs.new_string ?? toolArgs.newString;
241
- if (typeof filePath !== "string") return null;
242
- if (typeof oldStr !== "string" || typeof newStr !== "string") return null;
243
- let sl = startLine ?? 0;
244
- if (!sl) {
245
- try {
246
- const fileContent = (0, import_node_fs2.readFileSync)(filePath, "utf-8");
247
- const idx = fileContent.indexOf(newStr);
248
- if (idx >= 0) {
249
- sl = fileContent.substring(0, idx).split("\n").length;
250
- } else {
251
- sl = 1;
252
- }
253
- } catch {
254
- sl = 1;
255
- }
256
- }
257
- const lines = generateDiffLinesWithContext(oldStr, newStr, sl, filePath);
258
- if (lines.length === 0) return null;
259
- return { file: filePath, lines };
260
- }
261
-
262
- // src/ui/hooks/useSession.ts
263
- var TOOL_ARG_DISPLAY_MAX = 80;
264
- var TAIL_KEEP = 30;
265
- var MAX_COMPLETED_TOOLS = 50;
266
- var NOOP_TERMINAL = {
267
- write: () => {
268
- },
269
- writeLine: () => {
270
- },
271
- writeMarkdown: () => {
272
- },
273
- writeError: () => {
274
- },
275
- prompt: () => Promise.resolve(""),
276
- select: () => Promise.resolve(0),
277
- spinner: () => ({ stop: () => {
278
- }, update: () => {
279
- } })
280
- };
281
- function useSession(props) {
282
- const [permissionRequest, setPermissionRequest] = (0, import_react.useState)(null);
283
- const [streamingText, setStreamingText] = (0, import_react.useState)("");
284
- const streamingTextRef = (0, import_react.useRef)("");
285
- const [activeTools, setActiveTools] = (0, import_react.useState)([]);
286
- const permissionQueueRef = (0, import_react.useRef)([]);
287
- const processingRef = (0, import_react.useRef)(false);
288
- const processNextPermission = (0, import_react.useCallback)(() => {
289
- if (processingRef.current) return;
290
- const next = permissionQueueRef.current[0];
291
- if (!next) {
292
- setPermissionRequest(null);
293
- return;
294
- }
295
- processingRef.current = true;
296
- setPermissionRequest({
297
- toolName: next.toolName,
298
- toolArgs: next.toolArgs,
299
- resolve: (result) => {
300
- permissionQueueRef.current.shift();
301
- processingRef.current = false;
302
- setPermissionRequest(null);
303
- next.resolve(result);
304
- setTimeout(() => processNextPermission(), 0);
305
- }
306
- });
307
- }, []);
308
- const sessionRef = (0, import_react.useRef)(null);
309
- if (sessionRef.current === null) {
310
- const permissionHandler = (toolName, toolArgs) => {
311
- return new Promise((resolve) => {
312
- permissionQueueRef.current.push({ toolName, toolArgs, resolve });
313
- processNextPermission();
314
- });
315
- };
316
- let flushTimer = null;
317
- const onTextDelta = (delta) => {
318
- streamingTextRef.current += delta;
319
- if (!flushTimer) {
320
- flushTimer = setTimeout(() => {
321
- setStreamingText(streamingTextRef.current);
322
- flushTimer = null;
323
- }, 16);
324
- }
325
- };
326
- const onToolExecution = (event) => {
327
- if (event.type === "start") {
328
- let firstArg = "";
329
- if (event.toolArgs) {
330
- const firstVal = Object.values(event.toolArgs)[0];
331
- const raw = typeof firstVal === "string" ? firstVal : JSON.stringify(firstVal ?? "");
332
- firstArg = raw.length > TOOL_ARG_DISPLAY_MAX ? raw.slice(0, TOOL_ARG_DISPLAY_MAX - TAIL_KEEP - 3) + "..." + raw.slice(-TAIL_KEEP) : raw;
333
- }
334
- setActiveTools((prev) => [
335
- ...prev,
336
- { toolName: event.toolName, firstArg, isRunning: true, _toolArgs: event.toolArgs }
337
- ]);
338
- } else {
339
- const toolResult = event.denied ? "denied" : event.success === false ? "error" : "success";
340
- setActiveTools((prev) => {
341
- const updated = prev.map((t) => {
342
- if (!(t.toolName === event.toolName && t.isRunning)) return t;
343
- let startLine;
344
- if (event.toolResultData && event.toolName === "Edit") {
345
- try {
346
- const parsed = JSON.parse(event.toolResultData);
347
- if (typeof parsed.startLine === "number") {
348
- startLine = parsed.startLine;
349
- }
350
- } catch {
351
- }
352
- }
353
- const editDiff = extractEditDiff(
354
- event.toolName,
355
- t._toolArgs,
356
- startLine
357
- );
358
- const finished = {
359
- ...t,
360
- isRunning: false,
361
- result: toolResult
362
- };
363
- if (editDiff) {
364
- finished.diffLines = editDiff.lines;
365
- finished.diffFile = editDiff.file;
366
- }
367
- delete finished._toolArgs;
368
- return finished;
369
- });
370
- const completed = updated.filter((t) => !t.isRunning);
371
- if (completed.length > MAX_COMPLETED_TOOLS) {
372
- const excess = completed.length - MAX_COMPLETED_TOOLS;
373
- let removed = 0;
374
- return updated.filter((t) => {
375
- if (!t.isRunning && removed < excess) {
376
- removed++;
377
- return false;
378
- }
379
- return true;
380
- });
381
- }
382
- return updated;
383
- });
384
- }
385
- };
386
- const paths = (0, import_agent_sdk.projectPaths)(props.cwd ?? process.cwd());
387
- sessionRef.current = (0, import_agent_sdk.createSession)({
388
- config: props.config,
389
- context: props.context,
390
- terminal: NOOP_TERMINAL,
391
- sessionLogger: new import_agent_sdk.FileSessionLogger(paths.logs),
392
- projectInfo: props.projectInfo,
393
- sessionStore: props.sessionStore,
394
- permissionMode: props.permissionMode,
395
- maxTurns: props.maxTurns,
396
- permissionHandler,
397
- onTextDelta,
398
- onToolExecution
399
- });
400
- }
401
- const clearStreamingText = (0, import_react.useCallback)(() => {
402
- setStreamingText("");
403
- streamingTextRef.current = "";
404
- setActiveTools([]);
405
- }, []);
406
- return {
407
- session: sessionRef.current,
408
- permissionRequest,
409
- streamingText,
410
- clearStreamingText,
411
- activeTools
412
- };
413
- }
414
-
415
- // src/ui/hooks/useMessages.ts
416
- var import_react2 = require("react");
417
- var MAX_RENDERED_MESSAGES = 100;
418
- function useMessages() {
419
- const [messages, setMessages] = (0, import_react2.useState)([]);
420
- const addMessage = (0, import_react2.useCallback)((msg) => {
421
- setMessages((prev) => {
422
- const updated = [...prev, msg];
423
- if (updated.length > MAX_RENDERED_MESSAGES) {
424
- return updated.slice(-MAX_RENDERED_MESSAGES);
425
- }
426
- return updated;
427
- });
428
- }, []);
429
- return { messages, setMessages, addMessage };
430
- }
431
-
432
- // src/ui/hooks/useSlashCommands.ts
433
- var import_react3 = require("react");
434
194
  var import_agent_core = require("@robota-sdk/agent-core");
435
195
 
436
- // src/commands/slash-executor.ts
437
- var VALID_MODES2 = ["plan", "default", "acceptEdits", "bypassPermissions"];
438
- var HELP_TEXT = [
439
- "Available commands:",
440
- " /help \u2014 Show this help",
441
- " /clear \u2014 Clear conversation",
442
- " /compact [instr] \u2014 Compact context (optional focus instructions)",
443
- " /mode [m] \u2014 Show/change permission mode",
444
- " /language [lang] \u2014 Set response language (ko, en, ja, zh)",
445
- " /cost \u2014 Show session info",
446
- " /reset \u2014 Delete settings and exit",
447
- " /exit \u2014 Exit CLI"
448
- ].join("\n");
449
- function handleHelp(addMessage) {
450
- addMessage({ role: "system", content: HELP_TEXT });
451
- return { handled: true };
452
- }
453
- function handleClear(addMessage, clearMessages, session) {
454
- clearMessages();
455
- session.clearHistory();
456
- addMessage({ role: "system", content: "Conversation cleared." });
457
- return { handled: true };
458
- }
459
- async function handleCompact(args, session, addMessage) {
460
- const instructions = args.trim() || void 0;
461
- const before = session.getContextState().usedPercentage;
462
- addMessage({ role: "system", content: "Compacting context..." });
463
- await session.compact(instructions);
464
- const after = session.getContextState().usedPercentage;
465
- addMessage({
466
- role: "system",
467
- content: `Context compacted: ${Math.round(before)}% -> ${Math.round(after)}%`
468
- });
469
- return { handled: true };
470
- }
471
- function handleMode(arg, session, addMessage) {
472
- if (!arg) {
473
- addMessage({ role: "system", content: `Current mode: ${session.getPermissionMode()}` });
474
- } else if (VALID_MODES2.includes(arg)) {
475
- session.setPermissionMode(arg);
476
- addMessage({ role: "system", content: `Permission mode set to: ${arg}` });
477
- } else {
478
- addMessage({ role: "system", content: `Invalid mode. Valid: ${VALID_MODES2.join(" | ")}` });
479
- }
480
- return { handled: true };
481
- }
482
- function handleModel(modelId, addMessage) {
483
- if (!modelId) {
484
- addMessage({ role: "system", content: "Select a model from the /model submenu." });
485
- return { handled: true };
486
- }
487
- return { handled: true, pendingModelId: modelId };
488
- }
489
- function handleCost(session, addMessage) {
490
- addMessage({
491
- role: "system",
492
- content: `Session: ${session.getSessionId()}
493
- Messages: ${session.getMessageCount()}`
494
- });
495
- return { handled: true };
496
- }
497
- function handlePermissions(session, addMessage) {
498
- const mode = session.getPermissionMode();
499
- const sessionAllowed = session.getSessionAllowedTools();
500
- const lines = [`Permission mode: ${mode}`];
501
- if (sessionAllowed.length > 0) {
502
- lines.push(`Session-approved tools: ${sessionAllowed.join(", ")}`);
503
- } else {
504
- lines.push("No session-approved tools.");
505
- }
506
- addMessage({ role: "system", content: lines.join("\n") });
507
- return { handled: true };
508
- }
509
- function handleContext(session, addMessage) {
510
- const ctx = session.getContextState();
511
- addMessage({
512
- role: "system",
513
- content: `Context: ${ctx.usedTokens.toLocaleString()} / ${ctx.maxTokens.toLocaleString()} tokens (${Math.round(ctx.usedPercentage)}%)`
514
- });
515
- return { handled: true };
516
- }
517
- function handleLanguage(lang, addMessage) {
518
- if (!lang) {
519
- addMessage({ role: "system", content: "Usage: /language <code> (e.g., ko, en, ja, zh)" });
520
- return { handled: true };
521
- }
522
- const settingsPath = getUserSettingsPath();
523
- const settings = readSettings(settingsPath);
524
- settings.language = lang;
525
- writeSettings(settingsPath, settings);
526
- addMessage({ role: "system", content: `Language set to "${lang}". Restarting...` });
527
- return { handled: true, exitRequested: true };
528
- }
529
- function handleReset(addMessage) {
530
- const settingsPath = getUserSettingsPath();
531
- if (deleteSettings(settingsPath)) {
532
- addMessage({ role: "system", content: `Deleted ${settingsPath}. Exiting...` });
533
- } else {
534
- addMessage({ role: "system", content: "No user settings found." });
535
- }
536
- return { handled: true, exitRequested: true };
537
- }
538
- async function handlePluginCommand(args, addMessage, callbacks) {
539
- const parts = args.trim().split(/\s+/);
540
- const subcommand = parts[0] ?? "";
541
- const subArgs = parts.slice(1).join(" ").trim();
542
- try {
543
- switch (subcommand) {
544
- case "":
545
- case void 0:
546
- case "manage": {
547
- return { handled: true, triggerPluginTUI: true };
548
- }
549
- case "install": {
550
- if (!subArgs) {
551
- addMessage({ role: "system", content: "Usage: /plugin install <name>@<marketplace>" });
552
- return { handled: true };
553
- }
554
- await callbacks.install(subArgs);
555
- addMessage({ role: "system", content: `Installed plugin: ${subArgs}` });
556
- return { handled: true };
557
- }
558
- case "uninstall": {
559
- if (!subArgs) {
560
- addMessage({ role: "system", content: "Usage: /plugin uninstall <name>@<marketplace>" });
561
- return { handled: true };
562
- }
563
- await callbacks.uninstall(subArgs);
564
- addMessage({ role: "system", content: `Uninstalled plugin: ${subArgs}` });
565
- return { handled: true };
566
- }
567
- case "enable": {
568
- if (!subArgs) {
569
- addMessage({ role: "system", content: "Usage: /plugin enable <name>@<marketplace>" });
570
- return { handled: true };
571
- }
572
- await callbacks.enable(subArgs);
573
- addMessage({ role: "system", content: `Enabled plugin: ${subArgs}` });
574
- return { handled: true };
575
- }
576
- case "disable": {
577
- if (!subArgs) {
578
- addMessage({ role: "system", content: "Usage: /plugin disable <name>@<marketplace>" });
579
- return { handled: true };
580
- }
581
- await callbacks.disable(subArgs);
582
- addMessage({ role: "system", content: `Disabled plugin: ${subArgs}` });
583
- return { handled: true };
584
- }
585
- case "marketplace": {
586
- const mpParts = subArgs.split(/\s+/);
587
- const mpSubcommand = mpParts[0] ?? "";
588
- const mpArgs = mpParts.slice(1).join(" ").trim();
589
- if (mpSubcommand === "add" && mpArgs) {
590
- const registeredName = await callbacks.marketplaceAdd(mpArgs);
591
- addMessage({
592
- role: "system",
593
- content: `Added marketplace: "${registeredName}" (from ${mpArgs})
594
- Install plugins with: /plugin install <name>@${registeredName}`
595
- });
596
- return { handled: true };
597
- } else if (mpSubcommand === "remove" && mpArgs) {
598
- await callbacks.marketplaceRemove(mpArgs);
599
- addMessage({
600
- role: "system",
601
- content: `Removed marketplace "${mpArgs}" and uninstalled its plugins.`
602
- });
603
- return { handled: true };
604
- } else if (mpSubcommand === "update" && mpArgs) {
605
- await callbacks.marketplaceUpdate(mpArgs);
606
- addMessage({
607
- role: "system",
608
- content: `Updated marketplace "${mpArgs}".`
609
- });
610
- return { handled: true };
611
- } else if (mpSubcommand === "list") {
612
- const sources = await callbacks.marketplaceList();
613
- if (sources.length === 0) {
614
- addMessage({ role: "system", content: "No marketplace sources configured." });
615
- } else {
616
- const lines = sources.map((s) => ` ${s.name} (${s.type})`);
617
- addMessage({ role: "system", content: `Marketplace sources:
618
- ${lines.join("\n")}` });
619
- }
620
- return { handled: true };
621
- } else {
622
- addMessage({
623
- role: "system",
624
- content: "Usage: /plugin marketplace add <source> | remove <name> | update <name> | list"
625
- });
626
- return { handled: true };
627
- }
628
- }
629
- default:
630
- addMessage({ role: "system", content: `Unknown plugin subcommand: ${subcommand}` });
631
- return { handled: true };
632
- }
633
- } catch (error) {
634
- const message = error instanceof Error ? error.message : String(error);
635
- addMessage({ role: "system", content: `Plugin error: ${message}` });
636
- return { handled: true };
637
- }
638
- }
639
- async function handleReloadPlugins(addMessage, callbacks) {
640
- await callbacks.reloadPlugins();
641
- addMessage({ role: "system", content: "Plugins reload complete." });
642
- return { handled: true };
643
- }
644
- async function executeSlashCommand(cmd, args, session, addMessage, clearMessages, registry, pluginCallbacks) {
645
- switch (cmd) {
646
- case "help":
647
- return handleHelp(addMessage);
648
- case "clear":
649
- return handleClear(addMessage, clearMessages, session);
650
- case "compact":
651
- return handleCompact(args, session, addMessage);
652
- case "mode":
653
- return handleMode(args.split(/\s+/)[0] || void 0, session, addMessage);
654
- case "model":
655
- return handleModel(args.split(/\s+/)[0] || void 0, addMessage);
656
- case "language":
657
- return handleLanguage(args.split(/\s+/)[0] || void 0, addMessage);
658
- case "cost":
659
- return handleCost(session, addMessage);
660
- case "permissions":
661
- return handlePermissions(session, addMessage);
662
- case "context":
663
- return handleContext(session, addMessage);
664
- case "reset":
665
- return handleReset(addMessage);
666
- case "exit":
667
- return { handled: true, exitRequested: true };
668
- case "plugin":
669
- if (pluginCallbacks) {
670
- return handlePluginCommand(args, addMessage, pluginCallbacks);
671
- }
672
- addMessage({ role: "system", content: "Plugin management is not available." });
673
- return { handled: true };
674
- case "reload-plugins":
675
- if (pluginCallbacks) {
676
- return handleReloadPlugins(addMessage, pluginCallbacks);
677
- }
678
- addMessage({ role: "system", content: "Plugin management is not available." });
679
- return { handled: true };
680
- default: {
681
- const dynamicCmd = registry.getCommands().find((c) => c.name === cmd && (c.source === "skill" || c.source === "plugin"));
682
- if (dynamicCmd) {
683
- addMessage({ role: "system", content: `Invoking ${dynamicCmd.source}: ${cmd}` });
684
- return { handled: false };
685
- }
686
- addMessage({ role: "system", content: `Unknown command "/${cmd}". Type /help for help.` });
687
- return { handled: true };
688
- }
196
+ // src/commands/plugin-source.ts
197
+ var PluginCommandSource = class {
198
+ name = "plugin";
199
+ plugins;
200
+ constructor(plugins) {
201
+ this.plugins = plugins;
689
202
  }
690
- }
691
-
692
- // src/ui/hooks/useSlashCommands.ts
693
- var EXIT_DELAY_MS = 500;
694
- function useSlashCommands(session, addMessage, setMessages, exit, registry, pendingModelChangeRef, setPendingModelId, pluginCallbacks, setShowPluginTUI) {
695
- return (0, import_react3.useCallback)(
696
- async (input) => {
697
- const parts = input.slice(1).split(/\s+/);
698
- const cmd = parts[0]?.toLowerCase() ?? "";
699
- const args = parts.slice(1).join(" ");
700
- const clearMessages = () => setMessages([]);
701
- const slashAddMessage = (msg) => {
702
- addMessage((0, import_agent_core.createSystemMessage)(msg.content));
703
- };
704
- const result = await executeSlashCommand(
705
- cmd,
706
- args,
707
- session,
708
- slashAddMessage,
709
- clearMessages,
710
- registry,
711
- pluginCallbacks
712
- );
713
- if (result.pendingModelId) {
714
- pendingModelChangeRef.current = result.pendingModelId;
715
- setPendingModelId(result.pendingModelId);
716
- }
717
- if (result.triggerPluginTUI) {
718
- setShowPluginTUI?.(true);
719
- }
720
- if (result.exitRequested) {
721
- setTimeout(() => exit(), EXIT_DELAY_MS);
203
+ getCommands() {
204
+ const commands = [];
205
+ for (const plugin of this.plugins) {
206
+ for (const skill of plugin.skills) {
207
+ const baseName = skill.name.includes("@") ? skill.name.split("@")[0] : skill.name;
208
+ commands.push({
209
+ name: baseName,
210
+ description: `(${plugin.manifest.name}) ${skill.description}`,
211
+ source: "plugin",
212
+ skillContent: skill.skillContent,
213
+ pluginDir: plugin.pluginDir
214
+ });
722
215
  }
723
- return result.handled;
724
- },
725
- [
726
- session,
727
- addMessage,
728
- setMessages,
729
- exit,
730
- registry,
731
- pendingModelChangeRef,
732
- setPendingModelId,
733
- pluginCallbacks,
734
- setShowPluginTUI
735
- ]
736
- );
737
- }
738
-
739
- // src/ui/hooks/useSubmitHandler.ts
740
- var import_react4 = require("react");
741
- var import_node_crypto = require("crypto");
742
- var import_agent_sdk2 = require("@robota-sdk/agent-sdk");
743
- var import_agent_core2 = require("@robota-sdk/agent-core");
744
-
745
- // src/utils/tool-call-extractor.ts
746
- var TOOL_ARG_MAX_LENGTH = 80;
747
- var TAIL_KEEP2 = 30;
748
- function extractToolCallsWithDiff(history, startIndex) {
749
- const summaries = [];
750
- for (let i = startIndex; i < history.length; i++) {
751
- const msg = history[i];
752
- if (msg.role === "assistant" && msg.toolCalls) {
753
- for (const tc of msg.toolCalls) {
754
- const value = parseFirstArgValue(tc.function.arguments);
755
- const truncated = value.length > TOOL_ARG_MAX_LENGTH ? value.slice(0, TOOL_ARG_MAX_LENGTH - TAIL_KEEP2 - 3) + "..." + value.slice(-TAIL_KEEP2) : value;
756
- const summary = {
757
- line: `${tc.function.name}(${truncated})`
758
- };
759
- if (tc.function.name === "Edit") {
760
- try {
761
- const args = JSON.parse(tc.function.arguments);
762
- const diff = extractEditDiff("Edit", args);
763
- if (diff) {
764
- summary.diffLines = diff.lines;
765
- summary.diffFile = diff.file;
766
- }
767
- } catch {
768
- }
769
- }
770
- summaries.push(summary);
216
+ for (const cmd of plugin.commands) {
217
+ commands.push({
218
+ name: cmd.name,
219
+ description: cmd.description,
220
+ source: "plugin",
221
+ skillContent: cmd.skillContent,
222
+ pluginDir: plugin.pluginDir
223
+ });
771
224
  }
772
225
  }
226
+ return commands;
773
227
  }
774
- return summaries;
775
- }
776
- function parseFirstArgValue(argsJson) {
777
- try {
778
- const parsed = JSON.parse(argsJson);
779
- const firstVal = Object.values(parsed)[0];
780
- return typeof firstVal === "string" ? firstVal : JSON.stringify(firstVal);
781
- } catch {
782
- return argsJson;
783
- }
784
- }
228
+ };
785
229
 
786
230
  // src/utils/skill-prompt.ts
787
231
  var import_node_child_process = require("child_process");
@@ -815,518 +259,63 @@ async function preprocessShellCommands(content) {
815
259
  let output = "";
816
260
  try {
817
261
  output = (0, import_node_child_process.execSync)(command, {
818
- timeout: 5e3,
819
- encoding: "utf-8",
820
- stdio: ["pipe", "pipe", "pipe"]
821
- }).trimEnd();
822
- } catch {
823
- output = "";
824
- }
825
- result = result.replace(full, output);
826
- }
827
- return result;
828
- }
829
- async function buildSkillPrompt(input, registry, context) {
830
- const parts = input.slice(1).split(/\s+/);
831
- const cmd = parts[0]?.toLowerCase() ?? "";
832
- const skillCmd = registry.getCommands().find((c) => c.name === cmd && (c.source === "skill" || c.source === "plugin"));
833
- if (!skillCmd) return null;
834
- const args = parts.slice(1).join(" ").trim();
835
- const userInstruction = args || skillCmd.description;
836
- if (skillCmd.skillContent) {
837
- let processed = await preprocessShellCommands(skillCmd.skillContent);
838
- processed = substituteVariables(processed, args, context);
839
- return `<skill name="${cmd}">
840
- ${processed}
841
- </skill>
842
-
843
- Execute the "${cmd}" skill: ${userInstruction}`;
844
- }
845
- return `Use the "${cmd}" skill: ${userInstruction}`;
846
- }
847
-
848
- // src/commands/skill-executor.ts
849
- function buildProcessedContent(skill, args, context) {
850
- if (!skill.skillContent) return null;
851
- return substituteVariables(skill.skillContent, args, context);
852
- }
853
- function buildInjectPrompt(skill, args, context) {
854
- const processed = buildProcessedContent(skill, args, context);
855
- if (processed) {
856
- const userInstruction = args || skill.description;
857
- return `<skill name="${skill.name}">
858
- ${processed}
859
- </skill>
860
-
861
- Execute the "${skill.name}" skill: ${userInstruction}`;
862
- }
863
- return `Use the "${skill.name}" skill: ${args || skill.description}`;
864
- }
865
- async function executeSkill(skill, args, callbacks, context) {
866
- if (skill.context === "fork") {
867
- if (!callbacks.runInFork) {
868
- throw new Error("Fork execution is not available. Agent tool deps may not be initialized.");
869
- }
870
- const content = buildProcessedContent(skill, args, context);
871
- const prompt2 = content ?? `Use the "${skill.name}" skill: ${args || skill.description}`;
872
- const options = {};
873
- if (skill.agent) options.agent = skill.agent;
874
- if (skill.allowedTools) options.allowedTools = skill.allowedTools;
875
- const result = await callbacks.runInFork(prompt2, options);
876
- return { mode: "fork", result };
877
- }
878
- const prompt = buildInjectPrompt(skill, args, context);
879
- return { mode: "inject", prompt };
880
- }
881
-
882
- // src/ui/hooks/useSubmitHandler.ts
883
- function syncContextState(session, setter) {
884
- const ctx = session.getContextState();
885
- setter({ percentage: ctx.usedPercentage, usedTokens: ctx.usedTokens, maxTokens: ctx.maxTokens });
886
- }
887
- async function runSessionPrompt(prompt, session, addMessage, clearStreamingText, setIsThinking, setContextState, rawInput) {
888
- setIsThinking(true);
889
- clearStreamingText();
890
- const historyBefore = session.getHistory().length;
891
- try {
892
- const response = await session.run(prompt, rawInput);
893
- clearStreamingText();
894
- const history = session.getHistory();
895
- const toolSummaries = extractToolCallsWithDiff(
896
- history,
897
- historyBefore
898
- );
899
- if (toolSummaries.length > 0) {
900
- addMessage(
901
- (0, import_agent_core2.createToolMessage)(JSON.stringify(toolSummaries), {
902
- toolCallId: (0, import_node_crypto.randomUUID)(),
903
- name: `${toolSummaries.length} tools`
904
- })
905
- );
906
- }
907
- addMessage((0, import_agent_core2.createAssistantMessage)(response || "(empty response)"));
908
- syncContextState(session, setContextState);
909
- } catch (err) {
910
- clearStreamingText();
911
- const isAbortError = err instanceof DOMException && err.name === "AbortError" || err instanceof Error && (err.message.includes("aborted") || err.message.includes("abort"));
912
- if (isAbortError) {
913
- const history = session.getHistory();
914
- const toolSummaries = extractToolCallsWithDiff(
915
- history,
916
- historyBefore
917
- );
918
- if (toolSummaries.length > 0) {
919
- addMessage(
920
- (0, import_agent_core2.createToolMessage)(JSON.stringify(toolSummaries), {
921
- toolCallId: (0, import_node_crypto.randomUUID)(),
922
- name: `${toolSummaries.length} tools`
923
- })
924
- );
925
- }
926
- const assistantParts = [];
927
- let lastAssistantState = "complete";
928
- for (let i = historyBefore; i < history.length; i++) {
929
- const msg = history[i];
930
- if (msg && msg.role === "assistant" && msg.content) {
931
- assistantParts.push(msg.content);
932
- if (msg.state === "interrupted") lastAssistantState = "interrupted";
933
- }
934
- }
935
- if (assistantParts.length > 0) {
936
- addMessage(
937
- (0, import_agent_core2.createAssistantMessage)(assistantParts.join("\n\n"), { state: lastAssistantState })
938
- );
939
- }
940
- addMessage((0, import_agent_core2.createSystemMessage)("Interrupted by user."));
941
- } else {
942
- const errMsg = err instanceof Error ? err.message : String(err);
943
- addMessage((0, import_agent_core2.createSystemMessage)(`Error: ${errMsg}`));
944
- }
945
- } finally {
946
- setIsThinking(false);
947
- }
948
- }
949
- function createForkRunner(sessionKey) {
950
- const deps = (0, import_agent_sdk2.retrieveAgentToolDeps)(sessionKey);
951
- if (!deps) return void 0;
952
- return async (content, options) => {
953
- const agentType = options.agent ?? "general-purpose";
954
- const agentDef = (0, import_agent_sdk2.getBuiltInAgent)(agentType) ?? deps.customAgentRegistry?.(agentType);
955
- if (!agentDef) {
956
- throw new Error(`Unknown agent type for fork execution: ${agentType}`);
957
- }
958
- const effectiveDef = options.allowedTools ? { ...agentDef, tools: options.allowedTools } : agentDef;
959
- const subSession = (0, import_agent_sdk2.createSubagentSession)({
960
- agentDefinition: effectiveDef,
961
- parentConfig: deps.config,
962
- parentContext: deps.context,
963
- parentTools: deps.tools,
964
- terminal: deps.terminal,
965
- isForkWorker: true,
966
- permissionHandler: deps.permissionHandler,
967
- onTextDelta: deps.onTextDelta,
968
- onToolExecution: deps.onToolExecution
969
- });
970
- return await subSession.run(content);
971
- };
972
- }
973
- function findSkillCommand(input, registry) {
974
- const parts = input.slice(1).split(/\s+/);
975
- const cmd = parts[0]?.toLowerCase() ?? "";
976
- const skillCmd = registry.getCommands().find((c) => c.name === cmd && (c.source === "skill" || c.source === "plugin"));
977
- if (!skillCmd) return null;
978
- return { skill: skillCmd, args: parts.slice(1).join(" ").trim() };
979
- }
980
- function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamingText, setIsThinking, setContextState, registry) {
981
- return (0, import_react4.useCallback)(
982
- async (input) => {
983
- if (input.startsWith("/")) {
984
- const handled = await handleSlashCommand(input);
985
- if (handled) {
986
- syncContextState(session, setContextState);
987
- return;
988
- }
989
- const found = findSkillCommand(input, registry);
990
- if (!found) return;
991
- const { skill, args } = found;
992
- if (skill.context === "fork") {
993
- const runInFork = createForkRunner(session);
994
- const result = await executeSkill(skill, args, { runInFork });
995
- if (result.mode === "fork") {
996
- addMessage((0, import_agent_core2.createAssistantMessage)(result.result ?? "(empty response)"));
997
- syncContextState(session, setContextState);
998
- return;
999
- }
1000
- if (result.prompt) {
1001
- const cmdName2 = input.slice(1).split(/\s+/)[0]?.toLowerCase() ?? "";
1002
- const qualifiedName2 = registry.resolveQualifiedName(cmdName2);
1003
- const hookInput2 = qualifiedName2 ? `/${qualifiedName2}${input.slice(1 + cmdName2.length)}` : input;
1004
- return runSessionPrompt(
1005
- result.prompt,
1006
- session,
1007
- addMessage,
1008
- clearStreamingText,
1009
- setIsThinking,
1010
- setContextState,
1011
- hookInput2
1012
- );
1013
- }
1014
- return;
1015
- }
1016
- const prompt = await buildSkillPrompt(input, registry);
1017
- if (!prompt) return;
1018
- const cmdName = input.slice(1).split(/\s+/)[0]?.toLowerCase() ?? "";
1019
- const qualifiedName = registry.resolveQualifiedName(cmdName);
1020
- const hookInput = qualifiedName ? `/${qualifiedName}${input.slice(1 + cmdName.length)}` : input;
1021
- return runSessionPrompt(
1022
- prompt,
1023
- session,
1024
- addMessage,
1025
- clearStreamingText,
1026
- setIsThinking,
1027
- setContextState,
1028
- hookInput
1029
- );
1030
- }
1031
- addMessage((0, import_agent_core2.createUserMessage)(input));
1032
- return runSessionPrompt(
1033
- input,
1034
- session,
1035
- addMessage,
1036
- clearStreamingText,
1037
- setIsThinking,
1038
- setContextState
1039
- );
1040
- },
1041
- [
1042
- session,
1043
- addMessage,
1044
- handleSlashCommand,
1045
- clearStreamingText,
1046
- setIsThinking,
1047
- setContextState,
1048
- registry
1049
- ]
1050
- );
1051
- }
1052
-
1053
- // src/ui/hooks/useCommandRegistry.ts
1054
- var import_react5 = require("react");
1055
- var import_node_os2 = require("os");
1056
- var import_node_path3 = require("path");
1057
- var import_agent_sdk3 = require("@robota-sdk/agent-sdk");
1058
-
1059
- // src/commands/command-registry.ts
1060
- var CommandRegistry = class {
1061
- sources = [];
1062
- addSource(source) {
1063
- this.sources.push(source);
1064
- }
1065
- /** Get all commands, optionally filtered by prefix */
1066
- getCommands(filter) {
1067
- const all = [];
1068
- for (const source of this.sources) {
1069
- all.push(...source.getCommands());
1070
- }
1071
- if (!filter) return all;
1072
- const lower = filter.toLowerCase();
1073
- return all.filter((cmd) => cmd.name.toLowerCase().startsWith(lower));
1074
- }
1075
- /** Resolve a short name to its fully qualified plugin:name form */
1076
- resolveQualifiedName(shortName) {
1077
- const matches = this.getCommands().filter(
1078
- (c) => c.source === "plugin" && c.name.includes(":") && c.name.endsWith(`:${shortName}`)
1079
- );
1080
- if (matches.length !== 1) return null;
1081
- return matches[0].name;
1082
- }
1083
- /** Get subcommands for a specific command */
1084
- getSubcommands(commandName) {
1085
- const lower = commandName.toLowerCase();
1086
- for (const source of this.sources) {
1087
- for (const cmd of source.getCommands()) {
1088
- if (cmd.name.toLowerCase() === lower && cmd.subcommands) {
1089
- return cmd.subcommands;
1090
- }
1091
- }
1092
- }
1093
- return [];
1094
- }
1095
- };
1096
-
1097
- // src/commands/builtin-source.ts
1098
- var import_agent_core3 = require("@robota-sdk/agent-core");
1099
- function buildModelSubcommands() {
1100
- const seen = /* @__PURE__ */ new Set();
1101
- const commands = [];
1102
- for (const model of Object.values(import_agent_core3.CLAUDE_MODELS)) {
1103
- if (seen.has(model.name)) continue;
1104
- seen.add(model.name);
1105
- commands.push({
1106
- name: model.id,
1107
- description: `${model.name} (${(0, import_agent_core3.formatTokenCount)(model.contextWindow).toUpperCase()})`,
1108
- source: "builtin"
1109
- });
1110
- }
1111
- return commands;
1112
- }
1113
- function createBuiltinCommands() {
1114
- return [
1115
- { name: "help", description: "Show available commands", source: "builtin" },
1116
- { name: "clear", description: "Clear conversation history", source: "builtin" },
1117
- {
1118
- name: "mode",
1119
- description: "Permission mode",
1120
- source: "builtin",
1121
- subcommands: [
1122
- { name: "plan", description: "Plan only, no execution", source: "builtin" },
1123
- { name: "default", description: "Ask before risky actions", source: "builtin" },
1124
- { name: "acceptEdits", description: "Auto-approve file edits", source: "builtin" },
1125
- { name: "bypassPermissions", description: "Skip all permission checks", source: "builtin" }
1126
- ]
1127
- },
1128
- {
1129
- name: "model",
1130
- description: "Select AI model",
1131
- source: "builtin",
1132
- subcommands: buildModelSubcommands()
1133
- },
1134
- {
1135
- name: "language",
1136
- description: "Set response language",
1137
- source: "builtin",
1138
- subcommands: [
1139
- { name: "ko", description: "Korean", source: "builtin" },
1140
- { name: "en", description: "English", source: "builtin" },
1141
- { name: "ja", description: "Japanese", source: "builtin" },
1142
- { name: "zh", description: "Chinese", source: "builtin" }
1143
- ]
1144
- },
1145
- { name: "compact", description: "Compress context window", source: "builtin" },
1146
- { name: "cost", description: "Show session info", source: "builtin" },
1147
- { name: "context", description: "Context window info", source: "builtin" },
1148
- { name: "permissions", description: "Permission rules", source: "builtin" },
1149
- { name: "plugin", description: "Manage plugins", source: "builtin" },
1150
- { name: "reload-plugins", description: "Reload all plugin resources", source: "builtin" },
1151
- { name: "reset", description: "Delete settings and exit", source: "builtin" },
1152
- { name: "exit", description: "Exit CLI", source: "builtin" }
1153
- ];
1154
- }
1155
- var BuiltinCommandSource = class {
1156
- name = "builtin";
1157
- commands;
1158
- constructor() {
1159
- this.commands = createBuiltinCommands();
1160
- }
1161
- getCommands() {
1162
- return this.commands;
1163
- }
1164
- };
1165
-
1166
- // src/commands/skill-source.ts
1167
- var import_node_fs3 = require("fs");
1168
- var import_node_path2 = require("path");
1169
- var import_node_os = require("os");
1170
- var BOOLEAN_KEYS = /* @__PURE__ */ new Set(["disable-model-invocation", "user-invocable"]);
1171
- var LIST_KEYS = /* @__PURE__ */ new Set(["allowed-tools"]);
1172
- function kebabToCamel(key) {
1173
- return key.replace(/-([a-z])/g, (_match, letter) => letter.toUpperCase());
1174
- }
1175
- function parseFrontmatter(content) {
1176
- const lines = content.split("\n");
1177
- if (lines[0]?.trim() !== "---") return null;
1178
- const result = {};
1179
- for (let i = 1; i < lines.length; i++) {
1180
- const line = lines[i];
1181
- if (line.trim() === "---") break;
1182
- const match = line.match(/^([a-z][a-z0-9-]*):\s*(.+)/);
1183
- if (!match) continue;
1184
- const key = match[1];
1185
- const rawValue = match[2].trim();
1186
- const camelKey = kebabToCamel(key);
1187
- if (BOOLEAN_KEYS.has(key)) {
1188
- result[camelKey] = rawValue === "true";
1189
- } else if (LIST_KEYS.has(key)) {
1190
- result[camelKey] = rawValue.split(",").map((s) => s.trim());
1191
- } else {
1192
- result[camelKey] = rawValue;
1193
- }
1194
- }
1195
- return Object.keys(result).length > 0 ? result : null;
1196
- }
1197
- function buildCommand(frontmatter, content, fallbackName) {
1198
- const cmd = {
1199
- name: frontmatter?.name ?? fallbackName,
1200
- description: frontmatter?.description ?? `Skill: ${fallbackName}`,
1201
- source: "skill",
1202
- skillContent: content
1203
- };
1204
- if (frontmatter?.argumentHint !== void 0) cmd.argumentHint = frontmatter.argumentHint;
1205
- if (frontmatter?.disableModelInvocation !== void 0)
1206
- cmd.disableModelInvocation = frontmatter.disableModelInvocation;
1207
- if (frontmatter?.userInvocable !== void 0) cmd.userInvocable = frontmatter.userInvocable;
1208
- if (frontmatter?.allowedTools !== void 0) cmd.allowedTools = frontmatter.allowedTools;
1209
- if (frontmatter?.model !== void 0) cmd.model = frontmatter.model;
1210
- if (frontmatter?.effort !== void 0) cmd.effort = frontmatter.effort;
1211
- if (frontmatter?.context !== void 0) cmd.context = frontmatter.context;
1212
- if (frontmatter?.agent !== void 0) cmd.agent = frontmatter.agent;
1213
- return cmd;
1214
- }
1215
- function scanSkillsDir(skillsDir) {
1216
- if (!(0, import_node_fs3.existsSync)(skillsDir)) return [];
1217
- const commands = [];
1218
- const entries = (0, import_node_fs3.readdirSync)(skillsDir, { withFileTypes: true });
1219
- for (const entry of entries) {
1220
- if (!entry.isDirectory()) continue;
1221
- const skillFile = (0, import_node_path2.join)(skillsDir, entry.name, "SKILL.md");
1222
- if (!(0, import_node_fs3.existsSync)(skillFile)) continue;
1223
- const content = (0, import_node_fs3.readFileSync)(skillFile, "utf-8");
1224
- const frontmatter = parseFrontmatter(content);
1225
- commands.push(buildCommand(frontmatter, content, entry.name));
1226
- }
1227
- return commands;
1228
- }
1229
- function scanCommandsDir(commandsDir) {
1230
- if (!(0, import_node_fs3.existsSync)(commandsDir)) return [];
1231
- const commands = [];
1232
- const entries = (0, import_node_fs3.readdirSync)(commandsDir, { withFileTypes: true });
1233
- for (const entry of entries) {
1234
- if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
1235
- const filePath = (0, import_node_path2.join)(commandsDir, entry.name);
1236
- const content = (0, import_node_fs3.readFileSync)(filePath, "utf-8");
1237
- const frontmatter = parseFrontmatter(content);
1238
- const fallbackName = (0, import_node_path2.basename)(entry.name, ".md");
1239
- commands.push(buildCommand(frontmatter, content, fallbackName));
1240
- }
1241
- return commands;
1242
- }
1243
- var SkillCommandSource = class {
1244
- name = "skill";
1245
- cwd;
1246
- home;
1247
- cachedCommands = null;
1248
- constructor(cwd, home) {
1249
- this.cwd = cwd;
1250
- this.home = home ?? (0, import_node_os.homedir)();
1251
- }
1252
- getCommands() {
1253
- if (this.cachedCommands) return this.cachedCommands;
1254
- const sources = [
1255
- scanSkillsDir((0, import_node_path2.join)(this.cwd, ".claude", "skills")),
1256
- // 1. project .claude/skills
1257
- scanCommandsDir((0, import_node_path2.join)(this.cwd, ".claude", "commands")),
1258
- // 2. project .claude/commands (legacy)
1259
- scanSkillsDir((0, import_node_path2.join)(this.home, ".robota", "skills")),
1260
- // 3. user ~/.robota/skills
1261
- scanSkillsDir((0, import_node_path2.join)(this.cwd, ".agents", "skills"))
1262
- // 4. project .agents/skills
1263
- ];
1264
- const seen = /* @__PURE__ */ new Set();
1265
- const merged = [];
1266
- for (const commands of sources) {
1267
- for (const cmd of commands) {
1268
- if (!seen.has(cmd.name)) {
1269
- seen.add(cmd.name);
1270
- merged.push(cmd);
1271
- }
1272
- }
262
+ timeout: 5e3,
263
+ encoding: "utf-8",
264
+ stdio: ["pipe", "pipe", "pipe"]
265
+ }).trimEnd();
266
+ } catch {
267
+ output = "";
1273
268
  }
1274
- this.cachedCommands = merged;
1275
- return this.cachedCommands;
1276
- }
1277
- /** Get skills that models can invoke (excludes disableModelInvocation: true) */
1278
- getModelInvocableSkills() {
1279
- return this.getCommands().filter((cmd) => cmd.disableModelInvocation !== true);
1280
- }
1281
- /** Get skills that users can invoke (excludes userInvocable: false) */
1282
- getUserInvocableSkills() {
1283
- return this.getCommands().filter((cmd) => cmd.userInvocable !== false);
269
+ result = result.replace(full, output);
1284
270
  }
1285
- };
271
+ return result;
272
+ }
273
+ async function buildSkillPrompt(input, registry, context) {
274
+ const parts = input.slice(1).split(/\s+/);
275
+ const cmd = parts[0]?.toLowerCase() ?? "";
276
+ const skillCmd = registry.getCommands().find((c) => c.name === cmd && (c.source === "skill" || c.source === "plugin"));
277
+ if (!skillCmd) return null;
278
+ const args = parts.slice(1).join(" ").trim();
279
+ const userInstruction = args || skillCmd.description;
280
+ if (skillCmd.skillContent) {
281
+ let processed = await preprocessShellCommands(skillCmd.skillContent);
282
+ processed = substituteVariables(processed, args, context);
283
+ return `<skill name="${cmd}">
284
+ ${processed}
285
+ </skill>
1286
286
 
1287
- // src/commands/plugin-source.ts
1288
- var PluginCommandSource = class {
1289
- name = "plugin";
1290
- plugins;
1291
- constructor(plugins) {
1292
- this.plugins = plugins;
1293
- }
1294
- getCommands() {
1295
- const commands = [];
1296
- for (const plugin of this.plugins) {
1297
- for (const skill of plugin.skills) {
1298
- const baseName = skill.name.includes("@") ? skill.name.split("@")[0] : skill.name;
1299
- commands.push({
1300
- name: baseName,
1301
- description: `(${plugin.manifest.name}) ${skill.description}`,
1302
- source: "plugin",
1303
- skillContent: skill.skillContent,
1304
- pluginDir: plugin.pluginDir
1305
- });
1306
- }
1307
- for (const cmd of plugin.commands) {
1308
- commands.push({
1309
- name: cmd.name,
1310
- description: cmd.description,
1311
- source: "plugin",
1312
- skillContent: cmd.skillContent,
1313
- pluginDir: plugin.pluginDir
1314
- });
1315
- }
1316
- }
1317
- return commands;
287
+ Execute the "${cmd}" skill: ${userInstruction}`;
1318
288
  }
1319
- };
289
+ return `Use the "${cmd}" skill: ${userInstruction}`;
290
+ }
1320
291
 
1321
- // src/ui/hooks/useCommandRegistry.ts
292
+ // src/ui/hooks/plugin-hooks-merger.ts
293
+ var import_node_path2 = require("path");
1322
294
  function buildPluginEnv(plugin) {
1323
- const dataDir = (0, import_node_path3.join)((0, import_node_path3.dirname)((0, import_node_path3.dirname)(plugin.pluginDir)), "data", plugin.manifest.name);
295
+ const dataDir = (0, import_node_path2.join)((0, import_node_path2.dirname)((0, import_node_path2.dirname)(plugin.pluginDir)), "data", plugin.manifest.name);
1324
296
  return {
1325
297
  CLAUDE_PLUGIN_ROOT: plugin.pluginDir,
1326
298
  CLAUDE_PLUGIN_PATH: plugin.pluginDir,
1327
299
  CLAUDE_PLUGIN_DATA: dataDir
1328
300
  };
1329
301
  }
302
+ function resolvePluginRoot(group, pluginDir) {
303
+ if (Array.isArray(group.hooks)) {
304
+ return {
305
+ ...group,
306
+ hooks: group.hooks.map((h) => {
307
+ if (typeof h.command === "string") {
308
+ return {
309
+ ...h,
310
+ command: h.command.replace(/\$\{CLAUDE_PLUGIN_ROOT\}/g, pluginDir)
311
+ };
312
+ }
313
+ return h;
314
+ })
315
+ };
316
+ }
317
+ return group;
318
+ }
1330
319
  function mergePluginHooks(plugins) {
1331
320
  const merged = {};
1332
321
  for (const plugin of plugins) {
@@ -1338,78 +327,293 @@ function mergePluginHooks(plugins) {
1338
327
  if (!Array.isArray(groups)) continue;
1339
328
  if (!merged[event]) merged[event] = [];
1340
329
  const resolved = groups.map((group) => {
1341
- const resolved2 = resolvePluginRoot(group, plugin.pluginDir);
1342
- if (typeof resolved2 === "object" && resolved2 !== null) {
1343
- resolved2.env = pluginEnv;
1344
- }
1345
- return resolved2;
330
+ const r = resolvePluginRoot(group, plugin.pluginDir);
331
+ r.env = pluginEnv;
332
+ return r;
1346
333
  });
1347
334
  merged[event].push(...resolved);
1348
335
  }
1349
336
  }
1350
337
  return merged;
1351
338
  }
1352
- function resolvePluginRoot(group, pluginDir) {
1353
- if (typeof group !== "object" || group === null) return group;
1354
- const obj = group;
1355
- if (Array.isArray(obj.hooks)) {
1356
- return {
1357
- ...obj,
1358
- hooks: obj.hooks.map((h) => {
1359
- if (typeof h !== "object" || h === null) return h;
1360
- const hook = h;
1361
- if (typeof hook.command === "string") {
1362
- return {
1363
- ...hook,
1364
- command: hook.command.replace(/\$\{CLAUDE_PLUGIN_ROOT\}/g, pluginDir)
1365
- };
1366
- }
1367
- return hook;
1368
- })
1369
- };
339
+ function mergeHooksIntoConfig(configHooks, pluginHooks) {
340
+ const pluginKeys = Object.keys(pluginHooks);
341
+ if (pluginKeys.length === 0) return configHooks;
342
+ const merged = {};
343
+ for (const [event, groups] of Object.entries(pluginHooks)) {
344
+ merged[event] = [...groups];
1370
345
  }
1371
- return group;
346
+ if (configHooks) {
347
+ for (const [event, groups] of Object.entries(configHooks)) {
348
+ if (!Array.isArray(groups)) continue;
349
+ if (!merged[event]) merged[event] = [];
350
+ merged[event].push(...groups);
351
+ }
352
+ }
353
+ return merged;
1372
354
  }
1373
- function useCommandRegistry(cwd) {
1374
- const resultRef = (0, import_react5.useRef)(null);
1375
- if (resultRef.current === null) {
1376
- const registry = new CommandRegistry();
1377
- registry.addSource(new BuiltinCommandSource());
1378
- registry.addSource(new SkillCommandSource(cwd));
1379
- let pluginHooks = {};
1380
- const pluginsDir = (0, import_node_path3.join)((0, import_node_os2.homedir)(), ".robota", "plugins");
1381
- const loader = new import_agent_sdk3.BundlePluginLoader(pluginsDir);
1382
- try {
1383
- const plugins = loader.loadPluginsSync();
1384
- if (plugins.length > 0) {
1385
- registry.addSource(new PluginCommandSource(plugins));
1386
- pluginHooks = mergePluginHooks(plugins);
355
+
356
+ // src/ui/hooks/useInteractiveSession.ts
357
+ var MAX_RENDERED_MESSAGES = 100;
358
+ function initializeSession(props, permissionHandler) {
359
+ const cwd = props.cwd ?? process.cwd();
360
+ const registry = new import_agent_sdk.CommandRegistry();
361
+ registry.addSource(new import_agent_sdk.BuiltinCommandSource());
362
+ registry.addSource(new import_agent_sdk.SkillCommandSource(cwd));
363
+ let pluginHooks = {};
364
+ const pluginsDir = (0, import_node_path3.join)((0, import_node_os.homedir)(), ".robota", "plugins");
365
+ const loader = new import_agent_sdk.BundlePluginLoader(pluginsDir);
366
+ try {
367
+ const plugins = loader.loadPluginsSync();
368
+ if (plugins.length > 0) {
369
+ registry.addSource(new PluginCommandSource(plugins));
370
+ pluginHooks = mergePluginHooks(plugins);
371
+ }
372
+ } catch {
373
+ }
374
+ const mergedConfig = {
375
+ ...props.config,
376
+ hooks: mergeHooksIntoConfig(
377
+ props.config.hooks,
378
+ pluginHooks
379
+ )
380
+ };
381
+ const interactiveSession = new import_agent_sdk.InteractiveSession({
382
+ config: mergedConfig,
383
+ context: props.context,
384
+ projectInfo: props.projectInfo,
385
+ sessionStore: props.sessionStore,
386
+ permissionMode: props.permissionMode,
387
+ maxTurns: props.maxTurns,
388
+ cwd,
389
+ permissionHandler
390
+ });
391
+ return {
392
+ interactiveSession,
393
+ registry,
394
+ commandExecutor: new import_agent_sdk.SystemCommandExecutor(),
395
+ pluginHooks
396
+ };
397
+ }
398
+ function useInteractiveSession(props) {
399
+ const [messages, setMessages] = (0, import_react.useState)([]);
400
+ const addMessage = (0, import_react.useCallback)((msg) => {
401
+ setMessages((prev) => {
402
+ const updated = [...prev, msg];
403
+ return updated.length > MAX_RENDERED_MESSAGES ? updated.slice(-MAX_RENDERED_MESSAGES) : updated;
404
+ });
405
+ }, []);
406
+ const [streamingText, setStreamingText] = (0, import_react.useState)("");
407
+ const [activeTools, setActiveTools] = (0, import_react.useState)([]);
408
+ const [isThinking, setIsThinking] = (0, import_react.useState)(false);
409
+ const [isAborting, setIsAborting] = (0, import_react.useState)(false);
410
+ const [pendingPrompt, setPendingPrompt] = (0, import_react.useState)(null);
411
+ const [contextState, setContextState] = (0, import_react.useState)({ percentage: 0, usedTokens: 0, maxTokens: 0 });
412
+ const [permissionRequest, setPermissionRequest] = (0, import_react.useState)(null);
413
+ const permissionQueueRef = (0, import_react.useRef)([]);
414
+ const processingRef = (0, import_react.useRef)(false);
415
+ const processNextPermission = (0, import_react.useCallback)(() => {
416
+ if (processingRef.current) return;
417
+ const next = permissionQueueRef.current[0];
418
+ if (!next) {
419
+ setPermissionRequest(null);
420
+ return;
421
+ }
422
+ processingRef.current = true;
423
+ setPermissionRequest({
424
+ toolName: next.toolName,
425
+ toolArgs: next.toolArgs,
426
+ resolve: (result) => {
427
+ permissionQueueRef.current.shift();
428
+ processingRef.current = false;
429
+ setPermissionRequest(null);
430
+ next.resolve(result);
431
+ setTimeout(() => processNextPermission(), 0);
1387
432
  }
1388
- } catch {
433
+ });
434
+ }, []);
435
+ const permissionHandler = (0, import_react.useCallback)(
436
+ (toolName, toolArgs) => new Promise((resolve) => {
437
+ permissionQueueRef.current.push({ toolName, toolArgs, resolve });
438
+ processNextPermission();
439
+ }),
440
+ [processNextPermission]
441
+ );
442
+ const stateRef = (0, import_react.useRef)(null);
443
+ if (stateRef.current === null) {
444
+ stateRef.current = initializeSession(props, permissionHandler);
445
+ }
446
+ const { interactiveSession, registry, commandExecutor } = stateRef.current;
447
+ (0, import_react.useEffect)(() => {
448
+ let streamBuf = "";
449
+ const onTextDelta = (delta) => {
450
+ streamBuf += delta;
451
+ setStreamingText(streamBuf);
452
+ };
453
+ const onToolStart = (state) => {
454
+ setActiveTools((prev) => [...prev, state]);
455
+ };
456
+ const onToolEnd = (state) => {
457
+ setActiveTools(
458
+ (prev) => prev.map((t) => t.toolName === state.toolName && t.isRunning ? state : t)
459
+ );
460
+ };
461
+ const onThinking = (thinking) => {
462
+ setIsThinking(thinking);
463
+ if (!thinking) {
464
+ setIsAborting(false);
465
+ streamBuf = "";
466
+ setStreamingText("");
467
+ setActiveTools([]);
468
+ }
469
+ };
470
+ const onComplete = (result) => {
471
+ setContextState({
472
+ percentage: result.contextState.usedPercentage,
473
+ usedTokens: result.contextState.usedTokens,
474
+ maxTokens: result.contextState.maxTokens
475
+ });
476
+ };
477
+ const onInterrupted = () => {
478
+ };
479
+ const onError = () => {
480
+ };
481
+ interactiveSession.on("text_delta", onTextDelta);
482
+ interactiveSession.on("tool_start", onToolStart);
483
+ interactiveSession.on("tool_end", onToolEnd);
484
+ interactiveSession.on("thinking", onThinking);
485
+ interactiveSession.on("complete", onComplete);
486
+ interactiveSession.on("interrupted", onInterrupted);
487
+ interactiveSession.on("error", onError);
488
+ return () => {
489
+ interactiveSession.off("text_delta", onTextDelta);
490
+ interactiveSession.off("tool_start", onToolStart);
491
+ interactiveSession.off("tool_end", onToolEnd);
492
+ interactiveSession.off("thinking", onThinking);
493
+ interactiveSession.off("complete", onComplete);
494
+ interactiveSession.off("interrupted", onInterrupted);
495
+ interactiveSession.off("error", onError);
496
+ };
497
+ }, [interactiveSession]);
498
+ (0, import_react.useEffect)(() => {
499
+ if (!isThinking) {
500
+ const sessionMessages = interactiveSession.getMessages();
501
+ if (sessionMessages.length > 0) {
502
+ setMessages(
503
+ sessionMessages.length > MAX_RENDERED_MESSAGES ? sessionMessages.slice(-MAX_RENDERED_MESSAGES) : [...sessionMessages]
504
+ );
505
+ }
506
+ setPendingPrompt(interactiveSession.getPendingPrompt());
1389
507
  }
1390
- resultRef.current = { registry, pluginHooks };
508
+ }, [isThinking, interactiveSession]);
509
+ const handleSubmit = (0, import_react.useCallback)(
510
+ async (input) => {
511
+ if (input.startsWith("/")) {
512
+ const parts = input.slice(1).split(/\s+/);
513
+ const cmd = parts[0]?.toLowerCase() ?? "";
514
+ const args = parts.slice(1).join(" ");
515
+ const result = await commandExecutor.execute(cmd, interactiveSession, args);
516
+ if (result) {
517
+ addMessage((0, import_agent_core.createSystemMessage)(result.message));
518
+ const effects = interactiveSession;
519
+ if (result.data?.modelId) {
520
+ effects._pendingModelId = result.data.modelId;
521
+ return;
522
+ }
523
+ if (result.data?.language) {
524
+ effects._pendingLanguage = result.data.language;
525
+ return;
526
+ }
527
+ if (result.data?.resetRequested) {
528
+ effects._resetRequested = true;
529
+ return;
530
+ }
531
+ const ctx = interactiveSession.getContextState();
532
+ setContextState({
533
+ percentage: ctx.usedPercentage,
534
+ usedTokens: ctx.usedTokens,
535
+ maxTokens: ctx.maxTokens
536
+ });
537
+ return;
538
+ }
539
+ const skillCmd = registry.getCommands().find((c) => c.name === cmd && (c.source === "skill" || c.source === "plugin"));
540
+ if (skillCmd) {
541
+ const prompt = await buildSkillPrompt(input, registry);
542
+ if (prompt) {
543
+ await interactiveSession.submit(prompt);
544
+ return;
545
+ }
546
+ }
547
+ if (cmd === "exit") {
548
+ interactiveSession._exitRequested = true;
549
+ return;
550
+ }
551
+ if (cmd === "plugin") {
552
+ interactiveSession._triggerPluginTUI = true;
553
+ return;
554
+ }
555
+ addMessage((0, import_agent_core.createSystemMessage)(`Unknown command "/${cmd}". Type /help for help.`));
556
+ return;
557
+ }
558
+ await interactiveSession.submit(input);
559
+ },
560
+ [interactiveSession, commandExecutor, registry, addMessage]
561
+ );
562
+ const handleAbort = (0, import_react.useCallback)(() => {
563
+ setIsAborting(true);
564
+ interactiveSession.abort();
565
+ }, [interactiveSession]);
566
+ const handleCancelQueue = (0, import_react.useCallback)(() => {
567
+ interactiveSession.cancelQueue();
568
+ setPendingPrompt(null);
569
+ }, [interactiveSession]);
570
+ if (contextState.maxTokens === 0) {
571
+ const ctx = interactiveSession.getContextState();
572
+ setContextState({
573
+ percentage: ctx.usedPercentage,
574
+ usedTokens: ctx.usedTokens,
575
+ maxTokens: ctx.maxTokens
576
+ });
1391
577
  }
1392
- return resultRef.current;
578
+ return {
579
+ interactiveSession,
580
+ registry,
581
+ commandExecutor,
582
+ pluginHooks: stateRef.current.pluginHooks,
583
+ messages,
584
+ addMessage,
585
+ setMessages,
586
+ streamingText,
587
+ activeTools,
588
+ isThinking,
589
+ isAborting,
590
+ pendingPrompt,
591
+ permissionRequest,
592
+ contextState,
593
+ handleSubmit,
594
+ handleAbort,
595
+ handleCancelQueue
596
+ };
1393
597
  }
1394
598
 
1395
599
  // src/ui/hooks/usePluginCallbacks.ts
1396
- var import_react6 = require("react");
1397
- var import_node_os3 = require("os");
600
+ var import_react2 = require("react");
601
+ var import_node_os2 = require("os");
1398
602
  var import_node_path4 = require("path");
1399
- var import_agent_sdk4 = require("@robota-sdk/agent-sdk");
603
+ var import_agent_sdk2 = require("@robota-sdk/agent-sdk");
1400
604
  function usePluginCallbacks(cwd) {
1401
- return (0, import_react6.useMemo)(() => {
1402
- const home = (0, import_node_os3.homedir)();
605
+ return (0, import_react2.useMemo)(() => {
606
+ const home = (0, import_node_os2.homedir)();
1403
607
  const pluginsDir = (0, import_node_path4.join)(home, ".robota", "plugins");
1404
608
  const userSettingsPath = (0, import_node_path4.join)(home, ".robota", "settings.json");
1405
- const settingsStore = new import_agent_sdk4.PluginSettingsStore(userSettingsPath);
1406
- const marketplace = new import_agent_sdk4.MarketplaceClient({ pluginsDir });
1407
- const installer = new import_agent_sdk4.BundlePluginInstaller({
609
+ const settingsStore = new import_agent_sdk2.PluginSettingsStore(userSettingsPath);
610
+ const marketplace = new import_agent_sdk2.MarketplaceClient({ pluginsDir });
611
+ const installer = new import_agent_sdk2.BundlePluginInstaller({
1408
612
  pluginsDir,
1409
613
  settingsStore,
1410
614
  marketplaceClient: marketplace
1411
615
  });
1412
- const loader = new import_agent_sdk4.BundlePluginLoader(pluginsDir);
616
+ const loader = new import_agent_sdk2.BundlePluginLoader(pluginsDir);
1413
617
  return {
1414
618
  listInstalled: async () => {
1415
619
  const plugins = await loader.loadAll();
@@ -1448,7 +652,7 @@ function usePluginCallbacks(cwd) {
1448
652
  }
1449
653
  if (scope === "project") {
1450
654
  const projectPluginsDir = (0, import_node_path4.join)(cwd, ".robota", "plugins");
1451
- const projectInstaller = new import_agent_sdk4.BundlePluginInstaller({
655
+ const projectInstaller = new import_agent_sdk2.BundlePluginInstaller({
1452
656
  pluginsDir: projectPluginsDir,
1453
657
  settingsStore,
1454
658
  marketplaceClient: marketplace
@@ -1497,9 +701,9 @@ function usePluginCallbacks(cwd) {
1497
701
  }
1498
702
 
1499
703
  // src/ui/MessageList.tsx
1500
- var import_react7 = __toESM(require("react"), 1);
704
+ var import_react3 = __toESM(require("react"), 1);
1501
705
  var import_ink2 = require("ink");
1502
- var import_agent_core4 = require("@robota-sdk/agent-core");
706
+ var import_agent_core2 = require("@robota-sdk/agent-core");
1503
707
 
1504
708
  // src/ui/render-markdown.ts
1505
709
  var import_marked = require("marked");
@@ -1585,7 +789,7 @@ function RoleLabel({ role }) {
1585
789
  }
1586
790
  }
1587
791
  function ToolMessage({ message }) {
1588
- if (!(0, import_agent_core4.isToolMessage)(message)) {
792
+ if (!(0, import_agent_core2.isToolMessage)(message)) {
1589
793
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, {});
1590
794
  }
1591
795
  const toolName = message.name;
@@ -1645,10 +849,10 @@ function ToolMessage({ message }) {
1645
849
  ] }, i))
1646
850
  ] });
1647
851
  }
1648
- var MessageItem = import_react7.default.memo(function MessageItem2({
852
+ var MessageItem = import_react3.default.memo(function MessageItem2({
1649
853
  message
1650
854
  }) {
1651
- if ((0, import_agent_core4.isToolMessage)(message)) {
855
+ if ((0, import_agent_core2.isToolMessage)(message)) {
1652
856
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ToolMessage, { message });
1653
857
  }
1654
858
  const content = message.content ?? "";
@@ -1656,7 +860,7 @@ var MessageItem = import_react7.default.memo(function MessageItem2({
1656
860
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Box, { flexDirection: "column", marginBottom: 1, children: [
1657
861
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RoleLabel, { role: message.role }) }),
1658
862
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Text, { children: " " }),
1659
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Box, { marginLeft: 2, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Text, { wrap: "wrap", children: (0, import_agent_core4.isAssistantMessage)(message) ? renderMarkdown(content + (isInterrupted ? "\n\n_(interrupted)_" : "")) : content }) })
863
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Box, { marginLeft: 2, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Text, { wrap: "wrap", children: (0, import_agent_core2.isAssistantMessage)(message) ? renderMarkdown(content + (isInterrupted ? "\n\n_(interrupted)_" : "")) : content }) })
1660
864
  ] });
1661
865
  });
1662
866
  function MessageList({ messages }) {
@@ -1665,7 +869,7 @@ function MessageList({ messages }) {
1665
869
 
1666
870
  // src/ui/StatusBar.tsx
1667
871
  var import_ink3 = require("ink");
1668
- var import_agent_core5 = require("@robota-sdk/agent-core");
872
+ var import_agent_core3 = require("@robota-sdk/agent-core");
1669
873
  var import_jsx_runtime3 = require("react/jsx-runtime");
1670
874
  var CONTEXT_YELLOW_THRESHOLD = 70;
1671
875
  var CONTEXT_RED_THRESHOLD = 90;
@@ -1705,9 +909,9 @@ function StatusBar({
1705
909
  "Context: ",
1706
910
  Math.round(contextPercentage),
1707
911
  "% (",
1708
- (0, import_agent_core5.formatTokenCount)(contextUsedTokens),
912
+ (0, import_agent_core3.formatTokenCount)(contextUsedTokens),
1709
913
  "/",
1710
- (0, import_agent_core5.formatTokenCount)(contextMaxTokens),
914
+ (0, import_agent_core3.formatTokenCount)(contextMaxTokens),
1711
915
  ")"
1712
916
  ] })
1713
917
  ] }),
@@ -1724,11 +928,11 @@ function StatusBar({
1724
928
  }
1725
929
 
1726
930
  // src/ui/InputArea.tsx
1727
- var import_react10 = __toESM(require("react"), 1);
931
+ var import_react6 = __toESM(require("react"), 1);
1728
932
  var import_ink7 = require("ink");
1729
933
 
1730
934
  // src/ui/CjkTextInput.tsx
1731
- var import_react8 = require("react");
935
+ var import_react4 = require("react");
1732
936
  var import_ink4 = require("ink");
1733
937
  var import_chalk = __toESM(require("chalk"), 1);
1734
938
  var import_string_width = __toESM(require("string-width"), 1);
@@ -1774,11 +978,11 @@ function CjkTextInput({
1774
978
  showCursor = true,
1775
979
  availableWidth
1776
980
  }) {
1777
- const valueRef = (0, import_react8.useRef)(value);
1778
- const cursorRef = (0, import_react8.useRef)(value.length);
1779
- const [, forceRender] = (0, import_react8.useState)(0);
1780
- const isPastingRef = (0, import_react8.useRef)(false);
1781
- const pasteBufferRef = (0, import_react8.useRef)("");
981
+ const valueRef = (0, import_react4.useRef)(value);
982
+ const cursorRef = (0, import_react4.useRef)(value.length);
983
+ const [, forceRender] = (0, import_react4.useState)(0);
984
+ const isPastingRef = (0, import_react4.useRef)(false);
985
+ const pasteBufferRef = (0, import_react4.useRef)("");
1782
986
  if (value !== valueRef.current) {
1783
987
  valueRef.current = value;
1784
988
  if (cursorRef.current > value.length) {
@@ -1907,15 +1111,15 @@ function renderWithCursor(value, cursorOffset, placeholder, showCursor) {
1907
1111
  }
1908
1112
 
1909
1113
  // src/ui/WaveText.tsx
1910
- var import_react9 = require("react");
1114
+ var import_react5 = require("react");
1911
1115
  var import_ink5 = require("ink");
1912
1116
  var import_jsx_runtime5 = require("react/jsx-runtime");
1913
1117
  var WAVE_COLORS = ["#666666", "#888888", "#aaaaaa", "#888888"];
1914
1118
  var INTERVAL_MS = 400;
1915
1119
  var CHARS_PER_GROUP = 4;
1916
1120
  function WaveText({ text }) {
1917
- const [tick, setTick] = (0, import_react9.useState)(0);
1918
- (0, import_react9.useEffect)(() => {
1121
+ const [tick, setTick] = (0, import_react5.useState)(0);
1122
+ (0, import_react5.useEffect)(() => {
1919
1123
  const timer = setInterval(() => {
1920
1124
  setTick((prev) => prev + 1);
1921
1125
  }, INTERVAL_MS);
@@ -1987,16 +1191,16 @@ function parseSlashInput(value) {
1987
1191
  return { isSlash: true, parentCommand: parent, filter: rest };
1988
1192
  }
1989
1193
  function useAutocomplete(value, registry) {
1990
- const [selectedIndex, setSelectedIndex] = (0, import_react10.useState)(0);
1991
- const [dismissed, setDismissed] = (0, import_react10.useState)(false);
1992
- const prevValueRef = import_react10.default.useRef(value);
1194
+ const [selectedIndex, setSelectedIndex] = (0, import_react6.useState)(0);
1195
+ const [dismissed, setDismissed] = (0, import_react6.useState)(false);
1196
+ const prevValueRef = import_react6.default.useRef(value);
1993
1197
  if (prevValueRef.current !== value) {
1994
1198
  prevValueRef.current = value;
1995
1199
  if (dismissed) setDismissed(false);
1996
1200
  }
1997
1201
  const parsed = parseSlashInput(value);
1998
1202
  const isSubcommandMode = parsed.isSlash && parsed.parentCommand.length > 0;
1999
- const filteredCommands = (0, import_react10.useMemo)(() => {
1203
+ const filteredCommands = (0, import_react6.useMemo)(() => {
2000
1204
  if (!registry || !parsed.isSlash || dismissed) return [];
2001
1205
  if (isSubcommandMode) {
2002
1206
  const subs = registry.getSubcommands(parsed.parentCommand);
@@ -2041,12 +1245,12 @@ function InputArea({
2041
1245
  pendingPrompt,
2042
1246
  registry
2043
1247
  }) {
2044
- const [value, setValue] = (0, import_react10.useState)("");
2045
- const pasteStore = (0, import_react10.useRef)(/* @__PURE__ */ new Map());
1248
+ const [value, setValue] = (0, import_react6.useState)("");
1249
+ const pasteStore = (0, import_react6.useRef)(/* @__PURE__ */ new Map());
2046
1250
  const { stdout } = (0, import_ink7.useStdout)();
2047
1251
  const terminalColumns = stdout?.columns ?? 80;
2048
1252
  const availableWidth = Math.max(1, terminalColumns - INPUT_AREA_OVERHEAD);
2049
- const pasteIdRef = (0, import_react10.useRef)(0);
1253
+ const pasteIdRef = (0, import_react6.useRef)(0);
2050
1254
  const {
2051
1255
  showPopup,
2052
1256
  filteredCommands,
@@ -2055,7 +1259,7 @@ function InputArea({
2055
1259
  isSubcommandMode,
2056
1260
  setShowPopup
2057
1261
  } = useAutocomplete(value, registry);
2058
- const handlePaste = (0, import_react10.useCallback)((text) => {
1262
+ const handlePaste = (0, import_react6.useCallback)((text) => {
2059
1263
  pasteIdRef.current += 1;
2060
1264
  const id = pasteIdRef.current;
2061
1265
  pasteStore.current.set(id, text);
@@ -2063,7 +1267,7 @@ function InputArea({
2063
1267
  const label = `[Pasted text #${id} +${lineCount} lines]`;
2064
1268
  setValue((prev) => prev ? `${prev} ${label}` : label);
2065
1269
  }, []);
2066
- const handleSubmit = (0, import_react10.useCallback)(
1270
+ const handleSubmit = (0, import_react6.useCallback)(
2067
1271
  (text) => {
2068
1272
  const trimmed = text.trim();
2069
1273
  if (trimmed.length === 0) return;
@@ -2079,7 +1283,7 @@ function InputArea({
2079
1283
  },
2080
1284
  [showPopup, filteredCommands, selectedIndex, onSubmit]
2081
1285
  );
2082
- const selectCommand = (0, import_react10.useCallback)(
1286
+ const selectCommand = (0, import_react6.useCallback)(
2083
1287
  (cmd) => {
2084
1288
  const parsed = parseSlashInput(value);
2085
1289
  if (parsed.parentCommand) {
@@ -2164,7 +1368,7 @@ function InputArea({
2164
1368
  }
2165
1369
 
2166
1370
  // src/ui/ConfirmPrompt.tsx
2167
- var import_react11 = require("react");
1371
+ var import_react7 = require("react");
2168
1372
  var import_ink8 = require("ink");
2169
1373
  var import_jsx_runtime8 = require("react/jsx-runtime");
2170
1374
  function ConfirmPrompt({
@@ -2172,9 +1376,9 @@ function ConfirmPrompt({
2172
1376
  options = ["Yes", "No"],
2173
1377
  onSelect
2174
1378
  }) {
2175
- const [selected, setSelected] = (0, import_react11.useState)(0);
2176
- const resolvedRef = (0, import_react11.useRef)(false);
2177
- const doSelect = (0, import_react11.useCallback)(
1379
+ const [selected, setSelected] = (0, import_react7.useState)(0);
1380
+ const resolvedRef = (0, import_react7.useRef)(false);
1381
+ const doSelect = (0, import_react7.useCallback)(
2178
1382
  (index) => {
2179
1383
  if (resolvedRef.current) return;
2180
1384
  resolvedRef.current = true;
@@ -2207,7 +1411,7 @@ function ConfirmPrompt({
2207
1411
  }
2208
1412
 
2209
1413
  // src/ui/PermissionPrompt.tsx
2210
- var import_react12 = __toESM(require("react"), 1);
1414
+ var import_react8 = __toESM(require("react"), 1);
2211
1415
  var import_ink9 = require("ink");
2212
1416
  var import_jsx_runtime9 = require("react/jsx-runtime");
2213
1417
  var OPTIONS = ["Allow", "Allow always (this session)", "Deny"];
@@ -2217,15 +1421,15 @@ function formatArgs(args) {
2217
1421
  return entries.map(([k, v]) => `${k}: ${typeof v === "string" ? v : JSON.stringify(v)}`).join(", ");
2218
1422
  }
2219
1423
  function PermissionPrompt({ request }) {
2220
- const [selected, setSelected] = import_react12.default.useState(0);
2221
- const resolvedRef = import_react12.default.useRef(false);
2222
- const prevRequestRef = import_react12.default.useRef(request);
1424
+ const [selected, setSelected] = import_react8.default.useState(0);
1425
+ const resolvedRef = import_react8.default.useRef(false);
1426
+ const prevRequestRef = import_react8.default.useRef(request);
2223
1427
  if (prevRequestRef.current !== request) {
2224
1428
  prevRequestRef.current = request;
2225
1429
  resolvedRef.current = false;
2226
1430
  setSelected(0);
2227
1431
  }
2228
- const doResolve = import_react12.default.useCallback(
1432
+ const doResolve = import_react8.default.useCallback(
2229
1433
  (index) => {
2230
1434
  if (resolvedRef.current) return;
2231
1435
  resolvedRef.current = true;
@@ -2314,10 +1518,10 @@ function StreamingIndicator({ text, activeTools }) {
2314
1518
  }
2315
1519
 
2316
1520
  // src/ui/PluginTUI.tsx
2317
- var import_react15 = require("react");
1521
+ var import_react11 = require("react");
2318
1522
 
2319
1523
  // src/ui/MenuSelect.tsx
2320
- var import_react13 = require("react");
1524
+ var import_react9 = require("react");
2321
1525
  var import_ink11 = require("ink");
2322
1526
  var import_jsx_runtime11 = require("react/jsx-runtime");
2323
1527
  function MenuSelect({
@@ -2328,10 +1532,10 @@ function MenuSelect({
2328
1532
  loading,
2329
1533
  error
2330
1534
  }) {
2331
- const [selected, setSelected] = (0, import_react13.useState)(0);
2332
- const selectedRef = (0, import_react13.useRef)(0);
2333
- const resolvedRef = (0, import_react13.useRef)(false);
2334
- const doSelect = (0, import_react13.useCallback)(
1535
+ const [selected, setSelected] = (0, import_react9.useState)(0);
1536
+ const selectedRef = (0, import_react9.useRef)(0);
1537
+ const resolvedRef = (0, import_react9.useRef)(false);
1538
+ const doSelect = (0, import_react9.useCallback)(
2335
1539
  (index) => {
2336
1540
  if (resolvedRef.current || items.length === 0) return;
2337
1541
  resolvedRef.current = true;
@@ -2381,7 +1585,7 @@ function MenuSelect({
2381
1585
  }
2382
1586
 
2383
1587
  // src/ui/TextPrompt.tsx
2384
- var import_react14 = require("react");
1588
+ var import_react10 = require("react");
2385
1589
  var import_ink12 = require("ink");
2386
1590
  var import_jsx_runtime12 = require("react/jsx-runtime");
2387
1591
  function TextPrompt({
@@ -2391,11 +1595,11 @@ function TextPrompt({
2391
1595
  onCancel,
2392
1596
  validate
2393
1597
  }) {
2394
- const [value, setValue] = (0, import_react14.useState)("");
2395
- const [error, setError] = (0, import_react14.useState)();
2396
- const resolvedRef = (0, import_react14.useRef)(false);
2397
- const valueRef = (0, import_react14.useRef)("");
2398
- const handleSubmit = (0, import_react14.useCallback)(() => {
1598
+ const [value, setValue] = (0, import_react10.useState)("");
1599
+ const [error, setError] = (0, import_react10.useState)();
1600
+ const resolvedRef = (0, import_react10.useRef)(false);
1601
+ const valueRef = (0, import_react10.useRef)("");
1602
+ const handleSubmit = (0, import_react10.useCallback)(() => {
2399
1603
  if (resolvedRef.current) return;
2400
1604
  const trimmed = valueRef.current.trim();
2401
1605
  if (!trimmed) return;
@@ -2539,19 +1743,19 @@ function handleInstalledActionSelect(value, pluginId, callbacks, nav) {
2539
1743
  // src/ui/PluginTUI.tsx
2540
1744
  var import_jsx_runtime13 = require("react/jsx-runtime");
2541
1745
  function PluginTUI({ callbacks, onClose, addMessage }) {
2542
- const [stack, setStack] = (0, import_react15.useState)([{ screen: "main" }]);
2543
- const [items, setItems] = (0, import_react15.useState)([]);
2544
- const [loading, setLoading] = (0, import_react15.useState)(false);
2545
- const [error, setError] = (0, import_react15.useState)();
2546
- const [confirm, setConfirm] = (0, import_react15.useState)();
2547
- const [refreshCounter, setRefreshCounter] = (0, import_react15.useState)(0);
1746
+ const [stack, setStack] = (0, import_react11.useState)([{ screen: "main" }]);
1747
+ const [items, setItems] = (0, import_react11.useState)([]);
1748
+ const [loading, setLoading] = (0, import_react11.useState)(false);
1749
+ const [error, setError] = (0, import_react11.useState)();
1750
+ const [confirm, setConfirm] = (0, import_react11.useState)();
1751
+ const [refreshCounter, setRefreshCounter] = (0, import_react11.useState)(0);
2548
1752
  const current = stack[stack.length - 1] ?? { screen: "main" };
2549
- const push = (0, import_react15.useCallback)((state) => {
1753
+ const push = (0, import_react11.useCallback)((state) => {
2550
1754
  setStack((prev) => [...prev, state]);
2551
1755
  setItems([]);
2552
1756
  setError(void 0);
2553
1757
  }, []);
2554
- const pop = (0, import_react15.useCallback)(() => {
1758
+ const pop = (0, import_react11.useCallback)(() => {
2555
1759
  setStack((prev) => {
2556
1760
  if (prev.length <= 1) {
2557
1761
  onClose();
@@ -2562,7 +1766,7 @@ function PluginTUI({ callbacks, onClose, addMessage }) {
2562
1766
  setItems([]);
2563
1767
  setError(void 0);
2564
1768
  }, [onClose]);
2565
- const popN = (0, import_react15.useCallback)(
1769
+ const popN = (0, import_react11.useCallback)(
2566
1770
  (n) => {
2567
1771
  setStack((prev) => {
2568
1772
  const next = prev.slice(0, Math.max(1, prev.length - n));
@@ -2577,18 +1781,18 @@ function PluginTUI({ callbacks, onClose, addMessage }) {
2577
1781
  },
2578
1782
  [onClose]
2579
1783
  );
2580
- const notify = (0, import_react15.useCallback)(
1784
+ const notify = (0, import_react11.useCallback)(
2581
1785
  (content) => {
2582
1786
  addMessage?.({ role: "system", content });
2583
1787
  },
2584
1788
  [addMessage]
2585
1789
  );
2586
- const refresh = (0, import_react15.useCallback)(() => {
1790
+ const refresh = (0, import_react11.useCallback)(() => {
2587
1791
  setItems([]);
2588
1792
  setRefreshCounter((c) => c + 1);
2589
1793
  }, []);
2590
1794
  const nav = { push, pop, popN, notify, setConfirm, refresh };
2591
- (0, import_react15.useEffect)(() => {
1795
+ (0, import_react11.useEffect)(() => {
2592
1796
  const screen2 = current.screen;
2593
1797
  if (screen2 === "marketplace-list") {
2594
1798
  setLoading(true);
@@ -2638,7 +1842,7 @@ function PluginTUI({ callbacks, onClose, addMessage }) {
2638
1842
  });
2639
1843
  }
2640
1844
  }, [stack.length, current.screen, current.context?.marketplace, callbacks, refreshCounter]);
2641
- const handleSelect = (0, import_react15.useCallback)(
1845
+ const handleSelect = (0, import_react11.useCallback)(
2642
1846
  (value) => {
2643
1847
  const screen2 = current.screen;
2644
1848
  const ctx = current.context;
@@ -2656,7 +1860,7 @@ function PluginTUI({ callbacks, onClose, addMessage }) {
2656
1860
  },
2657
1861
  [current, items, callbacks, push, pop, popN, notify, setConfirm, refresh]
2658
1862
  );
2659
- const handleTextSubmit = (0, import_react15.useCallback)(
1863
+ const handleTextSubmit = (0, import_react11.useCallback)(
2660
1864
  (value) => {
2661
1865
  if (current.screen === "marketplace-add") {
2662
1866
  callbacks.marketplaceAdd(value).then((name) => {
@@ -2766,104 +1970,90 @@ function PluginTUI({ callbacks, onClose, addMessage }) {
2766
1970
 
2767
1971
  // src/ui/App.tsx
2768
1972
  var import_jsx_runtime14 = require("react/jsx-runtime");
2769
- var EXIT_DELAY_MS2 = 500;
2770
- function mergeHooksIntoConfig(configHooks, pluginHooks) {
2771
- const pluginKeys = Object.keys(pluginHooks);
2772
- if (pluginKeys.length === 0) return configHooks;
2773
- const merged = {};
2774
- for (const [event, groups] of Object.entries(pluginHooks)) {
2775
- merged[event] = [...groups];
2776
- }
2777
- if (configHooks) {
2778
- for (const [event, groups] of Object.entries(configHooks)) {
2779
- if (!Array.isArray(groups)) continue;
2780
- if (!merged[event]) merged[event] = [];
2781
- merged[event].push(...groups);
2782
- }
2783
- }
2784
- return merged;
2785
- }
1973
+ var EXIT_DELAY_MS = 500;
2786
1974
  function App(props) {
2787
1975
  const { exit } = (0, import_ink13.useApp)();
2788
- const { registry, pluginHooks } = useCommandRegistry(props.cwd ?? process.cwd());
2789
- const configWithPluginHooks = {
2790
- ...props.config,
2791
- hooks: mergeHooksIntoConfig(
2792
- props.config.hooks,
2793
- pluginHooks
2794
- )
2795
- };
2796
- const { session, permissionRequest, streamingText, clearStreamingText, activeTools } = useSession(
2797
- { ...props, config: configWithPluginHooks }
2798
- );
2799
- const { messages, setMessages, addMessage } = useMessages();
2800
- const [isThinking, setIsThinking] = (0, import_react16.useState)(false);
2801
- const initialCtx = session.getContextState();
2802
- const [contextState, setContextState] = (0, import_react16.useState)({
2803
- percentage: initialCtx.usedPercentage,
2804
- usedTokens: initialCtx.usedTokens,
2805
- maxTokens: initialCtx.maxTokens
2806
- });
2807
- const pendingModelChangeRef = (0, import_react16.useRef)(null);
2808
- const [pendingModelId, setPendingModelId] = (0, import_react16.useState)(null);
2809
- const [showPluginTUI, setShowPluginTUI] = (0, import_react16.useState)(false);
2810
- const [isAborting, setIsAborting] = (0, import_react16.useState)(false);
2811
- const [pendingPrompt, setPendingPrompt] = (0, import_react16.useState)(null);
2812
- const pendingPromptRef = (0, import_react16.useRef)(null);
2813
- const pluginCallbacks = usePluginCallbacks(props.cwd ?? process.cwd());
2814
- const handleSlashCommand = useSlashCommands(
2815
- session,
2816
- addMessage,
2817
- setMessages,
2818
- exit,
1976
+ const cwd = props.cwd ?? process.cwd();
1977
+ const {
1978
+ interactiveSession,
2819
1979
  registry,
2820
- pendingModelChangeRef,
2821
- setPendingModelId,
2822
- pluginCallbacks,
2823
- setShowPluginTUI
2824
- );
2825
- const executePrompt = useSubmitHandler(
2826
- session,
1980
+ messages,
2827
1981
  addMessage,
2828
- handleSlashCommand,
2829
- clearStreamingText,
2830
- setIsThinking,
2831
- setContextState,
2832
- registry
2833
- );
2834
- const handleSubmit = (0, import_react16.useCallback)(
2835
- async (input) => {
2836
- if (isThinking) {
2837
- setPendingPrompt(input);
2838
- pendingPromptRef.current = input;
2839
- return;
1982
+ streamingText,
1983
+ activeTools,
1984
+ isThinking,
1985
+ isAborting,
1986
+ pendingPrompt,
1987
+ permissionRequest,
1988
+ contextState,
1989
+ handleSubmit: baseHandleSubmit,
1990
+ handleAbort,
1991
+ handleCancelQueue
1992
+ } = useInteractiveSession({
1993
+ config: props.config,
1994
+ context: props.context,
1995
+ projectInfo: props.projectInfo,
1996
+ sessionStore: props.sessionStore,
1997
+ permissionMode: props.permissionMode,
1998
+ maxTurns: props.maxTurns,
1999
+ cwd
2000
+ });
2001
+ const pluginCallbacks = usePluginCallbacks(cwd);
2002
+ const [pendingModelId, setPendingModelId] = (0, import_react12.useState)(null);
2003
+ const pendingModelChangeRef = (0, import_react12.useRef)(null);
2004
+ const [showPluginTUI, setShowPluginTUI] = (0, import_react12.useState)(false);
2005
+ const handleSubmit = async (input) => {
2006
+ await baseHandleSubmit(input);
2007
+ const sideEffects = interactiveSession;
2008
+ if (sideEffects._pendingModelId) {
2009
+ const modelId = sideEffects._pendingModelId;
2010
+ delete sideEffects._pendingModelId;
2011
+ pendingModelChangeRef.current = modelId;
2012
+ setPendingModelId(modelId);
2013
+ return;
2014
+ }
2015
+ if (sideEffects._pendingLanguage) {
2016
+ const lang = sideEffects._pendingLanguage;
2017
+ delete sideEffects._pendingLanguage;
2018
+ const settingsPath = getUserSettingsPath();
2019
+ const settings = readSettings(settingsPath);
2020
+ settings.language = lang;
2021
+ writeSettings(settingsPath, settings);
2022
+ addMessage((0, import_agent_core4.createSystemMessage)(`Language set to "${lang}". Restarting...`));
2023
+ setTimeout(() => exit(), EXIT_DELAY_MS);
2024
+ return;
2025
+ }
2026
+ if (sideEffects._resetRequested) {
2027
+ delete sideEffects._resetRequested;
2028
+ const settingsPath = getUserSettingsPath();
2029
+ if (deleteSettings(settingsPath)) {
2030
+ addMessage((0, import_agent_core4.createSystemMessage)(`Deleted ${settingsPath}. Exiting...`));
2031
+ } else {
2032
+ addMessage((0, import_agent_core4.createSystemMessage)("No user settings found."));
2840
2033
  }
2841
- await executePrompt(input);
2842
- },
2843
- [isThinking, executePrompt]
2844
- );
2034
+ setTimeout(() => exit(), EXIT_DELAY_MS);
2035
+ return;
2036
+ }
2037
+ if (sideEffects._exitRequested) {
2038
+ delete sideEffects._exitRequested;
2039
+ setTimeout(() => exit(), EXIT_DELAY_MS);
2040
+ return;
2041
+ }
2042
+ if (sideEffects._triggerPluginTUI) {
2043
+ delete sideEffects._triggerPluginTUI;
2044
+ setShowPluginTUI(true);
2045
+ return;
2046
+ }
2047
+ };
2845
2048
  (0, import_ink13.useInput)(
2846
2049
  (_input, key) => {
2847
2050
  if (key.escape && isThinking) {
2848
- setIsAborting(true);
2849
- setPendingPrompt(null);
2850
- pendingPromptRef.current = null;
2851
- session.abort();
2051
+ handleAbort();
2852
2052
  }
2853
2053
  },
2854
2054
  { isActive: !permissionRequest && !showPluginTUI }
2855
2055
  );
2856
- (0, import_react16.useEffect)(() => {
2857
- if (!isThinking) {
2858
- setIsAborting(false);
2859
- if (pendingPromptRef.current) {
2860
- const prompt = pendingPromptRef.current;
2861
- setPendingPrompt(null);
2862
- pendingPromptRef.current = null;
2863
- setTimeout(() => executePrompt(prompt), 0);
2864
- }
2865
- }
2866
- }, [isThinking, pendingPrompt, executePrompt]);
2056
+ const session = interactiveSession.getSession();
2867
2057
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_ink13.Box, { flexDirection: "column", children: [
2868
2058
  /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_ink13.Box, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
2869
2059
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink13.Text, { color: "cyan", bold: true, children: `
@@ -2886,7 +2076,7 @@ function App(props) {
2886
2076
  pendingModelId && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2887
2077
  ConfirmPrompt,
2888
2078
  {
2889
- message: `Change model to ${(0, import_agent_core6.getModelName)(pendingModelId)}? This will restart the session.`,
2079
+ message: `Change model to ${(0, import_agent_core4.getModelName)(pendingModelId)}? This will restart the session.`,
2890
2080
  onSelect: (index) => {
2891
2081
  setPendingModelId(null);
2892
2082
  pendingModelChangeRef.current = null;
@@ -2895,20 +2085,20 @@ function App(props) {
2895
2085
  const settingsPath = getUserSettingsPath();
2896
2086
  updateModelInSettings(settingsPath, pendingModelId);
2897
2087
  addMessage(
2898
- (0, import_agent_core7.createSystemMessage)(
2899
- `Model changed to ${(0, import_agent_core6.getModelName)(pendingModelId)}. Restarting...`
2088
+ (0, import_agent_core4.createSystemMessage)(
2089
+ `Model changed to ${(0, import_agent_core4.getModelName)(pendingModelId)}. Restarting...`
2900
2090
  )
2901
2091
  );
2902
- setTimeout(() => exit(), EXIT_DELAY_MS2);
2092
+ setTimeout(() => exit(), EXIT_DELAY_MS);
2903
2093
  } catch (err) {
2904
2094
  addMessage(
2905
- (0, import_agent_core7.createSystemMessage)(
2095
+ (0, import_agent_core4.createSystemMessage)(
2906
2096
  `Failed: ${err instanceof Error ? err.message : String(err)}`
2907
2097
  )
2908
2098
  );
2909
2099
  }
2910
2100
  } else {
2911
- addMessage((0, import_agent_core7.createSystemMessage)("Model change cancelled."));
2101
+ addMessage((0, import_agent_core4.createSystemMessage)("Model change cancelled."));
2912
2102
  }
2913
2103
  }
2914
2104
  }
@@ -2918,14 +2108,14 @@ function App(props) {
2918
2108
  {
2919
2109
  callbacks: pluginCallbacks,
2920
2110
  onClose: () => setShowPluginTUI(false),
2921
- addMessage: (msg) => addMessage((0, import_agent_core7.createSystemMessage)(msg.content))
2111
+ addMessage: (msg) => addMessage((0, import_agent_core4.createSystemMessage)(msg.content))
2922
2112
  }
2923
2113
  ),
2924
2114
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2925
2115
  StatusBar,
2926
2116
  {
2927
2117
  permissionMode: session.getPermissionMode(),
2928
- modelName: (0, import_agent_core6.getModelName)(props.config.provider.model),
2118
+ modelName: (0, import_agent_core4.getModelName)(props.config.provider.model),
2929
2119
  sessionId: session.getSessionId(),
2930
2120
  messageCount: messages.length,
2931
2121
  isThinking,
@@ -2938,10 +2128,7 @@ function App(props) {
2938
2128
  InputArea,
2939
2129
  {
2940
2130
  onSubmit: handleSubmit,
2941
- onCancelQueue: () => {
2942
- setPendingPrompt(null);
2943
- pendingPromptRef.current = null;
2944
- },
2131
+ onCancelQueue: handleCancelQueue,
2945
2132
  isDisabled: !!permissionRequest || showPluginTUI || isThinking && !!pendingPrompt,
2946
2133
  isAborting,
2947
2134
  pendingPrompt,
@@ -2988,9 +2175,9 @@ function renderApp(options) {
2988
2175
  // src/cli.ts
2989
2176
  var import_meta = {};
2990
2177
  function checkSettingsFile(filePath) {
2991
- if (!(0, import_node_fs4.existsSync)(filePath)) return "missing";
2178
+ if (!(0, import_node_fs2.existsSync)(filePath)) return "missing";
2992
2179
  try {
2993
- const raw = (0, import_node_fs4.readFileSync)(filePath, "utf8").trim();
2180
+ const raw = (0, import_node_fs2.readFileSync)(filePath, "utf8").trim();
2994
2181
  if (raw.length === 0) return "incomplete";
2995
2182
  const parsed = JSON.parse(raw);
2996
2183
  const provider = parsed.provider;
@@ -3007,7 +2194,7 @@ function readVersion() {
3007
2194
  const candidates = [(0, import_node_path5.join)(dir, "..", "..", "package.json"), (0, import_node_path5.join)(dir, "..", "package.json")];
3008
2195
  for (const pkgPath of candidates) {
3009
2196
  try {
3010
- const raw = (0, import_node_fs4.readFileSync)(pkgPath, "utf-8");
2197
+ const raw = (0, import_node_fs2.readFileSync)(pkgPath, "utf-8");
3011
2198
  const pkg = JSON.parse(raw);
3012
2199
  if (pkg.version !== void 0 && pkg.name !== void 0) {
3013
2200
  return pkg.version;
@@ -3095,7 +2282,7 @@ async function ensureConfig(cwd) {
3095
2282
  }
3096
2283
  const language = await promptInput(" Response language (ko/en/ja/zh, default: en): ");
3097
2284
  const settingsDir = (0, import_node_path5.dirname)(userPath);
3098
- (0, import_node_fs4.mkdirSync)(settingsDir, { recursive: true });
2285
+ (0, import_node_fs2.mkdirSync)(settingsDir, { recursive: true });
3099
2286
  const settings = {
3100
2287
  provider: {
3101
2288
  name: "anthropic",
@@ -3106,7 +2293,7 @@ async function ensureConfig(cwd) {
3106
2293
  if (language) {
3107
2294
  settings.language = language;
3108
2295
  }
3109
- (0, import_node_fs4.writeFileSync)(userPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
2296
+ (0, import_node_fs2.writeFileSync)(userPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
3110
2297
  process.stdout.write(`
3111
2298
  Config saved to ${userPath}
3112
2299
 
@@ -3135,9 +2322,9 @@ async function startCli() {
3135
2322
  const cwd = process.cwd();
3136
2323
  await ensureConfig(cwd);
3137
2324
  const [config, context, projectInfo] = await Promise.all([
3138
- (0, import_agent_sdk5.loadConfig)(cwd),
3139
- (0, import_agent_sdk5.loadContext)(cwd),
3140
- (0, import_agent_sdk5.detectProject)(cwd)
2325
+ (0, import_agent_sdk3.loadConfig)(cwd),
2326
+ (0, import_agent_sdk3.loadContext)(cwd),
2327
+ (0, import_agent_sdk3.detectProject)(cwd)
3141
2328
  ]);
3142
2329
  if (args.model !== void 0) {
3143
2330
  config.provider.model = args.model;
@@ -3145,7 +2332,7 @@ async function startCli() {
3145
2332
  if (args.language !== void 0) {
3146
2333
  config.language = args.language;
3147
2334
  }
3148
- const sessionStore = new import_agent_sdk5.SessionStore();
2335
+ const sessionStore = new import_agent_sdk3.SessionStore();
3149
2336
  if (args.printMode) {
3150
2337
  const prompt = args.positional.join(" ").trim();
3151
2338
  if (prompt.length === 0) {
@@ -3153,15 +2340,15 @@ async function startCli() {
3153
2340
  process.exit(1);
3154
2341
  }
3155
2342
  const terminal = new PrintTerminal();
3156
- const paths = (0, import_agent_sdk5.projectPaths)(cwd);
3157
- const session = (0, import_agent_sdk5.createSession)({
2343
+ const paths = (0, import_agent_sdk3.projectPaths)(cwd);
2344
+ const session = (0, import_agent_sdk3.createSession)({
3158
2345
  config,
3159
2346
  context,
3160
2347
  terminal,
3161
- sessionLogger: new import_agent_sdk5.FileSessionLogger(paths.logs),
2348
+ sessionLogger: new import_agent_sdk3.FileSessionLogger(paths.logs),
3162
2349
  projectInfo,
3163
2350
  permissionMode: args.permissionMode,
3164
- promptForApproval: import_agent_sdk6.promptForApproval
2351
+ promptForApproval: import_agent_sdk4.promptForApproval
3165
2352
  });
3166
2353
  const response = await session.run(prompt);
3167
2354
  process.stdout.write(response + "\n");