@robota-sdk/agent-cli 3.0.0-beta.63 → 3.0.0-beta.64

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.
Files changed (41) hide show
  1. package/README.md +3 -3
  2. package/dist/node/bin.d.ts +1 -1
  3. package/dist/node/bin.js +19 -2220
  4. package/dist/node/bin.js.map +1 -0
  5. package/dist/node/child-process-subagent-ipc--Vp2dk1v.js +2 -0
  6. package/dist/node/child-process-subagent-ipc--Vp2dk1v.js.map +1 -0
  7. package/dist/node/child-process-subagent-ipc-Aitv2i6E.cjs +1 -0
  8. package/dist/node/child-process-subagent-ipc-CEy8bLN6.cjs +1 -0
  9. package/dist/node/child-process-subagent-ipc-DVpVp43R.js +2 -0
  10. package/dist/node/child-process-subagent-ipc-DVpVp43R.js.map +1 -0
  11. package/dist/node/index.cjs +17 -2188
  12. package/dist/node/index.d.ts +30 -58
  13. package/dist/node/index.d.ts.map +1 -0
  14. package/dist/node/index.js +18 -2005
  15. package/dist/node/index.js.map +1 -0
  16. package/dist/node/subagents/child-process-subagent-worker.cjs +1 -249
  17. package/dist/node/subagents/child-process-subagent-worker.d.ts +1 -2
  18. package/dist/node/subagents/child-process-subagent-worker.js +2 -123
  19. package/dist/node/subagents/child-process-subagent-worker.js.map +1 -0
  20. package/package.json +12 -37
  21. package/README.ko.md +0 -297
  22. package/dist/node/chunk-6US65UBD.js +0 -5740
  23. package/dist/node/chunk-7D75HL37.js +0 -287
  24. package/dist/node/chunk-BENOH47A.js +0 -287
  25. package/dist/node/cli-N6TYREZG.js +0 -9
  26. package/dist/node/index.d.cts +0 -70
  27. package/dist/node/subagents/child-process-subagent-worker.d.cts +0 -2
  28. package/dist/web/assets/index-B2N-LjvM.css +0 -2
  29. package/dist/web/assets/index-B5tu6JSD.js +0 -37
  30. package/dist/web/assets/index-B8VHZ-wb.css +0 -2
  31. package/dist/web/assets/index-BSadCc8W.js +0 -37
  32. package/dist/web/assets/index-CIgpKdFz.js +0 -37
  33. package/dist/web/assets/index-CTx5Gdk4.js +0 -37
  34. package/dist/web/assets/index-CUJJsgxp.js +0 -37
  35. package/dist/web/assets/index-Ck-mdN6u.css +0 -2
  36. package/dist/web/assets/index-CqPdNxqk.css +0 -2
  37. package/dist/web/assets/index-CyJ7yl0E.js +0 -37
  38. package/dist/web/assets/index-DFBoQ601.css +0 -2
  39. package/dist/web/assets/index-Dc3tp-Ci.js +0 -37
  40. package/dist/web/assets/index-DtSuwV8l.js +0 -37
  41. package/dist/web/index.html +0 -13
package/dist/node/bin.js CHANGED
@@ -1,43 +1,5 @@
1
1
  #!/usr/bin/env node
