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

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");
@@ -816,517 +260,62 @@ async function preprocessShellCommands(content) {
816
260
  try {
817
261
  output = (0, import_node_child_process.execSync)(command, {
818
262
  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
- }
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,299 @@ 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
+ streamBuf = "";
465
+ setStreamingText("");
466
+ setActiveTools([]);
467
+ } else {
468
+ setIsAborting(false);
469
+ }
470
+ };
471
+ const onComplete = (result) => {
472
+ setContextState({
473
+ percentage: result.contextState.usedPercentage,
474
+ usedTokens: result.contextState.usedTokens,
475
+ maxTokens: result.contextState.maxTokens
476
+ });
477
+ };
478
+ const onInterrupted = () => {
479
+ };
480
+ const onError = () => {
481
+ };
482
+ interactiveSession.on("text_delta", onTextDelta);
483
+ interactiveSession.on("tool_start", onToolStart);
484
+ interactiveSession.on("tool_end", onToolEnd);
485
+ interactiveSession.on("thinking", onThinking);
486
+ interactiveSession.on("complete", onComplete);
487
+ interactiveSession.on("interrupted", onInterrupted);
488
+ interactiveSession.on("error", onError);
489
+ return () => {
490
+ interactiveSession.off("text_delta", onTextDelta);
491
+ interactiveSession.off("tool_start", onToolStart);
492
+ interactiveSession.off("tool_end", onToolEnd);
493
+ interactiveSession.off("thinking", onThinking);
494
+ interactiveSession.off("complete", onComplete);
495
+ interactiveSession.off("interrupted", onInterrupted);
496
+ interactiveSession.off("error", onError);
497
+ };
498
+ }, [interactiveSession]);
499
+ (0, import_react.useEffect)(() => {
500
+ if (!isThinking) {
501
+ const sessionMessages = interactiveSession.getMessages();
502
+ if (sessionMessages.length > 0) {
503
+ setMessages(
504
+ sessionMessages.length > MAX_RENDERED_MESSAGES ? sessionMessages.slice(-MAX_RENDERED_MESSAGES) : [...sessionMessages]
505
+ );
506
+ }
507
+ setPendingPrompt(interactiveSession.getPendingPrompt());
1389
508
  }
1390
- resultRef.current = { registry, pluginHooks };
509
+ }, [isThinking, interactiveSession]);
510
+ const handleSubmit = (0, import_react.useCallback)(
511
+ async (input) => {
512
+ if (input.startsWith("/")) {
513
+ const parts = input.slice(1).split(/\s+/);
514
+ const cmd = parts[0]?.toLowerCase() ?? "";
515
+ const args = parts.slice(1).join(" ");
516
+ const result = await commandExecutor.execute(cmd, interactiveSession, args);
517
+ if (result) {
518
+ addMessage((0, import_agent_core.createSystemMessage)(result.message));
519
+ const effects = interactiveSession;
520
+ if (result.data?.modelId) {
521
+ effects._pendingModelId = result.data.modelId;
522
+ return;
523
+ }
524
+ if (result.data?.language) {
525
+ effects._pendingLanguage = result.data.language;
526
+ return;
527
+ }
528
+ if (result.data?.resetRequested) {
529
+ effects._resetRequested = true;
530
+ return;
531
+ }
532
+ const ctx = interactiveSession.getContextState();
533
+ setContextState({
534
+ percentage: ctx.usedPercentage,
535
+ usedTokens: ctx.usedTokens,
536
+ maxTokens: ctx.maxTokens
537
+ });
538
+ return;
539
+ }
540
+ const skillCmd = registry.getCommands().find((c) => c.name === cmd && (c.source === "skill" || c.source === "plugin"));
541
+ if (skillCmd) {
542
+ addMessage((0, import_agent_core.createSystemMessage)(`Invoking ${skillCmd.source}: ${cmd}`));
543
+ const prompt = await buildSkillPrompt(input, registry);
544
+ if (prompt) {
545
+ const qualifiedName = registry.resolveQualifiedName(cmd);
546
+ const hookInput = qualifiedName ? `/${qualifiedName}${input.slice(1 + cmd.length)}` : input;
547
+ await interactiveSession.submit(prompt, input, hookInput);
548
+ setPendingPrompt(interactiveSession.getPendingPrompt());
549
+ return;
550
+ }
551
+ }
552
+ if (cmd === "exit") {
553
+ interactiveSession._exitRequested = true;
554
+ return;
555
+ }
556
+ if (cmd === "plugin") {
557
+ interactiveSession._triggerPluginTUI = true;
558
+ return;
559
+ }
560
+ addMessage((0, import_agent_core.createSystemMessage)(`Unknown command "/${cmd}". Type /help for help.`));
561
+ return;
562
+ }
563
+ await interactiveSession.submit(input);
564
+ setPendingPrompt(interactiveSession.getPendingPrompt());
565
+ },
566
+ [interactiveSession, commandExecutor, registry, addMessage]
567
+ );
568
+ const handleAbort = (0, import_react.useCallback)(() => {
569
+ setIsAborting(true);
570
+ interactiveSession.abort();
571
+ }, [interactiveSession]);
572
+ const handleCancelQueue = (0, import_react.useCallback)(() => {
573
+ interactiveSession.cancelQueue();
574
+ setPendingPrompt(null);
575
+ }, [interactiveSession]);
576
+ if (contextState.maxTokens === 0) {
577
+ const ctx = interactiveSession.getContextState();
578
+ setContextState({
579
+ percentage: ctx.usedPercentage,
580
+ usedTokens: ctx.usedTokens,
581
+ maxTokens: ctx.maxTokens
582
+ });
1391
583
  }
