@robota-sdk/agent-cli 3.0.0-beta.56 → 3.0.0-beta.58
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.
- package/README.md +46 -13
- package/dist/node/bin.js +2 -2
- package/dist/node/{chunk-2JAZDNYT.js → chunk-4ZX5RLIX.js} +45 -15
- package/dist/node/{chunk-H3NRW5FW.js → chunk-B522YHTK.js} +1839 -526
- package/dist/node/index.cjs +1922 -585
- package/dist/node/index.js +2 -2
- package/dist/node/subagents/child-process-subagent-worker.js +1 -1
- package/package.json +14 -11
package/dist/node/index.cjs
CHANGED
|
@@ -40,8 +40,8 @@ __export(index_exports, {
|
|
|
40
40
|
module.exports = __toCommonJS(index_exports);
|
|
41
41
|
|
|
42
42
|
// src/cli.ts
|
|
43
|
-
var
|
|
44
|
-
var
|
|
43
|
+
var import_node_fs8 = require("fs");
|
|
44
|
+
var import_node_path10 = require("path");
|
|
45
45
|
var import_node_url = require("url");
|
|
46
46
|
var import_agent_sdk8 = require("@robota-sdk/agent-sdk");
|
|
47
47
|
var import_agent_sessions = require("@robota-sdk/agent-sessions");
|
|
@@ -98,7 +98,9 @@ function parseCliArgs() {
|
|
|
98
98
|
"api-key": { type: "string" },
|
|
99
99
|
"api-key-env": { type: "string" },
|
|
100
100
|
"set-current": { type: "boolean", default: false },
|
|
101
|
-
"settings-scope": { type: "string" }
|
|
101
|
+
"settings-scope": { type: "string" },
|
|
102
|
+
"check-update": { type: "boolean", default: false },
|
|
103
|
+
"disable-update-check": { type: "boolean", default: false }
|
|
102
104
|
}
|
|
103
105
|
});
|
|
104
106
|
return {
|
|
@@ -129,7 +131,9 @@ function parseCliArgs() {
|
|
|
129
131
|
apiKey: values["api-key"],
|
|
130
132
|
apiKeyEnv: values["api-key-env"],
|
|
131
133
|
setCurrent: values["set-current"] ?? false,
|
|
132
|
-
settingsScope: values["settings-scope"]
|
|
134
|
+
settingsScope: values["settings-scope"],
|
|
135
|
+
checkUpdate: values["check-update"] ?? false,
|
|
136
|
+
disableUpdateCheck: values["disable-update-check"] ?? false
|
|
133
137
|
};
|
|
134
138
|
}
|
|
135
139
|
|
|
@@ -193,16 +197,47 @@ var import_node_os = require("os");
|
|
|
193
197
|
// src/utils/provider-default-definitions.ts
|
|
194
198
|
var import_agent_provider_anthropic = require("@robota-sdk/agent-provider-anthropic");
|
|
195
199
|
var import_agent_provider_gemma = require("@robota-sdk/agent-provider-gemma");
|
|
200
|
+
var import_agent_provider_gemini = require("@robota-sdk/agent-provider-gemini");
|
|
196
201
|
var import_agent_provider_openai = require("@robota-sdk/agent-provider-openai");
|
|
202
|
+
var import_agent_provider_qwen = require("@robota-sdk/agent-provider-qwen");
|
|
197
203
|
var DEFAULT_PROVIDER_DEFINITIONS = [
|
|
198
204
|
(0, import_agent_provider_anthropic.createAnthropicProviderDefinition)(),
|
|
199
205
|
(0, import_agent_provider_openai.createOpenAIProviderDefinition)(),
|
|
200
|
-
(0,
|
|
206
|
+
(0, import_agent_provider_gemini.createGeminiProviderDefinition)(),
|
|
207
|
+
(0, import_agent_provider_gemma.createGemmaProviderDefinition)(),
|
|
208
|
+
(0, import_agent_provider_qwen.createQwenProviderDefinition)()
|
|
201
209
|
];
|
|
202
210
|
|
|
203
211
|
// src/utils/provider-definition.ts
|
|
204
212
|
var import_agent_core = require("@robota-sdk/agent-core");
|
|
205
213
|
|
|
214
|
+
// src/utils/env-ref.ts
|
|
215
|
+
var ENV_REFERENCE_PREFIX = "$ENV:";
|
|
216
|
+
function isEnvReference(value) {
|
|
217
|
+
return value.startsWith(ENV_REFERENCE_PREFIX);
|
|
218
|
+
}
|
|
219
|
+
function getEnvReferenceName(value) {
|
|
220
|
+
if (!isEnvReference(value)) {
|
|
221
|
+
return void 0;
|
|
222
|
+
}
|
|
223
|
+
const envName = value.slice(ENV_REFERENCE_PREFIX.length).trim();
|
|
224
|
+
return envName.length > 0 ? envName : void 0;
|
|
225
|
+
}
|
|
226
|
+
function resolveEnvReference(value) {
|
|
227
|
+
const envName = getEnvReferenceName(value);
|
|
228
|
+
if (envName === void 0) {
|
|
229
|
+
return value;
|
|
230
|
+
}
|
|
231
|
+
const resolved = process.env[envName];
|
|
232
|
+
return resolved !== void 0 && resolved.length > 0 ? resolved : void 0;
|
|
233
|
+
}
|
|
234
|
+
function hasUsableSecretReference(value) {
|
|
235
|
+
if (value === void 0 || value.length === 0) {
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
return resolveEnvReference(value) !== void 0;
|
|
239
|
+
}
|
|
240
|
+
|
|
206
241
|
// src/utils/provider-factory.ts
|
|
207
242
|
function readProviderSettings(cwd, options = {}) {
|
|
208
243
|
const merged = readMergedProviderSettings(cwd);
|
|
@@ -275,7 +310,8 @@ function resolveActiveProvider(settings, providerOverride, providerDefinitions =
|
|
|
275
310
|
model: profile.model,
|
|
276
311
|
apiKey: profile.apiKey,
|
|
277
312
|
baseURL: profile.baseURL,
|
|
278
|
-
timeout: profile.timeout
|
|
313
|
+
timeout: profile.timeout,
|
|
314
|
+
options: profile.options
|
|
279
315
|
},
|
|
280
316
|
providerDefinitions
|
|
281
317
|
);
|
|
@@ -288,7 +324,8 @@ function resolveActiveProvider(settings, providerOverride, providerDefinitions =
|
|
|
288
324
|
model: provider.model,
|
|
289
325
|
apiKey: provider.apiKey,
|
|
290
326
|
baseURL: provider.baseURL,
|
|
291
|
-
timeout: provider.timeout
|
|
327
|
+
timeout: provider.timeout,
|
|
328
|
+
options: provider.options
|
|
292
329
|
},
|
|
293
330
|
providerDefinitions
|
|
294
331
|
);
|
|
@@ -301,22 +338,17 @@ function normalizeProviderConfig(settings, providerDefinitions) {
|
|
|
301
338
|
if (!model) {
|
|
302
339
|
throw new Error(`Provider ${settings.name} requires model`);
|
|
303
340
|
}
|
|
341
|
+
const apiKeyReference = settings.apiKey ?? defaults.apiKey;
|
|
342
|
+
const options = settings.options ?? defaults.options;
|
|
304
343
|
return {
|
|
305
344
|
name: settings.name,
|
|
306
345
|
model,
|
|
307
|
-
apiKey:
|
|
346
|
+
apiKey: apiKeyReference !== void 0 ? resolveEnvReference(apiKeyReference) : void 0,
|
|
308
347
|
baseURL: settings.baseURL ?? defaults.baseURL,
|
|
309
|
-
timeout: settings.timeout
|
|
348
|
+
timeout: settings.timeout,
|
|
349
|
+
...options !== void 0 && { options }
|
|
310
350
|
};
|
|
311
351
|
}
|
|
312
|
-
function resolveEnvRef(value) {
|
|
313
|
-
const envPrefix = "$ENV:";
|
|
314
|
-
if (!value.startsWith(envPrefix)) {
|
|
315
|
-
return value;
|
|
316
|
-
}
|
|
317
|
-
const envName = value.slice(envPrefix.length);
|
|
318
|
-
return process.env[envName] ?? value;
|
|
319
|
-
}
|
|
320
352
|
function createProviderFromConfig(settings, providerDefinitions) {
|
|
321
353
|
const definition = (0, import_agent_core.findProviderDefinition)(providerDefinitions, settings.name);
|
|
322
354
|
if (definition === void 0) {
|
|
@@ -371,7 +403,7 @@ function isUsableProviderProfile(type, profile, providerDefinitions) {
|
|
|
371
403
|
if (!profile) {
|
|
372
404
|
return false;
|
|
373
405
|
}
|
|
374
|
-
if (profile.apiKey) {
|
|
406
|
+
if (hasUsableSecretReference(profile.apiKey)) {
|
|
375
407
|
return true;
|
|
376
408
|
}
|
|
377
409
|
if (!type) {
|
|
@@ -381,7 +413,7 @@ function isUsableProviderProfile(type, profile, providerDefinitions) {
|
|
|
381
413
|
if (definition === void 0) {
|
|
382
414
|
return false;
|
|
383
415
|
}
|
|
384
|
-
return definition.requiresApiKey !== true || definition.defaults?.apiKey
|
|
416
|
+
return definition.requiresApiKey !== true || hasUsableSecretReference(definition.defaults?.apiKey);
|
|
385
417
|
}
|
|
386
418
|
|
|
387
419
|
// src/utils/provider-settings.ts
|
|
@@ -411,7 +443,7 @@ function validateProviderProfile(profileName, profile, options = {}) {
|
|
|
411
443
|
throw new Error(`Provider profile "${profileName}" is missing model`);
|
|
412
444
|
}
|
|
413
445
|
const definition = (0, import_agent_core.findProviderDefinition)(options.providerDefinitions ?? [], profile.type);
|
|
414
|
-
if (definition?.requiresApiKey === true && !profile.apiKey
|
|
446
|
+
if (definition?.requiresApiKey === true && !hasUsableSecretReference(profile.apiKey ?? definition.defaults?.apiKey)) {
|
|
415
447
|
throw new Error(`Provider profile "${profileName}" is missing apiKey`);
|
|
416
448
|
}
|
|
417
449
|
}
|
|
@@ -478,6 +510,40 @@ function createProviderSetupFlow(type, providerDefinitions) {
|
|
|
478
510
|
values: {}
|
|
479
511
|
};
|
|
480
512
|
}
|
|
513
|
+
function formatProviderSetupSelectionPrompt(providerDefinitions) {
|
|
514
|
+
if (providerDefinitions.length === 0) {
|
|
515
|
+
return " No providers are available.";
|
|
516
|
+
}
|
|
517
|
+
const lines = [
|
|
518
|
+
" Select provider:",
|
|
519
|
+
...providerDefinitions.map(
|
|
520
|
+
(definition, index) => ` ${index + 1}. ${formatProviderSetupChoiceLabel(definition)}`
|
|
521
|
+
),
|
|
522
|
+
` Provider [1-${providerDefinitions.length}] (default: 1): `
|
|
523
|
+
];
|
|
524
|
+
return lines.join("\n");
|
|
525
|
+
}
|
|
526
|
+
function resolveProviderSetupSelection(rawValue, providerDefinitions) {
|
|
527
|
+
const value = rawValue.trim();
|
|
528
|
+
const selectedValue = value.length > 0 ? value : "1";
|
|
529
|
+
const index = parseProviderSelectionIndex(selectedValue);
|
|
530
|
+
if (index !== void 0) {
|
|
531
|
+
const definition2 = providerDefinitions[index];
|
|
532
|
+
if (definition2 !== void 0) {
|
|
533
|
+
return definition2.type;
|
|
534
|
+
}
|
|
535
|
+
throw new Error(
|
|
536
|
+
`Provider selection ${selectedValue} is out of range. Currently supported: ${(0, import_agent_core.formatSupportedProviderTypes)(providerDefinitions)}`
|
|
537
|
+
);
|
|
538
|
+
}
|
|
539
|
+
const definition = (0, import_agent_core.findProviderDefinition)(providerDefinitions, selectedValue);
|
|
540
|
+
if (definition === void 0) {
|
|
541
|
+
throw new Error(
|
|
542
|
+
`Unknown provider: ${selectedValue}. Currently supported: ${(0, import_agent_core.formatSupportedProviderTypes)(providerDefinitions)}`
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
return definition.type;
|
|
546
|
+
}
|
|
481
547
|
function getProviderSetupStep(state) {
|
|
482
548
|
const step = state.steps[state.stepIndex];
|
|
483
549
|
if (step === void 0) {
|
|
@@ -523,6 +589,16 @@ function formatProviderSetupPromptLabel(step) {
|
|
|
523
589
|
const suffix = step.defaultValue !== void 0 ? ` (default: ${step.defaultValue})` : "";
|
|
524
590
|
return ` ${step.title}${suffix}: `;
|
|
525
591
|
}
|
|
592
|
+
function formatProviderSetupChoiceLabel(definition) {
|
|
593
|
+
const label = definition.displayName !== void 0 ? `${definition.displayName} (${definition.type})` : definition.type;
|
|
594
|
+
return definition.description !== void 0 ? `${label} - ${definition.description}` : label;
|
|
595
|
+
}
|
|
596
|
+
function parseProviderSelectionIndex(value) {
|
|
597
|
+
if (!/^\d+$/.test(value)) {
|
|
598
|
+
return void 0;
|
|
599
|
+
}
|
|
600
|
+
return Number(value) - 1;
|
|
601
|
+
}
|
|
526
602
|
function validateProviderSetupValue(step, value) {
|
|
527
603
|
if (step.required === true && value.length === 0) {
|
|
528
604
|
return "Required";
|
|
@@ -615,15 +691,13 @@ async function ensureConfig(cwd, args, promptInput2, providerDefinitions = DEFAU
|
|
|
615
691
|
return;
|
|
616
692
|
}
|
|
617
693
|
if (!isInteractiveTerminal()) {
|
|
618
|
-
throw new Error(formatMissingProviderConfigMessage());
|
|
694
|
+
throw new Error(formatMissingProviderConfigMessage(providerDefinitions));
|
|
619
695
|
}
|
|
620
696
|
await runInteractiveProviderSetup(cwd, args, promptInput2, providerDefinitions);
|
|
621
697
|
}
|
|
622
698
|
async function runInteractiveProviderSetup(cwd, args, promptInput2, providerDefinitions = DEFAULT_PROVIDER_DEFINITIONS) {
|
|
623
|
-
const
|
|
624
|
-
const
|
|
625
|
-
const providerChoice = await promptInput2(` Provider (${supportedTypes}, default: ${defaultProviderType}): `) || defaultProviderType;
|
|
626
|
-
const type = parseProviderSetupType(providerChoice);
|
|
699
|
+
const providerChoice = await promptInput2(formatProviderSetupSelectionPrompt(providerDefinitions));
|
|
700
|
+
const type = resolveProviderSetupSelection(providerChoice, providerDefinitions);
|
|
627
701
|
const settingsPath = getSettingsPathForScope(cwd, args.settingsScope);
|
|
628
702
|
const input = await runProviderSetupPromptFlow(type, promptInput2, providerDefinitions);
|
|
629
703
|
applyProviderConfiguration(settingsPath, input, {
|
|
@@ -640,9 +714,6 @@ async function runInteractiveProviderSetup(cwd, args, promptInput2, providerDefi
|
|
|
640
714
|
|
|
641
715
|
`);
|
|
642
716
|
}
|
|
643
|
-
function parseProviderSetupType(value) {
|
|
644
|
-
return value.trim();
|
|
645
|
-
}
|
|
646
717
|
function buildSetupInputFromArgs(args) {
|
|
647
718
|
const type = args.providerType ?? args.configureProvider;
|
|
648
719
|
if (!args.configureProvider || !type) {
|
|
@@ -671,25 +742,36 @@ function getSettingsCheckPaths(cwd) {
|
|
|
671
742
|
function isInteractiveTerminal() {
|
|
672
743
|
return process.stdin.isTTY === true && process.stdout.isTTY === true;
|
|
673
744
|
}
|
|
674
|
-
function formatMissingProviderConfigMessage() {
|
|
745
|
+
function formatMissingProviderConfigMessage(providerDefinitions = DEFAULT_PROVIDER_DEFINITIONS) {
|
|
675
746
|
return [
|
|
676
747
|
"No provider configuration found.",
|
|
677
748
|
"Run `robota --configure` in an interactive terminal, or configure a provider:",
|
|
678
|
-
|
|
679
|
-
|
|
749
|
+
`Supported providers: ${(0, import_agent_core.formatSupportedProviderTypes)(providerDefinitions)}`,
|
|
750
|
+
...providerDefinitions.map(formatConfigureProviderExample)
|
|
680
751
|
].join("\n");
|
|
681
752
|
}
|
|
753
|
+
function formatConfigureProviderExample(definition) {
|
|
754
|
+
const flags = [
|
|
755
|
+
`robota --configure-provider ${definition.type}`,
|
|
756
|
+
`--type ${definition.type}`,
|
|
757
|
+
...definition.defaults?.baseURL !== void 0 ? ["--base-url <url>"] : [],
|
|
758
|
+
"--model <model>",
|
|
759
|
+
...definition.requiresApiKey === true ? ["--api-key-env <ENV_NAME>"] : [],
|
|
760
|
+
"--set-current"
|
|
761
|
+
];
|
|
762
|
+
return ` ${flags.join(" ")}`;
|
|
763
|
+
}
|
|
682
764
|
|
|
683
765
|
// src/cli.ts
|
|
684
766
|
var import_agent_transport_headless = require("@robota-sdk/agent-transport-headless");
|
|
685
767
|
|
|
686
768
|
// src/ui/render.tsx
|
|
687
|
-
var
|
|
769
|
+
var import_ink22 = require("ink");
|
|
688
770
|
|
|
689
771
|
// src/ui/App.tsx
|
|
690
|
-
var
|
|
691
|
-
var
|
|
692
|
-
var
|
|
772
|
+
var import_react19 = require("react");
|
|
773
|
+
var import_ink21 = require("ink");
|
|
774
|
+
var import_agent_core9 = require("@robota-sdk/agent-core");
|
|
693
775
|
|
|
694
776
|
// src/ui/hooks/useInteractiveSession.ts
|
|
695
777
|
var import_react2 = require("react");
|
|
@@ -718,7 +800,9 @@ function toBackgroundTaskViewModel(state, partialText) {
|
|
|
718
800
|
errorPreview: trimBackgroundPreview(state.error?.message),
|
|
719
801
|
startedAt: state.startedAt,
|
|
720
802
|
lastActivityAt: state.lastActivityAt,
|
|
721
|
-
timeoutReason: state.timeoutReason
|
|
803
|
+
timeoutReason: state.timeoutReason,
|
|
804
|
+
exitCode: state.result?.exitCode,
|
|
805
|
+
signalCode: state.result?.signalCode
|
|
722
806
|
};
|
|
723
807
|
}
|
|
724
808
|
function getBackgroundTaskStatusLabel(state) {
|
|
@@ -839,6 +923,13 @@ var TuiStateManager = class {
|
|
|
839
923
|
this.activeTools = [];
|
|
840
924
|
this.notify();
|
|
841
925
|
};
|
|
926
|
+
onContextUpdate = (state) => {
|
|
927
|
+
this.setContextState({
|
|
928
|
+
percentage: state.usedPercentage,
|
|
929
|
+
usedTokens: state.usedTokens,
|
|
930
|
+
maxTokens: state.maxTokens
|
|
931
|
+
});
|
|
932
|
+
};
|
|
842
933
|
onBackgroundTaskEvent = (event) => {
|
|
843
934
|
if ("task" in event) {
|
|
844
935
|
this.upsertBackgroundTask(event.task);
|
|
@@ -1013,7 +1104,14 @@ function buildProviderSwitch(providers, profileName) {
|
|
|
1013
1104
|
};
|
|
1014
1105
|
}
|
|
1015
1106
|
function buildProviderSetup(type, providerDefinitions) {
|
|
1016
|
-
if (!type
|
|
1107
|
+
if (!type) {
|
|
1108
|
+
return {
|
|
1109
|
+
message: "Provider setup requested. Select a provider to continue.",
|
|
1110
|
+
success: true,
|
|
1111
|
+
data: { providerSetup: {} }
|
|
1112
|
+
};
|
|
1113
|
+
}
|
|
1114
|
+
if ((0, import_agent_core.findProviderDefinition)(providerDefinitions, type) === void 0) {
|
|
1017
1115
|
return {
|
|
1018
1116
|
message: `Usage: provider add <type>. Supported: ${(0, import_agent_core.formatSupportedProviderTypes)(providerDefinitions)}`,
|
|
1019
1117
|
success: false
|
|
@@ -1101,8 +1199,8 @@ async function routeProviderCommand(cwd, args, interactiveSession, manager, prov
|
|
|
1101
1199
|
getEffects(interactiveSession)._pendingProviderProfile = providerSwitch.profile;
|
|
1102
1200
|
}
|
|
1103
1201
|
const providerSetup = result.data?.providerSetup;
|
|
1104
|
-
if (providerSetup
|
|
1105
|
-
getEffects(interactiveSession).
|
|
1202
|
+
if (providerSetup !== void 0) {
|
|
1203
|
+
getEffects(interactiveSession)._pendingProviderSetup = providerSetup;
|
|
1106
1204
|
}
|
|
1107
1205
|
}
|
|
1108
1206
|
function applySystemCommandResult(result, interactiveSession, manager) {
|
|
@@ -1129,6 +1227,11 @@ function applySystemCommandResult(result, interactiveSession, manager) {
|
|
|
1129
1227
|
effects._sessionName = data.name;
|
|
1130
1228
|
return;
|
|
1131
1229
|
}
|
|
1230
|
+
const statusLinePatch = data?.statuslinePatch;
|
|
1231
|
+
if (isStatusLineSettingsPatch(statusLinePatch)) {
|
|
1232
|
+
effects._statusLinePatch = statusLinePatch;
|
|
1233
|
+
return;
|
|
1234
|
+
}
|
|
1132
1235
|
const ctx = interactiveSession.getContextState();
|
|
1133
1236
|
manager.setContextState({
|
|
1134
1237
|
percentage: ctx.usedPercentage,
|
|
@@ -1173,6 +1276,13 @@ function routeTuiCommand(cmd, interactiveSession) {
|
|
|
1173
1276
|
function getEffects(interactiveSession) {
|
|
1174
1277
|
return interactiveSession;
|
|
1175
1278
|
}
|
|
1279
|
+
function isStatusLineSettingsPatch(value) {
|
|
1280
|
+
if (value === null || typeof value !== "object" || Array.isArray(value) || value instanceof Date) {
|
|
1281
|
+
return false;
|
|
1282
|
+
}
|
|
1283
|
+
const candidate = value;
|
|
1284
|
+
return (candidate.enabled === void 0 || typeof candidate.enabled === "boolean") && (candidate.gitBranch === void 0 || typeof candidate.gitBranch === "boolean");
|
|
1285
|
+
}
|
|
1176
1286
|
|
|
1177
1287
|
// src/ui/hooks/useInteractiveSession.ts
|
|
1178
1288
|
function initializeSession(props, permissionHandler) {
|
|
@@ -1235,8 +1345,8 @@ function useInteractiveSession(props) {
|
|
|
1235
1345
|
});
|
|
1236
1346
|
}, []);
|
|
1237
1347
|
const permissionHandler = (0, import_react2.useCallback)(
|
|
1238
|
-
(toolName, toolArgs) => new Promise((
|
|
1239
|
-
permissionQueueRef.current.push({ toolName, toolArgs, resolve });
|
|
1348
|
+
(toolName, toolArgs) => new Promise((resolve2) => {
|
|
1349
|
+
permissionQueueRef.current.push({ toolName, toolArgs, resolve: resolve2 });
|
|
1240
1350
|
processNextPermission();
|
|
1241
1351
|
}),
|
|
1242
1352
|
[processNextPermission]
|
|
@@ -1261,6 +1371,7 @@ function useInteractiveSession(props) {
|
|
|
1261
1371
|
interactiveSession.on("complete", manager.onComplete);
|
|
1262
1372
|
interactiveSession.on("interrupted", manager.onInterrupted);
|
|
1263
1373
|
interactiveSession.on("error", manager.onError);
|
|
1374
|
+
interactiveSession.on("context_update", manager.onContextUpdate);
|
|
1264
1375
|
interactiveSession.on("background_task_event", manager.onBackgroundTaskEvent);
|
|
1265
1376
|
const initCheck = setInterval(() => {
|
|
1266
1377
|
try {
|
|
@@ -1287,6 +1398,7 @@ function useInteractiveSession(props) {
|
|
|
1287
1398
|
interactiveSession.off("complete", manager.onComplete);
|
|
1288
1399
|
interactiveSession.off("interrupted", manager.onInterrupted);
|
|
1289
1400
|
interactiveSession.off("error", manager.onError);
|
|
1401
|
+
interactiveSession.off("context_update", manager.onContextUpdate);
|
|
1290
1402
|
interactiveSession.off("background_task_event", manager.onBackgroundTaskEvent);
|
|
1291
1403
|
};
|
|
1292
1404
|
}, [interactiveSession, manager]);
|
|
@@ -1449,6 +1561,108 @@ function usePluginCallbacks(cwd) {
|
|
|
1449
1561
|
var import_react4 = require("react");
|
|
1450
1562
|
var import_ink = require("ink");
|
|
1451
1563
|
var import_agent_core4 = require("@robota-sdk/agent-core");
|
|
1564
|
+
|
|
1565
|
+
// src/utils/provider-setup-interaction.ts
|
|
1566
|
+
function startProviderSetupInteraction(providerDefinitions, type) {
|
|
1567
|
+
if (type === void 0) {
|
|
1568
|
+
const state2 = {
|
|
1569
|
+
mode: "select-provider",
|
|
1570
|
+
providerDefinitions
|
|
1571
|
+
};
|
|
1572
|
+
return { status: "prompt", state: state2, prompt: toProviderSelectionPrompt(providerDefinitions) };
|
|
1573
|
+
}
|
|
1574
|
+
const state = {
|
|
1575
|
+
mode: "setup-fields",
|
|
1576
|
+
providerDefinitions,
|
|
1577
|
+
flow: createProviderSetupFlow(type, providerDefinitions)
|
|
1578
|
+
};
|
|
1579
|
+
return { status: "prompt", state, prompt: toProviderSetupStepPrompt(state.flow) };
|
|
1580
|
+
}
|
|
1581
|
+
function submitProviderSetupInteractionValue(state, value) {
|
|
1582
|
+
if (state.mode === "select-provider") {
|
|
1583
|
+
const nextState2 = {
|
|
1584
|
+
mode: "setup-fields",
|
|
1585
|
+
providerDefinitions: state.providerDefinitions,
|
|
1586
|
+
flow: createProviderSetupFlow(value, state.providerDefinitions)
|
|
1587
|
+
};
|
|
1588
|
+
return {
|
|
1589
|
+
status: "prompt",
|
|
1590
|
+
state: nextState2,
|
|
1591
|
+
prompt: toProviderSetupStepPrompt(nextState2.flow)
|
|
1592
|
+
};
|
|
1593
|
+
}
|
|
1594
|
+
const result = submitProviderSetupValue(state.flow, value);
|
|
1595
|
+
if (result.status === "complete") {
|
|
1596
|
+
return { status: "complete", input: result.input };
|
|
1597
|
+
}
|
|
1598
|
+
const nextState = {
|
|
1599
|
+
...state,
|
|
1600
|
+
flow: result.state
|
|
1601
|
+
};
|
|
1602
|
+
return { status: "prompt", state: nextState, prompt: toProviderSetupStepPrompt(result.state) };
|
|
1603
|
+
}
|
|
1604
|
+
function toProviderSelectionPrompt(providerDefinitions) {
|
|
1605
|
+
return {
|
|
1606
|
+
kind: "choice",
|
|
1607
|
+
title: "Select provider",
|
|
1608
|
+
options: providerDefinitions.map((definition) => ({
|
|
1609
|
+
value: definition.type,
|
|
1610
|
+
label: formatProviderSetupChoiceLabel(definition)
|
|
1611
|
+
})),
|
|
1612
|
+
maxVisible: 6
|
|
1613
|
+
};
|
|
1614
|
+
}
|
|
1615
|
+
function toProviderSetupStepPrompt(flow) {
|
|
1616
|
+
const step = getProviderSetupStep(flow);
|
|
1617
|
+
return {
|
|
1618
|
+
kind: "text",
|
|
1619
|
+
title: step.title,
|
|
1620
|
+
...step.defaultValue !== void 0 ? { placeholder: step.defaultValue } : {},
|
|
1621
|
+
...step.defaultValue !== void 0 ? { allowEmpty: true } : {},
|
|
1622
|
+
...step.masked !== void 0 ? { masked: step.masked } : {},
|
|
1623
|
+
validate: (value) => validateProviderSetupValue(step, value)
|
|
1624
|
+
};
|
|
1625
|
+
}
|
|
1626
|
+
|
|
1627
|
+
// src/utils/statusline-settings.ts
|
|
1628
|
+
var DEFAULT_STATUS_LINE_SETTINGS = {
|
|
1629
|
+
enabled: true,
|
|
1630
|
+
gitBranch: true
|
|
1631
|
+
};
|
|
1632
|
+
function readStatusLineSettings(settings) {
|
|
1633
|
+
const raw = settings.statusline;
|
|
1634
|
+
if (!isRecord(raw)) {
|
|
1635
|
+
return { ...DEFAULT_STATUS_LINE_SETTINGS };
|
|
1636
|
+
}
|
|
1637
|
+
return {
|
|
1638
|
+
enabled: typeof raw.enabled === "boolean" ? raw.enabled : DEFAULT_STATUS_LINE_SETTINGS.enabled,
|
|
1639
|
+
gitBranch: typeof raw.gitBranch === "boolean" ? raw.gitBranch : DEFAULT_STATUS_LINE_SETTINGS.gitBranch
|
|
1640
|
+
};
|
|
1641
|
+
}
|
|
1642
|
+
function applyStatusLineSettings(settingsPath, patch) {
|
|
1643
|
+
const settings = readSettings(settingsPath);
|
|
1644
|
+
const next = {
|
|
1645
|
+
...readStatusLineSettings(settings),
|
|
1646
|
+
...patch
|
|
1647
|
+
};
|
|
1648
|
+
settings.statusline = next;
|
|
1649
|
+
writeSettings(settingsPath, settings);
|
|
1650
|
+
return next;
|
|
1651
|
+
}
|
|
1652
|
+
function isRecord(value) {
|
|
1653
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) && !(value instanceof Date);
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1656
|
+
// src/ui/hooks/statusline-side-effect.ts
|
|
1657
|
+
function applyPendingStatusLinePatch(sideEffects, setStatusLineSettings) {
|
|
1658
|
+
if (!sideEffects._statusLinePatch) return false;
|
|
1659
|
+
const patch = sideEffects._statusLinePatch;
|
|
1660
|
+
delete sideEffects._statusLinePatch;
|
|
1661
|
+
setStatusLineSettings(applyStatusLineSettings(getUserSettingsPath(), patch));
|
|
1662
|
+
return true;
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
// src/ui/hooks/useSideEffects.ts
|
|
1452
1666
|
var EXIT_DELAY_MS = 500;
|
|
1453
1667
|
function useSideEffects({
|
|
1454
1668
|
cwd,
|
|
@@ -1456,6 +1670,7 @@ function useSideEffects({
|
|
|
1456
1670
|
addEntry,
|
|
1457
1671
|
baseHandleSubmit,
|
|
1458
1672
|
setSessionName,
|
|
1673
|
+
setStatusLineSettings,
|
|
1459
1674
|
providerDefinitions
|
|
1460
1675
|
}) {
|
|
1461
1676
|
const { exit } = (0, import_ink.useApp)();
|
|
@@ -1463,7 +1678,8 @@ function useSideEffects({
|
|
|
1463
1678
|
const pendingModelChangeRef = (0, import_react4.useRef)(null);
|
|
1464
1679
|
const [pendingProviderProfile, setPendingProviderProfile] = (0, import_react4.useState)(null);
|
|
1465
1680
|
const pendingProviderProfileRef = (0, import_react4.useRef)(null);
|
|
1466
|
-
const [
|
|
1681
|
+
const [pendingInteractionPrompt, setPendingInteractionPrompt] = (0, import_react4.useState)(null);
|
|
1682
|
+
const providerSetupInteractionRef = (0, import_react4.useRef)(null);
|
|
1467
1683
|
const [showPluginTUI, setShowPluginTUI] = (0, import_react4.useState)(false);
|
|
1468
1684
|
const [showSessionPicker, setShowSessionPicker] = (0, import_react4.useState)(false);
|
|
1469
1685
|
const requestShutdown = (0, import_react4.useCallback)(
|
|
@@ -1506,10 +1722,14 @@ function useSideEffects({
|
|
|
1506
1722
|
setPendingProviderProfile(profile);
|
|
1507
1723
|
return;
|
|
1508
1724
|
}
|
|
1509
|
-
if (sideEffects.
|
|
1510
|
-
const
|
|
1511
|
-
delete sideEffects.
|
|
1512
|
-
|
|
1725
|
+
if (sideEffects._pendingProviderSetup !== void 0) {
|
|
1726
|
+
const setup = sideEffects._pendingProviderSetup;
|
|
1727
|
+
delete sideEffects._pendingProviderSetup;
|
|
1728
|
+
const result = startProviderSetupInteraction(providerDefinitions, setup.type);
|
|
1729
|
+
if (result.status === "prompt") {
|
|
1730
|
+
providerSetupInteractionRef.current = result.state;
|
|
1731
|
+
setPendingInteractionPrompt(result.prompt);
|
|
1732
|
+
}
|
|
1513
1733
|
return;
|
|
1514
1734
|
}
|
|
1515
1735
|
if (sideEffects._resetRequested) {
|
|
@@ -1547,8 +1767,17 @@ function useSideEffects({
|
|
|
1547
1767
|
setSessionName(name);
|
|
1548
1768
|
return;
|
|
1549
1769
|
}
|
|
1770
|
+
if (applyPendingStatusLinePatch(sideEffects, setStatusLineSettings)) return;
|
|
1550
1771
|
},
|
|
1551
|
-
[
|
|
1772
|
+
[
|
|
1773
|
+
interactiveSession,
|
|
1774
|
+
baseHandleSubmit,
|
|
1775
|
+
addEntry,
|
|
1776
|
+
requestShutdown,
|
|
1777
|
+
setSessionName,
|
|
1778
|
+
setStatusLineSettings,
|
|
1779
|
+
providerDefinitions
|
|
1780
|
+
]
|
|
1552
1781
|
);
|
|
1553
1782
|
const handleModelConfirm = (0, import_react4.useCallback)(
|
|
1554
1783
|
(index) => {
|
|
@@ -1608,9 +1837,10 @@ function useSideEffects({
|
|
|
1608
1837
|
},
|
|
1609
1838
|
[cwd, addEntry, requestShutdown]
|
|
1610
1839
|
);
|
|
1611
|
-
const
|
|
1840
|
+
const completeProviderSetup = (0, import_react4.useCallback)(
|
|
1612
1841
|
(input) => {
|
|
1613
|
-
|
|
1842
|
+
providerSetupInteractionRef.current = null;
|
|
1843
|
+
setPendingInteractionPrompt(null);
|
|
1614
1844
|
try {
|
|
1615
1845
|
const settingsPath = getUserSettingsPath();
|
|
1616
1846
|
applyProviderConfiguration(settingsPath, input, { providerDefinitions });
|
|
@@ -1630,15 +1860,43 @@ function useSideEffects({
|
|
|
1630
1860
|
},
|
|
1631
1861
|
[addEntry, requestShutdown, providerDefinitions]
|
|
1632
1862
|
);
|
|
1633
|
-
const
|
|
1634
|
-
|
|
1863
|
+
const handleInteractionSubmit = (0, import_react4.useCallback)(
|
|
1864
|
+
(value) => {
|
|
1865
|
+
const state = providerSetupInteractionRef.current;
|
|
1866
|
+
if (state === null) {
|
|
1867
|
+
setPendingInteractionPrompt(null);
|
|
1868
|
+
return;
|
|
1869
|
+
}
|
|
1870
|
+
try {
|
|
1871
|
+
const result = submitProviderSetupInteractionValue(state, value);
|
|
1872
|
+
if (result.status === "complete") {
|
|
1873
|
+
completeProviderSetup(result.input);
|
|
1874
|
+
return;
|
|
1875
|
+
}
|
|
1876
|
+
providerSetupInteractionRef.current = result.state;
|
|
1877
|
+
setPendingInteractionPrompt(result.prompt);
|
|
1878
|
+
} catch (err) {
|
|
1879
|
+
providerSetupInteractionRef.current = null;
|
|
1880
|
+
setPendingInteractionPrompt(null);
|
|
1881
|
+
addEntry(
|
|
1882
|
+
(0, import_agent_core4.messageToHistoryEntry)(
|
|
1883
|
+
(0, import_agent_core4.createSystemMessage)(`Failed: ${err instanceof Error ? err.message : String(err)}`)
|
|
1884
|
+
)
|
|
1885
|
+
);
|
|
1886
|
+
}
|
|
1887
|
+
},
|
|
1888
|
+
[addEntry, completeProviderSetup]
|
|
1889
|
+
);
|
|
1890
|
+
const handleInteractionCancel = (0, import_react4.useCallback)(() => {
|
|
1891
|
+
providerSetupInteractionRef.current = null;
|
|
1892
|
+
setPendingInteractionPrompt(null);
|
|
1635
1893
|
addEntry((0, import_agent_core4.messageToHistoryEntry)((0, import_agent_core4.createSystemMessage)("Provider setup cancelled.")));
|
|
1636
1894
|
}, [addEntry]);
|
|
1637
1895
|
return {
|
|
1638
1896
|
handleSubmit,
|
|
1639
1897
|
pendingModelId,
|
|
1640
1898
|
pendingProviderProfile,
|
|
1641
|
-
|
|
1899
|
+
pendingInteractionPrompt,
|
|
1642
1900
|
showPluginTUI,
|
|
1643
1901
|
showSessionPicker,
|
|
1644
1902
|
setPendingModelId,
|
|
@@ -1646,102 +1904,344 @@ function useSideEffects({
|
|
|
1646
1904
|
setShowSessionPicker,
|
|
1647
1905
|
handleModelConfirm,
|
|
1648
1906
|
handleProviderConfirm,
|
|
1649
|
-
|
|
1650
|
-
|
|
1907
|
+
handleInteractionSubmit,
|
|
1908
|
+
handleInteractionCancel
|
|
1651
1909
|
};
|
|
1652
1910
|
}
|
|
1653
1911
|
|
|
1912
|
+
// src/ui/hooks/useStatusLineSettings.ts
|
|
1913
|
+
var import_react5 = require("react");
|
|
1914
|
+
function useStatusLineSettings() {
|
|
1915
|
+
return (0, import_react5.useState)(
|
|
1916
|
+
() => readStatusLineSettings(readSettings(getUserSettingsPath()))
|
|
1917
|
+
);
|
|
1918
|
+
}
|
|
1919
|
+
|
|
1654
1920
|
// src/ui/MessageList.tsx
|
|
1655
|
-
var
|
|
1656
|
-
var
|
|
1657
|
-
var
|
|
1921
|
+
var import_react6 = __toESM(require("react"), 1);
|
|
1922
|
+
var import_ink5 = require("ink");
|
|
1923
|
+
var import_agent_core6 = require("@robota-sdk/agent-core");
|
|
1658
1924
|
|
|
1659
1925
|
// src/ui/render-markdown.ts
|
|
1660
1926
|
var import_marked = require("marked");
|
|
1661
1927
|
var import_marked_terminal = __toESM(require("marked-terminal"), 1);
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1928
|
+
var ANSI_RED = "\x1B[31m";
|
|
1929
|
+
var ANSI_GREEN = "\x1B[32m";
|
|
1930
|
+
var ANSI_CYAN = "\x1B[36m";
|
|
1931
|
+
var ANSI_DIM = "\x1B[2m";
|
|
1932
|
+
var ANSI_RESET = "\x1B[0m";
|
|
1933
|
+
var CODE_BLOCK_INDENT = " ";
|
|
1934
|
+
var ZERO_COLOR = "0";
|
|
1935
|
+
var TerminalRendererConstructor = import_marked_terminal.default;
|
|
1936
|
+
function shouldUseColor(option) {
|
|
1937
|
+
if (option !== void 0) {
|
|
1938
|
+
return option;
|
|
1939
|
+
}
|
|
1940
|
+
if (process.env.NO_COLOR || process.env.FORCE_COLOR === ZERO_COLOR) {
|
|
1941
|
+
return false;
|
|
1942
|
+
}
|
|
1943
|
+
if (process.env.FORCE_COLOR) {
|
|
1944
|
+
return true;
|
|
1945
|
+
}
|
|
1946
|
+
return Boolean(process.stdout.isTTY);
|
|
1947
|
+
}
|
|
1948
|
+
function isDiffLanguage(language) {
|
|
1949
|
+
return language?.trim().toLowerCase() === "diff";
|
|
1950
|
+
}
|
|
1951
|
+
function colorizeDiffLine(line, color) {
|
|
1952
|
+
if (!color) {
|
|
1953
|
+
return line;
|
|
1954
|
+
}
|
|
1955
|
+
if (line.startsWith("+")) {
|
|
1956
|
+
return `${ANSI_GREEN}${line}${ANSI_RESET}`;
|
|
1957
|
+
}
|
|
1958
|
+
if (line.startsWith("-")) {
|
|
1959
|
+
return `${ANSI_RED}${line}${ANSI_RESET}`;
|
|
1960
|
+
}
|
|
1961
|
+
if (line.startsWith("@@")) {
|
|
1962
|
+
return `${ANSI_CYAN}${line}${ANSI_RESET}`;
|
|
1963
|
+
}
|
|
1964
|
+
if (line.startsWith("diff ") || line.startsWith("index ")) {
|
|
1965
|
+
return `${ANSI_DIM}${line}${ANSI_RESET}`;
|
|
1966
|
+
}
|
|
1967
|
+
return line;
|
|
1968
|
+
}
|
|
1969
|
+
function renderDiffCodeBlock(code, color) {
|
|
1970
|
+
const body = code.split("\n").map((line) => `${CODE_BLOCK_INDENT}${colorizeDiffLine(line, color)}`).join("\n");
|
|
1971
|
+
return `${body}
|
|
1972
|
+
|
|
1973
|
+
`;
|
|
1974
|
+
}
|
|
1975
|
+
function createTerminalRenderer(color) {
|
|
1976
|
+
const renderer = new TerminalRendererConstructor(void 0, { ignoreIllegals: true });
|
|
1977
|
+
const renderCode = renderer.code.bind(renderer);
|
|
1978
|
+
renderer.code = (code, language, escaped) => {
|
|
1979
|
+
if (isDiffLanguage(language)) {
|
|
1980
|
+
return renderDiffCodeBlock(code, color);
|
|
1981
|
+
}
|
|
1982
|
+
return renderCode(code, language, escaped);
|
|
1983
|
+
};
|
|
1984
|
+
return renderer;
|
|
1985
|
+
}
|
|
1986
|
+
function renderMarkdown(md, options = {}) {
|
|
1987
|
+
const result = import_marked.marked.parse(md, {
|
|
1988
|
+
renderer: createTerminalRenderer(shouldUseColor(options.color))
|
|
1989
|
+
});
|
|
1667
1990
|
return typeof result === "string" ? result.trimEnd() : md;
|
|
1668
1991
|
}
|
|
1669
1992
|
|
|
1670
|
-
// src/ui/
|
|
1993
|
+
// src/ui/ToolDiffBlock.tsx
|
|
1671
1994
|
var import_ink2 = require("ink");
|
|
1672
|
-
|
|
1995
|
+
|
|
1996
|
+
// src/utils/tool-diff-summary.ts
|
|
1673
1997
|
var MAX_DIFF_LINES = 12;
|
|
1674
1998
|
var TRUNCATED_SHOW = 10;
|
|
1675
|
-
function
|
|
1676
|
-
const
|
|
1677
|
-
const
|
|
1678
|
-
const
|
|
1679
|
-
const
|
|
1680
|
-
|
|
1999
|
+
function buildToolDiffSummary(input) {
|
|
2000
|
+
const visibleLines = input.lines.length > MAX_DIFF_LINES ? selectVisibleDiffLines(input.lines) : input.lines;
|
|
2001
|
+
const lineNumberWidth = Math.max(...visibleLines.map((line) => line.lineNumber), 0).toString().length;
|
|
2002
|
+
const body = visibleLines.map((line) => formatDiffLine(line, lineNumberWidth));
|
|
2003
|
+
const truncated = input.lines.length > MAX_DIFF_LINES;
|
|
2004
|
+
return {
|
|
2005
|
+
file: input.file,
|
|
2006
|
+
markdown: ["```diff", ...body, "```"].join("\n"),
|
|
2007
|
+
truncated,
|
|
2008
|
+
remainingLineCount: truncated ? input.lines.length - visibleLines.length : 0
|
|
2009
|
+
};
|
|
2010
|
+
}
|
|
2011
|
+
function formatDiffLine(line, lineNumberWidth) {
|
|
2012
|
+
if (line.type === "hunk") return line.text;
|
|
2013
|
+
const lineNumber = line.lineNumber.toString().padStart(lineNumberWidth, " ");
|
|
2014
|
+
if (line.type === "remove") return `- ${lineNumber} | ${line.text}`;
|
|
2015
|
+
if (line.type === "add") return `+ ${lineNumber} | ${line.text}`;
|
|
2016
|
+
return ` ${lineNumber} | ${line.text}`;
|
|
2017
|
+
}
|
|
2018
|
+
function selectVisibleDiffLines(lines) {
|
|
2019
|
+
const groups = groupByHunk(lines);
|
|
2020
|
+
const visible = [];
|
|
2021
|
+
for (const group of groups) {
|
|
2022
|
+
if (visible.length === 0 && group.length > TRUNCATED_SHOW) {
|
|
2023
|
+
return group.slice(0, TRUNCATED_SHOW);
|
|
2024
|
+
}
|
|
2025
|
+
if (visible.length + group.length > TRUNCATED_SHOW) break;
|
|
2026
|
+
visible.push(...group);
|
|
2027
|
+
}
|
|
2028
|
+
return visible.length > 0 ? visible : lines.slice(0, TRUNCATED_SHOW);
|
|
2029
|
+
}
|
|
2030
|
+
function groupByHunk(lines) {
|
|
2031
|
+
const groups = [];
|
|
2032
|
+
let current = [];
|
|
2033
|
+
for (const line of lines) {
|
|
2034
|
+
if (line.type === "hunk" && current.length > 0) {
|
|
2035
|
+
groups.push(current);
|
|
2036
|
+
current = [line];
|
|
2037
|
+
continue;
|
|
2038
|
+
}
|
|
2039
|
+
current.push(line);
|
|
2040
|
+
}
|
|
2041
|
+
if (current.length > 0) {
|
|
2042
|
+
groups.push(current);
|
|
2043
|
+
}
|
|
2044
|
+
return groups;
|
|
2045
|
+
}
|
|
2046
|
+
|
|
2047
|
+
// src/ui/ToolDiffBlock.tsx
|
|
2048
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
2049
|
+
function ToolDiffBlock({ file, lines }) {
|
|
2050
|
+
const summary = buildToolDiffSummary({ file, lines });
|
|
1681
2051
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink2.Box, { flexDirection: "column", marginLeft: 4, children: [
|
|
1682
|
-
file && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink2.Text, { color: "white", dimColor: true, children: [
|
|
2052
|
+
summary.file && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink2.Text, { color: "white", dimColor: true, children: [
|
|
1683
2053
|
"\u2502 ",
|
|
1684
|
-
file
|
|
2054
|
+
summary.file
|
|
1685
2055
|
] }),
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
if (line.type === "context") {
|
|
1689
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink2.Text, { color: "white", dimColor: true, children: [
|
|
1690
|
-
"\u2502 ",
|
|
1691
|
-
lineNum,
|
|
1692
|
-
" ",
|
|
1693
|
-
line.text
|
|
1694
|
-
] }, i);
|
|
1695
|
-
}
|
|
1696
|
-
const prefix = line.type === "remove" ? "-" : "+";
|
|
1697
|
-
const bgColor = line.type === "remove" ? "#5c1a1a" : "#1a3d1a";
|
|
1698
|
-
const fgColor = line.type === "remove" ? "#ff9999" : "#99ff99";
|
|
1699
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink2.Text, { color: fgColor, backgroundColor: bgColor, children: [
|
|
1700
|
-
"\u2502 ",
|
|
1701
|
-
lineNum,
|
|
1702
|
-
" ",
|
|
1703
|
-
prefix,
|
|
1704
|
-
" ",
|
|
1705
|
-
line.text
|
|
1706
|
-
] }, i);
|
|
1707
|
-
}),
|
|
1708
|
-
truncated && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink2.Text, { color: "white", dimColor: true, children: [
|
|
2056
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink2.Text, { children: renderMarkdown(summary.markdown) }),
|
|
2057
|
+
summary.truncated && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink2.Text, { color: "white", dimColor: true, children: [
|
|
1709
2058
|
"\u2502 ... and ",
|
|
1710
|
-
|
|
2059
|
+
summary.remainingLineCount,
|
|
1711
2060
|
" more lines"
|
|
1712
2061
|
] })
|
|
1713
2062
|
] });
|
|
1714
2063
|
}
|
|
1715
2064
|
|
|
1716
|
-
// src/ui/
|
|
2065
|
+
// src/ui/UsageSummaryEntry.tsx
|
|
2066
|
+
var import_ink3 = require("ink");
|
|
2067
|
+
var import_agent_core5 = require("@robota-sdk/agent-core");
|
|
1717
2068
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
2069
|
+
var TOKEN_COMPACT_THRESHOLD = 1e3;
|
|
2070
|
+
function UsageSummaryEntry({ entry }) {
|
|
2071
|
+
const usage = entry.data;
|
|
2072
|
+
if (!usage) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, {});
|
|
2073
|
+
const prompt = usage.promptTokens !== void 0 ? formatUsageTokenCount(usage.promptTokens) : "?";
|
|
2074
|
+
const completion = usage.completionTokens !== void 0 ? formatUsageTokenCount(usage.completionTokens) : "?";
|
|
2075
|
+
const total = formatUsageTokenCount(usage.totalTokens);
|
|
2076
|
+
const context = `${Math.round(usage.contextUsedPercentage)}% (${(0, import_agent_core5.formatTokenCount)(
|
|
2077
|
+
usage.contextUsedTokens
|
|
2078
|
+
)}/${(0, import_agent_core5.formatTokenCount)(usage.contextMaxTokens)})`;
|
|
2079
|
+
const costLabel = usage.costStatus === "unknown" ? "cost unknown" : `cost ${usage.costStatus}`;
|
|
2080
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink3.Box, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink3.Box, { children: [
|
|
2081
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink3.Text, { color: "white", bold: true, children: [
|
|
2082
|
+
"Usage:",
|
|
2083
|
+
" "
|
|
2084
|
+
] }),
|
|
2085
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink3.Text, { dimColor: true, children: [
|
|
2086
|
+
usage.kind,
|
|
2087
|
+
" ",
|
|
2088
|
+
total,
|
|
2089
|
+
" tokens (in ",
|
|
2090
|
+
prompt,
|
|
2091
|
+
" / out ",
|
|
2092
|
+
completion,
|
|
2093
|
+
") \xB7 Context ",
|
|
2094
|
+
context,
|
|
2095
|
+
" \xB7",
|
|
2096
|
+
" ",
|
|
2097
|
+
costLabel
|
|
2098
|
+
] })
|
|
2099
|
+
] }) });
|
|
2100
|
+
}
|
|
2101
|
+
function formatUsageTokenCount(tokens) {
|
|
2102
|
+
return tokens < TOKEN_COMPACT_THRESHOLD ? tokens.toLocaleString() : (0, import_agent_core5.formatTokenCount)(tokens);
|
|
2103
|
+
}
|
|
2104
|
+
|
|
2105
|
+
// src/ui/command-output-summary.ts
|
|
2106
|
+
var MAX_PREVIEW_LINES = 4;
|
|
2107
|
+
var SUCCESS_EXIT_CODE2 = 0;
|
|
2108
|
+
var COMMAND_TOOL_NAMES = /* @__PURE__ */ new Set(["Bash", "BackgroundProcess"]);
|
|
2109
|
+
function formatCommandOutputSummary(tool) {
|
|
2110
|
+
if (!COMMAND_TOOL_NAMES.has(tool.toolName) || !tool.toolResultData) return void 0;
|
|
2111
|
+
const parsed = parseToolResultData(tool.toolResultData);
|
|
2112
|
+
const exitCode = getNumberValue(parsed, "exitCode");
|
|
2113
|
+
const successValue = getBooleanValue(parsed, "success");
|
|
2114
|
+
const output = buildOutputText(tool.toolResultData, parsed);
|
|
2115
|
+
const lines = trimTrailingBlankLines(splitOutputLines(output));
|
|
2116
|
+
const previewLines = lines.slice(0, MAX_PREVIEW_LINES);
|
|
2117
|
+
const omittedLineCount = Math.max(0, lines.length - previewLines.length);
|
|
2118
|
+
const isFailed = tool.result === "error" || successValue === false || exitCode !== void 0 && exitCode !== SUCCESS_EXIT_CODE2;
|
|
2119
|
+
return {
|
|
2120
|
+
status: isFailed ? "error" : "success",
|
|
2121
|
+
statusLabel: formatStatusLabel(isFailed, exitCode),
|
|
2122
|
+
previewLines,
|
|
2123
|
+
omittedLineCount,
|
|
2124
|
+
transcriptHint: omittedLineCount > 0 ? `... +${omittedLineCount} lines (full output in session transcript)` : void 0
|
|
2125
|
+
};
|
|
2126
|
+
}
|
|
2127
|
+
function parseToolResultData(value) {
|
|
2128
|
+
try {
|
|
2129
|
+
return JSON.parse(value);
|
|
2130
|
+
} catch {
|
|
2131
|
+
return value;
|
|
2132
|
+
}
|
|
2133
|
+
}
|
|
2134
|
+
function buildOutputText(raw, parsed) {
|
|
2135
|
+
if (!isUniversalObject(parsed)) return raw;
|
|
2136
|
+
const output = getStringValue(parsed, "output");
|
|
2137
|
+
if (output !== void 0) return output;
|
|
2138
|
+
const stdout = getStringValue(parsed, "stdout");
|
|
2139
|
+
const stderr = getStringValue(parsed, "stderr");
|
|
2140
|
+
const error = getStringValue(parsed, "error");
|
|
2141
|
+
const lines = [];
|
|
2142
|
+
if (stdout) lines.push(stdout);
|
|
2143
|
+
if (stderr) lines.push(prefixLines(stderr, "[stderr] "));
|
|
2144
|
+
if (!stdout && !stderr && error) lines.push(error);
|
|
2145
|
+
return lines.join("\n");
|
|
2146
|
+
}
|
|
2147
|
+
function formatStatusLabel(isFailed, exitCode) {
|
|
2148
|
+
if (exitCode !== void 0 && exitCode !== SUCCESS_EXIT_CODE2) return `exit ${exitCode}`;
|
|
2149
|
+
return isFailed ? "error" : "ok";
|
|
2150
|
+
}
|
|
2151
|
+
function splitOutputLines(output) {
|
|
2152
|
+
if (!output) return [];
|
|
2153
|
+
return output.replace(/\r\n/g, "\n").split("\n");
|
|
2154
|
+
}
|
|
2155
|
+
function trimTrailingBlankLines(lines) {
|
|
2156
|
+
let end = lines.length;
|
|
2157
|
+
while (end > 0 && lines[end - 1].trim().length === 0) {
|
|
2158
|
+
end -= 1;
|
|
2159
|
+
}
|
|
2160
|
+
return lines.slice(0, end);
|
|
2161
|
+
}
|
|
2162
|
+
function prefixLines(value, prefix) {
|
|
2163
|
+
return splitOutputLines(value).map((line) => `${prefix}${line}`).join("\n");
|
|
2164
|
+
}
|
|
2165
|
+
function isUniversalObject(value) {
|
|
2166
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof Date);
|
|
2167
|
+
}
|
|
2168
|
+
function getStringValue(source, key) {
|
|
2169
|
+
if (!isUniversalObject(source)) return void 0;
|
|
2170
|
+
const value = source[key];
|
|
2171
|
+
return typeof value === "string" ? value : void 0;
|
|
2172
|
+
}
|
|
2173
|
+
function getNumberValue(source, key) {
|
|
2174
|
+
if (!isUniversalObject(source)) return void 0;
|
|
2175
|
+
const value = source[key];
|
|
2176
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
2177
|
+
}
|
|
2178
|
+
function getBooleanValue(source, key) {
|
|
2179
|
+
if (!isUniversalObject(source)) return void 0;
|
|
2180
|
+
const value = source[key];
|
|
2181
|
+
return typeof value === "boolean" ? value : void 0;
|
|
2182
|
+
}
|
|
2183
|
+
|
|
2184
|
+
// src/ui/ToolCommandOutput.tsx
|
|
2185
|
+
var import_ink4 = require("ink");
|
|
2186
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
2187
|
+
function ToolCommandOutput({ tool }) {
|
|
2188
|
+
const summary = formatCommandOutputSummary(tool);
|
|
2189
|
+
if (!summary) return null;
|
|
2190
|
+
if (summary.statusLabel === "ok" && summary.previewLines.length === 0 && !summary.transcriptHint) {
|
|
2191
|
+
return null;
|
|
2192
|
+
}
|
|
2193
|
+
const color = summary.status === "error" ? "red" : "white";
|
|
2194
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_ink4.Box, { flexDirection: "column", marginLeft: 4, children: [
|
|
2195
|
+
summary.statusLabel !== "ok" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ink4.Text, { color, dimColor: true, children: summary.statusLabel }),
|
|
2196
|
+
summary.previewLines.map((line, index) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ink4.Text, { color, dimColor: true, children: line }, `${line}-${index}`)),
|
|
2197
|
+
summary.transcriptHint && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ink4.Text, { dimColor: true, children: summary.transcriptHint })
|
|
2198
|
+
] });
|
|
2199
|
+
}
|
|
2200
|
+
|
|
2201
|
+
// src/ui/MessageList.tsx
|
|
2202
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
2203
|
+
function getToolSummaryStatus(tool) {
|
|
2204
|
+
if (formatCommandOutputSummary(tool)?.status === "error") return "\u2717";
|
|
2205
|
+
if (tool.isRunning) return "\u27F3";
|
|
2206
|
+
if (tool.result === "error") return "\u2717";
|
|
2207
|
+
if (tool.result === "denied") return "\u2298";
|
|
2208
|
+
return "\u2713";
|
|
2209
|
+
}
|
|
2210
|
+
function getToolSummaryColor(tool) {
|
|
2211
|
+
if (formatCommandOutputSummary(tool)?.status === "error" || tool.result === "error") return "red";
|
|
2212
|
+
if (tool.isRunning || tool.result === "denied") return "yellow";
|
|
2213
|
+
return "green";
|
|
2214
|
+
}
|
|
2215
|
+
function getToolSummaryLabel(tool) {
|
|
2216
|
+
return `${getToolSummaryStatus(tool)} ${tool.toolName}${tool.firstArg ? `(${tool.firstArg})` : ""}`;
|
|
2217
|
+
}
|
|
1718
2218
|
function RoleLabel({ role }) {
|
|
1719
2219
|
switch (role) {
|
|
1720
2220
|
case "user":
|
|
1721
|
-
return /* @__PURE__ */ (0,
|
|
2221
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ink5.Text, { color: "green", bold: true, children: [
|
|
1722
2222
|
"You:",
|
|
1723
2223
|
" "
|
|
1724
2224
|
] });
|
|
1725
2225
|
case "assistant":
|
|
1726
|
-
return /* @__PURE__ */ (0,
|
|
2226
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ink5.Text, { color: "cyan", bold: true, children: [
|
|
1727
2227
|
"Robota:",
|
|
1728
2228
|
" "
|
|
1729
2229
|
] });
|
|
1730
2230
|
case "system":
|
|
1731
|
-
return /* @__PURE__ */ (0,
|
|
2231
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ink5.Text, { color: "yellow", bold: true, children: [
|
|
1732
2232
|
"System:",
|
|
1733
2233
|
" "
|
|
1734
2234
|
] });
|
|
1735
2235
|
case "tool":
|
|
1736
|
-
return /* @__PURE__ */ (0,
|
|
2236
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ink5.Text, { color: "white", bold: true, children: [
|
|
1737
2237
|
"Tool:",
|
|
1738
2238
|
" "
|
|
1739
2239
|
] });
|
|
1740
2240
|
}
|
|
1741
2241
|
}
|
|
1742
2242
|
function ToolMessage({ message }) {
|
|
1743
|
-
if (!(0,
|
|
1744
|
-
return /* @__PURE__ */ (0,
|
|
2243
|
+
if (!(0, import_agent_core6.isToolMessage)(message)) {
|
|
2244
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, {});
|
|
1745
2245
|
}
|
|
1746
2246
|
const toolName = message.name;
|
|
1747
2247
|
const content = message.content;
|
|
@@ -1754,45 +2254,45 @@ function ToolMessage({ message }) {
|
|
|
1754
2254
|
} catch {
|
|
1755
2255
|
}
|
|
1756
2256
|
if (summaries) {
|
|
1757
|
-
return /* @__PURE__ */ (0,
|
|
1758
|
-
/* @__PURE__ */ (0,
|
|
1759
|
-
/* @__PURE__ */ (0,
|
|
2257
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ink5.Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
2258
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ink5.Box, { children: [
|
|
2259
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ink5.Text, { color: "white", bold: true, children: [
|
|
1760
2260
|
"Tool:",
|
|
1761
2261
|
" "
|
|
1762
2262
|
] }),
|
|
1763
|
-
toolName && /* @__PURE__ */ (0,
|
|
2263
|
+
toolName && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ink5.Text, { color: "white", dimColor: true, children: [
|
|
1764
2264
|
"[",
|
|
1765
2265
|
toolName,
|
|
1766
2266
|
"]"
|
|
1767
2267
|
] })
|
|
1768
2268
|
] }),
|
|
1769
|
-
/* @__PURE__ */ (0,
|
|
1770
|
-
summaries.map((s, i) => /* @__PURE__ */ (0,
|
|
1771
|
-
/* @__PURE__ */ (0,
|
|
2269
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ink5.Text, { children: " " }),
|
|
2270
|
+
summaries.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ink5.Box, { flexDirection: "column", children: [
|
|
2271
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ink5.Text, { color: "green", children: [
|
|
1772
2272
|
" ",
|
|
1773
2273
|
"\u2713",
|
|
1774
2274
|
" ",
|
|
1775
2275
|
s.line
|
|
1776
2276
|
] }),
|
|
1777
|
-
s.diffLines && s.diffLines.length > 0 && /* @__PURE__ */ (0,
|
|
2277
|
+
s.diffLines && s.diffLines.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ToolDiffBlock, { file: s.diffFile, lines: s.diffLines })
|
|
1778
2278
|
] }, i))
|
|
1779
2279
|
] });
|
|
1780
2280
|
}
|
|
1781
2281
|
const lines = content.split("\n").filter((l) => l.trim());
|
|
1782
|
-
return /* @__PURE__ */ (0,
|
|
1783
|
-
/* @__PURE__ */ (0,
|
|
1784
|
-
/* @__PURE__ */ (0,
|
|
2282
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ink5.Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
2283
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ink5.Box, { children: [
|
|
2284
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ink5.Text, { color: "white", bold: true, children: [
|
|
1785
2285
|
"Tool:",
|
|
1786
2286
|
" "
|
|
1787
2287
|
] }),
|
|
1788
|
-
toolName && /* @__PURE__ */ (0,
|
|
2288
|
+
toolName && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ink5.Text, { color: "white", dimColor: true, children: [
|
|
1789
2289
|
"[",
|
|
1790
2290
|
toolName,
|
|
1791
2291
|
"]"
|
|
1792
2292
|
] })
|
|
1793
2293
|
] }),
|
|
1794
|
-
/* @__PURE__ */ (0,
|
|
1795
|
-
lines.map((line, i) => /* @__PURE__ */ (0,
|
|
2294
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ink5.Text, { children: " " }),
|
|
2295
|
+
lines.map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ink5.Text, { color: "green", children: [
|
|
1796
2296
|
" ",
|
|
1797
2297
|
"\u2713",
|
|
1798
2298
|
" ",
|
|
@@ -1800,30 +2300,48 @@ function ToolMessage({ message }) {
|
|
|
1800
2300
|
] }, i))
|
|
1801
2301
|
] });
|
|
1802
2302
|
}
|
|
1803
|
-
var MessageItem =
|
|
2303
|
+
var MessageItem = import_react6.default.memo(function MessageItem2({
|
|
1804
2304
|
message
|
|
1805
2305
|
}) {
|
|
1806
|
-
if ((0,
|
|
1807
|
-
return /* @__PURE__ */ (0,
|
|
2306
|
+
if ((0, import_agent_core6.isToolMessage)(message)) {
|
|
2307
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ToolMessage, { message });
|
|
1808
2308
|
}
|
|
1809
2309
|
const content = message.content ?? "";
|
|
1810
2310
|
const isInterrupted = message.state === "interrupted";
|
|
1811
|
-
return /* @__PURE__ */ (0,
|
|
1812
|
-
/* @__PURE__ */ (0,
|
|
1813
|
-
/* @__PURE__ */ (0,
|
|
1814
|
-
/* @__PURE__ */ (0,
|
|
2311
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ink5.Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
2312
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ink5.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(RoleLabel, { role: message.role }) }),
|
|
2313
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ink5.Text, { children: " " }),
|
|
2314
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ink5.Box, { marginLeft: 2, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ink5.Text, { wrap: "wrap", children: (0, import_agent_core6.isAssistantMessage)(message) ? renderMarkdown(content + (isInterrupted ? "\n\n_(interrupted)_" : "")) : content }) })
|
|
1815
2315
|
] });
|
|
1816
2316
|
});
|
|
1817
2317
|
function ToolSummaryEntry({ entry }) {
|
|
1818
2318
|
const data = entry.data;
|
|
2319
|
+
const tools = data?.tools;
|
|
1819
2320
|
const lines = data?.summary?.split("\n") ?? [];
|
|
1820
|
-
|
|
1821
|
-
|
|
2321
|
+
if (tools && tools.length > 0) {
|
|
2322
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ink5.Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
2323
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ink5.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ink5.Text, { color: "white", bold: true, children: [
|
|
2324
|
+
"Tool:",
|
|
2325
|
+
" "
|
|
2326
|
+
] }) }),
|
|
2327
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ink5.Text, { children: " " }),
|
|
2328
|
+
tools.map((tool, i) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ink5.Box, { flexDirection: "column", children: [
|
|
2329
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ink5.Text, { color: getToolSummaryColor(tool), children: [
|
|
2330
|
+
" ",
|
|
2331
|
+
getToolSummaryLabel(tool)
|
|
2332
|
+
] }),
|
|
2333
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ToolCommandOutput, { tool }),
|
|
2334
|
+
tool.diffLines && tool.diffLines.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ToolDiffBlock, { file: tool.diffFile, lines: tool.diffLines })
|
|
2335
|
+
] }, i))
|
|
2336
|
+
] });
|
|
2337
|
+
}
|
|
2338
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ink5.Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
2339
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ink5.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ink5.Text, { color: "white", bold: true, children: [
|
|
1822
2340
|
"Tool:",
|
|
1823
2341
|
" "
|
|
1824
2342
|
] }) }),
|
|
1825
|
-
/* @__PURE__ */ (0,
|
|
1826
|
-
lines.map((line, i) => /* @__PURE__ */ (0,
|
|
2343
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ink5.Text, { children: " " }),
|
|
2344
|
+
lines.map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ink5.Text, { color: "green", children: [
|
|
1827
2345
|
" ",
|
|
1828
2346
|
line
|
|
1829
2347
|
] }, i))
|
|
@@ -1832,36 +2350,134 @@ function ToolSummaryEntry({ entry }) {
|
|
|
1832
2350
|
function EventEntry({ entry }) {
|
|
1833
2351
|
const eventData = entry.data;
|
|
1834
2352
|
const eventMessage = typeof eventData?.message === "string" ? eventData.message : typeof eventData?.content === "string" ? eventData.content : entry.type;
|
|
1835
|
-
return /* @__PURE__ */ (0,
|
|
1836
|
-
/* @__PURE__ */ (0,
|
|
2353
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ink5.Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
2354
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ink5.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ink5.Text, { color: "yellow", bold: true, children: [
|
|
1837
2355
|
"System:",
|
|
1838
2356
|
" "
|
|
1839
2357
|
] }) }),
|
|
1840
|
-
/* @__PURE__ */ (0,
|
|
1841
|
-
/* @__PURE__ */ (0,
|
|
2358
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ink5.Text, { children: " " }),
|
|
2359
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ink5.Box, { marginLeft: 2, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ink5.Text, { wrap: "wrap", children: eventMessage }) })
|
|
1842
2360
|
] });
|
|
1843
2361
|
}
|
|
1844
2362
|
function EntryItem({ entry }) {
|
|
1845
2363
|
if (entry.category === "chat") {
|
|
1846
2364
|
const message = entry.data;
|
|
1847
|
-
return /* @__PURE__ */ (0,
|
|
2365
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MessageItem, { message });
|
|
1848
2366
|
}
|
|
1849
2367
|
if (entry.type === "tool-summary") {
|
|
1850
|
-
return /* @__PURE__ */ (0,
|
|
2368
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ToolSummaryEntry, { entry });
|
|
2369
|
+
}
|
|
2370
|
+
if (entry.type === "usage-summary") {
|
|
2371
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(UsageSummaryEntry, { entry });
|
|
1851
2372
|
}
|
|
1852
2373
|
if (entry.type === "tool-start" || entry.type === "tool-end") {
|
|
1853
|
-
return /* @__PURE__ */ (0,
|
|
2374
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, {});
|
|
1854
2375
|
}
|
|
1855
|
-
return /* @__PURE__ */ (0,
|
|
2376
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(EventEntry, { entry });
|
|
1856
2377
|
}
|
|
1857
2378
|
function MessageList({ history }) {
|
|
1858
|
-
return /* @__PURE__ */ (0,
|
|
2379
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ink5.Box, { flexDirection: "column", children: history.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(EntryItem, { entry }, entry.id)) });
|
|
2380
|
+
}
|
|
2381
|
+
|
|
2382
|
+
// src/ui/SessionStatusBar.tsx
|
|
2383
|
+
var import_react7 = require("react");
|
|
2384
|
+
var import_agent_core8 = require("@robota-sdk/agent-core");
|
|
2385
|
+
|
|
2386
|
+
// src/utils/git-branch.ts
|
|
2387
|
+
var import_node_fs4 = require("fs");
|
|
2388
|
+
var import_node_path6 = require("path");
|
|
2389
|
+
var DETACHED_HEAD_LENGTH = 7;
|
|
2390
|
+
function resolveGitBranch(cwd) {
|
|
2391
|
+
try {
|
|
2392
|
+
const gitDir = findGitDir(cwd);
|
|
2393
|
+
if (!gitDir) return void 0;
|
|
2394
|
+
const head = (0, import_node_fs4.readFileSync)((0, import_node_path6.join)(gitDir, "HEAD"), "utf8").trim();
|
|
2395
|
+
if (!head) return void 0;
|
|
2396
|
+
if (head.startsWith("ref: ")) {
|
|
2397
|
+
const ref = head.slice("ref: ".length).trim();
|
|
2398
|
+
const branchPrefix = "refs/heads/";
|
|
2399
|
+
return ref.startsWith(branchPrefix) ? ref.slice(branchPrefix.length) : ref;
|
|
2400
|
+
}
|
|
2401
|
+
return head.slice(0, DETACHED_HEAD_LENGTH);
|
|
2402
|
+
} catch {
|
|
2403
|
+
return void 0;
|
|
2404
|
+
}
|
|
2405
|
+
}
|
|
2406
|
+
function findGitDir(start) {
|
|
2407
|
+
let current = (0, import_node_path6.resolve)(start);
|
|
2408
|
+
let parent = (0, import_node_path6.dirname)(current);
|
|
2409
|
+
while (parent !== current) {
|
|
2410
|
+
const candidate = (0, import_node_path6.join)(current, ".git");
|
|
2411
|
+
const resolved = resolveGitMetadata(candidate, current);
|
|
2412
|
+
if (resolved) return resolved;
|
|
2413
|
+
current = parent;
|
|
2414
|
+
parent = (0, import_node_path6.dirname)(current);
|
|
2415
|
+
}
|
|
2416
|
+
const rootCandidate = (0, import_node_path6.join)(current, ".git");
|
|
2417
|
+
return resolveGitMetadata(rootCandidate, current);
|
|
2418
|
+
}
|
|
2419
|
+
function resolveGitMetadata(candidate, repoDir) {
|
|
2420
|
+
if (!(0, import_node_fs4.existsSync)(candidate)) return void 0;
|
|
2421
|
+
const stat = (0, import_node_fs4.lstatSync)(candidate);
|
|
2422
|
+
if (stat.isDirectory()) return candidate;
|
|
2423
|
+
if (!stat.isFile()) return void 0;
|
|
2424
|
+
const content = (0, import_node_fs4.readFileSync)(candidate, "utf8").trim();
|
|
2425
|
+
const prefix = "gitdir:";
|
|
2426
|
+
if (!content.startsWith(prefix)) return void 0;
|
|
2427
|
+
const rawPath = content.slice(prefix.length).trim();
|
|
2428
|
+
return (0, import_node_path6.isAbsolute)(rawPath) ? rawPath : (0, import_node_path6.resolve)(repoDir, rawPath);
|
|
1859
2429
|
}
|
|
1860
2430
|
|
|
1861
2431
|
// src/ui/StatusBar.tsx
|
|
1862
|
-
var
|
|
1863
|
-
var
|
|
1864
|
-
|
|
2432
|
+
var import_ink6 = require("ink");
|
|
2433
|
+
var import_agent_core7 = require("@robota-sdk/agent-core");
|
|
2434
|
+
|
|
2435
|
+
// src/ui/status-activity.ts
|
|
2436
|
+
var NO_ACTIVE_ITEMS = 0;
|
|
2437
|
+
function formatStatusActivity(input) {
|
|
2438
|
+
const base = getPrimaryActivity(input);
|
|
2439
|
+
const segments = input.hasPendingPrompt && base.kind !== "queued" ? ["queued"] : [];
|
|
2440
|
+
const text = [base.label, ...segments].join(" \xB7 ");
|
|
2441
|
+
return { ...base, segments, text };
|
|
2442
|
+
}
|
|
2443
|
+
function getPrimaryActivity(input) {
|
|
2444
|
+
if (input.activeToolCount > NO_ACTIVE_ITEMS) {
|
|
2445
|
+
return {
|
|
2446
|
+
kind: "tools",
|
|
2447
|
+
label: `Tools x${input.activeToolCount}`,
|
|
2448
|
+
color: "cyan"
|
|
2449
|
+
};
|
|
2450
|
+
}
|
|
2451
|
+
if (input.isThinking) {
|
|
2452
|
+
return {
|
|
2453
|
+
kind: "thinking",
|
|
2454
|
+
label: "Thinking",
|
|
2455
|
+
color: "yellow"
|
|
2456
|
+
};
|
|
2457
|
+
}
|
|
2458
|
+
if (input.activeBackgroundTaskCount > NO_ACTIVE_ITEMS) {
|
|
2459
|
+
return {
|
|
2460
|
+
kind: "background",
|
|
2461
|
+
label: `Background x${input.activeBackgroundTaskCount}`,
|
|
2462
|
+
color: "cyan"
|
|
2463
|
+
};
|
|
2464
|
+
}
|
|
2465
|
+
if (input.hasPendingPrompt) {
|
|
2466
|
+
return {
|
|
2467
|
+
kind: "queued",
|
|
2468
|
+
label: "Queued",
|
|
2469
|
+
color: "yellow"
|
|
2470
|
+
};
|
|
2471
|
+
}
|
|
2472
|
+
return {
|
|
2473
|
+
kind: "idle",
|
|
2474
|
+
label: "Idle",
|
|
2475
|
+
color: "gray"
|
|
2476
|
+
};
|
|
2477
|
+
}
|
|
2478
|
+
|
|
2479
|
+
// src/ui/StatusBar.tsx
|
|
2480
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1865
2481
|
var CONTEXT_YELLOW_THRESHOLD = 70;
|
|
1866
2482
|
var CONTEXT_RED_THRESHOLD = 90;
|
|
1867
2483
|
function getContextColor(percentage) {
|
|
@@ -1869,67 +2485,194 @@ function getContextColor(percentage) {
|
|
|
1869
2485
|
if (percentage >= CONTEXT_YELLOW_THRESHOLD) return "yellow";
|
|
1870
2486
|
return "green";
|
|
1871
2487
|
}
|
|
1872
|
-
function
|
|
2488
|
+
function StatusActivityText({
|
|
2489
|
+
isThinking,
|
|
2490
|
+
activeToolCount,
|
|
2491
|
+
activeBackgroundTaskCount,
|
|
2492
|
+
hasPendingPrompt
|
|
2493
|
+
}) {
|
|
2494
|
+
const activity = formatStatusActivity({
|
|
2495
|
+
isThinking,
|
|
2496
|
+
activeToolCount,
|
|
2497
|
+
activeBackgroundTaskCount,
|
|
2498
|
+
hasPendingPrompt
|
|
2499
|
+
});
|
|
2500
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
2501
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_ink6.Text, { color: "cyan", bold: true, children: "Activity:" }),
|
|
2502
|
+
" ",
|
|
2503
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_ink6.Text, { color: activity.color, bold: activity.kind !== "idle", children: activity.text })
|
|
2504
|
+
] });
|
|
2505
|
+
}
|
|
2506
|
+
function ContextText({
|
|
2507
|
+
percentage,
|
|
2508
|
+
usedTokens,
|
|
2509
|
+
maxTokens
|
|
2510
|
+
}) {
|
|
2511
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_ink6.Text, { color: getContextColor(percentage), children: [
|
|
2512
|
+
"Context: ",
|
|
2513
|
+
Math.round(percentage),
|
|
2514
|
+
"% (",
|
|
2515
|
+
(0, import_agent_core7.formatTokenCount)(usedTokens),
|
|
2516
|
+
"/",
|
|
2517
|
+
(0, import_agent_core7.formatTokenCount)(maxTokens),
|
|
2518
|
+
")"
|
|
2519
|
+
] });
|
|
2520
|
+
}
|
|
2521
|
+
function ModeText({ permissionMode }) {
|
|
2522
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
2523
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_ink6.Text, { color: "cyan", bold: true, children: "Mode:" }),
|
|
2524
|
+
" ",
|
|
2525
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_ink6.Text, { children: permissionMode })
|
|
2526
|
+
] });
|
|
2527
|
+
}
|
|
2528
|
+
function StatusLeft({
|
|
1873
2529
|
permissionMode,
|
|
1874
2530
|
modelName,
|
|
1875
|
-
sessionId: _sessionId,
|
|
1876
|
-
messageCount,
|
|
1877
2531
|
isThinking,
|
|
2532
|
+
activeToolCount,
|
|
2533
|
+
activeBackgroundTaskCount,
|
|
2534
|
+
hasPendingPrompt,
|
|
1878
2535
|
contextPercentage,
|
|
1879
2536
|
contextUsedTokens,
|
|
1880
2537
|
contextMaxTokens,
|
|
1881
|
-
sessionName
|
|
2538
|
+
sessionName,
|
|
2539
|
+
gitBranch,
|
|
2540
|
+
showGitBranch
|
|
1882
2541
|
}) {
|
|
1883
|
-
const
|
|
1884
|
-
return /* @__PURE__ */ (0,
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
2542
|
+
const shouldShowGitBranch = showGitBranch && gitBranch !== void 0 && gitBranch.length > 0;
|
|
2543
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_ink6.Text, { children: [
|
|
2544
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2545
|
+
StatusActivityText,
|
|
2546
|
+
{
|
|
2547
|
+
isThinking,
|
|
2548
|
+
activeToolCount,
|
|
2549
|
+
activeBackgroundTaskCount,
|
|
2550
|
+
hasPendingPrompt
|
|
2551
|
+
}
|
|
2552
|
+
),
|
|
2553
|
+
" | ",
|
|
2554
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ModeText, { permissionMode }),
|
|
2555
|
+
sessionName && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
2556
|
+
" | ",
|
|
2557
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_ink6.Text, { color: "magenta", children: sessionName })
|
|
2558
|
+
] }),
|
|
2559
|
+
shouldShowGitBranch && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
2560
|
+
" | ",
|
|
2561
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_ink6.Text, { dimColor: true, children: [
|
|
2562
|
+
"git: ",
|
|
2563
|
+
gitBranch
|
|
2564
|
+
] })
|
|
2565
|
+
] }),
|
|
2566
|
+
" | ",
|
|
2567
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_ink6.Text, { dimColor: true, children: modelName }),
|
|
2568
|
+
" | ",
|
|
2569
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2570
|
+
ContextText,
|
|
2571
|
+
{
|
|
2572
|
+
percentage: contextPercentage,
|
|
2573
|
+
usedTokens: contextUsedTokens,
|
|
2574
|
+
maxTokens: contextMaxTokens
|
|
2575
|
+
}
|
|
2576
|
+
)
|
|
2577
|
+
] });
|
|
2578
|
+
}
|
|
2579
|
+
function StatusBar({
|
|
2580
|
+
permissionMode,
|
|
2581
|
+
modelName,
|
|
2582
|
+
sessionId: _sessionId,
|
|
2583
|
+
messageCount,
|
|
2584
|
+
isThinking,
|
|
2585
|
+
activeToolCount = 0,
|
|
2586
|
+
activeBackgroundTaskCount = 0,
|
|
2587
|
+
hasPendingPrompt = false,
|
|
2588
|
+
contextPercentage,
|
|
2589
|
+
contextUsedTokens,
|
|
2590
|
+
contextMaxTokens,
|
|
2591
|
+
sessionName,
|
|
2592
|
+
gitBranch,
|
|
2593
|
+
showGitBranch = true
|
|
2594
|
+
}) {
|
|
2595
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
2596
|
+
import_ink6.Box,
|
|
2597
|
+
{
|
|
2598
|
+
borderStyle: "single",
|
|
2599
|
+
borderColor: "gray",
|
|
2600
|
+
paddingLeft: 1,
|
|
2601
|
+
paddingRight: 1,
|
|
2602
|
+
justifyContent: "space-between",
|
|
2603
|
+
children: [
|
|
2604
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2605
|
+
StatusLeft,
|
|
2606
|
+
{
|
|
2607
|
+
permissionMode,
|
|
2608
|
+
modelName,
|
|
2609
|
+
isThinking,
|
|
2610
|
+
activeToolCount,
|
|
2611
|
+
activeBackgroundTaskCount,
|
|
2612
|
+
hasPendingPrompt,
|
|
2613
|
+
contextPercentage,
|
|
2614
|
+
contextUsedTokens,
|
|
2615
|
+
contextMaxTokens,
|
|
2616
|
+
sessionName,
|
|
2617
|
+
gitBranch,
|
|
2618
|
+
showGitBranch
|
|
2619
|
+
}
|
|
2620
|
+
),
|
|
2621
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_ink6.Text, { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_ink6.Text, { dimColor: true, children: [
|
|
2622
|
+
"msgs: ",
|
|
2623
|
+
messageCount
|
|
2624
|
+
] }) })
|
|
1921
2625
|
]
|
|
1922
2626
|
}
|
|
1923
2627
|
);
|
|
1924
2628
|
}
|
|
1925
2629
|
|
|
2630
|
+
// src/ui/SessionStatusBar.tsx
|
|
2631
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
2632
|
+
function SessionStatusBar({
|
|
2633
|
+
cwd,
|
|
2634
|
+
permissionMode,
|
|
2635
|
+
modelId,
|
|
2636
|
+
sessionId,
|
|
2637
|
+
messageCount,
|
|
2638
|
+
isThinking,
|
|
2639
|
+
activeToolCount,
|
|
2640
|
+
activeBackgroundTaskCount,
|
|
2641
|
+
hasPendingPrompt,
|
|
2642
|
+
contextState,
|
|
2643
|
+
sessionName,
|
|
2644
|
+
settings
|
|
2645
|
+
}) {
|
|
2646
|
+
const gitBranch = (0, import_react7.useMemo)(() => resolveGitBranch(cwd), [cwd]);
|
|
2647
|
+
if (!settings.enabled) return null;
|
|
2648
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2649
|
+
StatusBar,
|
|
2650
|
+
{
|
|
2651
|
+
permissionMode,
|
|
2652
|
+
modelName: modelId ? (0, import_agent_core8.getModelName)(modelId) : "",
|
|
2653
|
+
sessionId,
|
|
2654
|
+
messageCount,
|
|
2655
|
+
isThinking,
|
|
2656
|
+
activeToolCount,
|
|
2657
|
+
activeBackgroundTaskCount,
|
|
2658
|
+
hasPendingPrompt,
|
|
2659
|
+
contextPercentage: contextState.percentage,
|
|
2660
|
+
contextUsedTokens: contextState.usedTokens,
|
|
2661
|
+
contextMaxTokens: contextState.maxTokens,
|
|
2662
|
+
sessionName,
|
|
2663
|
+
gitBranch,
|
|
2664
|
+
showGitBranch: settings.gitBranch
|
|
2665
|
+
}
|
|
2666
|
+
);
|
|
2667
|
+
}
|
|
2668
|
+
|
|
1926
2669
|
// src/ui/InputArea.tsx
|
|
1927
|
-
var
|
|
1928
|
-
var
|
|
2670
|
+
var import_react11 = require("react");
|
|
2671
|
+
var import_ink10 = require("ink");
|
|
1929
2672
|
|
|
1930
2673
|
// src/ui/CjkTextInput.tsx
|
|
1931
|
-
var
|
|
1932
|
-
var
|
|
2674
|
+
var import_react8 = require("react");
|
|
2675
|
+
var import_ink7 = require("ink");
|
|
1933
2676
|
var import_chalk = __toESM(require("chalk"), 1);
|
|
1934
2677
|
|
|
1935
2678
|
// src/ui/flows/cjk-text-input-flow.ts
|
|
@@ -1956,10 +2699,20 @@ function applyCjkTextInput(state, input, key, options) {
|
|
|
1956
2699
|
if (pasteResult !== void 0) return pasteResult;
|
|
1957
2700
|
const controlResult = applyControlInput(state, input, key, options);
|
|
1958
2701
|
if (controlResult !== void 0) return controlResult;
|
|
1959
|
-
const cursorResult = applyCursorInput(state, key, options
|
|
2702
|
+
const cursorResult = applyCursorInput(state, key, options);
|
|
1960
2703
|
if (cursorResult !== void 0) return cursorResult;
|
|
1961
2704
|
return insertPrintableInput(state, input);
|
|
1962
2705
|
}
|
|
2706
|
+
function applyCjkTextPaste(state, text, options) {
|
|
2707
|
+
const normalizedText = text.replace(/\r\n?/g, "\n");
|
|
2708
|
+
if (normalizedText.length === 0) {
|
|
2709
|
+
return { state, effect: { type: "none" } };
|
|
2710
|
+
}
|
|
2711
|
+
if (normalizedText.includes("\n") && options.canPaste) {
|
|
2712
|
+
return { state, effect: { type: "paste", text: normalizedText, cursor: state.cursor } };
|
|
2713
|
+
}
|
|
2714
|
+
return insertPrintableInput(state, normalizedText);
|
|
2715
|
+
}
|
|
1963
2716
|
function applyPasteBoundaryInput(state, input, options) {
|
|
1964
2717
|
if (input === PASTE_START || input.startsWith(PASTE_START)) {
|
|
1965
2718
|
return startBracketedPaste(state, input);
|
|
@@ -1984,9 +2737,16 @@ function applyControlInput(state, input, key, options) {
|
|
|
1984
2737
|
}
|
|
1985
2738
|
return void 0;
|
|
1986
2739
|
}
|
|
1987
|
-
function applyCursorInput(state, key,
|
|
2740
|
+
function applyCursorInput(state, key, options) {
|
|
1988
2741
|
if (key.upArrow === true || key.downArrow === true) {
|
|
1989
|
-
|
|
2742
|
+
if (options.enableVerticalNavigation === false) {
|
|
2743
|
+
return { state, effect: { type: "none" } };
|
|
2744
|
+
}
|
|
2745
|
+
return moveCursorVertically(
|
|
2746
|
+
state,
|
|
2747
|
+
key.upArrow === true ? "up" : "down",
|
|
2748
|
+
options.availableWidth
|
|
2749
|
+
);
|
|
1990
2750
|
}
|
|
1991
2751
|
if (key.leftArrow === true) {
|
|
1992
2752
|
return moveCursorHorizontally(state, "left");
|
|
@@ -2049,15 +2809,8 @@ function continueBracketedPaste(state, input, options) {
|
|
|
2049
2809
|
};
|
|
2050
2810
|
}
|
|
2051
2811
|
const beforeMarker = input.split(PASTE_END)[0] ?? "";
|
|
2052
|
-
const text = (state.pasteBuffer + beforeMarker).replace(/\r\n?/g, "\n");
|
|
2053
2812
|
const nextState = { ...state, isPasting: false, pasteBuffer: "" };
|
|
2054
|
-
|
|
2055
|
-
return { state: nextState, effect: { type: "none" } };
|
|
2056
|
-
}
|
|
2057
|
-
if (text.includes("\n") && options.canPaste) {
|
|
2058
|
-
return { state: nextState, effect: { type: "paste", text, cursor: state.cursor } };
|
|
2059
|
-
}
|
|
2060
|
-
return insertPrintableInput(nextState, text);
|
|
2813
|
+
return applyCjkTextPaste(nextState, state.pasteBuffer + beforeMarker, options);
|
|
2061
2814
|
}
|
|
2062
2815
|
function moveCursorVertically(state, direction, availableWidth) {
|
|
2063
2816
|
if (!availableWidth || availableWidth <= 0) {
|
|
@@ -2107,7 +2860,7 @@ function insertPrintableInput(state, input) {
|
|
|
2107
2860
|
}
|
|
2108
2861
|
|
|
2109
2862
|
// src/ui/CjkTextInput.tsx
|
|
2110
|
-
var
|
|
2863
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
2111
2864
|
function CjkTextInput({
|
|
2112
2865
|
value,
|
|
2113
2866
|
onChange,
|
|
@@ -2117,32 +2870,70 @@ function CjkTextInput({
|
|
|
2117
2870
|
focus = true,
|
|
2118
2871
|
showCursor = true,
|
|
2119
2872
|
availableWidth,
|
|
2120
|
-
cursorHint = null
|
|
2873
|
+
cursorHint = null,
|
|
2874
|
+
enableVerticalNavigation = true
|
|
2121
2875
|
}) {
|
|
2122
|
-
const stateRef = (0,
|
|
2123
|
-
const [, forceRender] = (0,
|
|
2876
|
+
const stateRef = (0, import_react8.useRef)(createCjkTextInputFlowState(value));
|
|
2877
|
+
const [, forceRender] = (0, import_react8.useState)(0);
|
|
2124
2878
|
stateRef.current = syncCjkTextInputFlowState(stateRef.current, value, cursorHint);
|
|
2125
|
-
(
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
},
|
|
2137
|
-
{ isActive: focus }
|
|
2138
|
-
);
|
|
2139
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ink5.Text, { children: renderWithCursor(
|
|
2879
|
+
useCjkTextInputHandlers({
|
|
2880
|
+
stateRef,
|
|
2881
|
+
onChange,
|
|
2882
|
+
onSubmit,
|
|
2883
|
+
onPaste,
|
|
2884
|
+
availableWidth,
|
|
2885
|
+
focus,
|
|
2886
|
+
enableVerticalNavigation,
|
|
2887
|
+
forceRender
|
|
2888
|
+
});
|
|
2889
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Text, { children: renderWithCursor(
|
|
2140
2890
|
stateRef.current.value,
|
|
2141
2891
|
stateRef.current.cursor,
|
|
2142
2892
|
placeholder,
|
|
2143
2893
|
showCursor && focus
|
|
2144
2894
|
) });
|
|
2145
2895
|
}
|
|
2896
|
+
function useCjkTextInputHandlers(options) {
|
|
2897
|
+
(0, import_ink7.usePaste)(
|
|
2898
|
+
(text) => {
|
|
2899
|
+
applyCjkFlowSafely(
|
|
2900
|
+
options,
|
|
2901
|
+
() => applyCjkTextPaste(options.stateRef.current, text, createFlowOptions(options))
|
|
2902
|
+
);
|
|
2903
|
+
},
|
|
2904
|
+
{ isActive: options.focus }
|
|
2905
|
+
);
|
|
2906
|
+
(0, import_ink7.useInput)(
|
|
2907
|
+
(input, key) => {
|
|
2908
|
+
applyCjkFlowSafely(
|
|
2909
|
+
options,
|
|
2910
|
+
() => applyCjkTextInput(options.stateRef.current, input, key, createFlowOptions(options))
|
|
2911
|
+
);
|
|
2912
|
+
},
|
|
2913
|
+
{ isActive: options.focus }
|
|
2914
|
+
);
|
|
2915
|
+
}
|
|
2916
|
+
function createFlowOptions(options) {
|
|
2917
|
+
return {
|
|
2918
|
+
availableWidth: options.availableWidth,
|
|
2919
|
+
canPaste: options.onPaste !== void 0,
|
|
2920
|
+
enableVerticalNavigation: options.enableVerticalNavigation
|
|
2921
|
+
};
|
|
2922
|
+
}
|
|
2923
|
+
function applyCjkFlowSafely(options, run) {
|
|
2924
|
+
try {
|
|
2925
|
+
const result = run();
|
|
2926
|
+
options.stateRef.current = result.state;
|
|
2927
|
+
applyCjkTextInputEffect(
|
|
2928
|
+
result.effect,
|
|
2929
|
+
options.onChange,
|
|
2930
|
+
options.onSubmit,
|
|
2931
|
+
options.onPaste,
|
|
2932
|
+
options.forceRender
|
|
2933
|
+
);
|
|
2934
|
+
} catch {
|
|
2935
|
+
}
|
|
2936
|
+
}
|
|
2146
2937
|
function applyCjkTextInputEffect(effect, onChange, onSubmit, onPaste, forceRender) {
|
|
2147
2938
|
if (effect.type === "change") {
|
|
2148
2939
|
onChange(effect.value);
|
|
@@ -2177,38 +2968,38 @@ function renderWithCursor(value, cursorOffset, placeholder, showCursor) {
|
|
|
2177
2968
|
}
|
|
2178
2969
|
|
|
2179
2970
|
// src/ui/WaveText.tsx
|
|
2180
|
-
var
|
|
2181
|
-
var
|
|
2182
|
-
var
|
|
2971
|
+
var import_react9 = require("react");
|
|
2972
|
+
var import_ink8 = require("ink");
|
|
2973
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
2183
2974
|
var WAVE_COLORS = ["#666666", "#888888", "#aaaaaa", "#888888"];
|
|
2184
2975
|
var INTERVAL_MS = 400;
|
|
2185
2976
|
var CHARS_PER_GROUP = 4;
|
|
2186
2977
|
function WaveText({ text }) {
|
|
2187
|
-
const [tick, setTick] = (0,
|
|
2188
|
-
(0,
|
|
2978
|
+
const [tick, setTick] = (0, import_react9.useState)(0);
|
|
2979
|
+
(0, import_react9.useEffect)(() => {
|
|
2189
2980
|
const timer = setInterval(() => {
|
|
2190
2981
|
setTick((prev) => prev + 1);
|
|
2191
2982
|
}, INTERVAL_MS);
|
|
2192
2983
|
return () => clearInterval(timer);
|
|
2193
2984
|
}, []);
|
|
2194
2985
|
const chars = [...text];
|
|
2195
|
-
return /* @__PURE__ */ (0,
|
|
2986
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink8.Text, { children: chars.map((char, i) => {
|
|
2196
2987
|
const group = Math.floor(i / CHARS_PER_GROUP);
|
|
2197
2988
|
const colorIndex = (tick + group) % WAVE_COLORS.length;
|
|
2198
|
-
return /* @__PURE__ */ (0,
|
|
2989
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink8.Text, { color: WAVE_COLORS[colorIndex], children: char }, i);
|
|
2199
2990
|
}) });
|
|
2200
2991
|
}
|
|
2201
2992
|
|
|
2202
2993
|
// src/ui/SlashAutocomplete.tsx
|
|
2203
|
-
var
|
|
2204
|
-
var
|
|
2994
|
+
var import_ink9 = require("ink");
|
|
2995
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
2205
2996
|
var MAX_VISIBLE = 8;
|
|
2206
2997
|
function CommandRow(props) {
|
|
2207
2998
|
const { cmd, isSelected, showSlash } = props;
|
|
2208
2999
|
const indicator = isSelected ? "\u25B8 " : " ";
|
|
2209
3000
|
const nameColor = isSelected ? "cyan" : void 0;
|
|
2210
3001
|
const dimmed = !isSelected;
|
|
2211
|
-
return /* @__PURE__ */ (0,
|
|
3002
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Text, { color: nameColor, dimColor: dimmed, children: [
|
|
2212
3003
|
indicator,
|
|
2213
3004
|
showSlash ? `/${cmd.name} ${cmd.description}` : cmd.description
|
|
2214
3005
|
] }) });
|
|
@@ -2222,7 +3013,7 @@ function SlashAutocomplete({
|
|
|
2222
3013
|
if (!visible || commands.length === 0) return null;
|
|
2223
3014
|
const scrollOffset = computeScrollOffset(selectedIndex, commands.length);
|
|
2224
3015
|
const visibleCommands = commands.slice(scrollOffset, scrollOffset + MAX_VISIBLE);
|
|
2225
|
-
return /* @__PURE__ */ (0,
|
|
3016
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Box, { flexDirection: "column", borderStyle: "round", borderColor: "gray", paddingX: 1, children: visibleCommands.map((cmd, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2226
3017
|
CommandRow,
|
|
2227
3018
|
{
|
|
2228
3019
|
cmd,
|
|
@@ -2246,7 +3037,7 @@ function expandPasteLabels(text, store) {
|
|
|
2246
3037
|
}
|
|
2247
3038
|
|
|
2248
3039
|
// src/ui/hooks/useAutocomplete.ts
|
|
2249
|
-
var
|
|
3040
|
+
var import_react10 = __toESM(require("react"), 1);
|
|
2250
3041
|
function parseSlashInput(value) {
|
|
2251
3042
|
if (!value.startsWith("/")) return { isSlash: false, parentCommand: "", filter: "" };
|
|
2252
3043
|
const afterSlash = value.slice(1);
|
|
@@ -2257,16 +3048,16 @@ function parseSlashInput(value) {
|
|
|
2257
3048
|
return { isSlash: true, parentCommand: parent, filter: rest };
|
|
2258
3049
|
}
|
|
2259
3050
|
function useAutocomplete(value, registry) {
|
|
2260
|
-
const [selectedIndex, setSelectedIndex] = (0,
|
|
2261
|
-
const [dismissed, setDismissed] = (0,
|
|
2262
|
-
const prevValueRef =
|
|
3051
|
+
const [selectedIndex, setSelectedIndex] = (0, import_react10.useState)(0);
|
|
3052
|
+
const [dismissed, setDismissed] = (0, import_react10.useState)(false);
|
|
3053
|
+
const prevValueRef = import_react10.default.useRef(value);
|
|
2263
3054
|
if (prevValueRef.current !== value) {
|
|
2264
3055
|
prevValueRef.current = value;
|
|
2265
3056
|
if (dismissed) setDismissed(false);
|
|
2266
3057
|
}
|
|
2267
3058
|
const parsed = parseSlashInput(value);
|
|
2268
3059
|
const isSubcommandMode = parsed.isSlash && parsed.parentCommand.length > 0;
|
|
2269
|
-
const filteredCommands = (0,
|
|
3060
|
+
const filteredCommands = (0, import_react10.useMemo)(() => {
|
|
2270
3061
|
if (!registry || !parsed.isSlash || dismissed) return [];
|
|
2271
3062
|
if (isSubcommandMode) {
|
|
2272
3063
|
const subs = registry.getSubcommands(parsed.parentCommand);
|
|
@@ -2314,6 +3105,61 @@ function getPendingPromptInputAction(key) {
|
|
|
2314
3105
|
}
|
|
2315
3106
|
return void 0;
|
|
2316
3107
|
}
|
|
3108
|
+
function getPromptHistoryInputAction(key) {
|
|
3109
|
+
if (key.upArrow === true) return "previous";
|
|
3110
|
+
if (key.downArrow === true) return "next";
|
|
3111
|
+
return void 0;
|
|
3112
|
+
}
|
|
3113
|
+
function createPromptHistoryNavigationState() {
|
|
3114
|
+
return { selectedIndex: null, draft: "" };
|
|
3115
|
+
}
|
|
3116
|
+
function navigatePromptHistory(value, history, state, action) {
|
|
3117
|
+
if (history.length === 0) {
|
|
3118
|
+
return { value, cursorHint: value.length, state };
|
|
3119
|
+
}
|
|
3120
|
+
if (action === "previous") {
|
|
3121
|
+
const selectedIndex = state.selectedIndex === null ? history.length - 1 : Math.max(0, state.selectedIndex - 1);
|
|
3122
|
+
const nextValue = history[selectedIndex] ?? value;
|
|
3123
|
+
return {
|
|
3124
|
+
value: nextValue,
|
|
3125
|
+
cursorHint: nextValue.length,
|
|
3126
|
+
state: { selectedIndex, draft: state.selectedIndex === null ? value : state.draft }
|
|
3127
|
+
};
|
|
3128
|
+
}
|
|
3129
|
+
if (state.selectedIndex === null) {
|
|
3130
|
+
return { value, cursorHint: value.length, state };
|
|
3131
|
+
}
|
|
3132
|
+
if (state.selectedIndex < history.length - 1) {
|
|
3133
|
+
const selectedIndex = state.selectedIndex + 1;
|
|
3134
|
+
const nextValue = history[selectedIndex] ?? value;
|
|
3135
|
+
return {
|
|
3136
|
+
value: nextValue,
|
|
3137
|
+
cursorHint: nextValue.length,
|
|
3138
|
+
state: { ...state, selectedIndex }
|
|
3139
|
+
};
|
|
3140
|
+
}
|
|
3141
|
+
return {
|
|
3142
|
+
value: state.draft,
|
|
3143
|
+
cursorHint: state.draft.length,
|
|
3144
|
+
state: createPromptHistoryNavigationState()
|
|
3145
|
+
};
|
|
3146
|
+
}
|
|
3147
|
+
function appendPromptHistory(history, value) {
|
|
3148
|
+
const prompt = value.trim();
|
|
3149
|
+
if (prompt.length === 0) return [...history];
|
|
3150
|
+
if (history[history.length - 1] === prompt) return [...history];
|
|
3151
|
+
return [...history, prompt];
|
|
3152
|
+
}
|
|
3153
|
+
function extractPromptHistory(entries) {
|
|
3154
|
+
let prompts = [];
|
|
3155
|
+
for (const entry of entries) {
|
|
3156
|
+
if (entry.category !== "chat" || entry.type !== "user") continue;
|
|
3157
|
+
const data = entry.data;
|
|
3158
|
+
if (typeof data?.content !== "string") continue;
|
|
3159
|
+
prompts = appendPromptHistory(prompts, data.content);
|
|
3160
|
+
}
|
|
3161
|
+
return prompts;
|
|
3162
|
+
}
|
|
2317
3163
|
function moveAutocompleteSelection(selectedIndex, commandCount, direction) {
|
|
2318
3164
|
if (commandCount === 0) return 0;
|
|
2319
3165
|
if (direction === "previous") {
|
|
@@ -2356,11 +3202,12 @@ function shouldSubmitInput(text) {
|
|
|
2356
3202
|
}
|
|
2357
3203
|
|
|
2358
3204
|
// src/ui/InputArea.tsx
|
|
2359
|
-
var
|
|
3205
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
2360
3206
|
var BORDER_HORIZONTAL = 2;
|
|
2361
3207
|
var PADDING_LEFT = 1;
|
|
2362
3208
|
var PROMPT_WIDTH = 2;
|
|
2363
3209
|
var INPUT_AREA_OVERHEAD = BORDER_HORIZONTAL + PADDING_LEFT + PROMPT_WIDTH;
|
|
3210
|
+
var DEFAULT_TERMINAL_COLUMNS = 80;
|
|
2364
3211
|
function InputArea({
|
|
2365
3212
|
onSubmit,
|
|
2366
3213
|
onCancelQueue,
|
|
@@ -2368,15 +3215,26 @@ function InputArea({
|
|
|
2368
3215
|
isAborting,
|
|
2369
3216
|
pendingPrompt,
|
|
2370
3217
|
registry,
|
|
2371
|
-
sessionName
|
|
3218
|
+
sessionName,
|
|
3219
|
+
history
|
|
2372
3220
|
}) {
|
|
2373
|
-
const [value, setValue] = (0,
|
|
2374
|
-
const [cursorHint, setCursorHint] = (0,
|
|
2375
|
-
const
|
|
2376
|
-
const
|
|
2377
|
-
const
|
|
3221
|
+
const [value, setValue] = (0, import_react11.useState)("");
|
|
3222
|
+
const [cursorHint, setCursorHint] = (0, import_react11.useState)(null);
|
|
3223
|
+
const [historyState, setHistoryState] = (0, import_react11.useState)(createPromptHistoryNavigationState);
|
|
3224
|
+
const [localPromptHistory, setLocalPromptHistory] = (0, import_react11.useState)([]);
|
|
3225
|
+
const restoredPromptHistory = (0, import_react11.useMemo)(() => extractPromptHistory(history ?? []), [history]);
|
|
3226
|
+
const promptHistory = (0, import_react11.useMemo)(
|
|
3227
|
+
() => localPromptHistory.reduce(
|
|
3228
|
+
(prompts, prompt) => appendPromptHistory(prompts, prompt),
|
|
3229
|
+
restoredPromptHistory
|
|
3230
|
+
),
|
|
3231
|
+
[restoredPromptHistory, localPromptHistory]
|
|
3232
|
+
);
|
|
3233
|
+
const pasteStore = (0, import_react11.useRef)(/* @__PURE__ */ new Map());
|
|
3234
|
+
const { columns } = (0, import_ink10.useWindowSize)();
|
|
3235
|
+
const terminalColumns = columns > 0 ? columns : DEFAULT_TERMINAL_COLUMNS;
|
|
2378
3236
|
const availableWidth = Math.max(1, terminalColumns - INPUT_AREA_OVERHEAD);
|
|
2379
|
-
const pasteIdRef = (0,
|
|
3237
|
+
const pasteIdRef = (0, import_react11.useRef)(0);
|
|
2380
3238
|
const {
|
|
2381
3239
|
showPopup,
|
|
2382
3240
|
filteredCommands,
|
|
@@ -2385,7 +3243,7 @@ function InputArea({
|
|
|
2385
3243
|
isSubcommandMode,
|
|
2386
3244
|
setShowPopup
|
|
2387
3245
|
} = useAutocomplete(value, registry);
|
|
2388
|
-
const handlePaste = (0,
|
|
3246
|
+
const handlePaste = (0, import_react11.useCallback)((text, cursorPosition) => {
|
|
2389
3247
|
pasteIdRef.current += 1;
|
|
2390
3248
|
const id = pasteIdRef.current;
|
|
2391
3249
|
pasteStore.current.set(id, text);
|
|
@@ -2395,7 +3253,21 @@ function InputArea({
|
|
|
2395
3253
|
return change.value;
|
|
2396
3254
|
});
|
|
2397
3255
|
}, []);
|
|
2398
|
-
const
|
|
3256
|
+
const resetHistoryNavigation = (0, import_react11.useCallback)(() => {
|
|
3257
|
+
setHistoryState(createPromptHistoryNavigationState());
|
|
3258
|
+
}, []);
|
|
3259
|
+
const recordPromptHistory = (0, import_react11.useCallback)((prompt) => {
|
|
3260
|
+
setLocalPromptHistory((prev) => appendPromptHistory(prev, prompt));
|
|
3261
|
+
}, []);
|
|
3262
|
+
const submitPrompt = (0, import_react11.useCallback)(
|
|
3263
|
+
(prompt) => {
|
|
3264
|
+
recordPromptHistory(prompt);
|
|
3265
|
+
resetHistoryNavigation();
|
|
3266
|
+
onSubmit(prompt);
|
|
3267
|
+
},
|
|
3268
|
+
[onSubmit, recordPromptHistory, resetHistoryNavigation]
|
|
3269
|
+
);
|
|
3270
|
+
const tabCompleteCommand = (0, import_react11.useCallback)(
|
|
2399
3271
|
(cmd) => {
|
|
2400
3272
|
const result = resolveTabCompletion(value, cmd);
|
|
2401
3273
|
if (result.type === "insert") {
|
|
@@ -2407,7 +3279,7 @@ function InputArea({
|
|
|
2407
3279
|
},
|
|
2408
3280
|
[value, setSelectedIndex]
|
|
2409
3281
|
);
|
|
2410
|
-
const enterSelectCommand = (0,
|
|
3282
|
+
const enterSelectCommand = (0, import_react11.useCallback)(
|
|
2411
3283
|
(cmd) => {
|
|
2412
3284
|
const result = resolveEnterCommandSelection(value, cmd);
|
|
2413
3285
|
if (result.type === "insert") {
|
|
@@ -2418,11 +3290,11 @@ function InputArea({
|
|
|
2418
3290
|
return;
|
|
2419
3291
|
}
|
|
2420
3292
|
setValue("");
|
|
2421
|
-
|
|
3293
|
+
submitPrompt(result.value);
|
|
2422
3294
|
},
|
|
2423
|
-
[value,
|
|
3295
|
+
[value, submitPrompt, setSelectedIndex]
|
|
2424
3296
|
);
|
|
2425
|
-
const handleSubmit = (0,
|
|
3297
|
+
const handleSubmit = (0, import_react11.useCallback)(
|
|
2426
3298
|
(text) => {
|
|
2427
3299
|
if (!shouldSubmitInput(text)) return;
|
|
2428
3300
|
if (showPopup && filteredCommands[selectedIndex]) {
|
|
@@ -2433,11 +3305,11 @@ function InputArea({
|
|
|
2433
3305
|
setValue("");
|
|
2434
3306
|
pasteStore.current.clear();
|
|
2435
3307
|
pasteIdRef.current = 0;
|
|
2436
|
-
|
|
3308
|
+
submitPrompt(expanded);
|
|
2437
3309
|
},
|
|
2438
|
-
[showPopup, filteredCommands, selectedIndex,
|
|
3310
|
+
[showPopup, filteredCommands, selectedIndex, enterSelectCommand, submitPrompt]
|
|
2439
3311
|
);
|
|
2440
|
-
(0,
|
|
3312
|
+
(0, import_ink10.useInput)(
|
|
2441
3313
|
(_input, key) => {
|
|
2442
3314
|
if (!showPopup) return;
|
|
2443
3315
|
const action = getAutocompletePopupAction(key);
|
|
@@ -2454,7 +3326,18 @@ function InputArea({
|
|
|
2454
3326
|
},
|
|
2455
3327
|
{ isActive: showPopup && !isDisabled }
|
|
2456
3328
|
);
|
|
2457
|
-
(0,
|
|
3329
|
+
(0, import_ink10.useInput)(
|
|
3330
|
+
(_input, key) => {
|
|
3331
|
+
const action = getPromptHistoryInputAction(key);
|
|
3332
|
+
if (!action) return;
|
|
3333
|
+
const result = navigatePromptHistory(value, promptHistory, historyState, action);
|
|
3334
|
+
setValue(result.value);
|
|
3335
|
+
setCursorHint(result.cursorHint);
|
|
3336
|
+
setHistoryState(result.state);
|
|
3337
|
+
},
|
|
3338
|
+
{ isActive: !showPopup && !isDisabled && !pendingPrompt }
|
|
3339
|
+
);
|
|
3340
|
+
(0, import_ink10.useInput)(
|
|
2458
3341
|
(_input, key) => {
|
|
2459
3342
|
if (getPendingPromptInputAction(key) === "cancelQueue" && pendingPrompt) {
|
|
2460
3343
|
onCancelQueue?.();
|
|
@@ -2473,8 +3356,8 @@ function InputArea({
|
|
|
2473
3356
|
}
|
|
2474
3357
|
return { left: "\u250C" + "\u2500".repeat(innerWidth), label: "", right: "\u2510" };
|
|
2475
3358
|
})();
|
|
2476
|
-
return /* @__PURE__ */ (0,
|
|
2477
|
-
showPopup && /* @__PURE__ */ (0,
|
|
3359
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink10.Box, { flexDirection: "column", children: [
|
|
3360
|
+
showPopup && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2478
3361
|
SlashAutocomplete,
|
|
2479
3362
|
{
|
|
2480
3363
|
commands: filteredCommands,
|
|
@@ -2483,32 +3366,34 @@ function InputArea({
|
|
|
2483
3366
|
isSubcommandMode
|
|
2484
3367
|
}
|
|
2485
3368
|
),
|
|
2486
|
-
/* @__PURE__ */ (0,
|
|
3369
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink10.Text, { color: borderColor, children: [
|
|
2487
3370
|
topBorder.left,
|
|
2488
|
-
topBorder.label ? /* @__PURE__ */ (0,
|
|
3371
|
+
topBorder.label ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_ink10.Text, { backgroundColor: borderColor, color: "black", bold: true, children: topBorder.label }) : null,
|
|
2489
3372
|
topBorder.right
|
|
2490
3373
|
] }),
|
|
2491
|
-
/* @__PURE__ */ (0,
|
|
3374
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_ink10.Box, { borderStyle: "single", borderTop: false, borderColor, paddingLeft: 1, children: isAborting ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_ink10.Text, { color: "yellow", children: " Interrupting..." }) : pendingPrompt ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink10.Text, { color: "cyan", children: [
|
|
2492
3375
|
" ",
|
|
2493
3376
|
"Queued: ",
|
|
2494
3377
|
pendingPrompt.length > 50 ? pendingPrompt.slice(0, 47) + "..." : pendingPrompt,
|
|
2495
3378
|
" ",
|
|
2496
|
-
/* @__PURE__ */ (0,
|
|
2497
|
-
] }) : isDisabled ? /* @__PURE__ */ (0,
|
|
2498
|
-
/* @__PURE__ */ (0,
|
|
2499
|
-
/* @__PURE__ */ (0,
|
|
3379
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_ink10.Text, { dimColor: true, children: "(Backspace to cancel)" })
|
|
3380
|
+
] }) : isDisabled ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(WaveText, { text: " Waiting for response... (ESC to interrupt)" }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink10.Box, { children: [
|
|
3381
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_ink10.Text, { color: "green", bold: true, children: "> " }),
|
|
3382
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2500
3383
|
CjkTextInput,
|
|
2501
3384
|
{
|
|
2502
3385
|
value,
|
|
2503
3386
|
onChange: (v) => {
|
|
2504
3387
|
setValue(v);
|
|
3388
|
+
resetHistoryNavigation();
|
|
2505
3389
|
setCursorHint(null);
|
|
2506
3390
|
},
|
|
2507
3391
|
onSubmit: handleSubmit,
|
|
2508
3392
|
onPaste: handlePaste,
|
|
2509
3393
|
placeholder: "Type a message or /help",
|
|
2510
3394
|
availableWidth,
|
|
2511
|
-
cursorHint
|
|
3395
|
+
cursorHint,
|
|
3396
|
+
enableVerticalNavigation: false
|
|
2512
3397
|
}
|
|
2513
3398
|
)
|
|
2514
3399
|
] }) })
|
|
@@ -2516,8 +3401,8 @@ function InputArea({
|
|
|
2516
3401
|
}
|
|
2517
3402
|
|
|
2518
3403
|
// src/ui/ConfirmPrompt.tsx
|
|
2519
|
-
var
|
|
2520
|
-
var
|
|
3404
|
+
var import_react12 = require("react");
|
|
3405
|
+
var import_ink11 = require("ink");
|
|
2521
3406
|
|
|
2522
3407
|
// src/ui/flows/selection-flow.ts
|
|
2523
3408
|
function createSelectionFlowState() {
|
|
@@ -2620,15 +3505,15 @@ function applyConfirmPromptInput(state, action, optionCount) {
|
|
|
2620
3505
|
}
|
|
2621
3506
|
|
|
2622
3507
|
// src/ui/ConfirmPrompt.tsx
|
|
2623
|
-
var
|
|
3508
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
2624
3509
|
function ConfirmPrompt({
|
|
2625
3510
|
message,
|
|
2626
3511
|
options = ["Yes", "No"],
|
|
2627
3512
|
onSelect
|
|
2628
3513
|
}) {
|
|
2629
|
-
const [state, setState] = (0,
|
|
2630
|
-
const stateRef = (0,
|
|
2631
|
-
const applyAction = (0,
|
|
3514
|
+
const [state, setState] = (0, import_react12.useState)(() => createSelectionFlowState());
|
|
3515
|
+
const stateRef = (0, import_react12.useRef)(state);
|
|
3516
|
+
const applyAction = (0, import_react12.useCallback)(
|
|
2632
3517
|
(action) => {
|
|
2633
3518
|
const result = applyConfirmPromptInput(stateRef.current, action, options.length);
|
|
2634
3519
|
stateRef.current = result.state;
|
|
@@ -2639,16 +3524,16 @@ function ConfirmPrompt({
|
|
|
2639
3524
|
},
|
|
2640
3525
|
[onSelect, options.length]
|
|
2641
3526
|
);
|
|
2642
|
-
(0,
|
|
3527
|
+
(0, import_ink11.useInput)((input, key) => {
|
|
2643
3528
|
const action = getConfirmPromptInputAction(input, key, options.length);
|
|
2644
3529
|
if (action !== void 0) {
|
|
2645
3530
|
applyAction(action);
|
|
2646
3531
|
}
|
|
2647
3532
|
});
|
|
2648
|
-
return /* @__PURE__ */ (0,
|
|
2649
|
-
/* @__PURE__ */ (0,
|
|
2650
|
-
/* @__PURE__ */ (0,
|
|
2651
|
-
|
|
3533
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_ink11.Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
|
|
3534
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink11.Text, { color: "yellow", children: message }),
|
|
3535
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink11.Box, { marginTop: 1, children: options.map((opt, i) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink11.Box, { marginRight: 2, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
3536
|
+
import_ink11.Text,
|
|
2652
3537
|
{
|
|
2653
3538
|
color: i === state.selectedIndex ? "cyan" : void 0,
|
|
2654
3539
|
bold: i === state.selectedIndex,
|
|
@@ -2658,16 +3543,81 @@ function ConfirmPrompt({
|
|
|
2658
3543
|
]
|
|
2659
3544
|
}
|
|
2660
3545
|
) }, opt)) }),
|
|
2661
|
-
/* @__PURE__ */ (0,
|
|
3546
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink11.Text, { dimColor: true, children: " arrow keys to select, Enter to confirm" })
|
|
2662
3547
|
] });
|
|
2663
3548
|
}
|
|
2664
3549
|
|
|
2665
|
-
// src/ui/
|
|
2666
|
-
var
|
|
3550
|
+
// src/ui/InteractivePrompt.tsx
|
|
3551
|
+
var import_ink14 = require("ink");
|
|
3552
|
+
|
|
3553
|
+
// src/ui/ListPicker.tsx
|
|
3554
|
+
var import_react13 = require("react");
|
|
3555
|
+
var import_ink12 = require("ink");
|
|
3556
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
3557
|
+
var DEFAULT_MAX_VISIBLE = 3;
|
|
3558
|
+
function ListPicker({
|
|
3559
|
+
items,
|
|
3560
|
+
renderItem,
|
|
3561
|
+
onSelect,
|
|
3562
|
+
onCancel,
|
|
3563
|
+
maxVisible = DEFAULT_MAX_VISIBLE
|
|
3564
|
+
}) {
|
|
3565
|
+
const [state, setState] = (0, import_react13.useState)(() => createSelectionFlowState());
|
|
3566
|
+
const stateRef = (0, import_react13.useRef)(state);
|
|
3567
|
+
const applyAction = (0, import_react13.useCallback)(
|
|
3568
|
+
(action) => {
|
|
3569
|
+
const result = applySelectionInput(stateRef.current, action, {
|
|
3570
|
+
itemCount: items.length,
|
|
3571
|
+
maxVisible
|
|
3572
|
+
});
|
|
3573
|
+
stateRef.current = result.state;
|
|
3574
|
+
setState(result.state);
|
|
3575
|
+
if (result.effect.type === "cancel") {
|
|
3576
|
+
onCancel();
|
|
3577
|
+
} else if (result.effect.type === "select") {
|
|
3578
|
+
const item = items[result.effect.index];
|
|
3579
|
+
if (item !== void 0) {
|
|
3580
|
+
onSelect(item);
|
|
3581
|
+
}
|
|
3582
|
+
}
|
|
3583
|
+
},
|
|
3584
|
+
[items, maxVisible, onCancel, onSelect]
|
|
3585
|
+
);
|
|
3586
|
+
(0, import_ink12.useInput)((_input, key) => {
|
|
3587
|
+
const action = getVerticalSelectionInputAction(key);
|
|
3588
|
+
if (action !== void 0) {
|
|
3589
|
+
applyAction(action);
|
|
3590
|
+
}
|
|
3591
|
+
});
|
|
3592
|
+
if (items.length === 0) {
|
|
3593
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink12.Box, {});
|
|
3594
|
+
}
|
|
3595
|
+
const normalizedState = normalizeSelectionState(state, { itemCount: items.length, maxVisible });
|
|
3596
|
+
if (normalizedState !== state) {
|
|
3597
|
+
stateRef.current = normalizedState;
|
|
3598
|
+
}
|
|
3599
|
+
const { selectedIndex, scrollOffset } = normalizedState;
|
|
3600
|
+
const visibleItems = items.slice(scrollOffset, scrollOffset + maxVisible);
|
|
3601
|
+
const hasMore = scrollOffset + maxVisible < items.length;
|
|
3602
|
+
const hasLess = scrollOffset > 0;
|
|
3603
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_ink12.Box, { flexDirection: "column", children: [
|
|
3604
|
+
hasLess && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_ink12.Text, { dimColor: true, children: [
|
|
3605
|
+
" \u2191 ",
|
|
3606
|
+
scrollOffset,
|
|
3607
|
+
" more above"
|
|
3608
|
+
] }),
|
|
3609
|
+
visibleItems.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink12.Box, { marginBottom: 1, children: renderItem(item, scrollOffset + index === selectedIndex) }, scrollOffset + index)),
|
|
3610
|
+
hasMore && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_ink12.Text, { dimColor: true, children: [
|
|
3611
|
+
" \u2193 ",
|
|
3612
|
+
items.length - scrollOffset - maxVisible,
|
|
3613
|
+
" more below"
|
|
3614
|
+
] })
|
|
3615
|
+
] });
|
|
3616
|
+
}
|
|
2667
3617
|
|
|
2668
3618
|
// src/ui/TextPrompt.tsx
|
|
2669
|
-
var
|
|
2670
|
-
var
|
|
3619
|
+
var import_react14 = require("react");
|
|
3620
|
+
var import_ink13 = require("ink");
|
|
2671
3621
|
|
|
2672
3622
|
// src/ui/flows/text-prompt-flow.ts
|
|
2673
3623
|
function createTextPromptFlowState() {
|
|
@@ -2726,7 +3676,7 @@ function submitTextPromptValue(state, options) {
|
|
|
2726
3676
|
}
|
|
2727
3677
|
|
|
2728
3678
|
// src/ui/TextPrompt.tsx
|
|
2729
|
-
var
|
|
3679
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
2730
3680
|
function TextPrompt({
|
|
2731
3681
|
title,
|
|
2732
3682
|
placeholder,
|
|
@@ -2736,9 +3686,9 @@ function TextPrompt({
|
|
|
2736
3686
|
allowEmpty = false,
|
|
2737
3687
|
masked = false
|
|
2738
3688
|
}) {
|
|
2739
|
-
const [state, setState] = (0,
|
|
2740
|
-
const stateRef = (0,
|
|
2741
|
-
const applyAction = (0,
|
|
3689
|
+
const [state, setState] = (0, import_react14.useState)(() => createTextPromptFlowState());
|
|
3690
|
+
const stateRef = (0, import_react14.useRef)(state);
|
|
3691
|
+
const applyAction = (0, import_react14.useCallback)(
|
|
2742
3692
|
(action) => {
|
|
2743
3693
|
const result = applyTextPromptInput(stateRef.current, action, { allowEmpty, validate });
|
|
2744
3694
|
stateRef.current = result.state;
|
|
@@ -2751,64 +3701,67 @@ function TextPrompt({
|
|
|
2751
3701
|
},
|
|
2752
3702
|
[allowEmpty, validate, onCancel, onSubmit]
|
|
2753
3703
|
);
|
|
2754
|
-
(0,
|
|
3704
|
+
(0, import_ink13.useInput)((input, key) => {
|
|
2755
3705
|
const action = getTextPromptInputAction(input, key);
|
|
2756
3706
|
if (action !== void 0) {
|
|
2757
3707
|
applyAction(action);
|
|
2758
3708
|
}
|
|
2759
3709
|
});
|
|
2760
|
-
return /* @__PURE__ */ (0,
|
|
2761
|
-
/* @__PURE__ */ (0,
|
|
2762
|
-
/* @__PURE__ */ (0,
|
|
2763
|
-
/* @__PURE__ */ (0,
|
|
2764
|
-
state.value ? /* @__PURE__ */ (0,
|
|
2765
|
-
/* @__PURE__ */ (0,
|
|
3710
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_ink13.Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
|
|
3711
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_ink13.Text, { color: "yellow", bold: true, children: title }),
|
|
3712
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_ink13.Box, { marginTop: 1, children: [
|
|
3713
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_ink13.Text, { color: "cyan", children: "> " }),
|
|
3714
|
+
state.value ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_ink13.Text, { children: masked ? "*".repeat(state.value.length) : state.value }) : placeholder ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_ink13.Text, { dimColor: true, children: placeholder }) : null,
|
|
3715
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_ink13.Text, { color: "cyan", children: "\u2588" })
|
|
2766
3716
|
] }),
|
|
2767
|
-
state.error && /* @__PURE__ */ (0,
|
|
2768
|
-
/* @__PURE__ */ (0,
|
|
3717
|
+
state.error && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_ink13.Text, { color: "red", children: state.error }),
|
|
3718
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_ink13.Text, { dimColor: true, children: " Enter Submit Esc Cancel" })
|
|
2769
3719
|
] });
|
|
2770
3720
|
}
|
|
2771
3721
|
|
|
2772
|
-
// src/ui/
|
|
2773
|
-
var
|
|
2774
|
-
function
|
|
2775
|
-
|
|
2776
|
-
providerDefinitions,
|
|
3722
|
+
// src/ui/InteractivePrompt.tsx
|
|
3723
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
3724
|
+
function InteractivePrompt({
|
|
3725
|
+
prompt,
|
|
2777
3726
|
onSubmit,
|
|
2778
3727
|
onCancel
|
|
2779
3728
|
}) {
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
{
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
3729
|
+
if (prompt.kind === "text") {
|
|
3730
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
3731
|
+
TextPrompt,
|
|
3732
|
+
{
|
|
3733
|
+
title: prompt.title,
|
|
3734
|
+
placeholder: prompt.placeholder,
|
|
3735
|
+
allowEmpty: prompt.allowEmpty,
|
|
3736
|
+
masked: prompt.masked,
|
|
3737
|
+
validate: prompt.validate,
|
|
3738
|
+
onSubmit,
|
|
3739
|
+
onCancel
|
|
3740
|
+
},
|
|
3741
|
+
`text:${prompt.title}`
|
|
3742
|
+
);
|
|
3743
|
+
}
|
|
3744
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_ink14.Box, { flexDirection: "column", children: [
|
|
3745
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink14.Text, { bold: true, children: prompt.title }),
|
|
3746
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
3747
|
+
ListPicker,
|
|
3748
|
+
{
|
|
3749
|
+
items: [...prompt.options],
|
|
3750
|
+
maxVisible: prompt.maxVisible,
|
|
3751
|
+
renderItem: (option, isSelected) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_ink14.Text, { color: isSelected ? "cyan" : void 0, children: [
|
|
3752
|
+
isSelected ? "> " : " ",
|
|
3753
|
+
option.label
|
|
3754
|
+
] }),
|
|
3755
|
+
onSelect: (option) => onSubmit(option.value),
|
|
3756
|
+
onCancel
|
|
3757
|
+
}
|
|
3758
|
+
)
|
|
3759
|
+
] });
|
|
2807
3760
|
}
|
|
2808
3761
|
|
|
2809
3762
|
// src/ui/PermissionPrompt.tsx
|
|
2810
|
-
var
|
|
2811
|
-
var
|
|
3763
|
+
var import_react15 = __toESM(require("react"), 1);
|
|
3764
|
+
var import_ink15 = require("ink");
|
|
2812
3765
|
|
|
2813
3766
|
// src/ui/flows/permission-prompt-flow.ts
|
|
2814
3767
|
var PERMISSION_PROMPT_OPTIONS = ["Allow", "Allow always (this session)", "Deny"];
|
|
@@ -2859,23 +3812,23 @@ function resolvePermissionIndex(state, index) {
|
|
|
2859
3812
|
}
|
|
2860
3813
|
|
|
2861
3814
|
// src/ui/PermissionPrompt.tsx
|
|
2862
|
-
var
|
|
3815
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
2863
3816
|
function formatArgs(args) {
|
|
2864
3817
|
const entries = Object.entries(args);
|
|
2865
3818
|
if (entries.length === 0) return "(no arguments)";
|
|
2866
3819
|
return entries.map(([k, v]) => `${k}: ${typeof v === "string" ? v : JSON.stringify(v)}`).join(", ");
|
|
2867
3820
|
}
|
|
2868
3821
|
function PermissionPrompt({ request }) {
|
|
2869
|
-
const [state, setState] =
|
|
2870
|
-
const stateRef =
|
|
2871
|
-
const prevRequestRef =
|
|
3822
|
+
const [state, setState] = import_react15.default.useState(() => createSelectionFlowState());
|
|
3823
|
+
const stateRef = import_react15.default.useRef(state);
|
|
3824
|
+
const prevRequestRef = import_react15.default.useRef(request);
|
|
2872
3825
|
if (prevRequestRef.current !== request) {
|
|
2873
3826
|
prevRequestRef.current = request;
|
|
2874
3827
|
const nextState = createSelectionFlowState();
|
|
2875
3828
|
stateRef.current = nextState;
|
|
2876
3829
|
setState(nextState);
|
|
2877
3830
|
}
|
|
2878
|
-
const applyAction =
|
|
3831
|
+
const applyAction = import_react15.default.useCallback(
|
|
2879
3832
|
(action) => {
|
|
2880
3833
|
const result = applyPermissionPromptInput(stateRef.current, action);
|
|
2881
3834
|
stateRef.current = result.state;
|
|
@@ -2886,25 +3839,25 @@ function PermissionPrompt({ request }) {
|
|
|
2886
3839
|
},
|
|
2887
3840
|
[request]
|
|
2888
3841
|
);
|
|
2889
|
-
(0,
|
|
3842
|
+
(0, import_ink15.useInput)((input, key) => {
|
|
2890
3843
|
const action = getPermissionPromptInputAction(input, key);
|
|
2891
3844
|
if (action !== void 0) {
|
|
2892
3845
|
applyAction(action);
|
|
2893
3846
|
}
|
|
2894
3847
|
});
|
|
2895
|
-
return /* @__PURE__ */ (0,
|
|
2896
|
-
/* @__PURE__ */ (0,
|
|
2897
|
-
/* @__PURE__ */ (0,
|
|
3848
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink15.Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
|
|
3849
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink15.Text, { color: "yellow", bold: true, children: "[Permission Required]" }),
|
|
3850
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink15.Text, { children: [
|
|
2898
3851
|
"Tool:",
|
|
2899
3852
|
" ",
|
|
2900
|
-
/* @__PURE__ */ (0,
|
|
3853
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink15.Text, { color: "cyan", bold: true, children: request.toolName })
|
|
2901
3854
|
] }),
|
|
2902
|
-
/* @__PURE__ */ (0,
|
|
3855
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink15.Text, { dimColor: true, children: [
|
|
2903
3856
|
" ",
|
|
2904
3857
|
formatArgs(request.toolArgs)
|
|
2905
3858
|
] }),
|
|
2906
|
-
/* @__PURE__ */ (0,
|
|
2907
|
-
|
|
3859
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink15.Box, { marginTop: 1, children: PERMISSION_PROMPT_OPTIONS.map((opt, i) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink15.Box, { marginRight: 2, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
3860
|
+
import_ink15.Text,
|
|
2908
3861
|
{
|
|
2909
3862
|
color: i === state.selectedIndex ? "cyan" : void 0,
|
|
2910
3863
|
bold: i === state.selectedIndex,
|
|
@@ -2914,13 +3867,13 @@ function PermissionPrompt({ request }) {
|
|
|
2914
3867
|
]
|
|
2915
3868
|
}
|
|
2916
3869
|
) }, opt)) }),
|
|
2917
|
-
/* @__PURE__ */ (0,
|
|
3870
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink15.Text, { dimColor: true, children: " left/right to select, Enter to confirm" })
|
|
2918
3871
|
] });
|
|
2919
3872
|
}
|
|
2920
3873
|
|
|
2921
3874
|
// src/ui/StreamingIndicator.tsx
|
|
2922
|
-
var
|
|
2923
|
-
var
|
|
3875
|
+
var import_ink16 = require("ink");
|
|
3876
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
2924
3877
|
function getToolStyle(t) {
|
|
2925
3878
|
if (t.isRunning) return { color: "yellow", icon: "\u27F3", strikethrough: false };
|
|
2926
3879
|
if (t.result === "error") return { color: "red", icon: "\u2717", strikethrough: true };
|
|
@@ -2931,16 +3884,16 @@ function StreamingIndicator({ text, activeTools }) {
|
|
|
2931
3884
|
const hasTools = activeTools.length > 0;
|
|
2932
3885
|
const hasText = text.length > 0;
|
|
2933
3886
|
if (!hasTools && !hasText) {
|
|
2934
|
-
return /* @__PURE__ */ (0,
|
|
3887
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, {});
|
|
2935
3888
|
}
|
|
2936
|
-
return /* @__PURE__ */ (0,
|
|
2937
|
-
hasTools && /* @__PURE__ */ (0,
|
|
2938
|
-
/* @__PURE__ */ (0,
|
|
2939
|
-
/* @__PURE__ */ (0,
|
|
3889
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_ink16.Box, { flexDirection: "column", children: [
|
|
3890
|
+
hasTools && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_ink16.Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
3891
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_ink16.Text, { color: "white", bold: true, children: "Tools:" }),
|
|
3892
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_ink16.Text, { children: " " }),
|
|
2940
3893
|
activeTools.map((t, i) => {
|
|
2941
3894
|
const { color, icon, strikethrough } = getToolStyle(t);
|
|
2942
|
-
return /* @__PURE__ */ (0,
|
|
2943
|
-
/* @__PURE__ */ (0,
|
|
3895
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_ink16.Box, { flexDirection: "column", children: [
|
|
3896
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_ink16.Text, { color, strikethrough, children: [
|
|
2944
3897
|
" ",
|
|
2945
3898
|
icon,
|
|
2946
3899
|
" ",
|
|
@@ -2949,25 +3902,25 @@ function StreamingIndicator({ text, activeTools }) {
|
|
|
2949
3902
|
t.firstArg,
|
|
2950
3903
|
")"
|
|
2951
3904
|
] }),
|
|
2952
|
-
t.diffLines && t.diffLines.length > 0 && /* @__PURE__ */ (0,
|
|
3905
|
+
t.diffLines && t.diffLines.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ToolDiffBlock, { file: t.diffFile, lines: t.diffLines })
|
|
2953
3906
|
] }, `${t.toolName}-${i}`);
|
|
2954
3907
|
})
|
|
2955
3908
|
] }),
|
|
2956
|
-
hasText && /* @__PURE__ */ (0,
|
|
2957
|
-
/* @__PURE__ */ (0,
|
|
2958
|
-
/* @__PURE__ */ (0,
|
|
2959
|
-
/* @__PURE__ */ (0,
|
|
3909
|
+
hasText && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_ink16.Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
3910
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_ink16.Text, { color: "cyan", bold: true, children: "Robota:" }),
|
|
3911
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_ink16.Text, { children: " " }),
|
|
3912
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_ink16.Box, { marginLeft: 2, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_ink16.Text, { wrap: "wrap", children: renderMarkdown(text) }) })
|
|
2960
3913
|
] })
|
|
2961
3914
|
] });
|
|
2962
3915
|
}
|
|
2963
3916
|
|
|
2964
3917
|
// src/ui/PluginTUI.tsx
|
|
2965
|
-
var
|
|
3918
|
+
var import_react18 = require("react");
|
|
2966
3919
|
|
|
2967
3920
|
// src/ui/MenuSelect.tsx
|
|
2968
|
-
var
|
|
2969
|
-
var
|
|
2970
|
-
var
|
|
3921
|
+
var import_react16 = require("react");
|
|
3922
|
+
var import_ink17 = require("ink");
|
|
3923
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
2971
3924
|
function MenuSelect({
|
|
2972
3925
|
title,
|
|
2973
3926
|
items,
|
|
@@ -2976,10 +3929,10 @@ function MenuSelect({
|
|
|
2976
3929
|
loading,
|
|
2977
3930
|
error
|
|
2978
3931
|
}) {
|
|
2979
|
-
const [state, setState] = (0,
|
|
2980
|
-
const stateRef = (0,
|
|
3932
|
+
const [state, setState] = (0, import_react16.useState)(() => createSelectionFlowState());
|
|
3933
|
+
const stateRef = (0, import_react16.useRef)(state);
|
|
2981
3934
|
const isEnabled = !loading && !error;
|
|
2982
|
-
const applyAction = (0,
|
|
3935
|
+
const applyAction = (0, import_react16.useCallback)(
|
|
2983
3936
|
(action) => {
|
|
2984
3937
|
const result = applySelectionInput(stateRef.current, action, {
|
|
2985
3938
|
itemCount: items.length,
|
|
@@ -2998,7 +3951,7 @@ function MenuSelect({
|
|
|
2998
3951
|
},
|
|
2999
3952
|
[isEnabled, items, onBack, onSelect]
|
|
3000
3953
|
);
|
|
3001
|
-
(0,
|
|
3954
|
+
(0, import_ink17.useInput)((input, key) => {
|
|
3002
3955
|
const action = getVerticalSelectionInputAction(key);
|
|
3003
3956
|
if (action !== void 0) {
|
|
3004
3957
|
applyAction(action);
|
|
@@ -3009,24 +3962,24 @@ function MenuSelect({
|
|
|
3009
3962
|
stateRef.current = normalizedState;
|
|
3010
3963
|
}
|
|
3011
3964
|
const selected = normalizedState.selectedIndex;
|
|
3012
|
-
return /* @__PURE__ */ (0,
|
|
3013
|
-
/* @__PURE__ */ (0,
|
|
3014
|
-
loading && /* @__PURE__ */ (0,
|
|
3015
|
-
error && /* @__PURE__ */ (0,
|
|
3016
|
-
/* @__PURE__ */ (0,
|
|
3017
|
-
/* @__PURE__ */ (0,
|
|
3965
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_ink17.Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
|
|
3966
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_ink17.Text, { color: "yellow", bold: true, children: title }),
|
|
3967
|
+
loading && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_ink17.Box, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_ink17.Text, { dimColor: true, children: "Loading..." }) }),
|
|
3968
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_ink17.Box, { marginTop: 1, flexDirection: "column", children: [
|
|
3969
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_ink17.Text, { color: "red", children: error }),
|
|
3970
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_ink17.Text, { dimColor: true, children: "Press Esc to go back" })
|
|
3018
3971
|
] }),
|
|
3019
|
-
!loading && !error && /* @__PURE__ */ (0,
|
|
3020
|
-
/* @__PURE__ */ (0,
|
|
3972
|
+
!loading && !error && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_ink17.Box, { flexDirection: "column", marginTop: 1, children: items.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_ink17.Box, { children: [
|
|
3973
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_ink17.Text, { color: i === selected ? "cyan" : void 0, bold: i === selected, children: [
|
|
3021
3974
|
i === selected ? "> " : " ",
|
|
3022
3975
|
item.label
|
|
3023
3976
|
] }),
|
|
3024
|
-
item.hint && /* @__PURE__ */ (0,
|
|
3977
|
+
item.hint && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_ink17.Text, { dimColor: true, children: [
|
|
3025
3978
|
" ",
|
|
3026
3979
|
item.hint
|
|
3027
3980
|
] })
|
|
3028
3981
|
] }, item.value)) }),
|
|
3029
|
-
/* @__PURE__ */ (0,
|
|
3982
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_ink17.Text, { dimColor: true, children: loading || error ? "" : " \u2191\u2193 Navigate Enter Select Esc Back" })
|
|
3030
3983
|
] });
|
|
3031
3984
|
}
|
|
3032
3985
|
|
|
@@ -3123,12 +4076,12 @@ function handleInstalledActionSelect(value, pluginId, callbacks, nav) {
|
|
|
3123
4076
|
}
|
|
3124
4077
|
|
|
3125
4078
|
// src/ui/hooks/usePluginScreenData.ts
|
|
3126
|
-
var
|
|
4079
|
+
var import_react17 = require("react");
|
|
3127
4080
|
function usePluginScreenData(screen, marketplace, callbacks, refreshCounter, stackLength) {
|
|
3128
|
-
const [items, setItems] = (0,
|
|
3129
|
-
const [loading, setLoading] = (0,
|
|
3130
|
-
const [error, setError] = (0,
|
|
3131
|
-
(0,
|
|
4081
|
+
const [items, setItems] = (0, import_react17.useState)([]);
|
|
4082
|
+
const [loading, setLoading] = (0, import_react17.useState)(false);
|
|
4083
|
+
const [error, setError] = (0, import_react17.useState)();
|
|
4084
|
+
(0, import_react17.useEffect)(() => {
|
|
3132
4085
|
setItems([]);
|
|
3133
4086
|
setError(void 0);
|
|
3134
4087
|
if (screen === "marketplace-list") {
|
|
@@ -3183,16 +4136,16 @@ function usePluginScreenData(screen, marketplace, callbacks, refreshCounter, sta
|
|
|
3183
4136
|
}
|
|
3184
4137
|
|
|
3185
4138
|
// src/ui/PluginTUI.tsx
|
|
3186
|
-
var
|
|
4139
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
3187
4140
|
function PluginTUI({ callbacks, onClose, addMessage }) {
|
|
3188
|
-
const [stack, setStack] = (0,
|
|
3189
|
-
const [confirm, setConfirm] = (0,
|
|
3190
|
-
const [refreshCounter, setRefreshCounter] = (0,
|
|
4141
|
+
const [stack, setStack] = (0, import_react18.useState)([{ screen: "main" }]);
|
|
4142
|
+
const [confirm, setConfirm] = (0, import_react18.useState)();
|
|
4143
|
+
const [refreshCounter, setRefreshCounter] = (0, import_react18.useState)(0);
|
|
3191
4144
|
const current = stack[stack.length - 1] ?? { screen: "main" };
|
|
3192
|
-
const push = (0,
|
|
4145
|
+
const push = (0, import_react18.useCallback)((state) => {
|
|
3193
4146
|
setStack((prev) => [...prev, state]);
|
|
3194
4147
|
}, []);
|
|
3195
|
-
const pop = (0,
|
|
4148
|
+
const pop = (0, import_react18.useCallback)(() => {
|
|
3196
4149
|
setStack((prev) => {
|
|
3197
4150
|
if (prev.length <= 1) {
|
|
3198
4151
|
onClose();
|
|
@@ -3201,7 +4154,7 @@ function PluginTUI({ callbacks, onClose, addMessage }) {
|
|
|
3201
4154
|
return prev.slice(0, -1);
|
|
3202
4155
|
});
|
|
3203
4156
|
}, [onClose]);
|
|
3204
|
-
const popN = (0,
|
|
4157
|
+
const popN = (0, import_react18.useCallback)(
|
|
3205
4158
|
(n) => {
|
|
3206
4159
|
setStack((prev) => {
|
|
3207
4160
|
const next = prev.slice(0, Math.max(1, prev.length - n));
|
|
@@ -3214,20 +4167,20 @@ function PluginTUI({ callbacks, onClose, addMessage }) {
|
|
|
3214
4167
|
},
|
|
3215
4168
|
[onClose]
|
|
3216
4169
|
);
|
|
3217
|
-
const notify = (0,
|
|
4170
|
+
const notify = (0, import_react18.useCallback)(
|
|
3218
4171
|
(content) => {
|
|
3219
4172
|
addMessage?.({ role: "system", content });
|
|
3220
4173
|
},
|
|
3221
4174
|
[addMessage]
|
|
3222
4175
|
);
|
|
3223
|
-
const refresh = (0,
|
|
4176
|
+
const refresh = (0, import_react18.useCallback)(() => {
|
|
3224
4177
|
setRefreshCounter((c) => c + 1);
|
|
3225
4178
|
}, []);
|
|
3226
|
-
const setConfirmNav = (0,
|
|
4179
|
+
const setConfirmNav = (0, import_react18.useCallback)(
|
|
3227
4180
|
(state) => setConfirm(state),
|
|
3228
4181
|
[setConfirm]
|
|
3229
4182
|
);
|
|
3230
|
-
const pushNav = (0,
|
|
4183
|
+
const pushNav = (0, import_react18.useCallback)(
|
|
3231
4184
|
(state) => push({ screen: state.screen, context: state.context }),
|
|
3232
4185
|
[push]
|
|
3233
4186
|
);
|
|
@@ -3239,7 +4192,7 @@ function PluginTUI({ callbacks, onClose, addMessage }) {
|
|
|
3239
4192
|
refreshCounter,
|
|
3240
4193
|
stack.length
|
|
3241
4194
|
);
|
|
3242
|
-
const handleSelect = (0,
|
|
4195
|
+
const handleSelect = (0, import_react18.useCallback)(
|
|
3243
4196
|
(value) => {
|
|
3244
4197
|
const screen2 = current.screen;
|
|
3245
4198
|
const ctx = current.context;
|
|
@@ -3257,7 +4210,7 @@ function PluginTUI({ callbacks, onClose, addMessage }) {
|
|
|
3257
4210
|
},
|
|
3258
4211
|
[current, items, callbacks, push, pop, popN, notify, setConfirm, refresh]
|
|
3259
4212
|
);
|
|
3260
|
-
const handleTextSubmit = (0,
|
|
4213
|
+
const handleTextSubmit = (0, import_react18.useCallback)(
|
|
3261
4214
|
(value) => {
|
|
3262
4215
|
if (current.screen === "marketplace-add") {
|
|
3263
4216
|
callbacks.marketplaceAdd(value).then((name) => {
|
|
@@ -3272,7 +4225,7 @@ function PluginTUI({ callbacks, onClose, addMessage }) {
|
|
|
3272
4225
|
[current.screen, callbacks, notify, pop]
|
|
3273
4226
|
);
|
|
3274
4227
|
if (confirm) {
|
|
3275
|
-
return /* @__PURE__ */ (0,
|
|
4228
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
3276
4229
|
ConfirmPrompt,
|
|
3277
4230
|
{
|
|
3278
4231
|
message: confirm.message,
|
|
@@ -3285,7 +4238,7 @@ function PluginTUI({ callbacks, onClose, addMessage }) {
|
|
|
3285
4238
|
}
|
|
3286
4239
|
const screen = current.screen;
|
|
3287
4240
|
if (screen === "marketplace-add") {
|
|
3288
|
-
return /* @__PURE__ */ (0,
|
|
4241
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
3289
4242
|
TextPrompt,
|
|
3290
4243
|
{
|
|
3291
4244
|
title: "Add Marketplace Source",
|
|
@@ -3297,7 +4250,7 @@ function PluginTUI({ callbacks, onClose, addMessage }) {
|
|
|
3297
4250
|
);
|
|
3298
4251
|
}
|
|
3299
4252
|
if (screen === "marketplace-action") {
|
|
3300
|
-
return /* @__PURE__ */ (0,
|
|
4253
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
3301
4254
|
MenuSelect,
|
|
3302
4255
|
{
|
|
3303
4256
|
title: `Marketplace: ${current.context?.marketplace ?? ""}`,
|
|
@@ -3313,7 +4266,7 @@ function PluginTUI({ callbacks, onClose, addMessage }) {
|
|
|
3313
4266
|
);
|
|
3314
4267
|
}
|
|
3315
4268
|
if (screen === "marketplace-install-scope") {
|
|
3316
|
-
return /* @__PURE__ */ (0,
|
|
4269
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
3317
4270
|
MenuSelect,
|
|
3318
4271
|
{
|
|
3319
4272
|
title: `Install scope for "${current.context?.pluginId ?? ""}"`,
|
|
@@ -3328,7 +4281,7 @@ function PluginTUI({ callbacks, onClose, addMessage }) {
|
|
|
3328
4281
|
);
|
|
3329
4282
|
}
|
|
3330
4283
|
if (screen === "installed-action") {
|
|
3331
|
-
return /* @__PURE__ */ (0,
|
|
4284
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
3332
4285
|
MenuSelect,
|
|
3333
4286
|
{
|
|
3334
4287
|
title: `Plugin: ${current.context?.pluginId ?? ""}`,
|
|
@@ -3351,7 +4304,7 @@ function PluginTUI({ callbacks, onClose, addMessage }) {
|
|
|
3351
4304
|
{ label: "Installed Plugins", value: "installed" }
|
|
3352
4305
|
]
|
|
3353
4306
|
};
|
|
3354
|
-
return /* @__PURE__ */ (0,
|
|
4307
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
3355
4308
|
MenuSelect,
|
|
3356
4309
|
{
|
|
3357
4310
|
title: titleMap[screen] ?? "Plugin Management",
|
|
@@ -3366,75 +4319,8 @@ function PluginTUI({ callbacks, onClose, addMessage }) {
|
|
|
3366
4319
|
}
|
|
3367
4320
|
|
|
3368
4321
|
// src/ui/SessionPicker.tsx
|
|
3369
|
-
var
|
|
3370
|
-
|
|
3371
|
-
// src/ui/ListPicker.tsx
|
|
3372
|
-
var import_react17 = require("react");
|
|
3373
|
-
var import_ink14 = require("ink");
|
|
3374
|
-
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
3375
|
-
var DEFAULT_MAX_VISIBLE = 3;
|
|
3376
|
-
function ListPicker({
|
|
3377
|
-
items,
|
|
3378
|
-
renderItem,
|
|
3379
|
-
onSelect,
|
|
3380
|
-
onCancel,
|
|
3381
|
-
maxVisible = DEFAULT_MAX_VISIBLE
|
|
3382
|
-
}) {
|
|
3383
|
-
const [state, setState] = (0, import_react17.useState)(() => createSelectionFlowState());
|
|
3384
|
-
const stateRef = (0, import_react17.useRef)(state);
|
|
3385
|
-
const applyAction = (0, import_react17.useCallback)(
|
|
3386
|
-
(action) => {
|
|
3387
|
-
const result = applySelectionInput(stateRef.current, action, {
|
|
3388
|
-
itemCount: items.length,
|
|
3389
|
-
maxVisible
|
|
3390
|
-
});
|
|
3391
|
-
stateRef.current = result.state;
|
|
3392
|
-
setState(result.state);
|
|
3393
|
-
if (result.effect.type === "cancel") {
|
|
3394
|
-
onCancel();
|
|
3395
|
-
} else if (result.effect.type === "select") {
|
|
3396
|
-
const item = items[result.effect.index];
|
|
3397
|
-
if (item !== void 0) {
|
|
3398
|
-
onSelect(item);
|
|
3399
|
-
}
|
|
3400
|
-
}
|
|
3401
|
-
},
|
|
3402
|
-
[items, maxVisible, onCancel, onSelect]
|
|
3403
|
-
);
|
|
3404
|
-
(0, import_ink14.useInput)((_input, key) => {
|
|
3405
|
-
const action = getVerticalSelectionInputAction(key);
|
|
3406
|
-
if (action !== void 0) {
|
|
3407
|
-
applyAction(action);
|
|
3408
|
-
}
|
|
3409
|
-
});
|
|
3410
|
-
if (items.length === 0) {
|
|
3411
|
-
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink14.Box, {});
|
|
3412
|
-
}
|
|
3413
|
-
const normalizedState = normalizeSelectionState(state, { itemCount: items.length, maxVisible });
|
|
3414
|
-
if (normalizedState !== state) {
|
|
3415
|
-
stateRef.current = normalizedState;
|
|
3416
|
-
}
|
|
3417
|
-
const { selectedIndex, scrollOffset } = normalizedState;
|
|
3418
|
-
const visibleItems = items.slice(scrollOffset, scrollOffset + maxVisible);
|
|
3419
|
-
const hasMore = scrollOffset + maxVisible < items.length;
|
|
3420
|
-
const hasLess = scrollOffset > 0;
|
|
3421
|
-
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink14.Box, { flexDirection: "column", children: [
|
|
3422
|
-
hasLess && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink14.Text, { dimColor: true, children: [
|
|
3423
|
-
" \u2191 ",
|
|
3424
|
-
scrollOffset,
|
|
3425
|
-
" more above"
|
|
3426
|
-
] }),
|
|
3427
|
-
visibleItems.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink14.Box, { marginBottom: 1, children: renderItem(item, scrollOffset + index === selectedIndex) }, scrollOffset + index)),
|
|
3428
|
-
hasMore && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink14.Text, { dimColor: true, children: [
|
|
3429
|
-
" \u2193 ",
|
|
3430
|
-
items.length - scrollOffset - maxVisible,
|
|
3431
|
-
" more below"
|
|
3432
|
-
] })
|
|
3433
|
-
] });
|
|
3434
|
-
}
|
|
3435
|
-
|
|
3436
|
-
// src/ui/SessionPicker.tsx
|
|
3437
|
-
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
4322
|
+
var import_ink18 = require("ink");
|
|
4323
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
3438
4324
|
var SESSION_ID_DISPLAY_LENGTH = 8;
|
|
3439
4325
|
function SessionPicker({
|
|
3440
4326
|
sessionStore,
|
|
@@ -3443,9 +4329,9 @@ function SessionPicker({
|
|
|
3443
4329
|
onCancel
|
|
3444
4330
|
}) {
|
|
3445
4331
|
const sessions = (sessionStore?.list() ?? []).filter((s) => s.cwd === cwd);
|
|
3446
|
-
return /* @__PURE__ */ (0,
|
|
3447
|
-
/* @__PURE__ */ (0,
|
|
3448
|
-
/* @__PURE__ */ (0,
|
|
4332
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_ink18.Box, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
|
|
4333
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_ink18.Text, { bold: true, color: "cyan", children: "Select a session to resume (ESC to cancel):" }),
|
|
4334
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
3449
4335
|
ListPicker,
|
|
3450
4336
|
{
|
|
3451
4337
|
items: sessions,
|
|
@@ -3456,24 +4342,24 @@ function SessionPicker({
|
|
|
3456
4342
|
});
|
|
3457
4343
|
const rawPreview = lastMsg?.content?.replace(/[\n\r]+/g, " ").trim() ?? "";
|
|
3458
4344
|
const preview = rawPreview ? rawPreview.slice(0, 60) + (rawPreview.length > 60 ? "..." : "") : "";
|
|
3459
|
-
return /* @__PURE__ */ (0,
|
|
4345
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_ink18.Text, { children: [
|
|
3460
4346
|
isSelected ? "> " : " ",
|
|
3461
|
-
/* @__PURE__ */ (0,
|
|
4347
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_ink18.Text, { bold: true, children: session.name ?? session.id.slice(0, SESSION_ID_DISPLAY_LENGTH) }),
|
|
3462
4348
|
" ",
|
|
3463
|
-
/* @__PURE__ */ (0,
|
|
4349
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_ink18.Text, { dimColor: true, children: new Date(session.updatedAt).toLocaleString(void 0, {
|
|
3464
4350
|
month: "short",
|
|
3465
4351
|
day: "numeric",
|
|
3466
4352
|
hour: "2-digit",
|
|
3467
4353
|
minute: "2-digit"
|
|
3468
4354
|
}) }),
|
|
3469
4355
|
" ",
|
|
3470
|
-
/* @__PURE__ */ (0,
|
|
4356
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_ink18.Text, { dimColor: true, children: [
|
|
3471
4357
|
"msgs: ",
|
|
3472
4358
|
session.messages.length
|
|
3473
4359
|
] }),
|
|
3474
|
-
preview ? /* @__PURE__ */ (0,
|
|
4360
|
+
preview ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
|
|
3475
4361
|
"\n ",
|
|
3476
|
-
/* @__PURE__ */ (0,
|
|
4362
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_ink18.Text, { color: "gray", children: preview })
|
|
3477
4363
|
] }) : null
|
|
3478
4364
|
] });
|
|
3479
4365
|
},
|
|
@@ -3485,54 +4371,382 @@ function SessionPicker({
|
|
|
3485
4371
|
}
|
|
3486
4372
|
|
|
3487
4373
|
// src/ui/BackgroundTaskPanel.tsx
|
|
3488
|
-
var
|
|
3489
|
-
|
|
4374
|
+
var import_ink19 = require("ink");
|
|
4375
|
+
|
|
4376
|
+
// src/ui/background-task-row-format.ts
|
|
3490
4377
|
var MS_PER_SECOND = 1e3;
|
|
3491
4378
|
var SECONDS_PER_MINUTE = 60;
|
|
3492
4379
|
var MINUTES_PER_HOUR = 60;
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
4380
|
+
var SUCCESS_EXIT_CODE3 = 0;
|
|
4381
|
+
function formatBackgroundTaskRow(task, options = {}) {
|
|
4382
|
+
const row = {
|
|
4383
|
+
connector: options.isLast === false ? "\u251C" : "\u2514",
|
|
4384
|
+
marker: getStatusMarker(task),
|
|
4385
|
+
color: getStatusColor(task),
|
|
4386
|
+
label: getTaskLabel(task),
|
|
4387
|
+
segments: getTaskSegments(task, options.now ?? Date.now()),
|
|
4388
|
+
preview: getTaskPreview(task)
|
|
4389
|
+
};
|
|
4390
|
+
return {
|
|
4391
|
+
...row,
|
|
4392
|
+
accessibleText: formatAccessibleText(row)
|
|
4393
|
+
};
|
|
4394
|
+
}
|
|
4395
|
+
function getStatusColor(task) {
|
|
4396
|
+
if (isFailedTask(task)) return "red";
|
|
4397
|
+
if (task.status === "completed") return "green";
|
|
4398
|
+
if (task.status === "cancelled") return "yellow";
|
|
3497
4399
|
return "cyan";
|
|
3498
4400
|
}
|
|
3499
|
-
function getStatusMarker(
|
|
3500
|
-
if (status === "queued" || status === "running") return "\u25A1";
|
|
4401
|
+
function getStatusMarker(task) {
|
|
4402
|
+
if (task.status === "queued" || task.status === "running") return "\u25A1";
|
|
3501
4403
|
return "\u25A0";
|
|
3502
4404
|
}
|
|
4405
|
+
function getTaskLabel(task) {
|
|
4406
|
+
if (task.kind === "agent") return `${task.label} agent`;
|
|
4407
|
+
if (task.kind === "process") return task.label || "Process";
|
|
4408
|
+
return task.label;
|
|
4409
|
+
}
|
|
4410
|
+
function getTaskSegments(task, now) {
|
|
4411
|
+
const segments = [];
|
|
4412
|
+
if (task.status === "running") {
|
|
4413
|
+
const idle = formatAge(task.lastActivityAt, now);
|
|
4414
|
+
if (idle) segments.push(`idle ${idle}`);
|
|
4415
|
+
}
|
|
4416
|
+
if (task.status === "failed") {
|
|
4417
|
+
segments.push(task.statusLabel === "timed out" ? "timed out" : "failed");
|
|
4418
|
+
}
|
|
4419
|
+
if (task.status === "cancelled") {
|
|
4420
|
+
segments.push("cancelled");
|
|
4421
|
+
}
|
|
4422
|
+
if (task.timeoutReason) {
|
|
4423
|
+
segments.push(task.timeoutReason);
|
|
4424
|
+
}
|
|
4425
|
+
if (task.status === "completed" && task.exitCode !== void 0 && task.exitCode !== SUCCESS_EXIT_CODE3) {
|
|
4426
|
+
segments.push(`exit ${task.exitCode}`);
|
|
4427
|
+
}
|
|
4428
|
+
if (task.signalCode) {
|
|
4429
|
+
segments.push(`signal ${task.signalCode}`);
|
|
4430
|
+
}
|
|
4431
|
+
return segments;
|
|
4432
|
+
}
|
|
3503
4433
|
function getTaskPreview(task) {
|
|
3504
|
-
|
|
4434
|
+
const preview = task.errorPreview ?? task.resultPreview ?? task.currentAction ?? task.preview;
|
|
4435
|
+
return preview || void 0;
|
|
3505
4436
|
}
|
|
3506
|
-
function formatAge(iso) {
|
|
4437
|
+
function formatAge(iso, now) {
|
|
3507
4438
|
if (!iso) return void 0;
|
|
3508
4439
|
const timestamp = Date.parse(iso);
|
|
3509
4440
|
if (Number.isNaN(timestamp)) return void 0;
|
|
3510
|
-
const seconds = Math.max(0, Math.floor((
|
|
4441
|
+
const seconds = Math.max(0, Math.floor((now - timestamp) / MS_PER_SECOND));
|
|
3511
4442
|
if (seconds < SECONDS_PER_MINUTE) return `${seconds}s`;
|
|
3512
4443
|
const minutes = Math.floor(seconds / SECONDS_PER_MINUTE);
|
|
3513
4444
|
if (minutes < MINUTES_PER_HOUR) return `${minutes}m`;
|
|
3514
4445
|
return `${Math.floor(minutes / MINUTES_PER_HOUR)}h`;
|
|
3515
4446
|
}
|
|
4447
|
+
function isFailedTask(task) {
|
|
4448
|
+
return task.status === "failed" || task.status === "completed" && (task.exitCode !== void 0 && task.exitCode !== SUCCESS_EXIT_CODE3 || !!task.signalCode);
|
|
4449
|
+
}
|
|
4450
|
+
function formatAccessibleText(row) {
|
|
4451
|
+
const parts = [`${row.connector} ${row.marker} ${row.label}`, ...row.segments];
|
|
4452
|
+
if (row.preview) parts.push(row.preview);
|
|
4453
|
+
return parts.join(" \xB7 ");
|
|
4454
|
+
}
|
|
4455
|
+
|
|
4456
|
+
// src/ui/BackgroundTaskPanel.tsx
|
|
4457
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
3516
4458
|
function BackgroundTaskPanel({ tasks }) {
|
|
3517
4459
|
if (tasks.length === 0) return null;
|
|
3518
|
-
return /* @__PURE__ */ (0,
|
|
3519
|
-
/* @__PURE__ */ (0,
|
|
3520
|
-
tasks.map((task) =>
|
|
3521
|
-
|
|
3522
|
-
/* @__PURE__ */ (0,
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
4460
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_ink19.Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
4461
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_ink19.Text, { color: "cyan", bold: true, children: "Background work" }),
|
|
4462
|
+
tasks.map((task, index) => {
|
|
4463
|
+
const row = formatBackgroundTaskRow(task, { isLast: index === tasks.length - 1 });
|
|
4464
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_ink19.Text, { children: [
|
|
4465
|
+
`${row.connector} `,
|
|
4466
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_ink19.Text, { color: row.color, children: row.marker }),
|
|
4467
|
+
` ${row.label}`,
|
|
4468
|
+
row.segments.map((segment, segmentIndex) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_ink19.Text, { dimColor: true, children: ` \xB7 ${segment}` }, `${segment}-${segmentIndex}`)),
|
|
4469
|
+
row.preview ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_ink19.Text, { dimColor: true, children: ` \xB7 ${row.preview}` }) : null
|
|
4470
|
+
] }, task.id);
|
|
4471
|
+
})
|
|
3528
4472
|
] });
|
|
3529
4473
|
}
|
|
3530
4474
|
|
|
4475
|
+
// src/ui/UpdateNotice.tsx
|
|
4476
|
+
var import_ink20 = require("ink");
|
|
4477
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
4478
|
+
function UpdateNotice({ message }) {
|
|
4479
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_ink20.Box, { paddingX: 1, marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_ink20.Text, { color: "yellow", children: message }) });
|
|
4480
|
+
}
|
|
4481
|
+
|
|
4482
|
+
// src/utils/update-check.ts
|
|
4483
|
+
var import_node_fs5 = require("fs");
|
|
4484
|
+
var import_node_path7 = require("path");
|
|
4485
|
+
|
|
4486
|
+
// src/utils/semver-compare.ts
|
|
4487
|
+
function compareSemverVersions(left, right) {
|
|
4488
|
+
const parsedLeft = parseSemver(left);
|
|
4489
|
+
const parsedRight = parseSemver(right);
|
|
4490
|
+
if (parsedLeft === void 0 || parsedRight === void 0) {
|
|
4491
|
+
return Math.sign(left.localeCompare(right));
|
|
4492
|
+
}
|
|
4493
|
+
const coreCompare = compareNumber(parsedLeft.major, parsedRight.major) || compareNumber(parsedLeft.minor, parsedRight.minor) || compareNumber(parsedLeft.patch, parsedRight.patch);
|
|
4494
|
+
if (coreCompare !== 0) {
|
|
4495
|
+
return coreCompare;
|
|
4496
|
+
}
|
|
4497
|
+
return comparePrerelease(parsedLeft.prerelease, parsedRight.prerelease);
|
|
4498
|
+
}
|
|
4499
|
+
function isNewerSemverVersion(candidate, current) {
|
|
4500
|
+
return compareSemverVersions(candidate, current) > 0;
|
|
4501
|
+
}
|
|
4502
|
+
function parseSemver(value) {
|
|
4503
|
+
const normalized = value.trim().replace(/^v/, "").split("+")[0] ?? "";
|
|
4504
|
+
const [core, prereleaseText] = normalized.split("-", 2);
|
|
4505
|
+
const [majorText, minorText, patchText] = core.split(".");
|
|
4506
|
+
const major = parseNumericIdentifier(majorText);
|
|
4507
|
+
const minor = parseNumericIdentifier(minorText);
|
|
4508
|
+
const patch = parseNumericIdentifier(patchText);
|
|
4509
|
+
if (major === void 0 || minor === void 0 || patch === void 0) {
|
|
4510
|
+
return void 0;
|
|
4511
|
+
}
|
|
4512
|
+
return {
|
|
4513
|
+
major,
|
|
4514
|
+
minor,
|
|
4515
|
+
patch,
|
|
4516
|
+
prerelease: prereleaseText ? prereleaseText.split(".") : []
|
|
4517
|
+
};
|
|
4518
|
+
}
|
|
4519
|
+
function parseNumericIdentifier(value) {
|
|
4520
|
+
if (value === void 0 || !/^\d+$/.test(value)) {
|
|
4521
|
+
return void 0;
|
|
4522
|
+
}
|
|
4523
|
+
return Number(value);
|
|
4524
|
+
}
|
|
4525
|
+
function compareNumber(left, right) {
|
|
4526
|
+
return Math.sign(left - right);
|
|
4527
|
+
}
|
|
4528
|
+
function comparePrerelease(left, right) {
|
|
4529
|
+
if (left.length === 0 && right.length === 0) {
|
|
4530
|
+
return 0;
|
|
4531
|
+
}
|
|
4532
|
+
if (left.length === 0) {
|
|
4533
|
+
return 1;
|
|
4534
|
+
}
|
|
4535
|
+
if (right.length === 0) {
|
|
4536
|
+
return -1;
|
|
4537
|
+
}
|
|
4538
|
+
const max = Math.max(left.length, right.length);
|
|
4539
|
+
for (let index = 0; index < max; index += 1) {
|
|
4540
|
+
const leftPart = left[index];
|
|
4541
|
+
const rightPart = right[index];
|
|
4542
|
+
if (leftPart === void 0) {
|
|
4543
|
+
return -1;
|
|
4544
|
+
}
|
|
4545
|
+
if (rightPart === void 0) {
|
|
4546
|
+
return 1;
|
|
4547
|
+
}
|
|
4548
|
+
const partCompare = comparePrereleaseIdentifier(leftPart, rightPart);
|
|
4549
|
+
if (partCompare !== 0) {
|
|
4550
|
+
return partCompare;
|
|
4551
|
+
}
|
|
4552
|
+
}
|
|
4553
|
+
return 0;
|
|
4554
|
+
}
|
|
4555
|
+
function comparePrereleaseIdentifier(left, right) {
|
|
4556
|
+
const leftNumber = parseNumericIdentifier(left);
|
|
4557
|
+
const rightNumber = parseNumericIdentifier(right);
|
|
4558
|
+
if (leftNumber !== void 0 && rightNumber !== void 0) {
|
|
4559
|
+
return compareNumber(leftNumber, rightNumber);
|
|
4560
|
+
}
|
|
4561
|
+
if (leftNumber !== void 0) {
|
|
4562
|
+
return -1;
|
|
4563
|
+
}
|
|
4564
|
+
if (rightNumber !== void 0) {
|
|
4565
|
+
return 1;
|
|
4566
|
+
}
|
|
4567
|
+
return Math.sign(left.localeCompare(right));
|
|
4568
|
+
}
|
|
4569
|
+
|
|
4570
|
+
// src/utils/update-check.ts
|
|
4571
|
+
var CLI_UPDATE_PACKAGE_NAME = "@robota-sdk/agent-cli";
|
|
4572
|
+
var CLI_UPDATE_REGISTRY_URL = "https://registry.npmjs.org";
|
|
4573
|
+
var HOURS_PER_DAY = 24;
|
|
4574
|
+
var MINUTES_PER_HOUR2 = 60;
|
|
4575
|
+
var SECONDS_PER_MINUTE2 = 60;
|
|
4576
|
+
var MS_PER_SECOND2 = 1e3;
|
|
4577
|
+
var CLI_UPDATE_CACHE_TTL_MS = HOURS_PER_DAY * MINUTES_PER_HOUR2 * SECONDS_PER_MINUTE2 * MS_PER_SECOND2;
|
|
4578
|
+
var CLI_UPDATE_TIMEOUT_MS = 1500;
|
|
4579
|
+
var DEFAULT_INSTALL_COMMAND = "npm install -g '@robota-sdk/agent-cli@latest'";
|
|
4580
|
+
function getUserUpdateCheckCachePath(home = process.env.HOME ?? process.env.USERPROFILE ?? "/") {
|
|
4581
|
+
return (0, import_node_path7.join)(home, ".robota", "update-check.json");
|
|
4582
|
+
}
|
|
4583
|
+
function readUpdateCheckCache(path) {
|
|
4584
|
+
if (!(0, import_node_fs5.existsSync)(path)) {
|
|
4585
|
+
return void 0;
|
|
4586
|
+
}
|
|
4587
|
+
try {
|
|
4588
|
+
const parsed = JSON.parse((0, import_node_fs5.readFileSync)(path, "utf8"));
|
|
4589
|
+
return parseUpdateCheckCache(parsed);
|
|
4590
|
+
} catch {
|
|
4591
|
+
return void 0;
|
|
4592
|
+
}
|
|
4593
|
+
}
|
|
4594
|
+
function writeUpdateCheckCache(path, cache) {
|
|
4595
|
+
(0, import_node_fs5.mkdirSync)((0, import_node_path7.dirname)(path), { recursive: true });
|
|
4596
|
+
(0, import_node_fs5.writeFileSync)(path, JSON.stringify(cache, null, 2) + "\n", "utf8");
|
|
4597
|
+
}
|
|
4598
|
+
async function checkForCliUpdate(options) {
|
|
4599
|
+
if (options.disabled === true) {
|
|
4600
|
+
return { status: "skipped", reason: "disabled" };
|
|
4601
|
+
}
|
|
4602
|
+
const packageName = options.packageName ?? CLI_UPDATE_PACKAGE_NAME;
|
|
4603
|
+
const cachePath = options.cachePath ?? getUserUpdateCheckCachePath();
|
|
4604
|
+
const now = options.now ?? /* @__PURE__ */ new Date();
|
|
4605
|
+
const ttlMs = options.ttlMs ?? CLI_UPDATE_CACHE_TTL_MS;
|
|
4606
|
+
if (options.force !== true) {
|
|
4607
|
+
const cached = readUpdateCheckCache(cachePath);
|
|
4608
|
+
if (cached !== void 0 && isFreshCache(cached, now, ttlMs, packageName)) {
|
|
4609
|
+
return resultFromCache(cached, options.currentVersion);
|
|
4610
|
+
}
|
|
4611
|
+
}
|
|
4612
|
+
try {
|
|
4613
|
+
const latestVersion = await fetchLatestVersion({
|
|
4614
|
+
fetchImpl: options.fetchImpl ?? fetch,
|
|
4615
|
+
packageName,
|
|
4616
|
+
registryUrl: options.registryUrl ?? CLI_UPDATE_REGISTRY_URL,
|
|
4617
|
+
timeoutMs: options.timeoutMs ?? CLI_UPDATE_TIMEOUT_MS
|
|
4618
|
+
});
|
|
4619
|
+
tryWriteUpdateCheckCache(cachePath, {
|
|
4620
|
+
packageName,
|
|
4621
|
+
checkedAt: now.toISOString(),
|
|
4622
|
+
currentVersion: options.currentVersion,
|
|
4623
|
+
latestVersion
|
|
4624
|
+
});
|
|
4625
|
+
return resultFromLatestVersion(options.currentVersion, latestVersion);
|
|
4626
|
+
} catch (error) {
|
|
4627
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
4628
|
+
tryWriteUpdateCheckCache(cachePath, {
|
|
4629
|
+
packageName,
|
|
4630
|
+
checkedAt: now.toISOString(),
|
|
4631
|
+
currentVersion: options.currentVersion,
|
|
4632
|
+
errorMessage
|
|
4633
|
+
});
|
|
4634
|
+
return { status: "error", errorMessage };
|
|
4635
|
+
}
|
|
4636
|
+
}
|
|
4637
|
+
function tryWriteUpdateCheckCache(path, cache) {
|
|
4638
|
+
try {
|
|
4639
|
+
writeUpdateCheckCache(path, cache);
|
|
4640
|
+
} catch {
|
|
4641
|
+
}
|
|
4642
|
+
}
|
|
4643
|
+
async function getStartupCliUpdateNotice(options) {
|
|
4644
|
+
const result = await checkForCliUpdate(options);
|
|
4645
|
+
return result.status === "update_available" ? result.notice : void 0;
|
|
4646
|
+
}
|
|
4647
|
+
function shouldRunStartupCliUpdateCheck(input) {
|
|
4648
|
+
return input.printMode === false && input.disableUpdateCheck === false;
|
|
4649
|
+
}
|
|
4650
|
+
function formatCliUpdateNotice(notice) {
|
|
4651
|
+
return [
|
|
4652
|
+
`Robota update available: ${notice.currentVersion} -> ${notice.latestVersion}.`,
|
|
4653
|
+
`Run ${notice.installCommand}`
|
|
4654
|
+
].join(" ");
|
|
4655
|
+
}
|
|
4656
|
+
function formatCliUpdateCheckMessage(result) {
|
|
4657
|
+
if (result.status === "update_available") {
|
|
4658
|
+
return formatCliUpdateNotice(result.notice);
|
|
4659
|
+
}
|
|
4660
|
+
if (result.status === "current") {
|
|
4661
|
+
return `Robota is up to date (${result.currentVersion}).`;
|
|
4662
|
+
}
|
|
4663
|
+
if (result.status === "skipped") {
|
|
4664
|
+
return "Robota update check skipped.";
|
|
4665
|
+
}
|
|
4666
|
+
return `Robota update check failed: ${result.errorMessage}`;
|
|
4667
|
+
}
|
|
4668
|
+
function resultFromCache(cache, currentVersion) {
|
|
4669
|
+
if (cache.errorMessage !== void 0) {
|
|
4670
|
+
return { status: "error", errorMessage: cache.errorMessage };
|
|
4671
|
+
}
|
|
4672
|
+
if (cache.latestVersion === void 0) {
|
|
4673
|
+
return { status: "error", errorMessage: "Cached update check has no latest version" };
|
|
4674
|
+
}
|
|
4675
|
+
return resultFromLatestVersion(currentVersion, cache.latestVersion);
|
|
4676
|
+
}
|
|
4677
|
+
function resultFromLatestVersion(currentVersion, latestVersion) {
|
|
4678
|
+
if (isNewerSemverVersion(latestVersion, currentVersion)) {
|
|
4679
|
+
return {
|
|
4680
|
+
status: "update_available",
|
|
4681
|
+
notice: {
|
|
4682
|
+
currentVersion,
|
|
4683
|
+
latestVersion,
|
|
4684
|
+
installCommand: DEFAULT_INSTALL_COMMAND
|
|
4685
|
+
}
|
|
4686
|
+
};
|
|
4687
|
+
}
|
|
4688
|
+
return { status: "current", currentVersion, latestVersion };
|
|
4689
|
+
}
|
|
4690
|
+
function isFreshCache(cache, now, ttlMs, packageName) {
|
|
4691
|
+
if (cache.packageName !== packageName) {
|
|
4692
|
+
return false;
|
|
4693
|
+
}
|
|
4694
|
+
const checkedAt = Date.parse(cache.checkedAt);
|
|
4695
|
+
if (!Number.isFinite(checkedAt)) {
|
|
4696
|
+
return false;
|
|
4697
|
+
}
|
|
4698
|
+
return now.getTime() - checkedAt < ttlMs;
|
|
4699
|
+
}
|
|
4700
|
+
async function fetchLatestVersion(options) {
|
|
4701
|
+
const controller = new AbortController();
|
|
4702
|
+
const timeout = setTimeout(() => controller.abort(), options.timeoutMs);
|
|
4703
|
+
try {
|
|
4704
|
+
const packageUrl = buildPackageMetadataUrl(options.registryUrl, options.packageName);
|
|
4705
|
+
const response = await options.fetchImpl(packageUrl, {
|
|
4706
|
+
headers: { accept: "application/json" },
|
|
4707
|
+
signal: controller.signal
|
|
4708
|
+
});
|
|
4709
|
+
if (!response.ok) {
|
|
4710
|
+
throw new Error(`registry responded with HTTP ${response.status}`);
|
|
4711
|
+
}
|
|
4712
|
+
const metadata = await response.json();
|
|
4713
|
+
const latest = metadata["dist-tags"]?.latest;
|
|
4714
|
+
if (typeof latest !== "string" || latest.trim().length === 0) {
|
|
4715
|
+
throw new Error("registry metadata is missing dist-tags.latest");
|
|
4716
|
+
}
|
|
4717
|
+
return latest;
|
|
4718
|
+
} finally {
|
|
4719
|
+
clearTimeout(timeout);
|
|
4720
|
+
}
|
|
4721
|
+
}
|
|
4722
|
+
function buildPackageMetadataUrl(registryUrl, packageName) {
|
|
4723
|
+
return `${registryUrl.replace(/\/+$/, "")}/${encodeURIComponent(packageName)}`;
|
|
4724
|
+
}
|
|
4725
|
+
function parseUpdateCheckCache(value) {
|
|
4726
|
+
if (!isJsonObject(value)) {
|
|
4727
|
+
return void 0;
|
|
4728
|
+
}
|
|
4729
|
+
const candidate = value;
|
|
4730
|
+
if (typeof candidate.packageName === "string" && typeof candidate.checkedAt === "string" && typeof candidate.currentVersion === "string" && (candidate.latestVersion === void 0 || typeof candidate.latestVersion === "string") && (candidate.errorMessage === void 0 || typeof candidate.errorMessage === "string")) {
|
|
4731
|
+
return {
|
|
4732
|
+
packageName: candidate.packageName,
|
|
4733
|
+
checkedAt: candidate.checkedAt,
|
|
4734
|
+
currentVersion: candidate.currentVersion,
|
|
4735
|
+
...candidate.latestVersion !== void 0 && { latestVersion: candidate.latestVersion },
|
|
4736
|
+
...candidate.errorMessage !== void 0 && { errorMessage: candidate.errorMessage }
|
|
4737
|
+
};
|
|
4738
|
+
}
|
|
4739
|
+
return void 0;
|
|
4740
|
+
}
|
|
4741
|
+
function isJsonObject(value) {
|
|
4742
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
4743
|
+
}
|
|
4744
|
+
|
|
3531
4745
|
// src/ui/App.tsx
|
|
3532
|
-
var
|
|
4746
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
3533
4747
|
function App(props) {
|
|
3534
|
-
const [activeSessionId, setActiveSessionId] = (0,
|
|
3535
|
-
return /* @__PURE__ */ (0,
|
|
4748
|
+
const [activeSessionId, setActiveSessionId] = (0, import_react19.useState)(props.resumeSessionId);
|
|
4749
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
3536
4750
|
AppInner,
|
|
3537
4751
|
{
|
|
3538
4752
|
...props,
|
|
@@ -3544,7 +4758,7 @@ function App(props) {
|
|
|
3544
4758
|
}
|
|
3545
4759
|
function AppInner(props) {
|
|
3546
4760
|
const cwd = props.cwd;
|
|
3547
|
-
const providerDefinitions = props.providerDefinitions ??
|
|
4761
|
+
const providerDefinitions = props.providerDefinitions ?? [];
|
|
3548
4762
|
const {
|
|
3549
4763
|
interactiveSession,
|
|
3550
4764
|
registry,
|
|
@@ -3578,47 +4792,65 @@ function AppInner(props) {
|
|
|
3578
4792
|
providerDefinitions
|
|
3579
4793
|
});
|
|
3580
4794
|
const pluginCallbacks = usePluginCallbacks(cwd);
|
|
3581
|
-
const { exit } = (0,
|
|
3582
|
-
const [sessionName, setSessionName] = (0,
|
|
4795
|
+
const { exit } = (0, import_ink21.useApp)();
|
|
4796
|
+
const [sessionName, setSessionName] = (0, import_react19.useState)(props.sessionName);
|
|
4797
|
+
const [updateNotice, setUpdateNotice] = (0, import_react19.useState)();
|
|
4798
|
+
const [statusLineSettings, setStatusLineSettings] = useStatusLineSettings();
|
|
4799
|
+
const activeBackgroundTaskCount = backgroundTasks.filter(
|
|
4800
|
+
(task) => task.status === "queued" || task.status === "running"
|
|
4801
|
+
).length;
|
|
3583
4802
|
const {
|
|
3584
4803
|
handleSubmit,
|
|
3585
4804
|
pendingModelId,
|
|
3586
4805
|
pendingProviderProfile,
|
|
3587
|
-
|
|
4806
|
+
pendingInteractionPrompt,
|
|
3588
4807
|
showPluginTUI,
|
|
3589
4808
|
showSessionPicker,
|
|
3590
4809
|
setShowPluginTUI,
|
|
3591
4810
|
setShowSessionPicker,
|
|
3592
4811
|
handleModelConfirm,
|
|
3593
4812
|
handleProviderConfirm,
|
|
3594
|
-
|
|
3595
|
-
|
|
4813
|
+
handleInteractionSubmit,
|
|
4814
|
+
handleInteractionCancel
|
|
3596
4815
|
} = useSideEffects({
|
|
3597
4816
|
cwd,
|
|
3598
4817
|
interactiveSession,
|
|
3599
4818
|
addEntry,
|
|
3600
4819
|
baseHandleSubmit,
|
|
3601
4820
|
setSessionName,
|
|
4821
|
+
setStatusLineSettings,
|
|
3602
4822
|
providerDefinitions
|
|
3603
4823
|
});
|
|
3604
|
-
(0,
|
|
4824
|
+
(0, import_react19.useEffect)(() => {
|
|
3605
4825
|
const name = interactiveSession?.getName?.();
|
|
3606
4826
|
if (name && !sessionName) setSessionName(name);
|
|
3607
4827
|
}, [interactiveSession, sessionName]);
|
|
3608
|
-
(0,
|
|
4828
|
+
(0, import_react19.useEffect)(() => {
|
|
4829
|
+
let isMounted = true;
|
|
4830
|
+
props.startupUpdateNoticePromise?.then((notice) => {
|
|
4831
|
+
if (isMounted && notice !== void 0) {
|
|
4832
|
+
setUpdateNotice(notice);
|
|
4833
|
+
}
|
|
4834
|
+
}).catch(() => {
|
|
4835
|
+
});
|
|
4836
|
+
return () => {
|
|
4837
|
+
isMounted = false;
|
|
4838
|
+
};
|
|
4839
|
+
}, [props.startupUpdateNoticePromise]);
|
|
4840
|
+
(0, import_react19.useEffect)(() => {
|
|
3609
4841
|
const title = sessionName ? `Robota \u2014 ${sessionName}` : "Robota";
|
|
3610
4842
|
process.stdout.write(`\x1B]0;${title}\x07`);
|
|
3611
4843
|
}, [sessionName]);
|
|
3612
|
-
(0,
|
|
4844
|
+
(0, import_ink21.useInput)((_input, key) => {
|
|
3613
4845
|
if (!key.escape || !isThinking) return;
|
|
3614
4846
|
if (permissionRequest || showPluginTUI || showSessionPicker) return;
|
|
3615
4847
|
handleAbort();
|
|
3616
4848
|
});
|
|
3617
|
-
(0,
|
|
4849
|
+
(0, import_ink21.useInput)((input, key) => {
|
|
3618
4850
|
if (!key.ctrl || input !== "c" || isShuttingDown) return;
|
|
3619
4851
|
void handleShutdown("prompt_input_exit").finally(() => exit());
|
|
3620
4852
|
});
|
|
3621
|
-
(0,
|
|
4853
|
+
(0, import_react19.useEffect)(() => {
|
|
3622
4854
|
const onSigterm = () => {
|
|
3623
4855
|
if (isShuttingDown) return;
|
|
3624
4856
|
void handleShutdown("other").finally(() => exit());
|
|
@@ -3638,59 +4870,59 @@ function AppInner(props) {
|
|
|
3638
4870
|
sessionId = session.getSessionId();
|
|
3639
4871
|
} catch {
|
|
3640
4872
|
}
|
|
3641
|
-
return /* @__PURE__ */ (0,
|
|
3642
|
-
/* @__PURE__ */ (0,
|
|
3643
|
-
/* @__PURE__ */ (0,
|
|
4873
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_ink21.Box, { flexDirection: "column", children: [
|
|
4874
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_ink21.Box, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
|
|
4875
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_ink21.Text, { color: "cyan", bold: true, children: `
|
|
3644
4876
|
____ ___ ____ ___ _____ _
|
|
3645
4877
|
| _ \\ / _ \\| __ ) / _ \\_ _|/ \\
|
|
3646
4878
|
| |_) | | | | _ \\| | | || | / _ \\
|
|
3647
4879
|
| _ <| |_| | |_) | |_| || |/ ___ \\
|
|
3648
4880
|
|_| \\_\\\\___/|____/ \\___/ |_/_/ \\_\\
|
|
3649
4881
|
` }),
|
|
3650
|
-
/* @__PURE__ */ (0,
|
|
4882
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_ink21.Text, { dimColor: true, children: [
|
|
3651
4883
|
" v",
|
|
3652
4884
|
props.version ?? "0.0.0"
|
|
3653
4885
|
] })
|
|
3654
4886
|
] }),
|
|
3655
|
-
/* @__PURE__ */ (0,
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
/* @__PURE__ */ (0,
|
|
4887
|
+
updateNotice && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(UpdateNotice, { message: formatCliUpdateNotice(updateNotice) }),
|
|
4888
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_ink21.Box, { flexDirection: "column", paddingX: 1, flexGrow: 1, children: [
|
|
4889
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(MessageList, { history }),
|
|
4890
|
+
isShuttingDown && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_ink21.Box, { marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_ink21.Text, { color: "yellow", children: "Shutting down..." }) }),
|
|
4891
|
+
(isThinking || activeTools.length > 0) && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_ink21.Box, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(StreamingIndicator, { text: streamingText, activeTools }) }),
|
|
4892
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(BackgroundTaskPanel, { tasks: backgroundTasks })
|
|
3660
4893
|
] }),
|
|
3661
|
-
permissionRequest && /* @__PURE__ */ (0,
|
|
3662
|
-
pendingModelId && /* @__PURE__ */ (0,
|
|
4894
|
+
permissionRequest && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(PermissionPrompt, { request: permissionRequest }),
|
|
4895
|
+
pendingModelId && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
3663
4896
|
ConfirmPrompt,
|
|
3664
4897
|
{
|
|
3665
|
-
message: `Change model to ${(0,
|
|
4898
|
+
message: `Change model to ${(0, import_agent_core9.getModelName)(pendingModelId)}? This will restart the session.`,
|
|
3666
4899
|
onSelect: handleModelConfirm
|
|
3667
4900
|
}
|
|
3668
4901
|
),
|
|
3669
|
-
pendingProviderProfile && /* @__PURE__ */ (0,
|
|
4902
|
+
pendingProviderProfile && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
3670
4903
|
ConfirmPrompt,
|
|
3671
4904
|
{
|
|
3672
4905
|
message: `Change provider to ${pendingProviderProfile}? This will restart the session.`,
|
|
3673
4906
|
onSelect: handleProviderConfirm
|
|
3674
4907
|
}
|
|
3675
4908
|
),
|
|
3676
|
-
|
|
3677
|
-
|
|
4909
|
+
pendingInteractionPrompt && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
4910
|
+
InteractivePrompt,
|
|
3678
4911
|
{
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
onCancel: handleProviderSetupCancel
|
|
4912
|
+
prompt: pendingInteractionPrompt,
|
|
4913
|
+
onSubmit: handleInteractionSubmit,
|
|
4914
|
+
onCancel: handleInteractionCancel
|
|
3683
4915
|
}
|
|
3684
4916
|
),
|
|
3685
|
-
showPluginTUI && /* @__PURE__ */ (0,
|
|
4917
|
+
showPluginTUI && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
3686
4918
|
PluginTUI,
|
|
3687
4919
|
{
|
|
3688
4920
|
callbacks: pluginCallbacks,
|
|
3689
4921
|
onClose: () => setShowPluginTUI(false),
|
|
3690
|
-
addMessage: (msg) => addEntry((0,
|
|
4922
|
+
addMessage: (msg) => addEntry((0, import_agent_core9.messageToHistoryEntry)((0, import_agent_core9.createSystemMessage)(msg.content)))
|
|
3691
4923
|
}
|
|
3692
4924
|
),
|
|
3693
|
-
showSessionPicker && /* @__PURE__ */ (0,
|
|
4925
|
+
showSessionPicker && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
3694
4926
|
SessionPicker,
|
|
3695
4927
|
{
|
|
3696
4928
|
sessionStore: props.sessionStore,
|
|
@@ -3701,42 +4933,46 @@ function AppInner(props) {
|
|
|
3701
4933
|
},
|
|
3702
4934
|
onCancel: () => {
|
|
3703
4935
|
setShowSessionPicker(false);
|
|
3704
|
-
addEntry((0,
|
|
4936
|
+
addEntry((0, import_agent_core9.messageToHistoryEntry)((0, import_agent_core9.createSystemMessage)("Session resume cancelled.")));
|
|
3705
4937
|
}
|
|
3706
4938
|
}
|
|
3707
4939
|
),
|
|
3708
|
-
/* @__PURE__ */ (0,
|
|
3709
|
-
|
|
4940
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
4941
|
+
SessionStatusBar,
|
|
3710
4942
|
{
|
|
4943
|
+
cwd,
|
|
3711
4944
|
permissionMode,
|
|
3712
|
-
|
|
4945
|
+
modelId: props.modelId,
|
|
3713
4946
|
sessionId,
|
|
3714
4947
|
messageCount: history.length,
|
|
3715
4948
|
isThinking,
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
4949
|
+
activeToolCount: activeTools.length,
|
|
4950
|
+
activeBackgroundTaskCount,
|
|
4951
|
+
hasPendingPrompt: pendingPrompt !== null,
|
|
4952
|
+
contextState,
|
|
4953
|
+
sessionName,
|
|
4954
|
+
settings: statusLineSettings
|
|
3720
4955
|
}
|
|
3721
4956
|
),
|
|
3722
|
-
/* @__PURE__ */ (0,
|
|
4957
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
3723
4958
|
InputArea,
|
|
3724
4959
|
{
|
|
3725
4960
|
onSubmit: handleSubmit,
|
|
3726
4961
|
onCancelQueue: handleCancelQueue,
|
|
3727
|
-
isDisabled: !!permissionRequest || showPluginTUI || showSessionPicker || isShuttingDown ||
|
|
4962
|
+
isDisabled: !!permissionRequest || showPluginTUI || showSessionPicker || isShuttingDown || pendingInteractionPrompt !== null || isThinking && !!pendingPrompt,
|
|
3728
4963
|
isAborting,
|
|
3729
4964
|
pendingPrompt,
|
|
3730
4965
|
registry,
|
|
3731
|
-
sessionName
|
|
4966
|
+
sessionName,
|
|
4967
|
+
history
|
|
3732
4968
|
}
|
|
3733
4969
|
),
|
|
3734
|
-
/* @__PURE__ */ (0,
|
|
4970
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_ink21.Text, { children: " " })
|
|
3735
4971
|
] });
|
|
3736
4972
|
}
|
|
3737
4973
|
|
|
3738
4974
|
// src/ui/render.tsx
|
|
3739
|
-
var
|
|
4975
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
3740
4976
|
function renderApp(options) {
|
|
3741
4977
|
process.on("unhandledRejection", (reason) => {
|
|
3742
4978
|
process.stderr.write(`
|
|
@@ -3747,16 +4983,10 @@ function renderApp(options) {
|
|
|
3747
4983
|
`);
|
|
3748
4984
|
}
|
|
3749
4985
|
});
|
|
3750
|
-
|
|
3751
|
-
process.stdout.write("\x1B[?2004h");
|
|
3752
|
-
}
|
|
3753
|
-
const instance = (0, import_ink18.render)(/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(App, { ...options }), {
|
|
4986
|
+
const instance = (0, import_ink22.render)(/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(App, { ...options }), {
|
|
3754
4987
|
exitOnCtrlC: false
|
|
3755
4988
|
});
|
|
3756
4989
|
instance.waitUntilExit().then(() => {
|
|
3757
|
-
if (process.stdout.isTTY) {
|
|
3758
|
-
process.stdout.write("\x1B[?2004l");
|
|
3759
|
-
}
|
|
3760
4990
|
process.exit(0);
|
|
3761
4991
|
}).catch((err) => {
|
|
3762
4992
|
if (err) {
|
|
@@ -3806,7 +5036,7 @@ function resolveShell(request) {
|
|
|
3806
5036
|
return { command: request.shell ?? "sh", args: ["-c", request.command] };
|
|
3807
5037
|
}
|
|
3808
5038
|
function sendInput(child, input) {
|
|
3809
|
-
return new Promise((
|
|
5039
|
+
return new Promise((resolve2, reject) => {
|
|
3810
5040
|
const onError = (error) => {
|
|
3811
5041
|
child.stdin.off("error", onError);
|
|
3812
5042
|
reject(error);
|
|
@@ -3814,7 +5044,7 @@ function sendInput(child, input) {
|
|
|
3814
5044
|
child.stdin.once("error", onError);
|
|
3815
5045
|
child.stdin.end(input, () => {
|
|
3816
5046
|
child.stdin.off("error", onError);
|
|
3817
|
-
|
|
5047
|
+
resolve2();
|
|
3818
5048
|
});
|
|
3819
5049
|
});
|
|
3820
5050
|
}
|
|
@@ -3849,7 +5079,7 @@ function startProcessTask(taskId, request, killGraceMs) {
|
|
|
3849
5079
|
}
|
|
3850
5080
|
function createProcessResult(runtime) {
|
|
3851
5081
|
let settled = false;
|
|
3852
|
-
return new Promise((
|
|
5082
|
+
return new Promise((resolve2, reject) => {
|
|
3853
5083
|
const timeoutTimer = runtime.request.timeoutMs ? setTimeout(() => {
|
|
3854
5084
|
appendLog(runtime.logs, "system", `timed out after ${runtime.request.timeoutMs}ms`);
|
|
3855
5085
|
runtime.child.kill("SIGTERM");
|
|
@@ -3863,7 +5093,7 @@ function createProcessResult(runtime) {
|
|
|
3863
5093
|
if (settled) return;
|
|
3864
5094
|
settled = true;
|
|
3865
5095
|
clearTimers();
|
|
3866
|
-
|
|
5096
|
+
resolve2({
|
|
3867
5097
|
taskId: runtime.taskId,
|
|
3868
5098
|
kind: "process",
|
|
3869
5099
|
output: runtime.capture.getOutput(),
|
|
@@ -3938,22 +5168,22 @@ function readProcessLog(runtime, cursor) {
|
|
|
3938
5168
|
|
|
3939
5169
|
// src/subagents/child-process-subagent-runner.ts
|
|
3940
5170
|
var import_node_child_process3 = require("child_process");
|
|
3941
|
-
var
|
|
3942
|
-
var
|
|
5171
|
+
var import_node_fs7 = require("fs");
|
|
5172
|
+
var import_node_path9 = require("path");
|
|
3943
5173
|
var import_agent_sdk7 = require("@robota-sdk/agent-sdk");
|
|
3944
5174
|
|
|
3945
5175
|
// src/subagents/child-process-subagent-runner-result.ts
|
|
3946
5176
|
var import_agent_sdk5 = require("@robota-sdk/agent-sdk");
|
|
3947
5177
|
|
|
3948
5178
|
// src/subagents/child-process-subagent-ipc.ts
|
|
3949
|
-
function
|
|
5179
|
+
function isRecord2(value) {
|
|
3950
5180
|
return typeof value === "object" && value !== null;
|
|
3951
5181
|
}
|
|
3952
5182
|
function hasString(value, key) {
|
|
3953
5183
|
return typeof value[key] === "string";
|
|
3954
5184
|
}
|
|
3955
5185
|
function isSubagentWorkerChildMessage(value) {
|
|
3956
|
-
if (!
|
|
5186
|
+
if (!isRecord2(value) || !hasString(value, "type")) return false;
|
|
3957
5187
|
switch (value.type) {
|
|
3958
5188
|
case "ready":
|
|
3959
5189
|
return true;
|
|
@@ -4018,7 +5248,7 @@ function extractFirstArg(toolArgs) {
|
|
|
4018
5248
|
return typeof firstValue === "object" ? JSON.stringify(firstValue) : String(firstValue);
|
|
4019
5249
|
}
|
|
4020
5250
|
function sendWorkerMessage(child, message) {
|
|
4021
|
-
return new Promise((
|
|
5251
|
+
return new Promise((resolve2, reject) => {
|
|
4022
5252
|
if (!child.connected) {
|
|
4023
5253
|
reject(new import_agent_sdk4.BackgroundTaskError("crash", "Subagent worker IPC channel is closed"));
|
|
4024
5254
|
return;
|
|
@@ -4028,7 +5258,7 @@ function sendWorkerMessage(child, message) {
|
|
|
4028
5258
|
reject(error);
|
|
4029
5259
|
return;
|
|
4030
5260
|
}
|
|
4031
|
-
|
|
5261
|
+
resolve2();
|
|
4032
5262
|
});
|
|
4033
5263
|
});
|
|
4034
5264
|
}
|
|
@@ -4045,14 +5275,14 @@ async function cancelChildProcess(runtime, reason) {
|
|
|
4045
5275
|
|
|
4046
5276
|
// src/subagents/child-process-subagent-runner-result.ts
|
|
4047
5277
|
function createChildProcessSubagentResult(options) {
|
|
4048
|
-
return new Promise((
|
|
4049
|
-
new ChildProcessSubagentResultController(options,
|
|
5278
|
+
return new Promise((resolve2, reject) => {
|
|
5279
|
+
new ChildProcessSubagentResultController(options, resolve2, reject).start();
|
|
4050
5280
|
});
|
|
4051
5281
|
}
|
|
4052
5282
|
var ChildProcessSubagentResultController = class {
|
|
4053
|
-
constructor(options,
|
|
5283
|
+
constructor(options, resolve2, reject) {
|
|
4054
5284
|
this.options = options;
|
|
4055
|
-
this.resolve =
|
|
5285
|
+
this.resolve = resolve2;
|
|
4056
5286
|
this.reject = reject;
|
|
4057
5287
|
this.timeoutTimer = createTimeoutTimer(this.options.runtime, (error) => this.rejectOnce(error));
|
|
4058
5288
|
}
|
|
@@ -4160,8 +5390,8 @@ function formatEarlyExitMessage(code, signal) {
|
|
|
4160
5390
|
// src/subagents/git-worktree-isolation-adapter.ts
|
|
4161
5391
|
var import_node_child_process2 = require("child_process");
|
|
4162
5392
|
var import_node_crypto2 = require("crypto");
|
|
4163
|
-
var
|
|
4164
|
-
var
|
|
5393
|
+
var import_node_fs6 = require("fs");
|
|
5394
|
+
var import_node_path8 = require("path");
|
|
4165
5395
|
var import_agent_sdk6 = require("@robota-sdk/agent-sdk");
|
|
4166
5396
|
var WORKTREE_DIR = ".robota/worktrees";
|
|
4167
5397
|
var BRANCH_PREFIX = "robota";
|
|
@@ -4181,9 +5411,9 @@ var GitWorktreeIsolationAdapter = class {
|
|
|
4181
5411
|
const repoRoot = runGit(request.cwd, ["rev-parse", "--show-toplevel"]).trim();
|
|
4182
5412
|
const shortId = (0, import_node_crypto2.randomUUID)().slice(0, SHORT_ID_LENGTH);
|
|
4183
5413
|
const branchName = `${this.branchPrefix}/${request.jobId}-${shortId}`;
|
|
4184
|
-
const worktreeRoot = (0,
|
|
4185
|
-
const worktreePath = (0,
|
|
4186
|
-
(0,
|
|
5414
|
+
const worktreeRoot = (0, import_node_path8.join)(repoRoot, this.worktreeDir);
|
|
5415
|
+
const worktreePath = (0, import_node_path8.join)(worktreeRoot, `${request.jobId}-${shortId}`);
|
|
5416
|
+
(0, import_node_fs6.mkdirSync)(worktreeRoot, { recursive: true });
|
|
4187
5417
|
runGit(repoRoot, ["worktree", "add", "-b", branchName, worktreePath, "HEAD"]);
|
|
4188
5418
|
return { repoRoot, worktreePath, branchName };
|
|
4189
5419
|
}
|
|
@@ -4293,7 +5523,7 @@ var ChildProcessSubagentRunner = class {
|
|
|
4293
5523
|
}
|
|
4294
5524
|
resolveTranscriptPath(job) {
|
|
4295
5525
|
if (!this.logsDir) return void 0;
|
|
4296
|
-
return (0,
|
|
5526
|
+
return (0, import_node_path9.join)(this.logsDir, job.request.parentSessionId, "subagents", `${job.jobId}.jsonl`);
|
|
4297
5527
|
}
|
|
4298
5528
|
};
|
|
4299
5529
|
function resolveAgentDefinition(agentType, customRegistry) {
|
|
@@ -4319,19 +5549,20 @@ function createProviderProfile(providerConfig, deps, job) {
|
|
|
4319
5549
|
model: job.request.model ?? provider.model,
|
|
4320
5550
|
apiKey: provider.apiKey,
|
|
4321
5551
|
baseURL: provider.baseURL,
|
|
4322
|
-
timeout: provider.timeout
|
|
5552
|
+
timeout: provider.timeout,
|
|
5553
|
+
options: provider.options
|
|
4323
5554
|
};
|
|
4324
5555
|
}
|
|
4325
5556
|
function resolveDefaultWorkerPath() {
|
|
4326
5557
|
const entryPoint = process.argv[1] ?? "";
|
|
4327
|
-
const entryDir = entryPoint ? (0,
|
|
5558
|
+
const entryDir = entryPoint ? (0, import_node_path9.dirname)(entryPoint) : process.cwd();
|
|
4328
5559
|
const extension = entryPoint.endsWith(".ts") || entryPoint.endsWith(".tsx") ? ".ts" : ".js";
|
|
4329
5560
|
const candidates = [
|
|
4330
|
-
(0,
|
|
4331
|
-
(0,
|
|
5561
|
+
(0, import_node_path9.join)(entryDir, "subagents", `child-process-subagent-worker${extension}`),
|
|
5562
|
+
(0, import_node_path9.join)(entryDir, `child-process-subagent-worker${extension}`)
|
|
4332
5563
|
];
|
|
4333
5564
|
for (const candidate of candidates) {
|
|
4334
|
-
if ((0,
|
|
5565
|
+
if ((0, import_node_fs7.existsSync)(candidate)) {
|
|
4335
5566
|
return candidate;
|
|
4336
5567
|
}
|
|
4337
5568
|
}
|
|
@@ -4348,14 +5579,14 @@ function resolveDefaultExecArgv(workerPath) {
|
|
|
4348
5579
|
}
|
|
4349
5580
|
function readTranscriptLog(jobId, transcriptPath, cursor) {
|
|
4350
5581
|
const offset = cursor?.offset ?? 0;
|
|
4351
|
-
if (!(0,
|
|
5582
|
+
if (!(0, import_node_fs7.existsSync)(transcriptPath)) {
|
|
4352
5583
|
return {
|
|
4353
5584
|
taskId: jobId,
|
|
4354
5585
|
cursor,
|
|
4355
5586
|
lines: []
|
|
4356
5587
|
};
|
|
4357
5588
|
}
|
|
4358
|
-
const lines = (0,
|
|
5589
|
+
const lines = (0, import_node_fs7.readFileSync)(transcriptPath, "utf8").split(/\r?\n/).filter(Boolean);
|
|
4359
5590
|
const nextOffset = Math.min(offset + LOG_PAGE_SIZE2, lines.length);
|
|
4360
5591
|
return {
|
|
4361
5592
|
taskId: jobId,
|
|
@@ -4365,16 +5596,103 @@ function readTranscriptLog(jobId, transcriptPath, cursor) {
|
|
|
4365
5596
|
};
|
|
4366
5597
|
}
|
|
4367
5598
|
|
|
5599
|
+
// src/commands/statusline-command-module.ts
|
|
5600
|
+
var USAGE = [
|
|
5601
|
+
"Usage: /statusline on | off | reset | git on | git off",
|
|
5602
|
+
"Fields: model, context, permission mode, message count, session name, thinking state, git branch."
|
|
5603
|
+
].join("\n");
|
|
5604
|
+
function createStatusLineEntry() {
|
|
5605
|
+
return {
|
|
5606
|
+
name: "statusline",
|
|
5607
|
+
description: "Configure TUI status-line visibility and fields such as model, context, tokens, session, and git branch.",
|
|
5608
|
+
source: "cli",
|
|
5609
|
+
modelInvocable: false,
|
|
5610
|
+
argumentHint: "on | off | reset | git on | git off",
|
|
5611
|
+
subcommands: [
|
|
5612
|
+
{ name: "on", description: "Show the status line", source: "cli" },
|
|
5613
|
+
{ name: "off", description: "Hide the status line", source: "cli" },
|
|
5614
|
+
{ name: "reset", description: "Restore default status-line fields", source: "cli" },
|
|
5615
|
+
{ name: "git", description: "Show or hide git branch field", source: "cli" }
|
|
5616
|
+
]
|
|
5617
|
+
};
|
|
5618
|
+
}
|
|
5619
|
+
function parseStatusLineArgs(args) {
|
|
5620
|
+
const parts = args.trim().toLowerCase().split(/\s+/).filter((part) => part.length > 0);
|
|
5621
|
+
const [first, second] = parts;
|
|
5622
|
+
if (first === "on" && second === void 0) {
|
|
5623
|
+
return { success: true, message: "Status line enabled.", patch: { enabled: true } };
|
|
5624
|
+
}
|
|
5625
|
+
if (first === "off" && second === void 0) {
|
|
5626
|
+
return { success: true, message: "Status line disabled.", patch: { enabled: false } };
|
|
5627
|
+
}
|
|
5628
|
+
if (first === "reset" && second === void 0) {
|
|
5629
|
+
return {
|
|
5630
|
+
success: true,
|
|
5631
|
+
message: "Status line settings reset.",
|
|
5632
|
+
patch: { enabled: true, gitBranch: true }
|
|
5633
|
+
};
|
|
5634
|
+
}
|
|
5635
|
+
if (first === "git" && second === "on" && parts.length === 2) {
|
|
5636
|
+
return {
|
|
5637
|
+
success: true,
|
|
5638
|
+
message: "Status line git branch shown.",
|
|
5639
|
+
patch: { gitBranch: true }
|
|
5640
|
+
};
|
|
5641
|
+
}
|
|
5642
|
+
if (first === "git" && second === "off" && parts.length === 2) {
|
|
5643
|
+
return {
|
|
5644
|
+
success: true,
|
|
5645
|
+
message: "Status line git branch hidden.",
|
|
5646
|
+
patch: { gitBranch: false }
|
|
5647
|
+
};
|
|
5648
|
+
}
|
|
5649
|
+
return { success: false, message: USAGE };
|
|
5650
|
+
}
|
|
5651
|
+
function createStatusLineSystemCommand() {
|
|
5652
|
+
const entry = createStatusLineEntry();
|
|
5653
|
+
return {
|
|
5654
|
+
name: entry.name,
|
|
5655
|
+
description: entry.description,
|
|
5656
|
+
modelInvocable: false,
|
|
5657
|
+
userInvocable: true,
|
|
5658
|
+
argumentHint: entry.argumentHint,
|
|
5659
|
+
execute: (_session, args) => {
|
|
5660
|
+
const action = parseStatusLineArgs(args);
|
|
5661
|
+
if (!action.success) {
|
|
5662
|
+
return { success: false, message: action.message };
|
|
5663
|
+
}
|
|
5664
|
+
return {
|
|
5665
|
+
success: true,
|
|
5666
|
+
message: action.message,
|
|
5667
|
+
data: { statuslinePatch: action.patch }
|
|
5668
|
+
};
|
|
5669
|
+
}
|
|
5670
|
+
};
|
|
5671
|
+
}
|
|
5672
|
+
var StatusLineCommandSource = class {
|
|
5673
|
+
name = "cli-statusline";
|
|
5674
|
+
getCommands() {
|
|
5675
|
+
return [createStatusLineEntry()];
|
|
5676
|
+
}
|
|
5677
|
+
};
|
|
5678
|
+
function createStatusLineCommandModule() {
|
|
5679
|
+
return {
|
|
5680
|
+
name: "cli-statusline",
|
|
5681
|
+
commandSources: [new StatusLineCommandSource()],
|
|
5682
|
+
systemCommands: [createStatusLineSystemCommand()]
|
|
5683
|
+
};
|
|
5684
|
+
}
|
|
5685
|
+
|
|
4368
5686
|
// src/cli.ts
|
|
4369
5687
|
var import_meta = {};
|
|
4370
5688
|
function readVersion() {
|
|
4371
5689
|
try {
|
|
4372
5690
|
const thisFile = (0, import_node_url.fileURLToPath)(import_meta.url);
|
|
4373
|
-
const dir = (0,
|
|
4374
|
-
const candidates = [(0,
|
|
5691
|
+
const dir = (0, import_node_path10.dirname)(thisFile);
|
|
5692
|
+
const candidates = [(0, import_node_path10.join)(dir, "..", "..", "package.json"), (0, import_node_path10.join)(dir, "..", "package.json")];
|
|
4375
5693
|
for (const pkgPath of candidates) {
|
|
4376
5694
|
try {
|
|
4377
|
-
const raw = (0,
|
|
5695
|
+
const raw = (0, import_node_fs8.readFileSync)(pkgPath, "utf-8");
|
|
4378
5696
|
const pkg = JSON.parse(raw);
|
|
4379
5697
|
if (pkg.version !== void 0 && pkg.name !== void 0) {
|
|
4380
5698
|
return pkg.version;
|
|
@@ -4388,7 +5706,7 @@ function readVersion() {
|
|
|
4388
5706
|
}
|
|
4389
5707
|
}
|
|
4390
5708
|
function promptInput(label, masked = false) {
|
|
4391
|
-
return new Promise((
|
|
5709
|
+
return new Promise((resolve2) => {
|
|
4392
5710
|
process.stdout.write(label);
|
|
4393
5711
|
let input = "";
|
|
4394
5712
|
const stdin = process.stdin;
|
|
@@ -4403,7 +5721,7 @@ function promptInput(label, masked = false) {
|
|
|
4403
5721
|
stdin.setRawMode(wasRaw ?? false);
|
|
4404
5722
|
stdin.pause();
|
|
4405
5723
|
process.stdout.write("\n");
|
|
4406
|
-
|
|
5724
|
+
resolve2(input.trim());
|
|
4407
5725
|
return;
|
|
4408
5726
|
} else if (ch === "\x7F" || ch === "\b") {
|
|
4409
5727
|
if (input.length > 0) {
|
|
@@ -4433,8 +5751,21 @@ function resetConfig() {
|
|
|
4433
5751
|
}
|
|
4434
5752
|
async function startCli(options = {}) {
|
|
4435
5753
|
const args = parseCliArgs();
|
|
5754
|
+
const version = readVersion();
|
|
4436
5755
|
if (args.version) {
|
|
4437
|
-
process.stdout.write(`robota ${
|
|
5756
|
+
process.stdout.write(`robota ${version}
|
|
5757
|
+
`);
|
|
5758
|
+
return;
|
|
5759
|
+
}
|
|
5760
|
+
if (args.checkUpdate) {
|
|
5761
|
+
const result = await checkForCliUpdate({ currentVersion: version, force: true });
|
|
5762
|
+
const message = formatCliUpdateCheckMessage(result);
|
|
5763
|
+
if (result.status === "error") {
|
|
5764
|
+
process.stderr.write(`${message}
|
|
5765
|
+
`);
|
|
5766
|
+
process.exit(1);
|
|
5767
|
+
}
|
|
5768
|
+
process.stdout.write(`${message}
|
|
4438
5769
|
`);
|
|
4439
5770
|
return;
|
|
4440
5771
|
}
|
|
@@ -4444,6 +5775,11 @@ async function startCli(options = {}) {
|
|
|
4444
5775
|
}
|
|
4445
5776
|
const cwd = process.cwd();
|
|
4446
5777
|
const providerDefinitions = options.providerDefinitions ?? DEFAULT_PROVIDER_DEFINITIONS;
|
|
5778
|
+
const commandModules = [
|
|
5779
|
+
createStatusLineCommandModule(),
|
|
5780
|
+
...options.commandModules ?? []
|
|
5781
|
+
];
|
|
5782
|
+
const startupUpdateNoticePromise = shouldRunStartupCliUpdateCheck(args) ? getStartupCliUpdateNotice({ currentVersion: version }) : void 0;
|
|
4447
5783
|
if (args.configure) {
|
|
4448
5784
|
await runInteractiveProviderSetup(cwd, args, promptInput, providerDefinitions);
|
|
4449
5785
|
return;
|
|
@@ -4523,7 +5859,7 @@ ${args.jsonSchema}`
|
|
|
4523
5859
|
appendSystemPrompt,
|
|
4524
5860
|
backgroundTaskRunners,
|
|
4525
5861
|
subagentRunnerFactory,
|
|
4526
|
-
commandModules
|
|
5862
|
+
commandModules
|
|
4527
5863
|
});
|
|
4528
5864
|
const transport = (0, import_agent_transport_headless.createHeadlessTransport)({
|
|
4529
5865
|
outputFormat: args.outputFormat ?? "text",
|
|
@@ -4541,15 +5877,16 @@ ${args.jsonSchema}`
|
|
|
4541
5877
|
language: args.language,
|
|
4542
5878
|
permissionMode: args.permissionMode,
|
|
4543
5879
|
maxTurns: args.maxTurns,
|
|
4544
|
-
version
|
|
5880
|
+
version,
|
|
4545
5881
|
sessionStore,
|
|
4546
5882
|
resumeSessionId,
|
|
4547
5883
|
forkSession: args.forkSession,
|
|
4548
5884
|
sessionName: args.sessionName,
|
|
4549
5885
|
backgroundTaskRunners,
|
|
4550
5886
|
subagentRunnerFactory,
|
|
4551
|
-
commandModules
|
|
4552
|
-
providerDefinitions
|
|
5887
|
+
commandModules,
|
|
5888
|
+
providerDefinitions,
|
|
5889
|
+
startupUpdateNoticePromise
|
|
4553
5890
|
});
|
|
4554
5891
|
}
|
|
4555
5892
|
// Annotate the CommonJS export names for ESM import in node:
|