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