@robota-sdk/agent-cli 3.0.0-beta.23 → 3.0.0-beta.25

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_sdk4.Session,
34
- SessionStore: () => import_agent_sdk4.SessionStore,
35
- TRUST_TO_MODE: () => import_agent_sdk4.TRUST_TO_MODE,
36
- query: () => import_agent_sdk4.query,
33
+ Session: () => import_agent_sdk6.Session,
34
+ SessionStore: () => import_agent_sdk6.SessionStore,
35
+ TRUST_TO_MODE: () => import_agent_sdk6.TRUST_TO_MODE,
36
+ query: () => import_agent_sdk6.query,
37
37
  startCli: () => startCli
38
38
  });
39
39
  module.exports = __toCommonJS(index_exports);
40
- var import_agent_sdk4 = require("@robota-sdk/agent-sdk");
40
+ var import_agent_sdk6 = require("@robota-sdk/agent-sdk");
41
41
 
42
42
  // src/cli.ts
43
43
  var import_node_fs3 = require("fs");
44
- var import_node_path3 = require("path");
44
+ var import_node_path5 = require("path");
45
45
  var import_node_url = require("url");
46
- var import_agent_sdk2 = require("@robota-sdk/agent-sdk");
47
- var import_agent_sdk3 = require("@robota-sdk/agent-sdk");
46
+ var import_agent_sdk4 = require("@robota-sdk/agent-sdk");
47
+ var import_agent_sdk5 = require("@robota-sdk/agent-sdk");
48
48
 
49
49
  // src/utils/cli-args.ts
50
50
  var import_node_util = require("util");
@@ -182,7 +182,7 @@ var PrintTerminal = class {
182
182
  var import_ink11 = require("ink");
183
183
 
184
184
  // src/ui/App.tsx
185
- var import_react11 = require("react");
185
+ var import_react12 = require("react");
186
186
  var import_ink10 = require("ink");
187
187
  var import_agent_core3 = require("@robota-sdk/agent-core");
188
188
 
@@ -402,7 +402,122 @@ function handleReset(addMessage) {
402
402
  }
403
403
  return { handled: true, exitRequested: true };
404
404
  }