2
-
3
- // src/cli.ts
4
- import { readFileSync as readFileSync7 } from "fs";
5
- import { join as join10, dirname as dirname5, resolve as resolve2 } from "path";
6
- import { fileURLToPath } from "url";
7
- import { createAgentCommandModule } from "@robota-sdk/agent-command-agent";
8
- import { createBackgroundCommandModule } from "@robota-sdk/agent-command-background";
9
- import { createProviderCommandModule } from "@robota-sdk/agent-command-provider";
10
- import { createCompactCommandModule } from "@robota-sdk/agent-command-compact";
11
- import { createContextCommandModule } from "@robota-sdk/agent-command-context";
12
- import { createExitCommandModule } from "@robota-sdk/agent-command-exit";
13
- import { createHelpCommandModule } from "@robota-sdk/agent-command-help";
14
- import { createLanguageCommandModule } from "@robota-sdk/agent-command-language";
15
- import { createMemoryCommandModule } from "@robota-sdk/agent-command-memory";
16
- import { createModelCommandModule } from "@robota-sdk/agent-command-model";
17
- import { createPermissionsCommandModule } from "@robota-sdk/agent-command-permissions";
18
- import { createPluginCommandModule } from "@robota-sdk/agent-command-plugin";
19
- import { createResetCommandModule } from "@robota-sdk/agent-command-reset";
20
- import { createRewindCommandModule } from "@robota-sdk/agent-command-rewind";
21
- import { createStatusLineCommandModule } from "@robota-sdk/agent-command-statusline";
22
- import { createSessionCommandModule } from "@robota-sdk/agent-command-session";
23
- import { createSkillsCommandModule } from "@robota-sdk/agent-command-skills";
24
- import { createUserLocalCommandModule } from "@robota-sdk/agent-command-user-local";
25
- import { createModeCommandModule } from "@robota-sdk/agent-command-mode";
26
- import { createSettingsCommandModule } from "@robota-sdk/agent-command-settings";
27
- import {
28
- InteractiveSession,
29
- createProjectSessionStore,
30
- projectPaths,
31
- resolveLatestSessionId,
32
- resolveSessionIdByIdOrName
33
- } from "@robota-sdk/agent-sdk";
34
-
35
- // src/utils/cli-args.ts
36
- import { parseArgs } from "util";
37
- var VALID_MODES = ["plan", "default", "acceptEdits", "bypassPermissions"];
38
- var VALID_OUTPUT_FORMATS = ["text", "json", "stream-json"];
39
- function printHelp() {
40
- process.stdout.write(`
2
+ import{execSync as e,fork as t}from"node:child_process";import{existsSync as n,lstatSync as r,mkdirSync as i,readFileSync as a,unlinkSync as o,writeFileSync as s}from"node:fs";import{dirname as c,isAbsolute as l,join as u,resolve as d}from"node:path";import{fileURLToPath as f}from"node:url";import{BundlePluginInstaller as p,BundlePluginLoader as m,DEFAULT_STATUS_LINE_COMMAND_SETTINGS as h,InteractiveSession as g,MarketplaceClient as _,PluginCommandSource as v,PluginSettingsStore as y,buildProviderSetupPatch as ee,checkSettingsDocument as b,createProjectSessionStore as te,findProviderDefinition as ne,getBuiltInAgent as re,mergeProviderPatch as ie,projectPaths as ae,readMergedProviderSettingsFromPaths as oe,readMergedProviderSettingsFromPaths as se,resolveActiveProvider as ce,resolveLatestSessionId as le,resolveSessionIdByIdOrName as ue,setCurrentProvider as de}from"@robota-sdk/agent-framework";import{createAgentCommandModule as fe,createBackgroundCommandModule as pe,createCompactCommandModule as me,createContextCommandModule as he,createExitCommandModule as ge,createHelpCommandModule as _e,createLanguageCommandModule as ve,createMemoryCommandModule as ye,createModeCommandModule as be,createModelCommandModule as xe,createPermissionsCommandModule as Se,createPluginCommandModule as Ce,createProviderCommandModule as we,createResetCommandModule as Te,createRewindCommandModule as Ee,createSessionCommandModule as De,createSettingsCommandModule as Oe,createSkillsCommandModule as ke,createStatusLineCommandModule as Ae,createUserLocalCommandModule as je,executeUserLocalDirectCommand as Me,formatProviderSetupSelectionPrompt as Ne,resolveProviderSetupSelection as Pe,runProviderSetupPromptFlow as Fe}from"@robota-sdk/agent-command";import{parseArgs as Ie}from"node:util";import{BackgroundTaskError as x,createBackgroundTaskLogPage as Le,createDefaultBackgroundTaskRunners as Re,createGitWorktreeIsolationAdapter as ze,createProviderFromConfig as Be,createWorktreeSubagentRunner as Ve}from"@robota-sdk/agent-executor";import{createAnthropicProviderDefinition as He}from"@robota-sdk/agent-provider/anthropic";import{createDeepSeekProviderDefinition as Ue}from"@robota-sdk/agent-provider/deepseek";import{createGemmaProviderDefinition as We}from"@robota-sdk/agent-provider/gemma";import{createGeminiProviderDefinition as Ge}from"@robota-sdk/agent-provider/gemini";import{createOpenAIProviderDefinition as Ke}from"@robota-sdk/agent-provider/openai";import{createQwenProviderDefinition as qe}from"@robota-sdk/agent-provider/qwen";import{formatSupportedProviderTypes as Je}from"@robota-sdk/agent-core";import{createHeadlessTransport as Ye}from"@robota-sdk/agent-transport/headless";import{WsTransport as Xe}from"@robota-sdk/agent-transport/ws";import{TuiTransport as Ze}from"@robota-sdk/agent-transport/tui";import{homedir as S}from"node:os";const C=[`plan`,`default`,`acceptEdits`,`bypassPermissions`],w=[`text`,`json`,`stream-json`];function Qe(){process.stdout.write(`
41
3
  Usage: robota [options] [-p <prompt>]
42
4
 
43
5
  Options:
@@ -65,2184 +27,21 @@ Examples:
65
27
  robota -p "Hello" Print mode: send prompt and exit
66
28
  robota -p "Hello" --output-format json
67
29
  robota --continue Resume the last session
68
- `);
69
- }
70
- function parseOutputFormat(raw) {
71
- if (raw === void 0) return void 0;
72
- if (!VALID_OUTPUT_FORMATS.includes(raw)) {
73
- process.stderr.write(
74
- `Invalid --output-format "${raw}". Valid: ${VALID_OUTPUT_FORMATS.join(" | ")}
75
- `
76
- );
77
- process.exit(1);
78
- }
79
- return raw;
80
- }
81
- function parsePermissionMode(raw) {
82
- if (raw === void 0) return void 0;
83
- if (!VALID_MODES.includes(raw)) {
84
- process.stderr.write(`Invalid --permission-mode "${raw}". Valid: ${VALID_MODES.join(" | ")}
85
- `);
86
- process.exit(1);
87
- }
88
- return raw;
89
- }
90
- function parseMaxTurns(raw) {
91
- if (raw === void 0) return void 0;
92
- const n = parseInt(raw, 10);
93
- if (isNaN(n) || n <= 0) {
94
- process.stderr.write(`Invalid --max-turns "${raw}". Must be a positive integer.
95
- `);
96
- process.exit(1);
97
- }
98
- return n;
99
- }
100
- function parseCliArgs() {
101
- const { values, positionals } = parseArgs({
102
- allowPositionals: true,
103
- options: {
104
- help: { type: "boolean", short: "h", default: false },
105
- p: { type: "boolean", short: "p", default: false },
106
- continue: { type: "boolean", short: "c", default: false },
107
- resume: { type: "string", short: "r" },
108
- model: { type: "string" },
109
- language: { type: "string" },
110
- "permission-mode": { type: "string" },
111
- "max-turns": { type: "string" },
112
- "fork-session": { type: "boolean", default: false },
113
- name: { type: "string", short: "n" },
114
- "output-format": { type: "string" },
115
- format: { type: "string" },
116
- summary: { type: "string" },
117
- source: { type: "string" },
118
- "system-prompt": { type: "string" },
119
- "append-system-prompt": { type: "string" },
120
- "task-file": { type: "string" },
121
- version: { type: "boolean", default: false },
122
- reset: { type: "boolean", default: false },
123
- bare: { type: "boolean", default: false },
124
- "allowed-tools": { type: "string" },
125
- "no-session-persistence": { type: "boolean", default: false },
126
- "json-schema": { type: "string" },
127
- configure: { type: "boolean", default: false },
128
- "configure-provider": { type: "string" },
129
- provider: { type: "string" },
130
- type: { type: "string" },
131
- "base-url": { type: "string" },
132
- "api-key": { type: "string" },
133
- "api-key-env": { type: "string" },
134
- "set-current": { type: "boolean", default: false },
135
- "settings-scope": { type: "string" },
136
- "check-update": { type: "boolean", default: false },
137
- "disable-update-check": { type: "boolean", default: false }
138
- }
139
- });
140
- return {
141
- positional: positionals,
142
- help: values["help"] ?? false,
143
- printMode: values["p"] ?? false,
144
- continueMode: values["continue"] ?? false,
145
- resumeId: values["resume"],
146
- model: values["model"],
147
- language: values["language"],
148
- permissionMode: parsePermissionMode(values["permission-mode"]),
149
- maxTurns: parseMaxTurns(values["max-turns"]),
150
- forkSession: values["fork-session"] ?? false,
151
- sessionName: values["name"],
152
- outputFormat: parseOutputFormat(values["output-format"]),
153
- format: values["format"],
154
- summary: values["summary"],
155
- source: values["source"],
156
- systemPrompt: values["system-prompt"],
157
- appendSystemPrompt: values["append-system-prompt"],
158
- taskFile: values["task-file"],
159
- version: values["version"] ?? false,
160
- reset: values["reset"] ?? false,
161
- bare: values["bare"] ?? false,
162
- allowedTools: values["allowed-tools"],
163
- noSessionPersistence: values["no-session-persistence"] ?? false,
164
- jsonSchema: values["json-schema"],
165
- configure: values["configure"] ?? false,
166
- configureProvider: values["configure-provider"],
167
- provider: values["provider"],
168
- providerType: values["type"],
169
- baseURL: values["base-url"],
170
- apiKey: values["api-key"],
171
- apiKeyEnv: values["api-key-env"],
172
- setCurrent: values["set-current"] ?? false,
173
- settingsScope: values["settings-scope"],
174
- checkUpdate: values["check-update"] ?? false,
175
- disableUpdateCheck: values["disable-update-check"] ?? false
176
- };
177
- }
178
-
179
- // src/utils/settings-io.ts
180
- import { existsSync, readFileSync, writeFileSync, mkdirSync, unlinkSync } from "fs";
181
- import { join, dirname } from "path";
182
- function getUserSettingsPath() {
183
- const home = process.env.HOME ?? process.env.USERPROFILE ?? "/";
184
- return join(home, ".robota", "settings.json");
185
- }
186
- function readSettings(path) {
187
- if (!existsSync(path)) return {};
188
- const raw = readFileSync(path, "utf8");
189
- try {
190
- return JSON.parse(raw);
191
- } catch {
192
- process.stderr.write(`Warning: corrupt settings file at ${path}, resetting to defaults
193
- `);
194
- return {};
195
- }
196
- }
197
- function writeSettings(path, settings) {
198
- mkdirSync(dirname(path), { recursive: true });
199
- writeFileSync(path, JSON.stringify(settings, null, 2) + "\n", "utf8");
200
- }
201
- function deleteSettings(path) {
202
- if (existsSync(path)) {
203
- unlinkSync(path);
204
- return true;
205
- }
206
- return false;
207
- }
208
-
209
- // src/utils/provider-factory.ts
210
- import { readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
211
- import { join as join2 } from "path";
212
-
213
- // src/utils/provider-default-definitions.ts
214
- import { createAnthropicProviderDefinition } from "@robota-sdk/agent-provider-anthropic";
215
- import { createDeepSeekProviderDefinition } from "@robota-sdk/agent-provider-deepseek";
216
- import { createGemmaProviderDefinition } from "@robota-sdk/agent-provider-gemma";
217
- import { createGeminiProviderDefinition } from "@robota-sdk/agent-provider-gemini";
218
- import { createOpenAIProviderDefinition } from "@robota-sdk/agent-provider-openai";
219
- import { createQwenProviderDefinition } from "@robota-sdk/agent-provider-qwen";
220
- var DEFAULT_PROVIDER_DEFINITIONS = [
221
- createAnthropicProviderDefinition(),
222
- createOpenAIProviderDefinition(),
223
- createGeminiProviderDefinition(),
224
- createGemmaProviderDefinition(),
225
- createQwenProviderDefinition(),
226
- createDeepSeekProviderDefinition()
227
- ];
228
-
229
- // src/utils/provider-definition.ts
230
- import {
231
- findProviderDefinition,
232
- formatSupportedProviderTypes,
233
- getProviderCredentialRequirement
234
- } from "@robota-sdk/agent-core";
235
-
236
- // src/utils/env-ref.ts
237
- import {
238
- formatEnvReference,
239
- hasUsableSecretReference,
240
- isEnvReference,
241
- resolveEnvReference
242
- } from "@robota-sdk/agent-sdk";
243
-
244
- // src/utils/provider-factory.ts
245
- function readProviderSettings(cwd, options = {}) {
246
- const merged = readMergedProviderSettings(cwd);
247
- const providerConfig = resolveActiveProvider(
248
- merged,
249
- options.providerOverride,
250
- getProviderDefinitions(options)
251
- );
252
- if (providerConfig !== void 0) {
253
- return providerConfig;
254
- }
255
- throw new Error("No provider configuration found. Run `robota` to set up.");
256
- }
257
- function readMergedProviderSettings(cwd) {
258
- return readMergedProviderSettingsFromPaths(getProviderSettingsPaths(cwd));
259
- }
260
- function getProviderSettingsPaths(cwd) {
261
- const userHome = getUserHome();
262
- return [
263
- join2(userHome, ".robota", "settings.json"),
264
- join2(userHome, ".claude", "settings.json"),
265
- join2(cwd, ".robota", "settings.json"),
266
- join2(cwd, ".robota", "settings.local.json"),
267
- join2(cwd, ".claude", "settings.json"),
268
- join2(cwd, ".claude", "settings.local.json")
269
- ];
270
- }
271
- function getUserHome() {
272
- return process.env.HOME ?? process.env.USERPROFILE ?? "/";
273
- }
274
- function readMergedProviderSettingsFromPaths(paths) {
275
- return paths.reduce((settings, filePath) => {
276
- const parsed = readSettingsFile(filePath);
277
- if (parsed === void 0) {
278
- return settings;
279
- }
280
- return mergeSettings(settings, parsed);
281
- }, {});
282
- }
283
- function readSettingsFile(filePath) {
284
- if (!existsSync2(filePath)) {
285
- return void 0;
286
- }
287
- try {
288
- const raw = readFileSync2(filePath, "utf8");
289
- return JSON.parse(raw);
290
- } catch {
291
- return void 0;
292
- }
293
- }
294
- function mergeSettings(base, override) {
295
- return {
296
- ...base,
297
- ...override,
298
- provider: base.provider !== void 0 || override.provider !== void 0 ? { ...base.provider, ...override.provider } : void 0,
299
- providers: base.providers !== void 0 || override.providers !== void 0 ? mergeProviders(base.providers, override.providers) : void 0
300
- };
301
- }
302
- function mergeProviders(base, override) {
303
- const result = { ...base ?? {} };
304
- for (const [name, profile] of Object.entries(override ?? {})) {
305
- result[name] = { ...result[name], ...profile };
306
- }
307
- return result;
308
- }
309
- function resolveActiveProvider(settings, providerOverride, providerDefinitions = DEFAULT_PROVIDER_DEFINITIONS) {
310
- const activeProvider = providerOverride ?? settings.currentProvider;
311
- if (activeProvider !== void 0) {
312
- const profile = settings.providers?.[activeProvider];
313
- if (profile === void 0) {
314
- throw new Error(`Provider profile "${activeProvider}" was not found in providers`);
315
- }
316
- if (!profile.type) {
317
- throw new Error(`Provider profile "${activeProvider}" is missing type`);
318
- }
319
- return normalizeProviderConfig(
320
- {
321
- name: profile.type,
322
- model: profile.model,
323
- apiKey: profile.apiKey,
324
- baseURL: profile.baseURL,
325
- timeout: profile.timeout,
326
- options: profile.options
327
- },
328
- providerDefinitions
329
- );
330
- }
331
- const provider = settings.provider;
332
- if (provider?.name) {
333
- return normalizeProviderConfig(
334
- {
335
- name: provider.name,
336
- model: provider.model,
337
- apiKey: provider.apiKey,
338
- baseURL: provider.baseURL,
339
- timeout: provider.timeout,
340
- options: provider.options
341
- },
342
- providerDefinitions
343
- );
344
- }
345
- return void 0;
346
- }
347
- function normalizeProviderConfig(settings, providerDefinitions) {
348
- const defaults = findProviderDefinition(providerDefinitions, settings.name)?.defaults ?? {};
349
- const model = settings.model ?? defaults.model;
350
- if (!model) {
351
- throw new Error(`Provider ${settings.name} requires model`);
352
- }
353
- const apiKeyReference = settings.apiKey ?? defaults.apiKey;
354
- const options = settings.options ?? defaults.options;
355
- return {
356
- name: settings.name,
357
- model,
358
- apiKey: apiKeyReference !== void 0 ? resolveEnvReference(apiKeyReference) : void 0,
359
- baseURL: settings.baseURL ?? defaults.baseURL,
360
- timeout: settings.timeout,
361
- ...options !== void 0 && { options }
362
- };
363
- }
364
- function createProviderFromConfig(settings, providerDefinitions) {
365
- const definition = findProviderDefinition(providerDefinitions, settings.name);
366
- if (definition === void 0) {
367
- throw new Error(
368
- `Unknown provider: ${settings.name}. Currently supported: ${formatSupportedProviderTypes(providerDefinitions)}`
369
- );
370
- }
371
- const credentialRequirement = getProviderCredentialRequirement(definition);
372
- if (credentialRequirement !== void 0 && !hasRequiredProviderCredential(settings, credentialRequirement)) {
373
- throw new Error(
374
- `Provider ${settings.name} requires ${formatCredentialRequirement(credentialRequirement)}`
375
- );
376
- }
377
- return definition.createProvider(settings);
378
- }
379
- function createProviderFromSettings(cwd, modelOverride, options = {}) {
380
- const providerDefinitions = getProviderDefinitions(options);
381
- const settings = readProviderSettings(cwd, { ...options, providerDefinitions });
382
- const model = modelOverride ?? settings.model;
383
- return createProviderFromConfig({ ...settings, model }, providerDefinitions);
384
- }
385
- function hasRequiredProviderCredential(settings, requirement) {
386
- return requirement.anyOf.some((field) => hasProviderCredentialValue(settings, field));
387
- }
388
- function hasProviderCredentialValue(settings, field) {
389
- const value = settings[field];
390
- return value !== void 0 && value.length > 0;
391
- }
392
- function formatCredentialRequirement(requirement) {
393
- return requirement.anyOf.join(" or ");
394
- }
395
- function getProviderDefinitions(options) {
396
- return options.providerDefinitions ?? DEFAULT_PROVIDER_DEFINITIONS;
397
- }
398
-
399
- // src/utils/provider-setup.ts
400
- import { join as join3 } from "path";
401
-
402
- // src/utils/settings-check.ts
403
- import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
404
- function checkSettingsDocument(settings, providerDefinitions = []) {
405
- return hasUsableProviderConfig(settings, providerDefinitions) ? "valid" : "incomplete";
406
- }
407
- function hasUsableProviderConfig(settings, providerDefinitions) {
408
- if (typeof settings.currentProvider === "string") {
409
- const profile = settings.providers?.[settings.currentProvider];
410
- return isUsableProviderProfile(profile?.type, profile, providerDefinitions);
411
- }
412
- if (settings.provider && isUsableProviderProfile(settings.provider.name, settings.provider, providerDefinitions)) {
413
- return true;
414
- }
415
- return false;
416
- }
417
- function isUsableProviderProfile(type, profile, providerDefinitions) {
418
- if (!profile) {
419
- return false;
420
- }
421
- if (!type) {
422
- return hasUsableSecretReference(profile.apiKey);
423
- }
424
- const definition = findProviderDefinition(providerDefinitions, type);
425
- if (definition === void 0) {
426
- return false;
427
- }
428
- const credentialRequirement = getProviderCredentialRequirement(definition);
429
- if (credentialRequirement === void 0) {
430
- return true;
431
- }
432
- return hasUsableRequiredProviderCredential(profile, definition, credentialRequirement);
433
- }
434
- function hasUsableRequiredProviderCredential(profile, definition, requirement) {
435
- return requirement.anyOf.some(
436
- (field) => hasUsableSecretReference(resolveProviderCredentialValue(field, profile, definition))
437
- );
438
- }
439
- function resolveProviderCredentialValue(field, profile, definition) {
440
- return profile[field] ?? definition.defaults?.[field];
441
- }
442
-
443
- // src/utils/provider-settings.ts
444
- import {
445
- buildProviderProfile,
446
- buildProviderSetupPatch,
447
- deleteProviderProfile,
448
- mergeProviderPatch,
449
- setCurrentProvider,
450
- upsertProviderProfile,
451
- validateProviderProfile
452
- } from "@robota-sdk/agent-sdk";
453
-
454
- // src/utils/provider-configuration.ts
455
- function resolveProviderSettingsWriteTargetPath(cwd, options = {}) {
456
- const settingsPaths = options.settingsPaths ?? getProviderSettingsPaths(cwd);
457
- const targetPath = findLastPathWithCurrentProvider(settingsPaths) ?? settingsPaths[0];
458
- if (targetPath === void 0) {
459
- throw new Error("No settings path available for provider update");
460
- }
461
- return targetPath;
462
- }
463
- function readProviderDocument(settingsPath) {
464
- return readSettings(settingsPath);
465
- }
466
- function applyProviderConfiguration(settingsPath, input, options = {}) {
467
- const settings = readProviderDocument(settingsPath);
468
- const patch = buildProviderSetupPatch(input, options);
469
- const next = mergeProviderPatch(settings, patch);
470
- writeSettings(settingsPath, next);
471
- return next;
472
- }
473
- function applyProviderSwitch(settingsPath, profileName, options = {}) {
474
- const settings = readProviderDocument(settingsPath);
475
- const hasLocalProfile = settings.providers?.[profileName] !== void 0;
476
- const hasKnownProfile = options.knownProviders?.[profileName] !== void 0;
477
- const next = hasLocalProfile || hasKnownProfile ? { ...settings, currentProvider: profileName } : setCurrentProvider(settings, profileName);
478
- writeSettings(settingsPath, next);
479
- return next;
480
- }
481
- function applyActiveModelChange(cwd, modelId, options = {}) {
482
- const settingsPaths = options.settingsPaths ?? getProviderSettingsPaths(cwd);
483
- const merged = readMergedProviderSettingsFromPaths(settingsPaths);
484
- const activeProfileName = options.providerOverride ?? merged.currentProvider;
485
- if (typeof activeProfileName !== "string") {
486
- throw new Error(
487
- 'Cannot update model: no active provider profile. Set "currentProvider" in settings.'
488
- );
489
- }
490
- return updateActiveProviderProfileModel(settingsPaths, activeProfileName, modelId);
491
- }
492
- function updateActiveProviderProfileModel(settingsPaths, profileName, modelId) {
493
- const settingsPath = findLastPathWithProviderProfile(settingsPaths, profileName) ?? settingsPaths[0];
494
- if (settingsPath === void 0) {
495
- throw new Error("No settings path available for model update");
496
- }
497
- const settings = readProviderDocument(settingsPath);
498
- const providers = settings.providers ?? {};
499
- const existing = providers[profileName] ?? {};
500
- const next = {
501
- ...settings,
502
- providers: {
503
- ...providers,
504
- [profileName]: {
505
- ...existing,
506
- model: modelId
507
- }
508
- }
509
- };
510
- writeSettings(settingsPath, next);
511
- return { settingsPath, settings: next, profileName };
512
- }
513
- function findLastPathWithProviderProfile(settingsPaths, profileName) {
514
- for (let index = settingsPaths.length - 1; index >= 0; index -= 1) {
515
- const settingsPath = settingsPaths[index];
516
- if (settingsPath === void 0) continue;
517
- const settings = readProviderDocument(settingsPath);
518
- if (settings.providers?.[profileName] !== void 0) return settingsPath;
519
- }
520
- return void 0;
521
- }
522
- function findLastPathWithCurrentProvider(settingsPaths) {
523
- for (let index = settingsPaths.length - 1; index >= 0; index -= 1) {
524
- const settingsPath = settingsPaths[index];
525
- if (settingsPath === void 0) continue;
526
- const settings = readProviderDocument(settingsPath);
527
- if (settings.currentProvider !== void 0) return settingsPath;
528
- }
529
- return void 0;
530
- }
531
-
532
- // src/utils/provider-setup-flow.ts
533
- import {
534
- createProviderSetupFlow,
535
- formatProviderSetupChoiceLabel,
536
- formatProviderSetupHelpLinks,
537
- formatProviderSetupPromptLabel,
538
- formatProviderSetupSelectionPrompt,
539
- getProviderSetupStep,
540
- resolveProviderSetupSelection,
541
- runProviderSetupPromptFlow,
542
- submitProviderSetupValue,
543
- validateProviderSetupValue
544
- } from "@robota-sdk/agent-sdk";
545
-
546
- // src/utils/provider-setup.ts
547
- function getSettingsPathForScope(cwd, scope) {
548
- if (scope === void 0 || scope === "user") {
549
- return getUserSettingsPath();
550
- }
551
- if (scope === "project-local") {
552
- return join3(cwd, ".robota", "settings.local.json");
553
- }
554
- throw new Error(`Invalid --settings-scope "${scope}". Valid: user | project-local`);
555
- }
556
- function handleProviderConfigurationArgs(cwd, args, providerDefinitions = DEFAULT_PROVIDER_DEFINITIONS) {
557
- const settingsPath = getSettingsPathForScope(cwd, args.settingsScope);
558
- if (args.configureProvider) {
559
- applyProviderConfiguration(settingsPath, buildSetupInputFromArgs(args), {
560
- providerDefinitions
561
- });
562
- process.stdout.write(`Provider profile saved to ${settingsPath}
563
- `);
564
- return !args.printMode && args.positional.length === 0;
565
- }
566
- if (args.provider && args.setCurrent) {
567
- const switchSettingsPath = args.settingsScope === void 0 ? resolveProviderSettingsWriteTargetPath(cwd) : settingsPath;
568
- applyProviderSwitch(switchSettingsPath, args.provider, {
569
- knownProviders: readMergedProviderSettings(cwd).providers
570
- });
571
- process.stdout.write(`Current provider set to ${args.provider}
572
- `);
573
- return !args.printMode && args.positional.length === 0;
574
- }
575
- return false;
576
- }
577
- async function ensureConfig(cwd, args, promptInput2, providerDefinitions = DEFAULT_PROVIDER_DEFINITIONS) {
578
- const merged = readMergedProviderSettings(cwd);
579
- const selectedSettings = args.provider !== void 0 ? { ...merged, currentProvider: args.provider } : merged;
580
- if (checkSettingsDocument(selectedSettings, providerDefinitions) === "valid") {
581
- return;
582
- }
583
- if (!isInteractiveTerminal()) {
584
- throw new Error(formatMissingProviderConfigMessage(providerDefinitions));
585
- }
586
- await runInteractiveProviderSetup(
587
- cwd,
588
- selectStartupSetupArgs(cwd, args),
589
- promptInput2,
590
- providerDefinitions
591
- );
592
- const updated = readMergedProviderSettings(cwd);
593
- const updatedSettings = args.provider !== void 0 ? { ...updated, currentProvider: args.provider } : updated;
594
- if (checkSettingsDocument(updatedSettings, providerDefinitions) !== "valid") {
595
- throw new Error(formatMissingProviderConfigMessage(providerDefinitions));
596
- }
597
- }
598
- async function runInteractiveProviderSetup(cwd, args, promptInput2, providerDefinitions = DEFAULT_PROVIDER_DEFINITIONS) {
599
- const providerChoice = await promptInput2(formatProviderSetupSelectionPrompt(providerDefinitions));
600
- const type = resolveProviderSetupSelection(providerChoice, providerDefinitions);
601
- const settingsPath = getSettingsPathForScope(cwd, args.settingsScope);
602
- const input = await runProviderSetupPromptFlow(type, promptInput2, providerDefinitions, {
603
- existingProfileNames: Object.keys(readMergedProviderSettings(cwd).providers ?? {})
604
- });
605
- applyProviderConfiguration(settingsPath, input, {
606
- providerDefinitions
607
- });
608
- const language = await promptInput2(" Response language (ko/en/ja/zh, default: en): ");
609
- if (language) {
610
- const settings = readSettings(settingsPath);
611
- settings.language = language;
612
- writeSettings(settingsPath, settings);
613
- }
614
- process.stdout.write(`
615
- Config saved to ${settingsPath}
616
-
617
- `);
618
- }
619
- function buildSetupInputFromArgs(args) {
620
- const type = args.providerType ?? args.configureProvider;
621
- if (!args.configureProvider || !type) {
622
- throw new Error("--configure-provider requires a provider profile and --type");
623
- }
624
- return {
625
- profile: args.configureProvider,
626
- type,
627
- ...args.model !== void 0 && { model: args.model },
628
- ...args.apiKey !== void 0 && { apiKey: args.apiKey },
629
- ...args.apiKeyEnv !== void 0 && { apiKeyEnv: args.apiKeyEnv },
630
- ...args.baseURL !== void 0 && { baseURL: args.baseURL },
631
- setCurrent: args.setCurrent
632
- };
633
- }
634
- function selectStartupSetupArgs(cwd, args) {
635
- if (args.settingsScope !== void 0 || args.provider !== void 0) {
636
- return args;
637
- }
638
- const currentProviderPath = findHighestPriorityCurrentProviderPath(getProviderSettingsPaths(cwd));
639
- if (currentProviderPath === void 0) {
640
- return args;
641
- }
642
- const projectSettingsPath = join3(cwd, ".robota", "settings.json");
643
- const projectLocalSettingsPath = join3(cwd, ".robota", "settings.local.json");
644
- if (currentProviderPath === projectSettingsPath || currentProviderPath === projectLocalSettingsPath) {
645
- return { ...args, settingsScope: "project-local" };
646
- }
647
- return args;
648
- }
649
- function findHighestPriorityCurrentProviderPath(settingsPaths) {
650
- for (let index = settingsPaths.length - 1; index >= 0; index -= 1) {
651
- const settingsPath = settingsPaths[index];
652
- if (settingsPath === void 0) continue;
653
- const settings = readSettings(settingsPath);
654
- if (typeof settings.currentProvider === "string") {
655
- return settingsPath;
656
- }
657
- }
658
- return void 0;
659
- }
660
- function isInteractiveTerminal() {
661
- return process.stdin.isTTY === true && process.stdout.isTTY === true;
662
- }
663
- function formatMissingProviderConfigMessage(providerDefinitions = DEFAULT_PROVIDER_DEFINITIONS) {
664
- return [
665
- "No provider configuration found.",
666
- "Run `robota --configure` in an interactive terminal, or configure a provider:",
667
- `Supported providers: ${formatSupportedProviderTypes(providerDefinitions)}`,
668
- ...providerDefinitions.map(formatConfigureProviderExample)
669
- ].join("\n");
670
- }
671
- function formatConfigureProviderExample(definition) {
672
- const flags = [
673
- `robota --configure-provider ${definition.type}`,
674
- `--type ${definition.type}`,
675
- ...definition.defaults?.baseURL !== void 0 ? ["--base-url <url>"] : [],
676
- "--model <model>",
677
- ...definition.requiresApiKey === true ? ["--api-key-env <ENV_NAME>"] : [],
678
- "--set-current"
679
- ];
680
- return ` ${flags.join(" ")}`;
681
- }
682
-
683
- // src/cli.ts
684
- import { createHeadlessTransport } from "@robota-sdk/agent-transport-headless";
685
- import { WsTransport } from "@robota-sdk/agent-transport-ws";
686
- import { TuiTransport } from "@robota-sdk/agent-transport-tui";
687
-
688
- // src/transports/transport-registry.ts
689
- var TransportRegistry = class {
690
- entries = /* @__PURE__ */ new Map();
691
- settingsPath;
692
- constructor(settingsPath) {
693
- this.settingsPath = settingsPath;
694
- }
695
- register(transport) {
696
- this.entries.set(transport.name, transport);
697
- }
698
- getAll() {
699
- const saved = this.readTransportSettings();
700
- return Array.from(this.entries.values()).map((transport) => ({
701
- transport,
702
- config: this.resolveConfig(transport, saved[transport.name])
703
- }));
704
- }
705
- getEnabled() {
706
- return this.getAll().filter((e) => e.config.enabled).map((e) => e.transport);
707
- }
708
- async setEnabled(name, enabled) {
709
- const settings = readSettings(this.settingsPath);
710
- const transports = settings.transports ?? {};
711
- const entry = transports[name] ?? {};
712
- transports[name] = { ...entry, enabled };
713
- settings.transports = transports;
714
- writeSettings(this.settingsPath, settings);
715
- }
716
- async setOptions(name, options) {
717
- const settings = readSettings(this.settingsPath);
718
- const transports = settings.transports ?? {};
719
- const entry = transports[name] ?? {};
720
- transports[name] = { ...entry, options };
721
- settings.transports = transports;
722
- writeSettings(this.settingsPath, settings);
723
- }
724
- async startAll(session) {
725
- const enabled = this.getEnabled();
726
- for (const transport of enabled) {
727
- transport.attach(session);
728
- await transport.start();
729
- }
730
- }
731
- async stopAll() {
732
- for (const transport of this.entries.values()) {
733
- await transport.stop();
734
- }
735
- }
736
- resolveConfig(transport, saved) {
737
- const enabled = saved?.enabled ?? transport.defaultEnabled;
738
- const options = saved?.options ?? {};
739
- return { enabled, options };
740
- }
741
- readTransportSettings() {
742
- const settings = readSettings(this.settingsPath);
743
- const raw = settings.transports;
744
- if (!raw || typeof raw !== "object" || Array.isArray(raw)) return {};
745
- return raw;
746
- }
747
- };
748
-
749
- // src/background/managed-shell-process-runner.ts
750
- import { spawn } from "child_process";
751
- import {
752
- BackgroundTaskError,
753
- appendPrefixedLogLines,
754
- createBackgroundTaskLogPage,
755
- createLimitedOutputCapture
756
- } from "@robota-sdk/agent-sdk";
757
- var DEFAULT_OUTPUT_LIMIT_BYTES = 3e4;
758
- var DEFAULT_KILL_GRACE_MS = 2e3;
759
- function resolveShell(request) {
760
- return { command: request.shell ?? "sh", args: ["-c", request.command] };
761
- }
762
- function sendInput(child, input) {
763
- return new Promise((resolve3, reject) => {
764
- const onError = (error) => {
765
- child.stdin.off("error", onError);
766
- reject(error);
767
- };
768
- child.stdin.once("error", onError);
769
- child.stdin.end(input, () => {
770
- child.stdin.off("error", onError);
771
- resolve3();
772
- });
773
- });
774
- }
775
- function createManagedShellProcessRunner(options = {}) {
776
- const killGraceMs = options.killGraceMs ?? DEFAULT_KILL_GRACE_MS;
777
- return {
778
- kind: "process",
779
- start(task) {
780
- if (task.request.kind !== "process") {
781
- throw new BackgroundTaskError("runner", `Invalid process task kind: ${task.request.kind}`);
782
- }
783
- return startProcessTask(task.taskId, task.request, killGraceMs);
784
- }
785
- };
786
- }
787
- function startProcessTask(taskId, request, killGraceMs) {
788
- const shell = resolveShell(request);
789
- const runtime = {
790
- taskId,
791
- request,
792
- child: spawn(shell.command, shell.args, {
793
- cwd: request.cwd,
794
- env: { ...process.env, ...request.env ?? {} },
795
- stdio: ["pipe", "pipe", "pipe"]
796
- }),
797
- logs: [],
798
- capture: createLimitedOutputCapture({
799
- limitBytes: request.outputLimitBytes ?? DEFAULT_OUTPUT_LIMIT_BYTES
800
- }),
801
- killGraceMs
802
- };
803
- const result = createProcessResult(runtime);
804
- return createProcessHandle(runtime, result);
805
- }
806
- function createProcessResult(runtime) {
807
- let settled = false;
808
- return new Promise((resolve3, reject) => {
809
- const timeoutTimer = runtime.request.timeoutMs ? setTimeout(() => {
810
- appendPrefixedLogLines(
811
- runtime.logs,
812
- "system",
813
- `timed out after ${runtime.request.timeoutMs}ms`
814
- );
815
- runtime.child.kill("SIGTERM");
816
- rejectOnceLocal(new BackgroundTaskError("timeout", "Background process timed out"));
817
- }, runtime.request.timeoutMs) : void 0;
818
- function clearTimers() {
819
- if (timeoutTimer) clearTimeout(timeoutTimer);
820
- if (runtime.killTimer) clearTimeout(runtime.killTimer);
821
- }
822
- function resolveOnce(exitCode, signalCode) {
823
- if (settled) return;
824
- settled = true;
825
- clearTimers();
826
- resolve3({
827
- taskId: runtime.taskId,
828
- kind: "process",
829
- output: runtime.capture.getOutput(),
830
- exitCode,
831
- signalCode
832
- });
833
- }
834
- function rejectOnceLocal(error) {
835
- if (settled) return;
836
- settled = true;
837
- clearTimers();
838
- reject(error);
839
- }
840
- attachOutputListeners(runtime);
841
- runtime.child.on("error", (error) => {
842
- appendPrefixedLogLines(runtime.logs, "system", error.message);
843
- rejectOnceLocal(new BackgroundTaskError("process", error.message));
844
- });
845
- runtime.child.on("close", (code, signal) => {
846
- resolveOnce(code ?? void 0, signal ?? void 0);
847
- });
848
- if (runtime.request.stdin) {
849
- runtime.child.stdin.write(runtime.request.stdin);
850
- runtime.child.stdin.end();
851
- }
852
- });
853
- }
854
- function createProcessHandle(runtime, result) {
855
- return {
856
- taskId: runtime.taskId,
857
- ...runtime.child.pid !== void 0 ? { pid: runtime.child.pid } : {},
858
- result,
859
- cancel: async (reason) => {
860
- cancelProcess(runtime, reason);
861
- },
862
- send: async (input) => {
863
- if (!input.stdin) return;
864
- await sendInput(runtime.child, input.stdin);
865
- },
866
- readLog: (cursor) => Promise.resolve(readProcessLog(runtime, cursor))
867
- };
868
- }
869
- function attachOutputListeners(runtime) {
870
- runtime.child.stdout.on("data", (chunk) => {
871
- const text = chunk.toString("utf8");
872
- runtime.capture.appendOutput(text);
873
- appendPrefixedLogLines(runtime.logs, "stdout", text);
874
- });
875
- runtime.child.stderr.on("data", (chunk) => {
876
- const text = chunk.toString("utf8");
877
- runtime.capture.appendOutput(text);
878
- appendPrefixedLogLines(runtime.logs, "stderr", text);
879
- });
880
- }
881
- function cancelProcess(runtime, reason) {
882
- appendPrefixedLogLines(
883
- runtime.logs,
884
- "system",
885
- reason ? `cancel requested: ${reason}` : "cancel requested"
886
- );
887
- if (!runtime.child.killed) runtime.child.kill("SIGTERM");
888
- runtime.killTimer = setTimeout(() => {
889
- if (!runtime.child.killed) runtime.child.kill("SIGKILL");
890
- }, runtime.killGraceMs);
891
- }
892
- function readProcessLog(runtime, cursor) {
893
- return createBackgroundTaskLogPage(runtime.taskId, runtime.logs, cursor);
894
- }
895
-
896
- // src/subagents/child-process-subagent-runner.ts
897
- import { fork } from "child_process";
898
- import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
899
- import { dirname as dirname2, join as join5 } from "path";
900
- import {
901
- BackgroundTaskError as BackgroundTaskError5,
902
- createBackgroundTaskLogPage as createBackgroundTaskLogPage2,
903
- getBuiltInAgent,
904
- createWorktreeSubagentRunner
905
- } from "@robota-sdk/agent-sdk";
906
-
907
- // src/subagents/child-process-subagent-runner-result.ts
908
- import {
909
- BackgroundTaskError as BackgroundTaskError3
910
- } from "@robota-sdk/agent-sdk";
911
-
912
- // src/subagents/child-process-subagent-ipc.ts
913
- function isRecord(value) {
914
- return typeof value === "object" && value !== null;
915
- }
916
- function hasString(value, key) {
917
- return typeof value[key] === "string";
918
- }
919
- function isSubagentWorkerChildMessage(value) {
920
- if (!isRecord(value) || !hasString(value, "type")) return false;
921
- switch (value.type) {
922
- case "ready":
923
- return true;
924
- case "text_delta":
925
- return hasString(value, "delta");
926
- case "tool_start":
927
- return hasString(value, "toolName");
928
- case "tool_end":
929
- return hasString(value, "toolName") && typeof value.success === "boolean";
930
- case "result":
931
- return hasString(value, "output");
932
- case "error":
933
- return hasString(value, "message");
934
- case "cancelled":
935
- return value.reason === void 0 || typeof value.reason === "string";
936
- default:
937
- return false;
938
- }
939
- }
940
-
941
- // src/subagents/child-process-subagent-transport.ts
942
- import {
943
- BackgroundTaskError as BackgroundTaskError2
944
- } from "@robota-sdk/agent-sdk";
945
- function handleWorkerMessage(message, startWorker, resolveOnce, rejectOnce, emit) {
946
- switch (message.type) {
947
- case "ready":
948
- startWorker();
949
- break;
950
- case "result":
951
- resolveOnce(message.output);
952
- break;
953
- case "error":
954
- rejectOnce(new BackgroundTaskError2("runner", message.message));
955
- break;
956
- case "cancelled":
957
- rejectOnce(new BackgroundTaskError2("runner", message.reason ?? "Subagent worker cancelled"));
958
- break;
959
- case "text_delta":
960
- emit?.({ type: "background_task_text_delta", delta: message.delta });
961
- break;
962
- case "tool_start":
963
- emit?.({
964
- type: "background_task_tool_start",
965
- toolName: message.toolName,
966
- firstArg: extractFirstArg(message.toolArgs)
967
- });
968
- break;
969
- case "tool_end":
970
- emit?.({
971
- type: "background_task_tool_end",
972
- toolName: message.toolName,
973
- success: message.success
974
- });
975
- break;
976
- default:
977
- rejectOnce(new BackgroundTaskError2("runner", "Unhandled subagent worker message"));
978
- }
979
- }
980
- function extractFirstArg(toolArgs) {
981
- if (!toolArgs) return void 0;
982
- const firstValue = Object.values(toolArgs)[0];
983
- if (firstValue === void 0) return void 0;
984
- return typeof firstValue === "object" ? JSON.stringify(firstValue) : String(firstValue);
985
- }
986
- function sendWorkerMessage(child, message) {
987
- return new Promise((resolve3, reject) => {
988
- if (!child.connected) {
989
- reject(new BackgroundTaskError2("crash", "Subagent worker IPC channel is closed"));
990
- return;
991
- }
992
- child.send(message, (error) => {
993
- if (error) {
994
- reject(error);
995
- return;
996
- }
997
- resolve3();
998
- });
999
- });
1000
- }
1001
- async function cancelChildProcess(runtime, reason) {
1002
- if (runtime.child.connected) {
1003
- await sendWorkerMessage(runtime.child, { type: "cancel", reason }).catch(() => void 0);
1004
- }
1005
- runtime.killTimer = setTimeout(() => {
1006
- if (!runtime.child.killed) {
1007
- runtime.child.kill("SIGTERM");
1008
- }
1009
- }, runtime.killGraceMs);
1010
- }
1011
-
1012
- // src/subagents/child-process-subagent-runner-result.ts
1013
- function createChildProcessSubagentResult(options) {
1014
- return new Promise((resolve3, reject) => {
1015
- new ChildProcessSubagentResultController(options, resolve3, reject).start();
1016
- });
1017
- }
1018
- var ChildProcessSubagentResultController = class {
1019
- constructor(options, resolve3, reject) {
1020
- this.options = options;
1021
- this.resolve = resolve3;
1022
- this.reject = reject;
1023
- this.timeoutTimer = createTimeoutTimer(this.options.runtime, (error) => this.rejectOnce(error));
1024
- }
1025
- settled = false;
1026
- started = false;
1027
- timeoutTimer;
1028
- start() {
1029
- const { child } = this.options.runtime;
1030
- child.on("message", this.onMessage);
1031
- child.on("error", this.onError);
1032
- child.on("exit", this.onExit);
1033
- child.once("spawn", () => {
1034
- setImmediate(this.startWorker);
1035
- });
1036
- }
1037
- startWorker = () => {
1038
- if (this.started) return;
1039
- this.started = true;
1040
- const { child } = this.options.runtime;
1041
- void sendWorkerMessage(child, { type: "start", payload: this.options.payload }).catch(
1042
- (error) => {
1043
- this.rejectOnce(error instanceof Error ? error : new Error(String(error)));
1044
- }
1045
- );
1046
- };
1047
- onMessage = (message) => {
1048
- if (!isSubagentWorkerChildMessage(message)) {
1049
- this.rejectOnce(
1050
- new BackgroundTaskError3("runner", "Received malformed subagent worker message")
1051
- );
1052
- return;
1053
- }
1054
- const { job } = this.options.runtime;
1055
- handleWorkerMessage(message, this.startWorker, this.resolveOnce, this.rejectOnce, job.emit);
1056
- };
1057
- onError = (error) => {
1058
- this.rejectOnce(new BackgroundTaskError3("crash", error.message));
1059
- };
1060
- onExit = (code, signal) => {
1061
- if (this.settled) return;
1062
- this.rejectOnce(new BackgroundTaskError3("crash", formatEarlyExitMessage(code, signal)));
1063
- };
1064
- resolveOnce = (output) => {
1065
- if (this.settled) return;
1066
- this.settled = true;
1067
- this.clearTimers();
1068
- this.cleanup();
1069
- const { runtime, resolveTranscriptPath } = this.options;
1070
- this.resolve(toSubagentResult(runtime.job, output, resolveTranscriptPath));
1071
- };
1072
- rejectOnce = (error) => {
1073
- if (this.settled) return;
1074
- this.settled = true;
1075
- this.clearTimers();
1076
- this.cleanup();
1077
- this.reject(error);
1078
- };
1079
- clearTimers() {
1080
- if (this.timeoutTimer) clearTimeout(this.timeoutTimer);
1081
- if (this.options.runtime.killTimer) clearTimeout(this.options.runtime.killTimer);
1082
- }
1083
- cleanup() {
1084
- const { child } = this.options.runtime;
1085
- child.off("message", this.onMessage);
1086
- child.off("error", this.onError);
1087
- child.off("exit", this.onExit);
1088
- }
1089
- };
1090
- function createCancellationResult(jobId) {
1091
- let settled = false;
1092
- let rejectFn = () => {
1093
- };
1094
- const promise = new Promise((_resolve, reject) => {
1095
- rejectFn = reject;
1096
- });
1097
- return {
1098
- promise,
1099
- reject(reason) {
1100
- if (settled) return;
1101
- settled = true;
1102
- rejectFn(new BackgroundTaskError3("runner", reason ?? `Subagent job cancelled: ${jobId}`));
1103
- }
1104
- };
1105
- }
1106
- function createTimeoutTimer(runtime, rejectOnce) {
1107
- if (!runtime.job.request.timeoutMs) return void 0;
1108
- return setTimeout(() => {
1109
- void cancelChildProcess(runtime, "Subagent worker timed out");
1110
- rejectOnce(new BackgroundTaskError3("timeout", "Subagent worker timed out"));
1111
- }, runtime.job.request.timeoutMs);
1112
- }
1113
- function toSubagentResult(job, output, resolveTranscriptPath) {
1114
- const transcriptPath = resolveTranscriptPath(job);
1115
- return {
1116
- jobId: job.jobId,
1117
- output,
1118
- ...transcriptPath ? { metadata: { transcriptPath, logPath: transcriptPath } } : {}
1119
- };
1120
- }
1121
- function formatEarlyExitMessage(code, signal) {
1122
- const detail = signal !== null ? `signal ${signal}` : `exit code ${code === null ? "unknown" : code}`;
1123
- return `Subagent worker exited before result: ${detail}`;
1124
- }
1125
-
1126
- // src/subagents/git-worktree-isolation-adapter.ts
1127
- import { execFileSync } from "child_process";
1128
- import { randomUUID } from "crypto";
1129
- import { mkdirSync as mkdirSync2 } from "fs";
1130
- import { join as join4 } from "path";
1131
- import {
1132
- BackgroundTaskError as BackgroundTaskError4
1133
- } from "@robota-sdk/agent-sdk";
1134
- var WORKTREE_DIR = ".robota/worktrees";
1135
- var BRANCH_PREFIX = "robota";
1136
- var GIT_ENCODING = "utf8";
1137
- var SHORT_ID_LENGTH = 8;
1138
- var DEFAULT_MAX_CREATE_ATTEMPTS = 5;
1139
- var COLLISION_ERROR_PATTERN = /already exists|is already checked out|missing but already registered/i;
1140
- function createGitWorktreeIsolationAdapter(options) {
1141
- return new GitWorktreeIsolationAdapter(options);
1142
- }
1143
- var GitWorktreeIsolationAdapter = class {
1144
- worktreeDir;
1145
- branchPrefix;
1146
- idFactory;
1147
- maxCreateAttempts;
1148
- constructor(options = {}) {
1149
- this.worktreeDir = options.worktreeDir ?? WORKTREE_DIR;
1150
- this.branchPrefix = options.branchPrefix ?? BRANCH_PREFIX;
1151
- this.idFactory = options.idFactory ?? createShortId;
1152
- this.maxCreateAttempts = options.maxCreateAttempts ?? DEFAULT_MAX_CREATE_ATTEMPTS;
1153
- }
1154
- prepare(request) {
1155
- if (this.maxCreateAttempts < 1) {
1156
- throw new BackgroundTaskError4("runner", "Git worktree creation attempts must be at least 1");
1157
- }
1158
- const repoRoot = resolveRepoRoot(request.cwd);
1159
- const baseRevision = runGit(repoRoot, ["rev-parse", "HEAD"]).trim();
1160
- const parentStatus = runGit(repoRoot, ["status", "--porcelain"]).trimEnd();
1161
- const worktreeRoot = join4(repoRoot, this.worktreeDir);
1162
- mkdirSync2(worktreeRoot, { recursive: true });
1163
- let lastError;
1164
- for (let attempt = 0; attempt < this.maxCreateAttempts; attempt += 1) {
1165
- const shortId = normalizeShortId(this.idFactory());
1166
- const jobId = sanitizePathSegment(request.jobId);
1167
- const branchName = `${this.branchPrefix}/${jobId}-${shortId}`;
1168
- const worktreePath = join4(worktreeRoot, `${jobId}-${shortId}`);
1169
- try {
1170
- runGit(repoRoot, ["worktree", "add", "-b", branchName, worktreePath, "HEAD"]);
1171
- return { repoRoot, worktreePath, branchName, baseRevision, parentStatus };
1172
- } catch (error) {
1173
- lastError = toError(error);
1174
- if (!isCollisionError(lastError)) throw lastError;
1175
- }
1176
- }
1177
- throw new BackgroundTaskError4(
1178
- "runner",
1179
- `Unable to create Git worktree after ${this.maxCreateAttempts} attempts due to branch or path collisions. Last error: ${lastError?.message ?? "unknown error"}`
1180
- );
1181
- }
1182
- isClean(worktree) {
1183
- return this.getStatus(worktree).trim().length === 0;
1184
- }
1185
- getStatus(worktree) {
1186
- return runGit(worktree.worktreePath, ["status", "--porcelain"]);
1187
- }
1188
- remove(worktree) {
1189
- runGit(worktree.repoRoot, ["worktree", "remove", "--force", worktree.worktreePath]);
1190
- runGit(worktree.repoRoot, ["branch", "-D", worktree.branchName]);
1191
- }
1192
- };
1193
- function runGit(cwd, args) {
1194
- try {
1195
- return execFileSync("git", args, {
1196
- cwd,
1197
- encoding: GIT_ENCODING,
1198
- stdio: ["ignore", "pipe", "pipe"],
1199
- env: createGitEnvironment()
1200
- });
1201
- } catch (error) {
1202
- const message = error instanceof Error ? error.message : String(error);
1203
- throw new BackgroundTaskError4("runner", `git ${args.join(" ")} failed: ${message}`);
1204
- }
1205
- }
1206
- function createGitEnvironment() {
1207
- const env = { ...process.env };
1208
- for (const key of Object.keys(env)) {
1209
- if (key.startsWith("GIT_")) {
1210
- delete env[key];
1211
- }
1212
- }
1213
- return env;
1214
- }
1215
- function resolveRepoRoot(cwd) {
1216
- try {
1217
- return runGit(cwd, ["rev-parse", "--show-toplevel"]).trim();
1218
- } catch (error) {
1219
- const message = error instanceof Error ? error.message : String(error);
1220
- throw new BackgroundTaskError4(
1221
- "runner",
1222
- `Worktree isolation requires a Git repository. Run from a Git worktree or request isolation "none". Details: ${message}`
1223
- );
1224
- }
1225
- }
1226
- function createShortId() {
1227
- return randomUUID().slice(0, SHORT_ID_LENGTH);
1228
- }
1229
- function normalizeShortId(value) {
1230
- const sanitized = sanitizePathSegment(value).slice(0, SHORT_ID_LENGTH);
1231
- return sanitized.length > 0 ? sanitized : createShortId();
1232
- }
1233
- function sanitizePathSegment(value) {
1234
- const sanitized = value.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
1235
- return sanitized.length > 0 ? sanitized : "agent";
1236
- }
1237
- function toError(error) {
1238
- return error instanceof Error ? error : new Error(String(error));
1239
- }
1240
- function isCollisionError(error) {
1241
- return COLLISION_ERROR_PATTERN.test(error.message);
1242
- }
1243
-
1244
- // src/subagents/child-process-subagent-runner.ts
1245
- var DEFAULT_KILL_GRACE_MS2 = 2e3;
1246
- function createChildProcessSubagentRunnerFactory(options = {}) {
1247
- return (deps) => {
1248
- const runner = new ChildProcessSubagentRunner(deps, options);
1249
- if (options.worktreeIsolation === false) return runner;
1250
- return createWorktreeSubagentRunner({
1251
- runner,
1252
- worktreeAdapter: options.worktreeAdapter ?? createGitWorktreeIsolationAdapter(),
1253
- hooks: deps.config.hooks,
1254
- hookTypeExecutors: deps.hookTypeExecutors
1255
- });
1256
- };
1257
- }
1258
- var ChildProcessSubagentRunner = class {
1259
- constructor(deps, options = {}) {
1260
- this.deps = deps;
1261
- this.workerPath = options.workerPath ?? resolveDefaultWorkerPath();
1262
- this.execArgv = options.execArgv;
1263
- this.killGraceMs = options.killGraceMs ?? DEFAULT_KILL_GRACE_MS2;
1264
- this.providerConfig = options.providerConfig;
1265
- this.env = options.env;
1266
- this.logsDir = options.logsDir;
1267
- }
1268
- workerPath;
1269
- execArgv;
1270
- killGraceMs;
1271
- providerConfig;
1272
- env;
1273
- logsDir;
1274
- start(job) {
1275
- const child = fork(this.workerPath, [], {
1276
- cwd: job.request.cwd,
1277
- env: { ...process.env, ...this.env ?? {} },
1278
- execArgv: this.execArgv ?? resolveDefaultExecArgv(this.workerPath),
1279
- stdio: ["ignore", "ignore", "ignore", "ipc"]
1280
- });
1281
- const runtime = {
1282
- job,
1283
- child,
1284
- killGraceMs: this.killGraceMs
1285
- };
1286
- const payload = this.createStartPayload(job);
1287
- const workerResult = createChildProcessSubagentResult({
1288
- runtime,
1289
- payload,
1290
- resolveTranscriptPath: (request) => this.resolveTranscriptPath(request)
1291
- });
1292
- const cancellation = createCancellationResult(job.jobId);
1293
- void workerResult.catch(() => void 0);
1294
- const result = Promise.race([workerResult, cancellation.promise]);
1295
- const transcriptPath = this.resolveTranscriptPath(job);
1296
- return {
1297
- jobId: job.jobId,
1298
- ...child.pid !== void 0 && { pid: child.pid },
1299
- ...transcriptPath !== void 0 && { transcriptPath, logPath: transcriptPath },
1300
- result,
1301
- cancel: async (reason) => {
1302
- cancellation.reject(reason);
1303
- await cancelChildProcess(runtime, reason);
1304
- },
1305
- send: async (prompt) => {
1306
- await sendWorkerMessage(child, { type: "send", prompt });
1307
- },
1308
- ...transcriptPath !== void 0 && {
1309
- readLog: async (cursor) => readTranscriptLog(job.jobId, transcriptPath, cursor)
1310
- }
1311
- };
1312
- }
1313
- createStartPayload(job) {
1314
- const definition = resolveAgentDefinition(job.request.type, this.deps.customAgentRegistry);
1315
- return {
1316
- jobId: job.jobId,
1317
- request: job.request,
1318
- agentDefinition: applyRequestOverrides(definition, job),
1319
- parentConfig: this.deps.config,
1320
- parentContext: this.deps.context,
1321
- providerProfile: createProviderProfile(this.providerConfig, this.deps, job),
1322
- permissionMode: this.deps.permissionMode,
1323
- ...this.logsDir ? { logsDir: this.logsDir } : {}
1324
- };
1325
- }
1326
- resolveTranscriptPath(job) {
1327
- if (!this.logsDir) return void 0;
1328
- return join5(this.logsDir, job.request.parentSessionId, "subagents", `${job.jobId}.jsonl`);
1329
- }
1330
- };
1331
- function resolveAgentDefinition(agentType, customRegistry) {
1332
- const definition = customRegistry?.(agentType) ?? getBuiltInAgent(agentType);
1333
- if (!definition) {
1334
- throw new BackgroundTaskError5("validation", `Unknown agent type: ${agentType}`);
1335
- }
1336
- return definition;
1337
- }
1338
- function applyRequestOverrides(definition, job) {
1339
- return {
1340
- ...definition,
1341
- ...job.request.model ? { model: job.request.model } : {},
1342
- ...job.request.allowedTools ? { tools: job.request.allowedTools } : {},
1343
- ...job.request.disallowedTools ? { disallowedTools: job.request.disallowedTools } : {}
1344
- };
1345
- }
1346
- function createProviderProfile(providerConfig, deps, job) {
1347
- const provider = providerConfig ?? deps.config.provider;
1348
- return {
1349
- profileName: deps.config.currentProvider,
1350
- type: provider.name,
1351
- model: job.request.model ?? provider.model,
1352
- apiKey: provider.apiKey,
1353
- baseURL: provider.baseURL,
1354
- timeout: provider.timeout,
1355
- options: provider.options
1356
- };
1357
- }
1358
- function resolveDefaultWorkerPath() {
1359
- const entryPoint = process.argv[1] ?? "";
1360
- const entryDir = entryPoint ? dirname2(entryPoint) : process.cwd();
1361
- const extension = entryPoint.endsWith(".ts") || entryPoint.endsWith(".tsx") ? ".ts" : ".js";
1362
- const candidates = [
1363
- join5(entryDir, "subagents", `child-process-subagent-worker${extension}`),
1364
- join5(entryDir, `child-process-subagent-worker${extension}`)
1365
- ];
1366
- for (const candidate of candidates) {
1367
- if (existsSync4(candidate)) {
1368
- return candidate;
1369
- }
1370
- }
1371
- return candidates[0];
1372
- }
1373
- function resolveDefaultExecArgv(workerPath) {
1374
- if (!workerPath.endsWith(".ts")) {
1375
- return process.execArgv;
1376
- }
1377
- if (process.execArgv.some((arg) => arg.includes("tsx"))) {
1378
- return process.execArgv;
1379
- }
1380
- return [...process.execArgv, "--import", "tsx"];
1381
- }
1382
- function readTranscriptLog(jobId, transcriptPath, cursor) {
1383
- if (!existsSync4(transcriptPath)) {
1384
- return {
1385
- taskId: jobId,
1386
- cursor,
1387
- lines: []
1388
- };
1389
- }
1390
- const lines = readFileSync4(transcriptPath, "utf8").split(/\r?\n/).filter(Boolean);
1391
- return createBackgroundTaskLogPage2(jobId, lines, cursor);
1392
- }
1393
-
1394
- // src/utils/update-check.ts
1395
- import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "fs";
1396
- import { dirname as dirname3, join as join6 } from "path";
1397
-
1398
- // src/utils/semver-compare.ts
1399
- function compareSemverVersions(left, right) {
1400
- const parsedLeft = parseSemver(left);
1401
- const parsedRight = parseSemver(right);
1402
- if (parsedLeft === void 0 || parsedRight === void 0) {
1403
- return Math.sign(left.localeCompare(right));
1404
- }
1405
- const coreCompare = compareNumber(parsedLeft.major, parsedRight.major) || compareNumber(parsedLeft.minor, parsedRight.minor) || compareNumber(parsedLeft.patch, parsedRight.patch);
1406
- if (coreCompare !== 0) {
1407
- return coreCompare;
1408
- }
1409
- return comparePrerelease(parsedLeft.prerelease, parsedRight.prerelease);
1410
- }
1411
- function isNewerSemverVersion(candidate, current) {
1412
- return compareSemverVersions(candidate, current) > 0;
1413
- }
1414
- function parseSemver(value) {
1415
- const normalized = value.trim().replace(/^v/, "").split("+")[0] ?? "";
1416
- const [core, prereleaseText] = normalized.split("-", 2);
1417
- const [majorText, minorText, patchText] = core.split(".");
1418
- const major = parseNumericIdentifier(majorText);
1419
- const minor = parseNumericIdentifier(minorText);
1420
- const patch = parseNumericIdentifier(patchText);
1421
- if (major === void 0 || minor === void 0 || patch === void 0) {
1422
- return void 0;
1423
- }
1424
- return {
1425
- major,
1426
- minor,
1427
- patch,
1428
- prerelease: prereleaseText ? prereleaseText.split(".") : []
1429
- };
1430
- }
1431
- function parseNumericIdentifier(value) {
1432
- if (value === void 0 || !/^\d+$/.test(value)) {
1433
- return void 0;
1434
- }
1435
- return Number(value);
1436
- }
1437
- function compareNumber(left, right) {
1438
- return Math.sign(left - right);
1439
- }
1440
- function comparePrerelease(left, right) {
1441
- if (left.length === 0 && right.length === 0) {
1442
- return 0;
1443
- }
1444
- if (left.length === 0) {
1445
- return 1;
1446
- }
1447
- if (right.length === 0) {
1448
- return -1;
1449
- }
1450
- const max = Math.max(left.length, right.length);
1451
- for (let index = 0; index < max; index += 1) {
1452
- const leftPart = left[index];
1453
- const rightPart = right[index];
1454
- if (leftPart === void 0) {
1455
- return -1;
1456
- }
1457
- if (rightPart === void 0) {
1458
- return 1;
1459
- }
1460
- const partCompare = comparePrereleaseIdentifier(leftPart, rightPart);
1461
- if (partCompare !== 0) {
1462
- return partCompare;
1463
- }
1464
- }
1465
- return 0;
1466
- }
1467
- function comparePrereleaseIdentifier(left, right) {
1468
- const leftNumber = parseNumericIdentifier(left);
1469
- const rightNumber = parseNumericIdentifier(right);
1470
- if (leftNumber !== void 0 && rightNumber !== void 0) {
1471
- return compareNumber(leftNumber, rightNumber);
1472
- }
1473
- if (leftNumber !== void 0) {
1474
- return -1;
1475
- }
1476
- if (rightNumber !== void 0) {
1477
- return 1;
1478
- }
1479
- return Math.sign(left.localeCompare(right));
1480
- }
1481
-
1482
- // src/utils/update-check.ts
1483
- var CLI_UPDATE_PACKAGE_NAME = "@robota-sdk/agent-cli";
1484
- var CLI_UPDATE_REGISTRY_URL = "https://registry.npmjs.org";
1485
- var HOURS_PER_DAY = 24;
1486
- var MINUTES_PER_HOUR = 60;
1487
- var SECONDS_PER_MINUTE = 60;
1488
- var MS_PER_SECOND = 1e3;
1489
- var CLI_UPDATE_CACHE_TTL_MS = HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE * MS_PER_SECOND;
1490
- var CLI_UPDATE_TIMEOUT_MS = 1500;
1491
- var DEFAULT_INSTALL_COMMAND = "npm install -g '@robota-sdk/agent-cli@latest'";
1492
- function getUserUpdateCheckCachePath(home = process.env.HOME ?? process.env.USERPROFILE ?? "/") {
1493
- return join6(home, ".robota", "update-check.json");
1494
- }
1495
- function readUpdateCheckCache(path) {
1496
- if (!existsSync5(path)) {
1497
- return void 0;
1498
- }
1499
- try {
1500
- const parsed = JSON.parse(readFileSync5(path, "utf8"));
1501
- return parseUpdateCheckCache(parsed);
1502
- } catch {
1503
- return void 0;
1504
- }
1505
- }
1506
- function writeUpdateCheckCache(path, cache) {
1507
- mkdirSync3(dirname3(path), { recursive: true });
1508
- writeFileSync2(path, JSON.stringify(cache, null, 2) + "\n", "utf8");
1509
- }
1510
- async function checkForCliUpdate(options) {
1511
- if (options.disabled === true) {
1512
- return { status: "skipped", reason: "disabled" };
1513
- }
1514
- const packageName = options.packageName ?? CLI_UPDATE_PACKAGE_NAME;
1515
- const cachePath = options.cachePath ?? getUserUpdateCheckCachePath();
1516
- const now = options.now ?? /* @__PURE__ */ new Date();
1517
- const ttlMs = options.ttlMs ?? CLI_UPDATE_CACHE_TTL_MS;
1518
- if (options.force !== true) {
1519
- const cached = readUpdateCheckCache(cachePath);
1520
- if (cached !== void 0 && isFreshCache(cached, now, ttlMs, packageName)) {
1521
- return resultFromCache(cached, options.currentVersion);
1522
- }
1523
- }
1524
- try {
1525
- const latestVersion = await fetchLatestVersion({
1526
- fetchImpl: options.fetchImpl ?? fetch,
1527
- packageName,
1528
- registryUrl: options.registryUrl ?? CLI_UPDATE_REGISTRY_URL,
1529
- timeoutMs: options.timeoutMs ?? CLI_UPDATE_TIMEOUT_MS
1530
- });
1531
- tryWriteUpdateCheckCache(cachePath, {
1532
- packageName,
1533
- checkedAt: now.toISOString(),
1534
- currentVersion: options.currentVersion,
1535
- latestVersion
1536
- });
1537
- return resultFromLatestVersion(options.currentVersion, latestVersion);
1538
- } catch (error) {
1539
- const errorMessage = error instanceof Error ? error.message : String(error);
1540
- tryWriteUpdateCheckCache(cachePath, {
1541
- packageName,
1542
- checkedAt: now.toISOString(),
1543
- currentVersion: options.currentVersion,
1544
- errorMessage
1545
- });
1546
- return { status: "error", errorMessage };
1547
- }
1548
- }
1549
- function tryWriteUpdateCheckCache(path, cache) {
1550
- try {
1551
- writeUpdateCheckCache(path, cache);
1552
- } catch {
1553
- }
1554
- }
1555
- async function getStartupCliUpdateNotice(options) {
1556
- const result = await checkForCliUpdate(options);
1557
- return result.status === "update_available" ? result.notice : void 0;
1558
- }
1559
- function shouldRunStartupCliUpdateCheck(input) {
1560
- return input.printMode === false && input.disableUpdateCheck === false;
1561
- }
1562
- function formatCliUpdateNotice(notice) {
1563
- return [
1564
- `Robota update available: ${notice.currentVersion} -> ${notice.latestVersion}.`,
1565
- `Run ${notice.installCommand}`
1566
- ].join(" ");
1567
- }
1568
- function formatCliUpdateCheckMessage(result) {
1569
- if (result.status === "update_available") {
1570
- return formatCliUpdateNotice(result.notice);
1571
- }
1572
- if (result.status === "current") {
1573
- return `Robota is up to date (${result.currentVersion}).`;
1574
- }
1575
- if (result.status === "skipped") {
1576
- return "Robota update check skipped.";
1577
- }
1578
- return `Robota update check failed: ${result.errorMessage}`;
1579
- }
1580
- function resultFromCache(cache, currentVersion) {
1581
- if (cache.errorMessage !== void 0) {
1582
- return { status: "error", errorMessage: cache.errorMessage };
1583
- }
1584
- if (cache.latestVersion === void 0) {
1585
- return { status: "error", errorMessage: "Cached update check has no latest version" };
1586
- }
1587
- return resultFromLatestVersion(currentVersion, cache.latestVersion);
1588
- }
1589
- function resultFromLatestVersion(currentVersion, latestVersion) {
1590
- if (isNewerSemverVersion(latestVersion, currentVersion)) {
1591
- return {
1592
- status: "update_available",
1593
- notice: {
1594
- currentVersion,
1595
- latestVersion,
1596
- installCommand: DEFAULT_INSTALL_COMMAND
1597
- }
1598
- };
1599
- }
1600
- return { status: "current", currentVersion, latestVersion };
1601
- }
1602
- function isFreshCache(cache, now, ttlMs, packageName) {
1603
- if (cache.packageName !== packageName) {
1604
- return false;
1605
- }
1606
- const checkedAt = Date.parse(cache.checkedAt);
1607
- if (!Number.isFinite(checkedAt)) {
1608
- return false;
1609
- }
1610
- return now.getTime() - checkedAt < ttlMs;
1611
- }
1612
- async function fetchLatestVersion(options) {
1613
- const controller = new AbortController();
1614
- const timeout = setTimeout(() => controller.abort(), options.timeoutMs);
1615
- try {
1616
- const packageUrl = buildPackageMetadataUrl(options.registryUrl, options.packageName);
1617
- const response = await options.fetchImpl(packageUrl, {
1618
- headers: { accept: "application/json" },
1619
- signal: controller.signal
1620
- });
1621
- if (!response.ok) {
1622
- throw new Error(`registry responded with HTTP ${response.status}`);
1623
- }
1624
- const metadata = await response.json();
1625
- const latest = metadata["dist-tags"]?.latest;
1626
- if (typeof latest !== "string" || latest.trim().length === 0) {
1627
- throw new Error("registry metadata is missing dist-tags.latest");
1628
- }
1629
- return latest;
1630
- } finally {
1631
- clearTimeout(timeout);
1632
- }
1633
- }
1634
- function buildPackageMetadataUrl(registryUrl, packageName) {
1635
- return `${registryUrl.replace(/\/+$/, "")}/${encodeURIComponent(packageName)}`;
1636
- }
1637
- function parseUpdateCheckCache(value) {
1638
- if (!isJsonObject(value)) {
1639
- return void 0;
1640
- }
1641
- const candidate = value;
1642
- 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")) {
1643
- return {
1644
- packageName: candidate.packageName,
1645
- checkedAt: candidate.checkedAt,
1646
- currentVersion: candidate.currentVersion,
1647
- ...candidate.latestVersion !== void 0 && { latestVersion: candidate.latestVersion },
1648
- ...candidate.errorMessage !== void 0 && { errorMessage: candidate.errorMessage }
1649
- };
1650
- }
1651
- return void 0;
1652
- }
1653
- function isJsonObject(value) {
1654
- return value !== null && typeof value === "object" && !Array.isArray(value);
1655
- }
1656
-
1657
- // src/utils/statusline-settings.ts
1658
- import { DEFAULT_STATUS_LINE_COMMAND_SETTINGS } from "@robota-sdk/agent-sdk";
1659
- var DEFAULT_STATUS_LINE_SETTINGS = {
1660
- ...DEFAULT_STATUS_LINE_COMMAND_SETTINGS
1661
- };
1662
- function readStatusLineSettings(settings) {
1663
- const raw = settings.statusline;
1664
- if (!isRecord2(raw)) {
1665
- return { ...DEFAULT_STATUS_LINE_SETTINGS };
1666
- }
1667
- return {
1668
- enabled: typeof raw.enabled === "boolean" ? raw.enabled : DEFAULT_STATUS_LINE_SETTINGS.enabled,
1669
- gitBranch: typeof raw.gitBranch === "boolean" ? raw.gitBranch : DEFAULT_STATUS_LINE_SETTINGS.gitBranch
1670
- };
1671
- }
1672
- function applyStatusLineSettings(settingsPath, patch) {
1673
- const settings = readSettings(settingsPath);
1674
- const next = {
1675
- ...readStatusLineSettings(settings),
1676
- ...patch
1677
- };
1678
- settings.statusline = next;
1679
- writeSettings(settingsPath, settings);
1680
- return next;
1681
- }
1682
- function isRecord2(value) {
1683
- return value !== null && typeof value === "object" && !Array.isArray(value) && !(value instanceof Date);
1684
- }
1685
-
1686
- // src/utils/git-branch.ts
1687
- import { existsSync as existsSync6, lstatSync, readFileSync as readFileSync6 } from "fs";
1688
- import { dirname as dirname4, isAbsolute, join as join7, resolve } from "path";
1689
- var DETACHED_HEAD_LENGTH = 7;
1690
- function resolveGitBranch(cwd) {
1691
- try {
1692
- const gitDir = findGitDir(cwd);
1693
- if (!gitDir) return void 0;
1694
- const head = readFileSync6(join7(gitDir, "HEAD"), "utf8").trim();
1695
- if (!head) return void 0;
1696
- if (head.startsWith("ref: ")) {
1697
- const ref = head.slice("ref: ".length).trim();
1698
- const branchPrefix = "refs/heads/";
1699
- return ref.startsWith(branchPrefix) ? ref.slice(branchPrefix.length) : ref;
1700
- }
1701
- return head.slice(0, DETACHED_HEAD_LENGTH);
1702
- } catch {
1703
- return void 0;
1704
- }
1705
- }
1706
- function findGitDir(start) {
1707
- let current = resolve(start);
1708
- let parent = dirname4(current);
1709
- while (parent !== current) {
1710
- const candidate = join7(current, ".git");
1711
- const resolved = resolveGitMetadata(candidate, current);
1712
- if (resolved) return resolved;
1713
- current = parent;
1714
- parent = dirname4(current);
1715
- }
1716
- const rootCandidate = join7(current, ".git");
1717
- return resolveGitMetadata(rootCandidate, current);
1718
- }
1719
- function resolveGitMetadata(candidate, repoDir) {
1720
- if (!existsSync6(candidate)) return void 0;
1721
- const stat = lstatSync(candidate);
1722
- if (stat.isDirectory()) return candidate;
1723
- if (!stat.isFile()) return void 0;
1724
- const content = readFileSync6(candidate, "utf8").trim();
1725
- const prefix = "gitdir:";
1726
- if (!content.startsWith(prefix)) return void 0;
1727
- const rawPath = content.slice(prefix.length).trim();
1728
- return isAbsolute(rawPath) ? rawPath : resolve(repoDir, rawPath);
1729
- }
1730
-
1731
- // src/plugins/plugin-command-source-loader.ts
1732
- import { homedir } from "os";
1733
- import { join as join8 } from "path";
1734
- import { BundlePluginLoader, PluginCommandSource } from "@robota-sdk/agent-sdk";
1735
- var PLUGIN_SOURCE_NAME = "plugin";
1736
- function getHomeDir() {
1737
- return process.env.HOME ?? homedir();
1738
- }
1739
- function reloadPluginCommandSource(registry) {
1740
- const pluginsDir = join8(getHomeDir(), ".robota", "plugins");
1741
- const loader = new BundlePluginLoader(pluginsDir);
1742
- try {
1743
- const plugins = loader.loadPluginsSync();
1744
- if (plugins.length === 0) {
1745
- registry.replaceSource(PLUGIN_SOURCE_NAME);
1746
- return 0;
1747
- }
1748
- registry.replaceSource(PLUGIN_SOURCE_NAME, new PluginCommandSource(plugins));
1749
- return plugins.length;
1750
- } catch {
1751
- registry.replaceSource(PLUGIN_SOURCE_NAME);
1752
- return 0;
1753
- }
1754
- }
1755
-
1756
- // src/plugins/plugin-command-adapter.ts
1757
- import { homedir as homedir2 } from "os";
1758
- import { join as join9 } from "path";
1759
- import {
1760
- BundlePluginInstaller,
1761
- BundlePluginLoader as BundlePluginLoader2,
1762
- MarketplaceClient,
1763
- PluginSettingsStore
1764
- } from "@robota-sdk/agent-sdk";
1765
- function createCliPluginServices(cwd) {
1766
- const home = homedir2();
1767
- const pluginsDir = join9(home, ".robota", "plugins");
1768
- const userSettingsPath = join9(home, ".robota", "settings.json");
1769
- const settingsStore = new PluginSettingsStore(userSettingsPath);
1770
- const marketplace = new MarketplaceClient({ pluginsDir });
1771
- const installer = new BundlePluginInstaller({
1772
- pluginsDir,
1773
- settingsStore,
1774
- marketplaceClient: marketplace
1775
- });
1776
- const loader = new BundlePluginLoader2(pluginsDir);
1777
- return {
1778
- cwd,
1779
- marketplace,
1780
- installer,
1781
- loader,
1782
- settingsStore
1783
- };
1784
- }
1785
- async function listInstalledPlugins(services) {
1786
- const plugins = await services.loader.loadAll();
1787
- const enabledMap = services.settingsStore.getEnabledPlugins();
1788
- return plugins.map((plugin) => {
1789
- const parts = plugin.pluginDir.split("/");
1790
- const cacheIdx = parts.indexOf("cache");
1791
- const marketplaceName = cacheIdx >= 0 ? parts[cacheIdx + 1] ?? "" : "";
1792
- const fullId = marketplaceName ? `${plugin.manifest.name}@${marketplaceName}` : plugin.manifest.name;
1793
- return {
1794
- name: fullId,
1795
- description: plugin.manifest.description,
1796
- enabled: enabledMap[fullId] !== false && enabledMap[plugin.manifest.name] !== false
1797
- };
1798
- });
1799
- }
1800
- async function listAvailablePlugins(services, marketplaceName) {
1801
- let manifest;
1802
- try {
1803
- manifest = services.marketplace.fetchManifest(marketplaceName);
1804
- } catch {
1805
- return [];
1806
- }
1807
- const installed = services.installer.getInstalledPlugins();
1808
- const installedNames = new Set(Object.values(installed).map((record) => record.pluginName));
1809
- return manifest.plugins.map((plugin) => ({
1810
- name: plugin.name,
1811
- description: plugin.description,
1812
- installed: installedNames.has(plugin.name)
1813
- }));
1814
- }
1815
- async function installPlugin(services, pluginId, scope) {
1816
- const [name, marketplaceName] = pluginId.split("@");
1817
- if (!name || !marketplaceName) {
1818
- throw new Error("Plugin ID must be in format: name@marketplace");
1819
- }
1820
- if (scope === "project") {
1821
- const projectPluginsDir = join9(services.cwd, ".robota", "plugins");
1822
- const projectInstaller = new BundlePluginInstaller({
1823
- pluginsDir: projectPluginsDir,
1824
- settingsStore: services.settingsStore,
1825
- marketplaceClient: services.marketplace
1826
- });
1827
- await projectInstaller.install(name, marketplaceName);
1828
- return;
1829
- }
1830
- await services.installer.install(name, marketplaceName);
1831
- }
1832
- async function removeMarketplace(services, name) {
1833
- const installedFromMarketplace = services.installer.getPluginsByMarketplace(name);
1834
- for (const record of installedFromMarketplace) {
1835
- await services.installer.uninstall(`${record.pluginName}@${record.marketplace}`);
1836
- }
1837
- services.marketplace.removeMarketplace(name);
1838
- }
1839
- function listMarketplaces(services) {
1840
- return services.marketplace.listMarketplaces().map((marketplaceEntry) => ({
1841
- name: marketplaceEntry.name,
1842
- type: marketplaceEntry.source.type
1843
- }));
1844
- }
1845
- function createCliPluginCommandAdapter(cwd) {
1846
- const services = createCliPluginServices(cwd);
1847
- return {
1848
- listInstalled: () => listInstalledPlugins(services),
1849
- listAvailablePlugins: (marketplaceName) => listAvailablePlugins(services, marketplaceName),
1850
- install: (pluginId, scope) => installPlugin(services, pluginId, scope),
1851
- uninstall: async (pluginId) => services.installer.uninstall(pluginId),
1852
- enable: async (pluginId) => services.installer.enable(pluginId),
1853
- disable: async (pluginId) => services.installer.disable(pluginId),
1854
- marketplaceAdd: async (source) => {
1855
- if (source.includes("/") && !source.includes(":")) {
1856
- return services.marketplace.addMarketplace({ type: "github", repo: source });
1857
- }
1858
- return services.marketplace.addMarketplace({ type: "git", url: source });
1859
- },
1860
- marketplaceRemove: (name) => removeMarketplace(services, name),
1861
- marketplaceUpdate: async (name) => services.marketplace.updateMarketplace(name),
1862
- marketplaceList: async () => listMarketplaces(services),
1863
- reloadPlugins: async () => ({
1864
- loadedPluginCount: (await services.loader.loadAll()).length
1865
- })
1866
- };
1867
- }
1868
-
1869
- // src/user-local-direct-command.ts
1870
- import { executeUserLocalDirectCommand } from "@robota-sdk/agent-command-user-local";
1871
- async function runUserLocalDirectCommandIfRequested(args, cwd) {
1872
- if (args.positional[0] !== "user-local") {
1873
- return false;
1874
- }
1875
- const result = await executeUserLocalDirectCommand({
1876
- cwd,
1877
- argv: args.positional.slice(1),
1878
- format: args.format,
1879
- summary: args.summary,
1880
- source: args.source
1881
- });
1882
- const output = result.message.endsWith("\n") ? result.message : `${result.message}
1883
- `;
1884
- if (!result.success) {
1885
- process.stderr.write(output);
1886
- process.exit(1);
1887
- }
1888
- process.stdout.write(output);
1889
- return true;
1890
- }
1891
-
1892
- // src/cli.ts
1893
- var PRINTABLE_ASCII_START = 32;
1894
- function readVersion() {
1895
- try {
1896
- const thisFile = fileURLToPath(import.meta.url);
1897
- const dir = dirname5(thisFile);
1898
- const candidates = [join10(dir, "..", "..", "package.json"), join10(dir, "..", "package.json")];
1899
- for (const pkgPath of candidates) {
1900
- try {
1901
- const raw = readFileSync7(pkgPath, "utf-8");
1902
- const pkg = JSON.parse(raw);
1903
- if (pkg.version !== void 0 && pkg.name !== void 0) {
1904
- return pkg.version;
1905
- }
1906
- } catch {
1907
- }
1908
- }
1909
- return "0.0.0";
1910
- } catch {
1911
- return "0.0.0";
1912
- }
1913
- }
1914
- function promptInput(label, masked = false) {
1915
- return new Promise((resolve3, reject) => {
1916
- process.stdout.write(label);
1917
- let input = "";
1918
- const stdin = process.stdin;
1919
- const wasRaw = stdin.isRaw;
1920
- if (!stdin.isTTY) {
1921
- reject(
1922
- new Error(
1923
- "Cannot prompt for input: stdin is not a TTY.\nSet your API key via environment variable instead:\n ANTHROPIC_API_KEY=<key> robota\n OPENAI_API_KEY=<key> robota"
1924
- )
1925
- );
1926
- return;
1927
- }
1928
- stdin.setRawMode(true);
1929
- stdin.resume();
1930
- stdin.setEncoding("utf8");
1931
- const onData = (data) => {
1932
- for (const ch of data) {
1933
- if (ch === "\r" || ch === "\n") {
1934
- stdin.removeListener("data", onData);
1935
- stdin.setRawMode(wasRaw ?? false);
1936
- stdin.pause();
1937
- process.stdout.write("\n");
1938
- resolve3(input.trim());
1939
- return;
1940
- } else if (ch === "\x7F" || ch === "\b") {
1941
- if (input.length > 0) {
1942
- input = input.slice(0, -1);
1943
- process.stdout.write("\b \b");
1944
- }
1945
- } else if (ch === "") {
1946
- stdin.removeListener("data", onData);
1947
- stdin.setRawMode(wasRaw ?? false);
1948
- stdin.pause();
1949
- process.stdout.write("\n");
1950
- process.exit(0);
1951
- } else if (ch.charCodeAt(0) >= PRINTABLE_ASCII_START) {
1952
- input += ch;
1953
- process.stdout.write(masked ? "*" : ch);
1954
- }
1955
- }
1956
- };
1957
- stdin.on("data", onData);
1958
- });
1959
- }
1960
- function readTaskFilePrompt(cwd, taskFile) {
1961
- const taskPath = resolve2(cwd, taskFile);
1962
- const content = readFileSync7(taskPath, "utf8").trim();
1963
- if (content.length === 0) {
1964
- throw new Error(`Task file is empty: ${taskFile}`);
1965
- }
1966
- return `Task file (${taskFile}):
1967
- ${content}`;
1968
- }
1969
- function resetConfig() {
1970
- const userPath = getUserSettingsPath();
1971
- if (deleteSettings(userPath)) {
1972
- process.stdout.write(`Deleted ${userPath}
1973
- `);
1974
- } else {
1975
- process.stdout.write("No user settings found.\n");
1976
- }
1977
- }
1978
- function createDefaultCliCommandModules({
1979
- cwd,
1980
- providerDefinitions
1981
- }) {
1982
- return [
1983
- createSkillsCommandModule({ cwd }),
1984
- createHelpCommandModule(),
1985
- createAgentCommandModule(),
1986
- createModelCommandModule({
1987
- providerDefinitions,
1988
- settings: {
1989
- readMergedSettings: () => readMergedProviderSettings(cwd)
1990
- }
1991
- }),
1992
- createPermissionsCommandModule(),
1993
- createModeCommandModule(),
1994
- createLanguageCommandModule(),
1995
- createBackgroundCommandModule(),
1996
- createMemoryCommandModule(),
1997
- createUserLocalCommandModule(),
1998
- createCompactCommandModule(),
1999
- createContextCommandModule(),
2000
- createExitCommandModule(),
2001
- createSessionCommandModule(),
2002
- createResetCommandModule(),
2003
- createRewindCommandModule(),
2004
- createStatusLineCommandModule(),
2005
- createPluginCommandModule(),
2006
- createSettingsCommandModule(),
2007
- createProviderCommandModule({
2008
- providerDefinitions,
2009
- settings: {
2010
- readMergedSettings: () => readMergedProviderSettings(cwd),
2011
- readTargetSettings: () => readSettings(resolveProviderSettingsWriteTargetPath(cwd)),
2012
- writeTargetSettings: (settings) => writeSettings(resolveProviderSettingsWriteTargetPath(cwd), settings)
2013
- }
2014
- })
2015
- ];
2016
- }
2017
- function buildCommandSetup(cwd, args, options, version) {
2018
- const commandHostAdapters = {
2019
- settings: {
2020
- read: () => readSettings(getUserSettingsPath()),
2021
- write: (settings) => writeSettings(getUserSettingsPath(), settings)
2022
- },
2023
- plugin: createCliPluginCommandAdapter(cwd)
2024
- };
2025
- const providerDefinitions = options.providerDefinitions ?? DEFAULT_PROVIDER_DEFINITIONS;
2026
- const commandModules = [
2027
- ...createDefaultCliCommandModules({ cwd, providerDefinitions }),
2028
- ...options.commandModules ?? []
2029
- ];
2030
- const startupUpdateNoticePromise = shouldRunStartupCliUpdateCheck(args) ? getStartupCliUpdateNotice({ currentVersion: version }) : void 0;
2031
- return { commandHostAdapters, providerDefinitions, commandModules, startupUpdateNoticePromise };
2032
- }
2033
- function buildAppendSystemPrompt(cwd, args) {
2034
- const appendParts = [];
2035
- if (args.appendSystemPrompt) appendParts.push(args.appendSystemPrompt);
2036
- if (args.taskFile) {
2037
- try {
2038
- appendParts.push(readTaskFilePrompt(cwd, args.taskFile));
2039
- } catch (error) {
2040
- process.stderr.write(`${error instanceof Error ? error.message : String(error)}
2041
- `);
2042
- process.exit(1);
2043
- }
2044
- }
2045
- if (args.jsonSchema)
2046
- appendParts.push(
2047
- `Respond with valid JSON only, matching this JSON schema:
2048
- ${args.jsonSchema}`
2049
- );
2050
- return appendParts.length > 0 ? appendParts.join("\n\n") : void 0;
2051
- }
2052
- async function runPrintMode(cwd, args, provider, sessionStore, backgroundTaskRunners, subagentRunnerFactory, commandModules, commandHostAdapters) {
2053
- let prompt = args.positional.join(" ").trim();
2054
- if (!prompt && !process.stdin.isTTY) {
2055
- const chunks = [];
2056
- for await (const chunk of process.stdin) {
2057
- chunks.push(chunk);
2058
- }
2059
- prompt = Buffer.concat(chunks).toString("utf-8").trim();
2060
- }
2061
- if (!prompt) {
2062
- process.stderr.write("Print mode (-p) requires a prompt argument.\n");
2063
- process.exit(1);
2064
- }
2065
- const appendSystemPrompt = buildAppendSystemPrompt(cwd, args);
2066
- if (args.systemPrompt) {
2067
- process.stderr.write("Warning: --system-prompt is not yet functional and will be ignored.\n");
2068
- }
2069
- const session = new InteractiveSession({
2070
- cwd,
2071
- provider,
2072
- permissionMode: args.permissionMode ?? "bypassPermissions",
2073
- maxTurns: args.maxTurns,
2074
- sessionStore: args.noSessionPersistence ? void 0 : sessionStore,
2075
- sessionName: args.sessionName,
2076
- bare: args.bare || void 0,
2077
- allowedTools: args.allowedTools ? args.allowedTools.split(",").map((t) => t.trim()).filter((t) => t.length > 0) : void 0,
2078
- appendSystemPrompt,
2079
- backgroundTaskRunners,
2080
- subagentRunnerFactory,
2081
- commandModules,
2082
- commandHostAdapters
2083
- });
2084
- const transport = createHeadlessTransport({
2085
- outputFormat: args.outputFormat ?? "text",
2086
- prompt
2087
- });
2088
- session.attachTransport(transport);
2089
- await transport.start();
2090
- await session.shutdown({ reason: "prompt_input_exit", message: "Headless transport complete" });
2091
- process.exit(transport.getExitCode());
2092
- }
2093
- async function startCli(options = {}) {
2094
- const args = parseCliArgs();
2095
- const version = readVersion();
2096
- if (args.help) {
2097
- printHelp();
2098
- return;
2099
- }
2100
- if (args.version) {
2101
- process.stdout.write(`robota ${version}
2102
- `);
2103
- return;
2104
- }
2105
- if (args.checkUpdate) {
2106
- const result = await checkForCliUpdate({ currentVersion: version, force: true });
2107
- const message = formatCliUpdateCheckMessage(result);
2108
- if (result.status === "error") {
2109
- process.stderr.write(`${message}
2110
- `);
2111
- process.exit(1);
2112
- }
2113
- process.stdout.write(`${message}
2114
- `);
2115
- return;
2116
- }
2117
- if (args.reset) {
2118
- resetConfig();
2119
- return;
2120
- }
2121
- const cwd = process.cwd();
2122
- if (await runUserLocalDirectCommandIfRequested(args, cwd)) {
2123
- return;
2124
- }
2125
- const { commandHostAdapters, providerDefinitions, commandModules, startupUpdateNoticePromise } = buildCommandSetup(cwd, args, options, version);
2126
- if (args.configure) {
2127
- await runInteractiveProviderSetup(cwd, args, promptInput, providerDefinitions);
2128
- return;
2129
- }
2130
- if (handleProviderConfigurationArgs(cwd, args, providerDefinitions)) {
2131
- return;
2132
- }
2133
- try {
2134
- await ensureConfig(cwd, args, promptInput, providerDefinitions);
2135
- } catch (error) {
2136
- process.stderr.write(`${error instanceof Error ? error.message : String(error)}
2137
- `);
2138
- process.exit(1);
2139
- }
2140
- const providerOptions = args.provider ? { providerOverride: args.provider, providerDefinitions } : { providerDefinitions };
2141
- const activeProviderSettings = readMergedProviderSettings(cwd);
2142
- const providerProfileName = args.provider ?? activeProviderSettings.currentProvider;
2143
- const providerSettings = readProviderSettings(cwd, providerOptions);
2144
- const modelId = args.model ?? providerSettings.model;
2145
- const provider = createProviderFromSettings(cwd, args.model, providerOptions);
2146
- const backgroundTaskRunners = [createManagedShellProcessRunner()];
2147
- const paths = projectPaths(cwd);
2148
- const subagentRunnerFactory = createChildProcessSubagentRunnerFactory({
2149
- providerConfig: { ...providerSettings, model: modelId },
2150
- logsDir: paths.logs
2151
- });
2152
- const sessionStore = createProjectSessionStore(cwd);
2153
- let resumeSessionId;
2154
- let showSessionPickerOnStart = false;
2155
- if (args.continueMode) {
2156
- resumeSessionId = resolveLatestSessionId(sessionStore, cwd);
2157
- } else if (args.resumeId !== void 0) {
2158
- if (args.resumeId === "") {
2159
- showSessionPickerOnStart = true;
2160
- } else {
2161
- resumeSessionId = resolveSessionIdByIdOrName(sessionStore, args.resumeId);
2162
- if (resumeSessionId === void 0) {
2163
- process.stderr.write(`Session not found: ${args.resumeId}
2164
- `);
2165
- process.exit(1);
2166
- }
2167
- }
2168
- }
2169
- if (args.printMode) {
2170
- await runPrintMode(
2171
- cwd,
2172
- args,
2173
- provider,
2174
- sessionStore,
2175
- backgroundTaskRunners,
2176
- subagentRunnerFactory,
2177
- commandModules,
2178
- commandHostAdapters
2179
- );
2180
- return;
2181
- }
2182
- const tuiTransport = new TuiTransport({
2183
- cwd,
2184
- provider,
2185
- providerOverride: args.provider,
2186
- providerProfileName,
2187
- providerType: providerSettings.name,
2188
- modelId,
2189
- language: args.language,
2190
- permissionMode: args.permissionMode,
2191
- maxTurns: args.maxTurns,
2192
- version,
2193
- sessionStore: args.noSessionPersistence ? void 0 : sessionStore,
2194
- resumeSessionId,
2195
- showSessionPickerOnStart,
2196
- forkSession: args.forkSession,
2197
- sessionName: args.sessionName,
2198
- backgroundTaskRunners,
2199
- subagentRunnerFactory,
2200
- commandModules,
2201
- commandHostAdapters,
2202
- startupUpdateNotice: startupUpdateNoticePromise ? startupUpdateNoticePromise.then((n) => n ? formatCliUpdateNotice(n) : void 0) : void 0,
2203
- transportRegistry: createTransportRegistry(),
2204
- cliAdapter: createTuiCliAdapter(),
2205
- reloadPluginCommandSource
2206
- });
2207
- await tuiTransport.start();
2208
- process.exit(0);
2209
- }
2210
- function createTuiCliAdapter() {
2211
- return {
2212
- getUserSettingsPath: () => getUserSettingsPath(),
2213
- readSettings: (path) => readSettings(path),
2214
- writeSettings: (path, settings) => writeSettings(path, settings),
2215
- deleteSettings: (path) => deleteSettings(path),
2216
- applyStatusLineSettings: (path, patch) => applyStatusLineSettings(path, patch),
2217
- reloadPluginCommandSource: (registry) => {
2218
- reloadPluginCommandSource(registry);
2219
- },
2220
- applyActiveModelChange: (cwd, modelId, options) => {
2221
- applyActiveModelChange(cwd, modelId, options);
2222
- return { applied: true };
2223
- },
2224
- getGitBranch: (cwd) => resolveGitBranch(cwd)
2225
- };
2226
- }
2227
- function createTransportRegistry() {
2228
- const registry = new TransportRegistry(getUserSettingsPath());
2229
- registry.register(new WsTransport());
2230
- return registry;
2231
- }
2232
-
2233
- // src/bin.ts
2234
- process.on("uncaughtException", (err) => {
2235
- const msg = err.message ?? "";
2236
- const isLikelyIME = msg.includes("string-width") || msg.includes("setCursorPosition") || msg.includes("getStringWidth") || msg.includes("slice") || msg.includes("charCodeAt");
2237
- if (isLikelyIME) {
2238
- process.stderr.write(`[robota] IME error suppressed: ${msg}
2239
- `);
2240
- return;
2241
- }
2242
- throw err;
2243
- });
2244
- startCli().catch((err) => {
2245
- const message = err instanceof Error ? err.message : String(err);
2246
- process.stderr.write(message + "\n");
2247
- process.exit(1);
2248
- });
30
+ `)}function $e(e){if(e!==void 0)return w.includes(e)||(process.stderr.write(`Invalid --output-format "${e}". Valid: ${w.join(` | `)}\n`),process.exit(1)),e}function et(e){if(e!==void 0)return C.includes(e)||(process.stderr.write(`Invalid --permission-mode "${e}". Valid: ${C.join(` | `)}\n`),process.exit(1)),e}function tt(e){if(e===void 0)return;let t=parseInt(e,10);return(isNaN(t)||t<=0)&&(process.stderr.write(`Invalid --max-turns "${e}". Must be a positive integer.\n`),process.exit(1)),t}function nt(){let{values:e,positionals:t}=Ie({allowPositionals:!0,options:{help:{type:`boolean`,short:`h`,default:!1},p:{type:`boolean`,short:`p`,default:!1},continue:{type:`boolean`,short:`c`,default:!1},resume:{type:`string`,short:`r`},model:{type:`string`},language:{type:`string`},"permission-mode":{type:`string`},"max-turns":{type:`string`},"fork-session":{type:`boolean`,default:!1},name:{type:`string`,short:`n`},"output-format":{type:`string`},format:{type:`string`},summary:{type:`string`},source:{type:`string`},"system-prompt":{type:`string`},"append-system-prompt":{type:`string`},"task-file":{type:`string`},version:{type:`boolean`,default:!1},reset:{type:`boolean`,default:!1},bare:{type:`boolean`,default:!1},"allowed-tools":{type:`string`},"no-session-persistence":{type:`boolean`,default:!1},"json-schema":{type:`string`},configure:{type:`boolean`,default:!1},"configure-provider":{type:`string`},provider:{type:`string`},type:{type:`string`},"base-url":{type:`string`},"api-key":{type:`string`},"api-key-env":{type:`string`},"set-current":{type:`boolean`,default:!1},"settings-scope":{type:`string`},"check-update":{type:`boolean`,default:!1},"disable-update-check":{type:`boolean`,default:!1}}});return{positional:t,help:e.help??!1,printMode:e.p??!1,continueMode:e.continue??!1,resumeId:e.resume,model:e.model,language:e.language,permissionMode:et(e[`permission-mode`]),maxTurns:tt(e[`max-turns`]),forkSession:e[`fork-session`]??!1,sessionName:e.name,outputFormat:$e(e[`output-format`]),format:e.format,summary:e.summary,source:e.source,systemPrompt:e[`system-prompt`],appendSystemPrompt:e[`append-system-prompt`],taskFile:e[`task-file`],version:e.version??!1,reset:e.reset??!1,bare:e.bare??!1,allowedTools:e[`allowed-tools`],noSessionPersistence:e[`no-session-persistence`]??!1,jsonSchema:e[`json-schema`],configure:e.configure??!1,configureProvider:e[`configure-provider`],provider:e.provider,providerType:e.type,baseURL:e[`base-url`],apiKey:e[`api-key`],apiKeyEnv:e[`api-key-env`],setCurrent:e[`set-current`]??!1,settingsScope:e[`settings-scope`],checkUpdate:e[`check-update`]??!1,disableUpdateCheck:e[`disable-update-check`]??!1}}function T(){return u(process.env.HOME??process.env.USERPROFILE??`/`,`.robota`,`settings.json`)}function E(e){if(!n(e))return{};let t=a(e,`utf8`);try{return JSON.parse(t)}catch{return process.stderr.write(`Warning: corrupt settings file at ${e}, resetting to defaults\n`),{}}}function D(e,t){i(c(e),{recursive:!0}),s(e,JSON.stringify(t,null,2)+`
31
+ `,`utf8`)}function O(e){return n(e)?(o(e),!0):!1}const k=[He(),Ke(),Ge(),We(),qe(),Ue()];function A(e){let t=rt();return[u(t,`.robota`,`settings.json`),u(t,`.claude`,`settings.json`),u(e,`.robota`,`settings.json`),u(e,`.robota`,`settings.local.json`),u(e,`.claude`,`settings.json`),u(e,`.claude`,`settings.local.json`)]}function rt(){return process.env.HOME??process.env.USERPROFILE??`/`}function j(e){return oe(A(e))}function M(e,t={}){let n=ce(j(e),t.providerOverride,N(t));if(n!==void 0)return n;throw Error("No provider configuration found. Run `robota` to set up.")}function it(e,t,n={}){let r=N(n),i=M(e,{...n,providerDefinitions:r}),a=t??i.model;return Be({...i,model:a},r)}function N(e){return e.providerDefinitions??k}function P(e,t={}){let n=t.settingsPaths??A(e),r=lt(n)??n[0];if(r===void 0)throw Error(`No settings path available for provider update`);return r}function F(e){return E(e)}function I(e,t,n={}){let r=ie(F(e),ee(t,n));return D(e,r),r}function at(e,t,n={}){let r=F(e),i=r.providers?.[t]!==void 0,a=n.knownProviders?.[t]!==void 0,o=i||a?{...r,currentProvider:t}:de(r,t);return D(e,o),o}function ot(e,t,n={}){let r=n.settingsPaths??A(e),i=se(r),a=n.providerOverride??i.currentProvider;if(typeof a!=`string`)throw Error(`Cannot update model: no active provider profile. Set "currentProvider" in settings.`);return st(r,a,t)}function st(e,t,n){let r=ct(e,t)??e[0];if(r===void 0)throw Error(`No settings path available for model update`);let i=F(r),a=i.providers??{},o=a[t]??{},s={...i,providers:{...a,[t]:{...o,model:n}}};return D(r,s),{settingsPath:r,settings:s,profileName:t}}function ct(e,t){for(let n=e.length-1;n>=0;--n){let r=e[n];if(r!==void 0&&F(r).providers?.[t]!==void 0)return r}}function lt(e){for(let t=e.length-1;t>=0;--t){let n=e[t];if(n!==void 0&&F(n).currentProvider!==void 0)return n}}function L(e,t){if(t===void 0||t===`user`)return T();if(t===`project-local`)return u(e,`.robota`,`settings.local.json`);throw Error(`Invalid --settings-scope "${t}". Valid: user | project-local`)}function ut(e,t,n=k){let r=L(e,t.settingsScope);return t.configureProvider?(I(r,ft(t),{providerDefinitions:n}),process.stdout.write(`Provider profile saved to ${r}\n`),!t.printMode&&t.positional.length===0):t.provider&&t.setCurrent?(at(t.settingsScope===void 0?P(e):r,t.provider,{knownProviders:j(e).providers}),process.stdout.write(`Current provider set to ${t.provider}\n`),!t.printMode&&t.positional.length===0):!1}async function dt(e,t,n,r=k){let i=j(e);if(b(t.provider===void 0?i:{...i,currentProvider:t.provider},r)===`valid`)return;if(!ht())throw Error(z(r));await R(e,pt(e,t),n,r);let a=j(e);if(b(t.provider===void 0?a:{...a,currentProvider:t.provider},r)!==`valid`)throw Error(z(r))}async function R(e,t,n,r=k){let i=Pe(await n(Ne(r)),r),a=L(e,t.settingsScope);I(a,await Fe(i,n,r,{existingProfileNames:Object.keys(j(e).providers??{})}),{providerDefinitions:r});let o=await n(` Response language (ko/en/ja/zh, default: en): `);if(o){let e=E(a);e.language=o,D(a,e)}process.stdout.write(`\n Config saved to ${a}\n\n`)}function ft(e){let t=e.providerType??e.configureProvider;if(!e.configureProvider||!t)throw Error(`--configure-provider requires a provider profile and --type`);return{profile:e.configureProvider,type:t,...e.model!==void 0&&{model:e.model},...e.apiKey!==void 0&&{apiKey:e.apiKey},...e.apiKeyEnv!==void 0&&{apiKeyEnv:e.apiKeyEnv},...e.baseURL!==void 0&&{baseURL:e.baseURL},setCurrent:e.setCurrent}}function pt(e,t){if(t.settingsScope!==void 0||t.provider!==void 0)return t;let n=mt(A(e));if(n===void 0)return t;let r=u(e,`.robota`,`settings.json`),i=u(e,`.robota`,`settings.local.json`);return n===r||n===i?{...t,settingsScope:`project-local`}:t}function mt(e){for(let t=e.length-1;t>=0;--t){let n=e[t];if(n!==void 0&&typeof E(n).currentProvider==`string`)return n}}function ht(){return process.stdin.isTTY===!0&&process.stdout.isTTY===!0}function z(e=k){return[`No provider configuration found.`,"Run `robota --configure` in an interactive terminal, or configure a provider:",`Supported providers: ${Je(e)}`,...e.map(gt)].join(`
32
+ `)}function gt(e){return` ${[`robota --configure-provider ${e.type}`,`--type ${e.type}`,...e.defaults?.baseURL===void 0?[]:[`--base-url <url>`],`--model <model>`,...e.requiresApiKey===!0?[`--api-key-env <ENV_NAME>`]:[],`--set-current`].join(` `)}`}var _t=class{entries=new Map;settingsPath;constructor(e){this.settingsPath=e}register(e){this.entries.set(e.name,e)}getAll(){let e=this.readTransportSettings();return Array.from(this.entries.values()).map(t=>({transport:t,config:this.resolveConfig(t,e[t.name])}))}getEnabled(){return this.getAll().filter(e=>e.config.enabled).map(e=>e.transport)}async setEnabled(e,t){let n=E(this.settingsPath),r=n.transports??{};r[e]={...r[e]??{},enabled:t},n.transports=r,D(this.settingsPath,n)}async setOptions(e,t){let n=E(this.settingsPath),r=n.transports??{};r[e]={...r[e]??{},options:t},n.transports=r,D(this.settingsPath,n)}async startAll(e){let t=this.getEnabled();for(let n of t)n.attach(e),await n.start()}async stopAll(){for(let e of this.entries.values())await e.stop()}resolveConfig(e,t){return{enabled:t?.enabled??e.defaultEnabled,options:t?.options??{}}}readTransportSettings(){let e=E(this.settingsPath).transports;return!e||typeof e!=`object`||Array.isArray(e)?{}:e}};function vt(e){return typeof e==`object`&&!!e}function B(e,t){return typeof e[t]==`string`}function yt(e){if(!vt(e)||!B(e,`type`))return!1;switch(e.type){case`ready`:return!0;case`text_delta`:return B(e,`delta`);case`tool_start`:return B(e,`toolName`);case`tool_end`:return B(e,`toolName`)&&typeof e.success==`boolean`;case`result`:return B(e,`output`);case`error`:return B(e,`message`);case`cancelled`:return e.reason===void 0||typeof e.reason==`string`;default:return!1}}function bt(e,t,n,r,i){switch(e.type){case`ready`:t();break;case`result`:n(e.output);break;case`error`:r(new x(`runner`,e.message));break;case`cancelled`:r(new x(`runner`,e.reason??`Subagent worker cancelled`));break;case`text_delta`:i?.({type:`background_task_text_delta`,delta:e.delta});break;case`tool_start`:i?.({type:`background_task_tool_start`,toolName:e.toolName,firstArg:xt(e.toolArgs)});break;case`tool_end`:i?.({type:`background_task_tool_end`,toolName:e.toolName,success:e.success});break;default:r(new x(`runner`,`Unhandled subagent worker message`))}}function xt(e){if(!e)return;let t=Object.values(e)[0];if(t!==void 0)return typeof t==`object`?JSON.stringify(t):String(t)}function V(e,t){return new Promise((n,r)=>{if(!e.connected){r(new x(`crash`,`Subagent worker IPC channel is closed`));return}e.send(t,e=>{if(e){r(e);return}n()})})}async function H(e,t){e.child.connected&&await V(e.child,{type:`cancel`,reason:t}).catch(()=>void 0),e.killTimer=setTimeout(()=>{e.child.killed||e.child.kill(`SIGTERM`)},e.killGraceMs)}function St(e){return new Promise((t,n)=>{new Ct(e,t,n).start()})}var Ct=class{options;resolve;reject;settled=!1;started=!1;timeoutTimer;constructor(e,t,n){this.options=e,this.resolve=t,this.reject=n,this.timeoutTimer=Tt(this.options.runtime,e=>this.rejectOnce(e))}start(){let{child:e}=this.options.runtime;e.on(`message`,this.onMessage),e.on(`error`,this.onError),e.on(`exit`,this.onExit),e.once(`spawn`,()=>{setImmediate(this.startWorker)})}startWorker=()=>{if(this.started)return;this.started=!0;let{child:e}=this.options.runtime;V(e,{type:`start`,payload:this.options.payload}).catch(e=>{this.rejectOnce(e instanceof Error?e:Error(String(e)))})};onMessage=e=>{if(!yt(e)){this.rejectOnce(new x(`runner`,`Received malformed subagent worker message`));return}let{job:t}=this.options.runtime;bt(e,this.startWorker,this.resolveOnce,this.rejectOnce,t.emit)};onError=e=>{this.rejectOnce(new x(`crash`,e.message))};onExit=(e,t)=>{this.settled||this.rejectOnce(new x(`crash`,Dt(e,t)))};resolveOnce=e=>{if(this.settled)return;this.settled=!0,this.clearTimers(),this.cleanup();let{runtime:t,resolveTranscriptPath:n}=this.options;this.resolve(Et(t.job,e,n))};rejectOnce=e=>{this.settled||(this.settled=!0,this.clearTimers(),this.cleanup(),this.reject(e))};clearTimers(){this.timeoutTimer&&clearTimeout(this.timeoutTimer),this.options.runtime.killTimer&&clearTimeout(this.options.runtime.killTimer)}cleanup(){let{child:e}=this.options.runtime;e.off(`message`,this.onMessage),e.off(`error`,this.onError),e.off(`exit`,this.onExit)}};function wt(e){let t=!1,n=()=>{};return{promise:new Promise((e,t)=>{n=t}),reject(r){t||(t=!0,n(new x(`runner`,r??`Subagent job cancelled: ${e}`)))}}}function Tt(e,t){if(e.job.request.timeoutMs)return setTimeout(()=>{H(e,`Subagent worker timed out`),t(new x(`timeout`,`Subagent worker timed out`))},e.job.request.timeoutMs)}function Et(e,t,n){let r=n(e);return{jobId:e.jobId,output:t,...r?{metadata:{transcriptPath:r,logPath:r}}:{}}}function Dt(e,t){return`Subagent worker exited before result: ${t===null?`exit code ${e===null?`unknown`:e}`:`signal ${t}`}`}function Ot(e={}){return t=>{let n=new kt(t,e);return e.worktreeIsolation===!1?n:Ve({runner:n,worktreeAdapter:e.worktreeAdapter??ze(),hooks:t.config.hooks,hookTypeExecutors:t.hookTypeExecutors})}}var kt=class{deps;workerPath;execArgv;killGraceMs;providerConfig;env;logsDir;constructor(e,t={}){this.deps=e,this.workerPath=t.workerPath??Nt(),this.execArgv=t.execArgv,this.killGraceMs=t.killGraceMs??2e3,this.providerConfig=t.providerConfig,this.env=t.env,this.logsDir=t.logsDir}start(e){let n=t(this.workerPath,[],{cwd:e.request.cwd,env:{...process.env,...this.env??{}},execArgv:this.execArgv??Pt(this.workerPath),stdio:[`ignore`,`ignore`,`ignore`,`ipc`]}),r={job:e,child:n,killGraceMs:this.killGraceMs},i=St({runtime:r,payload:this.createStartPayload(e),resolveTranscriptPath:e=>this.resolveTranscriptPath(e)}),a=wt(e.jobId);i.catch(()=>void 0);let o=Promise.race([i,a.promise]),s=this.resolveTranscriptPath(e);return{jobId:e.jobId,...n.pid!==void 0&&{pid:n.pid},...s!==void 0&&{transcriptPath:s,logPath:s},result:o,cancel:async e=>{a.reject(e),await H(r,e)},send:async e=>{await V(n,{type:`send`,prompt:e})},...s!==void 0&&{readLog:async t=>Ft(e.jobId,s,t)}}}createStartPayload(e){let t=At(e.request.type,this.deps.customAgentRegistry);return{jobId:e.jobId,request:e.request,agentDefinition:jt(t,e),parentConfig:this.deps.config,parentContext:this.deps.context,providerProfile:Mt(this.providerConfig,this.deps,e),permissionMode:this.deps.permissionMode,...this.logsDir?{logsDir:this.logsDir}:{}}}resolveTranscriptPath(e){if(this.logsDir)return u(this.logsDir,e.request.parentSessionId,`subagents`,`${e.jobId}.jsonl`)}};function At(e,t){let n=t?.(e)??re(e);if(!n)throw new x(`validation`,`Unknown agent type: ${e}`);return n}function jt(e,t){return{...e,...t.request.model?{model:t.request.model}:{},...t.request.allowedTools?{tools:t.request.allowedTools}:{},...t.request.disallowedTools?{disallowedTools:t.request.disallowedTools}:{}}}function Mt(e,t,n){let r=e??t.config.provider;return{profileName:t.config.currentProvider,type:r.name,model:n.request.model??r.model,apiKey:r.apiKey,baseURL:r.baseURL,timeout:r.timeout,options:r.options}}function Nt(){let e=process.argv[1]??``,t=e?c(e):process.cwd(),r=e.endsWith(`.ts`)||e.endsWith(`.tsx`)?`.ts`:`.js`,i=[u(t,`subagents`,`child-process-subagent-worker${r}`),u(t,`child-process-subagent-worker${r}`)];for(let e of i)if(n(e))return e;return i[0]}function Pt(e){return!e.endsWith(`.ts`)||process.execArgv.some(e=>e.includes(`tsx`))?process.execArgv:[...process.execArgv,`--import`,`tsx`]}function Ft(e,t,r){return n(t)?Le(e,a(t,`utf8`).split(/\r?\n/).filter(Boolean),r):{taskId:e,cursor:r,lines:[]}}function It(e,t){let n=U(e),r=U(t);if(n===void 0||r===void 0)return Math.sign(e.localeCompare(t));let i=G(n.major,r.major)||G(n.minor,r.minor)||G(n.patch,r.patch);return i===0?Rt(n.prerelease,r.prerelease):i}function Lt(e,t){return It(e,t)>0}function U(e){let[t,n]=(e.trim().replace(/^v/,``).split(`+`)[0]??``).split(`-`,2),[r,i,a]=t.split(`.`),o=W(r),s=W(i),c=W(a);if(!(o===void 0||s===void 0||c===void 0))return{major:o,minor:s,patch:c,prerelease:n?n.split(`.`):[]}}function W(e){if(!(e===void 0||!/^\d+$/.test(e)))return Number(e)}function G(e,t){return Math.sign(e-t)}function Rt(e,t){if(e.length===0&&t.length===0)return 0;if(e.length===0)return 1;if(t.length===0)return-1;let n=Math.max(e.length,t.length);for(let r=0;r<n;r+=1){let n=e[r],i=t[r];if(n===void 0)return-1;if(i===void 0)return 1;let a=zt(n,i);if(a!==0)return a}return 0}function zt(e,t){let n=W(e),r=W(t);return n!==void 0&&r!==void 0?G(n,r):n===void 0?r===void 0?Math.sign(e.localeCompare(t)):1:-1}function Bt(e=process.env.HOME??process.env.USERPROFILE??`/`){return u(e,`.robota`,`update-check.json`)}function Vt(e){if(n(e))try{return Xt(JSON.parse(a(e,`utf8`)))}catch{return}}function Ht(e,t){i(c(e),{recursive:!0}),s(e,JSON.stringify(t,null,2)+`
33
+ `,`utf8`)}async function K(e){if(e.disabled===!0)return{status:`skipped`,reason:`disabled`};let t=e.packageName??`@robota-sdk/agent-cli`,n=e.cachePath??Bt(),r=e.now??new Date,i=e.ttlMs??864e5;if(e.force!==!0){let a=Vt(n);if(a!==void 0&&qt(a,r,i,t))return Kt(a,e.currentVersion)}try{let i=await Jt({fetchImpl:e.fetchImpl??fetch,packageName:t,registryUrl:e.registryUrl??`https://registry.npmjs.org`,timeoutMs:e.timeoutMs??1500});return q(n,{packageName:t,checkedAt:r.toISOString(),currentVersion:e.currentVersion,latestVersion:i}),Y(e.currentVersion,i)}catch(i){let a=i instanceof Error?i.message:String(i);return q(n,{packageName:t,checkedAt:r.toISOString(),currentVersion:e.currentVersion,errorMessage:a}),{status:`error`,errorMessage:a}}}function q(e,t){try{Ht(e,t)}catch{}}async function Ut(e){let t=await K(e);return t.status===`update_available`?t.notice:void 0}function Wt(e){return e.printMode===!1&&e.disableUpdateCheck===!1}function J(e){return[`Robota update available: ${e.currentVersion} -> ${e.latestVersion}.`,`Run ${e.installCommand}`].join(` `)}function Gt(e){return e.status===`update_available`?J(e.notice):e.status===`current`?`Robota is up to date (${e.currentVersion}).`:e.status===`skipped`?`Robota update check skipped.`:`Robota update check failed: ${e.errorMessage}`}function Kt(e,t){return e.errorMessage===void 0?e.latestVersion===void 0?{status:`error`,errorMessage:`Cached update check has no latest version`}:Y(t,e.latestVersion):{status:`error`,errorMessage:e.errorMessage}}function Y(e,t){return Lt(t,e)?{status:`update_available`,notice:{currentVersion:e,latestVersion:t,installCommand:`npm install -g '@robota-sdk/agent-cli@latest'`}}:{status:`current`,currentVersion:e,latestVersion:t}}function qt(e,t,n,r){if(e.packageName!==r)return!1;let i=Date.parse(e.checkedAt);return Number.isFinite(i)?t.getTime()-i<n:!1}async function Jt(e){let t=new AbortController,n=setTimeout(()=>t.abort(),e.timeoutMs);try{let n=Yt(e.registryUrl,e.packageName),r=await e.fetchImpl(n,{headers:{accept:`application/json`},signal:t.signal});if(!r.ok)throw Error(`registry responded with HTTP ${r.status}`);let i=(await r.json())[`dist-tags`]?.latest;if(typeof i!=`string`||i.trim().length===0)throw Error(`registry metadata is missing dist-tags.latest`);return i}finally{clearTimeout(n)}}function Yt(e,t){return`${e.replace(/\/+$/,``)}/${encodeURIComponent(t)}`}function Xt(e){if(!Zt(e))return;let t=e;if(typeof t.packageName==`string`&&typeof t.checkedAt==`string`&&typeof t.currentVersion==`string`&&(t.latestVersion===void 0||typeof t.latestVersion==`string`)&&(t.errorMessage===void 0||typeof t.errorMessage==`string`))return{packageName:t.packageName,checkedAt:t.checkedAt,currentVersion:t.currentVersion,...t.latestVersion!==void 0&&{latestVersion:t.latestVersion},...t.errorMessage!==void 0&&{errorMessage:t.errorMessage}}}function Zt(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}const X={...h};function Qt(e){let t=e.statusline;return en(t)?{enabled:typeof t.enabled==`boolean`?t.enabled:X.enabled,gitBranch:typeof t.gitBranch==`boolean`?t.gitBranch:X.gitBranch}:{...X}}function $t(e,t){let n=E(e),r={...Qt(n),...t};return n.statusline=r,D(e,n),r}function en(e){return typeof e==`object`&&!!e&&!Array.isArray(e)&&!(e instanceof Date)}function tn(e){try{let t=nn(e);if(!t)return;let n=a(u(t,`HEAD`),`utf8`).trim();if(!n)return;if(n.startsWith(`ref: `)){let e=n.slice(5).trim();return e.startsWith(`refs/heads/`)?e.slice(11):e}return n.slice(0,7)}catch{return}}function nn(e){let t=d(e),n=c(t);for(;n!==t;){let e=Z(u(t,`.git`),t);if(e)return e;t=n,n=c(t)}return Z(u(t,`.git`),t)}function Z(e,t){if(!n(e))return;let i=r(e);if(i.isDirectory())return e;if(!i.isFile())return;let o=a(e,`utf8`).trim();if(!o.startsWith(`gitdir:`))return;let s=o.slice(7).trim();return l(s)?s:d(t,s)}const Q=`plugin`;function rn(){return process.env.HOME??S()}function $(e){let t=new m(u(rn(),`.robota`,`plugins`));try{let n=t.loadPluginsSync();return n.length===0?(e.replaceSource(Q),0):(e.replaceSource(Q,new v(n)),n.length)}catch{return e.replaceSource(Q),0}}function an(t){let n=S(),r=u(n,`.robota`,`plugins`),i=u(n,`.robota`,`settings.json`),a=(t,n)=>e(t,{timeout:n.timeout,stdio:n.stdio??`pipe`}),o=new y(i),s=new _({pluginsDir:r,exec:a});return{cwd:t,marketplace:s,installer:new p({pluginsDir:r,settingsStore:o,marketplaceClient:s,exec:a}),loader:new m(r),settingsStore:o}}async function on(e){let t=await e.loader.loadAll(),n=e.settingsStore.getEnabledPlugins();return t.map(e=>{let t=e.pluginDir.split(`/`),r=t.indexOf(`cache`),i=r>=0?t[r+1]??``:``,a=i?`${e.manifest.name}@${i}`:e.manifest.name;return{name:a,description:e.manifest.description,enabled:n[a]!==!1&&n[e.manifest.name]!==!1}})}async function sn(e,t){let n;try{n=e.marketplace.fetchManifest(t)}catch{return[]}let r=e.installer.getInstalledPlugins(),i=new Set(Object.values(r).map(e=>e.pluginName));return n.plugins.map(e=>({name:e.name,description:e.description,installed:i.has(e.name)}))}async function cn(t,n,r){let[i,a]=n.split(`@`);if(!i||!a)throw Error(`Plugin ID must be in format: name@marketplace`);if(r===`project`){await new p({pluginsDir:u(t.cwd,`.robota`,`plugins`),settingsStore:t.settingsStore,marketplaceClient:t.marketplace,exec:(t,n)=>e(t,{timeout:n.timeout,stdio:n.stdio??`pipe`})}).install(i,a);return}await t.installer.install(i,a)}async function ln(e,t){let n=e.installer.getPluginsByMarketplace(t);for(let t of n)await e.installer.uninstall(`${t.pluginName}@${t.marketplace}`);e.marketplace.removeMarketplace(t)}function un(e){return e.marketplace.listMarketplaces().map(e=>({name:e.name,type:e.source.type}))}function dn(e){let t=an(e);return{listInstalled:()=>on(t),listAvailablePlugins:e=>sn(t,e),install:(e,n)=>cn(t,e,n),uninstall:async e=>t.installer.uninstall(e),enable:async e=>t.installer.enable(e),disable:async e=>t.installer.disable(e),marketplaceAdd:async e=>e.includes(`/`)&&!e.includes(`:`)?t.marketplace.addMarketplace({type:`github`,repo:e}):t.marketplace.addMarketplace({type:`git`,url:e}),marketplaceRemove:e=>ln(t,e),marketplaceUpdate:async e=>t.marketplace.updateMarketplace(e),marketplaceList:async()=>un(t),reloadPlugins:async()=>({loadedPluginCount:(await t.loader.loadAll()).length})}}async function fn(e,t){if(e.positional[0]!==`user-local`)return!1;let n=await Me({cwd:t,argv:e.positional.slice(1),format:e.format,summary:e.summary,source:e.source}),r=n.message.endsWith(`
34
+ `)?n.message:`${n.message}\n`;return n.success||(process.stderr.write(r),process.exit(1)),process.stdout.write(r),!0}function pn(){try{let e=c(f(import.meta.url)),t=[u(e,`..`,`..`,`package.json`),u(e,`..`,`package.json`)];for(let e of t)try{let t=a(e,`utf-8`),n=JSON.parse(t);if(n.version!==void 0&&n.name!==void 0)return n.version}catch{}return`0.0.0`}catch{return`0.0.0`}}function mn(e,t=!1){return new Promise((n,r)=>{process.stdout.write(e);let i=``,a=process.stdin,o=a.isRaw;if(!a.isTTY){r(Error(`Cannot prompt for input: stdin is not a TTY.
35
+ Set your API key via environment variable instead:
36
+ ANTHROPIC_API_KEY=<key> robota
37
+ OPENAI_API_KEY=<key> robota`));return}a.setRawMode(!0),a.resume(),a.setEncoding(`utf8`);let s=e=>{for(let r of e)if(r===`\r`||r===`
38
+ `){a.removeListener(`data`,s),a.setRawMode(o??!1),a.pause(),process.stdout.write(`
39
+ `),n(i.trim());return}else r===``||r===`\b`?i.length>0&&(i=i.slice(0,-1),process.stdout.write(`\b \b`)):r===``?(a.removeListener(`data`,s),a.setRawMode(o??!1),a.pause(),process.stdout.write(`
40
+ `),process.exit(0)):r.charCodeAt(0)>=32&&(i+=r,process.stdout.write(t?`*`:r))};a.on(`data`,s)})}function hn(e,t){let n=a(d(e,t),`utf8`).trim();if(n.length===0)throw Error(`Task file is empty: ${t}`);return`Task file (${t}):\n${n}`}function gn(){let e=T();O(e)?process.stdout.write(`Deleted ${e}\n`):process.stdout.write(`No user settings found.
41
+ `)}function _n({cwd:e,providerDefinitions:t}){return[ke({cwd:e}),_e(),fe(),xe({providerDefinitions:t,settings:{readMergedSettings:()=>j(e)}}),Se(),be(),ve(),pe(),ye(),je(),me(),he(),ge(),De(),Te(),Ee(),Ae(),Ce(),Oe(),we({providerDefinitions:t,settings:{readMergedSettings:()=>j(e),readTargetSettings:()=>E(P(e)),writeTargetSettings:t=>D(P(e),t)}})]}function vn(e,t,n,r){let i={settings:{read:()=>E(T()),write:e=>D(T(),e)},plugin:dn(e)},a=n.providerDefinitions??k;return{commandHostAdapters:i,providerDefinitions:a,commandModules:[..._n({cwd:e,providerDefinitions:a}),...n.commandModules??[]],startupUpdateNoticePromise:Wt(t)?Ut({currentVersion:r}):void 0}}function yn(e,t){let n=[];if(t.appendSystemPrompt&&n.push(t.appendSystemPrompt),t.taskFile)try{n.push(hn(e,t.taskFile))}catch(e){process.stderr.write(`${e instanceof Error?e.message:String(e)}\n`),process.exit(1)}return t.jsonSchema&&n.push(`Respond with valid JSON only, matching this JSON schema:\n${t.jsonSchema}`),n.length>0?n.join(`
42
+
43
+ `):void 0}async function bn(t,n,r,i,a,o,s,c){let l=n.positional.join(` `).trim();if(!l&&!process.stdin.isTTY){let e=[];for await(let t of process.stdin)e.push(t);l=Buffer.concat(e).toString(`utf-8`).trim()}l||(process.stderr.write(`Print mode (-p) requires a prompt argument.
44
+ `),process.exit(1));let u=yn(t,n);n.systemPrompt&&process.stderr.write(`Warning: --system-prompt is not yet functional and will be ignored.
45
+ `);let d=new g({cwd:t,provider:r,permissionMode:n.permissionMode??`bypassPermissions`,maxTurns:n.maxTurns,sessionStore:n.noSessionPersistence?void 0:i,sessionName:n.sessionName,bare:n.bare||void 0,allowedTools:n.allowedTools?n.allowedTools.split(`,`).map(e=>e.trim()).filter(e=>e.length>0):void 0,appendSystemPrompt:u,backgroundTaskRunners:a,subagentRunnerFactory:o,commandModules:s,commandHostAdapters:c,shellExec:t=>e(t,{timeout:5e3,encoding:`utf-8`,stdio:`pipe`}).trimEnd(),agentName:`robota-cli`}),f=Ye({outputFormat:n.outputFormat??`text`,prompt:l});d.attachTransport(f),await f.start(),await d.shutdown({reason:`prompt_input_exit`,message:`Headless transport complete`}),process.exit(f.getExitCode())}async function xn(t={}){let n=nt(),r=pn();if(n.help){Qe();return}if(n.version){process.stdout.write(`robota ${r}\n`);return}if(n.checkUpdate){let e=await K({currentVersion:r,force:!0}),t=Gt(e);e.status===`error`&&(process.stderr.write(`${t}\n`),process.exit(1)),process.stdout.write(`${t}\n`);return}if(n.reset){gn();return}let i=process.cwd();if(await fn(n,i))return;let{commandHostAdapters:a,providerDefinitions:o,commandModules:s,startupUpdateNoticePromise:c}=vn(i,n,t,r);if(n.configure){await R(i,n,mn,o);return}if(ut(i,n,o))return;try{await dt(i,n,mn,o)}catch(e){process.stderr.write(`${e instanceof Error?e.message:String(e)}\n`),process.exit(1)}let l=n.provider?{providerOverride:n.provider,providerDefinitions:o}:{providerDefinitions:o},u=j(i);n.provider??u.currentProvider;let d=M(i,l),f=n.model??d.model,p=it(i,n.model,l),m=Re(),h=ae(i),g=Ot({providerConfig:{...d,model:f},logsDir:h.logs}),_=te(i),v,y=!1;if(n.continueMode?v=le(_,i):n.resumeId!==void 0&&(n.resumeId===``?y=!0:(v=ue(_,n.resumeId),v===void 0&&(process.stderr.write(`Session not found: ${n.resumeId}\n`),process.exit(1)))),n.printMode){await bn(i,n,p,_,m,g,s,a);return}await new Ze({cwd:i,provider:p,providerOverride:n.provider,providerType:d.name,modelId:f,language:n.language,permissionMode:n.permissionMode,maxTurns:n.maxTurns,version:r,sessionStore:n.noSessionPersistence?void 0:_,resumeSessionId:v,showSessionPickerOnStart:y,forkSession:n.forkSession,sessionName:n.sessionName,backgroundTaskRunners:m,subagentRunnerFactory:g,commandModules:s,commandHostAdapters:a,shellExec:t=>e(t,{timeout:5e3,encoding:`utf-8`,stdio:`pipe`}).trimEnd(),startupUpdateNotice:c?c.then(e=>e?J(e):void 0):void 0,transportRegistry:Cn(),cliAdapter:Sn(o),reloadPluginCommandSource:$,agentName:`robota-cli`}).start(),process.exit(0)}function Sn(e){return{getUserSettingsPath:()=>T(),readSettings:e=>E(e),writeSettings:(e,t)=>D(e,t),deleteSettings:e=>O(e),applyStatusLineSettings:(e,t)=>$t(e,t),reloadPluginCommandSource:e=>{$(e)},applyActiveModelChange:(e,t,n)=>(ot(e,t,n),{applied:!0}),getGitBranch:e=>tn(e),getProviderDisplayName:t=>ne(e,t)?.displayName??t}}function Cn(){let e=new _t(T());return e.register(new Xe),e}process.on(`uncaughtException`,e=>{let t=e.message??``;if(t.includes(`string-width`)||t.includes(`setCursorPosition`)||t.includes(`getStringWidth`)||t.includes(`slice`)||t.includes(`charCodeAt`)){process.stderr.write(`[robota] IME error suppressed: ${t}\n`);return}throw e}),xn().catch(e=>{let t=e instanceof Error?e.message:String(e);process.stderr.write(t+`
46
+ `),process.exit(1)});export{};
47
+ //# sourceMappingURL=bin.js.map