@robota-sdk/agent-cli 3.0.0-beta.59 → 3.0.0-beta.60

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.
@@ -3,11 +3,13 @@ import {
3
3
  createProviderFromSettings,
4
4
  findProviderDefinition,
5
5
  formatSupportedProviderTypes,
6
+ getProviderSettingsPaths,
6
7
  hasUsableSecretReference,
7
8
  isSubagentWorkerChildMessage,
8
9
  readMergedProviderSettings,
10
+ readMergedProviderSettingsFromPaths,
9
11
  readProviderSettings
10
- } from "./chunk-4ZX5RLIX.js";
12
+ } from "./chunk-6XQKLNRF.js";
11
13
 
12
14
  // src/background/managed-shell-process-runner.ts
13
15
  import { spawn } from "child_process";
@@ -191,28 +193,55 @@ var WORKTREE_DIR = ".robota/worktrees";
191
193
  var BRANCH_PREFIX = "robota";
192
194
  var GIT_ENCODING = "utf8";
193
195
  var SHORT_ID_LENGTH = 8;
196
+ var DEFAULT_MAX_CREATE_ATTEMPTS = 5;
197
+ var COLLISION_ERROR_PATTERN = /already exists|is already checked out|missing but already registered/i;
194
198
  function createGitWorktreeIsolationAdapter(options) {
195
199
  return new GitWorktreeIsolationAdapter(options);
196
200
  }
