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

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,55 +3,30 @@ import {
3
3
  createProviderFromSettings,
4
4
  findProviderDefinition,
5
5
  formatSupportedProviderTypes,
6
+ getProviderCredentialRequirement,
6
7
  getProviderSettingsPaths,
7
8
  hasUsableSecretReference,
8
9
  isSubagentWorkerChildMessage,
9
10
  readMergedProviderSettings,
10
11
  readMergedProviderSettingsFromPaths,
11
12
  readProviderSettings
12
- } from "./chunk-6XQKLNRF.js";
13
+ } from "./chunk-BENOH47A.js";
13
14
 
14
15
  // src/background/managed-shell-process-runner.ts
15
16
  import { spawn } from "child_process";
16
17
  import {
17
- BackgroundTaskError
18
+ BackgroundTaskError,
19
+ appendPrefixedLogLines,
20
+ createBackgroundTaskLogPage,
21
+ createLimitedOutputCapture
18
22
  } from "@robota-sdk/agent-sdk";
19
23
  var DEFAULT_OUTPUT_LIMIT_BYTES = 3e4;
20
24
  var DEFAULT_KILL_GRACE_MS = 2e3;
21
- var LOG_PAGE_SIZE = 200;
22
- function createCapture(limitBytes) {
23
- const chunks = [];
24
- let capturedBytes = 0;
25
- let truncated = false;
26
- return {
27
- appendOutput(text) {
28
- if (truncated) return;
29
- const remaining = limitBytes - capturedBytes;
30
- const buffer = Buffer.from(text, "utf8");
31
- if (buffer.byteLength <= remaining) {
32
- chunks.push(text);
33
- capturedBytes += buffer.byteLength;
34
- return;
35
- }
36
- chunks.push(buffer.subarray(0, Math.max(remaining, 0)).toString("utf8"));
37
- chunks.push("\n[output truncated]\n");
38
- truncated = true;
39
- },
40
- getOutput() {
41
- return chunks.join("");
42
- }
43
- };
44
- }
45
- function appendLog(lines, source, text) {
46
- for (const line of text.split(/\r?\n/)) {
47
- if (line.length > 0) lines.push(`[${source}] ${line}`);
48
- }
49
- }
50
25
  function resolveShell(request) {
51
26
  return { command: request.shell ?? "sh", args: ["-c", request.command] };
52
27
  }