405
- async function executeSlashCommand(cmd, args, session, addMessage, clearMessages, registry) {
405
+ async function handlePluginCommand(args, addMessage, callbacks) {
406
+ const parts = args.trim().split(/\s+/);
407
+ const subcommand = parts[0] ?? "";
408
+ const subArgs = parts.slice(1).join(" ").trim();
409
+ try {
410
+ switch (subcommand) {
411
+ case "":
412
+ case void 0: {
413
+ const plugins = await callbacks.listInstalled();
414
+ if (plugins.length === 0) {
415
+ addMessage({ role: "system", content: "No plugins installed." });
416
+ } else {
417
+ const lines = plugins.map(
418
+ (p) => ` ${p.name} \u2014 ${p.description} [${p.enabled ? "enabled" : "disabled"}]`
419
+ );
420
+ addMessage({ role: "system", content: `Installed plugins:
421
+ ${lines.join("\n")}` });
422
+ }
423
+ return { handled: true };
424
+ }
425
+ case "install": {
426
+ if (!subArgs) {
427
+ addMessage({ role: "system", content: "Usage: /plugin install <name>@<marketplace>" });
428
+ return { handled: true };
429
+ }
430
+ await callbacks.install(subArgs);
431
+ addMessage({ role: "system", content: `Installed plugin: ${subArgs}` });
432
+ return { handled: true };
433
+ }
434
+ case "uninstall": {
435
+ if (!subArgs) {
436
+ addMessage({ role: "system", content: "Usage: /plugin uninstall <name>@<marketplace>" });
437
+ return { handled: true };
438
+ }
439
+ await callbacks.uninstall(subArgs);
440
+ addMessage({ role: "system", content: `Uninstalled plugin: ${subArgs}` });
441
+ return { handled: true };
442
+ }
443
+ case "enable": {
444
+ if (!subArgs) {
445
+ addMessage({ role: "system", content: "Usage: /plugin enable <name>@<marketplace>" });
446
+ return { handled: true };
447
+ }
448
+ await callbacks.enable(subArgs);
449
+ addMessage({ role: "system", content: `Enabled plugin: ${subArgs}` });
450
+ return { handled: true };
451
+ }
452
+ case "disable": {
453
+ if (!subArgs) {
454
+ addMessage({ role: "system", content: "Usage: /plugin disable <name>@<marketplace>" });
455
+ return { handled: true };
456
+ }
457
+ await callbacks.disable(subArgs);
458
+ addMessage({ role: "system", content: `Disabled plugin: ${subArgs}` });
459
+ return { handled: true };
460
+ }
461
+ case "marketplace": {
462
+ const mpParts = subArgs.split(/\s+/);
463
+ const mpSubcommand = mpParts[0] ?? "";
464
+ const mpArgs = mpParts.slice(1).join(" ").trim();
465
+ if (mpSubcommand === "add" && mpArgs) {
466
+ const registeredName = await callbacks.marketplaceAdd(mpArgs);
467
+ addMessage({
468
+ role: "system",
469
+ content: `Added marketplace: "${registeredName}" (from ${mpArgs})
470
+ Install plugins with: /plugin install <name>@${registeredName}`
471
+ });
472
+ return { handled: true };
473
+ } else if (mpSubcommand === "remove" && mpArgs) {
474
+ await callbacks.marketplaceRemove(mpArgs);
475
+ addMessage({
476
+ role: "system",
477
+ content: `Removed marketplace "${mpArgs}" and uninstalled its plugins.`
478
+ });
479
+ return { handled: true };
480
+ } else if (mpSubcommand === "update" && mpArgs) {
481
+ await callbacks.marketplaceUpdate(mpArgs);
482
+ addMessage({
483
+ role: "system",
484
+ content: `Updated marketplace "${mpArgs}".`
485
+ });
486
+ return { handled: true };
487
+ } else if (mpSubcommand === "list") {
488
+ const sources = await callbacks.marketplaceList();
489
+ if (sources.length === 0) {
490
+ addMessage({ role: "system", content: "No marketplace sources configured." });
491
+ } else {
492
+ const lines = sources.map((s) => ` ${s.name} (${s.type})`);
493
+ addMessage({ role: "system", content: `Marketplace sources:
494
+ ${lines.join("\n")}` });
495
+ }
496
+ return { handled: true };
497
+ } else {
498
+ addMessage({
499
+ role: "system",
500
+ content: "Usage: /plugin marketplace add <source> | remove <name> | update <name> | list"
501
+ });
502
+ return { handled: true };
503
+ }
504
+ }
505
+ default:
506
+ addMessage({ role: "system", content: `Unknown plugin subcommand: ${subcommand}` });
507
+ return { handled: true };
508
+ }
509
+ } catch (error) {
510
+ const message = error instanceof Error ? error.message : String(error);
511
+ addMessage({ role: "system", content: `Plugin error: ${message}` });
512
+ return { handled: true };
513
+ }
514
+ }
515
+ async function handleReloadPlugins(addMessage, callbacks) {
516
+ await callbacks.reloadPlugins();
517
+ addMessage({ role: "system", content: "Plugins reload complete." });
518
+ return { handled: true };
519
+ }
520
+ async function executeSlashCommand(cmd, args, session, addMessage, clearMessages, registry, pluginCallbacks) {
406
521
  switch (cmd) {
407
522
  case "help":
408
523
  return handleHelp(addMessage);
@@ -426,10 +541,22 @@ async function executeSlashCommand(cmd, args, session, addMessage, clearMessages
426
541
  return handleReset(addMessage);
427
542
  case "exit":
428
543
  return { handled: true, exitRequested: true };
544
+ case "plugin":
545
+ if (pluginCallbacks) {
546
+ return handlePluginCommand(args, addMessage, pluginCallbacks);
547
+ }
548
+ addMessage({ role: "system", content: "Plugin management is not available." });
549
+ return { handled: true };
550
+ case "reload-plugins":
551
+ if (pluginCallbacks) {
552
+ return handleReloadPlugins(addMessage, pluginCallbacks);
553
+ }
554
+ addMessage({ role: "system", content: "Plugin management is not available." });
555
+ return { handled: true };
429
556
  default: {
430
- const skillCmd = registry.getCommands().find((c) => c.name === cmd && c.source === "skill");
431
- if (skillCmd) {
432
- addMessage({ role: "system", content: `Invoking skill: ${cmd}` });
557
+ const dynamicCmd = registry.getCommands().find((c) => c.name === cmd && (c.source === "skill" || c.source === "plugin"));
558
+ if (dynamicCmd) {
559
+ addMessage({ role: "system", content: `Invoking ${dynamicCmd.source}: ${cmd}` });
433
560
  return { handled: false };
434
561
  }
435
562
  addMessage({ role: "system", content: `Unknown command "/${cmd}". Type /help for help.` });
@@ -440,14 +567,22 @@ async function executeSlashCommand(cmd, args, session, addMessage, clearMessages
440
567
 
441
568
  // src/ui/hooks/useSlashCommands.ts
442
569
  var EXIT_DELAY_MS = 500;
443
- function useSlashCommands(session, addMessage, setMessages, exit, registry, pendingModelChangeRef, setPendingModelId) {
570
+ function useSlashCommands(session, addMessage, setMessages, exit, registry, pendingModelChangeRef, setPendingModelId, pluginCallbacks) {
444
571
  return (0, import_react3.useCallback)(
445
572
  async (input) => {
446
573
  const parts = input.slice(1).split(/\s+/);
447
574
  const cmd = parts[0]?.toLowerCase() ?? "";
448
575
  const args = parts.slice(1).join(" ");
449
576
  const clearMessages = () => setMessages([]);
450
- const result = await executeSlashCommand(cmd, args, session, addMessage, clearMessages, registry);
577
+ const result = await executeSlashCommand(
578
+ cmd,
579
+ args,
580
+ session,
581
+ addMessage,
582
+ clearMessages,
583
+ registry,
584
+ pluginCallbacks
585
+ );
451
586
  if (result.pendingModelId) {
452
587
  pendingModelChangeRef.current = result.pendingModelId;
453
588
  setPendingModelId(result.pendingModelId);
@@ -457,7 +592,16 @@ function useSlashCommands(session, addMessage, setMessages, exit, registry, pend
457
592
  }
458
593
  return result.handled;
459
594
  },
460
- [session, addMessage, setMessages, exit, registry, pendingModelChangeRef, setPendingModelId]
595
+ [
596
+ session,
597
+ addMessage,
598
+ setMessages,
599
+ exit,
600
+ registry,
601
+ pendingModelChangeRef,
602
+ setPendingModelId,
603
+ pluginCallbacks
604
+ ]
461
605
  );
462
606
  }
463
607
 
@@ -492,16 +636,60 @@ function parseFirstArgValue(argsJson) {
492
636
  }
493
637
 
494
638
  // src/utils/skill-prompt.ts
495
- function buildSkillPrompt(input, registry) {
639
+ var import_node_child_process = require("child_process");
640
+ function substituteVariables(content, args, context) {
641
+ const argParts = args ? args.split(/\s+/) : [];
642
+ let result = content;
643
+ result = result.replace(/\$ARGUMENTS\[(\d+)]/g, (_match, index) => {
644
+ return argParts[Number(index)] ?? "";
645
+ });
646
+ result = result.replace(/\$ARGUMENTS/g, args);
647
+ result = result.replace(/\$(\d)(?!\d|\w|\[)/g, (_match, digit) => {
648
+ return argParts[Number(digit)] ?? "";
649
+ });
650
+ result = result.replace(/\$\{CLAUDE_SESSION_ID}/g, context?.sessionId ?? "");
651
+ result = result.replace(/\$\{CLAUDE_SKILL_DIR}/g, context?.skillDir ?? "");
652
+ return result;
653
+ }
654
+ async function preprocessShellCommands(content) {
655
+ const shellPattern = /!`([^`]+)`/g;
656
+ if (!shellPattern.test(content)) {
657
+ return content;
658
+ }
659
+ shellPattern.lastIndex = 0;
660
+ let result = content;
661
+ let match;
662
+ const matches = [];
663
+ while ((match = shellPattern.exec(content)) !== null) {
664
+ matches.push({ full: match[0], command: match[1] });
665
+ }
666
+ for (const { full, command } of matches) {
667
+ let output = "";
668
+ try {
669
+ output = (0, import_node_child_process.execSync)(command, {
670
+ timeout: 5e3,
671
+ encoding: "utf-8",
672
+ stdio: ["pipe", "pipe", "pipe"]
673
+ }).trimEnd();
674
+ } catch {
675
+ output = "";
676
+ }
677
+ result = result.replace(full, output);
678
+ }
679
+ return result;
680
+ }
681
+ async function buildSkillPrompt(input, registry, context) {
496
682
  const parts = input.slice(1).split(/\s+/);
497
683
  const cmd = parts[0]?.toLowerCase() ?? "";
498
- const skillCmd = registry.getCommands().find((c) => c.name === cmd && c.source === "skill");
684
+ const skillCmd = registry.getCommands().find((c) => c.name === cmd && (c.source === "skill" || c.source === "plugin"));
499
685
  if (!skillCmd) return null;
500
686
  const args = parts.slice(1).join(" ").trim();
501
687
  const userInstruction = args || skillCmd.description;
502
688
  if (skillCmd.skillContent) {
689
+ let processed = await preprocessShellCommands(skillCmd.skillContent);
690
+ processed = substituteVariables(processed, args, context);
503
691
  return `<skill name="${cmd}">
504
- ${skillCmd.skillContent}
692
+ ${processed}
505
693
  </skill>
506
694
 
507
695
  Execute the "${cmd}" skill: ${userInstruction}`;
@@ -514,12 +702,12 @@ function syncContextState(session, setter) {
514
702
  const ctx = session.getContextState();
515
703
  setter({ percentage: ctx.usedPercentage, usedTokens: ctx.usedTokens, maxTokens: ctx.maxTokens });
516
704
  }
517
- async function runSessionPrompt(prompt, session, addMessage, clearStreamingText, setIsThinking, setContextState) {
705
+ async function runSessionPrompt(prompt, session, addMessage, clearStreamingText, setIsThinking, setContextState, rawInput) {
518
706
  setIsThinking(true);
519
707
  clearStreamingText();
520
708
  const historyBefore = session.getHistory().length;
521
709
  try {
522
- const response = await session.run(prompt);
710
+ const response = await session.run(prompt, rawInput);
523
711
  clearStreamingText();
524
712
  const history = session.getHistory();
525
713
  const toolLines = extractToolCalls(
@@ -527,7 +715,11 @@ async function runSessionPrompt(prompt, session, addMessage, clearStreamingText,
527
715
  historyBefore
528
716
  );
529
717
  if (toolLines.length > 0) {
530
- addMessage({ role: "tool", content: toolLines.join("\n"), toolName: `${toolLines.length} tools` });
718
+ addMessage({
719
+ role: "tool",
720
+ content: toolLines.join("\n"),
721
+ toolName: `${toolLines.length} tools`
722
+ });
531
723
  }
532
724
  addMessage({ role: "assistant", content: response || "(empty response)" });
533
725
  syncContextState(session, setContextState);
@@ -552,19 +744,45 @@ function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamin
552
744
  syncContextState(session, setContextState);
553
745
  return;
554
746
  }
555
- const prompt = buildSkillPrompt(input, registry);
747
+ const prompt = await buildSkillPrompt(input, registry);
556
748
  if (!prompt) return;
557
- return runSessionPrompt(prompt, session, addMessage, clearStreamingText, setIsThinking, setContextState);
749
+ return runSessionPrompt(
750
+ prompt,
751
+ session,
752
+ addMessage,
753
+ clearStreamingText,
754
+ setIsThinking,
755
+ setContextState,
756
+ input
757
+ );
558
758
  }
559
759
  addMessage({ role: "user", content: input });
560
- return runSessionPrompt(input, session, addMessage, clearStreamingText, setIsThinking, setContextState);
760
+ return runSessionPrompt(
761
+ input,
762
+ session,
763
+ addMessage,
764
+ clearStreamingText,
765
+ setIsThinking,
766
+ setContextState
767
+ );
561
768
  },
562
- [session, addMessage, handleSlashCommand, clearStreamingText, setIsThinking, setContextState, registry]
769
+ [
770
+ session,
771
+ addMessage,
772
+ handleSlashCommand,
773
+ clearStreamingText,
774
+ setIsThinking,
775
+ setContextState,
776
+ registry
777
+ ]
563
778
  );
564
779
  }
565
780
 
566
781
  // src/ui/hooks/useCommandRegistry.ts
567
782
  var import_react5 = require("react");
783
+ var import_node_os2 = require("os");
784
+ var import_node_path3 = require("path");
785
+ var import_agent_sdk2 = require("@robota-sdk/agent-sdk");
568
786
 
569
787
  // src/commands/command-registry.ts
570
788
  var CommandRegistry = class {
@@ -648,6 +866,23 @@ function createBuiltinCommands() {
648
866
  { name: "cost", description: "Show session info", source: "builtin" },
649
867
  { name: "context", description: "Context window info", source: "builtin" },
650
868
  { name: "permissions", description: "Permission rules", source: "builtin" },
869
+ {
870
+ name: "plugin",
871
+ description: "Manage plugins",
872
+ source: "builtin",
873
+ subcommands: [
874
+ { name: "install", description: "Install a plugin (name@marketplace)", source: "builtin" },
875
+ {
876
+ name: "uninstall",
877
+ description: "Uninstall a plugin (name@marketplace)",
878
+ source: "builtin"
879
+ },
880
+ { name: "enable", description: "Enable a plugin (name@marketplace)", source: "builtin" },
881
+ { name: "disable", description: "Disable a plugin (name@marketplace)", source: "builtin" },
882
+ { name: "marketplace", description: "Manage marketplace sources", source: "builtin" }
883
+ ]
884
+ },
885
+ { name: "reload-plugins", description: "Reload all plugin resources", source: "builtin" },
651
886
  { name: "reset", description: "Delete settings and exit", source: "builtin" },
652
887
  { name: "exit", description: "Exit CLI", source: "builtin" }
653
888
  ];
@@ -667,25 +902,50 @@ var BuiltinCommandSource = class {
667
902
  var import_node_fs2 = require("fs");
668
903
  var import_node_path2 = require("path");
669
904
  var import_node_os = require("os");
905
+ var BOOLEAN_KEYS = /* @__PURE__ */ new Set(["disable-model-invocation", "user-invocable"]);
906
+ var LIST_KEYS = /* @__PURE__ */ new Set(["allowed-tools"]);
907
+ function kebabToCamel(key) {
908
+ return key.replace(/-([a-z])/g, (_match, letter) => letter.toUpperCase());
909
+ }
670
910
  function parseFrontmatter(content) {
671
911
  const lines = content.split("\n");
672
912
  if (lines[0]?.trim() !== "---") return null;
673
- let name = "";
674
- let description = "";
913
+ const result = {};
675
914
  for (let i = 1; i < lines.length; i++) {
676
915
  const line = lines[i];
677
916
  if (line.trim() === "---") break;
678
- const nameMatch = line.match(/^name:\s*(.+)/);
679
- if (nameMatch) {
680
- name = nameMatch[1].trim();
681
- continue;
682
- }
683
- const descMatch = line.match(/^description:\s*(.+)/);
684
- if (descMatch) {
685
- description = descMatch[1].trim();
917
+ const match = line.match(/^([a-z][a-z0-9-]*):\s*(.+)/);
918
+ if (!match) continue;
919
+ const key = match[1];
920
+ const rawValue = match[2].trim();
921
+ const camelKey = kebabToCamel(key);
922
+ if (BOOLEAN_KEYS.has(key)) {
923
+ result[camelKey] = rawValue === "true";
924
+ } else if (LIST_KEYS.has(key)) {
925
+ result[camelKey] = rawValue.split(",").map((s) => s.trim());
926
+ } else {
927
+ result[camelKey] = rawValue;
686
928
  }
687
929
  }
688
- return name ? { name, description } : null;
930
+ return Object.keys(result).length > 0 ? result : null;
931
+ }
932
+ function buildCommand(frontmatter, content, fallbackName) {
933
+ const cmd = {
934
+ name: frontmatter?.name ?? fallbackName,
935
+ description: frontmatter?.description ?? `Skill: ${fallbackName}`,
936
+ source: "skill",
937
+ skillContent: content
938
+ };
939
+ if (frontmatter?.argumentHint !== void 0) cmd.argumentHint = frontmatter.argumentHint;
940
+ if (frontmatter?.disableModelInvocation !== void 0)
941
+ cmd.disableModelInvocation = frontmatter.disableModelInvocation;
942
+ if (frontmatter?.userInvocable !== void 0) cmd.userInvocable = frontmatter.userInvocable;
943
+ if (frontmatter?.allowedTools !== void 0) cmd.allowedTools = frontmatter.allowedTools;
944
+ if (frontmatter?.model !== void 0) cmd.model = frontmatter.model;
945
+ if (frontmatter?.effort !== void 0) cmd.effort = frontmatter.effort;
946
+ if (frontmatter?.context !== void 0) cmd.context = frontmatter.context;
947
+ if (frontmatter?.agent !== void 0) cmd.agent = frontmatter.agent;
948
+ return cmd;
689
949
  }
690
950
  function scanSkillsDir(skillsDir) {
691
951
  if (!(0, import_node_fs2.existsSync)(skillsDir)) return [];
@@ -697,48 +957,246 @@ function scanSkillsDir(skillsDir) {
697
957
  if (!(0, import_node_fs2.existsSync)(skillFile)) continue;
698
958
  const content = (0, import_node_fs2.readFileSync)(skillFile, "utf-8");
699
959
  const frontmatter = parseFrontmatter(content);
700
- commands.push({
701
- name: frontmatter?.name ?? entry.name,
702
- description: frontmatter?.description ?? `Skill: ${entry.name}`,
703
- source: "skill",
704
- skillContent: content
705
- });
960
+ commands.push(buildCommand(frontmatter, content, entry.name));
961
+ }
962
+ return commands;
963
+ }
964
+ function scanCommandsDir(commandsDir) {
965
+ if (!(0, import_node_fs2.existsSync)(commandsDir)) return [];
966
+ const commands = [];
967
+ const entries = (0, import_node_fs2.readdirSync)(commandsDir, { withFileTypes: true });
968
+ for (const entry of entries) {
969
+ if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
970
+ const filePath = (0, import_node_path2.join)(commandsDir, entry.name);
971
+ const content = (0, import_node_fs2.readFileSync)(filePath, "utf-8");
972
+ const frontmatter = parseFrontmatter(content);
973
+ const fallbackName = (0, import_node_path2.basename)(entry.name, ".md");
974
+ commands.push(buildCommand(frontmatter, content, fallbackName));
706
975
  }
707
976
  return commands;
708
977
  }
709
978
  var SkillCommandSource = class {
710
979
  name = "skill";
711
980
  cwd;
981
+ home;
712
982
  cachedCommands = null;
713
- constructor(cwd) {
983
+ constructor(cwd, home) {
714
984
  this.cwd = cwd;
985
+ this.home = home ?? (0, import_node_os.homedir)();
715
986
  }
716
987
  getCommands() {
717
988
  if (this.cachedCommands) return this.cachedCommands;
718
- const projectSkills = scanSkillsDir((0, import_node_path2.join)(this.cwd, ".agents", "skills"));
719
- const userSkills = scanSkillsDir((0, import_node_path2.join)((0, import_node_os.homedir)(), ".claude", "skills"));
720
- const seen = new Set(projectSkills.map((cmd) => cmd.name));
721
- const merged = [...projectSkills];
722
- for (const cmd of userSkills) {
723
- if (!seen.has(cmd.name)) {
724
- merged.push(cmd);
989
+ const sources = [
990
+ scanSkillsDir((0, import_node_path2.join)(this.cwd, ".claude", "skills")),
991
+ // 1. project .claude/skills
992
+ scanCommandsDir((0, import_node_path2.join)(this.cwd, ".claude", "commands")),
993
+ // 2. project .claude/commands (legacy)
994
+ scanSkillsDir((0, import_node_path2.join)(this.home, ".robota", "skills")),
995
+ // 3. user ~/.robota/skills
996
+ scanSkillsDir((0, import_node_path2.join)(this.cwd, ".agents", "skills"))
997
+ // 4. project .agents/skills
998
+ ];
999
+ const seen = /* @__PURE__ */ new Set();
1000
+ const merged = [];
1001
+ for (const commands of sources) {
1002
+ for (const cmd of commands) {
1003
+ if (!seen.has(cmd.name)) {
1004
+ seen.add(cmd.name);
1005
+ merged.push(cmd);
1006
+ }
725
1007
  }
726
1008
  }
727
1009
  this.cachedCommands = merged;
728
1010
  return this.cachedCommands;
729
1011
  }
1012
+ /** Get skills that models can invoke (excludes disableModelInvocation: true) */
1013
+ getModelInvocableSkills() {
1014
+ return this.getCommands().filter((cmd) => cmd.disableModelInvocation !== true);
1015
+ }
1016
+ /** Get skills that users can invoke (excludes userInvocable: false) */
1017
+ getUserInvocableSkills() {
1018
+ return this.getCommands().filter((cmd) => cmd.userInvocable !== false);
1019
+ }
1020
+ };
1021
+
1022
+ // src/commands/plugin-source.ts
1023
+ var PluginCommandSource = class {
1024
+ name = "plugin";
1025
+ plugins;
1026
+ constructor(plugins) {
1027
+ this.plugins = plugins;
1028
+ }
1029
+ getCommands() {
1030
+ const commands = [];
1031
+ for (const plugin of this.plugins) {
1032
+ for (const skill of plugin.skills) {
1033
+ const baseName = skill.name.includes("@") ? skill.name.split("@")[0] : skill.name;
1034
+ commands.push({
1035
+ name: baseName,
1036
+ description: `${skill.description} (${plugin.manifest.name})`,
1037
+ source: "plugin",
1038
+ skillContent: skill.skillContent,
1039
+ pluginDir: plugin.pluginDir
1040
+ });
1041
+ }
1042
+ for (const cmd of plugin.commands) {
1043
+ commands.push({
1044
+ name: cmd.name,
1045
+ description: cmd.description,
1046
+ source: "plugin",
1047
+ skillContent: cmd.skillContent,
1048
+ pluginDir: plugin.pluginDir
1049
+ });
1050
+ }
1051
+ }
1052
+ return commands;
1053
+ }
730
1054
  };
731
1055
 
732
1056
  // src/ui/hooks/useCommandRegistry.ts
1057
+ function buildPluginEnv(plugin) {
1058
+ const dataDir = (0, import_node_path3.join)((0, import_node_path3.dirname)((0, import_node_path3.dirname)(plugin.pluginDir)), "data", plugin.manifest.name);
1059
+ return {
1060
+ CLAUDE_PLUGIN_ROOT: plugin.pluginDir,
1061
+ CLAUDE_PLUGIN_PATH: plugin.pluginDir,
1062
+ CLAUDE_PLUGIN_DATA: dataDir
1063
+ };
1064
+ }
1065
+ function mergePluginHooks(plugins) {
1066
+ const merged = {};
1067
+ for (const plugin of plugins) {
1068
+ const hooksObj = plugin.hooks;
1069
+ if (!hooksObj) continue;
1070
+ const pluginEnv = buildPluginEnv(plugin);
1071
+ const innerHooks = hooksObj.hooks ?? hooksObj;
1072
+ for (const [event, groups] of Object.entries(innerHooks)) {
1073
+ if (!Array.isArray(groups)) continue;
1074
+ if (!merged[event]) merged[event] = [];
1075
+ const resolved = groups.map((group) => {
1076
+ const resolved2 = resolvePluginRoot(group, plugin.pluginDir);
1077
+ if (typeof resolved2 === "object" && resolved2 !== null) {
1078
+ resolved2.env = pluginEnv;
1079
+ }
1080
+ return resolved2;
1081
+ });
1082
+ merged[event].push(...resolved);
1083
+ }
1084
+ }
1085
+ return merged;
1086
+ }
1087
+ function resolvePluginRoot(group, pluginDir) {
1088
+ if (typeof group !== "object" || group === null) return group;
1089
+ const obj = group;
1090
+ if (Array.isArray(obj.hooks)) {
1091
+ return {
1092
+ ...obj,
1093
+ hooks: obj.hooks.map((h) => {
1094
+ if (typeof h !== "object" || h === null) return h;
1095
+ const hook = h;
1096
+ if (typeof hook.command === "string") {
1097
+ return {
1098
+ ...hook,
1099
+ command: hook.command.replace(/\$\{CLAUDE_PLUGIN_ROOT\}/g, pluginDir)
1100
+ };
1101
+ }
1102
+ return hook;
1103
+ })
1104
+ };
1105
+ }
1106
+ return group;
1107
+ }
733
1108
  function useCommandRegistry(cwd) {
734
- const registryRef = (0, import_react5.useRef)(null);
735
- if (registryRef.current === null) {
1109
+ const resultRef = (0, import_react5.useRef)(null);
1110
+ if (resultRef.current === null) {
736
1111
  const registry = new CommandRegistry();
737
1112
  registry.addSource(new BuiltinCommandSource());
738
1113
  registry.addSource(new SkillCommandSource(cwd));
739
- registryRef.current = registry;
1114
+ let pluginHooks = {};
1115
+ const pluginsDir = (0, import_node_path3.join)((0, import_node_os2.homedir)(), ".robota", "plugins");
1116
+ const loader = new import_agent_sdk2.BundlePluginLoader(pluginsDir);
1117
+ try {
1118
+ const plugins = loader.loadPluginsSync();
1119
+ if (plugins.length > 0) {
1120
+ registry.addSource(new PluginCommandSource(plugins));
1121
+ pluginHooks = mergePluginHooks(plugins);
1122
+ }
1123
+ } catch {
1124
+ }
1125
+ resultRef.current = { registry, pluginHooks };
740
1126
  }
741
- return registryRef.current;
1127
+ return resultRef.current;
1128
+ }
1129
+
1130
+ // src/ui/hooks/usePluginCallbacks.ts
1131
+ var import_react6 = require("react");
1132
+ var import_node_os3 = require("os");
1133
+ var import_node_path4 = require("path");
1134
+ var import_agent_sdk3 = require("@robota-sdk/agent-sdk");
1135
+ function usePluginCallbacks(cwd) {
1136
+ return (0, import_react6.useMemo)(() => {
1137
+ const home = (0, import_node_os3.homedir)();
1138
+ const pluginsDir = (0, import_node_path4.join)(home, ".robota", "plugins");
1139
+ const userSettingsPath = (0, import_node_path4.join)(home, ".robota", "settings.json");
1140
+ const settingsStore = new import_agent_sdk3.PluginSettingsStore(userSettingsPath);
1141
+ const marketplace = new import_agent_sdk3.MarketplaceClient({ pluginsDir });
1142
+ const installer = new import_agent_sdk3.BundlePluginInstaller({
1143
+ pluginsDir,
1144
+ settingsStore,
1145
+ marketplaceClient: marketplace
1146
+ });
1147
+ const loader = new import_agent_sdk3.BundlePluginLoader(pluginsDir);
1148
+ return {
1149
+ listInstalled: async () => {
1150
+ const plugins = await loader.loadAll();
1151
+ return plugins.map((p) => ({
1152
+ name: p.manifest.name,
1153
+ description: p.manifest.description,
1154
+ enabled: true
1155
+ }));
1156
+ },
1157
+ install: async (pluginId) => {
1158
+ const [name, marketplaceName] = pluginId.split("@");
1159
+ if (!name || !marketplaceName) {
1160
+ throw new Error("Plugin ID must be in format: name@marketplace");
1161
+ }
1162
+ await installer.install(name, marketplaceName);
1163
+ },
1164
+ uninstall: async (pluginId) => {
1165
+ await installer.uninstall(pluginId);
1166
+ },
1167
+ enable: async (pluginId) => {
1168
+ await installer.enable(pluginId);
1169
+ },
1170
+ disable: async (pluginId) => {
1171
+ await installer.disable(pluginId);
1172
+ },
1173
+ marketplaceAdd: async (source) => {
1174
+ if (source.includes("/") && !source.includes(":")) {
1175
+ return marketplace.addMarketplace({ type: "github", repo: source });
1176
+ } else {
1177
+ return marketplace.addMarketplace({ type: "git", url: source });
1178
+ }
1179
+ },
1180
+ marketplaceRemove: async (name) => {
1181
+ const installedFromMarketplace = installer.getPluginsByMarketplace(name);
1182
+ for (const record of installedFromMarketplace) {
1183
+ await installer.uninstall(`${record.pluginName}@${record.marketplace}`);
1184
+ }
1185
+ marketplace.removeMarketplace(name);
1186
+ },
1187
+ marketplaceUpdate: async (name) => {
1188
+ marketplace.updateMarketplace(name);
1189
+ },
1190
+ marketplaceList: async () => {
1191
+ return marketplace.listMarketplaces().map((m) => ({
1192
+ name: m.name,
1193
+ type: m.source.type
1194
+ }));
1195
+ },
1196
+ reloadPlugins: async () => {
1197
+ }
1198
+ };
1199
+ }, [cwd]);
742
1200
  }
743
1201
 
744
1202
  // src/ui/MessageList.tsx
@@ -861,11 +1319,11 @@ function StatusBar({
861
1319
  }
862
1320
 
863
1321
  // src/ui/InputArea.tsx
864
- var import_react8 = __toESM(require("react"), 1);
1322
+ var import_react9 = __toESM(require("react"), 1);
865
1323
  var import_ink6 = require("ink");
866
1324
 
867
1325
  // src/ui/CjkTextInput.tsx
868
- var import_react6 = require("react");
1326
+ var import_react7 = require("react");
869
1327
  var import_ink3 = require("ink");
870
1328
  var import_chalk = __toESM(require("chalk"), 1);
871
1329
  var import_jsx_runtime3 = require("react/jsx-runtime");
@@ -885,9 +1343,9 @@ function CjkTextInput({
885
1343
  focus = true,
886
1344
  showCursor = true
887
1345
  }) {
888
- const valueRef = (0, import_react6.useRef)(value);
889
- const cursorRef = (0, import_react6.useRef)(value.length);
890
- const [, forceRender] = (0, import_react6.useState)(0);
1346
+ const valueRef = (0, import_react7.useRef)(value);
1347
+ const cursorRef = (0, import_react7.useRef)(value.length);
1348
+ const [, forceRender] = (0, import_react7.useState)(0);
891
1349
  if (value !== valueRef.current) {
892
1350
  valueRef.current = value;
893
1351
  if (cursorRef.current > value.length) {
@@ -964,15 +1422,15 @@ function renderWithCursor(value, cursorOffset, placeholder, showCursor) {
964
1422
  }
965
1423
 
966
1424
  // src/ui/WaveText.tsx
967
- var import_react7 = require("react");
1425
+ var import_react8 = require("react");
968
1426
  var import_ink4 = require("ink");
969
1427
  var import_jsx_runtime4 = require("react/jsx-runtime");
970
1428
  var WAVE_COLORS = ["#666666", "#888888", "#aaaaaa", "#888888"];
971
1429
  var INTERVAL_MS = 400;
972
1430
  var CHARS_PER_GROUP = 4;
973
1431
  function WaveText({ text }) {
974
- const [tick, setTick] = (0, import_react7.useState)(0);
975
- (0, import_react7.useEffect)(() => {
1432
+ const [tick, setTick] = (0, import_react8.useState)(0);
1433
+ (0, import_react8.useEffect)(() => {
976
1434
  const timer = setInterval(() => {
977
1435
  setTick((prev) => prev + 1);
978
1436
  }, INTERVAL_MS);
@@ -1038,16 +1496,16 @@ function parseSlashInput(value) {
1038
1496
  return { isSlash: true, parentCommand: parent, filter: rest };
1039
1497
  }
1040
1498
  function useAutocomplete(value, registry) {
1041
- const [selectedIndex, setSelectedIndex] = (0, import_react8.useState)(0);
1042
- const [dismissed, setDismissed] = (0, import_react8.useState)(false);
1043
- const prevValueRef = import_react8.default.useRef(value);
1499
+ const [selectedIndex, setSelectedIndex] = (0, import_react9.useState)(0);
1500
+ const [dismissed, setDismissed] = (0, import_react9.useState)(false);
1501
+ const prevValueRef = import_react9.default.useRef(value);
1044
1502
  if (prevValueRef.current !== value) {
1045
1503
  prevValueRef.current = value;
1046
1504
  if (dismissed) setDismissed(false);
1047
1505
  }
1048
1506
  const parsed = parseSlashInput(value);
1049
1507
  const isSubcommandMode = parsed.isSlash && parsed.parentCommand.length > 0;
1050
- const filteredCommands = (0, import_react8.useMemo)(() => {
1508
+ const filteredCommands = (0, import_react9.useMemo)(() => {
1051
1509
  if (!registry || !parsed.isSlash || dismissed) return [];
1052
1510
  if (isSubcommandMode) {
1053
1511
  const subs = registry.getSubcommands(parsed.parentCommand);
@@ -1081,7 +1539,7 @@ function useAutocomplete(value, registry) {
1081
1539
  };
1082
1540
  }
1083
1541
  function InputArea({ onSubmit, isDisabled, registry }) {
1084
- const [value, setValue] = (0, import_react8.useState)("");
1542
+ const [value, setValue] = (0, import_react9.useState)("");
1085
1543
  const {
1086
1544
  showPopup,
1087
1545
  filteredCommands,
@@ -1090,7 +1548,7 @@ function InputArea({ onSubmit, isDisabled, registry }) {
1090
1548
  isSubcommandMode,
1091
1549
  setShowPopup
1092
1550
  } = useAutocomplete(value, registry);
1093
- const handleSubmit = (0, import_react8.useCallback)(
1551
+ const handleSubmit = (0, import_react9.useCallback)(
1094
1552
  (text) => {
1095
1553
  const trimmed = text.trim();
1096
1554
  if (trimmed.length === 0) return;
@@ -1103,7 +1561,7 @@ function InputArea({ onSubmit, isDisabled, registry }) {
1103
1561
  },
1104
1562
  [showPopup, filteredCommands, selectedIndex, onSubmit]
1105
1563
  );
1106
- const selectCommand = (0, import_react8.useCallback)(
1564
+ const selectCommand = (0, import_react9.useCallback)(
1107
1565
  (cmd) => {
1108
1566
  const parsed = parseSlashInput(value);
1109
1567
  if (parsed.parentCommand) {
@@ -1164,7 +1622,7 @@ function InputArea({ onSubmit, isDisabled, registry }) {
1164
1622
  }
1165
1623
 
1166
1624
  // src/ui/ConfirmPrompt.tsx
1167
- var import_react9 = require("react");
1625
+ var import_react10 = require("react");
1168
1626
  var import_ink7 = require("ink");
1169
1627
  var import_jsx_runtime7 = require("react/jsx-runtime");
1170
1628
  function ConfirmPrompt({
@@ -1172,9 +1630,9 @@ function ConfirmPrompt({
1172
1630
  options = ["Yes", "No"],
1173
1631
  onSelect
1174
1632
  }) {
1175
- const [selected, setSelected] = (0, import_react9.useState)(0);
1176
- const resolvedRef = (0, import_react9.useRef)(false);
1177
- const doSelect = (0, import_react9.useCallback)(
1633
+ const [selected, setSelected] = (0, import_react10.useState)(0);
1634
+ const resolvedRef = (0, import_react10.useRef)(false);
1635
+ const doSelect = (0, import_react10.useCallback)(
1178
1636
  (index) => {
1179
1637
  if (resolvedRef.current) return;
1180
1638
  resolvedRef.current = true;
@@ -1207,7 +1665,7 @@ function ConfirmPrompt({
1207
1665
  }
1208
1666
 
1209
1667
  // src/ui/PermissionPrompt.tsx
1210
- var import_react10 = __toESM(require("react"), 1);
1668
+ var import_react11 = __toESM(require("react"), 1);
1211
1669
  var import_ink8 = require("ink");
1212
1670
  var import_jsx_runtime8 = require("react/jsx-runtime");
1213
1671
  var OPTIONS = ["Allow", "Allow always (this session)", "Deny"];
@@ -1217,15 +1675,15 @@ function formatArgs(args) {
1217
1675
  return entries.map(([k, v]) => `${k}: ${typeof v === "string" ? v : JSON.stringify(v)}`).join(", ");
1218
1676
  }
1219
1677
  function PermissionPrompt({ request }) {
1220
- const [selected, setSelected] = import_react10.default.useState(0);
1221
- const resolvedRef = import_react10.default.useRef(false);
1222
- const prevRequestRef = import_react10.default.useRef(request);
1678
+ const [selected, setSelected] = import_react11.default.useState(0);
1679
+ const resolvedRef = import_react11.default.useRef(false);
1680
+ const prevRequestRef = import_react11.default.useRef(request);
1223
1681
  if (prevRequestRef.current !== request) {
1224
1682
  prevRequestRef.current = request;
1225
1683
  resolvedRef.current = false;
1226
1684
  setSelected(0);
1227
1685
  }
1228
- const doResolve = import_react10.default.useCallback(
1686
+ const doResolve = import_react11.default.useCallback(
1229
1687
  (index) => {
1230
1688
  if (resolvedRef.current) return;
1231
1689
  resolvedRef.current = true;
@@ -1304,21 +1762,56 @@ function StreamingIndicator({ text, activeTools }) {
1304
1762
  // src/ui/App.tsx
1305
1763
  var import_jsx_runtime10 = require("react/jsx-runtime");
1306
1764
  var EXIT_DELAY_MS2 = 500;
1765
+ function mergeHooksIntoConfig(configHooks, pluginHooks) {
1766
+ const pluginKeys = Object.keys(pluginHooks);
1767
+ if (pluginKeys.length === 0) return configHooks;
1768
+ const merged = {};
1769
+ for (const [event, groups] of Object.entries(pluginHooks)) {
1770
+ merged[event] = [...groups];
1771
+ }
1772
+ if (configHooks) {
1773
+ for (const [event, groups] of Object.entries(configHooks)) {
1774
+ if (!Array.isArray(groups)) continue;
1775
+ if (!merged[event]) merged[event] = [];
1776
+ merged[event].push(...groups);
1777
+ }
1778
+ }
1779
+ return merged;
1780
+ }
1307
1781
  function App(props) {
1308
1782
  const { exit } = (0, import_ink10.useApp)();
1309
- const { session, permissionRequest, streamingText, clearStreamingText, activeTools } = useSession(props);
1783
+ const { registry, pluginHooks } = useCommandRegistry(props.cwd ?? process.cwd());
1784
+ const configWithPluginHooks = {
1785
+ ...props.config,
1786
+ hooks: mergeHooksIntoConfig(
1787
+ props.config.hooks,
1788
+ pluginHooks
1789
+ )
1790
+ };
1791
+ const { session, permissionRequest, streamingText, clearStreamingText, activeTools } = useSession(
1792
+ { ...props, config: configWithPluginHooks }
1793
+ );
1310
1794
  const { messages, setMessages, addMessage } = useMessages();
1311
- const [isThinking, setIsThinking] = (0, import_react11.useState)(false);
1795
+ const [isThinking, setIsThinking] = (0, import_react12.useState)(false);
1312
1796
  const initialCtx = session.getContextState();
1313
- const [contextState, setContextState] = (0, import_react11.useState)({
1797
+ const [contextState, setContextState] = (0, import_react12.useState)({
1314
1798
  percentage: initialCtx.usedPercentage,
1315
1799
  usedTokens: initialCtx.usedTokens,
1316
1800
  maxTokens: initialCtx.maxTokens
1317
1801
  });
1318
- const registry = useCommandRegistry(props.cwd ?? process.cwd());
1319
- const pendingModelChangeRef = (0, import_react11.useRef)(null);
1320
- const [pendingModelId, setPendingModelId] = (0, import_react11.useState)(null);
1321
- const handleSlashCommand = useSlashCommands(session, addMessage, setMessages, exit, registry, pendingModelChangeRef, setPendingModelId);
1802
+ const pendingModelChangeRef = (0, import_react12.useRef)(null);
1803
+ const [pendingModelId, setPendingModelId] = (0, import_react12.useState)(null);
1804
+ const pluginCallbacks = usePluginCallbacks(props.cwd ?? process.cwd());
1805
+ const handleSlashCommand = useSlashCommands(
1806
+ session,
1807
+ addMessage,
1808
+ setMessages,
1809
+ exit,
1810
+ registry,
1811
+ pendingModelChangeRef,
1812
+ setPendingModelId,
1813
+ pluginCallbacks
1814
+ );
1322
1815
  const handleSubmit = useSubmitHandler(
1323
1816
  session,
1324
1817
  addMessage,
@@ -1365,10 +1858,16 @@ function App(props) {
1365
1858
  try {
1366
1859
  const settingsPath = getUserSettingsPath();
1367
1860
  updateModelInSettings(settingsPath, pendingModelId);
1368
- addMessage({ role: "system", content: `Model changed to ${(0, import_agent_core3.getModelName)(pendingModelId)}. Restarting...` });
1861
+ addMessage({
1862
+ role: "system",
1863
+ content: `Model changed to ${(0, import_agent_core3.getModelName)(pendingModelId)}. Restarting...`
1864
+ });
1369
1865
  setTimeout(() => exit(), EXIT_DELAY_MS2);
1370
1866
  } catch (err) {
1371
- addMessage({ role: "system", content: `Failed: ${err instanceof Error ? err.message : String(err)}` });
1867
+ addMessage({
1868
+ role: "system",
1869
+ content: `Failed: ${err instanceof Error ? err.message : String(err)}`
1870
+ });
1372
1871
  }
1373
1872
  } else {
1374
1873
  addMessage({ role: "system", content: "Model change cancelled." });
@@ -1427,23 +1926,24 @@ function renderApp(options) {
1427
1926
 
1428
1927
  // src/cli.ts
1429
1928
  var import_meta = {};
1430
- function hasValidSettingsFile(filePath) {
1431
- if (!(0, import_node_fs3.existsSync)(filePath)) return false;
1929
+ function checkSettingsFile(filePath) {
1930
+ if (!(0, import_node_fs3.existsSync)(filePath)) return "missing";
1432
1931
  try {
1433
1932
  const raw = (0, import_node_fs3.readFileSync)(filePath, "utf8").trim();
1434
- if (raw.length === 0) return false;
1933
+ if (raw.length === 0) return "incomplete";
1435
1934
  const parsed = JSON.parse(raw);
1436
1935
  const provider = parsed.provider;
1437
- return !!provider?.apiKey;
1936
+ if (!provider?.apiKey) return "incomplete";
1937
+ return "valid";
1438
1938
  } catch {
1439
- return false;
1939
+ return "corrupt";
1440
1940
  }
1441
1941
  }
1442
1942
  function readVersion() {
1443
1943
  try {
1444
1944
  const thisFile = (0, import_node_url.fileURLToPath)(import_meta.url);
1445
- const dir = (0, import_node_path3.dirname)(thisFile);
1446
- const candidates = [(0, import_node_path3.join)(dir, "..", "..", "package.json"), (0, import_node_path3.join)(dir, "..", "package.json")];
1945
+ const dir = (0, import_node_path5.dirname)(thisFile);
1946
+ const candidates = [(0, import_node_path5.join)(dir, "..", "..", "package.json"), (0, import_node_path5.join)(dir, "..", "package.json")];
1447
1947
  for (const pkgPath of candidates) {
1448
1948
  try {
1449
1949
  const raw = (0, import_node_fs3.readFileSync)(pkgPath, "utf-8");
@@ -1496,14 +1996,36 @@ function promptInput(label, masked = false) {
1496
1996
  }
1497
1997
  async function ensureConfig(cwd) {
1498
1998
  const userPath = getUserSettingsPath();
1499
- const projectPath = (0, import_node_path3.join)(cwd, ".robota", "settings.json");
1500
- const localPath = (0, import_node_path3.join)(cwd, ".robota", "settings.local.json");
1501
- if (hasValidSettingsFile(userPath) || hasValidSettingsFile(projectPath) || hasValidSettingsFile(localPath)) {
1999
+ const projectPath = (0, import_node_path5.join)(cwd, ".robota", "settings.json");
2000
+ const localPath = (0, import_node_path5.join)(cwd, ".robota", "settings.local.json");
2001
+ const paths = [userPath, projectPath, localPath];
2002
+ const checks = paths.map((p) => ({ path: p, status: checkSettingsFile(p) }));
2003
+ if (checks.some((c) => c.status === "valid")) {
1502
2004
  return;
1503
2005
  }
2006
+ const corrupt = checks.filter((c) => c.status === "corrupt");
2007
+ const incomplete = checks.filter((c) => c.status === "incomplete");
1504
2008
  process.stdout.write("\n");
1505
- process.stdout.write(" Welcome to Robota CLI!\n");
1506
- process.stdout.write(" No configuration found. Let's set up.\n");
2009
+ if (corrupt.length > 0) {
2010
+ for (const c of corrupt) {
2011
+ process.stderr.write(` ERROR: Settings file is corrupt (invalid JSON): ${c.path}
2012
+ `);
2013
+ }
2014
+ process.stdout.write("\n");
2015
+ }
2016
+ if (incomplete.length > 0) {
2017
+ for (const c of incomplete) {
2018
+ process.stderr.write(` WARNING: Settings file is missing provider.apiKey: ${c.path}
2019
+ `);
2020
+ }
2021
+ process.stdout.write("\n");
2022
+ }
2023
+ if (corrupt.length === 0 && incomplete.length === 0) {
2024
+ process.stdout.write(" Welcome to Robota CLI!\n");
2025
+ process.stdout.write(" No configuration found. Let's set up.\n");
2026
+ } else {
2027
+ process.stdout.write(" Reconfiguring...\n");
2028
+ }
1507
2029
  process.stdout.write("\n");
1508
2030
  const apiKey = await promptInput(" Anthropic API key: ", true);
1509
2031
  if (!apiKey) {
@@ -1511,7 +2033,7 @@ async function ensureConfig(cwd) {
1511
2033
  process.exit(1);
1512
2034
  }
1513
2035
  const language = await promptInput(" Response language (ko/en/ja/zh, default: en): ");
1514
- const settingsDir = (0, import_node_path3.dirname)(userPath);
2036
+ const settingsDir = (0, import_node_path5.dirname)(userPath);
1515
2037
  (0, import_node_fs3.mkdirSync)(settingsDir, { recursive: true });
1516
2038
  const settings = {
1517
2039
  provider: {
@@ -1552,9 +2074,9 @@ async function startCli() {
1552
2074
  const cwd = process.cwd();
1553
2075
  await ensureConfig(cwd);
1554
2076
  const [config, context, projectInfo] = await Promise.all([
1555
- (0, import_agent_sdk2.loadConfig)(cwd),
1556
- (0, import_agent_sdk2.loadContext)(cwd),
1557
- (0, import_agent_sdk2.detectProject)(cwd)
2077
+ (0, import_agent_sdk4.loadConfig)(cwd),
2078
+ (0, import_agent_sdk4.loadContext)(cwd),
2079
+ (0, import_agent_sdk4.detectProject)(cwd)
1558
2080
  ]);
1559
2081
  if (args.model !== void 0) {
1560
2082
  config.provider.model = args.model;
@@ -1562,7 +2084,7 @@ async function startCli() {
1562
2084
  if (args.language !== void 0) {
1563
2085
  config.language = args.language;
1564
2086
  }
1565
- const sessionStore = new import_agent_sdk2.SessionStore();
2087
+ const sessionStore = new import_agent_sdk4.SessionStore();
1566
2088
  if (args.printMode) {
1567
2089
  const prompt = args.positional.join(" ").trim();
1568
2090
  if (prompt.length === 0) {
@@ -1570,15 +2092,15 @@ async function startCli() {
1570
2092
  process.exit(1);
1571
2093
  }
1572
2094
  const terminal = new PrintTerminal();
1573
- const paths = (0, import_agent_sdk2.projectPaths)(cwd);
1574
- const session = (0, import_agent_sdk2.createSession)({
2095
+ const paths = (0, import_agent_sdk4.projectPaths)(cwd);
2096
+ const session = (0, import_agent_sdk4.createSession)({
1575
2097
  config,
1576
2098
  context,
1577
2099
  terminal,
1578
- sessionLogger: new import_agent_sdk2.FileSessionLogger(paths.logs),
2100
+ sessionLogger: new import_agent_sdk4.FileSessionLogger(paths.logs),
1579
2101
  projectInfo,
1580
2102
  permissionMode: args.permissionMode,
1581
- promptForApproval: import_agent_sdk3.promptForApproval
2103
+ promptForApproval: import_agent_sdk5.promptForApproval
1582
2104
  });
1583
2105
  const response = await session.run(prompt);
1584
2106
  process.stdout.write(response + "\n");