1392
- return resultRef.current;
584
+ return {
585
+ interactiveSession,
586
+ registry,
587
+ commandExecutor,
588
+ pluginHooks: stateRef.current.pluginHooks,
589
+ messages,
590
+ addMessage,
591
+ setMessages,
592
+ streamingText,
593
+ activeTools,
594
+ isThinking,
595
+ isAborting,
596
+ pendingPrompt,
597
+ permissionRequest,
598
+ contextState,
599
+ handleSubmit,
600
+ handleAbort,
601
+ handleCancelQueue
602
+ };
1393
603
  }
1394
604
 
1395
605
  // src/ui/hooks/usePluginCallbacks.ts
1396
- var import_react6 = require("react");
1397
- var import_node_os3 = require("os");
606
+ var import_react2 = require("react");
607
+ var import_node_os2 = require("os");
1398
608
  var import_node_path4 = require("path");
1399
- var import_agent_sdk4 = require("@robota-sdk/agent-sdk");
609
+ var import_agent_sdk2 = require("@robota-sdk/agent-sdk");
1400
610
  function usePluginCallbacks(cwd) {
1401
- return (0, import_react6.useMemo)(() => {
1402
- const home = (0, import_node_os3.homedir)();
611
+ return (0, import_react2.useMemo)(() => {
612
+ const home = (0, import_node_os2.homedir)();
1403
613
  const pluginsDir = (0, import_node_path4.join)(home, ".robota", "plugins");
1404
614
  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({
615
+ const settingsStore = new import_agent_sdk2.PluginSettingsStore(userSettingsPath);
616
+ const marketplace = new import_agent_sdk2.MarketplaceClient({ pluginsDir });
617
+ const installer = new import_agent_sdk2.BundlePluginInstaller({
1408
618
  pluginsDir,
1409
619
  settingsStore,
1410
620
  marketplaceClient: marketplace
1411
621
  });
1412
- const loader = new import_agent_sdk4.BundlePluginLoader(pluginsDir);
622
+ const loader = new import_agent_sdk2.BundlePluginLoader(pluginsDir);
1413
623
  return {
1414
624
  listInstalled: async () => {
1415
625
  const plugins = await loader.loadAll();
@@ -1448,7 +658,7 @@ function usePluginCallbacks(cwd) {
1448
658
  }
1449
659
  if (scope === "project") {
1450
660
  const projectPluginsDir = (0, import_node_path4.join)(cwd, ".robota", "plugins");
1451
- const projectInstaller = new import_agent_sdk4.BundlePluginInstaller({
661
+ const projectInstaller = new import_agent_sdk2.BundlePluginInstaller({
1452
662
  pluginsDir: projectPluginsDir,
1453
663
  settingsStore,
1454
664
  marketplaceClient: marketplace
@@ -1497,9 +707,9 @@ function usePluginCallbacks(cwd) {
1497
707
  }
1498
708
 
1499
709
  // src/ui/MessageList.tsx
1500
- var import_react7 = __toESM(require("react"), 1);
710
+ var import_react3 = __toESM(require("react"), 1);
1501
711
  var import_ink2 = require("ink");
1502
- var import_agent_core4 = require("@robota-sdk/agent-core");
712
+ var import_agent_core2 = require("@robota-sdk/agent-core");
1503
713
 
1504
714
  // src/ui/render-markdown.ts
1505
715
  var import_marked = require("marked");
@@ -1585,7 +795,7 @@ function RoleLabel({ role }) {
1585
795
  }
1586
796
  }
1587
797
  function ToolMessage({ message }) {
1588
- if (!(0, import_agent_core4.isToolMessage)(message)) {
798
+ if (!(0, import_agent_core2.isToolMessage)(message)) {
1589
799
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, {});
1590
800
  }
1591
801
  const toolName = message.name;
@@ -1645,10 +855,10 @@ function ToolMessage({ message }) {
1645
855
  ] }, i))
1646
856
  ] });
1647
857
  }
1648
- var MessageItem = import_react7.default.memo(function MessageItem2({
858
+ var MessageItem = import_react3.default.memo(function MessageItem2({
1649
859
  message
1650
860
  }) {
1651
- if ((0, import_agent_core4.isToolMessage)(message)) {
861
+ if ((0, import_agent_core2.isToolMessage)(message)) {
1652
862
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ToolMessage, { message });
1653
863
  }
1654
864
  const content = message.content ?? "";
@@ -1656,7 +866,7 @@ var MessageItem = import_react7.default.memo(function MessageItem2({
1656
866
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Box, { flexDirection: "column", marginBottom: 1, children: [
1657
867
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RoleLabel, { role: message.role }) }),
1658
868
  /* @__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 }) })
869
+ /* @__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
870
  ] });
1661
871
  });
1662
872
  function MessageList({ messages }) {
@@ -1665,7 +875,7 @@ function MessageList({ messages }) {
1665
875
 
1666
876
  // src/ui/StatusBar.tsx
1667
877
  var import_ink3 = require("ink");
1668
- var import_agent_core5 = require("@robota-sdk/agent-core");
878
+ var import_agent_core3 = require("@robota-sdk/agent-core");
1669
879
  var import_jsx_runtime3 = require("react/jsx-runtime");
1670
880
  var CONTEXT_YELLOW_THRESHOLD = 70;
1671
881
  var CONTEXT_RED_THRESHOLD = 90;
@@ -1705,9 +915,9 @@ function StatusBar({
1705
915
  "Context: ",
1706
916
  Math.round(contextPercentage),
1707
917
  "% (",
1708
- (0, import_agent_core5.formatTokenCount)(contextUsedTokens),
918
+ (0, import_agent_core3.formatTokenCount)(contextUsedTokens),
1709
919
  "/",
1710
- (0, import_agent_core5.formatTokenCount)(contextMaxTokens),
920
+ (0, import_agent_core3.formatTokenCount)(contextMaxTokens),
1711
921
  ")"
1712
922
  ] })
1713
923
  ] }),
@@ -1724,11 +934,11 @@ function StatusBar({
1724
934
  }
1725
935
 
1726
936
  // src/ui/InputArea.tsx
1727
- var import_react10 = __toESM(require("react"), 1);
937
+ var import_react6 = __toESM(require("react"), 1);
1728
938
  var import_ink7 = require("ink");
1729
939
 
1730
940
  // src/ui/CjkTextInput.tsx
1731
- var import_react8 = require("react");
941
+ var import_react4 = require("react");
1732
942
  var import_ink4 = require("ink");
1733
943
  var import_chalk = __toESM(require("chalk"), 1);
1734
944
  var import_string_width = __toESM(require("string-width"), 1);
@@ -1774,11 +984,11 @@ function CjkTextInput({
1774
984
  showCursor = true,
1775
985
  availableWidth
1776
986
  }) {
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)("");
987
+ const valueRef = (0, import_react4.useRef)(value);
988
+ const cursorRef = (0, import_react4.useRef)(value.length);
989
+ const [, forceRender] = (0, import_react4.useState)(0);
990
+ const isPastingRef = (0, import_react4.useRef)(false);
991
+ const pasteBufferRef = (0, import_react4.useRef)("");
1782
992
  if (value !== valueRef.current) {
1783
993
  valueRef.current = value;
1784
994
  if (cursorRef.current > value.length) {
@@ -1907,15 +1117,15 @@ function renderWithCursor(value, cursorOffset, placeholder, showCursor) {
1907
1117
  }
1908
1118
 
1909
1119
  // src/ui/WaveText.tsx
1910
- var import_react9 = require("react");
1120
+ var import_react5 = require("react");
1911
1121
  var import_ink5 = require("ink");
1912
1122
  var import_jsx_runtime5 = require("react/jsx-runtime");
1913
1123
  var WAVE_COLORS = ["#666666", "#888888", "#aaaaaa", "#888888"];
1914
1124
  var INTERVAL_MS = 400;
1915
1125
  var CHARS_PER_GROUP = 4;
1916
1126
  function WaveText({ text }) {
1917
- const [tick, setTick] = (0, import_react9.useState)(0);
1918
- (0, import_react9.useEffect)(() => {
1127
+ const [tick, setTick] = (0, import_react5.useState)(0);
1128
+ (0, import_react5.useEffect)(() => {
1919
1129
  const timer = setInterval(() => {
1920
1130
  setTick((prev) => prev + 1);
1921
1131
  }, INTERVAL_MS);
@@ -1987,16 +1197,16 @@ function parseSlashInput(value) {
1987
1197
  return { isSlash: true, parentCommand: parent, filter: rest };
1988
1198
  }
1989
1199
  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);
1200
+ const [selectedIndex, setSelectedIndex] = (0, import_react6.useState)(0);
1201
+ const [dismissed, setDismissed] = (0, import_react6.useState)(false);
1202
+ const prevValueRef = import_react6.default.useRef(value);
1993
1203
  if (prevValueRef.current !== value) {
1994
1204
  prevValueRef.current = value;
1995
1205
  if (dismissed) setDismissed(false);
1996
1206
  }
1997
1207
  const parsed = parseSlashInput(value);
1998
1208
  const isSubcommandMode = parsed.isSlash && parsed.parentCommand.length > 0;
1999
- const filteredCommands = (0, import_react10.useMemo)(() => {
1209
+ const filteredCommands = (0, import_react6.useMemo)(() => {
2000
1210
  if (!registry || !parsed.isSlash || dismissed) return [];
2001
1211
  if (isSubcommandMode) {
2002
1212
  const subs = registry.getSubcommands(parsed.parentCommand);
@@ -2041,12 +1251,12 @@ function InputArea({
2041
1251
  pendingPrompt,
2042
1252
  registry
2043
1253
  }) {
2044
- const [value, setValue] = (0, import_react10.useState)("");
2045
- const pasteStore = (0, import_react10.useRef)(/* @__PURE__ */ new Map());
1254
+ const [value, setValue] = (0, import_react6.useState)("");
1255
+ const pasteStore = (0, import_react6.useRef)(/* @__PURE__ */ new Map());
2046
1256
  const { stdout } = (0, import_ink7.useStdout)();
2047
1257
  const terminalColumns = stdout?.columns ?? 80;
2048
1258
  const availableWidth = Math.max(1, terminalColumns - INPUT_AREA_OVERHEAD);
2049
- const pasteIdRef = (0, import_react10.useRef)(0);
1259
+ const pasteIdRef = (0, import_react6.useRef)(0);
2050
1260
  const {
2051
1261
  showPopup,
2052
1262
  filteredCommands,
@@ -2055,7 +1265,7 @@ function InputArea({
2055
1265
  isSubcommandMode,
2056
1266
  setShowPopup
2057
1267
  } = useAutocomplete(value, registry);
2058
- const handlePaste = (0, import_react10.useCallback)((text) => {
1268
+ const handlePaste = (0, import_react6.useCallback)((text) => {
2059
1269
  pasteIdRef.current += 1;
2060
1270
  const id = pasteIdRef.current;
2061
1271
  pasteStore.current.set(id, text);
@@ -2063,7 +1273,7 @@ function InputArea({
2063
1273
  const label = `[Pasted text #${id} +${lineCount} lines]`;
2064
1274
  setValue((prev) => prev ? `${prev} ${label}` : label);
2065
1275
  }, []);
2066
- const handleSubmit = (0, import_react10.useCallback)(
1276
+ const handleSubmit = (0, import_react6.useCallback)(
2067
1277
  (text) => {
2068
1278
  const trimmed = text.trim();
2069
1279
  if (trimmed.length === 0) return;
@@ -2079,7 +1289,7 @@ function InputArea({
2079
1289
  },
2080
1290
  [showPopup, filteredCommands, selectedIndex, onSubmit]
2081
1291
  );
2082
- const selectCommand = (0, import_react10.useCallback)(
1292
+ const selectCommand = (0, import_react6.useCallback)(
2083
1293
  (cmd) => {
2084
1294
  const parsed = parseSlashInput(value);
2085
1295
  if (parsed.parentCommand) {
@@ -2164,7 +1374,7 @@ function InputArea({
2164
1374
  }
2165
1375
 
2166
1376
  // src/ui/ConfirmPrompt.tsx
2167
- var import_react11 = require("react");
1377
+ var import_react7 = require("react");
2168
1378
  var import_ink8 = require("ink");
2169
1379
  var import_jsx_runtime8 = require("react/jsx-runtime");
2170
1380
  function ConfirmPrompt({
@@ -2172,9 +1382,9 @@ function ConfirmPrompt({
2172
1382
  options = ["Yes", "No"],
2173
1383
  onSelect
2174
1384
  }) {
2175
- const [selected, setSelected] = (0, import_react11.useState)(0);
2176
- const resolvedRef = (0, import_react11.useRef)(false);
2177
- const doSelect = (0, import_react11.useCallback)(
1385
+ const [selected, setSelected] = (0, import_react7.useState)(0);
1386
+ const resolvedRef = (0, import_react7.useRef)(false);
1387
+ const doSelect = (0, import_react7.useCallback)(
2178
1388
  (index) => {
2179
1389
  if (resolvedRef.current) return;
2180
1390
  resolvedRef.current = true;
@@ -2207,7 +1417,7 @@ function ConfirmPrompt({
2207
1417
  }
2208
1418
 
2209
1419
  // src/ui/PermissionPrompt.tsx
2210
- var import_react12 = __toESM(require("react"), 1);
1420
+ var import_react8 = __toESM(require("react"), 1);
2211
1421
  var import_ink9 = require("ink");
2212
1422
  var import_jsx_runtime9 = require("react/jsx-runtime");
2213
1423
  var OPTIONS = ["Allow", "Allow always (this session)", "Deny"];
@@ -2217,15 +1427,15 @@ function formatArgs(args) {
2217
1427
  return entries.map(([k, v]) => `${k}: ${typeof v === "string" ? v : JSON.stringify(v)}`).join(", ");
2218
1428
  }
2219
1429
  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);
1430
+ const [selected, setSelected] = import_react8.default.useState(0);
1431
+ const resolvedRef = import_react8.default.useRef(false);
1432
+ const prevRequestRef = import_react8.default.useRef(request);
2223
1433
  if (prevRequestRef.current !== request) {
2224
1434
  prevRequestRef.current = request;
2225
1435
  resolvedRef.current = false;
2226
1436
  setSelected(0);
2227
1437
  }
2228
- const doResolve = import_react12.default.useCallback(
1438
+ const doResolve = import_react8.default.useCallback(
2229
1439
  (index) => {
2230
1440
  if (resolvedRef.current) return;
2231
1441
  resolvedRef.current = true;
@@ -2314,10 +1524,10 @@ function StreamingIndicator({ text, activeTools }) {
2314
1524
  }
2315
1525
 
2316
1526
  // src/ui/PluginTUI.tsx
2317
- var import_react15 = require("react");
1527
+ var import_react11 = require("react");
2318
1528
 
2319
1529
  // src/ui/MenuSelect.tsx
2320
- var import_react13 = require("react");
1530
+ var import_react9 = require("react");
2321
1531
  var import_ink11 = require("ink");
2322
1532
  var import_jsx_runtime11 = require("react/jsx-runtime");
2323
1533
  function MenuSelect({
@@ -2328,10 +1538,10 @@ function MenuSelect({
2328
1538
  loading,
2329
1539
  error
2330
1540
  }) {
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)(
1541
+ const [selected, setSelected] = (0, import_react9.useState)(0);
1542
+ const selectedRef = (0, import_react9.useRef)(0);
1543
+ const resolvedRef = (0, import_react9.useRef)(false);
1544
+ const doSelect = (0, import_react9.useCallback)(
2335
1545
  (index) => {
2336
1546
  if (resolvedRef.current || items.length === 0) return;
2337
1547
  resolvedRef.current = true;
@@ -2381,7 +1591,7 @@ function MenuSelect({
2381
1591
  }
2382
1592
 
2383
1593
  // src/ui/TextPrompt.tsx
2384
- var import_react14 = require("react");
1594
+ var import_react10 = require("react");
2385
1595
  var import_ink12 = require("ink");
2386
1596
  var import_jsx_runtime12 = require("react/jsx-runtime");
2387
1597
  function TextPrompt({
@@ -2391,11 +1601,11 @@ function TextPrompt({
2391
1601
  onCancel,
2392
1602
  validate
2393
1603
  }) {
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)(() => {
1604
+ const [value, setValue] = (0, import_react10.useState)("");
1605
+ const [error, setError] = (0, import_react10.useState)();
1606
+ const resolvedRef = (0, import_react10.useRef)(false);
1607
+ const valueRef = (0, import_react10.useRef)("");
1608
+ const handleSubmit = (0, import_react10.useCallback)(() => {
2399
1609
  if (resolvedRef.current) return;
2400
1610
  const trimmed = valueRef.current.trim();
2401
1611
  if (!trimmed) return;
@@ -2539,19 +1749,19 @@ function handleInstalledActionSelect(value, pluginId, callbacks, nav) {
2539
1749
  // src/ui/PluginTUI.tsx
2540
1750
  var import_jsx_runtime13 = require("react/jsx-runtime");
2541
1751
  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);
1752
+ const [stack, setStack] = (0, import_react11.useState)([{ screen: "main" }]);
1753
+ const [items, setItems] = (0, import_react11.useState)([]);
1754
+ const [loading, setLoading] = (0, import_react11.useState)(false);
1755
+ const [error, setError] = (0, import_react11.useState)();
1756
+ const [confirm, setConfirm] = (0, import_react11.useState)();
1757
+ const [refreshCounter, setRefreshCounter] = (0, import_react11.useState)(0);
2548
1758
  const current = stack[stack.length - 1] ?? { screen: "main" };
2549
- const push = (0, import_react15.useCallback)((state) => {
1759
+ const push = (0, import_react11.useCallback)((state) => {
2550
1760
  setStack((prev) => [...prev, state]);
2551
1761
  setItems([]);
2552
1762
  setError(void 0);
2553
1763
  }, []);
2554
- const pop = (0, import_react15.useCallback)(() => {
1764
+ const pop = (0, import_react11.useCallback)(() => {
2555
1765
  setStack((prev) => {
2556
1766
  if (prev.length <= 1) {
2557
1767
  onClose();
@@ -2562,7 +1772,7 @@ function PluginTUI({ callbacks, onClose, addMessage }) {
2562
1772
  setItems([]);
2563
1773
  setError(void 0);
2564
1774
  }, [onClose]);
2565
- const popN = (0, import_react15.useCallback)(
1775
+ const popN = (0, import_react11.useCallback)(
2566
1776
  (n) => {
2567
1777
  setStack((prev) => {
2568
1778
  const next = prev.slice(0, Math.max(1, prev.length - n));
@@ -2577,18 +1787,18 @@ function PluginTUI({ callbacks, onClose, addMessage }) {
2577
1787
  },
2578
1788
  [onClose]
2579
1789
  );
2580
- const notify = (0, import_react15.useCallback)(
1790
+ const notify = (0, import_react11.useCallback)(
2581
1791
  (content) => {
2582
1792
  addMessage?.({ role: "system", content });
2583
1793
  },
2584
1794
  [addMessage]
2585
1795
  );
2586
- const refresh = (0, import_react15.useCallback)(() => {
1796
+ const refresh = (0, import_react11.useCallback)(() => {
2587
1797
  setItems([]);
2588
1798
  setRefreshCounter((c) => c + 1);
2589
1799
  }, []);
2590
1800
  const nav = { push, pop, popN, notify, setConfirm, refresh };
2591
- (0, import_react15.useEffect)(() => {
1801
+ (0, import_react11.useEffect)(() => {
2592
1802
  const screen2 = current.screen;
2593
1803
  if (screen2 === "marketplace-list") {
2594
1804
  setLoading(true);
@@ -2638,7 +1848,7 @@ function PluginTUI({ callbacks, onClose, addMessage }) {
2638
1848
  });
2639
1849
  }
2640
1850
  }, [stack.length, current.screen, current.context?.marketplace, callbacks, refreshCounter]);
2641
- const handleSelect = (0, import_react15.useCallback)(
1851
+ const handleSelect = (0, import_react11.useCallback)(
2642
1852
  (value) => {
2643
1853
  const screen2 = current.screen;
2644
1854
  const ctx = current.context;
@@ -2656,7 +1866,7 @@ function PluginTUI({ callbacks, onClose, addMessage }) {
2656
1866
  },
2657
1867
  [current, items, callbacks, push, pop, popN, notify, setConfirm, refresh]
2658
1868
  );
2659
- const handleTextSubmit = (0, import_react15.useCallback)(
1869
+ const handleTextSubmit = (0, import_react11.useCallback)(
2660
1870
  (value) => {
2661
1871
  if (current.screen === "marketplace-add") {
2662
1872
  callbacks.marketplaceAdd(value).then((name) => {
@@ -2766,104 +1976,90 @@ function PluginTUI({ callbacks, onClose, addMessage }) {
2766
1976
 
2767
1977
  // src/ui/App.tsx
2768
1978
  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
- }
1979
+ var EXIT_DELAY_MS = 500;
2786
1980
  function App(props) {
2787
1981
  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,
1982
+ const cwd = props.cwd ?? process.cwd();
1983
+ const {
1984
+ interactiveSession,
2819
1985
  registry,
2820
- pendingModelChangeRef,
2821
- setPendingModelId,
2822
- pluginCallbacks,
2823
- setShowPluginTUI
2824
- );
2825
- const executePrompt = useSubmitHandler(
2826
- session,
1986
+ messages,
2827
1987
  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;
1988
+ streamingText,
1989
+ activeTools,
1990
+ isThinking,
1991
+ isAborting,
1992
+ pendingPrompt,
1993
+ permissionRequest,
1994
+ contextState,
1995
+ handleSubmit: baseHandleSubmit,
1996
+ handleAbort,
1997
+ handleCancelQueue
1998
+ } = useInteractiveSession({
1999
+ config: props.config,
2000
+ context: props.context,
2001
+ projectInfo: props.projectInfo,
2002
+ sessionStore: props.sessionStore,
2003
+ permissionMode: props.permissionMode,
2004
+ maxTurns: props.maxTurns,
2005
+ cwd
2006
+ });
2007
+ const pluginCallbacks = usePluginCallbacks(cwd);
2008
+ const [pendingModelId, setPendingModelId] = (0, import_react12.useState)(null);
2009
+ const pendingModelChangeRef = (0, import_react12.useRef)(null);
2010
+ const [showPluginTUI, setShowPluginTUI] = (0, import_react12.useState)(false);
2011
+ const handleSubmit = async (input) => {
2012
+ await baseHandleSubmit(input);
2013
+ const sideEffects = interactiveSession;
2014
+ if (sideEffects._pendingModelId) {
2015
+ const modelId = sideEffects._pendingModelId;
2016
+ delete sideEffects._pendingModelId;
2017
+ pendingModelChangeRef.current = modelId;
2018
+ setPendingModelId(modelId);
2019
+ return;
2020
+ }
2021
+ if (sideEffects._pendingLanguage) {
2022
+ const lang = sideEffects._pendingLanguage;
2023
+ delete sideEffects._pendingLanguage;
2024
+ const settingsPath = getUserSettingsPath();
2025
+ const settings = readSettings(settingsPath);
2026
+ settings.language = lang;
2027
+ writeSettings(settingsPath, settings);
2028
+ addMessage((0, import_agent_core4.createSystemMessage)(`Language set to "${lang}". Restarting...`));
2029
+ setTimeout(() => exit(), EXIT_DELAY_MS);
2030
+ return;
2031
+ }
2032
+ if (sideEffects._resetRequested) {
2033
+ delete sideEffects._resetRequested;
2034
+ const settingsPath = getUserSettingsPath();
2035
+ if (deleteSettings(settingsPath)) {
2036
+ addMessage((0, import_agent_core4.createSystemMessage)(`Deleted ${settingsPath}. Exiting...`));
2037
+ } else {
2038
+ addMessage((0, import_agent_core4.createSystemMessage)("No user settings found."));
2840
2039
  }
2841
- await executePrompt(input);
2842
- },
2843
- [isThinking, executePrompt]
2844
- );
2040
+ setTimeout(() => exit(), EXIT_DELAY_MS);
2041
+ return;
2042
+ }
2043
+ if (sideEffects._exitRequested) {
2044
+ delete sideEffects._exitRequested;
2045
+ setTimeout(() => exit(), EXIT_DELAY_MS);
2046
+ return;
2047
+ }
2048
+ if (sideEffects._triggerPluginTUI) {
2049
+ delete sideEffects._triggerPluginTUI;
2050
+ setShowPluginTUI(true);
2051
+ return;
2052
+ }
2053
+ };
2845
2054
  (0, import_ink13.useInput)(
2846
2055
  (_input, key) => {
2847
2056
  if (key.escape && isThinking) {
2848
- setIsAborting(true);
2849
- setPendingPrompt(null);
2850
- pendingPromptRef.current = null;
2851
- session.abort();
2057
+ handleAbort();
2852
2058
  }
2853
2059
  },
2854
2060
  { isActive: !permissionRequest && !showPluginTUI }
2855
2061
  );
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]);
2062
+ const session = interactiveSession.getSession();
2867
2063
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_ink13.Box, { flexDirection: "column", children: [
2868
2064
  /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_ink13.Box, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
2869
2065
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink13.Text, { color: "cyan", bold: true, children: `
@@ -2880,13 +2076,13 @@ function App(props) {
2880
2076
  ] }),
2881
2077
  /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_ink13.Box, { flexDirection: "column", paddingX: 1, flexGrow: 1, children: [
2882
2078
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(MessageList, { messages }),
2883
- isThinking && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink13.Box, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(StreamingIndicator, { text: streamingText, activeTools }) })
2079
+ (isThinking || activeTools.length > 0) && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink13.Box, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(StreamingIndicator, { text: streamingText, activeTools }) })
2884
2080
  ] }),
2885
2081
  permissionRequest && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(PermissionPrompt, { request: permissionRequest }),
2886
2082
  pendingModelId && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2887
2083
  ConfirmPrompt,
2888
2084
  {
2889
- message: `Change model to ${(0, import_agent_core6.getModelName)(pendingModelId)}? This will restart the session.`,
2085
+ message: `Change model to ${(0, import_agent_core4.getModelName)(pendingModelId)}? This will restart the session.`,
2890
2086
  onSelect: (index) => {
2891
2087
  setPendingModelId(null);
2892
2088
  pendingModelChangeRef.current = null;
@@ -2895,20 +2091,20 @@ function App(props) {
2895
2091
  const settingsPath = getUserSettingsPath();
2896
2092
  updateModelInSettings(settingsPath, pendingModelId);
2897
2093
  addMessage(
2898
- (0, import_agent_core7.createSystemMessage)(
2899
- `Model changed to ${(0, import_agent_core6.getModelName)(pendingModelId)}. Restarting...`
2094
+ (0, import_agent_core4.createSystemMessage)(
2095
+ `Model changed to ${(0, import_agent_core4.getModelName)(pendingModelId)}. Restarting...`
2900
2096
  )
2901
2097
  );
2902
- setTimeout(() => exit(), EXIT_DELAY_MS2);
2098
+ setTimeout(() => exit(), EXIT_DELAY_MS);
2903
2099
  } catch (err) {
2904
2100
  addMessage(
2905
- (0, import_agent_core7.createSystemMessage)(
2101
+ (0, import_agent_core4.createSystemMessage)(
2906
2102
  `Failed: ${err instanceof Error ? err.message : String(err)}`
2907
2103
  )
2908
2104
  );
2909
2105
  }
2910
2106
  } else {
2911
- addMessage((0, import_agent_core7.createSystemMessage)("Model change cancelled."));
2107
+ addMessage((0, import_agent_core4.createSystemMessage)("Model change cancelled."));
2912
2108
  }
2913
2109
  }
2914
2110
  }
@@ -2918,14 +2114,14 @@ function App(props) {
2918
2114
  {
2919
2115
  callbacks: pluginCallbacks,
2920
2116
  onClose: () => setShowPluginTUI(false),
2921
- addMessage: (msg) => addMessage((0, import_agent_core7.createSystemMessage)(msg.content))
2117
+ addMessage: (msg) => addMessage((0, import_agent_core4.createSystemMessage)(msg.content))
2922
2118
  }
2923
2119
  ),
2924
2120
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2925
2121
  StatusBar,
2926
2122
  {
2927
2123
  permissionMode: session.getPermissionMode(),
2928
- modelName: (0, import_agent_core6.getModelName)(props.config.provider.model),
2124
+ modelName: (0, import_agent_core4.getModelName)(props.config.provider.model),
2929
2125
  sessionId: session.getSessionId(),
2930
2126
  messageCount: messages.length,
2931
2127
  isThinking,
@@ -2938,10 +2134,7 @@ function App(props) {
2938
2134
  InputArea,
2939
2135
  {
2940
2136
  onSubmit: handleSubmit,
2941
- onCancelQueue: () => {
2942
- setPendingPrompt(null);
2943
- pendingPromptRef.current = null;
2944
- },
2137
+ onCancelQueue: handleCancelQueue,
2945
2138
  isDisabled: !!permissionRequest || showPluginTUI || isThinking && !!pendingPrompt,
2946
2139
  isAborting,
2947
2140
  pendingPrompt,
@@ -2988,9 +2181,9 @@ function renderApp(options) {
2988
2181
  // src/cli.ts
2989
2182
  var import_meta = {};
2990
2183
  function checkSettingsFile(filePath) {
2991
- if (!(0, import_node_fs4.existsSync)(filePath)) return "missing";
2184
+ if (!(0, import_node_fs2.existsSync)(filePath)) return "missing";
2992
2185
  try {
2993
- const raw = (0, import_node_fs4.readFileSync)(filePath, "utf8").trim();
2186
+ const raw = (0, import_node_fs2.readFileSync)(filePath, "utf8").trim();
2994
2187
  if (raw.length === 0) return "incomplete";
2995
2188
  const parsed = JSON.parse(raw);
2996
2189
  const provider = parsed.provider;
@@ -3007,7 +2200,7 @@ function readVersion() {
3007
2200
  const candidates = [(0, import_node_path5.join)(dir, "..", "..", "package.json"), (0, import_node_path5.join)(dir, "..", "package.json")];
3008
2201
  for (const pkgPath of candidates) {
3009
2202
  try {
3010
- const raw = (0, import_node_fs4.readFileSync)(pkgPath, "utf-8");
2203
+ const raw = (0, import_node_fs2.readFileSync)(pkgPath, "utf-8");
3011
2204
  const pkg = JSON.parse(raw);
3012
2205
  if (pkg.version !== void 0 && pkg.name !== void 0) {
3013
2206
  return pkg.version;
@@ -3095,7 +2288,7 @@ async function ensureConfig(cwd) {
3095
2288
  }
3096
2289
  const language = await promptInput(" Response language (ko/en/ja/zh, default: en): ");
3097
2290
  const settingsDir = (0, import_node_path5.dirname)(userPath);
3098
- (0, import_node_fs4.mkdirSync)(settingsDir, { recursive: true });
2291
+ (0, import_node_fs2.mkdirSync)(settingsDir, { recursive: true });
3099
2292
  const settings = {
3100
2293
  provider: {
3101
2294
  name: "anthropic",
@@ -3106,7 +2299,7 @@ async function ensureConfig(cwd) {
3106
2299
  if (language) {
3107
2300
  settings.language = language;
3108
2301
  }
3109
- (0, import_node_fs4.writeFileSync)(userPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
2302
+ (0, import_node_fs2.writeFileSync)(userPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
3110
2303
  process.stdout.write(`
3111
2304
  Config saved to ${userPath}
3112
2305
 
@@ -3135,9 +2328,9 @@ async function startCli() {
3135
2328
  const cwd = process.cwd();
3136
2329
  await ensureConfig(cwd);
3137
2330
  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)
2331
+ (0, import_agent_sdk3.loadConfig)(cwd),
2332
+ (0, import_agent_sdk3.loadContext)(cwd),
2333
+ (0, import_agent_sdk3.detectProject)(cwd)
3141
2334
  ]);
3142
2335
  if (args.model !== void 0) {
3143
2336
  config.provider.model = args.model;
@@ -3145,7 +2338,7 @@ async function startCli() {
3145
2338
  if (args.language !== void 0) {
3146
2339
  config.language = args.language;
3147
2340
  }
3148
- const sessionStore = new import_agent_sdk5.SessionStore();
2341
+ const sessionStore = new import_agent_sdk3.SessionStore();
3149
2342
  if (args.printMode) {
3150
2343
  const prompt = args.positional.join(" ").trim();
3151
2344
  if (prompt.length === 0) {
@@ -3153,15 +2346,15 @@ async function startCli() {
3153
2346
  process.exit(1);
3154
2347
  }
3155
2348
  const terminal = new PrintTerminal();
3156
- const paths = (0, import_agent_sdk5.projectPaths)(cwd);
3157
- const session = (0, import_agent_sdk5.createSession)({
2349
+ const paths = (0, import_agent_sdk3.projectPaths)(cwd);
2350
+ const session = (0, import_agent_sdk3.createSession)({
3158
2351
  config,
3159
2352
  context,
3160
2353
  terminal,
3161
- sessionLogger: new import_agent_sdk5.FileSessionLogger(paths.logs),
2354
+ sessionLogger: new import_agent_sdk3.FileSessionLogger(paths.logs),
3162
2355
  projectInfo,
3163
2356
  permissionMode: args.permissionMode,
3164
- promptForApproval: import_agent_sdk6.promptForApproval
2357
+ promptForApproval: import_agent_sdk4.promptForApproval
3165
2358
  });
3166
2359
  const response = await session.run(prompt);
3167
2360
  process.stdout.write(response + "\n");