53
28
  function sendInput(child, input) {
54
- return new Promise((resolve2, reject) => {
29
+ return new Promise((resolve3, reject) => {
55
30
  const onError = (error) => {
56
31
  child.stdin.off("error", onError);
57
32
  reject(error);
@@ -59,7 +34,7 @@ function sendInput(child, input) {
59
34
  child.stdin.once("error", onError);
60
35
  child.stdin.end(input, () => {
61
36
  child.stdin.off("error", onError);
62
- resolve2();
37
+ resolve3();
63
38
  });
64
39
  });
65
40
  }
@@ -86,7 +61,9 @@ function startProcessTask(taskId, request, killGraceMs) {
86
61
  stdio: ["pipe", "pipe", "pipe"]
87
62
  }),
88
63
  logs: [],
89
- capture: createCapture(request.outputLimitBytes ?? DEFAULT_OUTPUT_LIMIT_BYTES),
64
+ capture: createLimitedOutputCapture({
65
+ limitBytes: request.outputLimitBytes ?? DEFAULT_OUTPUT_LIMIT_BYTES
66
+ }),
90
67
  killGraceMs
91
68
  };
92
69
  const result = createProcessResult(runtime);
@@ -94,9 +71,13 @@ function startProcessTask(taskId, request, killGraceMs) {
94
71
  }
95
72
  function createProcessResult(runtime) {
96
73
  let settled = false;
97
- return new Promise((resolve2, reject) => {
74
+ return new Promise((resolve3, reject) => {
98
75
  const timeoutTimer = runtime.request.timeoutMs ? setTimeout(() => {
99
- appendLog(runtime.logs, "system", `timed out after ${runtime.request.timeoutMs}ms`);
76
+ appendPrefixedLogLines(
77
+ runtime.logs,
78
+ "system",
79
+ `timed out after ${runtime.request.timeoutMs}ms`
80
+ );
100
81
  runtime.child.kill("SIGTERM");
101
82
  rejectOnceLocal(new BackgroundTaskError("timeout", "Background process timed out"));
102
83
  }, runtime.request.timeoutMs) : void 0;
@@ -108,7 +89,7 @@ function createProcessResult(runtime) {
108
89
  if (settled) return;
109
90
  settled = true;
110
91
  clearTimers();
111
- resolve2({
92
+ resolve3({
112
93
  taskId: runtime.taskId,
113
94
  kind: "process",
114
95
  output: runtime.capture.getOutput(),
@@ -124,7 +105,7 @@ function createProcessResult(runtime) {
124
105
  }
125
106
  attachOutputListeners(runtime);
126
107
  runtime.child.on("error", (error) => {
127
- appendLog(runtime.logs, "system", error.message);
108
+ appendPrefixedLogLines(runtime.logs, "system", error.message);
128
109
  rejectOnceLocal(new BackgroundTaskError("process", error.message));
129
110
  });
130
111
  runtime.child.on("close", (code, signal) => {
@@ -155,30 +136,27 @@ function attachOutputListeners(runtime) {
155
136
  runtime.child.stdout.on("data", (chunk) => {
156
137
  const text = chunk.toString("utf8");
157
138
  runtime.capture.appendOutput(text);
158
- appendLog(runtime.logs, "stdout", text);
139
+ appendPrefixedLogLines(runtime.logs, "stdout", text);
159
140
  });
160
141
  runtime.child.stderr.on("data", (chunk) => {
161
142
  const text = chunk.toString("utf8");
162
143
  runtime.capture.appendOutput(text);
163
- appendLog(runtime.logs, "stderr", text);
144
+ appendPrefixedLogLines(runtime.logs, "stderr", text);
164
145
  });
165
146
  }
166
147
  function cancelProcess(runtime, reason) {
167
- appendLog(runtime.logs, "system", reason ? `cancel requested: ${reason}` : "cancel requested");
148
+ appendPrefixedLogLines(
149
+ runtime.logs,
150
+ "system",
151
+ reason ? `cancel requested: ${reason}` : "cancel requested"
152
+ );
168
153
  if (!runtime.child.killed) runtime.child.kill("SIGTERM");
169
154
  runtime.killTimer = setTimeout(() => {
170
155
  if (!runtime.child.killed) runtime.child.kill("SIGKILL");
171
156
  }, runtime.killGraceMs);
172
157
  }
173
158
  function readProcessLog(runtime, cursor) {
174
- const offset = cursor?.offset ?? 0;
175
- const nextOffset = Math.min(offset + LOG_PAGE_SIZE, runtime.logs.length);
176
- return {
177
- taskId: runtime.taskId,
178
- cursor,
179
- nextCursor: nextOffset < runtime.logs.length ? { offset: nextOffset } : void 0,
180
- lines: runtime.logs.slice(offset, nextOffset)
181
- };
159
+ return createBackgroundTaskLogPage(runtime.taskId, runtime.logs, cursor);
182
160
  }
183
161
 
184
162
  // src/subagents/git-worktree-isolation-adapter.ts
@@ -305,6 +283,7 @@ import { existsSync, readFileSync } from "fs";
305
283
  import { dirname, join as join2 } from "path";
306
284
  import {
307
285
  BackgroundTaskError as BackgroundTaskError5,
286
+ createBackgroundTaskLogPage as createBackgroundTaskLogPage2,
308
287
  getBuiltInAgent,
309
288
  createWorktreeSubagentRunner
310
289
  } from "@robota-sdk/agent-sdk";
@@ -360,7 +339,7 @@ function extractFirstArg(toolArgs) {
360
339
  return typeof firstValue === "object" ? JSON.stringify(firstValue) : String(firstValue);
361
340
  }
362
341
  function sendWorkerMessage(child, message) {
363
- return new Promise((resolve2, reject) => {
342
+ return new Promise((resolve3, reject) => {
364
343
  if (!child.connected) {
365
344
  reject(new BackgroundTaskError3("crash", "Subagent worker IPC channel is closed"));
366
345
  return;
@@ -370,7 +349,7 @@ function sendWorkerMessage(child, message) {
370
349
  reject(error);
371
350
  return;
372
351
  }
373
- resolve2();
352
+ resolve3();
374
353
  });
375
354
  });
376
355
  }
@@ -387,14 +366,14 @@ async function cancelChildProcess(runtime, reason) {
387
366
 
388
367
  // src/subagents/child-process-subagent-runner-result.ts
389
368
  function createChildProcessSubagentResult(options) {
390
- return new Promise((resolve2, reject) => {
391
- new ChildProcessSubagentResultController(options, resolve2, reject).start();
369
+ return new Promise((resolve3, reject) => {
370
+ new ChildProcessSubagentResultController(options, resolve3, reject).start();
392
371
  });
393
372
  }
394
373
  var ChildProcessSubagentResultController = class {
395
- constructor(options, resolve2, reject) {
374
+ constructor(options, resolve3, reject) {
396
375
  this.options = options;
397
- this.resolve = resolve2;
376
+ this.resolve = resolve3;
398
377
  this.reject = reject;
399
378
  this.timeoutTimer = createTimeoutTimer(this.options.runtime, (error) => this.rejectOnce(error));
400
379
  }
@@ -501,7 +480,6 @@ function formatEarlyExitMessage(code, signal) {
501
480
 
502
481
  // src/subagents/child-process-subagent-runner.ts
503
482
  var DEFAULT_KILL_GRACE_MS2 = 2e3;
504
- var LOG_PAGE_SIZE2 = 200;
505
483
  function createChildProcessSubagentRunnerFactory(options = {}) {
506
484
  return (deps) => {
507
485
  const runner = new ChildProcessSubagentRunner(deps, options);
@@ -639,7 +617,6 @@ function resolveDefaultExecArgv(workerPath) {
639
617
  return [...process.execArgv, "--import", "tsx"];
640
618
  }
641
619
  function readTranscriptLog(jobId, transcriptPath, cursor) {
642
- const offset = cursor?.offset ?? 0;
643
620
  if (!existsSync(transcriptPath)) {
644
621
  return {
645
622
  taskId: jobId,
@@ -648,18 +625,12 @@ function readTranscriptLog(jobId, transcriptPath, cursor) {
648
625
  };
649
626
  }
650
627
  const lines = readFileSync(transcriptPath, "utf8").split(/\r?\n/).filter(Boolean);
651
- const nextOffset = Math.min(offset + LOG_PAGE_SIZE2, lines.length);
652
- return {
653
- taskId: jobId,
654
- cursor,
655
- nextCursor: nextOffset < lines.length ? { offset: nextOffset } : void 0,
656
- lines: lines.slice(offset, nextOffset)
657
- };
628
+ return createBackgroundTaskLogPage2(jobId, lines, cursor);
658
629
  }
659
630
 
660
631
  // src/cli.ts
661
632
  import { readFileSync as readFileSync6 } from "fs";
662
- import { join as join9, dirname as dirname5 } from "path";
633
+ import { join as join9, dirname as dirname5, resolve as resolve2 } from "path";
663
634
  import { fileURLToPath } from "url";
664
635
  import { createAgentCommandModule } from "@robota-sdk/agent-command-agent";
665
636
  import { createBackgroundCommandModule } from "@robota-sdk/agent-command-background";
@@ -670,7 +641,6 @@ import { createExitCommandModule } from "@robota-sdk/agent-command-exit";
670
641
  import { createHelpCommandModule } from "@robota-sdk/agent-command-help";
671
642
  import { createLanguageCommandModule } from "@robota-sdk/agent-command-language";
672
643
  import { createMemoryCommandModule } from "@robota-sdk/agent-command-memory";
673
- import { createModeCommandModule } from "@robota-sdk/agent-command-mode";
674
644
  import { createModelCommandModule } from "@robota-sdk/agent-command-model";
675
645
  import { createPermissionsCommandModule } from "@robota-sdk/agent-command-permissions";
676
646
  import { createPluginCommandModule } from "@robota-sdk/agent-command-plugin";
@@ -678,8 +648,14 @@ import { createResetCommandModule } from "@robota-sdk/agent-command-reset";
678
648
  import { createRewindCommandModule } from "@robota-sdk/agent-command-rewind";
679
649
  import { createStatusLineCommandModule } from "@robota-sdk/agent-command-statusline";
680
650
  import { createSessionCommandModule } from "@robota-sdk/agent-command-session";
681
- import { InteractiveSession as InteractiveSession2, projectPaths } from "@robota-sdk/agent-sdk";
682
- import { SessionStore } from "@robota-sdk/agent-sessions";
651
+ import { createSkillsCommandModule } from "@robota-sdk/agent-command-skills";
652
+ import {
653
+ InteractiveSession as InteractiveSession2,
654
+ createProjectSessionStore,
655
+ projectPaths,
656
+ resolveLatestSessionId,
657
+ resolveSessionIdByIdOrName
658
+ } from "@robota-sdk/agent-sdk";
683
659
 
684
660
  // src/utils/cli-args.ts
685
661
  import { parseArgs } from "util";
@@ -719,6 +695,7 @@ function parseCliArgs() {
719
695
  "output-format": { type: "string" },
720
696
  "system-prompt": { type: "string" },
721
697
  "append-system-prompt": { type: "string" },
698
+ "task-file": { type: "string" },
722
699
  version: { type: "boolean", default: false },
723
700
  reset: { type: "boolean", default: false },
724
701
  bare: { type: "boolean", default: false },
@@ -752,6 +729,7 @@ function parseCliArgs() {
752
729
  outputFormat: values["output-format"],
753
730
  systemPrompt: values["system-prompt"],
754
731
  appendSystemPrompt: values["append-system-prompt"],
732
+ taskFile: values["task-file"],
755
733
  version: values["version"] ?? false,
756
734
  reset: values["reset"] ?? false,
757
735
  bare: values["bare"] ?? false,
@@ -824,23 +802,33 @@ function isUsableProviderProfile(type, profile, providerDefinitions) {
824
802
  if (!profile) {
825
803
  return false;
826
804
  }
827
- if (hasUsableSecretReference(profile.apiKey)) {
828
- return true;
829
- }
830
805
  if (!type) {
831
- return false;
806
+ return hasUsableSecretReference(profile.apiKey);
832
807
  }
833
808
  const definition = findProviderDefinition(providerDefinitions, type);
834
809
  if (definition === void 0) {
835
810
  return false;
836
811
  }
837
- return definition.requiresApiKey !== true || hasUsableSecretReference(definition.defaults?.apiKey);
812
+ const credentialRequirement = getProviderCredentialRequirement(definition);
813
+ if (credentialRequirement === void 0) {
814
+ return true;
815
+ }
816
+ return hasUsableRequiredProviderCredential(profile, definition, credentialRequirement);
817
+ }
818
+ function hasUsableRequiredProviderCredential(profile, definition, requirement) {
819
+ return requirement.anyOf.some(
820
+ (field) => hasUsableSecretReference(resolveProviderCredentialValue(field, profile, definition))
821
+ );
822
+ }
823
+ function resolveProviderCredentialValue(field, profile, definition) {
824
+ return profile[field] ?? definition.defaults?.[field];
838
825
  }
839
826
 
840
827
  // src/utils/provider-settings.ts
841
828
  import {
842
829
  buildProviderProfile,
843
830
  buildProviderSetupPatch,
831
+ deleteProviderProfile,
844
832
  mergeProviderPatch,
845
833
  setCurrentProvider,
846
834
  upsertProviderProfile,
@@ -848,6 +836,14 @@ import {
848
836
  } from "@robota-sdk/agent-sdk";
849
837
 
850
838
  // src/utils/provider-configuration.ts
839
+ function resolveProviderSettingsWriteTargetPath(cwd, options = {}) {
840
+ const settingsPaths = options.settingsPaths ?? getProviderSettingsPaths(cwd);
841
+ const targetPath = findLastPathWithCurrentProvider(settingsPaths) ?? settingsPaths[0];
842
+ if (targetPath === void 0) {
843
+ throw new Error("No settings path available for provider update");
844
+ }
845
+ return targetPath;
846
+ }
851
847
  function readProviderDocument(settingsPath) {
852
848
  return readSettings(settingsPath);
853
849
  }
@@ -930,11 +926,21 @@ function findLastPathWithLegacyProvider(settingsPaths) {
930
926
  }
931
927
  return void 0;
932
928
  }
929
+ function findLastPathWithCurrentProvider(settingsPaths) {
930
+ for (let index = settingsPaths.length - 1; index >= 0; index -= 1) {
931
+ const settingsPath = settingsPaths[index];
932
+ if (settingsPath === void 0) continue;
933
+ const settings = readProviderDocument(settingsPath);
934
+ if (settings.currentProvider !== void 0) return settingsPath;
935
+ }
936
+ return void 0;
937
+ }
933
938
 
934
939
  // src/utils/provider-setup-flow.ts
935
940
  import {
936
941
  createProviderSetupFlow,
937
942
  formatProviderSetupChoiceLabel,
943
+ formatProviderSetupHelpLinks,
938
944
  formatProviderSetupPromptLabel,
939
945
  formatProviderSetupSelectionPrompt,
940
946
  getProviderSetupStep,
@@ -965,7 +971,8 @@ function handleProviderConfigurationArgs(cwd, args, providerDefinitions = DEFAUL
965
971
  return !args.printMode && args.positional.length === 0;
966
972
  }
967
973
  if (args.provider && args.setCurrent) {
968
- applyProviderSwitch(settingsPath, args.provider, {
974
+ const switchSettingsPath = args.settingsScope === void 0 ? resolveProviderSettingsWriteTargetPath(cwd) : settingsPath;
975
+ applyProviderSwitch(switchSettingsPath, args.provider, {
969
976
  knownProviders: readMergedProviderSettings(cwd).providers
970
977
  });
971
978
  process.stdout.write(`Current provider set to ${args.provider}
@@ -999,7 +1006,9 @@ async function runInteractiveProviderSetup(cwd, args, promptInput2, providerDefi
999
1006
  const providerChoice = await promptInput2(formatProviderSetupSelectionPrompt(providerDefinitions));
1000
1007
  const type = resolveProviderSetupSelection(providerChoice, providerDefinitions);
1001
1008
  const settingsPath = getSettingsPathForScope(cwd, args.settingsScope);
1002
- const input = await runProviderSetupPromptFlow(type, promptInput2, providerDefinitions);
1009
+ const input = await runProviderSetupPromptFlow(type, promptInput2, providerDefinitions, {
1010
+ existingProfileNames: Object.keys(readMergedProviderSettings(cwd).providers ?? {})
1011
+ });
1003
1012
  applyProviderConfiguration(settingsPath, input, {
1004
1013
  providerDefinitions
1005
1014
  });
@@ -1087,16 +1096,12 @@ import { render } from "ink";
1087
1096
  // src/ui/App.tsx
1088
1097
  import { useState as useState14, useEffect as useEffect4 } from "react";
1089
1098
  import { Box as Box18, Text as Text20, useApp as useApp2, useInput as useInput8 } from "ink";
1099
+ import { listResumableSessionSummaries } from "@robota-sdk/agent-sdk";
1090
1100
  import { createSystemMessage as createSystemMessage6, messageToHistoryEntry as messageToHistoryEntry6 } from "@robota-sdk/agent-core";
1091
1101
 
1092
1102
  // src/ui/hooks/useInteractiveSession.ts
1093
1103
  import { useState, useRef, useCallback as useCallback2, useEffect } from "react";
1094
- import {
1095
- InteractiveSession,
1096
- CommandRegistry as CommandRegistry2,
1097
- createBuiltinCommandModule,
1098
- SkillCommandSource
1099
- } from "@robota-sdk/agent-sdk";
1104
+ import { InteractiveSession, CommandRegistry as CommandRegistry2 } from "@robota-sdk/agent-sdk";
1100
1105
  import { createSystemMessage as createSystemMessage2, messageToHistoryEntry as messageToHistoryEntry2 } from "@robota-sdk/agent-core";
1101
1106
 
1102
1107
  // src/ui/background-task-view-model.ts
@@ -1362,7 +1367,6 @@ var TuiStateManager = class {
1362
1367
 
1363
1368
  // src/ui/hooks/useSlashRouting.ts
1364
1369
  import { useCallback } from "react";
1365
- import { randomUUID as randomUUID2 } from "crypto";
1366
1370
  import { createSystemMessage, messageToHistoryEntry } from "@robota-sdk/agent-core";
1367
1371
 
1368
1372
  // src/plugins/plugin-command-source-loader.ts
@@ -1391,7 +1395,7 @@ function reloadPluginCommandSource(registry) {
1391
1395
  }
1392
1396
 
1393
1397
  // src/ui/hooks/useSlashRouting.ts
1394
- function useSlashRouting(interactiveSession, registry, manager) {
1398
+ function useSlashRouting(interactiveSession, registry, manager, commandEffectQueue) {
1395
1399
  return useCallback(
1396
1400
  async (input) => {
1397
1401
  manager.onUserTurnAccepted();
@@ -1405,10 +1409,11 @@ function useSlashRouting(interactiveSession, registry, manager) {
1405
1409
  const args = parts.slice(1).join(" ");
1406
1410
  const result = await interactiveSession.executeCommand(cmd, args);
1407
1411
  if (result) {
1408
- applySystemCommandResult(result, interactiveSession, registry, manager);
1409
- return;
1410
- }
1411
- if (await routeSkillCommand(input, cmd, registry, interactiveSession, manager)) {
1412
+ if (result.effects?.some((effect) => effect.type === "session-execution-started")) {
1413
+ manager.setPendingPrompt(interactiveSession.getPendingPrompt());
1414
+ return;
1415
+ }
1416
+ applySystemCommandResult(result, interactiveSession, registry, manager, commandEffectQueue);
1412
1417
  return;
1413
1418
  }
1414
1419
  manager.addEntry(
@@ -1417,18 +1422,17 @@ function useSlashRouting(interactiveSession, registry, manager) {
1417
1422
  )
1418
1423
  );
1419
1424
  },
1420
- [interactiveSession, registry, manager]
1425
+ [interactiveSession, registry, manager, commandEffectQueue]
1421
1426
  );
1422
1427
  }
1423
- function applySystemCommandResult(result, interactiveSession, registry, manager) {
1428
+ function applySystemCommandResult(result, interactiveSession, registry, manager, commandEffectQueue) {
1424
1429
  const pendingEffects = applyImmediateCommandEffects(result.effects, registry, manager);
1425
1430
  manager.addEntry(messageToHistoryEntry(createSystemMessage(result.message)));
1426
- const effects = getEffects(interactiveSession);
1427
1431
  if (result.interaction !== void 0) {
1428
- effects._pendingCommandInteraction = result.interaction;
1432
+ commandEffectQueue.enqueueInteraction(result.interaction);
1429
1433
  }
1430
1434
  if (pendingEffects.length > 0) {
1431
- effects._pendingCommandEffects = pendingEffects;
1435
+ commandEffectQueue.enqueueEffects(pendingEffects);
1432
1436
  }
1433
1437
  const ctx = interactiveSession.getContextState();
1434
1438
  manager.setContextState({
@@ -1453,37 +1457,32 @@ function applyImmediateCommandEffects(effects, registry, manager) {
1453
1457
  }
1454
1458
  return pendingEffects;
1455
1459
  }
1456
- async function routeSkillCommand(input, cmd, registry, interactiveSession, manager) {
1457
- const skillCmd = registry.getCommands().find((c) => c.name === cmd && (c.source === "skill" || c.source === "plugin"));
1458
- if (!skillCmd) {
1459
- return false;
1460
+
1461
+ // src/ui/hooks/command-effect-queue.ts
1462
+ var CommandEffectQueue = class {
1463
+ queue = [];
1464
+ enqueueInteraction(interaction) {
1465
+ this.queue.push({ type: "interaction", interaction });
1460
1466
  }
1461
- manager.addEntry({
1462
- id: randomUUID2(),
1463
- timestamp: /* @__PURE__ */ new Date(),
1464
- category: "event",
1465
- type: "skill-invocation",
1466
- data: {
1467
- skillName: cmd,
1468
- source: skillCmd.source,
1469
- message: `Invoking ${skillCmd.source}: ${cmd}`
1470
- }
1471
- });
1472
- const args = input.slice(1 + cmd.length).trimStart();
1473
- const qualifiedName = registry.resolveQualifiedName(cmd);
1474
- const hookInput = qualifiedName ? `/${qualifiedName}${input.slice(1 + cmd.length)}` : input;
1475
- await interactiveSession.executeSkillCommand(skillCmd, args, input, hookInput);
1476
- manager.setPendingPrompt(interactiveSession.getPendingPrompt());
1477
- return true;
1478
- }
1479
- function getEffects(interactiveSession) {
1480
- return interactiveSession;
1481
- }
1467
+ enqueueEffects(effects) {
1468
+ if (effects.length === 0) return;
1469
+ this.queue.push({ type: "effects", effects: [...effects] });
1470
+ }
1471
+ drain() {
1472
+ return this.queue.shift();
1473
+ }
1474
+ clear() {
1475
+ this.queue.length = 0;
1476
+ }
1477
+ };
1482
1478
 
1483
1479
  // src/ui/hooks/useInteractiveSession.ts
1484
1480
  function applyCompactEventToManager(interactiveSession, manager) {
1485
1481
  manager.syncHistory(interactiveSession.getFullHistory());
1486
1482
  }
1483
+ function applySkillActivationEventToManager(interactiveSession, manager) {
1484
+ manager.syncHistory(interactiveSession.getFullHistory());
1485
+ }
1487
1486
  function initializeSession(props, permissionHandler) {
1488
1487
  const interactiveSession = new InteractiveSession({
1489
1488
  cwd: props.cwd,
@@ -1501,14 +1500,13 @@ function initializeSession(props, permissionHandler) {
1501
1500
  commandHostAdapters: props.commandHostAdapters
1502
1501
  });
1503
1502
  const registry = new CommandRegistry2();
1504
- registry.addModule(createBuiltinCommandModule());
1505
1503
  for (const module of props.commandModules ?? []) {
1506
1504
  registry.addModule(module);
1507
1505
  }
1508
- registry.addSource(new SkillCommandSource(props.cwd));
1509
1506
  reloadPluginCommandSource(registry);
1510
1507
  const manager = new TuiStateManager();
1511
- return { interactiveSession, registry, manager };
1508
+ const commandEffectQueue = new CommandEffectQueue();
1509
+ return { interactiveSession, registry, manager, commandEffectQueue };
1512
1510
  }
1513
1511
  function useInteractiveSession(props) {
1514
1512
  const [, forceRender] = useState(0);
@@ -1537,8 +1535,8 @@ function useInteractiveSession(props) {
1537
1535
  });
1538
1536
  }, []);
1539
1537
  const permissionHandler = useCallback2(
1540
- (toolName, toolArgs) => new Promise((resolve2) => {
1541
- permissionQueueRef.current.push({ toolName, toolArgs, resolve: resolve2 });
1538
+ (toolName, toolArgs) => new Promise((resolve3) => {
1539
+ permissionQueueRef.current.push({ toolName, toolArgs, resolve: resolve3 });
1542
1540
  processNextPermission();
1543
1541
  }),
1544
1542
  [processNextPermission]
@@ -1547,7 +1545,7 @@ function useInteractiveSession(props) {
1547
1545
  if (stateRef.current === null) {
1548
1546
  stateRef.current = initializeSession(props, permissionHandler);
1549
1547
  }
1550
- const { interactiveSession, registry, manager } = stateRef.current;
1548
+ const { interactiveSession, registry, manager, commandEffectQueue } = stateRef.current;
1551
1549
  manager.onChange = () => forceRender((n) => n + 1);
1552
1550
  if (manager.history.length === 0) {
1553
1551
  const restored = interactiveSession.getFullHistory();
@@ -1557,6 +1555,7 @@ function useInteractiveSession(props) {
1557
1555
  }
1558
1556
  useEffect(() => {
1559
1557
  const onCompact = () => applyCompactEventToManager(interactiveSession, manager);
1558
+ const onSkillActivation = () => applySkillActivationEventToManager(interactiveSession, manager);
1560
1559
  interactiveSession.on("text_delta", manager.onTextDelta);
1561
1560
  interactiveSession.on("tool_start", manager.onToolStart);
1562
1561
  interactiveSession.on("tool_end", manager.onToolEnd);
@@ -1566,6 +1565,7 @@ function useInteractiveSession(props) {
1566
1565
  interactiveSession.on("error", manager.onError);
1567
1566
  interactiveSession.on("context_update", manager.onContextUpdate);
1568
1567
  interactiveSession.on("compact", onCompact);
1568
+ interactiveSession.on("skill_activation", onSkillActivation);
1569
1569
  interactiveSession.on("background_task_event", manager.onBackgroundTaskEvent);
1570
1570
  const initCheck = setInterval(() => {
1571
1571
  try {
@@ -1594,6 +1594,7 @@ function useInteractiveSession(props) {
1594
1594
  interactiveSession.off("error", manager.onError);
1595
1595
  interactiveSession.off("context_update", manager.onContextUpdate);
1596
1596
  interactiveSession.off("compact", onCompact);
1597
+ interactiveSession.off("skill_activation", onSkillActivation);
1597
1598
  interactiveSession.off("background_task_event", manager.onBackgroundTaskEvent);
1598
1599
  };
1599
1600
  }, [interactiveSession, manager]);
@@ -1603,7 +1604,7 @@ function useInteractiveSession(props) {
1603
1604
  manager.setPendingPrompt(interactiveSession.getPendingPrompt());
1604
1605
  }
1605
1606
  }, [manager.isThinking, interactiveSession, manager]);
1606
- const handleSubmit = useSlashRouting(interactiveSession, registry, manager);
1607
+ const handleSubmit = useSlashRouting(interactiveSession, registry, manager, commandEffectQueue);
1607
1608
  const handleAbort = useCallback2(() => {
1608
1609
  manager.setAborting(true);
1609
1610
  interactiveSession.abort();
@@ -1624,6 +1625,7 @@ function useInteractiveSession(props) {
1624
1625
  return {
1625
1626
  interactiveSession,
1626
1627
  registry,
1628
+ commandEffectQueue,
1627
1629
  history: manager.history,
1628
1630
  addEntry: (entry) => manager.addEntry(entry),
1629
1631
  streamingText: manager.streamingText,
@@ -1916,10 +1918,12 @@ function useSideEffects({
1916
1918
  cwd,
1917
1919
  providerOverride,
1918
1920
  interactiveSession,
1921
+ commandEffectQueue,
1919
1922
  addEntry,
1920
1923
  baseHandleSubmit,
1921
1924
  setSessionName,
1922
- setStatusLineSettings
1925
+ setStatusLineSettings,
1926
+ showSessionPickerOnStart
1923
1927
  }) {
1924
1928
  const { exit } = useApp();
1925
1929
  const [pendingModelId, setPendingModelId] = useState2(null);
@@ -1927,7 +1931,7 @@ function useSideEffects({
1927
1931
  const [pendingInteractionPrompt, setPendingInteractionPrompt] = useState2(null);
1928
1932
  const commandInteractionRef = useRef2(null);
1929
1933
  const [showPluginTUI, setShowPluginTUI] = useState2(false);
1930
- const [showSessionPicker, setShowSessionPicker] = useState2(false);
1934
+ const [showSessionPicker, setShowSessionPicker] = useState2(showSessionPickerOnStart ?? false);
1931
1935
  const requestShutdown = useCallback3(
1932
1936
  (reason, message) => {
1933
1937
  addEntry(messageToHistoryEntry5(createSystemMessage5("Shutting down...")));
@@ -1968,33 +1972,31 @@ function useSideEffects({
1968
1972
  commandInteractionRef.current = null;
1969
1973
  setPendingInteractionPrompt(null);
1970
1974
  if (result.effects !== void 0 && result.effects.length > 0) {
1971
- applyEffects(result.effects, interactiveSession);
1975
+ applyEffects(result.effects, getHostSideEffects(interactiveSession));
1972
1976
  }
1973
1977
  },
1974
1978
  [addEntry, applyEffects, interactiveSession]
1975
1979
  );
1976
1980
  const applyQueuedCommandState = useCallback3(
1977
1981
  (sideEffects) => {
1978
- if (sideEffects._pendingCommandInteraction !== void 0) {
1979
- const interaction = sideEffects._pendingCommandInteraction;
1980
- delete sideEffects._pendingCommandInteraction;
1982
+ const queued = commandEffectQueue.drain();
1983
+ if (queued === void 0) {
1984
+ return false;
1985
+ }
1986
+ if (queued.type === "interaction") {
1987
+ const { interaction } = queued;
1981
1988
  commandInteractionRef.current = interaction;
1982
1989
  setPendingInteractionPrompt(interaction.prompt);
1983
1990
  return true;
1984
1991
  }
1985
- if (sideEffects._pendingCommandEffects !== void 0) {
1986
- const effects = sideEffects._pendingCommandEffects;
1987
- delete sideEffects._pendingCommandEffects;
1988
- return applyEffects(effects, sideEffects);
1989
- }
1990
- return false;
1992
+ return applyEffects(queued.effects, sideEffects);
1991
1993
  },
1992
- [applyEffects]
1994
+ [applyEffects, commandEffectQueue]
1993
1995
  );
1994
1996
  const handleSubmit = useCallback3(
1995
1997
  async (input) => {
1996
1998
  await baseHandleSubmit(input);
1997
- const sideEffects = interactiveSession;
1999
+ const sideEffects = getHostSideEffects(interactiveSession);
1998
2000
  if (applyQueuedCommandState(sideEffects)) return;
1999
2001
  if (sideEffects._pendingModelId) {
2000
2002
  const modelId = sideEffects._pendingModelId;
@@ -2105,6 +2107,9 @@ function useSideEffects({
2105
2107
  handleInteractionCancel
2106
2108
  };
2107
2109
  }
2110
+ function getHostSideEffects(interactiveSession) {
2111
+ return interactiveSession;
2112
+ }
2108
2113
 
2109
2114
  // src/ui/hooks/useStatusLineSettings.ts
2110
2115
  import { useState as useState3 } from "react";
@@ -2122,10 +2127,12 @@ import { isToolMessage, isAssistantMessage } from "@robota-sdk/agent-core";
2122
2127
  // src/ui/render-markdown.ts
2123
2128
  import { marked } from "marked";
2124
2129
  import TerminalRenderer from "marked-terminal";
2125
- var ANSI_RED = "\x1B[31m";
2126
- var ANSI_GREEN = "\x1B[32m";
2130
+ var ANSI_LIGHT_RED = "\x1B[38;5;210m";
2131
+ var ANSI_LIGHT_GREEN = "\x1B[38;5;120m";
2127
2132
  var ANSI_CYAN = "\x1B[36m";
2128
2133
  var ANSI_DIM = "\x1B[2m";
2134
+ var ANSI_DARK_RED_BACKGROUND = "\x1B[48;5;52m";
2135
+ var ANSI_DARK_GREEN_BACKGROUND = "\x1B[48;5;22m";
2129
2136
  var ANSI_RESET = "\x1B[0m";
2130
2137
  var CODE_BLOCK_INDENT = " ";
2131
2138
  var ZERO_COLOR = "0";
@@ -2145,36 +2152,59 @@ function shouldUseColor(option) {
2145
2152
  function isDiffLanguage(language) {
2146
2153
  return language?.trim().toLowerCase() === "diff";
2147
2154
  }
2148
- function colorizeDiffLine(line, color) {
2155
+ function styleAddedOrRemovedDiffRow(line, rowWidth, color) {
2156
+ const row = `${CODE_BLOCK_INDENT}${line}`.padEnd(rowWidth);
2149
2157
  if (!color) {
2150
- return line;
2158
+ return row.trimEnd();
2151
2159
  }
2152
2160
  if (line.startsWith("+")) {
2153
- return `${ANSI_GREEN}${line}${ANSI_RESET}`;
2161
+ return `${ANSI_DARK_GREEN_BACKGROUND}${ANSI_LIGHT_GREEN}${row}${ANSI_RESET}`;
2154
2162
  }
2155
2163
  if (line.startsWith("-")) {
2156
- return `${ANSI_RED}${line}${ANSI_RESET}`;
2164
+ return `${ANSI_DARK_RED_BACKGROUND}${ANSI_LIGHT_RED}${row}${ANSI_RESET}`;
2165
+ }
2166
+ return row.trimEnd();
2167
+ }
2168
+ function colorizeDiffLine(line, color, rowWidth) {
2169
+ if (line.startsWith("+") || line.startsWith("-")) {
2170
+ return styleAddedOrRemovedDiffRow(line, rowWidth, color);
2171
+ }
2172
+ const row = `${CODE_BLOCK_INDENT}${line}`;
2173
+ if (!color) {
2174
+ return row;
2157
2175
  }
2158
2176
  if (line.startsWith("@@")) {
2159
- return `${ANSI_CYAN}${line}${ANSI_RESET}`;
2177
+ return `${ANSI_CYAN}${row}${ANSI_RESET}`;
2160
2178
  }
2161
2179
  if (line.startsWith("diff ") || line.startsWith("index ")) {
2162
- return `${ANSI_DIM}${line}${ANSI_RESET}`;
2180
+ return `${ANSI_DIM}${row}${ANSI_RESET}`;
2163
2181
  }
2164
- return line;
2182
+ return row;
2165
2183
  }
2166
- function renderDiffCodeBlock(code, color) {
2167
- const body = code.split("\n").map((line) => `${CODE_BLOCK_INDENT}${colorizeDiffLine(line, color)}`).join("\n");
2184
+ function resolveDiffRowWidth(lines, requestedWidth) {
2185
+ const minimumWidth = lines.reduce(
2186
+ (maxWidth, line) => Math.max(maxWidth, CODE_BLOCK_INDENT.length + line.length),
2187
+ 0
2188
+ );
2189
+ if (requestedWidth === void 0) {
2190
+ return minimumWidth;
2191
+ }
2192
+ return Math.max(minimumWidth, requestedWidth);
2193
+ }
2194
+ function renderDiffCodeBlock(code, color, codeBlockWidth) {
2195
+ const lines = code.split("\n");
2196
+ const rowWidth = resolveDiffRowWidth(lines, codeBlockWidth);
2197
+ const body = lines.map((line) => colorizeDiffLine(line, color, rowWidth)).join("\n");
2168
2198
  return `${body}
2169
2199
 
2170
2200
  `;
2171
2201
  }
2172
- function createTerminalRenderer(color) {
2202
+ function createTerminalRenderer(color, codeBlockWidth) {
2173
2203
  const renderer = new TerminalRendererConstructor(void 0, { ignoreIllegals: true });
2174
2204
  const renderCode = renderer.code.bind(renderer);
2175
2205
  renderer.code = (code, language, escaped) => {
2176
2206
  if (isDiffLanguage(language)) {
2177
- return renderDiffCodeBlock(code, color);
2207
+ return renderDiffCodeBlock(code, color, codeBlockWidth);
2178
2208
  }
2179
2209
  return renderCode(code, language, escaped);
2180
2210
  };
@@ -2182,7 +2212,7 @@ function createTerminalRenderer(color) {
2182
2212
  }
2183
2213
  function renderMarkdown(md, options = {}) {
2184
2214
  const result = marked.parse(md, {
2185
- renderer: createTerminalRenderer(shouldUseColor(options.color))
2215
+ renderer: createTerminalRenderer(shouldUseColor(options.color), options.codeBlockWidth)
2186
2216
  });
2187
2217
  return typeof result === "string" ? result.trimEnd() : md;
2188
2218
  }
@@ -2694,11 +2724,7 @@ function StatusActivityText({
2694
2724
  activeBackgroundTaskCount,
2695
2725
  hasPendingPrompt
2696
2726
  });
2697
- return /* @__PURE__ */ jsxs5(Fragment3, { children: [
2698
- /* @__PURE__ */ jsx5(Text5, { color: "cyan", bold: true, children: "Activity:" }),
2699
- " ",
2700
- /* @__PURE__ */ jsx5(Text5, { color: activity.color, bold: activity.kind !== "idle", children: activity.text })
2701
- ] });
2727
+ return /* @__PURE__ */ jsx5(Text5, { color: activity.color, bold: activity.kind !== "idle", children: activity.text });
2702
2728
  }
2703
2729
  function ContextText({
2704
2730
  percentage,
@@ -2722,77 +2748,79 @@ function ModeText({ permissionMode }) {
2722
2748
  /* @__PURE__ */ jsx5(Text5, { children: permissionMode })
2723
2749
  ] });
2724
2750
  }
2725
- function StatusLeft({
2726
- permissionMode,
2751
+ function shouldShowPermissionMode(permissionMode) {
2752
+ return permissionMode !== "default";
2753
+ }
2754
+ function ProviderText({
2727
2755
  modelName,
2728
- isThinking,
2729
- activeToolCount,
2730
- activeBackgroundTaskCount,
2731
- hasPendingPrompt,
2732
- contextPercentage,
2733
- contextUsedTokens,
2734
- contextMaxTokens,
2735
- sessionName,
2736
- gitBranch,
2737
- showGitBranch
2756
+ providerProfileName,
2757
+ providerType
2738
2758
  }) {
2739
- const shouldShowGitBranch = showGitBranch && gitBranch !== void 0 && gitBranch.length > 0;
2759
+ if (providerProfileName !== void 0 && providerType !== void 0) {
2760
+ return /* @__PURE__ */ jsxs5(Text5, { dimColor: true, children: [
2761
+ providerProfileName,
2762
+ " (",
2763
+ providerType,
2764
+ ") ",
2765
+ modelName
2766
+ ] });
2767
+ }
2768
+ return /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: modelName });
2769
+ }
2770
+ function StatusLeft(props) {
2771
+ const shouldShowGitBranch = props.showGitBranch && props.gitBranch !== void 0 && props.gitBranch.length > 0;
2772
+ const showPermissionMode = shouldShowPermissionMode(props.permissionMode);
2740
2773
  return /* @__PURE__ */ jsxs5(Text5, { children: [
2741
2774
  /* @__PURE__ */ jsx5(
2742
2775
  StatusActivityText,
2743
2776
  {
2744
- isThinking,
2745
- activeToolCount,
2746
- activeBackgroundTaskCount,
2747
- hasPendingPrompt
2777
+ isThinking: props.isThinking,
2778
+ activeToolCount: props.activeToolCount,
2779
+ activeBackgroundTaskCount: props.activeBackgroundTaskCount,
2780
+ hasPendingPrompt: props.hasPendingPrompt
2748
2781
  }
2749
2782
  ),
2750
- " | ",
2751
- /* @__PURE__ */ jsx5(ModeText, { permissionMode }),
2752
- sessionName && /* @__PURE__ */ jsxs5(Fragment3, { children: [
2783
+ showPermissionMode && /* @__PURE__ */ jsxs5(Fragment3, { children: [
2784
+ " | ",
2785
+ /* @__PURE__ */ jsx5(ModeText, { permissionMode: props.permissionMode })
2786
+ ] }),
2787
+ props.sessionName && /* @__PURE__ */ jsxs5(Fragment3, { children: [
2753
2788
  " | ",
2754
- /* @__PURE__ */ jsx5(Text5, { color: "magenta", children: sessionName })
2789
+ /* @__PURE__ */ jsx5(Text5, { color: "magenta", children: props.sessionName })
2755
2790
  ] }),
2756
2791
  shouldShowGitBranch && /* @__PURE__ */ jsxs5(Fragment3, { children: [
2757
2792
  " | ",
2758
2793
  /* @__PURE__ */ jsxs5(Text5, { dimColor: true, children: [
2759
2794
  "git: ",
2760
- gitBranch
2795
+ props.gitBranch
2761
2796
  ] })
2762
2797
  ] }),
2763
2798
  " | ",
2764
- /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: modelName }),
2799
+ /* @__PURE__ */ jsx5(
2800
+ ProviderText,
2801
+ {
2802
+ modelName: props.modelName,
2803
+ providerProfileName: props.providerProfileName,
2804
+ providerType: props.providerType
2805
+ }
2806
+ ),
2765
2807
  " | ",
2766
2808
  /* @__PURE__ */ jsx5(
2767
2809
  ContextText,
2768
2810
  {
2769
- percentage: contextPercentage,
2770
- usedTokens: contextUsedTokens,
2771
- maxTokens: contextMaxTokens
2811
+ percentage: props.contextPercentage,
2812
+ usedTokens: props.contextUsedTokens,
2813
+ maxTokens: props.contextMaxTokens
2772
2814
  }
2773
2815
  )
2774
2816
  ] });
2775
2817
  }
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
- }
2791
2818
  function StatusBar({
2792
2819
  permissionMode,
2793
2820
  modelName,
2821
+ providerProfileName,
2822
+ providerType,
2794
2823
  sessionId: _sessionId,
2795
- messageCount,
2796
2824
  isThinking,
2797
2825
  activeToolCount = 0,
2798
2826
  activeBackgroundTaskCount = 0,
@@ -2804,7 +2832,7 @@ function StatusBar({
2804
2832
  gitBranch,
2805
2833
  showGitBranch = true
2806
2834
  }) {
2807
- return /* @__PURE__ */ jsxs5(
2835
+ return /* @__PURE__ */ jsx5(
2808
2836
  Box5,
2809
2837
  {
2810
2838
  borderStyle: "single",
@@ -2812,26 +2840,25 @@ function StatusBar({
2812
2840
  paddingLeft: 1,
2813
2841
  paddingRight: 1,
2814
2842
  justifyContent: "space-between",
2815
- children: [
2816
- /* @__PURE__ */ jsx5(
2817
- StatusLeft,
2818
- {
2819
- permissionMode,
2820
- modelName,
2821
- isThinking,
2822
- activeToolCount,
2823
- activeBackgroundTaskCount,
2824
- hasPendingPrompt,
2825
- contextPercentage,
2826
- contextUsedTokens,
2827
- contextMaxTokens,
2828
- sessionName,
2829
- gitBranch,
2830
- showGitBranch
2831
- }
2832
- ),
2833
- /* @__PURE__ */ jsx5(StatusRight, { isThinking, messageCount })
2834
- ]
2843
+ children: /* @__PURE__ */ jsx5(
2844
+ StatusLeft,
2845
+ {
2846
+ permissionMode,
2847
+ modelName,
2848
+ providerProfileName,
2849
+ providerType,
2850
+ isThinking,
2851
+ activeToolCount,
2852
+ activeBackgroundTaskCount,
2853
+ hasPendingPrompt,
2854
+ contextPercentage,
2855
+ contextUsedTokens,
2856
+ contextMaxTokens,
2857
+ sessionName,
2858
+ gitBranch,
2859
+ showGitBranch
2860
+ }
2861
+ )
2835
2862
  }
2836
2863
  );
2837
2864
  }
@@ -2842,8 +2869,9 @@ function SessionStatusBar({
2842
2869
  cwd,
2843
2870
  permissionMode,
2844
2871
  modelId,
2872
+ providerProfileName,
2873
+ providerType,
2845
2874
  sessionId,
2846
- messageCount,
2847
2875
  isThinking,
2848
2876
  activeToolCount,
2849
2877
  activeBackgroundTaskCount,
@@ -2859,8 +2887,9 @@ function SessionStatusBar({
2859
2887
  {
2860
2888
  permissionMode,
2861
2889
  modelName: modelId ? getModelName2(modelId) : "",
2890
+ providerProfileName,
2891
+ providerType,
2862
2892
  sessionId,
2863
- messageCount,
2864
2893
  isThinking,
2865
2894
  activeToolCount,
2866
2895
  activeBackgroundTaskCount,
@@ -3888,6 +3917,7 @@ function submitTextPromptValue(state, options) {
3888
3917
  import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
3889
3918
  function TextPrompt({
3890
3919
  title,
3920
+ description,
3891
3921
  placeholder,
3892
3922
  onSubmit,
3893
3923
  onCancel,
@@ -3912,12 +3942,11 @@ function TextPrompt({
3912
3942
  );
3913
3943
  useInput5((input, key) => {
3914
3944
  const action = getTextPromptInputAction(input, key);
3915
- if (action !== void 0) {
3916
- applyAction(action);
3917
- }
3945
+ if (action !== void 0) applyAction(action);
3918
3946
  });
3919
3947
  return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
3920
3948
  /* @__PURE__ */ jsx13(Text12, { color: "yellow", bold: true, children: title }),
3949
+ /* @__PURE__ */ jsx13(PromptDescription, { description }),
3921
3950
  /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
3922
3951
  /* @__PURE__ */ jsx13(Text12, { color: "cyan", children: "> " }),
3923
3952
  state.value ? /* @__PURE__ */ jsx13(Text12, { children: masked ? "*".repeat(state.value.length) : state.value }) : placeholder ? /* @__PURE__ */ jsx13(Text12, { dimColor: true, children: placeholder }) : null,
@@ -3927,6 +3956,12 @@ function TextPrompt({
3927
3956
  /* @__PURE__ */ jsx13(Text12, { dimColor: true, children: " Enter Submit Esc Cancel" })
3928
3957
  ] });
3929
3958
  }
3959
+ function PromptDescription({ description }) {
3960
+ if (description === void 0 || description.length === 0) {
3961
+ return null;
3962
+ }
3963
+ return /* @__PURE__ */ jsx13(Text12, { dimColor: true, children: description });
3964
+ }
3930
3965
 
3931
3966
  // src/ui/InteractivePrompt.tsx
3932
3967
  import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
@@ -3940,6 +3975,7 @@ function InteractivePrompt({
3940
3975
  TextPrompt,
3941
3976
  {
3942
3977
  title: prompt.title,
3978
+ description: prompt.description,
3943
3979
  placeholder: prompt.placeholder,
3944
3980
  allowEmpty: prompt.allowEmpty,
3945
3981
  masked: prompt.masked,
@@ -3952,6 +3988,7 @@ function InteractivePrompt({
3952
3988
  }
3953
3989
  return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
3954
3990
  /* @__PURE__ */ jsx14(Text13, { bold: true, children: prompt.title }),
3991
+ prompt.description !== void 0 && prompt.description.length > 0 && /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: prompt.description }),
3955
3992
  /* @__PURE__ */ jsx14(
3956
3993
  ListPicker,
3957
3994
  {
@@ -4542,26 +4579,20 @@ function PluginTUI({ callbacks, onClose, addMessage }) {
4542
4579
  import { Box as Box15, Text as Text17 } from "ink";
4543
4580
  import { Fragment as Fragment5, jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
4544
4581
  var SESSION_ID_DISPLAY_LENGTH = 8;
4582
+ var SESSION_PREVIEW_DISPLAY_LENGTH = 60;
4545
4583
  function SessionPicker({
4546
- sessionStore,
4547
- cwd,
4584
+ sessions,
4548
4585
  onSelect,
4549
4586
  onCancel
4550
4587
  }) {
4551
- const sessions = (sessionStore?.list() ?? []).filter((s) => s.cwd === cwd);
4552
4588
  return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
4553
4589
  /* @__PURE__ */ jsx19(Text17, { bold: true, color: "cyan", children: "Select a session to resume (ESC to cancel):" }),
4554
4590
  /* @__PURE__ */ jsx19(
4555
4591
  ListPicker,
4556
4592
  {
4557
- items: sessions,
4593
+ items: [...sessions],
4558
4594
  renderItem: (session, isSelected) => {
4559
- const lastMsg = session.messages.slice().reverse().find((m) => {
4560
- const msg = m;
4561
- return msg.role === "assistant" && msg.content;
4562
- });
4563
- const rawPreview = lastMsg?.content?.replace(/[\n\r]+/g, " ").trim() ?? "";
4564
- const preview = rawPreview ? rawPreview.slice(0, 60) + (rawPreview.length > 60 ? "..." : "") : "";
4595
+ const preview = session.preview ? session.preview.slice(0, SESSION_PREVIEW_DISPLAY_LENGTH) + (session.preview.length > SESSION_PREVIEW_DISPLAY_LENGTH ? "..." : "") : "";
4565
4596
  return /* @__PURE__ */ jsxs15(Text17, { children: [
4566
4597
  isSelected ? "> " : " ",
4567
4598
  /* @__PURE__ */ jsx19(Text17, { bold: true, children: session.name ?? session.id.slice(0, SESSION_ID_DISPLAY_LENGTH) }),
@@ -4575,7 +4606,7 @@ function SessionPicker({
4575
4606
  " ",
4576
4607
  /* @__PURE__ */ jsxs15(Text17, { dimColor: true, children: [
4577
4608
  "msgs: ",
4578
- session.messages.length
4609
+ session.messageCount
4579
4610
  ] }),
4580
4611
  preview ? /* @__PURE__ */ jsxs15(Fragment5, { children: [
4581
4612
  "\n ",
@@ -4971,12 +5002,19 @@ function isJsonObject(value) {
4971
5002
  import { jsx as jsx22, jsxs as jsxs17 } from "react/jsx-runtime";
4972
5003
  function App(props) {
4973
5004
  const [activeSessionId, setActiveSessionId] = useState14(props.resumeSessionId);
5005
+ const [showInitialSessionPicker, setShowInitialSessionPicker] = useState14(
5006
+ props.showSessionPickerOnStart ?? false
5007
+ );
4974
5008
  return /* @__PURE__ */ jsx22(
4975
5009
  AppInner,
4976
5010
  {
4977
5011
  ...props,
5012
+ showSessionPickerOnStart: showInitialSessionPicker,
4978
5013
  resumeSessionId: activeSessionId,
4979
- onSessionSwitch: (sessionId) => setActiveSessionId(sessionId)
5014
+ onSessionSwitch: (sessionId) => {
5015
+ setShowInitialSessionPicker(false);
5016
+ setActiveSessionId(sessionId);
5017
+ }
4980
5018
  },
4981
5019
  activeSessionId ?? "__new__"
4982
5020
  );
@@ -4986,6 +5024,7 @@ function AppInner(props) {
4986
5024
  const {
4987
5025
  interactiveSession,
4988
5026
  registry,
5027
+ commandEffectQueue,
4989
5028
  history,
4990
5029
  addEntry,
4991
5030
  streamingText,
@@ -5039,10 +5078,12 @@ function AppInner(props) {
5039
5078
  cwd,
5040
5079
  providerOverride: props.providerOverride,
5041
5080
  interactiveSession,
5081
+ commandEffectQueue,
5042
5082
  addEntry,
5043
5083
  baseHandleSubmit,
5044
5084
  setSessionName,
5045
- setStatusLineSettings
5085
+ setStatusLineSettings,
5086
+ showSessionPickerOnStart: props.showSessionPickerOnStart
5046
5087
  });
5047
5088
  useEffect4(() => {
5048
5089
  const name = interactiveSession?.getName?.();
@@ -5148,8 +5189,7 @@ function AppInner(props) {
5148
5189
  showSessionPicker && /* @__PURE__ */ jsx22(
5149
5190
  SessionPicker,
5150
5191
  {
5151
- sessionStore: props.sessionStore,
5152
- cwd: props.cwd,
5192
+ sessions: listResumableSessionSummaries(props.sessionStore, props.cwd),
5153
5193
  onSelect: (id) => {
5154
5194
  setShowSessionPicker(false);
5155
5195
  props.onSessionSwitch(id);
@@ -5166,8 +5206,9 @@ function AppInner(props) {
5166
5206
  cwd,
5167
5207
  permissionMode,
5168
5208
  modelId: props.modelId,
5209
+ providerProfileName: props.providerProfileName,
5210
+ providerType: props.providerType,
5169
5211
  sessionId,
5170
- messageCount: history.length,
5171
5212
  isThinking,
5172
5213
  activeToolCount: activeTools.length,
5173
5214
  activeBackgroundTaskCount,
@@ -5243,7 +5284,7 @@ function readVersion() {
5243
5284
  }
5244
5285
  }
5245
5286
  function promptInput(label, masked = false) {
5246
- return new Promise((resolve2) => {
5287
+ return new Promise((resolve3) => {
5247
5288
  process.stdout.write(label);
5248
5289
  let input = "";
5249
5290
  const stdin = process.stdin;
@@ -5258,7 +5299,7 @@ function promptInput(label, masked = false) {
5258
5299
  stdin.setRawMode(wasRaw ?? false);
5259
5300
  stdin.pause();
5260
5301
  process.stdout.write("\n");
5261
- resolve2(input.trim());
5302
+ resolve3(input.trim());
5262
5303
  return;
5263
5304
  } else if (ch === "\x7F" || ch === "\b") {
5264
5305
  if (input.length > 0) {
@@ -5277,6 +5318,15 @@ function promptInput(label, masked = false) {
5277
5318
  stdin.on("data", onData);
5278
5319
  });
5279
5320
  }
5321
+ function readTaskFilePrompt(cwd, taskFile) {
5322
+ const taskPath = resolve2(cwd, taskFile);
5323
+ const content = readFileSync6(taskPath, "utf8").trim();
5324
+ if (content.length === 0) {
5325
+ throw new Error(`Task file is empty: ${taskFile}`);
5326
+ }
5327
+ return `Task file (${taskFile}):
5328
+ ${content}`;
5329
+ }
5280
5330
  function resetConfig() {
5281
5331
  const userPath = getUserSettingsPath();
5282
5332
  if (deleteSettings(userPath)) {
@@ -5286,6 +5336,42 @@ function resetConfig() {
5286
5336
  process.stdout.write("No user settings found.\n");
5287
5337
  }
5288
5338
  }
5339
+ function createDefaultCliCommandModules({
5340
+ cwd,
5341
+ providerDefinitions
5342
+ }) {
5343
+ return [
5344
+ createSkillsCommandModule({ cwd }),
5345
+ createHelpCommandModule(),
5346
+ createAgentCommandModule(),
5347
+ createModelCommandModule({
5348
+ providerDefinitions,
5349
+ settings: {
5350
+ readMergedSettings: () => readMergedProviderSettings(cwd)
5351
+ }
5352
+ }),
5353
+ createPermissionsCommandModule(),
5354
+ createLanguageCommandModule(),
5355
+ createBackgroundCommandModule(),
5356
+ createMemoryCommandModule(),
5357
+ createCompactCommandModule(),
5358
+ createContextCommandModule(),
5359
+ createExitCommandModule(),
5360
+ createSessionCommandModule(),
5361
+ createResetCommandModule(),
5362
+ createRewindCommandModule(),
5363
+ createStatusLineCommandModule(),
5364
+ createPluginCommandModule(),
5365
+ createProviderCommandModule({
5366
+ providerDefinitions,
5367
+ settings: {
5368
+ readMergedSettings: () => readMergedProviderSettings(cwd),
5369
+ readTargetSettings: () => readSettings(resolveProviderSettingsWriteTargetPath(cwd)),
5370
+ writeTargetSettings: (settings) => writeSettings(resolveProviderSettingsWriteTargetPath(cwd), settings)
5371
+ }
5372
+ })
5373
+ ];
5374
+ }
5289
5375
  async function startCli(options = {}) {
5290
5376
  const args = parseCliArgs();
5291
5377
  const version = readVersion();
@@ -5320,30 +5406,7 @@ async function startCli(options = {}) {
5320
5406
  };
5321
5407
  const providerDefinitions = options.providerDefinitions ?? DEFAULT_PROVIDER_DEFINITIONS;
5322
5408
  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(),
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
- }),
5409
+ ...createDefaultCliCommandModules({ cwd, providerDefinitions }),
5347
5410
  ...options.commandModules ?? []
5348
5411
  ];
5349
5412
  const startupUpdateNoticePromise = shouldRunStartupCliUpdateCheck(args) ? getStartupCliUpdateNotice({ currentVersion: version }) : void 0;
@@ -5362,6 +5425,8 @@ async function startCli(options = {}) {
5362
5425
  process.exit(1);
5363
5426
  }
5364
5427
  const providerOptions = args.provider ? { providerOverride: args.provider, providerDefinitions } : { providerDefinitions };
5428
+ const activeProviderSettings = readMergedProviderSettings(cwd);
5429
+ const providerProfileName = args.provider ?? activeProviderSettings.currentProvider;
5365
5430
  const providerSettings = readProviderSettings(cwd, providerOptions);
5366
5431
  const modelId = args.model ?? providerSettings.model;
5367
5432
  const provider = createProviderFromSettings(cwd, args.model, providerOptions);
@@ -5371,22 +5436,17 @@ async function startCli(options = {}) {
5371
5436
  providerConfig: { ...providerSettings, model: modelId },
5372
5437
  logsDir: paths.logs
5373
5438
  });
5374
- const sessionStore = new SessionStore(paths.sessions);
5439
+ const sessionStore = createProjectSessionStore(cwd);
5375
5440
  let resumeSessionId;
5441
+ let showSessionPickerOnStart = false;
5376
5442
  if (args.continueMode) {
5377
- const sessions = sessionStore.list().filter((s) => s.cwd === cwd);
5378
- if (sessions.length > 0) {
5379
- resumeSessionId = sessions[0].id;
5380
- }
5443
+ resumeSessionId = resolveLatestSessionId(sessionStore, cwd);
5381
5444
  } else if (args.resumeId !== void 0) {
5382
5445
  if (args.resumeId === "") {
5383
- resumeSessionId = "__picker__";
5446
+ showSessionPickerOnStart = true;
5384
5447
  } else {
5385
- const sessions = sessionStore.list();
5386
- const match = sessions.find((s) => s.id === args.resumeId || s.name === args.resumeId);
5387
- if (match) {
5388
- resumeSessionId = match.id;
5389
- } else {
5448
+ resumeSessionId = resolveSessionIdByIdOrName(sessionStore, args.resumeId);
5449
+ if (resumeSessionId === void 0) {
5390
5450
  process.stderr.write(`Session not found: ${args.resumeId}
5391
5451
  `);
5392
5452
  process.exit(1);
@@ -5408,6 +5468,15 @@ async function startCli(options = {}) {
5408
5468
  }
5409
5469
  const appendParts = [];
5410
5470
  if (args.appendSystemPrompt) appendParts.push(args.appendSystemPrompt);
5471
+ if (args.taskFile) {
5472
+ try {
5473
+ appendParts.push(readTaskFilePrompt(cwd, args.taskFile));
5474
+ } catch (error) {
5475
+ process.stderr.write(`${error instanceof Error ? error.message : String(error)}
5476
+ `);
5477
+ process.exit(1);
5478
+ }
5479
+ }
5411
5480
  if (args.jsonSchema)
5412
5481
  appendParts.push(
5413
5482
  `Respond with valid JSON only, matching this JSON schema:
@@ -5442,6 +5511,8 @@ ${args.jsonSchema}`
5442
5511
  cwd,
5443
5512
  provider,
5444
5513
  providerOverride: args.provider,
5514
+ providerProfileName,
5515
+ providerType: providerSettings.name,
5445
5516
  modelId,
5446
5517
  language: args.language,
5447
5518
  permissionMode: args.permissionMode,
@@ -5449,6 +5520,7 @@ ${args.jsonSchema}`
5449
5520
  version,
5450
5521
  sessionStore,
5451
5522
  resumeSessionId,
5523
+ showSessionPickerOnStart,
5452
5524
  forkSession: args.forkSession,
5453
5525
  sessionName: args.sessionName,
5454
5526
  backgroundTaskRunners,