197
201
  var GitWorktreeIsolationAdapter = class {
198
202
  worktreeDir;
199
203
  branchPrefix;
204
+ idFactory;
205
+ maxCreateAttempts;
200
206
  constructor(options = {}) {
201
207
  this.worktreeDir = options.worktreeDir ?? WORKTREE_DIR;
202
208
  this.branchPrefix = options.branchPrefix ?? BRANCH_PREFIX;
209
+ this.idFactory = options.idFactory ?? createShortId;
210
+ this.maxCreateAttempts = options.maxCreateAttempts ?? DEFAULT_MAX_CREATE_ATTEMPTS;
203
211
  }
204
212
  prepare(request) {
205
- const repoRoot = runGit(request.cwd, ["rev-parse", "--show-toplevel"]).trim();
206
- const shortId = randomUUID().slice(0, SHORT_ID_LENGTH);
207
- const branchName = `${this.branchPrefix}/${request.jobId}-${shortId}`;
213
+ if (this.maxCreateAttempts < 1) {
214
+ throw new BackgroundTaskError2("runner", "Git worktree creation attempts must be at least 1");
215
+ }
216
+ const repoRoot = resolveRepoRoot(request.cwd);
217
+ const baseRevision = runGit(repoRoot, ["rev-parse", "HEAD"]).trim();
218
+ const parentStatus = runGit(repoRoot, ["status", "--porcelain"]).trimEnd();
208
219
  const worktreeRoot = join(repoRoot, this.worktreeDir);
209
- const worktreePath = join(worktreeRoot, `${request.jobId}-${shortId}`);
210
220
  mkdirSync(worktreeRoot, { recursive: true });
211
- runGit(repoRoot, ["worktree", "add", "-b", branchName, worktreePath, "HEAD"]);
212
- return { repoRoot, worktreePath, branchName };
221
+ let lastError;
222
+ for (let attempt = 0; attempt < this.maxCreateAttempts; attempt += 1) {
223
+ const shortId = normalizeShortId(this.idFactory());
224
+ const jobId = sanitizePathSegment(request.jobId);
225
+ const branchName = `${this.branchPrefix}/${jobId}-${shortId}`;
226
+ const worktreePath = join(worktreeRoot, `${jobId}-${shortId}`);
227
+ try {
228
+ runGit(repoRoot, ["worktree", "add", "-b", branchName, worktreePath, "HEAD"]);
229
+ return { repoRoot, worktreePath, branchName, baseRevision, parentStatus };
230
+ } catch (error) {
231
+ lastError = toError(error);
232
+ if (!isCollisionError(lastError)) throw lastError;
233
+ }
234
+ }
235
+ throw new BackgroundTaskError2(
236
+ "runner",
237
+ `Unable to create Git worktree after ${this.maxCreateAttempts} attempts due to branch or path collisions. Last error: ${lastError?.message ?? "unknown error"}`
238
+ );
213
239
  }
214
240
  isClean(worktree) {
215
- return runGit(worktree.worktreePath, ["status", "--porcelain"]).trim().length === 0;
241
+ return this.getStatus(worktree).trim().length === 0;
242
+ }
243
+ getStatus(worktree) {
244
+ return runGit(worktree.worktreePath, ["status", "--porcelain"]);
216
245
  }
217
246
  remove(worktree) {
218
247
  runGit(worktree.repoRoot, ["worktree", "remove", "--force", worktree.worktreePath]);
@@ -224,13 +253,51 @@ function runGit(cwd, args) {
224
253
  return execFileSync("git", args, {
225
254
  cwd,
226
255
  encoding: GIT_ENCODING,
227
- stdio: ["ignore", "pipe", "pipe"]
256
+ stdio: ["ignore", "pipe", "pipe"],
257
+ env: createGitEnvironment()
228
258
  });
229
259
  } catch (error) {
230
260
  const message = error instanceof Error ? error.message : String(error);
231
261
  throw new BackgroundTaskError2("runner", `git ${args.join(" ")} failed: ${message}`);
232
262
  }
233
263
  }
264
+ function createGitEnvironment() {
265
+ const env = { ...process.env };
266
+ for (const key of Object.keys(env)) {
267
+ if (key.startsWith("GIT_")) {
268
+ delete env[key];
269
+ }
270
+ }
271
+ return env;
272
+ }
273
+ function resolveRepoRoot(cwd) {
274
+ try {
275
+ return runGit(cwd, ["rev-parse", "--show-toplevel"]).trim();
276
+ } catch (error) {
277
+ const message = error instanceof Error ? error.message : String(error);
278
+ throw new BackgroundTaskError2(
279
+ "runner",
280
+ `Worktree isolation requires a Git repository. Run from a Git worktree or request isolation "none". Details: ${message}`
281
+ );
282
+ }
283
+ }
284
+ function createShortId() {
285
+ return randomUUID().slice(0, SHORT_ID_LENGTH);
286
+ }
287
+ function normalizeShortId(value) {
288
+ const sanitized = sanitizePathSegment(value).slice(0, SHORT_ID_LENGTH);
289
+ return sanitized.length > 0 ? sanitized : createShortId();
290
+ }
291
+ function sanitizePathSegment(value) {
292
+ const sanitized = value.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
293
+ return sanitized.length > 0 ? sanitized : "agent";
294
+ }
295
+ function toError(error) {
296
+ return error instanceof Error ? error : new Error(String(error));
297
+ }
298
+ function isCollisionError(error) {
299
+ return COLLISION_ERROR_PATTERN.test(error.message);
300
+ }
234
301
 
235
302
  // src/subagents/child-process-subagent-runner.ts
236
303
  import { fork } from "child_process";
@@ -594,6 +661,23 @@ function readTranscriptLog(jobId, transcriptPath, cursor) {
594
661
  import { readFileSync as readFileSync6 } from "fs";
595
662
  import { join as join9, dirname as dirname5 } from "path";
596
663
  import { fileURLToPath } from "url";
664
+ import { createAgentCommandModule } from "@robota-sdk/agent-command-agent";
665
+ import { createBackgroundCommandModule } from "@robota-sdk/agent-command-background";
666
+ import { createProviderCommandModule } from "@robota-sdk/agent-command-provider";
667
+ import { createCompactCommandModule } from "@robota-sdk/agent-command-compact";
668
+ import { createContextCommandModule } from "@robota-sdk/agent-command-context";
669
+ import { createExitCommandModule } from "@robota-sdk/agent-command-exit";
670
+ import { createHelpCommandModule } from "@robota-sdk/agent-command-help";
671
+ import { createLanguageCommandModule } from "@robota-sdk/agent-command-language";
672
+ import { createMemoryCommandModule } from "@robota-sdk/agent-command-memory";
673
+ import { createModeCommandModule } from "@robota-sdk/agent-command-mode";
674
+ import { createModelCommandModule } from "@robota-sdk/agent-command-model";
675
+ import { createPermissionsCommandModule } from "@robota-sdk/agent-command-permissions";
676
+ import { createPluginCommandModule } from "@robota-sdk/agent-command-plugin";
677
+ import { createResetCommandModule } from "@robota-sdk/agent-command-reset";
678
+ import { createRewindCommandModule } from "@robota-sdk/agent-command-rewind";
679
+ import { createStatusLineCommandModule } from "@robota-sdk/agent-command-statusline";
680
+ import { createSessionCommandModule } from "@robota-sdk/agent-command-session";
597
681
  import { InteractiveSession as InteractiveSession2, projectPaths } from "@robota-sdk/agent-sdk";
598
682
  import { SessionStore } from "@robota-sdk/agent-sessions";
599
683
 
@@ -710,28 +794,6 @@ function writeSettings(path, settings) {
710
794
  mkdirSync2(dirname2(path), { recursive: true });
711
795
  writeFileSync(path, JSON.stringify(settings, null, 2) + "\n", "utf8");
712
796
  }
713
- function updateModelInSettings(settingsPath, modelId) {
714
- const settings = readSettings(settingsPath);
715
- const currentProvider = settings.currentProvider;
716
- const providers = settings.providers;
717
- if (typeof currentProvider === "string" && isSettingsData(providers)) {
718
- const providerMap = providers;
719
- providerMap[currentProvider] = {
720
- ...isSettingsData(providerMap[currentProvider]) ? providerMap[currentProvider] : {},
721
- model: modelId
722
- };
723
- settings.providers = providerMap;
724
- } else {
725
- settings.provider = {
726
- ...isSettingsData(settings.provider) ? settings.provider : {},
727
- model: modelId
728
- };
729
- }
730
- writeSettings(settingsPath, settings);
731
- }
732
- function isSettingsData(value) {
733
- return value !== null && typeof value === "object" && !Array.isArray(value) && !(value instanceof Date);
734
- }
735
797
  function deleteSettings(path) {
736
798
  if (existsSync2(path)) {
737
799
  unlinkSync(path);
@@ -742,31 +804,21 @@ function deleteSettings(path) {
742
804
 
743
805
  // src/utils/provider-setup.ts
744
806
  import { join as join4 } from "path";
745
- import { homedir } from "os";
746
807
 
747
808
  // src/utils/settings-check.ts
748
809
  import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
749
- function checkSettingsFile(filePath, providerDefinitions = []) {
750
- if (!existsSync3(filePath)) return "missing";
751
- try {
752
- const raw = readFileSync3(filePath, "utf8").trim();
753
- if (raw.length === 0) return "incomplete";
754
- const parsed = JSON.parse(raw);
755
- if (!hasUsableProviderConfig(parsed, providerDefinitions)) return "incomplete";
756
- return "valid";
757
- } catch {
758
- return "corrupt";
759
- }
810
+ function checkSettingsDocument(settings, providerDefinitions = []) {
811
+ return hasUsableProviderConfig(settings, providerDefinitions) ? "valid" : "incomplete";
760
812
  }
761
813
  function hasUsableProviderConfig(settings, providerDefinitions) {
814
+ if (typeof settings.currentProvider === "string") {
815
+ const profile = settings.providers?.[settings.currentProvider];
816
+ return isUsableProviderProfile(profile?.type, profile, providerDefinitions);
817
+ }
762
818
  if (settings.provider && isUsableProviderProfile(settings.provider.name, settings.provider, providerDefinitions)) {
763
819
  return true;
764
820
  }
765
- if (typeof settings.currentProvider !== "string") {
766
- return false;
767
- }
768
- const profile = settings.providers?.[settings.currentProvider];
769
- return isUsableProviderProfile(profile?.type, profile, providerDefinitions);
821
+ return false;
770
822
  }
771
823
  function isUsableProviderProfile(type, profile, providerDefinitions) {
772
824
  if (!profile) {
@@ -786,69 +838,14 @@ function isUsableProviderProfile(type, profile, providerDefinitions) {
786
838
  }
787
839
 
788
840
  // src/utils/provider-settings.ts
789
- function upsertProviderProfile(settings, profileName, profile) {
790
- return {
791
- ...settings,
792
- providers: {
793
- ...settings.providers ?? {},
794
- [profileName]: profile
795
- }
796
- };
797
- }
798
- function setCurrentProvider(settings, profileName) {
799
- if (!settings.providers?.[profileName]) {
800
- throw new Error(`Provider profile "${profileName}" was not found`);
801
- }
802
- return {
803
- ...settings,
804
- currentProvider: profileName
805
- };
806
- }
807
- function validateProviderProfile(profileName, profile, options = {}) {
808
- if (!profile.type) {
809
- throw new Error(`Provider profile "${profileName}" is missing type`);
810
- }
811
- if (!profile.model) {
812
- throw new Error(`Provider profile "${profileName}" is missing model`);
813
- }
814
- const definition = findProviderDefinition(options.providerDefinitions ?? [], profile.type);
815
- if (definition?.requiresApiKey === true && !hasUsableSecretReference(profile.apiKey ?? definition.defaults?.apiKey)) {
816
- throw new Error(`Provider profile "${profileName}" is missing apiKey`);
817
- }
818
- }
819
- function buildProviderSetupPatch(input, options = {}) {
820
- const profile = buildProviderProfile(input, options);
821
- validateProviderProfile(input.profile, profile, options);
822
- return {
823
- ...input.setCurrent && { currentProvider: input.profile },
824
- providers: {
825
- [input.profile]: profile
826
- }
827
- };
828
- }
829
- function buildProviderProfile(input, options = {}) {
830
- const defaults = getProviderDefaults(input.type, options.providerDefinitions ?? []);
831
- const apiKey = input.apiKeyEnv !== void 0 ? `$ENV:${input.apiKeyEnv}` : input.apiKey ?? defaults.apiKey;
832
- const baseURL = input.baseURL ?? defaults.baseURL;
833
- return {
834
- type: input.type,
835
- model: input.model ?? defaults.model,
836
- ...apiKey !== void 0 && { apiKey },
837
- ...baseURL !== void 0 && { baseURL },
838
- ...input.timeout !== void 0 && { timeout: input.timeout }
839
- };
840
- }
841
- function getProviderDefaults(type, providerDefinitions) {
842
- return findProviderDefinition(providerDefinitions, type)?.defaults ?? {};
843
- }
844
- function mergeProviderPatch(settings, patch) {
845
- const [profileName, profile] = Object.entries(patch.providers)[0] ?? [];
846
- if (!profileName || !profile) {
847
- return settings;
848
- }
849
- const withProfile = upsertProviderProfile(settings, profileName, profile);
850
- return patch.currentProvider ? setCurrentProvider(withProfile, patch.currentProvider) : withProfile;
851
- }
841
+ import {
842
+ buildProviderProfile,
843
+ buildProviderSetupPatch,
844
+ mergeProviderPatch,
845
+ setCurrentProvider,
846
+ upsertProviderProfile,
847
+ validateProviderProfile
848
+ } from "@robota-sdk/agent-sdk";
852
849
 
853
850
  // src/utils/provider-configuration.ts
854
851
  function readProviderDocument(settingsPath) {
@@ -869,158 +866,84 @@ function applyProviderSwitch(settingsPath, profileName, options = {}) {
869
866
  writeSettings(settingsPath, next);
870
867
  return next;
871
868
  }
872
-
873
- // src/utils/provider-setup-flow.ts
874
- function createProviderSetupFlow(type, providerDefinitions) {
875
- return {
876
- type,
877
- steps: getProviderSetupSteps(type, providerDefinitions),
878
- stepIndex: 0,
879
- values: {}
880
- };
881
- }
882
- function formatProviderSetupSelectionPrompt(providerDefinitions) {
883
- if (providerDefinitions.length === 0) {
884
- return " No providers are available.";
885
- }
886
- const lines = [
887
- " Select provider:",
888
- ...providerDefinitions.map(
889
- (definition, index) => ` ${index + 1}. ${formatProviderSetupChoiceLabel(definition)}`
890
- ),
891
- ` Provider [1-${providerDefinitions.length}] (default: 1): `
892
- ];
893
- return lines.join("\n");
894
- }
895
- function resolveProviderSetupSelection(rawValue, providerDefinitions) {
896
- const value = rawValue.trim();
897
- const selectedValue = value.length > 0 ? value : "1";
898
- const index = parseProviderSelectionIndex(selectedValue);
899
- if (index !== void 0) {
900
- const definition2 = providerDefinitions[index];
901
- if (definition2 !== void 0) {
902
- return definition2.type;
903
- }
904
- throw new Error(
905
- `Provider selection ${selectedValue} is out of range. Currently supported: ${formatSupportedProviderTypes(providerDefinitions)}`
906
- );
907
- }
908
- const definition = findProviderDefinition(providerDefinitions, selectedValue);
909
- if (definition === void 0) {
910
- throw new Error(
911
- `Unknown provider: ${selectedValue}. Currently supported: ${formatSupportedProviderTypes(providerDefinitions)}`
912
- );
869
+ function applyActiveModelChange(cwd, modelId, options = {}) {
870
+ const settingsPaths = options.settingsPaths ?? getProviderSettingsPaths(cwd);
871
+ const merged = readMergedProviderSettingsFromPaths(settingsPaths);
872
+ const activeProfileName = options.providerOverride ?? merged.currentProvider;
873
+ if (typeof activeProfileName === "string") {
874
+ return updateActiveProviderProfileModel(settingsPaths, activeProfileName, modelId);
913
875
  }
914
- return definition.type;
876
+ return updateLegacyProviderModel(settingsPaths, modelId);
915
877
  }
916
- function getProviderSetupStep(state) {
917
- const step = state.steps[state.stepIndex];
918
- if (step === void 0) {
919
- throw new Error(`Provider setup step ${state.stepIndex} is out of range`);
878
+ function updateActiveProviderProfileModel(settingsPaths, profileName, modelId) {
879
+ const settingsPath = findLastPathWithProviderProfile(settingsPaths, profileName) ?? settingsPaths[0];
880
+ if (settingsPath === void 0) {
881
+ throw new Error("No settings path available for model update");
920
882
  }
921
- return step;
922
- }
923
- function submitProviderSetupValue(state, rawValue) {
924
- const step = getProviderSetupStep(state);
925
- const value = rawValue.trim() || step.defaultValue || "";
926
- const validationMessage = validateProviderSetupValue(step, value);
927
- if (validationMessage !== void 0) {
928
- return { status: "error", state, message: validationMessage };
929
- }
930
- const nextState = {
931
- ...state,
932
- stepIndex: state.stepIndex + 1,
933
- values: { ...state.values, [step.key]: value }
934
- };
935
- if (nextState.stepIndex < state.steps.length) {
936
- return { status: "next", state: nextState };
937
- }
938
- return { status: "complete", input: buildProviderSetupInput(nextState) };
939
- }
940
- async function runProviderSetupPromptFlow(type, promptInput2, providerDefinitions) {
941
- let state = createProviderSetupFlow(type, providerDefinitions);
942
- const stepCount = state.steps.length;
943
- while (state.stepIndex < stepCount) {
944
- const step = getProviderSetupStep(state);
945
- const value = await promptInput2(formatProviderSetupPromptLabel(step), step.masked === true);
946
- const result = submitProviderSetupValue(state, value);
947
- if (result.status === "complete") {
948
- return result.input;
949
- }
950
- if (result.status === "error") {
951
- throw new Error(result.message);
883
+ const settings = readProviderDocument(settingsPath);
884
+ const providers = settings.providers ?? {};
885
+ const existing = providers[profileName] ?? {};
886
+ const next = {
887
+ ...settings,
888
+ providers: {
889
+ ...providers,
890
+ [profileName]: {
891
+ ...existing,
892
+ model: modelId
893
+ }
952
894
  }
953
- state = result.state;
954
- }
955
- throw new Error("Provider setup flow ended without completion");
956
- }
957
- function formatProviderSetupPromptLabel(step) {
958
- const suffix = step.defaultValue !== void 0 ? ` (default: ${step.defaultValue})` : "";
959
- return ` ${step.title}${suffix}: `;
960
- }
961
- function formatProviderSetupChoiceLabel(definition) {
962
- const label = definition.displayName !== void 0 ? `${definition.displayName} (${definition.type})` : definition.type;
963
- return definition.description !== void 0 ? `${label} - ${definition.description}` : label;
895
+ };
896
+ writeSettings(settingsPath, next);
897
+ return { settingsPath, settings: next, profileName };
964
898
  }
965
- function parseProviderSelectionIndex(value) {
966
- if (!/^\d+$/.test(value)) {
967
- return void 0;
899
+ function updateLegacyProviderModel(settingsPaths, modelId) {
900
+ const settingsPath = findLastPathWithLegacyProvider(settingsPaths) ?? settingsPaths[0];
901
+ if (settingsPath === void 0) {
902
+ throw new Error("No settings path available for model update");
968
903
  }
969
- return Number(value) - 1;
904
+ const settings = readProviderDocument(settingsPath);
905
+ const next = {
906
+ ...settings,
907
+ provider: {
908
+ ...settings.provider ?? {},
909
+ model: modelId
910
+ }
911
+ };
912
+ writeSettings(settingsPath, next);
913
+ return { settingsPath, settings: next, legacyProvider: true };
970
914
  }
971
- function validateProviderSetupValue(step, value) {
972
- if (step.required === true && value.length === 0) {
973
- return "Required";
915
+ function findLastPathWithProviderProfile(settingsPaths, profileName) {
916
+ for (let index = settingsPaths.length - 1; index >= 0; index -= 1) {
917
+ const settingsPath = settingsPaths[index];
918
+ if (settingsPath === void 0) continue;
919
+ const settings = readProviderDocument(settingsPath);
920
+ if (settings.providers?.[profileName] !== void 0) return settingsPath;
974
921
  }
975
922
  return void 0;
976
923
  }
977
- function getProviderSetupSteps(type, providerDefinitions) {
978
- const definition = findProviderDefinition(providerDefinitions, type);
979
- if (definition === void 0) {
980
- throw new Error(
981
- `Unknown provider: ${type}. Currently supported: ${formatSupportedProviderTypes(providerDefinitions)}`
982
- );
983
- }
984
- if (definition.setupSteps !== void 0) {
985
- return [...definition.setupSteps];
986
- }
987
- const steps = [
988
- {
989
- key: "model",
990
- title: `${definition.type} model`,
991
- defaultValue: definition.defaults?.model,
992
- required: definition.defaults?.model === void 0
993
- }
994
- ];
995
- if (definition.defaults?.baseURL !== void 0) {
996
- steps.unshift({
997
- key: "baseURL",
998
- title: `${definition.type} base URL`,
999
- defaultValue: definition.defaults.baseURL
1000
- });
924
+ function findLastPathWithLegacyProvider(settingsPaths) {
925
+ for (let index = settingsPaths.length - 1; index >= 0; index -= 1) {
926
+ const settingsPath = settingsPaths[index];
927
+ if (settingsPath === void 0) continue;
928
+ const settings = readProviderDocument(settingsPath);
929
+ if (settings.provider !== void 0) return settingsPath;
1001
930
  }
1002
- if (definition.requiresApiKey === true) {
1003
- steps.push({
1004
- key: "apiKey",
1005
- title: `${definition.type} API key`,
1006
- defaultValue: definition.defaults?.apiKey,
1007
- required: definition.defaults?.apiKey === void 0,
1008
- masked: true
1009
- });
1010
- }
1011
- return steps;
1012
- }
1013
- function buildProviderSetupInput(state) {
1014
- return {
1015
- profile: state.type,
1016
- type: state.type,
1017
- model: state.values.model,
1018
- apiKey: state.values.apiKey,
1019
- ...state.values.baseURL !== void 0 && { baseURL: state.values.baseURL },
1020
- setCurrent: true
1021
- };
931
+ return void 0;
1022
932
  }
1023
933
 
934
+ // src/utils/provider-setup-flow.ts
935
+ import {
936
+ createProviderSetupFlow,
937
+ formatProviderSetupChoiceLabel,
938
+ formatProviderSetupPromptLabel,
939
+ formatProviderSetupSelectionPrompt,
940
+ getProviderSetupStep,
941
+ resolveProviderSetupSelection,
942
+ runProviderSetupPromptFlow,
943
+ submitProviderSetupValue,
944
+ validateProviderSetupValue
945
+ } from "@robota-sdk/agent-sdk";
946
+
1024
947
  // src/utils/provider-setup.ts
1025
948
  function getSettingsPathForScope(cwd, scope) {
1026
949
  if (scope === void 0 || scope === "user") {
@@ -1052,17 +975,25 @@ function handleProviderConfigurationArgs(cwd, args, providerDefinitions = DEFAUL
1052
975
  return false;
1053
976
  }
1054
977
  async function ensureConfig(cwd, args, promptInput2, providerDefinitions = DEFAULT_PROVIDER_DEFINITIONS) {
1055
- const checks = getSettingsCheckPaths(cwd).map((path) => ({
1056
- path,
1057
- status: checkSettingsFile(path, providerDefinitions)
1058
- }));
1059
- if (checks.some((check) => check.status === "valid")) {
978
+ const merged = readMergedProviderSettings(cwd);
979
+ const selectedSettings = args.provider !== void 0 ? { ...merged, currentProvider: args.provider } : merged;
980
+ if (checkSettingsDocument(selectedSettings, providerDefinitions) === "valid") {
1060
981
  return;
1061
982
  }
1062
983
  if (!isInteractiveTerminal()) {
1063
984
  throw new Error(formatMissingProviderConfigMessage(providerDefinitions));
1064
985
  }
1065
- await runInteractiveProviderSetup(cwd, args, promptInput2, providerDefinitions);
986
+ await runInteractiveProviderSetup(
987
+ cwd,
988
+ selectStartupSetupArgs(cwd, args),
989
+ promptInput2,
990
+ providerDefinitions
991
+ );
992
+ const updated = readMergedProviderSettings(cwd);
993
+ const updatedSettings = args.provider !== void 0 ? { ...updated, currentProvider: args.provider } : updated;
994
+ if (checkSettingsDocument(updatedSettings, providerDefinitions) !== "valid") {
995
+ throw new Error(formatMissingProviderConfigMessage(providerDefinitions));
996
+ }
1066
997
  }
1067
998
  async function runInteractiveProviderSetup(cwd, args, promptInput2, providerDefinitions = DEFAULT_PROVIDER_DEFINITIONS) {
1068
999
  const providerChoice = await promptInput2(formatProviderSetupSelectionPrompt(providerDefinitions));
@@ -1098,15 +1029,31 @@ function buildSetupInputFromArgs(args) {
1098
1029
  setCurrent: args.setCurrent
1099
1030
  };
1100
1031
  }
1101
- function getSettingsCheckPaths(cwd) {
1102
- return [
1103
- getUserSettingsPath(),
1104
- join4(homedir(), ".claude", "settings.json"),
1105
- join4(cwd, ".robota", "settings.json"),
1106
- join4(cwd, ".robota", "settings.local.json"),
1107
- join4(cwd, ".claude", "settings.json"),
1108
- join4(cwd, ".claude", "settings.local.json")
1109
- ];
1032
+ function selectStartupSetupArgs(cwd, args) {
1033
+ if (args.settingsScope !== void 0 || args.provider !== void 0) {
1034
+ return args;
1035
+ }
1036
+ const currentProviderPath = findHighestPriorityCurrentProviderPath(getProviderSettingsPaths(cwd));
1037
+ if (currentProviderPath === void 0) {
1038
+ return args;
1039
+ }
1040
+ const projectSettingsPath = join4(cwd, ".robota", "settings.json");
1041
+ const projectLocalSettingsPath = join4(cwd, ".robota", "settings.local.json");
1042
+ if (currentProviderPath === projectSettingsPath || currentProviderPath === projectLocalSettingsPath) {
1043
+ return { ...args, settingsScope: "project-local" };
1044
+ }
1045
+ return args;
1046
+ }
1047
+ function findHighestPriorityCurrentProviderPath(settingsPaths) {
1048
+ for (let index = settingsPaths.length - 1; index >= 0; index -= 1) {
1049
+ const settingsPath = settingsPaths[index];
1050
+ if (settingsPath === void 0) continue;
1051
+ const settings = readSettings(settingsPath);
1052
+ if (typeof settings.currentProvider === "string") {
1053
+ return settingsPath;
1054
+ }
1055
+ }
1056
+ return void 0;
1110
1057
  }
1111
1058
  function isInteractiveTerminal() {
1112
1059
  return process.stdin.isTTY === true && process.stdout.isTTY === true;
@@ -1140,19 +1087,15 @@ import { render } from "ink";
1140
1087
  // src/ui/App.tsx
1141
1088
  import { useState as useState14, useEffect as useEffect4 } from "react";
1142
1089
  import { Box as Box18, Text as Text20, useApp as useApp2, useInput as useInput8 } from "ink";
1143
- import { getModelName as getModelName3, createSystemMessage as createSystemMessage4, messageToHistoryEntry as messageToHistoryEntry4 } from "@robota-sdk/agent-core";
1090
+ import { createSystemMessage as createSystemMessage6, messageToHistoryEntry as messageToHistoryEntry6 } from "@robota-sdk/agent-core";
1144
1091
 
1145
1092
  // src/ui/hooks/useInteractiveSession.ts
1146
1093
  import { useState, useRef, useCallback as useCallback2, useEffect } from "react";
1147
- import { homedir as homedir2 } from "os";
1148
- import { join as join5 } from "path";
1149
1094
  import {
1150
1095
  InteractiveSession,
1151
- CommandRegistry,
1152
- BuiltinCommandSource,
1153
- SkillCommandSource,
1154
- PluginCommandSource,
1155
- BundlePluginLoader
1096
+ CommandRegistry as CommandRegistry2,
1097
+ createBuiltinCommandModule,
1098
+ SkillCommandSource
1156
1099
  } from "@robota-sdk/agent-sdk";
1157
1100
  import { createSystemMessage as createSystemMessage2, messageToHistoryEntry as messageToHistoryEntry2 } from "@robota-sdk/agent-core";
1158
1101
 
@@ -1178,7 +1121,11 @@ function toBackgroundTaskViewModel(state, partialText) {
1178
1121
  lastActivityAt: state.lastActivityAt,
1179
1122
  timeoutReason: state.timeoutReason,
1180
1123
  exitCode: state.result?.exitCode,
1181
- signalCode: state.result?.signalCode
1124
+ signalCode: state.result?.signalCode,
1125
+ worktreePath: state.worktreePath,
1126
+ branchName: state.branchName,
1127
+ worktreeStatus: state.worktreeStatus,
1128
+ worktreeNextAction: state.worktreeNextAction
1182
1129
  };
1183
1130
  }
1184
1131
  function getBackgroundTaskStatusLabel(state) {
@@ -1343,6 +1290,14 @@ var TuiStateManager = class {
1343
1290
  this.history = updated.length > MAX_RENDERED_MESSAGES ? updated.slice(-MAX_RENDERED_MESSAGES) : updated;
1344
1291
  this.notify();
1345
1292
  }
1293
+ clearHistory() {
1294
+ this.history = [];
1295
+ this.debouncedStreamNotify.flush();
1296
+ this.streamBuf = "";
1297
+ this.streamingText = "";
1298
+ this.activeTools = [];
1299
+ this.notify();
1300
+ }
1346
1301
  /** Update pending prompt state */
1347
1302
  setPendingPrompt(prompt) {
1348
1303
  this.pendingPrompt = prompt;
@@ -1408,133 +1363,35 @@ var TuiStateManager = class {
1408
1363
  // src/ui/hooks/useSlashRouting.ts
1409
1364
  import { useCallback } from "react";
1410
1365
  import { randomUUID as randomUUID2 } from "crypto";
1411
- import {
1412
- createSystemMessage,
1413
- messageToHistoryEntry
1414
- } from "@robota-sdk/agent-core";
1366
+ import { createSystemMessage, messageToHistoryEntry } from "@robota-sdk/agent-core";
1415
1367
 
1416
- // src/utils/provider-command.ts
1417
- async function handleProviderCommand(cwd, args, deps = {}) {
1418
- const settings = readMergedProviderSettings(cwd);
1419
- const providerDefinitions = deps.providerDefinitions ?? DEFAULT_PROVIDER_DEFINITIONS;
1420
- const [subcommand = "current", profileArg] = args.trim().split(/\s+/);
1421
- if (subcommand === "list") {
1422
- return {
1423
- message: formatProviderList(settings.currentProvider, settings.providers),
1424
- success: true
1425
- };
1426
- }
1427
- if (subcommand === "current" || subcommand === "") {
1428
- return {
1429
- message: formatCurrentProvider(settings.currentProvider, settings.providers),
1430
- success: true
1431
- };
1432
- }
1433
- if (subcommand === "use") {
1434
- return buildProviderSwitch(settings.providers, profileArg);
1435
- }
1436
- if (subcommand === "test") {
1437
- return await testProvider(settings.currentProvider, settings.providers, profileArg, deps);
1438
- }
1439
- if (subcommand === "add") {
1440
- return buildProviderSetup(profileArg, providerDefinitions);
1441
- }
1442
- return {
1443
- message: "Usage: provider [current|list|use <profile>|add <type>|test [profile]]",
1444
- success: false
1445
- };
1446
- }
1447
- function formatProviderList(currentProvider, providers) {
1448
- const entries = Object.entries(providers ?? {});
1449
- if (entries.length === 0) {
1450
- return "No provider profiles configured.";
1451
- }
1452
- return entries.map(([name, profile]) => {
1453
- const marker = name === currentProvider ? "*" : "-";
1454
- return `${marker} ${name}: ${profile.type ?? "unknown"} ${profile.model ?? "(no model)"}`;
1455
- }).join("\n");
1456
- }
1457
- function formatCurrentProvider(currentProvider, providers) {
1458
- if (!currentProvider) {
1459
- return "No current provider configured.";
1460
- }
1461
- const profile = providers?.[currentProvider];
1462
- if (!profile) {
1463
- return `Current provider "${currentProvider}" was not found in providers.`;
1464
- }
1465
- return [
1466
- `Current provider: ${currentProvider}`,
1467
- `Type: ${profile.type ?? "unknown"}`,
1468
- `Model: ${profile.model ?? "(no model)"}`,
1469
- ...profile.baseURL ? [`Base URL: ${profile.baseURL}`] : []
1470
- ].join("\n");
1471
- }
1472
- function buildProviderSwitch(providers, profileName) {
1473
- if (!profileName) {
1474
- return { message: "Usage: provider use <profile>", success: false };
1475
- }
1476
- if (!providers?.[profileName]) {
1477
- return { message: `Provider profile "${profileName}" was not found.`, success: false };
1478
- }
1479
- return {
1480
- message: `Provider change requested: ${profileName}`,
1481
- success: true,
1482
- data: { providerSwitch: { profile: profileName } }
1483
- };
1484
- }
1485
- function buildProviderSetup(type, providerDefinitions) {
1486
- if (!type) {
1487
- return {
1488
- message: "Provider setup requested. Select a provider to continue.",
1489
- success: true,
1490
- data: { providerSetup: {} }
1491
- };
1492
- }
1493
- if (findProviderDefinition(providerDefinitions, type) === void 0) {
1494
- return {
1495
- message: `Usage: provider add <type>. Supported: ${formatSupportedProviderTypes(providerDefinitions)}`,
1496
- success: false
1497
- };
1498
- }
1499
- return {
1500
- message: `Provider setup requested: ${type}`,
1501
- success: true,
1502
- data: { providerSetup: { type } }
1503
- };
1368
+ // src/plugins/plugin-command-source-loader.ts
1369
+ import { homedir } from "os";
1370
+ import { join as join5 } from "path";
1371
+ import { BundlePluginLoader, PluginCommandSource } from "@robota-sdk/agent-sdk";
1372
+ var PLUGIN_SOURCE_NAME = "plugin";
1373
+ function getHomeDir() {
1374
+ return process.env.HOME ?? homedir();
1504
1375
  }
1505
- async function testProvider(currentProvider, providers, profileArg, deps) {
1506
- const profileName = profileArg ?? currentProvider;
1507
- if (!profileName) {
1508
- return { message: "No provider profile selected.", success: false };
1509
- }
1510
- const profile = providers?.[profileName];
1511
- if (!profile) {
1512
- return { message: `Provider profile "${profileName}" was not found.`, success: false };
1513
- }
1376
+ function reloadPluginCommandSource(registry) {
1377
+ const pluginsDir = join5(getHomeDir(), ".robota", "plugins");
1378
+ const loader = new BundlePluginLoader(pluginsDir);
1514
1379
  try {
1515
- validateProviderProfile(profileName, profile, {
1516
- providerDefinitions: deps.providerDefinitions ?? DEFAULT_PROVIDER_DEFINITIONS
1517
- });
1518
- } catch (error) {
1519
- return { message: error instanceof Error ? error.message : String(error), success: false };
1380
+ const plugins = loader.loadPluginsSync();
1381
+ if (plugins.length === 0) {
1382
+ registry.replaceSource(PLUGIN_SOURCE_NAME);
1383
+ return 0;
1384
+ }
1385
+ registry.replaceSource(PLUGIN_SOURCE_NAME, new PluginCommandSource(plugins));
1386
+ return plugins.length;
1387
+ } catch {
1388
+ registry.replaceSource(PLUGIN_SOURCE_NAME);
1389
+ return 0;
1520
1390
  }
1521
- const providerDefinitions = deps.providerDefinitions ?? DEFAULT_PROVIDER_DEFINITIONS;
1522
- const definition = profile.type ? findProviderDefinition(providerDefinitions, profile.type) : void 0;
1523
- const probe = deps.probe ?? definition?.probeProfile ?? probeProviderProfile;
1524
- const result = await probe(profile);
1525
- return {
1526
- message: result.ok ? `Provider "${profileName}" test passed: ${result.message}` : `Provider "${profileName}" test failed: ${result.message}; manual configuration can continue.`,
1527
- success: true,
1528
- data: { providerTest: { profile: profileName } }
1529
- };
1530
- }
1531
- async function probeProviderProfile(profile) {
1532
- void profile;
1533
- return { ok: true, message: "Profile fields are valid; no endpoint probe configured." };
1534
1391
  }
1535
1392
 
1536
1393
  // src/ui/hooks/useSlashRouting.ts
1537
- function useSlashRouting(cwd, interactiveSession, registry, manager, providerDefinitions) {
1394
+ function useSlashRouting(interactiveSession, registry, manager) {
1538
1395
  return useCallback(
1539
1396
  async (input) => {
1540
1397
  manager.onUserTurnAccepted();
@@ -1546,70 +1403,32 @@ function useSlashRouting(cwd, interactiveSession, registry, manager, providerDef
1546
1403
  const parts = input.slice(1).split(/\s+/);
1547
1404
  const cmd = parts[0]?.toLowerCase() ?? "";
1548
1405
  const args = parts.slice(1).join(" ");
1549
- if (cmd === "provider") {
1550
- await routeProviderCommand(cwd, args, interactiveSession, manager, providerDefinitions);
1551
- return;
1552
- }
1553
1406
  const result = await interactiveSession.executeCommand(cmd, args);
1554
1407
  if (result) {
1555
- applySystemCommandResult(result, interactiveSession, manager);
1408
+ applySystemCommandResult(result, interactiveSession, registry, manager);
1556
1409
  return;
1557
1410
  }
1558
1411
  if (await routeSkillCommand(input, cmd, registry, interactiveSession, manager)) {
1559
1412
  return;
1560
1413
  }
1561
- if (routeTuiCommand(cmd, interactiveSession)) {
1562
- return;
1563
- }
1564
1414
  manager.addEntry(
1565
1415
  messageToHistoryEntry(
1566
1416
  createSystemMessage(`Unknown command "/${cmd}". Type /help for help.`)
1567
1417
  )
1568
1418
  );
1569
1419
  },
1570
- [cwd, interactiveSession, registry, manager, providerDefinitions]
1420
+ [interactiveSession, registry, manager]
1571
1421
  );
1572
1422
  }
1573
- async function routeProviderCommand(cwd, args, interactiveSession, manager, providerDefinitions) {
1574
- const result = await handleProviderCommand(cwd, args, { providerDefinitions });
1423
+ function applySystemCommandResult(result, interactiveSession, registry, manager) {
1424
+ const pendingEffects = applyImmediateCommandEffects(result.effects, registry, manager);
1575
1425
  manager.addEntry(messageToHistoryEntry(createSystemMessage(result.message)));
1576
- const providerSwitch = result.data?.providerSwitch;
1577
- if (providerSwitch?.profile) {
1578
- getEffects(interactiveSession)._pendingProviderProfile = providerSwitch.profile;
1579
- }
1580
- const providerSetup = result.data?.providerSetup;
1581
- if (providerSetup !== void 0) {
1582
- getEffects(interactiveSession)._pendingProviderSetup = providerSetup;
1583
- }
1584
- }
1585
- function applySystemCommandResult(result, interactiveSession, manager) {
1586
- manager.addEntry(messageToHistoryEntry(createSystemMessage(result.message)));
1587
- const data = result.data;
1588
1426
  const effects = getEffects(interactiveSession);
1589
- if (typeof data?.modelId === "string") {
1590
- effects._pendingModelId = data.modelId;
1591
- return;
1592
- }
1593
- if (typeof data?.language === "string") {
1594
- effects._pendingLanguage = data.language;
1595
- return;
1427
+ if (result.interaction !== void 0) {
1428
+ effects._pendingCommandInteraction = result.interaction;
1596
1429
  }
1597
- if (data?.resetRequested === true) {
1598
- effects._resetRequested = true;
1599
- return;
1600
- }
1601
- if (data?.triggerResumePicker === true) {
1602
- effects._triggerResumePicker = true;
1603
- return;
1604
- }
1605
- if (typeof data?.name === "string") {
1606
- effects._sessionName = data.name;
1607
- return;
1608
- }
1609
- const statusLinePatch = data?.statuslinePatch;
1610
- if (isStatusLineSettingsPatch(statusLinePatch)) {
1611
- effects._statusLinePatch = statusLinePatch;
1612
- return;
1430
+ if (pendingEffects.length > 0) {
1431
+ effects._pendingCommandEffects = pendingEffects;
1613
1432
  }
1614
1433
  const ctx = interactiveSession.getContextState();
1615
1434
  manager.setContextState({
@@ -1618,6 +1437,22 @@ function applySystemCommandResult(result, interactiveSession, manager) {
1618
1437
  maxTokens: ctx.maxTokens
1619
1438
  });
1620
1439
  }
1440
+ function applyImmediateCommandEffects(effects, registry, manager) {
1441
+ if (effects === void 0 || effects.length === 0) return [];
1442
+ const pendingEffects = [];
1443
+ for (const effect of effects) {
1444
+ if (effect.type === "conversation-history-cleared") {
1445
+ manager.clearHistory();
1446
+ continue;
1447
+ }
1448
+ if (effect.type === "plugin-registry-reload-requested") {
1449
+ reloadPluginCommandSource(registry);
1450
+ continue;
1451
+ }
1452
+ pendingEffects.push(effect);
1453
+ }
1454
+ return pendingEffects;
1455
+ }
1621
1456
  async function routeSkillCommand(input, cmd, registry, interactiveSession, manager) {
1622
1457
  const skillCmd = registry.getCommands().find((c) => c.name === cmd && (c.source === "skill" || c.source === "plugin"));
1623
1458
  if (!skillCmd) {
@@ -1641,29 +1476,14 @@ async function routeSkillCommand(input, cmd, registry, interactiveSession, manag
1641
1476
  manager.setPendingPrompt(interactiveSession.getPendingPrompt());
1642
1477
  return true;
1643
1478
  }
1644
- function routeTuiCommand(cmd, interactiveSession) {
1645
- if (cmd === "exit") {
1646
- getEffects(interactiveSession)._exitRequested = true;
1647
- return true;
1648
- }
1649
- if (cmd === "plugin") {
1650
- getEffects(interactiveSession)._triggerPluginTUI = true;
1651
- return true;
1652
- }
1653
- return false;
1654
- }
1655
1479
  function getEffects(interactiveSession) {
1656
1480
  return interactiveSession;
1657
1481
  }
1658
- function isStatusLineSettingsPatch(value) {
1659
- if (value === null || typeof value !== "object" || Array.isArray(value) || value instanceof Date) {
1660
- return false;
1661
- }
1662
- const candidate = value;
1663
- return (candidate.enabled === void 0 || typeof candidate.enabled === "boolean") && (candidate.gitBranch === void 0 || typeof candidate.gitBranch === "boolean");
1664
- }
1665
1482
 
1666
1483
  // src/ui/hooks/useInteractiveSession.ts
1484
+ function applyCompactEventToManager(interactiveSession, manager) {
1485
+ manager.syncHistory(interactiveSession.getFullHistory());
1486
+ }
1667
1487
  function initializeSession(props, permissionHandler) {
1668
1488
  const interactiveSession = new InteractiveSession({
1669
1489
  cwd: props.cwd,
@@ -1677,23 +1497,16 @@ function initializeSession(props, permissionHandler) {
1677
1497
  sessionName: props.sessionName,
1678
1498
  backgroundTaskRunners: props.backgroundTaskRunners,
1679
1499
  subagentRunnerFactory: props.subagentRunnerFactory,
1680
- commandModules: props.commandModules
1500
+ commandModules: props.commandModules,
1501
+ commandHostAdapters: props.commandHostAdapters
1681
1502
  });
1682
- const registry = new CommandRegistry();
1683
- registry.addSource(new BuiltinCommandSource());
1503
+ const registry = new CommandRegistry2();
1504
+ registry.addModule(createBuiltinCommandModule());
1684
1505
  for (const module of props.commandModules ?? []) {
1685
1506
  registry.addModule(module);
1686
1507
  }
1687
1508
  registry.addSource(new SkillCommandSource(props.cwd));
1688
- const pluginsDir = join5(homedir2(), ".robota", "plugins");
1689
- const loader = new BundlePluginLoader(pluginsDir);
1690
- try {
1691
- const plugins = loader.loadPluginsSync();
1692
- if (plugins.length > 0) {
1693
- registry.addSource(new PluginCommandSource(plugins));
1694
- }
1695
- } catch {
1696
- }
1509
+ reloadPluginCommandSource(registry);
1697
1510
  const manager = new TuiStateManager();
1698
1511
  return { interactiveSession, registry, manager };
1699
1512
  }
@@ -1743,6 +1556,7 @@ function useInteractiveSession(props) {
1743
1556
  }
1744
1557
  }
1745
1558
  useEffect(() => {
1559
+ const onCompact = () => applyCompactEventToManager(interactiveSession, manager);
1746
1560
  interactiveSession.on("text_delta", manager.onTextDelta);
1747
1561
  interactiveSession.on("tool_start", manager.onToolStart);
1748
1562
  interactiveSession.on("tool_end", manager.onToolEnd);
@@ -1751,6 +1565,7 @@ function useInteractiveSession(props) {
1751
1565
  interactiveSession.on("interrupted", manager.onInterrupted);
1752
1566
  interactiveSession.on("error", manager.onError);
1753
1567
  interactiveSession.on("context_update", manager.onContextUpdate);
1568
+ interactiveSession.on("compact", onCompact);
1754
1569
  interactiveSession.on("background_task_event", manager.onBackgroundTaskEvent);
1755
1570
  const initCheck = setInterval(() => {
1756
1571
  try {
@@ -1778,6 +1593,7 @@ function useInteractiveSession(props) {
1778
1593
  interactiveSession.off("interrupted", manager.onInterrupted);
1779
1594
  interactiveSession.off("error", manager.onError);
1780
1595
  interactiveSession.off("context_update", manager.onContextUpdate);
1596
+ interactiveSession.off("compact", onCompact);
1781
1597
  interactiveSession.off("background_task_event", manager.onBackgroundTaskEvent);
1782
1598
  };
1783
1599
  }, [interactiveSession, manager]);
@@ -1787,13 +1603,7 @@ function useInteractiveSession(props) {
1787
1603
  manager.setPendingPrompt(interactiveSession.getPendingPrompt());
1788
1604
  }
1789
1605
  }, [manager.isThinking, interactiveSession, manager]);
1790
- const handleSubmit = useSlashRouting(
1791
- props.cwd,
1792
- interactiveSession,
1793
- registry,
1794
- manager,
1795
- props.providerDefinitions ?? []
1796
- );
1606
+ const handleSubmit = useSlashRouting(interactiveSession, registry, manager);
1797
1607
  const handleAbort = useCallback2(() => {
1798
1608
  manager.setAborting(true);
1799
1609
  interactiveSession.abort();
@@ -1834,184 +1644,134 @@ function useInteractiveSession(props) {
1834
1644
 
1835
1645
  // src/ui/hooks/usePluginCallbacks.ts
1836
1646
  import { useMemo } from "react";
1837
- import { homedir as homedir3 } from "os";
1647
+
1648
+ // src/plugins/plugin-command-adapter.ts
1649
+ import { homedir as homedir2 } from "os";
1838
1650
  import { join as join6 } from "path";
1839
1651
  import {
1840
- PluginSettingsStore,
1841
- BundlePluginLoader as BundlePluginLoader2,
1842
1652
  BundlePluginInstaller,
1843
- MarketplaceClient
1653
+ BundlePluginLoader as BundlePluginLoader2,
1654
+ MarketplaceClient,
1655
+ PluginSettingsStore
1844
1656
  } from "@robota-sdk/agent-sdk";
1845
- function usePluginCallbacks(cwd) {
1846
- return useMemo(() => {
1847
- const home = homedir3();
1848
- const pluginsDir = join6(home, ".robota", "plugins");
1849
- const userSettingsPath = join6(home, ".robota", "settings.json");
1850
- const settingsStore = new PluginSettingsStore(userSettingsPath);
1851
- const marketplace = new MarketplaceClient({ pluginsDir });
1852
- const installer = new BundlePluginInstaller({
1853
- pluginsDir,
1854
- settingsStore,
1855
- marketplaceClient: marketplace
1856
- });
1857
- const loader = new BundlePluginLoader2(pluginsDir);
1858
- return {
1859
- listInstalled: async () => {
1860
- const plugins = await loader.loadAll();
1861
- const enabledMap = settingsStore.getEnabledPlugins();
1862
- return plugins.map((p) => {
1863
- const parts = p.pluginDir.split("/");
1864
- const cacheIdx = parts.indexOf("cache");
1865
- const marketplaceName = cacheIdx >= 0 ? parts[cacheIdx + 1] : "";
1866
- const fullId = marketplaceName ? `${p.manifest.name}@${marketplaceName}` : p.manifest.name;
1867
- return {
1868
- name: fullId,
1869
- description: p.manifest.description,
1870
- enabled: enabledMap[fullId] !== false && enabledMap[p.manifest.name] !== false
1871
- };
1872
- });
1873
- },
1874
- listAvailablePlugins: async (marketplaceName) => {
1875
- let manifest;
1876
- try {
1877
- manifest = marketplace.fetchManifest(marketplaceName);
1878
- } catch {
1879
- return [];
1880
- }
1881
- const installed = installer.getInstalledPlugins();
1882
- const installedNames = new Set(Object.values(installed).map((r) => r.pluginName));
1883
- return manifest.plugins.map((p) => ({
1884
- name: p.name,
1885
- description: p.description,
1886
- installed: installedNames.has(p.name)
1887
- }));
1888
- },
1889
- install: async (pluginId, scope) => {
1890
- const [name, marketplaceName] = pluginId.split("@");
1891
- if (!name || !marketplaceName) {
1892
- throw new Error("Plugin ID must be in format: name@marketplace");
1893
- }
1894
- if (scope === "project") {
1895
- const projectPluginsDir = join6(cwd, ".robota", "plugins");
1896
- const projectInstaller = new BundlePluginInstaller({
1897
- pluginsDir: projectPluginsDir,
1898
- settingsStore,
1899
- marketplaceClient: marketplace
1900
- });
1901
- await projectInstaller.install(name, marketplaceName);
1902
- } else {
1903
- await installer.install(name, marketplaceName);
1904
- }
1905
- },
1906
- uninstall: async (pluginId) => {
1907
- await installer.uninstall(pluginId);
1908
- },
1909
- enable: async (pluginId) => {
1910
- await installer.enable(pluginId);
1911
- },
1912
- disable: async (pluginId) => {
1913
- await installer.disable(pluginId);
1914
- },
1915
- marketplaceAdd: async (source) => {
1916
- if (source.includes("/") && !source.includes(":")) {
1917
- return marketplace.addMarketplace({ type: "github", repo: source });
1918
- } else {
1919
- return marketplace.addMarketplace({ type: "git", url: source });
1920
- }
1921
- },
1922
- marketplaceRemove: async (name) => {
1923
- const installedFromMarketplace = installer.getPluginsByMarketplace(name);
1924
- for (const record of installedFromMarketplace) {
1925
- await installer.uninstall(`${record.pluginName}@${record.marketplace}`);
1926
- }
1927
- marketplace.removeMarketplace(name);
1928
- },
1929
- marketplaceUpdate: async (name) => {
1930
- marketplace.updateMarketplace(name);
1931
- },
1932
- marketplaceList: async () => {
1933
- return marketplace.listMarketplaces().map((m) => ({
1934
- name: m.name,
1935
- type: m.source.type
1936
- }));
1937
- },
1938
- reloadPlugins: async () => {
1939
- }
1940
- };
1941
- }, [cwd]);
1942
- }
1943
-
1944
- // src/ui/hooks/useSideEffects.ts
1945
- import { useState as useState2, useRef as useRef2, useCallback as useCallback3 } from "react";
1946
- import { useApp } from "ink";
1947
- import { createSystemMessage as createSystemMessage3, messageToHistoryEntry as messageToHistoryEntry3, getModelName } from "@robota-sdk/agent-core";
1948
-
1949
- // src/utils/provider-setup-interaction.ts
1950
- function startProviderSetupInteraction(providerDefinitions, type) {
1951
- if (type === void 0) {
1952
- const state2 = {
1953
- mode: "select-provider",
1954
- providerDefinitions
1955
- };
1956
- return { status: "prompt", state: state2, prompt: toProviderSelectionPrompt(providerDefinitions) };
1957
- }
1958
- const state = {
1959
- mode: "setup-fields",
1960
- providerDefinitions,
1961
- flow: createProviderSetupFlow(type, providerDefinitions)
1657
+ function createCliPluginServices(cwd) {
1658
+ const home = homedir2();
1659
+ const pluginsDir = join6(home, ".robota", "plugins");
1660
+ const userSettingsPath = join6(home, ".robota", "settings.json");
1661
+ const settingsStore = new PluginSettingsStore(userSettingsPath);
1662
+ const marketplace = new MarketplaceClient({ pluginsDir });
1663
+ const installer = new BundlePluginInstaller({
1664
+ pluginsDir,
1665
+ settingsStore,
1666
+ marketplaceClient: marketplace
1667
+ });
1668
+ const loader = new BundlePluginLoader2(pluginsDir);
1669
+ return {
1670
+ cwd,
1671
+ marketplace,
1672
+ installer,
1673
+ loader,
1674
+ settingsStore
1962
1675
  };
1963
- return { status: "prompt", state, prompt: toProviderSetupStepPrompt(state.flow) };
1964
- }
1965
- function submitProviderSetupInteractionValue(state, value) {
1966
- if (state.mode === "select-provider") {
1967
- const nextState2 = {
1968
- mode: "setup-fields",
1969
- providerDefinitions: state.providerDefinitions,
1970
- flow: createProviderSetupFlow(value, state.providerDefinitions)
1971
- };
1676
+ }
1677
+ async function listInstalledPlugins(services) {
1678
+ const plugins = await services.loader.loadAll();
1679
+ const enabledMap = services.settingsStore.getEnabledPlugins();
1680
+ return plugins.map((plugin) => {
1681
+ const parts = plugin.pluginDir.split("/");
1682
+ const cacheIdx = parts.indexOf("cache");
1683
+ const marketplaceName = cacheIdx >= 0 ? parts[cacheIdx + 1] ?? "" : "";
1684
+ const fullId = marketplaceName ? `${plugin.manifest.name}@${marketplaceName}` : plugin.manifest.name;
1972
1685
  return {
1973
- status: "prompt",
1974
- state: nextState2,
1975
- prompt: toProviderSetupStepPrompt(nextState2.flow)
1686
+ name: fullId,
1687
+ description: plugin.manifest.description,
1688
+ enabled: enabledMap[fullId] !== false && enabledMap[plugin.manifest.name] !== false
1976
1689
  };
1690
+ });
1691
+ }
1692
+ async function listAvailablePlugins(services, marketplaceName) {
1693
+ let manifest;
1694
+ try {
1695
+ manifest = services.marketplace.fetchManifest(marketplaceName);
1696
+ } catch {
1697
+ return [];
1698
+ }
1699
+ const installed = services.installer.getInstalledPlugins();
1700
+ const installedNames = new Set(Object.values(installed).map((record) => record.pluginName));
1701
+ return manifest.plugins.map((plugin) => ({
1702
+ name: plugin.name,
1703
+ description: plugin.description,
1704
+ installed: installedNames.has(plugin.name)
1705
+ }));
1706
+ }
1707
+ async function installPlugin(services, pluginId, scope) {
1708
+ const [name, marketplaceName] = pluginId.split("@");
1709
+ if (!name || !marketplaceName) {
1710
+ throw new Error("Plugin ID must be in format: name@marketplace");
1711
+ }
1712
+ if (scope === "project") {
1713
+ const projectPluginsDir = join6(services.cwd, ".robota", "plugins");
1714
+ const projectInstaller = new BundlePluginInstaller({
1715
+ pluginsDir: projectPluginsDir,
1716
+ settingsStore: services.settingsStore,
1717
+ marketplaceClient: services.marketplace
1718
+ });
1719
+ await projectInstaller.install(name, marketplaceName);
1720
+ return;
1977
1721
  }
1978
- const result = submitProviderSetupValue(state.flow, value);
1979
- if (result.status === "complete") {
1980
- return { status: "complete", input: result.input };
1722
+ await services.installer.install(name, marketplaceName);
1723
+ }
1724
+ async function removeMarketplace(services, name) {
1725
+ const installedFromMarketplace = services.installer.getPluginsByMarketplace(name);
1726
+ for (const record of installedFromMarketplace) {
1727
+ await services.installer.uninstall(`${record.pluginName}@${record.marketplace}`);
1981
1728
  }
1982
- const nextState = {
1983
- ...state,
1984
- flow: result.state
1985
- };
1986
- return { status: "prompt", state: nextState, prompt: toProviderSetupStepPrompt(result.state) };
1729
+ services.marketplace.removeMarketplace(name);
1987
1730
  }
1988
- function toProviderSelectionPrompt(providerDefinitions) {
1989
- return {
1990
- kind: "choice",
1991
- title: "Select provider",
1992
- options: providerDefinitions.map((definition) => ({
1993
- value: definition.type,
1994
- label: formatProviderSetupChoiceLabel(definition)
1995
- })),
1996
- maxVisible: 6
1997
- };
1731
+ function listMarketplaces(services) {
1732
+ return services.marketplace.listMarketplaces().map((marketplaceEntry) => ({
1733
+ name: marketplaceEntry.name,
1734
+ type: marketplaceEntry.source.type
1735
+ }));
1998
1736
  }
1999
- function toProviderSetupStepPrompt(flow) {
2000
- const step = getProviderSetupStep(flow);
1737
+ function createCliPluginCommandAdapter(cwd) {
1738
+ const services = createCliPluginServices(cwd);
2001
1739
  return {
2002
- kind: "text",
2003
- title: step.title,
2004
- ...step.defaultValue !== void 0 ? { placeholder: step.defaultValue } : {},
2005
- ...step.defaultValue !== void 0 ? { allowEmpty: true } : {},
2006
- ...step.masked !== void 0 ? { masked: step.masked } : {},
2007
- validate: (value) => validateProviderSetupValue(step, value)
1740
+ listInstalled: () => listInstalledPlugins(services),
1741
+ listAvailablePlugins: (marketplaceName) => listAvailablePlugins(services, marketplaceName),
1742
+ install: (pluginId, scope) => installPlugin(services, pluginId, scope),
1743
+ uninstall: async (pluginId) => services.installer.uninstall(pluginId),
1744
+ enable: async (pluginId) => services.installer.enable(pluginId),
1745
+ disable: async (pluginId) => services.installer.disable(pluginId),
1746
+ marketplaceAdd: async (source) => {
1747
+ if (source.includes("/") && !source.includes(":")) {
1748
+ return services.marketplace.addMarketplace({ type: "github", repo: source });
1749
+ }
1750
+ return services.marketplace.addMarketplace({ type: "git", url: source });
1751
+ },
1752
+ marketplaceRemove: (name) => removeMarketplace(services, name),
1753
+ marketplaceUpdate: async (name) => services.marketplace.updateMarketplace(name),
1754
+ marketplaceList: async () => listMarketplaces(services),
1755
+ reloadPlugins: async () => ({
1756
+ loadedPluginCount: (await services.loader.loadAll()).length
1757
+ })
2008
1758
  };
2009
1759
  }
2010
1760
 
1761
+ // src/ui/hooks/usePluginCallbacks.ts
1762
+ function usePluginCallbacks(cwd) {
1763
+ return useMemo(() => createCliPluginCommandAdapter(cwd), [cwd]);
1764
+ }
1765
+
1766
+ // src/ui/hooks/useSideEffects.ts
1767
+ import { useState as useState2, useRef as useRef2, useCallback as useCallback3 } from "react";
1768
+ import { useApp } from "ink";
1769
+ import { createSystemMessage as createSystemMessage5, messageToHistoryEntry as messageToHistoryEntry5 } from "@robota-sdk/agent-core";
1770
+
2011
1771
  // src/utils/statusline-settings.ts
1772
+ import { DEFAULT_STATUS_LINE_COMMAND_SETTINGS } from "@robota-sdk/agent-sdk";
2012
1773
  var DEFAULT_STATUS_LINE_SETTINGS = {
2013
- enabled: true,
2014
- gitBranch: true
1774
+ ...DEFAULT_STATUS_LINE_COMMAND_SETTINGS
2015
1775
  };
2016
1776
  function readStatusLineSettings(settings) {
2017
1777
  const raw = settings.statusline;
@@ -2046,39 +1806,196 @@ function applyPendingStatusLinePatch(sideEffects, setStatusLineSettings) {
2046
1806
  return true;
2047
1807
  }
2048
1808
 
1809
+ // src/ui/hooks/command-effect-handler.ts
1810
+ import { isStatusLineCommandSettingsPatch } from "@robota-sdk/agent-sdk";
1811
+ import { createSystemMessage as createSystemMessage3, messageToHistoryEntry as messageToHistoryEntry3 } from "@robota-sdk/agent-core";
1812
+ function applyCommandEffects(effects, sideEffects, deps) {
1813
+ for (const effect of effects) {
1814
+ if (effect.type === "model-change-requested") {
1815
+ deps.requestModelChange(effect.modelId);
1816
+ return true;
1817
+ }
1818
+ if (effect.type === "language-change-requested") {
1819
+ applyLanguageEffect(effect.language, deps);
1820
+ return true;
1821
+ }
1822
+ if (effect.type === "settings-reset-requested") {
1823
+ applySettingsResetEffect(deps);
1824
+ return true;
1825
+ }
1826
+ if (effect.type === "session-exit-requested") {
1827
+ deps.requestShutdown(
1828
+ effect.reason ?? "prompt_input_exit",
1829
+ effect.message ?? "User requested exit"
1830
+ );
1831
+ return true;
1832
+ }
1833
+ if (effect.type === "session-restart-requested") {
1834
+ deps.requestShutdown(effect.reason, effect.message);
1835
+ return true;
1836
+ }
1837
+ if (effect.type === "plugin-tui-requested") {
1838
+ deps.openPluginTUI();
1839
+ return true;
1840
+ }
1841
+ if (effect.type === "session-picker-requested") {
1842
+ deps.openSessionPicker();
1843
+ return true;
1844
+ }
1845
+ if (effect.type === "session-renamed") {
1846
+ deps.renameSession(effect.name);
1847
+ return true;
1848
+ }
1849
+ if (effect.type === "statusline-settings-patch") {
1850
+ if (isStatusLineCommandSettingsPatch(effect.patch)) {
1851
+ sideEffects._statusLinePatch = effect.patch;
1852
+ if (deps.applyStatusLinePatch(effect.patch)) return true;
1853
+ }
1854
+ }
1855
+ }
1856
+ return false;
1857
+ }
1858
+ function applyLanguageEffect(language, deps) {
1859
+ const settingsPath = getUserSettingsPath();
1860
+ const settings = readSettings(settingsPath);
1861
+ settings.language = language;
1862
+ writeSettings(settingsPath, settings);
1863
+ deps.addEntry(
1864
+ messageToHistoryEntry3(createSystemMessage3(`Language set to "${language}". Restarting...`))
1865
+ );
1866
+ deps.requestShutdown("other", "Language change restart");
1867
+ }
1868
+ function applySettingsResetEffect(deps) {
1869
+ const settingsPath = getUserSettingsPath();
1870
+ if (deleteSettings(settingsPath)) {
1871
+ deps.addEntry(
1872
+ messageToHistoryEntry3(createSystemMessage3(`Deleted ${settingsPath}. Exiting...`))
1873
+ );
1874
+ } else {
1875
+ deps.addEntry(messageToHistoryEntry3(createSystemMessage3("No user settings found.")));
1876
+ }
1877
+ deps.requestShutdown("other", "Reset settings restart");
1878
+ }
1879
+
1880
+ // src/ui/hooks/model-change-side-effect.ts
1881
+ import {
1882
+ createSystemMessage as createSystemMessage4,
1883
+ getModelName,
1884
+ messageToHistoryEntry as messageToHistoryEntry4
1885
+ } from "@robota-sdk/agent-core";
1886
+ function formatModelChangeConfirmationMessage(modelId) {
1887
+ return `Change model to ${getModelName(modelId)}? This will exit the current session so the next session uses it.`;
1888
+ }
1889
+ function formatModelChangeExitMessage(modelId) {
1890
+ return `Model changed to ${getModelName(modelId)}. Exiting so the next session uses it.`;
1891
+ }
1892
+ function applyConfirmedModelChange(deps) {
1893
+ const applyModelChange = deps.applyModelChange ?? applyActiveModelChange;
1894
+ const options = deps.providerOverride !== void 0 ? { providerOverride: deps.providerOverride } : void 0;
1895
+ try {
1896
+ applyModelChange(deps.cwd, deps.modelId, options);
1897
+ deps.addEntry(
1898
+ messageToHistoryEntry4(createSystemMessage4(formatModelChangeExitMessage(deps.modelId)))
1899
+ );
1900
+ deps.requestShutdown("other", "Model change applied");
1901
+ } catch (error) {
1902
+ deps.addEntry(
1903
+ messageToHistoryEntry4(
1904
+ createSystemMessage4(`Failed: ${error instanceof Error ? error.message : String(error)}`)
1905
+ )
1906
+ );
1907
+ }
1908
+ }
1909
+ function addModelChangeCancelledMessage(addEntry) {
1910
+ addEntry(messageToHistoryEntry4(createSystemMessage4("Model change cancelled.")));
1911
+ }
1912
+
2049
1913
  // src/ui/hooks/useSideEffects.ts
2050
1914
  var EXIT_DELAY_MS = 500;
2051
1915
  function useSideEffects({
2052
1916
  cwd,
1917
+ providerOverride,
2053
1918
  interactiveSession,
2054
1919
  addEntry,
2055
1920
  baseHandleSubmit,
2056
1921
  setSessionName,
2057
- setStatusLineSettings,
2058
- providerDefinitions
1922
+ setStatusLineSettings
2059
1923
  }) {
2060
1924
  const { exit } = useApp();
2061
1925
  const [pendingModelId, setPendingModelId] = useState2(null);
2062
1926
  const pendingModelChangeRef = useRef2(null);
2063
- const [pendingProviderProfile, setPendingProviderProfile] = useState2(null);
2064
- const pendingProviderProfileRef = useRef2(null);
2065
1927
  const [pendingInteractionPrompt, setPendingInteractionPrompt] = useState2(null);
2066
- const providerSetupInteractionRef = useRef2(null);
1928
+ const commandInteractionRef = useRef2(null);
2067
1929
  const [showPluginTUI, setShowPluginTUI] = useState2(false);
2068
1930
  const [showSessionPicker, setShowSessionPicker] = useState2(false);
2069
1931
  const requestShutdown = useCallback3(
2070
1932
  (reason, message) => {
2071
- addEntry(messageToHistoryEntry3(createSystemMessage3("Shutting down...")));
1933
+ addEntry(messageToHistoryEntry5(createSystemMessage5("Shutting down...")));
2072
1934
  setTimeout(() => {
2073
1935
  void interactiveSession.shutdown({ reason, message }).finally(() => exit());
2074
1936
  }, EXIT_DELAY_MS);
2075
1937
  },
2076
1938
  [interactiveSession, addEntry, exit]
2077
1939
  );
1940
+ const applyEffects = useCallback3(
1941
+ (effects, sideEffects) => applyCommandEffects(effects, sideEffects, {
1942
+ addEntry,
1943
+ requestShutdown,
1944
+ requestModelChange: (modelId) => {
1945
+ pendingModelChangeRef.current = modelId;
1946
+ setPendingModelId(modelId);
1947
+ },
1948
+ openPluginTUI: () => setShowPluginTUI(true),
1949
+ openSessionPicker: () => setShowSessionPicker(true),
1950
+ renameSession: (name) => {
1951
+ interactiveSession.setName(name);
1952
+ setSessionName(name);
1953
+ },
1954
+ applyStatusLinePatch: () => applyPendingStatusLinePatch(sideEffects, setStatusLineSettings)
1955
+ }),
1956
+ [addEntry, interactiveSession, requestShutdown, setSessionName, setStatusLineSettings]
1957
+ );
1958
+ const applyCommandResult = useCallback3(
1959
+ (result) => {
1960
+ if (result.message.length > 0) {
1961
+ addEntry(messageToHistoryEntry5(createSystemMessage5(result.message)));
1962
+ }
1963
+ if (result.interaction !== void 0) {
1964
+ commandInteractionRef.current = result.interaction;
1965
+ setPendingInteractionPrompt(result.interaction.prompt);
1966
+ return;
1967
+ }
1968
+ commandInteractionRef.current = null;
1969
+ setPendingInteractionPrompt(null);
1970
+ if (result.effects !== void 0 && result.effects.length > 0) {
1971
+ applyEffects(result.effects, interactiveSession);
1972
+ }
1973
+ },
1974
+ [addEntry, applyEffects, interactiveSession]
1975
+ );
1976
+ const applyQueuedCommandState = useCallback3(
1977
+ (sideEffects) => {
1978
+ if (sideEffects._pendingCommandInteraction !== void 0) {
1979
+ const interaction = sideEffects._pendingCommandInteraction;
1980
+ delete sideEffects._pendingCommandInteraction;
1981
+ commandInteractionRef.current = interaction;
1982
+ setPendingInteractionPrompt(interaction.prompt);
1983
+ return true;
1984
+ }
1985
+ if (sideEffects._pendingCommandEffects !== void 0) {
1986
+ const effects = sideEffects._pendingCommandEffects;
1987
+ delete sideEffects._pendingCommandEffects;
1988
+ return applyEffects(effects, sideEffects);
1989
+ }
1990
+ return false;
1991
+ },
1992
+ [applyEffects]
1993
+ );
2078
1994
  const handleSubmit = useCallback3(
2079
1995
  async (input) => {
2080
1996
  await baseHandleSubmit(input);
2081
1997
  const sideEffects = interactiveSession;
1998
+ if (applyQueuedCommandState(sideEffects)) return;
2082
1999
  if (sideEffects._pendingModelId) {
2083
2000
  const modelId = sideEffects._pendingModelId;
2084
2001
  delete sideEffects._pendingModelId;
@@ -2086,69 +2003,25 @@ function useSideEffects({
2086
2003
  setPendingModelId(modelId);
2087
2004
  return;
2088
2005
  }
2089
- if (sideEffects._pendingLanguage) {
2090
- const lang = sideEffects._pendingLanguage;
2091
- delete sideEffects._pendingLanguage;
2092
- const settingsPath = getUserSettingsPath();
2093
- const settings = readSettings(settingsPath);
2094
- settings.language = lang;
2095
- writeSettings(settingsPath, settings);
2096
- addEntry(
2097
- messageToHistoryEntry3(createSystemMessage3(`Language set to "${lang}". Restarting...`))
2098
- );
2099
- requestShutdown("other", "Language change restart");
2100
- return;
2101
- }
2102
- if (sideEffects._pendingProviderProfile) {
2103
- const profile = sideEffects._pendingProviderProfile;
2104
- delete sideEffects._pendingProviderProfile;
2105
- pendingProviderProfileRef.current = profile;
2106
- setPendingProviderProfile(profile);
2107
- return;
2108
- }
2109
- if (sideEffects._pendingProviderSetup !== void 0) {
2110
- const setup = sideEffects._pendingProviderSetup;
2111
- delete sideEffects._pendingProviderSetup;
2112
- const result = startProviderSetupInteraction(providerDefinitions, setup.type);
2113
- if (result.status === "prompt") {
2114
- providerSetupInteractionRef.current = result.state;
2115
- setPendingInteractionPrompt(result.prompt);
2116
- }
2117
- return;
2118
- }
2119
2006
  if (sideEffects._resetRequested) {
2120
2007
  delete sideEffects._resetRequested;
2121
- const settingsPath = getUserSettingsPath();
2122
- if (deleteSettings(settingsPath)) {
2123
- addEntry(
2124
- messageToHistoryEntry3(createSystemMessage3(`Deleted ${settingsPath}. Exiting...`))
2125
- );
2126
- } else {
2127
- addEntry(messageToHistoryEntry3(createSystemMessage3("No user settings found.")));
2128
- }
2129
- requestShutdown("other", "Reset settings restart");
2008
+ applyEffects([{ type: "settings-reset-requested" }], sideEffects);
2130
2009
  return;
2131
2010
  }
2132
2011
  if (sideEffects._exitRequested) {
2133
2012
  delete sideEffects._exitRequested;
2134
- requestShutdown("prompt_input_exit", "User requested exit");
2135
- return;
2136
- }
2137
- if (sideEffects._triggerPluginTUI) {
2138
- delete sideEffects._triggerPluginTUI;
2139
- setShowPluginTUI(true);
2013
+ applyEffects([{ type: "session-exit-requested" }], sideEffects);
2140
2014
  return;
2141
2015
  }
2142
2016
  if (sideEffects._triggerResumePicker) {
2143
2017
  delete sideEffects._triggerResumePicker;
2144
- setShowSessionPicker(true);
2018
+ applyEffects([{ type: "session-picker-requested" }], sideEffects);
2145
2019
  return;
2146
2020
  }
2147
2021
  if (sideEffects._sessionName) {
2148
2022
  const name = sideEffects._sessionName;
2149
2023
  delete sideEffects._sessionName;
2150
- interactiveSession.setName(name);
2151
- setSessionName(name);
2024
+ applyEffects([{ type: "session-renamed", name }], sideEffects);
2152
2025
  return;
2153
2026
  }
2154
2027
  if (applyPendingStatusLinePatch(sideEffects, setStatusLineSettings)) return;
@@ -2156,11 +2029,9 @@ function useSideEffects({
2156
2029
  [
2157
2030
  interactiveSession,
2158
2031
  baseHandleSubmit,
2159
- addEntry,
2160
- requestShutdown,
2161
- setSessionName,
2162
- setStatusLineSettings,
2163
- providerDefinitions
2032
+ applyQueuedCommandState,
2033
+ applyEffects,
2034
+ setStatusLineSettings
2164
2035
  ]
2165
2036
  );
2166
2037
  const handleModelConfirm = useCallback3(
@@ -2169,117 +2040,60 @@ function useSideEffects({
2169
2040
  setPendingModelId(null);
2170
2041
  pendingModelChangeRef.current = null;
2171
2042
  if (index === 0 && modelId) {
2172
- try {
2173
- const settingsPath = getUserSettingsPath();
2174
- updateModelInSettings(settingsPath, modelId);
2175
- addEntry(
2176
- messageToHistoryEntry3(
2177
- createSystemMessage3(`Model changed to ${getModelName(modelId)}. Restarting...`)
2178
- )
2179
- );
2180
- requestShutdown("other", "Model change restart");
2181
- } catch (err) {
2182
- addEntry(
2183
- messageToHistoryEntry3(
2184
- createSystemMessage3(`Failed: ${err instanceof Error ? err.message : String(err)}`)
2185
- )
2186
- );
2187
- }
2188
- } else {
2189
- addEntry(messageToHistoryEntry3(createSystemMessage3("Model change cancelled.")));
2190
- }
2191
- },
2192
- [addEntry, requestShutdown]
2193
- );
2194
- const handleProviderConfirm = useCallback3(
2195
- (index) => {
2196
- const profile = pendingProviderProfileRef.current;
2197
- setPendingProviderProfile(null);
2198
- pendingProviderProfileRef.current = null;
2199
- if (index === 0 && profile) {
2200
- try {
2201
- const settingsPath = getUserSettingsPath();
2202
- applyProviderSwitch(settingsPath, profile, {
2203
- knownProviders: readMergedProviderSettings(cwd).providers
2204
- });
2205
- addEntry(
2206
- messageToHistoryEntry3(
2207
- createSystemMessage3(`Provider changed to ${profile}. Restarting...`)
2208
- )
2209
- );
2210
- requestShutdown("other", "Provider change restart");
2211
- } catch (err) {
2212
- addEntry(
2213
- messageToHistoryEntry3(
2214
- createSystemMessage3(`Failed: ${err instanceof Error ? err.message : String(err)}`)
2215
- )
2216
- );
2217
- }
2043
+ applyConfirmedModelChange({
2044
+ cwd,
2045
+ modelId,
2046
+ providerOverride,
2047
+ addEntry,
2048
+ requestShutdown
2049
+ });
2218
2050
  } else {
2219
- addEntry(messageToHistoryEntry3(createSystemMessage3("Provider change cancelled.")));
2051
+ addModelChangeCancelledMessage(addEntry);
2220
2052
  }
2221
2053
  },
2222
- [cwd, addEntry, requestShutdown]
2223
- );
2224
- const completeProviderSetup = useCallback3(
2225
- (input) => {
2226
- providerSetupInteractionRef.current = null;
2227
- setPendingInteractionPrompt(null);
2228
- try {
2229
- const settingsPath = getUserSettingsPath();
2230
- applyProviderConfiguration(settingsPath, input, { providerDefinitions });
2231
- addEntry(
2232
- messageToHistoryEntry3(
2233
- createSystemMessage3(`Provider ${input.profile} configured. Restarting...`)
2234
- )
2235
- );
2236
- requestShutdown("other", "Provider setup restart");
2237
- } catch (err) {
2238
- addEntry(
2239
- messageToHistoryEntry3(
2240
- createSystemMessage3(`Failed: ${err instanceof Error ? err.message : String(err)}`)
2241
- )
2242
- );
2243
- }
2244
- },
2245
- [addEntry, requestShutdown, providerDefinitions]
2054
+ [cwd, providerOverride, addEntry, requestShutdown]
2246
2055
  );
2247
2056
  const handleInteractionSubmit = useCallback3(
2248
- (value) => {
2249
- const state = providerSetupInteractionRef.current;
2250
- if (state === null) {
2057
+ async (value) => {
2058
+ const interaction = commandInteractionRef.current;
2059
+ if (interaction === null) {
2251
2060
  setPendingInteractionPrompt(null);
2252
2061
  return;
2253
2062
  }
2254
2063
  try {
2255
- const result = submitProviderSetupInteractionValue(state, value);
2256
- if (result.status === "complete") {
2257
- completeProviderSetup(result.input);
2258
- return;
2259
- }
2260
- providerSetupInteractionRef.current = result.state;
2261
- setPendingInteractionPrompt(result.prompt);
2064
+ const result = await interaction.submit(value);
2065
+ applyCommandResult(result);
2262
2066
  } catch (err) {
2263
- providerSetupInteractionRef.current = null;
2067
+ commandInteractionRef.current = null;
2264
2068
  setPendingInteractionPrompt(null);
2265
2069
  addEntry(
2266
- messageToHistoryEntry3(
2267
- createSystemMessage3(`Failed: ${err instanceof Error ? err.message : String(err)}`)
2070
+ messageToHistoryEntry5(
2071
+ createSystemMessage5(`Failed: ${err instanceof Error ? err.message : String(err)}`)
2268
2072
  )
2269
2073
  );
2270
2074
  }
2271
2075
  },
2272
- [addEntry, completeProviderSetup]
2076
+ [addEntry, applyCommandResult]
2273
2077
  );
2274
2078
  const handleInteractionCancel = useCallback3(() => {
2275
- providerSetupInteractionRef.current = null;
2079
+ const interaction = commandInteractionRef.current;
2080
+ commandInteractionRef.current = null;
2276
2081
  setPendingInteractionPrompt(null);
2277
- addEntry(messageToHistoryEntry3(createSystemMessage3("Provider setup cancelled.")));
2278
- }, [addEntry]);
2082
+ if (interaction?.cancel === void 0) {
2083
+ addEntry(messageToHistoryEntry5(createSystemMessage5("Command interaction cancelled.")));
2084
+ return;
2085
+ }
2086
+ Promise.resolve(interaction.cancel()).then((result) => applyCommandResult(result)).catch((err) => {
2087
+ addEntry(
2088
+ messageToHistoryEntry5(
2089
+ createSystemMessage5(`Failed: ${err instanceof Error ? err.message : String(err)}`)
2090
+ )
2091
+ );
2092
+ });
2093
+ }, [addEntry, applyCommandResult]);
2279
2094
  return {
2280
2095
  handleSubmit,
2281
2096
  pendingModelId,
2282
- pendingProviderProfile,
2283
2097
  pendingInteractionPrompt,
2284
2098
  showPluginTUI,
2285
2099
  showSessionPicker,
@@ -2287,7 +2101,6 @@ function useSideEffects({
2287
2101
  setShowPluginTUI,
2288
2102
  setShowSessionPicker,
2289
2103
  handleModelConfirm,
2290
- handleProviderConfirm,
2291
2104
  handleInteractionSubmit,
2292
2105
  handleInteractionCancel
2293
2106
  };
@@ -2960,6 +2773,21 @@ function StatusLeft({
2960
2773
  )
2961
2774
  ] });
2962
2775
  }
2776
+ function StatusRight({
2777
+ isThinking,
2778
+ messageCount
2779
+ }) {
2780
+ return /* @__PURE__ */ jsxs5(Text5, { children: [
2781
+ isThinking && /* @__PURE__ */ jsxs5(Fragment3, { children: [
2782
+ /* @__PURE__ */ jsx5(Text5, { color: "yellow", children: "thinking..." }),
2783
+ " "
2784
+ ] }),
2785
+ /* @__PURE__ */ jsxs5(Text5, { dimColor: true, children: [
2786
+ "msgs: ",
2787
+ messageCount
2788
+ ] })
2789
+ ] });
2790
+ }
2963
2791
  function StatusBar({
2964
2792
  permissionMode,
2965
2793
  modelName,
@@ -3002,10 +2830,7 @@ function StatusBar({
3002
2830
  showGitBranch
3003
2831
  }
3004
2832
  ),
3005
- /* @__PURE__ */ jsx5(Text5, { children: /* @__PURE__ */ jsxs5(Text5, { dimColor: true, children: [
3006
- "msgs: ",
3007
- messageCount
3008
- ] }) })
2833
+ /* @__PURE__ */ jsx5(StatusRight, { isThinking, messageCount })
3009
2834
  ]
3010
2835
  }
3011
2836
  );
@@ -4264,32 +4089,43 @@ function getToolStyle(t) {
4264
4089
  if (t.result === "denied") return { color: "yellowBright", icon: "\u2298", strikethrough: true };
4265
4090
  return { color: "green", icon: "\u2713", strikethrough: false };
4266
4091
  }
4267
- function StreamingIndicator({ text, activeTools }) {
4092
+ function renderThinkingFallback(isThinking) {
4093
+ if (!isThinking) return /* @__PURE__ */ jsx16(Fragment4, {});
4094
+ return /* @__PURE__ */ jsx16(Box13, { marginBottom: 1, children: /* @__PURE__ */ jsx16(Text15, { color: "yellow", children: "Thinking..." }) });
4095
+ }
4096
+ function renderTools(activeTools) {
4097
+ return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", marginBottom: 1, children: [
4098
+ /* @__PURE__ */ jsx16(Text15, { color: "white", bold: true, children: "Tools:" }),
4099
+ /* @__PURE__ */ jsx16(Text15, { children: " " }),
4100
+ activeTools.map((t, i) => {
4101
+ const { color, icon, strikethrough } = getToolStyle(t);
4102
+ return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", children: [
4103
+ /* @__PURE__ */ jsxs13(Text15, { color, strikethrough, children: [
4104
+ " ",
4105
+ icon,
4106
+ " ",
4107
+ t.toolName,
4108
+ "(",
4109
+ t.firstArg,
4110
+ ")"
4111
+ ] }),
4112
+ t.diffLines && t.diffLines.length > 0 && /* @__PURE__ */ jsx16(ToolDiffBlock, { file: t.diffFile, lines: t.diffLines })
4113
+ ] }, `${t.toolName}-${i}`);
4114
+ })
4115
+ ] });
4116
+ }
4117
+ function StreamingIndicator({
4118
+ text,
4119
+ activeTools,
4120
+ isThinking = false
4121
+ }) {
4268
4122
  const hasTools = activeTools.length > 0;
4269
4123
  const hasText = text.length > 0;
4270
4124
  if (!hasTools && !hasText) {
4271
- return /* @__PURE__ */ jsx16(Fragment4, {});
4125
+ return renderThinkingFallback(isThinking);
4272
4126
  }
4273
4127
  return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", children: [
4274
- hasTools && /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", marginBottom: 1, children: [
4275
- /* @__PURE__ */ jsx16(Text15, { color: "white", bold: true, children: "Tools:" }),
4276
- /* @__PURE__ */ jsx16(Text15, { children: " " }),
4277
- activeTools.map((t, i) => {
4278
- const { color, icon, strikethrough } = getToolStyle(t);
4279
- return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", children: [
4280
- /* @__PURE__ */ jsxs13(Text15, { color, strikethrough, children: [
4281
- " ",
4282
- icon,
4283
- " ",
4284
- t.toolName,
4285
- "(",
4286
- t.firstArg,
4287
- ")"
4288
- ] }),
4289
- t.diffLines && t.diffLines.length > 0 && /* @__PURE__ */ jsx16(ToolDiffBlock, { file: t.diffFile, lines: t.diffLines })
4290
- ] }, `${t.toolName}-${i}`);
4291
- })
4292
- ] }),
4128
+ hasTools && renderTools(activeTools),
4293
4129
  hasText && /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", marginBottom: 1, children: [
4294
4130
  /* @__PURE__ */ jsx16(Text15, { color: "cyan", bold: true, children: "Robota:" }),
4295
4131
  /* @__PURE__ */ jsx16(Text15, { children: " " }),
@@ -4812,9 +4648,14 @@ function getTaskSegments(task, now) {
4812
4648
  if (task.signalCode) {
4813
4649
  segments.push(`signal ${task.signalCode}`);
4814
4650
  }
4651
+ if (task.worktreePath || task.branchName) {
4652
+ segments.push("worktree");
4653
+ }
4815
4654
  return segments;
4816
4655
  }
4817
4656
  function getTaskPreview(task) {
4657
+ if (task.worktreeNextAction) return task.worktreeNextAction;
4658
+ if (task.worktreePath) return task.worktreePath;
4818
4659
  const preview = task.errorPreview ?? task.resultPreview ?? task.currentAction ?? task.preview;
4819
4660
  return preview || void 0;
4820
4661
  }
@@ -5142,7 +4983,6 @@ function App(props) {
5142
4983
  }
5143
4984
  function AppInner(props) {
5144
4985
  const cwd = props.cwd;
5145
- const providerDefinitions = props.providerDefinitions ?? [];
5146
4986
  const {
5147
4987
  interactiveSession,
5148
4988
  registry,
@@ -5173,9 +5013,10 @@ function AppInner(props) {
5173
5013
  backgroundTaskRunners: props.backgroundTaskRunners,
5174
5014
  subagentRunnerFactory: props.subagentRunnerFactory,
5175
5015
  commandModules: props.commandModules,
5176
- providerDefinitions
5016
+ commandHostAdapters: props.commandHostAdapters
5177
5017
  });
5178
- const pluginCallbacks = usePluginCallbacks(cwd);
5018
+ const fallbackPluginCallbacks = usePluginCallbacks(cwd);
5019
+ const pluginCallbacks = props.commandHostAdapters?.plugin ?? fallbackPluginCallbacks;
5179
5020
  const { exit } = useApp2();
5180
5021
  const [sessionName, setSessionName] = useState14(props.sessionName);
5181
5022
  const [updateNotice, setUpdateNotice] = useState14();
@@ -5186,24 +5027,22 @@ function AppInner(props) {
5186
5027
  const {
5187
5028
  handleSubmit,
5188
5029
  pendingModelId,
5189
- pendingProviderProfile,
5190
5030
  pendingInteractionPrompt,
5191
5031
  showPluginTUI,
5192
5032
  showSessionPicker,
5193
5033
  setShowPluginTUI,
5194
5034
  setShowSessionPicker,
5195
5035
  handleModelConfirm,
5196
- handleProviderConfirm,
5197
5036
  handleInteractionSubmit,
5198
5037
  handleInteractionCancel
5199
5038
  } = useSideEffects({
5200
5039
  cwd,
5040
+ providerOverride: props.providerOverride,
5201
5041
  interactiveSession,
5202
5042
  addEntry,
5203
5043
  baseHandleSubmit,
5204
5044
  setSessionName,
5205
- setStatusLineSettings,
5206
- providerDefinitions
5045
+ setStatusLineSettings
5207
5046
  });
5208
5047
  useEffect4(() => {
5209
5048
  const name = interactiveSession?.getName?.();
@@ -5272,24 +5111,24 @@ function AppInner(props) {
5272
5111
  /* @__PURE__ */ jsxs17(Box18, { flexDirection: "column", paddingX: 1, flexGrow: 1, children: [
5273
5112
  /* @__PURE__ */ jsx22(MessageList, { history }),
5274
5113
  isShuttingDown && /* @__PURE__ */ jsx22(Box18, { marginBottom: 1, children: /* @__PURE__ */ jsx22(Text20, { color: "yellow", children: "Shutting down..." }) }),
5275
- (isThinking || activeTools.length > 0) && /* @__PURE__ */ jsx22(Box18, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsx22(StreamingIndicator, { text: streamingText, activeTools }) }),
5114
+ (isThinking || activeTools.length > 0) && /* @__PURE__ */ jsx22(Box18, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsx22(
5115
+ StreamingIndicator,
5116
+ {
5117
+ text: streamingText,
5118
+ activeTools,
5119
+ isThinking
5120
+ }
5121
+ ) }),
5276
5122
  /* @__PURE__ */ jsx22(BackgroundTaskPanel, { tasks: backgroundTasks })
5277
5123
  ] }),
5278
5124
  permissionRequest && /* @__PURE__ */ jsx22(PermissionPrompt, { request: permissionRequest }),
5279
5125
  pendingModelId && /* @__PURE__ */ jsx22(
5280
5126
  ConfirmPrompt,
5281
5127
  {
5282
- message: `Change model to ${getModelName3(pendingModelId)}? This will restart the session.`,
5128
+ message: formatModelChangeConfirmationMessage(pendingModelId),
5283
5129
  onSelect: handleModelConfirm
5284
5130
  }
5285
5131
  ),
5286
- pendingProviderProfile && /* @__PURE__ */ jsx22(
5287
- ConfirmPrompt,
5288
- {
5289
- message: `Change provider to ${pendingProviderProfile}? This will restart the session.`,
5290
- onSelect: handleProviderConfirm
5291
- }
5292
- ),
5293
5132
  pendingInteractionPrompt && /* @__PURE__ */ jsx22(
5294
5133
  InteractivePrompt,
5295
5134
  {
@@ -5303,7 +5142,7 @@ function AppInner(props) {
5303
5142
  {
5304
5143
  callbacks: pluginCallbacks,
5305
5144
  onClose: () => setShowPluginTUI(false),
5306
- addMessage: (msg) => addEntry(messageToHistoryEntry4(createSystemMessage4(msg.content)))
5145
+ addMessage: (msg) => addEntry(messageToHistoryEntry6(createSystemMessage6(msg.content)))
5307
5146
  }
5308
5147
  ),
5309
5148
  showSessionPicker && /* @__PURE__ */ jsx22(
@@ -5317,7 +5156,7 @@ function AppInner(props) {
5317
5156
  },
5318
5157
  onCancel: () => {
5319
5158
  setShowSessionPicker(false);
5320
- addEntry(messageToHistoryEntry4(createSystemMessage4("Session resume cancelled.")));
5159
+ addEntry(messageToHistoryEntry6(createSystemMessage6("Session resume cancelled.")));
5321
5160
  }
5322
5161
  }
5323
5162
  ),
@@ -5382,93 +5221,6 @@ function renderApp(options) {
5382
5221
  });
5383
5222
  }
5384
5223
 
5385
- // src/commands/statusline-command-module.ts
5386
- var USAGE = [
5387
- "Usage: /statusline on | off | reset | git on | git off",
5388
- "Fields: model, context, permission mode, message count, session name, thinking state, git branch."
5389
- ].join("\n");
5390
- function createStatusLineEntry() {
5391
- return {
5392
- name: "statusline",
5393
- description: "Configure TUI status-line visibility and fields such as model, context, tokens, session, and git branch.",
5394
- source: "cli",
5395
- modelInvocable: false,
5396
- argumentHint: "on | off | reset | git on | git off",
5397
- subcommands: [
5398
- { name: "on", description: "Show the status line", source: "cli" },
5399
- { name: "off", description: "Hide the status line", source: "cli" },
5400
- { name: "reset", description: "Restore default status-line fields", source: "cli" },
5401
- { name: "git", description: "Show or hide git branch field", source: "cli" }
5402
- ]
5403
- };
5404
- }
5405
- function parseStatusLineArgs(args) {
5406
- const parts = args.trim().toLowerCase().split(/\s+/).filter((part) => part.length > 0);
5407
- const [first, second] = parts;
5408
- if (first === "on" && second === void 0) {
5409
- return { success: true, message: "Status line enabled.", patch: { enabled: true } };
5410
- }
5411
- if (first === "off" && second === void 0) {
5412
- return { success: true, message: "Status line disabled.", patch: { enabled: false } };
5413
- }
5414
- if (first === "reset" && second === void 0) {
5415
- return {
5416
- success: true,
5417
- message: "Status line settings reset.",
5418
- patch: { enabled: true, gitBranch: true }
5419
- };
5420
- }
5421
- if (first === "git" && second === "on" && parts.length === 2) {
5422
- return {
5423
- success: true,
5424
- message: "Status line git branch shown.",
5425
- patch: { gitBranch: true }
5426
- };
5427
- }
5428
- if (first === "git" && second === "off" && parts.length === 2) {
5429
- return {
5430
- success: true,
5431
- message: "Status line git branch hidden.",
5432
- patch: { gitBranch: false }
5433
- };
5434
- }
5435
- return { success: false, message: USAGE };
5436
- }
5437
- function createStatusLineSystemCommand() {
5438
- const entry = createStatusLineEntry();
5439
- return {
5440
- name: entry.name,
5441
- description: entry.description,
5442
- modelInvocable: false,
5443
- userInvocable: true,
5444
- argumentHint: entry.argumentHint,
5445
- execute: (_session, args) => {
5446
- const action = parseStatusLineArgs(args);
5447
- if (!action.success) {
5448
- return { success: false, message: action.message };
5449
- }
5450
- return {
5451
- success: true,
5452
- message: action.message,
5453
- data: { statuslinePatch: action.patch }
5454
- };
5455
- }
5456
- };
5457
- }
5458
- var StatusLineCommandSource = class {
5459
- name = "cli-statusline";
5460
- getCommands() {
5461
- return [createStatusLineEntry()];
5462
- }
5463
- };
5464
- function createStatusLineCommandModule() {
5465
- return {
5466
- name: "cli-statusline",
5467
- commandSources: [new StatusLineCommandSource()],
5468
- systemCommands: [createStatusLineSystemCommand()]
5469
- };
5470
- }
5471
-
5472
5224
  // src/cli.ts
5473
5225
  function readVersion() {
5474
5226
  try {
@@ -5559,9 +5311,39 @@ async function startCli(options = {}) {
5559
5311
  return;
5560
5312
  }
5561
5313
  const cwd = process.cwd();
5314
+ const commandHostAdapters = {
5315
+ settings: {
5316
+ read: () => readSettings(getUserSettingsPath()),
5317
+ write: (settings) => writeSettings(getUserSettingsPath(), settings)
5318
+ },
5319
+ plugin: createCliPluginCommandAdapter(cwd)
5320
+ };
5562
5321
  const providerDefinitions = options.providerDefinitions ?? DEFAULT_PROVIDER_DEFINITIONS;
5563
5322
  const commandModules = [
5323
+ createHelpCommandModule(),
5324
+ createAgentCommandModule(),
5325
+ createModelCommandModule(),
5326
+ createModeCommandModule(),
5327
+ createPermissionsCommandModule(),
5328
+ createLanguageCommandModule(),
5329
+ createBackgroundCommandModule(),
5330
+ createMemoryCommandModule(),
5331
+ createCompactCommandModule(),
5332
+ createContextCommandModule(),
5333
+ createExitCommandModule(),
5334
+ createSessionCommandModule(),
5335
+ createResetCommandModule(),
5336
+ createRewindCommandModule(),
5564
5337
  createStatusLineCommandModule(),
5338
+ createPluginCommandModule(),
5339
+ createProviderCommandModule({
5340
+ providerDefinitions,
5341
+ settings: {
5342
+ readMergedSettings: () => readMergedProviderSettings(cwd),
5343
+ readTargetSettings: () => readSettings(getUserSettingsPath()),
5344
+ writeTargetSettings: (settings) => writeSettings(getUserSettingsPath(), settings)
5345
+ }
5346
+ }),
5565
5347
  ...options.commandModules ?? []
5566
5348
  ];
5567
5349
  const startupUpdateNoticePromise = shouldRunStartupCliUpdateCheck(args) ? getStartupCliUpdateNotice({ currentVersion: version }) : void 0;
@@ -5644,7 +5426,8 @@ ${args.jsonSchema}`
5644
5426
  appendSystemPrompt,
5645
5427
  backgroundTaskRunners,
5646
5428
  subagentRunnerFactory,
5647
- commandModules
5429
+ commandModules,
5430
+ commandHostAdapters
5648
5431
  });
5649
5432
  const transport = createHeadlessTransport({
5650
5433
  outputFormat: args.outputFormat ?? "text",
@@ -5658,6 +5441,7 @@ ${args.jsonSchema}`
5658
5441
  renderApp({
5659
5442
  cwd,
5660
5443
  provider,
5444
+ providerOverride: args.provider,
5661
5445
  modelId,
5662
5446
  language: args.language,
5663
5447
  permissionMode: args.permissionMode,
@@ -5670,7 +5454,7 @@ ${args.jsonSchema}`
5670
5454
  backgroundTaskRunners,
5671
5455
  subagentRunnerFactory,
5672
5456
  commandModules,
5673
- providerDefinitions,
5457
+ commandHostAdapters,
5674
5458
  startupUpdateNoticePromise
5675
5459
  });
5676
5460
  }