@robota-sdk/agent-sdk 3.0.0-beta.54 → 3.0.0-beta.56
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 +34 -16
- package/dist/node/index.cjs +2552 -1184
- package/dist/node/index.d.cts +1286 -952
- package/dist/node/index.d.ts +1286 -952
- package/dist/node/index.js +2530 -1172
- package/package.json +5 -4
package/dist/node/index.cjs
CHANGED
|
@@ -32,6 +32,9 @@ var index_exports = {};
|
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
AgentExecutor: () => AgentExecutor,
|
|
34
34
|
BUILT_IN_AGENTS: () => BUILT_IN_AGENTS,
|
|
35
|
+
BackgroundJobOrchestrator: () => BackgroundJobOrchestrator,
|
|
36
|
+
BackgroundTaskError: () => import_agent_runtime5.BackgroundTaskError,
|
|
37
|
+
BackgroundTaskManager: () => import_agent_runtime3.BackgroundTaskManager,
|
|
35
38
|
BuiltinCommandSource: () => BuiltinCommandSource,
|
|
36
39
|
BundlePluginInstaller: () => BundlePluginInstaller,
|
|
37
40
|
BundlePluginLoader: () => BundlePluginLoader,
|
|
@@ -42,242 +45,641 @@ __export(index_exports, {
|
|
|
42
45
|
PluginSettingsStore: () => PluginSettingsStore,
|
|
43
46
|
PromptExecutor: () => PromptExecutor,
|
|
44
47
|
SkillCommandSource: () => SkillCommandSource,
|
|
45
|
-
|
|
48
|
+
SubagentManager: () => import_agent_runtime7.SubagentManager,
|
|
49
|
+
SystemCommandExecutor: () => SystemCommandExecutor,
|
|
50
|
+
TRUST_TO_MODE: () => import_agent_core4.TRUST_TO_MODE,
|
|
51
|
+
WorktreeSubagentRunner: () => import_agent_runtime8.WorktreeSubagentRunner,
|
|
46
52
|
assembleSubagentPrompt: () => assembleSubagentPrompt,
|
|
47
53
|
buildSkillPrompt: () => buildSkillPrompt,
|
|
48
|
-
chatEntryToMessage: () =>
|
|
54
|
+
chatEntryToMessage: () => import_agent_core5.chatEntryToMessage,
|
|
49
55
|
createAgentTool: () => createAgentTool,
|
|
56
|
+
createBackgroundProcessTool: () => createBackgroundProcessTool,
|
|
57
|
+
createCommandExecutionTool: () => createCommandExecutionTool,
|
|
58
|
+
createDefaultTools: () => createDefaultTools,
|
|
50
59
|
createQuery: () => createQuery,
|
|
51
60
|
createSubagentLogger: () => createSubagentLogger,
|
|
52
61
|
createSubagentSession: () => createSubagentSession,
|
|
53
|
-
|
|
62
|
+
createSystemCommands: () => createSystemCommands,
|
|
63
|
+
createWorktreeSubagentRunner: () => import_agent_runtime8.createWorktreeSubagentRunner,
|
|
64
|
+
evaluatePermission: () => import_agent_core6.evaluatePermission,
|
|
65
|
+
executeSkill: () => executeSkill,
|
|
66
|
+
getBackgroundTaskTransitions: () => import_agent_runtime4.getBackgroundTaskTransitions,
|
|
54
67
|
getBuiltInAgent: () => getBuiltInAgent,
|
|
55
68
|
getForkWorkerSuffix: () => getForkWorkerSuffix,
|
|
56
|
-
getMessagesForAPI: () =>
|
|
69
|
+
getMessagesForAPI: () => import_agent_core5.getMessagesForAPI,
|
|
57
70
|
getSubagentSuffix: () => getSubagentSuffix,
|
|
58
|
-
isChatEntry: () =>
|
|
59
|
-
|
|
60
|
-
|
|
71
|
+
isChatEntry: () => import_agent_core5.isChatEntry,
|
|
72
|
+
isTerminalBackgroundTaskStatus: () => import_agent_runtime4.isTerminalBackgroundTaskStatus,
|
|
73
|
+
messageToHistoryEntry: () => import_agent_core5.messageToHistoryEntry,
|
|
74
|
+
parseFrontmatter: () => parseFrontmatter,
|
|
61
75
|
preprocessShellCommands: () => preprocessShellCommands,
|
|
62
76
|
projectPaths: () => projectPaths,
|
|
63
77
|
promptForApproval: () => promptForApproval,
|
|
64
78
|
resolveSubagentLogDir: () => resolveSubagentLogDir,
|
|
65
79
|
retrieveAgentToolDeps: () => retrieveAgentToolDeps,
|
|
66
|
-
runHooks: () =>
|
|
80
|
+
runHooks: () => import_agent_core7.runHooks,
|
|
67
81
|
storeAgentToolDeps: () => storeAgentToolDeps,
|
|
68
82
|
substituteVariables: () => substituteVariables,
|
|
83
|
+
summarizeBackgroundJobGroup: () => summarizeBackgroundJobGroup,
|
|
84
|
+
transitionBackgroundTaskStatus: () => import_agent_runtime4.transitionBackgroundTaskStatus,
|
|
69
85
|
userPaths: () => userPaths
|
|
70
86
|
});
|
|
71
87
|
module.exports = __toCommonJS(index_exports);
|
|
72
88
|
|
|
73
89
|
// src/interactive/interactive-session.ts
|
|
74
|
-
var
|
|
90
|
+
var import_agent_core3 = require("@robota-sdk/agent-core");
|
|
75
91
|
|
|
76
|
-
// src/commands/
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
return
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
{
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
92
|
+
// src/commands/capability-descriptors.ts
|
|
93
|
+
function inferKind(command) {
|
|
94
|
+
if (command.source === "skill") return "skill";
|
|
95
|
+
if (command.source === "plugin" && command.skillContent) return "skill";
|
|
96
|
+
return "builtin-command";
|
|
97
|
+
}
|
|
98
|
+
function commandToCapabilityDescriptor(command) {
|
|
99
|
+
const skillLike = command.source === "skill" || command.source === "plugin" && Boolean(command.skillContent);
|
|
100
|
+
return {
|
|
101
|
+
name: `/${command.name}`,
|
|
102
|
+
kind: inferKind(command),
|
|
103
|
+
description: command.description,
|
|
104
|
+
userInvocable: command.userInvocable !== false,
|
|
105
|
+
modelInvocable: command.modelInvocable === true || skillLike && command.disableModelInvocation !== true,
|
|
106
|
+
...command.argumentHint ? { argumentHint: command.argumentHint } : {},
|
|
107
|
+
...command.safety ? { safety: command.safety } : {}
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// src/commands/command-registry.ts
|
|
112
|
+
var CommandRegistry = class {
|
|
113
|
+
sources = [];
|
|
114
|
+
addSource(source) {
|
|
115
|
+
this.sources.push(source);
|
|
116
|
+
}
|
|
117
|
+
addModule(module2) {
|
|
118
|
+
for (const source of module2.commandSources ?? []) {
|
|
119
|
+
this.addSource(source);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/** Get all commands, optionally filtered by prefix */
|
|
123
|
+
getCommands(filter) {
|
|
124
|
+
const all = [];
|
|
125
|
+
for (const source of this.sources) {
|
|
126
|
+
all.push(...source.getCommands());
|
|
127
|
+
}
|
|
128
|
+
if (!filter) return all;
|
|
129
|
+
const lower = filter.toLowerCase();
|
|
130
|
+
return all.filter((cmd) => cmd.name.toLowerCase().startsWith(lower));
|
|
131
|
+
}
|
|
132
|
+
/** Resolve a short name to its fully qualified plugin:name form */
|
|
133
|
+
resolveQualifiedName(shortName) {
|
|
134
|
+
const matches = this.getCommands().filter(
|
|
135
|
+
(c) => c.source === "plugin" && c.name.includes(":") && c.name.endsWith(`:${shortName}`)
|
|
136
|
+
);
|
|
137
|
+
if (matches.length !== 1) return null;
|
|
138
|
+
return matches[0].name;
|
|
139
|
+
}
|
|
140
|
+
/** Get subcommands for a specific command */
|
|
141
|
+
getSubcommands(commandName) {
|
|
142
|
+
const lower = commandName.toLowerCase();
|
|
143
|
+
for (const source of this.sources) {
|
|
144
|
+
for (const cmd of source.getCommands()) {
|
|
145
|
+
if (cmd.name.toLowerCase() === lower && cmd.subcommands) {
|
|
146
|
+
return cmd.subcommands;
|
|
147
|
+
}
|
|
125
148
|
}
|
|
126
|
-
}
|
|
149
|
+
}
|
|
150
|
+
return [];
|
|
151
|
+
}
|
|
152
|
+
getCapabilityDescriptors() {
|
|
153
|
+
return this.getCommands().map((command) => commandToCapabilityDescriptor(command));
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
// src/commands/builtin-source.ts
|
|
158
|
+
var import_agent_core = require("@robota-sdk/agent-core");
|
|
159
|
+
function buildModelSubcommands() {
|
|
160
|
+
const seen = /* @__PURE__ */ new Set();
|
|
161
|
+
const commands = [];
|
|
162
|
+
for (const model of Object.values(import_agent_core.CLAUDE_MODELS)) {
|
|
163
|
+
if (seen.has(model.name)) continue;
|
|
164
|
+
seen.add(model.name);
|
|
165
|
+
commands.push({
|
|
166
|
+
name: model.id,
|
|
167
|
+
description: `${model.name} (${(0, import_agent_core.formatTokenCount)(model.contextWindow).toUpperCase()})`,
|
|
168
|
+
source: "builtin"
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
return commands;
|
|
172
|
+
}
|
|
173
|
+
function buildProviderSubcommands() {
|
|
174
|
+
return [
|
|
175
|
+
{ name: "current", description: "Show current provider", source: "builtin" },
|
|
176
|
+
{ name: "list", description: "List provider profiles", source: "builtin" },
|
|
177
|
+
{ name: "use", description: "Switch provider profile", source: "builtin" },
|
|
178
|
+
{ name: "test", description: "Test provider profile", source: "builtin" }
|
|
179
|
+
];
|
|
180
|
+
}
|
|
181
|
+
function buildBackgroundSubcommands() {
|
|
182
|
+
return [
|
|
183
|
+
{ name: "list", description: "List background tasks", source: "builtin" },
|
|
184
|
+
{ name: "read", description: "Read a background task log page", source: "builtin" },
|
|
185
|
+
{ name: "cancel", description: "Cancel a running background task", source: "builtin" },
|
|
186
|
+
{ name: "close", description: "Dismiss a terminal background task", source: "builtin" }
|
|
187
|
+
];
|
|
188
|
+
}
|
|
189
|
+
function createBuiltinCommands() {
|
|
190
|
+
return [
|
|
191
|
+
{ name: "help", description: "Show available commands", source: "builtin" },
|
|
192
|
+
{ name: "clear", description: "Clear conversation history", source: "builtin" },
|
|
127
193
|
{
|
|
128
194
|
name: "mode",
|
|
129
|
-
description: "
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
data: { mode: underlying.getPermissionMode() }
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
if (VALID_MODES.includes(arg)) {
|
|
141
|
-
underlying.setPermissionMode(arg);
|
|
142
|
-
return {
|
|
143
|
-
message: `Permission mode set to: ${arg}`,
|
|
144
|
-
success: true,
|
|
145
|
-
data: { mode: arg }
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
return {
|
|
149
|
-
message: `Invalid mode. Valid: ${VALID_MODES.join(" | ")}`,
|
|
150
|
-
success: false
|
|
151
|
-
};
|
|
152
|
-
}
|
|
195
|
+
description: "Permission mode",
|
|
196
|
+
source: "builtin",
|
|
197
|
+
subcommands: [
|
|
198
|
+
{ name: "plan", description: "Plan only, no execution", source: "builtin" },
|
|
199
|
+
{ name: "default", description: "Ask before risky actions", source: "builtin" },
|
|
200
|
+
{ name: "acceptEdits", description: "Auto-approve file edits", source: "builtin" },
|
|
201
|
+
{ name: "bypassPermissions", description: "Skip all permission checks", source: "builtin" }
|
|
202
|
+
]
|
|
153
203
|
},
|
|
154
204
|
{
|
|
155
205
|
name: "model",
|
|
156
|
-
description: "
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
if (!modelId) {
|
|
160
|
-
return { message: "Usage: model <model-id>", success: false };
|
|
161
|
-
}
|
|
162
|
-
return {
|
|
163
|
-
message: `Model change requested: ${modelId}`,
|
|
164
|
-
success: true,
|
|
165
|
-
data: { modelId }
|
|
166
|
-
};
|
|
167
|
-
}
|
|
206
|
+
description: "Select AI model",
|
|
207
|
+
source: "builtin",
|
|
208
|
+
subcommands: buildModelSubcommands()
|
|
168
209
|
},
|
|
169
210
|
{
|
|
170
211
|
name: "language",
|
|
171
212
|
description: "Set response language",
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
success: true,
|
|
180
|
-
data: { language: lang }
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
},
|
|
184
|
-
{
|
|
185
|
-
name: "cost",
|
|
186
|
-
description: "Show session info",
|
|
187
|
-
execute: (session, _args) => {
|
|
188
|
-
const underlying = session.getSession();
|
|
189
|
-
const sessionId = underlying.getSessionId();
|
|
190
|
-
const messageCount = underlying.getMessageCount();
|
|
191
|
-
return {
|
|
192
|
-
message: `Session: ${sessionId}
|
|
193
|
-
Messages: ${messageCount}`,
|
|
194
|
-
success: true,
|
|
195
|
-
data: { sessionId, messageCount }
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
},
|
|
199
|
-
{
|
|
200
|
-
name: "context",
|
|
201
|
-
description: "Context window info",
|
|
202
|
-
execute: (session, _args) => {
|
|
203
|
-
const ctx = session.getContextState();
|
|
204
|
-
return {
|
|
205
|
-
message: `Context: ${ctx.usedTokens.toLocaleString()} / ${ctx.maxTokens.toLocaleString()} tokens (${Math.round(ctx.usedPercentage)}%)`,
|
|
206
|
-
success: true,
|
|
207
|
-
data: {
|
|
208
|
-
usedTokens: ctx.usedTokens,
|
|
209
|
-
maxTokens: ctx.maxTokens,
|
|
210
|
-
percentage: ctx.usedPercentage
|
|
211
|
-
}
|
|
212
|
-
};
|
|
213
|
-
}
|
|
213
|
+
source: "builtin",
|
|
214
|
+
subcommands: [
|
|
215
|
+
{ name: "ko", description: "Korean", source: "builtin" },
|
|
216
|
+
{ name: "en", description: "English", source: "builtin" },
|
|
217
|
+
{ name: "ja", description: "Japanese", source: "builtin" },
|
|
218
|
+
{ name: "zh", description: "Chinese", source: "builtin" }
|
|
219
|
+
]
|
|
214
220
|
},
|
|
221
|
+
{ name: "compact", description: "Compress context window", source: "builtin" },
|
|
222
|
+
{ name: "cost", description: "Show session info", source: "builtin" },
|
|
223
|
+
{ name: "context", description: "Context window info", source: "builtin" },
|
|
224
|
+
{ name: "permissions", description: "Permission rules", source: "builtin" },
|
|
215
225
|
{
|
|
216
|
-
name: "
|
|
217
|
-
description: "
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
const mode = underlying.getPermissionMode();
|
|
221
|
-
const sessionAllowed = underlying.getSessionAllowedTools();
|
|
222
|
-
const lines = [`Permission mode: ${mode}`];
|
|
223
|
-
if (sessionAllowed.length > 0) {
|
|
224
|
-
lines.push(`Session-approved tools: ${sessionAllowed.join(", ")}`);
|
|
225
|
-
} else {
|
|
226
|
-
lines.push("No session-approved tools.");
|
|
227
|
-
}
|
|
228
|
-
return {
|
|
229
|
-
message: lines.join("\n"),
|
|
230
|
-
success: true,
|
|
231
|
-
data: { mode, sessionAllowed }
|
|
232
|
-
};
|
|
233
|
-
}
|
|
226
|
+
name: "provider",
|
|
227
|
+
description: "Manage provider profiles",
|
|
228
|
+
source: "builtin",
|
|
229
|
+
subcommands: buildProviderSubcommands()
|
|
234
230
|
},
|
|
231
|
+
{ name: "resume", description: "Resume a previous session", source: "builtin" },
|
|
235
232
|
{
|
|
236
|
-
name: "
|
|
237
|
-
description: "
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
success: true,
|
|
241
|
-
data: { triggerResumePicker: true }
|
|
242
|
-
})
|
|
233
|
+
name: "background",
|
|
234
|
+
description: "List and control background tasks",
|
|
235
|
+
source: "builtin",
|
|
236
|
+
subcommands: buildBackgroundSubcommands()
|
|
243
237
|
},
|
|
244
|
-
{
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
238
|
+
{ name: "rename", description: "Rename the current session", source: "builtin" },
|
|
239
|
+
{ name: "plugin", description: "Manage plugins", source: "builtin" },
|
|
240
|
+
{ name: "reload-plugins", description: "Reload all plugin resources", source: "builtin" },
|
|
241
|
+
{ name: "reset", description: "Delete settings and exit", source: "builtin" },
|
|
242
|
+
{ name: "exit", description: "Exit CLI", source: "builtin" }
|
|
243
|
+
];
|
|
244
|
+
}
|
|
245
|
+
var BuiltinCommandSource = class {
|
|
246
|
+
name = "builtin";
|
|
247
|
+
commands;
|
|
248
|
+
constructor() {
|
|
249
|
+
this.commands = createBuiltinCommands();
|
|
250
|
+
}
|
|
251
|
+
getCommands() {
|
|
252
|
+
return this.commands;
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
// src/commands/skill-source.ts
|
|
257
|
+
var import_node_fs = require("fs");
|
|
258
|
+
var import_node_path = require("path");
|
|
259
|
+
var import_node_os = require("os");
|
|
260
|
+
var BOOLEAN_KEYS = /* @__PURE__ */ new Set(["disable-model-invocation", "user-invocable"]);
|
|
261
|
+
var LIST_KEYS = /* @__PURE__ */ new Set(["allowed-tools"]);
|
|
262
|
+
function kebabToCamel(key) {
|
|
263
|
+
return key.replace(/-([a-z])/g, (_match, letter) => letter.toUpperCase());
|
|
264
|
+
}
|
|
265
|
+
function parseListValue(rawValue) {
|
|
266
|
+
const separator = rawValue.includes(",") ? /\s*,\s*/ : /\s+/;
|
|
267
|
+
return rawValue.split(separator).map((value) => value.trim()).filter((value) => value.length > 0);
|
|
268
|
+
}
|
|
269
|
+
function parseFrontmatter(content) {
|
|
270
|
+
const lines = content.split("\n");
|
|
271
|
+
if (lines[0]?.trim() !== "---") return null;
|
|
272
|
+
const result = {};
|
|
273
|
+
for (let i = 1; i < lines.length; i++) {
|
|
274
|
+
const line = lines[i];
|
|
275
|
+
if (line.trim() === "---") break;
|
|
276
|
+
const match = line.match(/^([a-z][a-z0-9-]*):\s*(.+)/);
|
|
277
|
+
if (!match) continue;
|
|
278
|
+
const key = match[1];
|
|
279
|
+
const rawValue = match[2].trim();
|
|
280
|
+
const camelKey = kebabToCamel(key);
|
|
281
|
+
if (BOOLEAN_KEYS.has(key)) {
|
|
282
|
+
result[camelKey] = rawValue === "true";
|
|
283
|
+
} else if (LIST_KEYS.has(key)) {
|
|
284
|
+
result[camelKey] = parseListValue(rawValue);
|
|
285
|
+
} else {
|
|
286
|
+
result[camelKey] = rawValue;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
return Object.keys(result).length > 0 ? result : null;
|
|
290
|
+
}
|
|
291
|
+
function buildCommand(frontmatter, content, fallbackName) {
|
|
292
|
+
const cmd = {
|
|
293
|
+
name: frontmatter?.name ?? fallbackName,
|
|
294
|
+
description: frontmatter?.description ?? `Skill: ${fallbackName}`,
|
|
295
|
+
source: "skill",
|
|
296
|
+
skillContent: content
|
|
297
|
+
};
|
|
298
|
+
if (frontmatter?.argumentHint !== void 0) cmd.argumentHint = frontmatter.argumentHint;
|
|
299
|
+
if (frontmatter?.disableModelInvocation !== void 0)
|
|
300
|
+
cmd.disableModelInvocation = frontmatter.disableModelInvocation;
|
|
301
|
+
if (frontmatter?.userInvocable !== void 0) cmd.userInvocable = frontmatter.userInvocable;
|
|
302
|
+
if (frontmatter?.allowedTools !== void 0) cmd.allowedTools = frontmatter.allowedTools;
|
|
303
|
+
if (frontmatter?.model !== void 0) cmd.model = frontmatter.model;
|
|
304
|
+
if (frontmatter?.effort !== void 0) cmd.effort = frontmatter.effort;
|
|
305
|
+
if (frontmatter?.context !== void 0) cmd.context = frontmatter.context;
|
|
306
|
+
if (frontmatter?.agent !== void 0) cmd.agent = frontmatter.agent;
|
|
307
|
+
return cmd;
|
|
308
|
+
}
|
|
309
|
+
function scanSkillsDir(skillsDir) {
|
|
310
|
+
if (!(0, import_node_fs.existsSync)(skillsDir)) return [];
|
|
311
|
+
const commands = [];
|
|
312
|
+
const entries = (0, import_node_fs.readdirSync)(skillsDir, { withFileTypes: true });
|
|
313
|
+
for (const entry of entries) {
|
|
314
|
+
if (!entry.isDirectory()) continue;
|
|
315
|
+
const skillFile = (0, import_node_path.join)(skillsDir, entry.name, "SKILL.md");
|
|
316
|
+
if (!(0, import_node_fs.existsSync)(skillFile)) continue;
|
|
317
|
+
const content = (0, import_node_fs.readFileSync)(skillFile, "utf-8");
|
|
318
|
+
const frontmatter = parseFrontmatter(content);
|
|
319
|
+
commands.push(buildCommand(frontmatter, content, entry.name));
|
|
320
|
+
}
|
|
321
|
+
return commands;
|
|
322
|
+
}
|
|
323
|
+
function scanCommandsDir(commandsDir) {
|
|
324
|
+
if (!(0, import_node_fs.existsSync)(commandsDir)) return [];
|
|
325
|
+
const commands = [];
|
|
326
|
+
const entries = (0, import_node_fs.readdirSync)(commandsDir, { withFileTypes: true });
|
|
327
|
+
for (const entry of entries) {
|
|
328
|
+
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
329
|
+
const filePath = (0, import_node_path.join)(commandsDir, entry.name);
|
|
330
|
+
const content = (0, import_node_fs.readFileSync)(filePath, "utf-8");
|
|
331
|
+
const frontmatter = parseFrontmatter(content);
|
|
332
|
+
const fallbackName = (0, import_node_path.basename)(entry.name, ".md");
|
|
333
|
+
commands.push(buildCommand(frontmatter, content, fallbackName));
|
|
334
|
+
}
|
|
335
|
+
return commands;
|
|
336
|
+
}
|
|
337
|
+
var SkillCommandSource = class {
|
|
338
|
+
name = "skill";
|
|
339
|
+
cwd;
|
|
340
|
+
home;
|
|
341
|
+
cachedCommands = null;
|
|
342
|
+
constructor(cwd, home) {
|
|
343
|
+
this.cwd = cwd;
|
|
344
|
+
this.home = home ?? (0, import_node_os.homedir)();
|
|
345
|
+
}
|
|
346
|
+
getCommands() {
|
|
347
|
+
if (this.cachedCommands) return this.cachedCommands;
|
|
348
|
+
const sources = [
|
|
349
|
+
scanSkillsDir((0, import_node_path.join)(this.cwd, ".claude", "skills")),
|
|
350
|
+
scanCommandsDir((0, import_node_path.join)(this.cwd, ".claude", "commands")),
|
|
351
|
+
scanSkillsDir((0, import_node_path.join)(this.home, ".robota", "skills")),
|
|
352
|
+
scanSkillsDir((0, import_node_path.join)(this.cwd, ".agents", "skills"))
|
|
353
|
+
];
|
|
354
|
+
const seen = /* @__PURE__ */ new Set();
|
|
355
|
+
const merged = [];
|
|
356
|
+
for (const commands of sources) {
|
|
357
|
+
for (const cmd of commands) {
|
|
358
|
+
if (!seen.has(cmd.name)) {
|
|
359
|
+
seen.add(cmd.name);
|
|
360
|
+
merged.push(cmd);
|
|
251
361
|
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
this.cachedCommands = merged;
|
|
365
|
+
return this.cachedCommands;
|
|
366
|
+
}
|
|
367
|
+
getModelInvocableSkills() {
|
|
368
|
+
return this.getCommands().filter((cmd) => cmd.disableModelInvocation !== true);
|
|
369
|
+
}
|
|
370
|
+
getUserInvocableSkills() {
|
|
371
|
+
return this.getCommands().filter((cmd) => cmd.userInvocable !== false);
|
|
372
|
+
}
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
// src/commands/plugin-source.ts
|
|
376
|
+
var PluginCommandSource = class {
|
|
377
|
+
name = "plugin";
|
|
378
|
+
plugins;
|
|
379
|
+
constructor(plugins) {
|
|
380
|
+
this.plugins = plugins;
|
|
381
|
+
}
|
|
382
|
+
getCommands() {
|
|
383
|
+
const commands = [];
|
|
384
|
+
for (const plugin of this.plugins) {
|
|
385
|
+
for (const skill of plugin.skills) {
|
|
386
|
+
const baseName = skill.name.includes("@") ? skill.name.split("@")[0] : skill.name;
|
|
387
|
+
commands.push({
|
|
388
|
+
name: baseName,
|
|
389
|
+
description: `(${plugin.manifest.name}) ${skill.description}`,
|
|
390
|
+
source: "plugin",
|
|
391
|
+
skillContent: skill.skillContent,
|
|
392
|
+
pluginDir: plugin.pluginDir
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
for (const cmd of plugin.commands) {
|
|
396
|
+
commands.push({
|
|
397
|
+
name: cmd.name,
|
|
398
|
+
description: cmd.description,
|
|
399
|
+
source: "plugin",
|
|
400
|
+
skillContent: cmd.skillContent,
|
|
401
|
+
pluginDir: plugin.pluginDir
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
return commands;
|
|
406
|
+
}
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
// src/commands/background-command.ts
|
|
410
|
+
var DECIMAL_RADIX = 10;
|
|
411
|
+
function parseCommandParts(args) {
|
|
412
|
+
return args.trim().split(/\s+/).filter(Boolean);
|
|
413
|
+
}
|
|
414
|
+
function formatBackgroundTask(task) {
|
|
415
|
+
const preview = task.promptPreview ?? task.commandPreview ?? "";
|
|
416
|
+
const unread = task.unread ? " unread" : "";
|
|
417
|
+
const action = task.currentAction ? ` (${task.currentAction})` : "";
|
|
418
|
+
const timeout = task.timeoutReason ? ` timeout=${task.timeoutReason}` : "";
|
|
419
|
+
const activity = task.lastActivityAt ? ` lastActivityAt=${task.lastActivityAt}` : "";
|
|
420
|
+
const suffix = preview ? ` \u2014 ${preview}` : "";
|
|
421
|
+
return `${task.id} [${task.status}${unread}${timeout}${activity}] ${task.kind}:${task.label}${action}${suffix}`;
|
|
422
|
+
}
|
|
423
|
+
function formatBackgroundTaskList(tasks) {
|
|
424
|
+
if (tasks.length === 0) return "No background tasks.";
|
|
425
|
+
return ["Background tasks:", ...tasks.map((task) => ` ${formatBackgroundTask(task)}`)].join(
|
|
426
|
+
"\n"
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
function parseCursor(value) {
|
|
430
|
+
if (!value) return void 0;
|
|
431
|
+
const offset = Number.parseInt(value, DECIMAL_RADIX);
|
|
432
|
+
return Number.isNaN(offset) ? void 0 : { offset };
|
|
433
|
+
}
|
|
434
|
+
async function executeBackgroundCommand(session, args) {
|
|
435
|
+
const [action = "list", taskId, ...reasonParts] = parseCommandParts(args);
|
|
436
|
+
if (action === "list") {
|
|
437
|
+
const tasks = session.listBackgroundTasks();
|
|
438
|
+
return {
|
|
439
|
+
message: formatBackgroundTaskList(tasks),
|
|
440
|
+
success: true,
|
|
441
|
+
data: { count: tasks.length }
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
if (!taskId) {
|
|
445
|
+
return {
|
|
446
|
+
message: "Usage: background list | background read <task-id> [offset] | background cancel <task-id> | background close <task-id>",
|
|
447
|
+
success: false
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
if (action === "read" || action === "log" || action === "open") {
|
|
451
|
+
const page = await session.readBackgroundTaskLog(taskId, parseCursor(reasonParts[0]));
|
|
452
|
+
const next = page.nextCursor ? `
|
|
453
|
+
Next offset: ${page.nextCursor.offset}` : "";
|
|
454
|
+
return {
|
|
455
|
+
message: page.lines.length > 0 ? `${page.lines.join("\n")}${next}` : `No log lines: ${taskId}`,
|
|
456
|
+
success: true,
|
|
457
|
+
data: { taskId, nextOffset: page.nextCursor?.offset }
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
if (action === "cancel" || action === "stop") {
|
|
461
|
+
await session.cancelBackgroundTask(taskId, reasonParts.join(" ") || void 0);
|
|
462
|
+
return { message: `Background task cancelled: ${taskId}`, success: true, data: { taskId } };
|
|
463
|
+
}
|
|
464
|
+
if (action === "close" || action === "dismiss") {
|
|
465
|
+
await session.closeBackgroundTask(taskId);
|
|
466
|
+
return { message: `Background task closed: ${taskId}`, success: true, data: { taskId } };
|
|
467
|
+
}
|
|
468
|
+
return { message: `Unknown background action: ${action}`, success: false };
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// src/commands/system-command.ts
|
|
472
|
+
var VALID_MODES = ["plan", "default", "acceptEdits", "bypassPermissions"];
|
|
473
|
+
function createSystemCommands() {
|
|
474
|
+
return [
|
|
475
|
+
{
|
|
476
|
+
name: "help",
|
|
477
|
+
description: "Show available commands",
|
|
478
|
+
execute: (_session, _args) => ({
|
|
479
|
+
message: [
|
|
480
|
+
"Available commands:",
|
|
481
|
+
" help \u2014 Show this help",
|
|
482
|
+
" clear \u2014 Clear conversation",
|
|
483
|
+
" compact [instr] \u2014 Compact context (optional focus instructions)",
|
|
484
|
+
" mode [m] \u2014 Show/change permission mode",
|
|
485
|
+
" model <id> \u2014 Change AI model",
|
|
486
|
+
" language <code> \u2014 Set response language (ko, en, ja, zh)",
|
|
487
|
+
" cost \u2014 Show session info",
|
|
488
|
+
" context \u2014 Context window info",
|
|
489
|
+
" permissions \u2014 Permission rules",
|
|
490
|
+
" provider \u2014 Provider profile status and switching",
|
|
491
|
+
" resume \u2014 Resume a previous session",
|
|
492
|
+
" background \u2014 List/cancel/close background tasks",
|
|
493
|
+
" rename <name> \u2014 Rename the current session",
|
|
494
|
+
" reset \u2014 Delete settings and exit"
|
|
495
|
+
].join("\n"),
|
|
496
|
+
success: true
|
|
497
|
+
})
|
|
498
|
+
},
|
|
499
|
+
{
|
|
500
|
+
name: "clear",
|
|
501
|
+
description: "Clear conversation history",
|
|
502
|
+
execute: (session, _args) => {
|
|
503
|
+
const underlying = session.getSession();
|
|
504
|
+
underlying.clearHistory();
|
|
505
|
+
return { message: "Conversation cleared.", success: true };
|
|
506
|
+
}
|
|
507
|
+
},
|
|
508
|
+
{
|
|
509
|
+
name: "compact",
|
|
510
|
+
description: "Compress context window",
|
|
511
|
+
execute: async (session, args) => {
|
|
512
|
+
const underlying = session.getSession();
|
|
513
|
+
const instructions = args.trim() || void 0;
|
|
514
|
+
const before = underlying.getContextState().usedPercentage;
|
|
515
|
+
await underlying.compact(instructions);
|
|
516
|
+
const after = underlying.getContextState().usedPercentage;
|
|
252
517
|
return {
|
|
253
|
-
message: `
|
|
518
|
+
message: `Context compacted: ${Math.round(before)}% -> ${Math.round(after)}%`,
|
|
254
519
|
success: true,
|
|
255
|
-
data: {
|
|
520
|
+
data: { before, after }
|
|
256
521
|
};
|
|
257
522
|
}
|
|
258
523
|
},
|
|
259
524
|
{
|
|
260
|
-
name: "
|
|
261
|
-
description: "
|
|
262
|
-
execute: (
|
|
525
|
+
name: "mode",
|
|
526
|
+
description: "Show/change permission mode",
|
|
527
|
+
execute: (session, args) => {
|
|
528
|
+
const underlying = session.getSession();
|
|
529
|
+
const arg = args.trim().split(/\s+/)[0];
|
|
530
|
+
if (!arg) {
|
|
531
|
+
return {
|
|
532
|
+
message: `Current mode: ${underlying.getPermissionMode()}`,
|
|
533
|
+
success: true,
|
|
534
|
+
data: { mode: underlying.getPermissionMode() }
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
if (VALID_MODES.includes(arg)) {
|
|
538
|
+
underlying.setPermissionMode(arg);
|
|
539
|
+
return {
|
|
540
|
+
message: `Permission mode set to: ${arg}`,
|
|
541
|
+
success: true,
|
|
542
|
+
data: { mode: arg }
|
|
543
|
+
};
|
|
544
|
+
}
|
|
263
545
|
return {
|
|
264
|
-
message:
|
|
265
|
-
success:
|
|
266
|
-
data: { resetRequested: true }
|
|
546
|
+
message: `Invalid mode. Valid: ${VALID_MODES.join(" | ")}`,
|
|
547
|
+
success: false
|
|
267
548
|
};
|
|
268
549
|
}
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
550
|
+
},
|
|
551
|
+
{
|
|
552
|
+
name: "model",
|
|
553
|
+
description: "Change AI model",
|
|
554
|
+
execute: (_session, args) => {
|
|
555
|
+
const modelId = args.trim().split(/\s+/)[0];
|
|
556
|
+
if (!modelId) {
|
|
557
|
+
return { message: "Usage: model <model-id>", success: false };
|
|
558
|
+
}
|
|
559
|
+
return {
|
|
560
|
+
message: `Model change requested: ${modelId}`,
|
|
561
|
+
success: true,
|
|
562
|
+
data: { modelId }
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
},
|
|
566
|
+
{
|
|
567
|
+
name: "language",
|
|
568
|
+
description: "Set response language",
|
|
569
|
+
execute: (_session, args) => {
|
|
570
|
+
const lang = args.trim().split(/\s+/)[0];
|
|
571
|
+
if (!lang) {
|
|
572
|
+
return { message: "Usage: language <code> (e.g., ko, en, ja, zh)", success: false };
|
|
573
|
+
}
|
|
574
|
+
return {
|
|
575
|
+
message: `Language set to "${lang}".`,
|
|
576
|
+
success: true,
|
|
577
|
+
data: { language: lang }
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
},
|
|
581
|
+
{
|
|
582
|
+
name: "cost",
|
|
583
|
+
description: "Show session info",
|
|
584
|
+
execute: (session, _args) => {
|
|
585
|
+
const underlying = session.getSession();
|
|
586
|
+
const sessionId = underlying.getSessionId();
|
|
587
|
+
const messageCount = underlying.getMessageCount();
|
|
588
|
+
return {
|
|
589
|
+
message: `Session: ${sessionId}
|
|
590
|
+
Messages: ${messageCount}`,
|
|
591
|
+
success: true,
|
|
592
|
+
data: { sessionId, messageCount }
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
},
|
|
596
|
+
{
|
|
597
|
+
name: "context",
|
|
598
|
+
description: "Context window info",
|
|
599
|
+
execute: (session, _args) => {
|
|
600
|
+
const ctx = session.getContextState();
|
|
601
|
+
return {
|
|
602
|
+
message: `Context: ${ctx.usedTokens.toLocaleString()} / ${ctx.maxTokens.toLocaleString()} tokens (${Math.round(ctx.usedPercentage)}%)`,
|
|
603
|
+
success: true,
|
|
604
|
+
data: {
|
|
605
|
+
usedTokens: ctx.usedTokens,
|
|
606
|
+
maxTokens: ctx.maxTokens,
|
|
607
|
+
percentage: ctx.usedPercentage
|
|
608
|
+
}
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
},
|
|
612
|
+
{
|
|
613
|
+
name: "permissions",
|
|
614
|
+
description: "Show permission rules",
|
|
615
|
+
execute: (session, _args) => {
|
|
616
|
+
const underlying = session.getSession();
|
|
617
|
+
const mode = underlying.getPermissionMode();
|
|
618
|
+
const sessionAllowed = underlying.getSessionAllowedTools();
|
|
619
|
+
const lines = [`Permission mode: ${mode}`];
|
|
620
|
+
if (sessionAllowed.length > 0) {
|
|
621
|
+
lines.push(`Session-approved tools: ${sessionAllowed.join(", ")}`);
|
|
622
|
+
} else {
|
|
623
|
+
lines.push("No session-approved tools.");
|
|
624
|
+
}
|
|
625
|
+
return {
|
|
626
|
+
message: lines.join("\n"),
|
|
627
|
+
success: true,
|
|
628
|
+
data: { mode, sessionAllowed }
|
|
629
|
+
};
|
|
630
|
+
}
|
|
631
|
+
},
|
|
632
|
+
{
|
|
633
|
+
name: "resume",
|
|
634
|
+
description: "Resume a previous session",
|
|
635
|
+
execute: (_session, _args) => ({
|
|
636
|
+
message: "Opening session picker...",
|
|
637
|
+
success: true,
|
|
638
|
+
data: { triggerResumePicker: true }
|
|
639
|
+
})
|
|
640
|
+
},
|
|
641
|
+
{
|
|
642
|
+
name: "background",
|
|
643
|
+
description: "List and control background tasks",
|
|
644
|
+
execute: executeBackgroundCommand
|
|
645
|
+
},
|
|
646
|
+
{
|
|
647
|
+
name: "rename",
|
|
648
|
+
description: "Rename the current session",
|
|
649
|
+
execute: (_session, args) => {
|
|
650
|
+
const name = args.trim();
|
|
651
|
+
if (!name) {
|
|
652
|
+
return { message: "Usage: rename <name>", success: false };
|
|
653
|
+
}
|
|
654
|
+
return {
|
|
655
|
+
message: `Session renamed to "${name}".`,
|
|
656
|
+
success: true,
|
|
657
|
+
data: { name }
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
},
|
|
661
|
+
{
|
|
662
|
+
name: "reset",
|
|
663
|
+
description: "Delete settings",
|
|
664
|
+
execute: (_session, _args) => {
|
|
665
|
+
return {
|
|
666
|
+
message: "Reset requested.",
|
|
667
|
+
success: true,
|
|
668
|
+
data: { resetRequested: true }
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
];
|
|
673
|
+
}
|
|
674
|
+
var SystemCommandExecutor = class {
|
|
675
|
+
commands;
|
|
676
|
+
constructor(commands) {
|
|
677
|
+
this.commands = /* @__PURE__ */ new Map();
|
|
678
|
+
for (const cmd of commands ?? createSystemCommands()) {
|
|
679
|
+
this.commands.set(cmd.name, cmd);
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
/** Register an additional command. */
|
|
281
683
|
register(command) {
|
|
282
684
|
this.commands.set(command.name, command);
|
|
283
685
|
}
|
|
@@ -287,15 +689,696 @@ var SystemCommandExecutor = class {
|
|
|
287
689
|
if (!cmd) return null;
|
|
288
690
|
return await cmd.execute(session, args);
|
|
289
691
|
}
|
|
290
|
-
/** List all registered commands. */
|
|
291
|
-
listCommands() {
|
|
292
|
-
return [...this.commands.values()];
|
|
692
|
+
/** List all registered commands. */
|
|
693
|
+
listCommands() {
|
|
694
|
+
return [...this.commands.values()];
|
|
695
|
+
}
|
|
696
|
+
listModelInvocableCommands() {
|
|
697
|
+
return this.listCommands().filter((command) => command.modelInvocable === true).map((command) => ({
|
|
698
|
+
name: `/${command.name}`,
|
|
699
|
+
kind: "builtin-command",
|
|
700
|
+
description: command.description,
|
|
701
|
+
userInvocable: command.userInvocable !== false,
|
|
702
|
+
modelInvocable: true,
|
|
703
|
+
...command.argumentHint ? { argumentHint: command.argumentHint } : {},
|
|
704
|
+
...command.safety ? { safety: command.safety } : {}
|
|
705
|
+
}));
|
|
706
|
+
}
|
|
707
|
+
isModelInvocable(name) {
|
|
708
|
+
return this.commands.get(name)?.modelInvocable === true;
|
|
709
|
+
}
|
|
710
|
+
async executeModelInvocable(name, session, args) {
|
|
711
|
+
if (!this.isModelInvocable(name)) return null;
|
|
712
|
+
return this.execute(name, session, args);
|
|
713
|
+
}
|
|
714
|
+
/** Check if a command exists. */
|
|
715
|
+
hasCommand(name) {
|
|
716
|
+
return this.commands.has(name);
|
|
717
|
+
}
|
|
718
|
+
};
|
|
719
|
+
|
|
720
|
+
// src/utils/skill-prompt.ts
|
|
721
|
+
var import_node_child_process = require("child_process");
|
|
722
|
+
function substituteVariables(content, args, context) {
|
|
723
|
+
const argParts = args ? args.split(/\s+/) : [];
|
|
724
|
+
let result = content;
|
|
725
|
+
result = result.replace(/\$ARGUMENTS\[(\d+)]/g, (_match, index) => {
|
|
726
|
+
return argParts[Number(index)] ?? "";
|
|
727
|
+
});
|
|
728
|
+
result = result.replace(/\$ARGUMENTS/g, args);
|
|
729
|
+
result = result.replace(/\$(\d)(?!\d|\w|\[)/g, (_match, digit) => {
|
|
730
|
+
return argParts[Number(digit)] ?? "";
|
|
731
|
+
});
|
|
732
|
+
result = result.replace(/\$\{CLAUDE_SESSION_ID}/g, context?.sessionId ?? "");
|
|
733
|
+
result = result.replace(/\$\{CLAUDE_SKILL_DIR}/g, context?.skillDir ?? "");
|
|
734
|
+
return result;
|
|
735
|
+
}
|
|
736
|
+
async function preprocessShellCommands(content) {
|
|
737
|
+
const shellPattern = /!`([^`]+)`/g;
|
|
738
|
+
if (!shellPattern.test(content)) {
|
|
739
|
+
return content;
|
|
740
|
+
}
|
|
741
|
+
shellPattern.lastIndex = 0;
|
|
742
|
+
let result = content;
|
|
743
|
+
let match;
|
|
744
|
+
const matches = [];
|
|
745
|
+
while ((match = shellPattern.exec(content)) !== null) {
|
|
746
|
+
matches.push({ full: match[0], command: match[1] });
|
|
747
|
+
}
|
|
748
|
+
for (const { full, command } of matches) {
|
|
749
|
+
let output = "";
|
|
750
|
+
try {
|
|
751
|
+
output = (0, import_node_child_process.execSync)(command, {
|
|
752
|
+
timeout: 5e3,
|
|
753
|
+
encoding: "utf-8",
|
|
754
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
755
|
+
}).trimEnd();
|
|
756
|
+
} catch {
|
|
757
|
+
output = "";
|
|
758
|
+
}
|
|
759
|
+
result = result.replace(full, output);
|
|
760
|
+
}
|
|
761
|
+
return result;
|
|
762
|
+
}
|
|
763
|
+
async function buildSkillPrompt(input, registry, context) {
|
|
764
|
+
const parts = input.slice(1).split(/\s+/);
|
|
765
|
+
const cmd = parts[0]?.toLowerCase() ?? "";
|
|
766
|
+
const skillCmd = registry.getCommands().find((c) => c.name === cmd && (c.source === "skill" || c.source === "plugin"));
|
|
767
|
+
if (!skillCmd) return null;
|
|
768
|
+
const args = parts.slice(1).join(" ").trim();
|
|
769
|
+
const userInstruction = args || skillCmd.description;
|
|
770
|
+
if (skillCmd.skillContent) {
|
|
771
|
+
let processed = await preprocessShellCommands(skillCmd.skillContent);
|
|
772
|
+
processed = substituteVariables(processed, args, context);
|
|
773
|
+
return `<skill name="${cmd}">
|
|
774
|
+
${processed}
|
|
775
|
+
</skill>
|
|
776
|
+
|
|
777
|
+
Execute the "${cmd}" skill: ${userInstruction}`;
|
|
778
|
+
}
|
|
779
|
+
return `Use the "${cmd}" skill: ${userInstruction}`;
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
// src/commands/skill-executor.ts
|
|
783
|
+
async function buildProcessedContent(skill, args, context) {
|
|
784
|
+
if (!skill.skillContent) return null;
|
|
785
|
+
const preprocessed = await preprocessShellCommands(skill.skillContent);
|
|
786
|
+
return substituteVariables(preprocessed, args, context);
|
|
787
|
+
}
|
|
788
|
+
async function buildInjectPrompt(skill, args, context) {
|
|
789
|
+
const processed = await buildProcessedContent(skill, args, context);
|
|
790
|
+
if (processed) {
|
|
791
|
+
const userInstruction = args || skill.description;
|
|
792
|
+
return `<skill name="${skill.name}">
|
|
793
|
+
${processed}
|
|
794
|
+
</skill>
|
|
795
|
+
|
|
796
|
+
Execute the "${skill.name}" skill: ${userInstruction}`;
|
|
797
|
+
}
|
|
798
|
+
return `Use the "${skill.name}" skill: ${args || skill.description}`;
|
|
799
|
+
}
|
|
800
|
+
async function executeSkill(skill, args, callbacks, context) {
|
|
801
|
+
if (skill.context === "fork") {
|
|
802
|
+
if (!callbacks.runInFork) {
|
|
803
|
+
throw new Error("Fork execution is not available. Agent tool deps may not be initialized.");
|
|
804
|
+
}
|
|
805
|
+
const content = await buildProcessedContent(skill, args, context);
|
|
806
|
+
const prompt2 = content ?? `Use the "${skill.name}" skill: ${args || skill.description}`;
|
|
807
|
+
const options = {};
|
|
808
|
+
if (skill.agent) options.agent = skill.agent;
|
|
809
|
+
if (skill.allowedTools) options.allowedTools = skill.allowedTools;
|
|
810
|
+
const result = await callbacks.runInFork(prompt2, options);
|
|
811
|
+
return { mode: "fork", result };
|
|
812
|
+
}
|
|
813
|
+
const prompt = await buildInjectPrompt(skill, args, context);
|
|
814
|
+
return { mode: "inject", prompt };
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
// src/assembly/create-subagent-session.ts
|
|
818
|
+
var import_agent_sessions = require("@robota-sdk/agent-sessions");
|
|
819
|
+
|
|
820
|
+
// src/assembly/subagent-prompts.ts
|
|
821
|
+
function getSubagentSuffix() {
|
|
822
|
+
return `When you complete the task, respond with a concise report covering what was done and any key findings \u2014 the caller will relay this to the user, so it only needs the essentials.
|
|
823
|
+
|
|
824
|
+
In your final response, share file paths (always absolute, never relative) that are relevant to the task. Include code snippets only when the exact text is load-bearing \u2014 do not recap code you merely read.
|
|
825
|
+
|
|
826
|
+
Do not use emojis.`;
|
|
827
|
+
}
|
|
828
|
+
function getForkWorkerSuffix() {
|
|
829
|
+
return `You are a worker subagent executing a specific task. Do NOT spawn sub-agents; execute directly. Keep your report under 500 words. Use this structure:
|
|
830
|
+
- Scope: What was requested
|
|
831
|
+
- Result: What was done
|
|
832
|
+
- Key files: Relevant file paths (absolute)
|
|
833
|
+
- Files changed: List of modifications
|
|
834
|
+
- Issues: Any problems encountered`;
|
|
835
|
+
}
|
|
836
|
+
function assembleSubagentPrompt(options) {
|
|
837
|
+
const parts = [options.agentBody];
|
|
838
|
+
if (options.claudeMd) {
|
|
839
|
+
parts.push(options.claudeMd);
|
|
840
|
+
}
|
|
841
|
+
if (options.agentsMd) {
|
|
842
|
+
parts.push(options.agentsMd);
|
|
843
|
+
}
|
|
844
|
+
const suffix = options.isForkWorker ? getForkWorkerSuffix() : getSubagentSuffix();
|
|
845
|
+
parts.push(suffix);
|
|
846
|
+
return parts.join("\n\n");
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
// src/assembly/create-subagent-session.ts
|
|
850
|
+
var MODEL_SHORTCUTS = {
|
|
851
|
+
sonnet: "claude-sonnet-4-6",
|
|
852
|
+
haiku: "claude-haiku-4-5",
|
|
853
|
+
opus: "claude-opus-4-6"
|
|
854
|
+
};
|
|
855
|
+
function resolveModelId(shortName, _parentModel) {
|
|
856
|
+
return MODEL_SHORTCUTS[shortName] ?? shortName;
|
|
857
|
+
}
|
|
858
|
+
function filterTools(parentTools, agentDefinition) {
|
|
859
|
+
let tools = [...parentTools];
|
|
860
|
+
if (agentDefinition.disallowedTools) {
|
|
861
|
+
const denySet = new Set(agentDefinition.disallowedTools);
|
|
862
|
+
tools = tools.filter((t) => !denySet.has(t.getName()));
|
|
863
|
+
}
|
|
864
|
+
if (agentDefinition.tools) {
|
|
865
|
+
const allowSet = new Set(agentDefinition.tools);
|
|
866
|
+
tools = tools.filter((t) => allowSet.has(t.getName()));
|
|
867
|
+
}
|
|
868
|
+
tools = tools.filter((t) => t.getName() !== "Agent");
|
|
869
|
+
return tools;
|
|
870
|
+
}
|
|
871
|
+
function createSubagentSession(options) {
|
|
872
|
+
const { agentDefinition, parentConfig, parentContext, parentTools, terminal } = options;
|
|
873
|
+
const tools = filterTools(parentTools, agentDefinition);
|
|
874
|
+
const model = agentDefinition.model ? resolveModelId(agentDefinition.model, parentConfig.provider.model) : parentConfig.provider.model;
|
|
875
|
+
const systemMessage = assembleSubagentPrompt({
|
|
876
|
+
agentBody: agentDefinition.systemPrompt,
|
|
877
|
+
claudeMd: parentContext.claudeMd,
|
|
878
|
+
agentsMd: parentContext.agentsMd,
|
|
879
|
+
isForkWorker: options.isForkWorker ?? false
|
|
880
|
+
});
|
|
881
|
+
const provider = options.provider;
|
|
882
|
+
return new import_agent_sessions.Session({
|
|
883
|
+
tools,
|
|
884
|
+
provider,
|
|
885
|
+
systemMessage,
|
|
886
|
+
terminal,
|
|
887
|
+
...options.sessionId !== void 0 ? { sessionId: options.sessionId } : {},
|
|
888
|
+
...options.sessionLogger !== void 0 ? { sessionLogger: options.sessionLogger } : {},
|
|
889
|
+
model,
|
|
890
|
+
maxTurns: agentDefinition.maxTurns,
|
|
891
|
+
permissions: parentConfig.permissions,
|
|
892
|
+
permissionMode: options.permissionMode,
|
|
893
|
+
defaultTrustLevel: parentConfig.defaultTrustLevel,
|
|
894
|
+
permissionHandler: options.permissionHandler,
|
|
895
|
+
hooks: options.hooks,
|
|
896
|
+
hookTypeExecutors: options.hookTypeExecutors,
|
|
897
|
+
onTextDelta: options.onTextDelta,
|
|
898
|
+
onToolExecution: options.onToolExecution
|
|
899
|
+
});
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
// src/agents/built-in-agents.ts
|
|
903
|
+
var GENERAL_PURPOSE_SYSTEM_PROMPT = `You are a general-purpose task execution agent. You have access to all tools available in the parent session and can perform any task delegated to you.
|
|
904
|
+
|
|
905
|
+
Your role is to complete the assigned task thoroughly and accurately. Follow these guidelines:
|
|
906
|
+
|
|
907
|
+
- Execute the task as described in the prompt. Do not expand scope beyond what is requested.
|
|
908
|
+
- Use the most appropriate tools for each step. Prefer precise tools (Read, Grep, Glob) over broad ones (Bash) when possible.
|
|
909
|
+
- Report your findings clearly and concisely when the task is complete.
|
|
910
|
+
- If a task cannot be completed, explain why and what information is missing.
|
|
911
|
+
- Maintain the same code quality standards as the parent session (strict types, no fallbacks, proper error handling).`;
|
|
912
|
+
var EXPLORE_SYSTEM_PROMPT = `You are a codebase exploration and analysis agent. Your purpose is to search, read, and understand code without making any modifications.
|
|
913
|
+
|
|
914
|
+
You operate in read-only mode. You must NEVER attempt to write or edit files. Your tools are restricted to read-only operations: reading files, searching with grep and glob, and running non-destructive bash commands.
|
|
915
|
+
|
|
916
|
+
Your role is to answer questions about the codebase by:
|
|
917
|
+
|
|
918
|
+
- Searching for relevant files, symbols, and patterns using Glob and Grep.
|
|
919
|
+
- Reading source files, configuration, and documentation to understand structure and behavior.
|
|
920
|
+
- Tracing code paths across modules to understand how components interact.
|
|
921
|
+
- Summarizing findings in a clear, structured format with file paths and line references.
|
|
922
|
+
- Identifying architectural patterns, dependencies, and potential issues.
|
|
923
|
+
|
|
924
|
+
When exploring, prefer targeted searches over broad scans. Start with the most likely locations and narrow down. Always include absolute file paths in your responses so the caller can navigate directly to relevant code.`;
|
|
925
|
+
var PLAN_SYSTEM_PROMPT = `You are a planning, research, and architecture agent. Your purpose is to analyze requirements, research approaches, and produce structured plans without making any code modifications.
|
|
926
|
+
|
|
927
|
+
You operate in read-only mode. You must NEVER attempt to write or edit files. Your tools are restricted to read-only operations.
|
|
928
|
+
|
|
929
|
+
Your role is to:
|
|
930
|
+
|
|
931
|
+
- Analyze the current codebase state relevant to the task by reading specs, source code, and tests.
|
|
932
|
+
- Research implementation approaches by examining existing patterns and architectural conventions in the repository.
|
|
933
|
+
- Identify affected files, modules, and interfaces that a proposed change would touch.
|
|
934
|
+
- Assess risks, dependencies, and potential breaking changes.
|
|
935
|
+
- Produce a structured implementation plan with clear steps, file lists, and ordering.
|
|
936
|
+
- Consider edge cases, error handling, and test coverage requirements.
|
|
937
|
+
|
|
938
|
+
Output your plan in a structured format with numbered steps. For each step, specify which files are involved and what changes are needed. Flag any decisions that require human judgment or clarification.`;
|
|
939
|
+
var BUILT_IN_AGENTS = [
|
|
940
|
+
{
|
|
941
|
+
name: "general-purpose",
|
|
942
|
+
description: "General-purpose task execution agent with full tool access.",
|
|
943
|
+
systemPrompt: GENERAL_PURPOSE_SYSTEM_PROMPT
|
|
944
|
+
},
|
|
945
|
+
{
|
|
946
|
+
name: "Explore",
|
|
947
|
+
description: "Read-only codebase exploration and analysis agent.",
|
|
948
|
+
systemPrompt: EXPLORE_SYSTEM_PROMPT,
|
|
949
|
+
disallowedTools: ["Write", "Edit"]
|
|
950
|
+
},
|
|
951
|
+
{
|
|
952
|
+
name: "Plan",
|
|
953
|
+
description: "Read-only planning, research, and architecture agent.",
|
|
954
|
+
systemPrompt: PLAN_SYSTEM_PROMPT,
|
|
955
|
+
disallowedTools: ["Write", "Edit"]
|
|
956
|
+
}
|
|
957
|
+
];
|
|
958
|
+
function getBuiltInAgent(name) {
|
|
959
|
+
return BUILT_IN_AGENTS.find((agent) => agent.name === name);
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
// src/tools/agent-tool.ts
|
|
963
|
+
var import_zod = require("zod");
|
|
964
|
+
var import_agent_tools = require("@robota-sdk/agent-tools");
|
|
965
|
+
var import_agent_runtime = require("@robota-sdk/agent-runtime");
|
|
966
|
+
|
|
967
|
+
// src/subagents/in-process-subagent-runner.ts
|
|
968
|
+
function resolveAgentDefinition(agentType, customRegistry) {
|
|
969
|
+
const definition = customRegistry?.(agentType) ?? getBuiltInAgent(agentType);
|
|
970
|
+
if (!definition) {
|
|
971
|
+
throw new Error(`Unknown agent type: ${agentType}`);
|
|
972
|
+
}
|
|
973
|
+
return definition;
|
|
974
|
+
}
|
|
975
|
+
function applyRequestOverrides(definition, job) {
|
|
976
|
+
return {
|
|
977
|
+
...definition,
|
|
978
|
+
...job.request.model ? { model: job.request.model } : {},
|
|
979
|
+
...job.request.allowedTools ? { tools: job.request.allowedTools } : {},
|
|
980
|
+
...job.request.disallowedTools ? { disallowedTools: job.request.disallowedTools } : {}
|
|
981
|
+
};
|
|
982
|
+
}
|
|
983
|
+
function extractFirstArg(toolArgs) {
|
|
984
|
+
if (!toolArgs) return void 0;
|
|
985
|
+
const firstValue = Object.values(toolArgs)[0];
|
|
986
|
+
if (firstValue === void 0) return void 0;
|
|
987
|
+
return typeof firstValue === "object" ? JSON.stringify(firstValue) : String(firstValue);
|
|
988
|
+
}
|
|
989
|
+
function assertSupportedIsolation(job) {
|
|
990
|
+
if (job.request.isolation === "worktree") {
|
|
991
|
+
throw new Error("Worktree isolation requires a runtime shell subagent runner");
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
function emitToolExecutionEvent(job, event) {
|
|
995
|
+
if (event.type === "start") {
|
|
996
|
+
job.emit?.({
|
|
997
|
+
type: "background_task_tool_start",
|
|
998
|
+
toolName: event.toolName,
|
|
999
|
+
firstArg: extractFirstArg(event.toolArgs)
|
|
1000
|
+
});
|
|
1001
|
+
return;
|
|
1002
|
+
}
|
|
1003
|
+
job.emit?.({
|
|
1004
|
+
type: "background_task_tool_end",
|
|
1005
|
+
toolName: event.toolName,
|
|
1006
|
+
success: event.success ?? true
|
|
1007
|
+
});
|
|
1008
|
+
}
|
|
1009
|
+
function createInProcessSubagentRunner(deps) {
|
|
1010
|
+
return {
|
|
1011
|
+
start(job) {
|
|
1012
|
+
assertSupportedIsolation(job);
|
|
1013
|
+
const definition = resolveAgentDefinition(job.request.type, deps.customAgentRegistry);
|
|
1014
|
+
const session = createSubagentSession({
|
|
1015
|
+
agentDefinition: applyRequestOverrides(definition, job),
|
|
1016
|
+
parentConfig: deps.config,
|
|
1017
|
+
parentContext: deps.context,
|
|
1018
|
+
parentTools: deps.tools,
|
|
1019
|
+
provider: deps.provider,
|
|
1020
|
+
terminal: deps.terminal,
|
|
1021
|
+
permissionMode: deps.permissionMode,
|
|
1022
|
+
permissionHandler: deps.permissionHandler,
|
|
1023
|
+
hooks: deps.hooks,
|
|
1024
|
+
hookTypeExecutors: deps.hookTypeExecutors,
|
|
1025
|
+
onTextDelta: (delta) => {
|
|
1026
|
+
job.emit?.({ type: "background_task_text_delta", delta });
|
|
1027
|
+
deps.onTextDelta?.(delta);
|
|
1028
|
+
},
|
|
1029
|
+
onToolExecution: (event) => {
|
|
1030
|
+
emitToolExecutionEvent(job, event);
|
|
1031
|
+
deps.onToolExecution?.(event);
|
|
1032
|
+
}
|
|
1033
|
+
});
|
|
1034
|
+
return {
|
|
1035
|
+
jobId: job.jobId,
|
|
1036
|
+
result: session.run(job.request.prompt).then((output) => ({
|
|
1037
|
+
jobId: job.jobId,
|
|
1038
|
+
output
|
|
1039
|
+
})),
|
|
1040
|
+
cancel: () => {
|
|
1041
|
+
session.abort();
|
|
1042
|
+
return Promise.resolve();
|
|
1043
|
+
}
|
|
1044
|
+
};
|
|
1045
|
+
}
|
|
1046
|
+
};
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
// src/tools/agent-tool.ts
|
|
1050
|
+
var AGENT_TOOL_DESCRIPTION = [
|
|
1051
|
+
"Creates one subagent job for delegated work in an isolated context.",
|
|
1052
|
+
"One tool call creates one subagent job.",
|
|
1053
|
+
"When the user explicitly asks to create, run, spawn, delegate to, or use agents/subagents, start the requested subagent job immediately.",
|
|
1054
|
+
"Do not ask a follow-up question unless execution is impossible or unsafe.",
|
|
1055
|
+
"For multiple or parallel agents, create one Agent tool call per requested role in the current turn.",
|
|
1056
|
+
"Subagent jobs run as background tasks by default.",
|
|
1057
|
+
"The tool waits for a terminal result and returns completed, failed, or timed-out outcome data to the parent conversation.",
|
|
1058
|
+
"Execution is represented by a real tool call and runtime background task event."
|
|
1059
|
+
].join(" ");
|
|
1060
|
+
function createAgentToolPromptDescription(agentDefinitions = []) {
|
|
1061
|
+
const availableAgents = agentDefinitions.length > 0 ? ` Available agent types: ${agentDefinitions.map((agent) => `${agent.name} (${agent.description})`).join(", ")}.` : "";
|
|
1062
|
+
return [
|
|
1063
|
+
"Agent \u2014 creates one isolated subagent job.",
|
|
1064
|
+
"One Agent tool call corresponds to one subagent job.",
|
|
1065
|
+
"When the user explicitly asks to create, run, spawn, delegate to, or use agents/subagents, start the requested subagent job immediately.",
|
|
1066
|
+
"Do not ask a follow-up question unless execution is impossible or unsafe.",
|
|
1067
|
+
"For multiple or parallel agents, create one Agent tool call per requested role in the current turn.",
|
|
1068
|
+
"The tool returns terminal result data.",
|
|
1069
|
+
"Runtime mode is background.",
|
|
1070
|
+
availableAgents
|
|
1071
|
+
].join(" ").replace(/\s+/g, " ").trim();
|
|
1072
|
+
}
|
|
1073
|
+
function asZodSchema(schema) {
|
|
1074
|
+
return schema;
|
|
1075
|
+
}
|
|
1076
|
+
var AgentSchema = import_zod.z.object({
|
|
1077
|
+
prompt: import_zod.z.string().describe("The task for the subagent to perform"),
|
|
1078
|
+
subagent_type: import_zod.z.string().optional().describe('Agent type: "general-purpose", "Explore", "Plan", or a custom agent name'),
|
|
1079
|
+
model: import_zod.z.string().optional().describe("Optional model override"),
|
|
1080
|
+
isolation: import_zod.z.enum(["none", "worktree"]).optional().describe('Optional runtime isolation mode. "worktree" runs in a Git worktree.')
|
|
1081
|
+
}).passthrough();
|
|
1082
|
+
var sessionDepsStore = /* @__PURE__ */ new WeakMap();
|
|
1083
|
+
function storeAgentToolDeps(key, deps) {
|
|
1084
|
+
sessionDepsStore.set(key, deps);
|
|
1085
|
+
}
|
|
1086
|
+
function retrieveAgentToolDeps(key) {
|
|
1087
|
+
return sessionDepsStore.get(key);
|
|
1088
|
+
}
|
|
1089
|
+
function resolveAgentDefinition2(agentType, customRegistry) {
|
|
1090
|
+
if (customRegistry) {
|
|
1091
|
+
const custom = customRegistry(agentType);
|
|
1092
|
+
if (custom) return custom;
|
|
1093
|
+
}
|
|
1094
|
+
const builtIn = getBuiltInAgent(agentType);
|
|
1095
|
+
if (builtIn) return builtIn;
|
|
1096
|
+
return void 0;
|
|
1097
|
+
}
|
|
1098
|
+
function createSubagentManager(deps) {
|
|
1099
|
+
return deps.subagentManager ?? new import_agent_runtime.SubagentManager({
|
|
1100
|
+
runner: createInProcessSubagentRunner(deps)
|
|
1101
|
+
});
|
|
1102
|
+
}
|
|
1103
|
+
function createSpawnRequest(args, agentType, agentDef, deps) {
|
|
1104
|
+
return {
|
|
1105
|
+
type: agentType,
|
|
1106
|
+
label: agentDef.name,
|
|
1107
|
+
parentSessionId: deps.parentSessionId ?? "unknown-session",
|
|
1108
|
+
mode: "background",
|
|
1109
|
+
depth: deps.subagentDepth ?? 1,
|
|
1110
|
+
cwd: deps.cwd ?? process.cwd(),
|
|
1111
|
+
prompt: args.prompt,
|
|
1112
|
+
model: args.model,
|
|
1113
|
+
isolation: args.isolation
|
|
1114
|
+
};
|
|
1115
|
+
}
|
|
1116
|
+
function stringifyUnknownAgentType(agentType) {
|
|
1117
|
+
return JSON.stringify({
|
|
1118
|
+
success: false,
|
|
1119
|
+
output: "",
|
|
1120
|
+
error: `Unknown agent type: ${agentType}`
|
|
1121
|
+
});
|
|
1122
|
+
}
|
|
1123
|
+
function stringifyAgentSuccess(result) {
|
|
1124
|
+
const worktreePath = result.metadata?.["worktreePath"];
|
|
1125
|
+
const branchName = result.metadata?.["branchName"];
|
|
1126
|
+
return JSON.stringify({
|
|
1127
|
+
success: true,
|
|
1128
|
+
output: result.output,
|
|
1129
|
+
agentId: result.jobId,
|
|
1130
|
+
metadata: result.metadata,
|
|
1131
|
+
...typeof worktreePath === "string" ? { worktreePath } : {},
|
|
1132
|
+
...typeof branchName === "string" ? { branchName } : {}
|
|
1133
|
+
});
|
|
1134
|
+
}
|
|
1135
|
+
function stringifyAgentError(message, agentId) {
|
|
1136
|
+
return JSON.stringify({
|
|
1137
|
+
success: false,
|
|
1138
|
+
output: "",
|
|
1139
|
+
error: `Sub-agent error: ${message}`,
|
|
1140
|
+
agentId
|
|
1141
|
+
});
|
|
1142
|
+
}
|
|
1143
|
+
async function runManagedAgent(args, deps, manager) {
|
|
1144
|
+
const agentType = args.subagent_type ?? "general-purpose";
|
|
1145
|
+
const agentDef = resolveAgentDefinition2(agentType, deps.customAgentRegistry);
|
|
1146
|
+
if (!agentDef) {
|
|
1147
|
+
return stringifyUnknownAgentType(agentType);
|
|
1148
|
+
}
|
|
1149
|
+
let agentId;
|
|
1150
|
+
try {
|
|
1151
|
+
const state = await manager.spawn(createSpawnRequest(args, agentType, agentDef, deps));
|
|
1152
|
+
agentId = state.id;
|
|
1153
|
+
const response = await manager.wait(state.id);
|
|
1154
|
+
return stringifyAgentSuccess(response);
|
|
1155
|
+
} catch (err) {
|
|
1156
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1157
|
+
return stringifyAgentError(message, agentId);
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
function createAgentTool(deps) {
|
|
1161
|
+
const manager = createSubagentManager(deps);
|
|
1162
|
+
return (0, import_agent_tools.createZodFunctionTool)(
|
|
1163
|
+
"Agent",
|
|
1164
|
+
AGENT_TOOL_DESCRIPTION,
|
|
1165
|
+
asZodSchema(AgentSchema),
|
|
1166
|
+
async (params) => {
|
|
1167
|
+
const args = params;
|
|
1168
|
+
return runManagedAgent(
|
|
1169
|
+
{
|
|
1170
|
+
prompt: args.prompt,
|
|
1171
|
+
...args.subagent_type !== void 0 ? { subagent_type: args.subagent_type } : {},
|
|
1172
|
+
...args.model !== void 0 ? { model: args.model } : {},
|
|
1173
|
+
...args.isolation !== void 0 ? { isolation: args.isolation } : {}
|
|
1174
|
+
},
|
|
1175
|
+
deps,
|
|
1176
|
+
manager
|
|
1177
|
+
);
|
|
1178
|
+
}
|
|
1179
|
+
);
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
// src/background-tasks/index.ts
|
|
1183
|
+
var import_agent_runtime3 = require("@robota-sdk/agent-runtime");
|
|
1184
|
+
|
|
1185
|
+
// src/background-tasks/background-job-orchestrator.ts
|
|
1186
|
+
var import_agent_runtime2 = require("@robota-sdk/agent-runtime");
|
|
1187
|
+
var DEFAULT_SUMMARY_LENGTH = 1e3;
|
|
1188
|
+
var BackgroundJobOrchestrator = class {
|
|
1189
|
+
manager;
|
|
1190
|
+
now;
|
|
1191
|
+
idFactory;
|
|
1192
|
+
unsubscribeManager;
|
|
1193
|
+
listeners = /* @__PURE__ */ new Set();
|
|
1194
|
+
groups = /* @__PURE__ */ new Map();
|
|
1195
|
+
sequence = 0;
|
|
1196
|
+
constructor(options) {
|
|
1197
|
+
this.manager = options.manager;
|
|
1198
|
+
this.now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
1199
|
+
this.idFactory = options.idFactory ?? (() => this.nextGroupId());
|
|
1200
|
+
this.sequence = options.initialGroups?.length ?? 0;
|
|
1201
|
+
for (const group of options.initialGroups ?? []) this.restoreGroup(group);
|
|
1202
|
+
this.unsubscribeManager = this.manager.subscribe((event) => this.handleTaskEvent(event));
|
|
1203
|
+
}
|
|
1204
|
+
createGroup(request) {
|
|
1205
|
+
const now = this.now();
|
|
1206
|
+
const state = {
|
|
1207
|
+
id: this.idFactory(request),
|
|
1208
|
+
parentSessionId: request.parentSessionId,
|
|
1209
|
+
waitPolicy: request.waitPolicy,
|
|
1210
|
+
taskIds: [...request.taskIds],
|
|
1211
|
+
status: "running",
|
|
1212
|
+
createdAt: now,
|
|
1213
|
+
updatedAt: now,
|
|
1214
|
+
results: [],
|
|
1215
|
+
...request.label ? { label: request.label } : {}
|
|
1216
|
+
};
|
|
1217
|
+
const record = this.createRecord(state);
|
|
1218
|
+
this.groups.set(state.id, record);
|
|
1219
|
+
this.captureExistingTerminalTasks(record);
|
|
1220
|
+
this.emit({ type: "background_job_group_created", group: cloneGroup(record.state) });
|
|
1221
|
+
this.evaluateCompletion(record);
|
|
1222
|
+
return cloneGroup(record.state);
|
|
1223
|
+
}
|
|
1224
|
+
listGroups() {
|
|
1225
|
+
return [...this.groups.values()].map((record) => cloneGroup(record.state));
|
|
1226
|
+
}
|
|
1227
|
+
getGroup(groupId) {
|
|
1228
|
+
const record = this.groups.get(groupId);
|
|
1229
|
+
return record ? cloneGroup(record.state) : void 0;
|
|
1230
|
+
}
|
|
1231
|
+
waitGroup(groupId) {
|
|
1232
|
+
const record = this.groups.get(groupId);
|
|
1233
|
+
if (!record) return Promise.reject(new Error(`Unknown background job group: ${groupId}`));
|
|
1234
|
+
return record.completion;
|
|
1235
|
+
}
|
|
1236
|
+
subscribe(listener) {
|
|
1237
|
+
this.listeners.add(listener);
|
|
1238
|
+
return () => {
|
|
1239
|
+
this.listeners.delete(listener);
|
|
1240
|
+
};
|
|
1241
|
+
}
|
|
1242
|
+
dispose() {
|
|
1243
|
+
this.unsubscribeManager();
|
|
1244
|
+
this.listeners.clear();
|
|
1245
|
+
}
|
|
1246
|
+
nextGroupId() {
|
|
1247
|
+
this.sequence += 1;
|
|
1248
|
+
return `group_${this.sequence}`;
|
|
1249
|
+
}
|
|
1250
|
+
restoreGroup(group) {
|
|
1251
|
+
const record = this.createRecord(cloneGroup(group));
|
|
1252
|
+
this.groups.set(group.id, record);
|
|
1253
|
+
if (group.status === "completed") record.resolve(cloneGroup(group));
|
|
1254
|
+
}
|
|
1255
|
+
createRecord(state) {
|
|
1256
|
+
let resolveGroup = () => {
|
|
1257
|
+
};
|
|
1258
|
+
const completion = new Promise((resolve2) => {
|
|
1259
|
+
resolveGroup = resolve2;
|
|
1260
|
+
});
|
|
1261
|
+
return { state, completion, resolve: resolveGroup };
|
|
1262
|
+
}
|
|
1263
|
+
captureExistingTerminalTasks(record) {
|
|
1264
|
+
for (const taskId of record.state.taskIds) {
|
|
1265
|
+
const task = this.manager.get(taskId);
|
|
1266
|
+
if (task && (0, import_agent_runtime2.isTerminalBackgroundTaskStatus)(task.status)) this.captureTask(record, task);
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
handleTaskEvent(event) {
|
|
1270
|
+
const task = getTerminalTask(event);
|
|
1271
|
+
if (!task) return;
|
|
1272
|
+
for (const record of this.groups.values()) {
|
|
1273
|
+
if (!record.state.taskIds.includes(task.id)) continue;
|
|
1274
|
+
if (!this.captureTask(record, task)) continue;
|
|
1275
|
+
if (record.state.status === "running") this.evaluateCompletion(record);
|
|
1276
|
+
else this.emit({ type: "background_job_group_updated", group: cloneGroup(record.state) });
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
captureTask(record, task) {
|
|
1280
|
+
if (record.state.results.some((result) => result.taskId === task.id)) return false;
|
|
1281
|
+
record.state.results = [...record.state.results, createResultEnvelope(task)];
|
|
1282
|
+
record.state.updatedAt = this.now();
|
|
1283
|
+
return true;
|
|
1284
|
+
}
|
|
1285
|
+
evaluateCompletion(record) {
|
|
1286
|
+
if (record.state.status === "completed") return;
|
|
1287
|
+
if (!shouldComplete(record.state)) {
|
|
1288
|
+
this.emit({ type: "background_job_group_updated", group: cloneGroup(record.state) });
|
|
1289
|
+
return;
|
|
1290
|
+
}
|
|
1291
|
+
const now = this.now();
|
|
1292
|
+
record.state.status = "completed";
|
|
1293
|
+
record.state.completedAt = now;
|
|
1294
|
+
record.state.updatedAt = now;
|
|
1295
|
+
const completed = cloneGroup(record.state);
|
|
1296
|
+
record.resolve(completed);
|
|
1297
|
+
this.emit({ type: "background_job_group_completed", group: completed });
|
|
293
1298
|
}
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
return this.commands.has(name);
|
|
1299
|
+
emit(event) {
|
|
1300
|
+
for (const listener of this.listeners) listener(event);
|
|
297
1301
|
}
|
|
298
1302
|
};
|
|
1303
|
+
function getTerminalTask(event) {
|
|
1304
|
+
if (event.type === "background_task_completed" || event.type === "background_task_failed" || event.type === "background_task_cancelled") {
|
|
1305
|
+
return event.task;
|
|
1306
|
+
}
|
|
1307
|
+
return void 0;
|
|
1308
|
+
}
|
|
1309
|
+
function shouldComplete(group) {
|
|
1310
|
+
if (group.waitPolicy === "manual") return false;
|
|
1311
|
+
if (group.waitPolicy === "wait_any") return group.results.length > 0;
|
|
1312
|
+
return group.taskIds.every((taskId) => group.results.some((result) => result.taskId === taskId));
|
|
1313
|
+
}
|
|
1314
|
+
function createResultEnvelope(task) {
|
|
1315
|
+
return {
|
|
1316
|
+
taskId: task.id,
|
|
1317
|
+
label: task.label,
|
|
1318
|
+
status: task.status,
|
|
1319
|
+
...task.result?.output ? { summary: summarizeOutput(task.result.output) } : {},
|
|
1320
|
+
...task.transcriptPath || task.logPath ? { outputRef: task.transcriptPath ?? task.logPath } : {},
|
|
1321
|
+
...task.error ? { error: { ...task.error } } : {},
|
|
1322
|
+
...task.startedAt ? { startedAt: task.startedAt } : {},
|
|
1323
|
+
...task.completedAt ? { completedAt: task.completedAt } : {}
|
|
1324
|
+
};
|
|
1325
|
+
}
|
|
1326
|
+
function summarizeOutput(output) {
|
|
1327
|
+
const trimmed = output.trim();
|
|
1328
|
+
if (trimmed.length <= DEFAULT_SUMMARY_LENGTH) return trimmed;
|
|
1329
|
+
return `${trimmed.slice(0, DEFAULT_SUMMARY_LENGTH)}...`;
|
|
1330
|
+
}
|
|
1331
|
+
function summarizeBackgroundJobGroup(group) {
|
|
1332
|
+
const completed = countResults(group, "completed");
|
|
1333
|
+
const failed = countResults(group, "failed");
|
|
1334
|
+
const cancelled = countResults(group, "cancelled");
|
|
1335
|
+
return {
|
|
1336
|
+
groupId: group.id,
|
|
1337
|
+
status: group.status,
|
|
1338
|
+
total: group.taskIds.length,
|
|
1339
|
+
completed,
|
|
1340
|
+
failed,
|
|
1341
|
+
cancelled,
|
|
1342
|
+
pending: Math.max(group.taskIds.length - group.results.length, 0),
|
|
1343
|
+
lines: group.results.map((result) => formatResultLine(result))
|
|
1344
|
+
};
|
|
1345
|
+
}
|
|
1346
|
+
function countResults(group, status) {
|
|
1347
|
+
return group.results.filter((result) => result.status === status).length;
|
|
1348
|
+
}
|
|
1349
|
+
function formatResultLine(result) {
|
|
1350
|
+
const detail = normalizeResultDetail(result);
|
|
1351
|
+
const output = result.outputRef && result.summary ? ` (output: ${result.outputRef})` : "";
|
|
1352
|
+
return `[${result.status}] ${result.label} ${result.taskId}: ${detail}${output}`;
|
|
1353
|
+
}
|
|
1354
|
+
function normalizeResultDetail(result) {
|
|
1355
|
+
const detail = result.error?.message ?? result.summary ?? "";
|
|
1356
|
+
const normalized = detail.replace(/\s+/g, " ").trim();
|
|
1357
|
+
return normalized.length > 0 ? normalized : "(no summary)";
|
|
1358
|
+
}
|
|
1359
|
+
function cloneGroup(group) {
|
|
1360
|
+
return {
|
|
1361
|
+
...group,
|
|
1362
|
+
taskIds: [...group.taskIds],
|
|
1363
|
+
results: group.results.map((result) => ({
|
|
1364
|
+
...result,
|
|
1365
|
+
...result.error ? { error: { ...result.error } } : {}
|
|
1366
|
+
}))
|
|
1367
|
+
};
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
// src/background-tasks/index.ts
|
|
1371
|
+
var import_agent_runtime4 = require("@robota-sdk/agent-runtime");
|
|
1372
|
+
var import_agent_runtime5 = require("@robota-sdk/agent-runtime");
|
|
1373
|
+
|
|
1374
|
+
// src/background-tasks/session-background-store.ts
|
|
1375
|
+
var sessionBackgroundTaskManagers = /* @__PURE__ */ new WeakMap();
|
|
1376
|
+
function storeSessionBackgroundTaskManager(key, manager) {
|
|
1377
|
+
sessionBackgroundTaskManagers.set(key, manager);
|
|
1378
|
+
}
|
|
1379
|
+
function retrieveSessionBackgroundTaskManager(key) {
|
|
1380
|
+
return sessionBackgroundTaskManagers.get(key);
|
|
1381
|
+
}
|
|
299
1382
|
|
|
300
1383
|
// src/interactive/interactive-session-execution.ts
|
|
301
1384
|
function isAbortError(err) {
|
|
@@ -336,7 +1419,7 @@ function buildInterruptedResult(sessionHistory, interactiveHistory, historyBefor
|
|
|
336
1419
|
contextState
|
|
337
1420
|
};
|
|
338
1421
|
}
|
|
339
|
-
function persistSession(sessionStore, session, sessionName, cwd, history) {
|
|
1422
|
+
function persistSession(sessionStore, session, sessionName, cwd, history, backgroundState) {
|
|
340
1423
|
try {
|
|
341
1424
|
const sessionId = session.getSessionId();
|
|
342
1425
|
const existing = sessionStore.load(sessionId);
|
|
@@ -347,7 +1430,15 @@ function persistSession(sessionStore, session, sessionName, cwd, history) {
|
|
|
347
1430
|
createdAt: existing?.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
348
1431
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
349
1432
|
messages: session.getHistory(),
|
|
350
|
-
history
|
|
1433
|
+
history,
|
|
1434
|
+
systemPrompt: session.getSystemMessage(),
|
|
1435
|
+
toolSchemas: session.getToolSchemas(),
|
|
1436
|
+
...backgroundState ? {
|
|
1437
|
+
backgroundTasks: [...backgroundState.tasks],
|
|
1438
|
+
backgroundTaskEvents: [...backgroundState.events],
|
|
1439
|
+
backgroundJobGroups: [...backgroundState.groups ?? []],
|
|
1440
|
+
backgroundJobGroupEvents: [...backgroundState.groupEvents ?? []]
|
|
1441
|
+
} : {}
|
|
351
1442
|
});
|
|
352
1443
|
} catch {
|
|
353
1444
|
}
|
|
@@ -374,7 +1465,7 @@ var TOOL_ARG_DISPLAY_MAX = 80;
|
|
|
374
1465
|
var TAIL_KEEP = 30;
|
|
375
1466
|
var MAX_COMPLETED_TOOLS = 50;
|
|
376
1467
|
var STREAMING_FLUSH_INTERVAL_MS = 16;
|
|
377
|
-
function
|
|
1468
|
+
function extractFirstArg2(toolArgs) {
|
|
378
1469
|
if (!toolArgs) return "";
|
|
379
1470
|
const firstVal = Object.values(toolArgs)[0];
|
|
380
1471
|
const raw = typeof firstVal === "string" ? firstVal : JSON.stringify(firstVal ?? "");
|
|
@@ -416,7 +1507,7 @@ function trimCompletedTools(activeTools) {
|
|
|
416
1507
|
});
|
|
417
1508
|
}
|
|
418
1509
|
function applyToolStart(state, event) {
|
|
419
|
-
const firstArg =
|
|
1510
|
+
const firstArg = extractFirstArg2(event.toolArgs);
|
|
420
1511
|
const toolState = { toolName: event.toolName, firstArg, isRunning: true };
|
|
421
1512
|
state.activeTools.push(toolState);
|
|
422
1513
|
state.history.push({
|
|
@@ -560,14 +1651,31 @@ Respond with JSON: { "ok": boolean, "reason"?: string }`;
|
|
|
560
1651
|
// src/assembly/create-session.ts
|
|
561
1652
|
var import_agent_sessions2 = require("@robota-sdk/agent-sessions");
|
|
562
1653
|
|
|
563
|
-
// src/context/system-prompt-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
1654
|
+
// src/context/system-prompt-composer.ts
|
|
1655
|
+
function renderSection(section) {
|
|
1656
|
+
const content = section.content.trim();
|
|
1657
|
+
if (!section.title) return content;
|
|
1658
|
+
return [`## ${section.title}`, content].join("\n");
|
|
1659
|
+
}
|
|
1660
|
+
function composeSystemPrompt(sections) {
|
|
1661
|
+
return [...sections].filter((section) => section.content.trim().length > 0).sort((a, b) => a.priority - b.priority || a.id.localeCompare(b.id)).map((section) => renderSection(section)).join("\n\n");
|
|
1662
|
+
}
|
|
1663
|
+
|
|
1664
|
+
// src/context/system-prompt-section-providers.ts
|
|
1665
|
+
var TRUST_LEVEL_LABELS = {
|
|
1666
|
+
safe: "safe",
|
|
1667
|
+
moderate: "moderate",
|
|
1668
|
+
full: "full"
|
|
568
1669
|
};
|
|
569
|
-
function
|
|
570
|
-
|
|
1670
|
+
function createSection(id, title, priority, content, source) {
|
|
1671
|
+
return { id, title, priority, content, source };
|
|
1672
|
+
}
|
|
1673
|
+
function createWorkingDirectorySection(cwd) {
|
|
1674
|
+
if (!cwd) return void 0;
|
|
1675
|
+
return createSection("runtime-cwd", "Working Directory", 30, `\`${cwd}\``, "runtime");
|
|
1676
|
+
}
|
|
1677
|
+
function createProjectSection(info) {
|
|
1678
|
+
const lines = [];
|
|
571
1679
|
if (info.name !== void 0) {
|
|
572
1680
|
lines.push(`- **Name:** ${info.name}`);
|
|
573
1681
|
}
|
|
@@ -580,83 +1688,118 @@ function buildProjectSection(info) {
|
|
|
580
1688
|
if (info.packageManager !== void 0) {
|
|
581
1689
|
lines.push(`- **Package manager:** ${info.packageManager}`);
|
|
582
1690
|
}
|
|
583
|
-
return lines.join("\n");
|
|
1691
|
+
return createSection("runtime-project", "Current Project", 40, lines.join("\n"), "runtime");
|
|
584
1692
|
}
|
|
585
|
-
function
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
1693
|
+
function createPermissionSection(trustLevel) {
|
|
1694
|
+
return createSection(
|
|
1695
|
+
"permission-mode",
|
|
1696
|
+
"Permission Mode",
|
|
1697
|
+
50,
|
|
1698
|
+
`- **Trust level:** ${TRUST_LEVEL_LABELS[trustLevel]}`,
|
|
1699
|
+
"permissions"
|
|
1700
|
+
);
|
|
591
1701
|
}
|
|
592
|
-
function
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
"
|
|
600
|
-
"",
|
|
601
|
-
|
|
1702
|
+
function createResponseLanguageSection(language) {
|
|
1703
|
+
if (language === void 0 || language.trim().length === 0) return void 0;
|
|
1704
|
+
return createSection("runtime-response-language", "Response Language", 45, language, "runtime");
|
|
1705
|
+
}
|
|
1706
|
+
function createAgentsMdSection(agentsMd) {
|
|
1707
|
+
if (agentsMd.trim().length === 0) return void 0;
|
|
1708
|
+
return createSection(
|
|
1709
|
+
"project-agents-md",
|
|
1710
|
+
"Agent Instructions",
|
|
1711
|
+
10,
|
|
1712
|
+
agentsMd,
|
|
1713
|
+
"project-instructions"
|
|
1714
|
+
);
|
|
1715
|
+
}
|
|
1716
|
+
function createClaudeMdSection(claudeMd) {
|
|
1717
|
+
if (claudeMd.trim().length === 0) return void 0;
|
|
1718
|
+
return createSection("project-claude-md", "Project Notes", 20, claudeMd, "project-instructions");
|
|
1719
|
+
}
|
|
1720
|
+
function createToolDescriptionSection(descriptions) {
|
|
1721
|
+
if (descriptions.length === 0) return void 0;
|
|
1722
|
+
return createSection(
|
|
1723
|
+
"tool-descriptions",
|
|
1724
|
+
"Available Tools",
|
|
1725
|
+
60,
|
|
1726
|
+
descriptions.map((description) => `- ${description}`).join("\n"),
|
|
1727
|
+
"tool"
|
|
1728
|
+
);
|
|
1729
|
+
}
|
|
1730
|
+
function formatCapability(descriptor) {
|
|
1731
|
+
const arg = descriptor.argumentHint ? ` ${descriptor.argumentHint}` : "";
|
|
1732
|
+
return `- ${descriptor.name}${arg}: ${descriptor.description}`;
|
|
1733
|
+
}
|
|
1734
|
+
function createCapabilityKindSection(kind, title, priority, source, descriptors) {
|
|
1735
|
+
const content = descriptors.filter((descriptor) => descriptor.modelInvocable && descriptor.kind === kind).map(formatCapability).join("\n");
|
|
1736
|
+
if (content.trim().length === 0) return void 0;
|
|
1737
|
+
return createSection(`capability-${kind}`, title, priority, content, source);
|
|
1738
|
+
}
|
|
1739
|
+
function createCapabilitySections(descriptors) {
|
|
1740
|
+
const sections = [];
|
|
1741
|
+
const commandSection = createCapabilityKindSection(
|
|
1742
|
+
"builtin-command",
|
|
1743
|
+
"Built-in Commands",
|
|
1744
|
+
70,
|
|
1745
|
+
"command",
|
|
1746
|
+
descriptors
|
|
1747
|
+
);
|
|
1748
|
+
const skillSection = createCapabilityKindSection("skill", "Skills", 80, "skill", descriptors);
|
|
1749
|
+
const agentSection = createCapabilityKindSection("agent", "Agents", 90, "agent", descriptors);
|
|
1750
|
+
const toolSection = createCapabilityKindSection("tool", "Tools", 100, "tool", descriptors);
|
|
1751
|
+
if (commandSection) sections.push(commandSection);
|
|
1752
|
+
if (skillSection) sections.push(skillSection);
|
|
1753
|
+
if (agentSection) sections.push(agentSection);
|
|
1754
|
+
if (toolSection) sections.push(toolSection);
|
|
1755
|
+
return sections;
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1758
|
+
// src/context/system-prompt-builder.ts
|
|
1759
|
+
function appendOptionalSection(sections, section) {
|
|
1760
|
+
if (section !== void 0) sections.push(section);
|
|
1761
|
+
}
|
|
1762
|
+
function mapSkillDescriptors(skills) {
|
|
1763
|
+
return skills.map((skill) => ({
|
|
1764
|
+
name: skill.name,
|
|
1765
|
+
kind: "skill",
|
|
1766
|
+
description: skill.description,
|
|
1767
|
+
userInvocable: true,
|
|
1768
|
+
modelInvocable: skill.disableModelInvocation !== true
|
|
1769
|
+
}));
|
|
1770
|
+
}
|
|
1771
|
+
function mapAgentDescriptors(agents) {
|
|
1772
|
+
return agents.map((agent) => ({
|
|
1773
|
+
name: agent.name,
|
|
1774
|
+
kind: "agent",
|
|
1775
|
+
description: agent.description,
|
|
1776
|
+
userInvocable: false,
|
|
1777
|
+
modelInvocable: true,
|
|
1778
|
+
safety: "background-agent"
|
|
1779
|
+
}));
|
|
1780
|
+
}
|
|
1781
|
+
function buildCapabilityDescriptors(params) {
|
|
1782
|
+
return [
|
|
1783
|
+
...params.commandDescriptors ?? [],
|
|
1784
|
+
...params.skills ? mapSkillDescriptors(params.skills) : [],
|
|
1785
|
+
...params.agents ? mapAgentDescriptors(params.agents) : []
|
|
602
1786
|
];
|
|
603
|
-
return lines.join("\n");
|
|
604
1787
|
}
|
|
605
1788
|
function buildSystemPrompt(params) {
|
|
606
|
-
const { agentsMd, claudeMd, toolDescriptions, trustLevel, projectInfo, cwd, language } = params;
|
|
607
1789
|
const sections = [];
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
);
|
|
618
|
-
}
|
|
619
|
-
sections.push(roleLines.join("\n"));
|
|
620
|
-
if (cwd) {
|
|
621
|
-
sections.push(`## Working Directory
|
|
622
|
-
\`${cwd}\``);
|
|
623
|
-
}
|
|
624
|
-
sections.push(buildProjectSection(projectInfo));
|
|
625
|
-
sections.push(
|
|
626
|
-
[
|
|
627
|
-
"## Permission Mode",
|
|
628
|
-
`Your current trust level is **${TRUST_LEVEL_DESCRIPTIONS[trustLevel]}**.`
|
|
629
|
-
].join("\n")
|
|
630
|
-
);
|
|
631
|
-
if (agentsMd.trim().length > 0) {
|
|
632
|
-
sections.push(["## Agent Instructions", agentsMd].join("\n"));
|
|
633
|
-
}
|
|
634
|
-
if (claudeMd.trim().length > 0) {
|
|
635
|
-
sections.push(["## Project Notes", claudeMd].join("\n"));
|
|
636
|
-
}
|
|
637
|
-
sections.push(
|
|
638
|
-
[
|
|
639
|
-
"## Web Search",
|
|
640
|
-
"You have access to web search. When the user asks to search, look up, or find current/latest information,",
|
|
641
|
-
"you MUST use the web_search tool. Do NOT answer from training data when the user explicitly asks to search.",
|
|
642
|
-
"Always prefer web search for: news, latest versions, current events, live documentation."
|
|
643
|
-
].join("\n")
|
|
644
|
-
);
|
|
645
|
-
const toolsSection = buildToolsSection(toolDescriptions);
|
|
646
|
-
if (toolsSection.length > 0) {
|
|
647
|
-
sections.push(toolsSection);
|
|
648
|
-
}
|
|
649
|
-
if (params.skills !== void 0 && params.skills.length > 0) {
|
|
650
|
-
const skillsSection = buildSkillsSection(params.skills);
|
|
651
|
-
if (skillsSection.length > 0) {
|
|
652
|
-
sections.push(skillsSection);
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
return sections.join("\n\n");
|
|
1790
|
+
appendOptionalSection(sections, createAgentsMdSection(params.agentsMd));
|
|
1791
|
+
appendOptionalSection(sections, createClaudeMdSection(params.claudeMd));
|
|
1792
|
+
appendOptionalSection(sections, createWorkingDirectorySection(params.cwd));
|
|
1793
|
+
sections.push(createProjectSection(params.projectInfo));
|
|
1794
|
+
appendOptionalSection(sections, createResponseLanguageSection(params.language));
|
|
1795
|
+
sections.push(createPermissionSection(params.trustLevel));
|
|
1796
|
+
appendOptionalSection(sections, createToolDescriptionSection(params.toolDescriptions));
|
|
1797
|
+
sections.push(...createCapabilitySections(buildCapabilityDescriptors(params)));
|
|
1798
|
+
return composeSystemPrompt(sections);
|
|
656
1799
|
}
|
|
657
1800
|
|
|
658
1801
|
// src/assembly/create-tools.ts
|
|
659
|
-
var
|
|
1802
|
+
var import_agent_tools2 = require("@robota-sdk/agent-tools");
|
|
660
1803
|
var DEFAULT_TOOL_DESCRIPTIONS = [
|
|
661
1804
|
"Bash \u2014 execute shell commands",
|
|
662
1805
|
"Read \u2014 read file contents with line numbers",
|
|
@@ -668,251 +1811,139 @@ var DEFAULT_TOOL_DESCRIPTIONS = [
|
|
|
668
1811
|
];
|
|
669
1812
|
function createDefaultTools() {
|
|
670
1813
|
return [
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
1814
|
+
import_agent_tools2.bashTool,
|
|
1815
|
+
import_agent_tools2.readTool,
|
|
1816
|
+
import_agent_tools2.writeTool,
|
|
1817
|
+
import_agent_tools2.editTool,
|
|
1818
|
+
import_agent_tools2.globTool,
|
|
1819
|
+
import_agent_tools2.grepTool,
|
|
1820
|
+
import_agent_tools2.webFetchTool,
|
|
1821
|
+
import_agent_tools2.webSearchTool
|
|
679
1822
|
];
|
|
680
1823
|
}
|
|
681
1824
|
|
|
682
|
-
// src/tools/
|
|
683
|
-
var
|
|
684
|
-
var
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
Your role is to complete the assigned task thoroughly and accurately. Follow these guidelines:
|
|
690
|
-
|
|
691
|
-
- Execute the task as described in the prompt. Do not expand scope beyond what is requested.
|
|
692
|
-
- Use the most appropriate tools for each step. Prefer precise tools (Read, Grep, Glob) over broad ones (Bash) when possible.
|
|
693
|
-
- Report your findings clearly and concisely when the task is complete.
|
|
694
|
-
- If a task cannot be completed, explain why and what information is missing.
|
|
695
|
-
- Maintain the same code quality standards as the parent session (strict types, no fallbacks, proper error handling).`;
|
|
696
|
-
var EXPLORE_SYSTEM_PROMPT = `You are a codebase exploration and analysis agent. Your purpose is to search, read, and understand code without making any modifications.
|
|
697
|
-
|
|
698
|
-
You operate in read-only mode. You must NEVER attempt to write or edit files. Your tools are restricted to read-only operations: reading files, searching with grep and glob, and running non-destructive bash commands.
|
|
699
|
-
|
|
700
|
-
Your role is to answer questions about the codebase by:
|
|
701
|
-
|
|
702
|
-
- Searching for relevant files, symbols, and patterns using Glob and Grep.
|
|
703
|
-
- Reading source files, configuration, and documentation to understand structure and behavior.
|
|
704
|
-
- Tracing code paths across modules to understand how components interact.
|
|
705
|
-
- Summarizing findings in a clear, structured format with file paths and line references.
|
|
706
|
-
- Identifying architectural patterns, dependencies, and potential issues.
|
|
707
|
-
|
|
708
|
-
When exploring, prefer targeted searches over broad scans. Start with the most likely locations and narrow down. Always include absolute file paths in your responses so the caller can navigate directly to relevant code.`;
|
|
709
|
-
var PLAN_SYSTEM_PROMPT = `You are a planning, research, and architecture agent. Your purpose is to analyze requirements, research approaches, and produce structured plans without making any code modifications.
|
|
710
|
-
|
|
711
|
-
You operate in read-only mode. You must NEVER attempt to write or edit files. Your tools are restricted to read-only operations.
|
|
712
|
-
|
|
713
|
-
Your role is to:
|
|
714
|
-
|
|
715
|
-
- Analyze the current codebase state relevant to the task by reading specs, source code, and tests.
|
|
716
|
-
- Research implementation approaches by examining existing patterns and architectural conventions in the repository.
|
|
717
|
-
- Identify affected files, modules, and interfaces that a proposed change would touch.
|
|
718
|
-
- Assess risks, dependencies, and potential breaking changes.
|
|
719
|
-
- Produce a structured implementation plan with clear steps, file lists, and ordering.
|
|
720
|
-
- Consider edge cases, error handling, and test coverage requirements.
|
|
721
|
-
|
|
722
|
-
Output your plan in a structured format with numbered steps. For each step, specify which files are involved and what changes are needed. Flag any decisions that require human judgment or clarification.`;
|
|
723
|
-
var BUILT_IN_AGENTS = [
|
|
724
|
-
{
|
|
725
|
-
name: "general-purpose",
|
|
726
|
-
description: "General-purpose task execution agent with full tool access.",
|
|
727
|
-
systemPrompt: GENERAL_PURPOSE_SYSTEM_PROMPT
|
|
728
|
-
},
|
|
729
|
-
{
|
|
730
|
-
name: "Explore",
|
|
731
|
-
description: "Read-only codebase exploration and analysis agent.",
|
|
732
|
-
systemPrompt: EXPLORE_SYSTEM_PROMPT,
|
|
733
|
-
model: "claude-haiku-4-5",
|
|
734
|
-
disallowedTools: ["Write", "Edit"]
|
|
735
|
-
},
|
|
736
|
-
{
|
|
737
|
-
name: "Plan",
|
|
738
|
-
description: "Read-only planning, research, and architecture agent.",
|
|
739
|
-
systemPrompt: PLAN_SYSTEM_PROMPT,
|
|
740
|
-
disallowedTools: ["Write", "Edit"]
|
|
741
|
-
}
|
|
742
|
-
];
|
|
743
|
-
function getBuiltInAgent(name) {
|
|
744
|
-
return BUILT_IN_AGENTS.find((agent) => agent.name === name);
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
// src/assembly/create-subagent-session.ts
|
|
748
|
-
var import_agent_sessions = require("@robota-sdk/agent-sessions");
|
|
749
|
-
|
|
750
|
-
// src/assembly/subagent-prompts.ts
|
|
751
|
-
function getSubagentSuffix() {
|
|
752
|
-
return `When you complete the task, respond with a concise report covering what was done and any key findings \u2014 the caller will relay this to the user, so it only needs the essentials.
|
|
753
|
-
|
|
754
|
-
In your final response, share file paths (always absolute, never relative) that are relevant to the task. Include code snippets only when the exact text is load-bearing \u2014 do not recap code you merely read.
|
|
755
|
-
|
|
756
|
-
Do not use emojis.`;
|
|
757
|
-
}
|
|
758
|
-
function getForkWorkerSuffix() {
|
|
759
|
-
return `You are a worker subagent executing a specific task. Do NOT spawn sub-agents; execute directly. Keep your report under 500 words. Use this structure:
|
|
760
|
-
- Scope: What was requested
|
|
761
|
-
- Result: What was done
|
|
762
|
-
- Key files: Relevant file paths (absolute)
|
|
763
|
-
- Files changed: List of modifications
|
|
764
|
-
- Issues: Any problems encountered`;
|
|
1825
|
+
// src/tools/background-process-tool.ts
|
|
1826
|
+
var import_zod2 = require("zod");
|
|
1827
|
+
var import_agent_tools3 = require("@robota-sdk/agent-tools");
|
|
1828
|
+
var DEFAULT_PROCESS_TIMEOUT_MS = 12e4;
|
|
1829
|
+
function asZodSchema2(schema) {
|
|
1830
|
+
return schema;
|
|
765
1831
|
}
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
1832
|
+
var BackgroundProcessSchema = import_zod2.z.object({
|
|
1833
|
+
command: import_zod2.z.string().describe("The shell command to start in the background"),
|
|
1834
|
+
timeout: import_zod2.z.number().optional().describe("Optional timeout in milliseconds. Default is 120000."),
|
|
1835
|
+
workingDirectory: import_zod2.z.string().optional().describe("Working directory for the command. Defaults to the current project directory."),
|
|
1836
|
+
stdin: import_zod2.z.string().optional().describe("Optional stdin to write after the process starts."),
|
|
1837
|
+
outputLimitBytes: import_zod2.z.number().optional().describe("Maximum captured output bytes kept in the task result.")
|
|
1838
|
+
});
|
|
1839
|
+
function stringifyStarted(taskId, status, command) {
|
|
1840
|
+
return JSON.stringify({
|
|
1841
|
+
success: true,
|
|
1842
|
+
background: true,
|
|
1843
|
+
output: "",
|
|
1844
|
+
taskId,
|
|
1845
|
+
status,
|
|
1846
|
+
command
|
|
1847
|
+
});
|
|
777
1848
|
}
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
};
|
|
785
|
-
function resolveModelId(shortName, _parentModel) {
|
|
786
|
-
return MODEL_SHORTCUTS[shortName] ?? shortName;
|
|
1849
|
+
function stringifyProcessError(message) {
|
|
1850
|
+
return JSON.stringify({
|
|
1851
|
+
success: false,
|
|
1852
|
+
background: true,
|
|
1853
|
+
output: "",
|
|
1854
|
+
error: `Background process error: ${message}`
|
|
1855
|
+
});
|
|
787
1856
|
}
|
|
788
|
-
function
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
1857
|
+
async function startBackgroundProcess(args, deps) {
|
|
1858
|
+
try {
|
|
1859
|
+
const state = await deps.backgroundTaskManager.spawn({
|
|
1860
|
+
kind: "process",
|
|
1861
|
+
label: args.command,
|
|
1862
|
+
mode: "background",
|
|
1863
|
+
parentSessionId: deps.parentSessionId ?? "unknown-session",
|
|
1864
|
+
depth: 0,
|
|
1865
|
+
cwd: args.workingDirectory ?? deps.cwd ?? process.cwd(),
|
|
1866
|
+
command: args.command,
|
|
1867
|
+
stdin: args.stdin,
|
|
1868
|
+
timeoutMs: args.timeout ?? DEFAULT_PROCESS_TIMEOUT_MS,
|
|
1869
|
+
outputLimitBytes: args.outputLimitBytes
|
|
1870
|
+
});
|
|
1871
|
+
return stringifyStarted(state.id, state.status, args.command);
|
|
1872
|
+
} catch (error) {
|
|
1873
|
+
return stringifyProcessError(error instanceof Error ? error.message : String(error));
|
|
797
1874
|
}
|
|
798
|
-
tools = tools.filter((t) => t.getName() !== "Agent");
|
|
799
|
-
return tools;
|
|
800
1875
|
}
|
|
801
|
-
function
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
agentsMd: parentContext.agentsMd,
|
|
809
|
-
isForkWorker: options.isForkWorker ?? false
|
|
810
|
-
});
|
|
811
|
-
const provider = options.provider;
|
|
812
|
-
return new import_agent_sessions.Session({
|
|
813
|
-
tools,
|
|
814
|
-
provider,
|
|
815
|
-
systemMessage,
|
|
816
|
-
terminal,
|
|
817
|
-
model,
|
|
818
|
-
maxTurns: agentDefinition.maxTurns,
|
|
819
|
-
permissions: parentConfig.permissions,
|
|
820
|
-
permissionMode: options.permissionMode,
|
|
821
|
-
defaultTrustLevel: parentConfig.defaultTrustLevel,
|
|
822
|
-
permissionHandler: options.permissionHandler,
|
|
823
|
-
hooks: options.hooks,
|
|
824
|
-
hookTypeExecutors: options.hookTypeExecutors,
|
|
825
|
-
onTextDelta: options.onTextDelta,
|
|
826
|
-
onToolExecution: options.onToolExecution
|
|
827
|
-
});
|
|
1876
|
+
function createBackgroundProcessTool(deps) {
|
|
1877
|
+
return (0, import_agent_tools3.createZodFunctionTool)(
|
|
1878
|
+
"BackgroundProcess",
|
|
1879
|
+
"Start a shell command as a managed background task. Use this for long-running commands that should not block the current conversation. Use /background list, /background read <taskId>, /background cancel <taskId>, or /background close <taskId> to inspect or control it.",
|
|
1880
|
+
asZodSchema2(BackgroundProcessSchema),
|
|
1881
|
+
async (params) => startBackgroundProcess(params, deps)
|
|
1882
|
+
);
|
|
828
1883
|
}
|
|
829
1884
|
|
|
830
|
-
// src/tools/
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
subagent_type: import_zod.z.string().optional().describe('Agent type: "general-purpose", "Explore", "Plan", or a custom agent name'),
|
|
837
|
-
model: import_zod.z.string().optional().describe("Optional model override")
|
|
1885
|
+
// src/tools/command-execution-tool.ts
|
|
1886
|
+
var import_zod3 = require("zod");
|
|
1887
|
+
var import_agent_tools4 = require("@robota-sdk/agent-tools");
|
|
1888
|
+
var CommandExecutionSchema = import_zod3.z.object({
|
|
1889
|
+
command: import_zod3.z.string().describe("Command name to execute, with or without a leading slash"),
|
|
1890
|
+
args: import_zod3.z.string().optional().describe("Arguments to pass to the command")
|
|
838
1891
|
});
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
sessionDepsStore.set(key, deps);
|
|
842
|
-
}
|
|
843
|
-
function retrieveAgentToolDeps(key) {
|
|
844
|
-
return sessionDepsStore.get(key);
|
|
845
|
-
}
|
|
846
|
-
function resolveAgentDefinition(agentType, customRegistry) {
|
|
847
|
-
const builtIn = getBuiltInAgent(agentType);
|
|
848
|
-
if (builtIn) return builtIn;
|
|
849
|
-
if (customRegistry) return customRegistry(agentType);
|
|
850
|
-
return void 0;
|
|
851
|
-
}
|
|
852
|
-
function generateAgentId() {
|
|
853
|
-
return `agent_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
1892
|
+
function asZodSchema3(schema) {
|
|
1893
|
+
return schema;
|
|
854
1894
|
}
|
|
855
|
-
function
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
}
|
|
866
|
-
const effectiveDef = args.model ? { ...agentDef, model: args.model } : agentDef;
|
|
867
|
-
const session = createSubagentSession({
|
|
868
|
-
agentDefinition: effectiveDef,
|
|
869
|
-
parentConfig: deps.config,
|
|
870
|
-
parentContext: deps.context,
|
|
871
|
-
parentTools: deps.tools,
|
|
872
|
-
provider: deps.provider,
|
|
873
|
-
terminal: deps.terminal,
|
|
874
|
-
permissionMode: deps.permissionMode,
|
|
875
|
-
permissionHandler: deps.permissionHandler,
|
|
876
|
-
hooks: deps.hooks,
|
|
877
|
-
hookTypeExecutors: deps.hookTypeExecutors,
|
|
878
|
-
onTextDelta: deps.onTextDelta,
|
|
879
|
-
onToolExecution: deps.onToolExecution
|
|
880
|
-
});
|
|
881
|
-
const agentId = generateAgentId();
|
|
882
|
-
try {
|
|
883
|
-
const response = await session.run(args.prompt);
|
|
884
|
-
return JSON.stringify({
|
|
885
|
-
success: true,
|
|
886
|
-
output: response,
|
|
887
|
-
agentId
|
|
888
|
-
});
|
|
889
|
-
} catch (err) {
|
|
890
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
891
|
-
return JSON.stringify({
|
|
892
|
-
success: false,
|
|
893
|
-
output: "",
|
|
894
|
-
error: `Sub-agent error: ${message}`,
|
|
895
|
-
agentId
|
|
896
|
-
});
|
|
897
|
-
}
|
|
1895
|
+
function normalizeCommand(command) {
|
|
1896
|
+
return command.trim().replace(/^\/+/, "").split(/\s+/)[0] ?? "";
|
|
1897
|
+
}
|
|
1898
|
+
function stringifyCommandResult(command, result) {
|
|
1899
|
+
if (!result) {
|
|
1900
|
+
return JSON.stringify({
|
|
1901
|
+
success: false,
|
|
1902
|
+
command,
|
|
1903
|
+
error: `Unknown command: ${command}`
|
|
1904
|
+
});
|
|
898
1905
|
}
|
|
899
|
-
return
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
1906
|
+
return JSON.stringify({
|
|
1907
|
+
success: result.success,
|
|
1908
|
+
command,
|
|
1909
|
+
message: result.message,
|
|
1910
|
+
data: result.data
|
|
1911
|
+
});
|
|
1912
|
+
}
|
|
1913
|
+
function createCommandExecutionTool(deps) {
|
|
1914
|
+
return (0, import_agent_tools4.createZodFunctionTool)(
|
|
1915
|
+
"ExecuteCommand",
|
|
1916
|
+
"Executes a registered model-invocable Robota command through the command registry. Accepted command names and argument grammar come from registered command descriptors.",
|
|
1917
|
+
asZodSchema3(CommandExecutionSchema),
|
|
903
1918
|
async (params) => {
|
|
904
|
-
|
|
1919
|
+
const args = CommandExecutionSchema.parse(params);
|
|
1920
|
+
const command = normalizeCommand(args.command);
|
|
1921
|
+
if (!deps.isModelInvocable(command)) {
|
|
1922
|
+
return JSON.stringify({
|
|
1923
|
+
success: false,
|
|
1924
|
+
command,
|
|
1925
|
+
error: `Command is not model-invocable: ${command}`
|
|
1926
|
+
});
|
|
1927
|
+
}
|
|
1928
|
+
return stringifyCommandResult(command, await deps.execute(command, args.args ?? ""));
|
|
905
1929
|
}
|
|
906
1930
|
);
|
|
907
1931
|
}
|
|
908
1932
|
|
|
1933
|
+
// src/assembly/create-session.ts
|
|
1934
|
+
var import_agent_runtime6 = require("@robota-sdk/agent-runtime");
|
|
1935
|
+
|
|
909
1936
|
// src/agents/agent-definition-loader.ts
|
|
910
|
-
var
|
|
911
|
-
var
|
|
912
|
-
var
|
|
913
|
-
var
|
|
1937
|
+
var import_node_fs2 = require("fs");
|
|
1938
|
+
var import_node_path2 = require("path");
|
|
1939
|
+
var import_node_os2 = require("os");
|
|
1940
|
+
var LIST_KEYS2 = /* @__PURE__ */ new Set(["tools", "disallowedTools"]);
|
|
914
1941
|
var NUMBER_KEYS = /* @__PURE__ */ new Set(["maxTurns"]);
|
|
915
|
-
function
|
|
1942
|
+
function parseListValue2(rawValue) {
|
|
1943
|
+
const separator = rawValue.includes(",") ? /\s*,\s*/ : /\s+/;
|
|
1944
|
+
return rawValue.split(separator).map((value) => value.trim()).filter((value) => value.length > 0);
|
|
1945
|
+
}
|
|
1946
|
+
function parseFrontmatter2(content) {
|
|
916
1947
|
const lines = content.split("\n");
|
|
917
1948
|
if (lines[0]?.trim() !== "---") {
|
|
918
1949
|
return { frontmatter: null, body: content };
|
|
@@ -934,8 +1965,8 @@ function parseFrontmatter(content) {
|
|
|
934
1965
|
if (!match) continue;
|
|
935
1966
|
const key = match[1];
|
|
936
1967
|
const rawValue = match[2].trim();
|
|
937
|
-
if (
|
|
938
|
-
result[key] = rawValue
|
|
1968
|
+
if (LIST_KEYS2.has(key)) {
|
|
1969
|
+
result[key] = parseListValue2(rawValue);
|
|
939
1970
|
} else if (NUMBER_KEYS.has(key)) {
|
|
940
1971
|
result[key] = parseInt(rawValue, 10);
|
|
941
1972
|
} else {
|
|
@@ -949,20 +1980,20 @@ function parseFrontmatter(content) {
|
|
|
949
1980
|
};
|
|
950
1981
|
}
|
|
951
1982
|
function scanAgentsDir(dir) {
|
|
952
|
-
if (!(0,
|
|
1983
|
+
if (!(0, import_node_fs2.existsSync)(dir)) return [];
|
|
953
1984
|
const agents = [];
|
|
954
1985
|
let entries;
|
|
955
1986
|
try {
|
|
956
|
-
entries = (0,
|
|
1987
|
+
entries = (0, import_node_fs2.readdirSync)(dir, { withFileTypes: true });
|
|
957
1988
|
} catch {
|
|
958
1989
|
return [];
|
|
959
1990
|
}
|
|
960
1991
|
for (const entry of entries) {
|
|
961
1992
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
962
|
-
const filePath = (0,
|
|
963
|
-
const content = (0,
|
|
964
|
-
const { frontmatter, body } =
|
|
965
|
-
const fallbackName = (0,
|
|
1993
|
+
const filePath = (0, import_node_path2.join)(dir, entry.name);
|
|
1994
|
+
const content = (0, import_node_fs2.readFileSync)(filePath, "utf-8");
|
|
1995
|
+
const { frontmatter, body } = parseFrontmatter2(content);
|
|
1996
|
+
const fallbackName = (0, import_node_path2.basename)(entry.name, ".md");
|
|
966
1997
|
const agent = {
|
|
967
1998
|
name: frontmatter?.name ?? fallbackName,
|
|
968
1999
|
description: frontmatter?.description ?? "",
|
|
@@ -982,13 +2013,16 @@ var AgentDefinitionLoader = class {
|
|
|
982
2013
|
home;
|
|
983
2014
|
constructor(cwd, home) {
|
|
984
2015
|
this.cwd = cwd;
|
|
985
|
-
this.home = home ?? (0,
|
|
2016
|
+
this.home = home ?? (0, import_node_os2.homedir)();
|
|
986
2017
|
}
|
|
987
2018
|
/** Load all agent definitions, merged with built-in agents. Custom overrides built-in on name collision. */
|
|
988
2019
|
loadAll() {
|
|
989
2020
|
const sources = [
|
|
990
|
-
scanAgentsDir((0,
|
|
991
|
-
scanAgentsDir((0,
|
|
2021
|
+
scanAgentsDir((0, import_node_path2.join)(this.cwd, ".robota", "agents")),
|
|
2022
|
+
scanAgentsDir((0, import_node_path2.join)(this.cwd, ".agents", "agents")),
|
|
2023
|
+
scanAgentsDir((0, import_node_path2.join)(this.cwd, ".claude", "agents")),
|
|
2024
|
+
scanAgentsDir((0, import_node_path2.join)(this.home, ".robota", "agents")),
|
|
2025
|
+
scanAgentsDir((0, import_node_path2.join)(this.home, ".claude", "agents"))
|
|
992
2026
|
];
|
|
993
2027
|
const seen = /* @__PURE__ */ new Set();
|
|
994
2028
|
const customAgents = [];
|
|
@@ -1014,7 +2048,49 @@ var AgentDefinitionLoader = class {
|
|
|
1014
2048
|
}
|
|
1015
2049
|
};
|
|
1016
2050
|
|
|
2051
|
+
// src/assembly/background-task-hooks.ts
|
|
2052
|
+
var import_agent_core2 = require("@robota-sdk/agent-core");
|
|
2053
|
+
function getSubagentHookEvent(event) {
|
|
2054
|
+
if (event.type === "background_task_started" && event.task.kind === "agent") {
|
|
2055
|
+
return "SubagentStart";
|
|
2056
|
+
}
|
|
2057
|
+
if ((event.type === "background_task_completed" || event.type === "background_task_failed" || event.type === "background_task_cancelled") && event.task.kind === "agent") {
|
|
2058
|
+
return "SubagentStop";
|
|
2059
|
+
}
|
|
2060
|
+
return void 0;
|
|
2061
|
+
}
|
|
2062
|
+
function fireSubagentLifecycleHook(event, cwd, hooks, hookTypeExecutors) {
|
|
2063
|
+
const hookEventName = getSubagentHookEvent(event);
|
|
2064
|
+
if (!hookEventName || !("task" in event)) return;
|
|
2065
|
+
const input = {
|
|
2066
|
+
session_id: event.task.parentSessionId,
|
|
2067
|
+
cwd,
|
|
2068
|
+
hook_event_name: hookEventName,
|
|
2069
|
+
agent_id: event.task.id,
|
|
2070
|
+
agent_type: event.task.agentType ?? event.task.label,
|
|
2071
|
+
...event.task.transcriptPath ? {
|
|
2072
|
+
agent_transcript_path: event.task.transcriptPath,
|
|
2073
|
+
transcript_path: event.task.transcriptPath
|
|
2074
|
+
} : {},
|
|
2075
|
+
...event.task.error?.message || event.task.timeoutReason ? { reason: event.task.error?.message ?? event.task.timeoutReason } : {},
|
|
2076
|
+
...hookEventName === "SubagentStop" ? {
|
|
2077
|
+
stop_hook_active: false,
|
|
2078
|
+
...event.task.result?.output ? { last_assistant_message: event.task.result.output } : {}
|
|
2079
|
+
} : {},
|
|
2080
|
+
env: {
|
|
2081
|
+
CLAUDE_PROJECT_DIR: cwd,
|
|
2082
|
+
CLAUDE_SESSION_ID: event.task.parentSessionId,
|
|
2083
|
+
ROBOTA_AGENT_ID: event.task.id,
|
|
2084
|
+
ROBOTA_AGENT_TYPE: event.task.agentType ?? event.task.label
|
|
2085
|
+
}
|
|
2086
|
+
};
|
|
2087
|
+
void (0, import_agent_core2.runHooks)(hooks, hookEventName, input, hookTypeExecutors).catch(() => void 0);
|
|
2088
|
+
}
|
|
2089
|
+
|
|
1017
2090
|
// src/assembly/create-session.ts
|
|
2091
|
+
var ID_RADIX = 36;
|
|
2092
|
+
var ID_RANDOM_LENGTH = 9;
|
|
2093
|
+
var DEFAULT_PROVIDER_IDLE_TIMEOUT_MS = 12e4;
|
|
1018
2094
|
function createSession(options) {
|
|
1019
2095
|
if (!options.provider) {
|
|
1020
2096
|
throw new Error(
|
|
@@ -1022,9 +2098,18 @@ function createSession(options) {
|
|
|
1022
2098
|
);
|
|
1023
2099
|
}
|
|
1024
2100
|
const provider = options.provider;
|
|
2101
|
+
const cwd = options.cwd ?? process.cwd();
|
|
2102
|
+
const sessionId = options.sessionId ?? createSessionId();
|
|
1025
2103
|
const defaultTools = createDefaultTools();
|
|
1026
2104
|
const tools = [...defaultTools, ...options.additionalTools ?? []];
|
|
1027
|
-
|
|
2105
|
+
if (options.modelCommandExecutor && options.isModelCommandInvocable) {
|
|
2106
|
+
tools.push(
|
|
2107
|
+
createCommandExecutionTool({
|
|
2108
|
+
execute: options.modelCommandExecutor,
|
|
2109
|
+
isModelInvocable: options.isModelCommandInvocable
|
|
2110
|
+
})
|
|
2111
|
+
);
|
|
2112
|
+
}
|
|
1028
2113
|
const hookTypeExecutors = [];
|
|
1029
2114
|
if (options.providerFactory) {
|
|
1030
2115
|
hookTypeExecutors.push(
|
|
@@ -1044,31 +2129,102 @@ function createSession(options) {
|
|
|
1044
2129
|
if (options.additionalHookExecutors) {
|
|
1045
2130
|
hookTypeExecutors.push(...options.additionalHookExecutors);
|
|
1046
2131
|
}
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
2132
|
+
let agentToolDeps;
|
|
2133
|
+
let agentDefinitions = [];
|
|
2134
|
+
let backgroundTaskManager;
|
|
2135
|
+
if (options.enableAgentRuntime) {
|
|
2136
|
+
const agentLoader = new AgentDefinitionLoader(cwd);
|
|
2137
|
+
agentDefinitions = agentLoader.loadAll();
|
|
2138
|
+
agentToolDeps = {
|
|
2139
|
+
config: options.config,
|
|
2140
|
+
context: options.context,
|
|
2141
|
+
tools,
|
|
2142
|
+
terminal: options.terminal,
|
|
2143
|
+
provider,
|
|
2144
|
+
cwd,
|
|
2145
|
+
parentSessionId: sessionId,
|
|
2146
|
+
permissionMode: options.permissionMode,
|
|
2147
|
+
permissionHandler: options.permissionHandler,
|
|
2148
|
+
hooks: options.config.hooks,
|
|
2149
|
+
hookTypeExecutors: hookTypeExecutors.length > 0 ? hookTypeExecutors : void 0,
|
|
2150
|
+
onTextDelta: options.onTextDelta,
|
|
2151
|
+
onToolExecution: options.onToolExecution,
|
|
2152
|
+
customAgentRegistry: (name) => agentLoader.getAgent(name),
|
|
2153
|
+
agentDefinitions
|
|
2154
|
+
};
|
|
2155
|
+
const subagentManager = new import_agent_runtime6.SubagentManager({
|
|
2156
|
+
runner: (options.subagentRunnerFactory ?? createInProcessSubagentRunner)(agentToolDeps),
|
|
2157
|
+
backgroundTaskRunners: options.backgroundTaskRunners
|
|
2158
|
+
});
|
|
2159
|
+
agentToolDeps.subagentManager = subagentManager;
|
|
2160
|
+
backgroundTaskManager = subagentManager.getBackgroundTaskManager();
|
|
2161
|
+
agentToolDeps.backgroundTaskManager = backgroundTaskManager;
|
|
2162
|
+
} else {
|
|
2163
|
+
backgroundTaskManager = new import_agent_runtime6.BackgroundTaskManager({
|
|
2164
|
+
runners: options.backgroundTaskRunners ?? []
|
|
2165
|
+
});
|
|
2166
|
+
}
|
|
2167
|
+
const sessionLogger = options.sessionLogger;
|
|
2168
|
+
if (backgroundTaskManager && sessionLogger) {
|
|
2169
|
+
backgroundTaskManager.subscribe(
|
|
2170
|
+
(event) => logBackgroundTaskEvent(sessionLogger, sessionId, event)
|
|
2171
|
+
);
|
|
2172
|
+
}
|
|
2173
|
+
if (backgroundTaskManager) {
|
|
2174
|
+
backgroundTaskManager.subscribe(
|
|
2175
|
+
(event) => fireSubagentLifecycleHook(
|
|
2176
|
+
event,
|
|
2177
|
+
cwd,
|
|
2178
|
+
options.config.hooks,
|
|
2179
|
+
hookTypeExecutors.length > 0 ? hookTypeExecutors : void 0
|
|
2180
|
+
)
|
|
2181
|
+
);
|
|
2182
|
+
}
|
|
2183
|
+
let backgroundProcessToolDeps;
|
|
2184
|
+
if (backgroundTaskManager && options.backgroundTaskRunners?.some((runner) => runner.kind === "process")) {
|
|
2185
|
+
backgroundProcessToolDeps = {
|
|
2186
|
+
backgroundTaskManager,
|
|
2187
|
+
cwd,
|
|
2188
|
+
parentSessionId: sessionId
|
|
2189
|
+
};
|
|
2190
|
+
tools.push(createBackgroundProcessTool(backgroundProcessToolDeps));
|
|
2191
|
+
}
|
|
2192
|
+
if (agentToolDeps) {
|
|
2193
|
+
tools.push(createAgentTool(agentToolDeps));
|
|
2194
|
+
}
|
|
1062
2195
|
const buildPrompt = options.systemPromptBuilder ?? buildSystemPrompt;
|
|
2196
|
+
const defaultToolDescriptions = [
|
|
2197
|
+
...DEFAULT_TOOL_DESCRIPTIONS,
|
|
2198
|
+
...agentToolDeps ? [createAgentToolPromptDescription(agentDefinitions)] : [],
|
|
2199
|
+
...options.modelCommandExecutor ? ["ExecuteCommand \u2014 execute model-invocable Robota commands"] : []
|
|
2200
|
+
];
|
|
1063
2201
|
const systemMessage = buildPrompt({
|
|
1064
2202
|
agentsMd: options.context.agentsMd,
|
|
1065
2203
|
claudeMd: options.context.claudeMd,
|
|
1066
|
-
toolDescriptions: options.toolDescriptions ??
|
|
2204
|
+
toolDescriptions: options.toolDescriptions ?? (backgroundProcessToolDeps ? [
|
|
2205
|
+
...defaultToolDescriptions,
|
|
2206
|
+
"BackgroundProcess \u2014 start long-running shell commands as managed background tasks"
|
|
2207
|
+
] : defaultToolDescriptions),
|
|
1067
2208
|
trustLevel: options.config.defaultTrustLevel,
|
|
1068
2209
|
projectInfo: options.projectInfo ?? { type: "unknown", language: "unknown" },
|
|
1069
|
-
cwd
|
|
1070
|
-
language: options.config.language
|
|
2210
|
+
cwd,
|
|
2211
|
+
language: options.config.language,
|
|
2212
|
+
skills: new SkillCommandSource(cwd).getModelInvocableSkills().map((skill) => ({
|
|
2213
|
+
name: skill.name,
|
|
2214
|
+
description: skill.description,
|
|
2215
|
+
disableModelInvocation: skill.disableModelInvocation
|
|
2216
|
+
})),
|
|
2217
|
+
...agentDefinitions.length > 0 ? {
|
|
2218
|
+
agents: agentDefinitions.map((agent) => ({
|
|
2219
|
+
name: agent.name,
|
|
2220
|
+
description: agent.description
|
|
2221
|
+
}))
|
|
2222
|
+
} : {},
|
|
2223
|
+
commandDescriptors: options.commandDescriptors ?? []
|
|
1071
2224
|
});
|
|
2225
|
+
const finalSystemMessage = options.appendSystemPrompt ? `${systemMessage}
|
|
2226
|
+
|
|
2227
|
+
${options.appendSystemPrompt}` : systemMessage;
|
|
1072
2228
|
const defaultAllow = [
|
|
1073
2229
|
"Read(.agents/**)",
|
|
1074
2230
|
"Read(.claude/**)",
|
|
@@ -1077,23 +2233,25 @@ function createSession(options) {
|
|
|
1077
2233
|
"Glob(.claude/**)",
|
|
1078
2234
|
"Glob(.robota/**)"
|
|
1079
2235
|
];
|
|
2236
|
+
const allowedToolPatterns = (options.allowedTools ?? []).map((name) => `${name}(*)`);
|
|
1080
2237
|
const mergedPermissions = {
|
|
1081
|
-
allow: [...defaultAllow, ...options.config.permissions.allow ?? []],
|
|
2238
|
+
allow: [...defaultAllow, ...options.config.permissions.allow ?? [], ...allowedToolPatterns],
|
|
1082
2239
|
deny: options.config.permissions.deny ?? []
|
|
1083
2240
|
};
|
|
1084
2241
|
const session = new import_agent_sessions2.Session({
|
|
1085
2242
|
tools,
|
|
1086
2243
|
provider,
|
|
1087
|
-
systemMessage,
|
|
2244
|
+
systemMessage: finalSystemMessage,
|
|
1088
2245
|
terminal: options.terminal,
|
|
1089
2246
|
permissions: mergedPermissions,
|
|
1090
2247
|
hooks: options.config.hooks,
|
|
1091
2248
|
permissionMode: options.permissionMode,
|
|
1092
2249
|
defaultTrustLevel: options.config.defaultTrustLevel,
|
|
1093
2250
|
model: options.config.provider.model,
|
|
2251
|
+
providerTimeout: options.config.provider.timeout ?? DEFAULT_PROVIDER_IDLE_TIMEOUT_MS,
|
|
1094
2252
|
maxTurns: options.maxTurns,
|
|
1095
2253
|
sessionStore: options.sessionStore,
|
|
1096
|
-
sessionId
|
|
2254
|
+
sessionId,
|
|
1097
2255
|
permissionHandler: options.permissionHandler,
|
|
1098
2256
|
onTextDelta: options.onTextDelta,
|
|
1099
2257
|
onToolExecution: options.onToolExecution,
|
|
@@ -1103,43 +2261,55 @@ function createSession(options) {
|
|
|
1103
2261
|
sessionLogger: options.sessionLogger,
|
|
1104
2262
|
hookTypeExecutors: hookTypeExecutors.length > 0 ? hookTypeExecutors : void 0
|
|
1105
2263
|
});
|
|
1106
|
-
|
|
2264
|
+
if (agentToolDeps) agentToolDeps.parentSessionId = session.getSessionId();
|
|
2265
|
+
if (backgroundProcessToolDeps) backgroundProcessToolDeps.parentSessionId = session.getSessionId();
|
|
2266
|
+
if (backgroundTaskManager) storeSessionBackgroundTaskManager(session, backgroundTaskManager);
|
|
2267
|
+
if (agentToolDeps) storeAgentToolDeps(session, agentToolDeps);
|
|
1107
2268
|
return session;
|
|
1108
2269
|
}
|
|
2270
|
+
function createSessionId() {
|
|
2271
|
+
return `session_${Date.now()}_${Math.random().toString(ID_RADIX).substr(2, ID_RANDOM_LENGTH)}`;
|
|
2272
|
+
}
|
|
2273
|
+
function logBackgroundTaskEvent(logger, sessionId, event) {
|
|
2274
|
+
logger.log(sessionId, "background_task_event", {
|
|
2275
|
+
backgroundEventType: event.type,
|
|
2276
|
+
backgroundEvent: event
|
|
2277
|
+
});
|
|
2278
|
+
}
|
|
1109
2279
|
|
|
1110
2280
|
// src/assembly/subagent-logger.ts
|
|
1111
|
-
var
|
|
1112
|
-
var
|
|
2281
|
+
var import_node_fs3 = require("fs");
|
|
2282
|
+
var import_node_path3 = require("path");
|
|
1113
2283
|
var import_agent_sessions3 = require("@robota-sdk/agent-sessions");
|
|
1114
2284
|
function createSubagentLogger(parentSessionId, _agentId, baseLogsDir) {
|
|
1115
|
-
const subagentDir = (0,
|
|
1116
|
-
(0,
|
|
2285
|
+
const subagentDir = (0, import_node_path3.join)(baseLogsDir, parentSessionId, "subagents");
|
|
2286
|
+
(0, import_node_fs3.mkdirSync)(subagentDir, { recursive: true });
|
|
1117
2287
|
return new import_agent_sessions3.FileSessionLogger(subagentDir);
|
|
1118
2288
|
}
|
|
1119
2289
|
function resolveSubagentLogDir(parentSessionId, baseLogsDir) {
|
|
1120
|
-
return (0,
|
|
2290
|
+
return (0, import_node_path3.join)(baseLogsDir, parentSessionId, "subagents");
|
|
1121
2291
|
}
|
|
1122
2292
|
|
|
1123
2293
|
// src/interactive/interactive-session-init.ts
|
|
1124
2294
|
var import_agent_sessions4 = require("@robota-sdk/agent-sessions");
|
|
1125
2295
|
|
|
1126
2296
|
// src/paths.ts
|
|
1127
|
-
var
|
|
1128
|
-
var
|
|
2297
|
+
var import_node_path4 = require("path");
|
|
2298
|
+
var import_node_os3 = require("os");
|
|
1129
2299
|
function projectPaths(cwd) {
|
|
1130
|
-
const base = (0,
|
|
2300
|
+
const base = (0, import_node_path4.join)(cwd, ".robota");
|
|
1131
2301
|
return {
|
|
1132
|
-
settings: (0,
|
|
1133
|
-
settingsLocal: (0,
|
|
1134
|
-
logs: (0,
|
|
1135
|
-
sessions: (0,
|
|
2302
|
+
settings: (0, import_node_path4.join)(base, "settings.json"),
|
|
2303
|
+
settingsLocal: (0, import_node_path4.join)(base, "settings.local.json"),
|
|
2304
|
+
logs: (0, import_node_path4.join)(base, "logs"),
|
|
2305
|
+
sessions: (0, import_node_path4.join)(base, "sessions")
|
|
1136
2306
|
};
|
|
1137
2307
|
}
|
|
1138
2308
|
function userPaths() {
|
|
1139
|
-
const base = (0,
|
|
2309
|
+
const base = (0, import_node_path4.join)((0, import_node_os3.homedir)(), ".robota");
|
|
1140
2310
|
return {
|
|
1141
|
-
settings: (0,
|
|
1142
|
-
sessions: (0,
|
|
2311
|
+
settings: (0, import_node_path4.join)(base, "settings.json"),
|
|
2312
|
+
sessions: (0, import_node_path4.join)(base, "sessions")
|
|
1143
2313
|
};
|
|
1144
2314
|
}
|
|
1145
2315
|
|
|
@@ -1148,77 +2318,96 @@ var import_fs = require("fs");
|
|
|
1148
2318
|
var import_path = require("path");
|
|
1149
2319
|
|
|
1150
2320
|
// src/config/config-types.ts
|
|
1151
|
-
var
|
|
1152
|
-
var ProviderSchema =
|
|
1153
|
-
name:
|
|
1154
|
-
model:
|
|
1155
|
-
apiKey:
|
|
2321
|
+
var import_zod4 = require("zod");
|
|
2322
|
+
var ProviderSchema = import_zod4.z.object({
|
|
2323
|
+
name: import_zod4.z.string().optional(),
|
|
2324
|
+
model: import_zod4.z.string().optional(),
|
|
2325
|
+
apiKey: import_zod4.z.string().optional(),
|
|
2326
|
+
baseURL: import_zod4.z.string().optional(),
|
|
2327
|
+
timeout: import_zod4.z.number().optional()
|
|
2328
|
+
});
|
|
2329
|
+
var ProviderProfileSchema = import_zod4.z.object({
|
|
2330
|
+
type: import_zod4.z.string().optional(),
|
|
2331
|
+
model: import_zod4.z.string().optional(),
|
|
2332
|
+
apiKey: import_zod4.z.string().optional(),
|
|
2333
|
+
baseURL: import_zod4.z.string().optional(),
|
|
2334
|
+
timeout: import_zod4.z.number().optional()
|
|
1156
2335
|
});
|
|
1157
|
-
var PermissionsSchema =
|
|
2336
|
+
var PermissionsSchema = import_zod4.z.object({
|
|
1158
2337
|
/** Patterns that are always approved without prompting */
|
|
1159
|
-
allow:
|
|
2338
|
+
allow: import_zod4.z.array(import_zod4.z.string()).optional(),
|
|
1160
2339
|
/** Patterns that are always denied */
|
|
1161
|
-
deny:
|
|
2340
|
+
deny: import_zod4.z.array(import_zod4.z.string()).optional()
|
|
1162
2341
|
});
|
|
1163
|
-
var EnvSchema =
|
|
1164
|
-
var CommandHookDefinitionSchema =
|
|
1165
|
-
type:
|
|
1166
|
-
command:
|
|
1167
|
-
timeout:
|
|
2342
|
+
var EnvSchema = import_zod4.z.record(import_zod4.z.string()).optional();
|
|
2343
|
+
var CommandHookDefinitionSchema = import_zod4.z.object({
|
|
2344
|
+
type: import_zod4.z.literal("command"),
|
|
2345
|
+
command: import_zod4.z.string(),
|
|
2346
|
+
timeout: import_zod4.z.number().optional()
|
|
1168
2347
|
});
|
|
1169
|
-
var HttpHookDefinitionSchema =
|
|
1170
|
-
type:
|
|
1171
|
-
url:
|
|
1172
|
-
headers:
|
|
1173
|
-
timeout:
|
|
2348
|
+
var HttpHookDefinitionSchema = import_zod4.z.object({
|
|
2349
|
+
type: import_zod4.z.literal("http"),
|
|
2350
|
+
url: import_zod4.z.string(),
|
|
2351
|
+
headers: import_zod4.z.record(import_zod4.z.string()).optional(),
|
|
2352
|
+
timeout: import_zod4.z.number().optional()
|
|
1174
2353
|
});
|
|
1175
|
-
var PromptHookDefinitionSchema =
|
|
1176
|
-
type:
|
|
1177
|
-
prompt:
|
|
1178
|
-
model:
|
|
2354
|
+
var PromptHookDefinitionSchema = import_zod4.z.object({
|
|
2355
|
+
type: import_zod4.z.literal("prompt"),
|
|
2356
|
+
prompt: import_zod4.z.string(),
|
|
2357
|
+
model: import_zod4.z.string().optional()
|
|
1179
2358
|
});
|
|
1180
|
-
var AgentHookDefinitionSchema =
|
|
1181
|
-
type:
|
|
1182
|
-
agent:
|
|
1183
|
-
maxTurns:
|
|
1184
|
-
timeout:
|
|
2359
|
+
var AgentHookDefinitionSchema = import_zod4.z.object({
|
|
2360
|
+
type: import_zod4.z.literal("agent"),
|
|
2361
|
+
agent: import_zod4.z.string(),
|
|
2362
|
+
maxTurns: import_zod4.z.number().optional(),
|
|
2363
|
+
timeout: import_zod4.z.number().optional()
|
|
1185
2364
|
});
|
|
1186
|
-
var HookDefinitionSchema =
|
|
2365
|
+
var HookDefinitionSchema = import_zod4.z.discriminatedUnion("type", [
|
|
1187
2366
|
CommandHookDefinitionSchema,
|
|
1188
2367
|
HttpHookDefinitionSchema,
|
|
1189
2368
|
PromptHookDefinitionSchema,
|
|
1190
2369
|
AgentHookDefinitionSchema
|
|
1191
2370
|
]);
|
|
1192
|
-
var HookGroupSchema =
|
|
1193
|
-
matcher:
|
|
1194
|
-
hooks:
|
|
2371
|
+
var HookGroupSchema = import_zod4.z.object({
|
|
2372
|
+
matcher: import_zod4.z.string(),
|
|
2373
|
+
hooks: import_zod4.z.array(HookDefinitionSchema)
|
|
1195
2374
|
});
|
|
1196
|
-
var HooksSchema =
|
|
1197
|
-
PreToolUse:
|
|
1198
|
-
PostToolUse:
|
|
1199
|
-
SessionStart:
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
2375
|
+
var HooksSchema = import_zod4.z.object({
|
|
2376
|
+
PreToolUse: import_zod4.z.array(HookGroupSchema).optional(),
|
|
2377
|
+
PostToolUse: import_zod4.z.array(HookGroupSchema).optional(),
|
|
2378
|
+
SessionStart: import_zod4.z.array(HookGroupSchema).optional(),
|
|
2379
|
+
SessionEnd: import_zod4.z.array(HookGroupSchema).optional(),
|
|
2380
|
+
Stop: import_zod4.z.array(HookGroupSchema).optional(),
|
|
2381
|
+
StopFailure: import_zod4.z.array(HookGroupSchema).optional(),
|
|
2382
|
+
PreCompact: import_zod4.z.array(HookGroupSchema).optional(),
|
|
2383
|
+
PostCompact: import_zod4.z.array(HookGroupSchema).optional(),
|
|
2384
|
+
UserPromptSubmit: import_zod4.z.array(HookGroupSchema).optional(),
|
|
2385
|
+
SubagentStart: import_zod4.z.array(HookGroupSchema).optional(),
|
|
2386
|
+
SubagentStop: import_zod4.z.array(HookGroupSchema).optional(),
|
|
2387
|
+
WorktreeCreate: import_zod4.z.array(HookGroupSchema).optional(),
|
|
2388
|
+
WorktreeRemove: import_zod4.z.array(HookGroupSchema).optional()
|
|
1205
2389
|
}).optional();
|
|
1206
|
-
var EnabledPluginsSchema =
|
|
1207
|
-
var MarketplaceSourceSchema =
|
|
1208
|
-
source:
|
|
1209
|
-
type:
|
|
1210
|
-
repo:
|
|
1211
|
-
url:
|
|
1212
|
-
path:
|
|
1213
|
-
ref:
|
|
2390
|
+
var EnabledPluginsSchema = import_zod4.z.record(import_zod4.z.boolean()).optional();
|
|
2391
|
+
var MarketplaceSourceSchema = import_zod4.z.object({
|
|
2392
|
+
source: import_zod4.z.object({
|
|
2393
|
+
type: import_zod4.z.enum(["github", "git", "local", "url"]),
|
|
2394
|
+
repo: import_zod4.z.string().optional(),
|
|
2395
|
+
url: import_zod4.z.string().optional(),
|
|
2396
|
+
path: import_zod4.z.string().optional(),
|
|
2397
|
+
ref: import_zod4.z.string().optional()
|
|
1214
2398
|
})
|
|
1215
2399
|
});
|
|
1216
|
-
var ExtraKnownMarketplacesSchema =
|
|
1217
|
-
var SettingsSchema =
|
|
2400
|
+
var ExtraKnownMarketplacesSchema = import_zod4.z.record(MarketplaceSourceSchema).optional().catch(void 0);
|
|
2401
|
+
var SettingsSchema = import_zod4.z.object({
|
|
1218
2402
|
/** Trust level used when no --permission-mode flag is given */
|
|
1219
|
-
defaultTrustLevel:
|
|
2403
|
+
defaultTrustLevel: import_zod4.z.enum(["safe", "moderate", "full"]).optional(),
|
|
1220
2404
|
/** Response language (e.g., "ko", "en", "ja"). Injected into system prompt. */
|
|
1221
|
-
language:
|
|
2405
|
+
language: import_zod4.z.string().optional(),
|
|
2406
|
+
/** Active provider profile key from providers. */
|
|
2407
|
+
currentProvider: import_zod4.z.string().optional(),
|
|
2408
|
+
/** Provider profiles keyed by user-facing profile name. */
|
|
2409
|
+
providers: import_zod4.z.record(ProviderProfileSchema).optional(),
|
|
2410
|
+
/** Legacy single-provider settings. Prefer currentProvider + providers for new config. */
|
|
1222
2411
|
provider: ProviderSchema.optional(),
|
|
1223
2412
|
permissions: PermissionsSchema.optional(),
|
|
1224
2413
|
env: EnvSchema,
|
|
@@ -1269,16 +2458,30 @@ function resolveEnvRef(value) {
|
|
|
1269
2458
|
return value;
|
|
1270
2459
|
}
|
|
1271
2460
|
function resolveEnvRefs(settings) {
|
|
1272
|
-
|
|
2461
|
+
const provider = settings.provider?.apiKey !== void 0 ? {
|
|
2462
|
+
...settings.provider,
|
|
2463
|
+
apiKey: resolveEnvRef(settings.provider.apiKey)
|
|
2464
|
+
} : settings.provider;
|
|
2465
|
+
if (settings.providers !== void 0) {
|
|
2466
|
+
const providers = Object.fromEntries(
|
|
2467
|
+
Object.entries(settings.providers).map(([name, profile]) => [
|
|
2468
|
+
name,
|
|
2469
|
+
{
|
|
2470
|
+
...profile,
|
|
2471
|
+
...profile.apiKey !== void 0 && { apiKey: resolveEnvRef(profile.apiKey) }
|
|
2472
|
+
}
|
|
2473
|
+
])
|
|
2474
|
+
);
|
|
1273
2475
|
return {
|
|
1274
2476
|
...settings,
|
|
1275
|
-
provider
|
|
1276
|
-
|
|
1277
|
-
apiKey: resolveEnvRef(settings.provider.apiKey)
|
|
1278
|
-
}
|
|
2477
|
+
provider,
|
|
2478
|
+
providers
|
|
1279
2479
|
};
|
|
1280
2480
|
}
|
|
1281
|
-
return
|
|
2481
|
+
return {
|
|
2482
|
+
...settings,
|
|
2483
|
+
provider
|
|
2484
|
+
};
|
|
1282
2485
|
}
|
|
1283
2486
|
function mergeSettings(layers) {
|
|
1284
2487
|
return layers.reduce((merged, layer) => {
|
|
@@ -1294,20 +2497,53 @@ function mergeSettings(layers) {
|
|
|
1294
2497
|
...merged.env ?? {},
|
|
1295
2498
|
...layer.env ?? {}
|
|
1296
2499
|
},
|
|
2500
|
+
providers: merged.providers !== void 0 || layer.providers !== void 0 ? mergeProviders(merged.providers, layer.providers) : void 0,
|
|
1297
2501
|
enabledPlugins: merged.enabledPlugins !== void 0 || layer.enabledPlugins !== void 0 ? { ...merged.enabledPlugins ?? {}, ...layer.enabledPlugins ?? {} } : void 0,
|
|
1298
2502
|
extraKnownMarketplaces: layer.extraKnownMarketplaces ?? merged.extraKnownMarketplaces
|
|
1299
2503
|
};
|
|
1300
2504
|
}, {});
|
|
1301
2505
|
}
|
|
2506
|
+
function mergeProviders(base, override) {
|
|
2507
|
+
const result = { ...base ?? {} };
|
|
2508
|
+
for (const [name, profile] of Object.entries(override ?? {})) {
|
|
2509
|
+
result[name] = {
|
|
2510
|
+
...result[name],
|
|
2511
|
+
...profile
|
|
2512
|
+
};
|
|
2513
|
+
}
|
|
2514
|
+
return result;
|
|
2515
|
+
}
|
|
2516
|
+
function resolveProvider(merged) {
|
|
2517
|
+
if (merged.currentProvider !== void 0) {
|
|
2518
|
+
const profile = merged.providers?.[merged.currentProvider];
|
|
2519
|
+
if (profile === void 0) {
|
|
2520
|
+
throw new Error(`currentProvider "${merged.currentProvider}" was not found in providers`);
|
|
2521
|
+
}
|
|
2522
|
+
if (profile.type === void 0) {
|
|
2523
|
+
throw new Error(`Provider profile "${merged.currentProvider}" is missing type`);
|
|
2524
|
+
}
|
|
2525
|
+
return {
|
|
2526
|
+
name: profile.type,
|
|
2527
|
+
model: profile.model ?? DEFAULTS.provider.model,
|
|
2528
|
+
apiKey: profile.apiKey ?? DEFAULTS.provider.apiKey,
|
|
2529
|
+
...profile.baseURL !== void 0 && { baseURL: profile.baseURL },
|
|
2530
|
+
...profile.timeout !== void 0 && { timeout: profile.timeout }
|
|
2531
|
+
};
|
|
2532
|
+
}
|
|
2533
|
+
return {
|
|
2534
|
+
name: merged.provider?.name ?? DEFAULTS.provider.name,
|
|
2535
|
+
model: merged.provider?.model ?? DEFAULTS.provider.model,
|
|
2536
|
+
apiKey: merged.provider?.apiKey ?? DEFAULTS.provider.apiKey,
|
|
2537
|
+
...merged.provider?.baseURL !== void 0 && { baseURL: merged.provider.baseURL },
|
|
2538
|
+
...merged.provider?.timeout !== void 0 && { timeout: merged.provider.timeout }
|
|
2539
|
+
};
|
|
2540
|
+
}
|
|
1302
2541
|
function toResolvedConfig(merged) {
|
|
1303
2542
|
return {
|
|
1304
2543
|
defaultTrustLevel: merged.defaultTrustLevel ?? DEFAULTS.defaultTrustLevel,
|
|
1305
2544
|
language: merged.language,
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
model: merged.provider?.model ?? DEFAULTS.provider.model,
|
|
1309
|
-
apiKey: merged.provider?.apiKey ?? DEFAULTS.provider.apiKey
|
|
1310
|
-
},
|
|
2545
|
+
currentProvider: merged.currentProvider,
|
|
2546
|
+
provider: resolveProvider(merged),
|
|
1311
2547
|
permissions: {
|
|
1312
2548
|
allow: merged.permissions?.allow ?? DEFAULTS.permissions.allow,
|
|
1313
2549
|
deny: merged.permissions?.deny ?? DEFAULTS.permissions.deny
|
|
@@ -1323,6 +2559,8 @@ function getSettingsPaths(cwd) {
|
|
|
1323
2559
|
return [
|
|
1324
2560
|
(0, import_path.join)(home, ".robota", "settings.json"),
|
|
1325
2561
|
// 1. user (lowest)
|
|
2562
|
+
(0, import_path.join)(home, ".claude", "settings.json"),
|
|
2563
|
+
// 1b. user (Claude Code compat)
|
|
1326
2564
|
(0, import_path.join)(cwd, ".robota", "settings.json"),
|
|
1327
2565
|
// 2. project
|
|
1328
2566
|
(0, import_path.join)(cwd, ".robota", "settings.local.json"),
|
|
@@ -1476,8 +2714,8 @@ async function detectProject(cwd) {
|
|
|
1476
2714
|
}
|
|
1477
2715
|
|
|
1478
2716
|
// src/plugins/plugin-settings-store.ts
|
|
1479
|
-
var
|
|
1480
|
-
var
|
|
2717
|
+
var import_node_fs4 = require("fs");
|
|
2718
|
+
var import_node_path5 = require("path");
|
|
1481
2719
|
var PluginSettingsStore = class {
|
|
1482
2720
|
settingsPath;
|
|
1483
2721
|
constructor(settingsPath) {
|
|
@@ -1485,11 +2723,11 @@ var PluginSettingsStore = class {
|
|
|
1485
2723
|
}
|
|
1486
2724
|
/** Read the full settings file from disk. */
|
|
1487
2725
|
readAll() {
|
|
1488
|
-
if (!(0,
|
|
2726
|
+
if (!(0, import_node_fs4.existsSync)(this.settingsPath)) {
|
|
1489
2727
|
return {};
|
|
1490
2728
|
}
|
|
1491
2729
|
try {
|
|
1492
|
-
const raw = (0,
|
|
2730
|
+
const raw = (0, import_node_fs4.readFileSync)(this.settingsPath, "utf-8");
|
|
1493
2731
|
const data = JSON.parse(raw);
|
|
1494
2732
|
if (typeof data === "object" && data !== null) {
|
|
1495
2733
|
return data;
|
|
@@ -1501,11 +2739,11 @@ var PluginSettingsStore = class {
|
|
|
1501
2739
|
}
|
|
1502
2740
|
/** Write the full settings file to disk. */
|
|
1503
2741
|
writeAll(settings) {
|
|
1504
|
-
const dir = (0,
|
|
1505
|
-
if (!(0,
|
|
1506
|
-
(0,
|
|
2742
|
+
const dir = (0, import_node_path5.dirname)(this.settingsPath);
|
|
2743
|
+
if (!(0, import_node_fs4.existsSync)(dir)) {
|
|
2744
|
+
(0, import_node_fs4.mkdirSync)(dir, { recursive: true });
|
|
1507
2745
|
}
|
|
1508
|
-
(0,
|
|
2746
|
+
(0, import_node_fs4.writeFileSync)(this.settingsPath, JSON.stringify(settings, null, 2), "utf-8");
|
|
1509
2747
|
}
|
|
1510
2748
|
// --- enabledPlugins ---
|
|
1511
2749
|
/** Get the enabledPlugins map. */
|
|
@@ -1577,11 +2815,11 @@ var PluginSettingsStore = class {
|
|
|
1577
2815
|
};
|
|
1578
2816
|
|
|
1579
2817
|
// src/plugins/bundle-plugin-loader.ts
|
|
1580
|
-
var
|
|
1581
|
-
var
|
|
2818
|
+
var import_node_fs6 = require("fs");
|
|
2819
|
+
var import_node_path6 = require("path");
|
|
1582
2820
|
|
|
1583
2821
|
// src/plugins/bundle-plugin-utils.ts
|
|
1584
|
-
var
|
|
2822
|
+
var import_node_fs5 = require("fs");
|
|
1585
2823
|
function parseSkillFrontmatter(raw) {
|
|
1586
2824
|
const trimmed = raw.trimStart();
|
|
1587
2825
|
if (!trimmed.startsWith("---")) {
|
|
@@ -1630,9 +2868,9 @@ function validateManifest(data) {
|
|
|
1630
2868
|
};
|
|
1631
2869
|
}
|
|
1632
2870
|
function getSortedSubdirs(dirPath) {
|
|
1633
|
-
if (!(0,
|
|
2871
|
+
if (!(0, import_node_fs5.existsSync)(dirPath)) return [];
|
|
1634
2872
|
try {
|
|
1635
|
-
const entries = (0,
|
|
2873
|
+
const entries = (0, import_node_fs5.readdirSync)(dirPath, { withFileTypes: true });
|
|
1636
2874
|
return entries.filter((e) => e.isDirectory()).map((e) => e.name).sort();
|
|
1637
2875
|
} catch {
|
|
1638
2876
|
return [];
|
|
@@ -1662,23 +2900,23 @@ var BundlePluginLoader = class {
|
|
|
1662
2900
|
* For each marketplace/plugin pair, the latest version (lexicographically last) is loaded.
|
|
1663
2901
|
*/
|
|
1664
2902
|
discoverAndLoad() {
|
|
1665
|
-
const cacheDir = (0,
|
|
1666
|
-
if (!(0,
|
|
2903
|
+
const cacheDir = (0, import_node_path6.join)(this.pluginsDir, "cache");
|
|
2904
|
+
if (!(0, import_node_fs6.existsSync)(cacheDir)) {
|
|
1667
2905
|
return [];
|
|
1668
2906
|
}
|
|
1669
2907
|
const results = [];
|
|
1670
2908
|
const marketplaces = getSortedSubdirs(cacheDir);
|
|
1671
2909
|
for (const marketplace of marketplaces) {
|
|
1672
|
-
const marketplaceDir = (0,
|
|
2910
|
+
const marketplaceDir = (0, import_node_path6.join)(cacheDir, marketplace);
|
|
1673
2911
|
const plugins = getSortedSubdirs(marketplaceDir);
|
|
1674
2912
|
for (const pluginName of plugins) {
|
|
1675
|
-
const pluginDir = (0,
|
|
2913
|
+
const pluginDir = (0, import_node_path6.join)(marketplaceDir, pluginName);
|
|
1676
2914
|
const versions = getSortedSubdirs(pluginDir);
|
|
1677
2915
|
if (versions.length === 0) continue;
|
|
1678
2916
|
const latestVersion = versions[versions.length - 1];
|
|
1679
|
-
const versionDir = (0,
|
|
1680
|
-
const manifestPath = (0,
|
|
1681
|
-
if (!(0,
|
|
2917
|
+
const versionDir = (0, import_node_path6.join)(pluginDir, latestVersion);
|
|
2918
|
+
const manifestPath = (0, import_node_path6.join)(versionDir, ".claude-plugin", "plugin.json");
|
|
2919
|
+
if (!(0, import_node_fs6.existsSync)(manifestPath)) continue;
|
|
1682
2920
|
const manifest = this.readManifest(manifestPath);
|
|
1683
2921
|
if (!manifest) continue;
|
|
1684
2922
|
const pluginId = `${manifest.name}@${marketplace}`;
|
|
@@ -1692,7 +2930,7 @@ var BundlePluginLoader = class {
|
|
|
1692
2930
|
/** Read and validate a plugin.json manifest. Returns null on failure. */
|
|
1693
2931
|
readManifest(path) {
|
|
1694
2932
|
try {
|
|
1695
|
-
const raw = (0,
|
|
2933
|
+
const raw = (0, import_node_fs6.readFileSync)(path, "utf-8");
|
|
1696
2934
|
const data = JSON.parse(raw);
|
|
1697
2935
|
return validateManifest(data);
|
|
1698
2936
|
} catch {
|
|
@@ -1727,15 +2965,15 @@ var BundlePluginLoader = class {
|
|
|
1727
2965
|
}
|
|
1728
2966
|
/** Load skills from the plugin's skills/ directory. */
|
|
1729
2967
|
loadSkills(pluginDir, pluginName) {
|
|
1730
|
-
const skillsDir = (0,
|
|
1731
|
-
if (!(0,
|
|
1732
|
-
const entries = (0,
|
|
2968
|
+
const skillsDir = (0, import_node_path6.join)(pluginDir, "skills");
|
|
2969
|
+
if (!(0, import_node_fs6.existsSync)(skillsDir)) return [];
|
|
2970
|
+
const entries = (0, import_node_fs6.readdirSync)(skillsDir, { withFileTypes: true });
|
|
1733
2971
|
const skills = [];
|
|
1734
2972
|
for (const entry of entries) {
|
|
1735
2973
|
if (!entry.isDirectory()) continue;
|
|
1736
|
-
const skillFile = (0,
|
|
1737
|
-
if (!(0,
|
|
1738
|
-
const raw = (0,
|
|
2974
|
+
const skillFile = (0, import_node_path6.join)(skillsDir, entry.name, "SKILL.md");
|
|
2975
|
+
if (!(0, import_node_fs6.existsSync)(skillFile)) continue;
|
|
2976
|
+
const raw = (0, import_node_fs6.readFileSync)(skillFile, "utf-8");
|
|
1739
2977
|
const { metadata, content } = parseSkillFrontmatter(raw);
|
|
1740
2978
|
const description = typeof metadata.description === "string" ? metadata.description : "";
|
|
1741
2979
|
const skill = {
|
|
@@ -1750,13 +2988,13 @@ var BundlePluginLoader = class {
|
|
|
1750
2988
|
}
|
|
1751
2989
|
/** Load commands from the plugin's commands/ directory (flat .md files). */
|
|
1752
2990
|
loadCommands(pluginDir, pluginName) {
|
|
1753
|
-
const commandsDir = (0,
|
|
1754
|
-
if (!(0,
|
|
1755
|
-
const entries = (0,
|
|
2991
|
+
const commandsDir = (0, import_node_path6.join)(pluginDir, "commands");
|
|
2992
|
+
if (!(0, import_node_fs6.existsSync)(commandsDir)) return [];
|
|
2993
|
+
const entries = (0, import_node_fs6.readdirSync)(commandsDir, { withFileTypes: true });
|
|
1756
2994
|
const commands = [];
|
|
1757
2995
|
for (const entry of entries) {
|
|
1758
2996
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
1759
|
-
const raw = (0,
|
|
2997
|
+
const raw = (0, import_node_fs6.readFileSync)((0, import_node_path6.join)(commandsDir, entry.name), "utf-8");
|
|
1760
2998
|
const { metadata, content } = parseSkillFrontmatter(raw);
|
|
1761
2999
|
const name = typeof metadata.name === "string" ? metadata.name : entry.name.replace(/\.md$/, "");
|
|
1762
3000
|
const description = typeof metadata.description === "string" ? metadata.description : "";
|
|
@@ -1771,10 +3009,10 @@ var BundlePluginLoader = class {
|
|
|
1771
3009
|
}
|
|
1772
3010
|
/** Load hooks from hooks/hooks.json if present. */
|
|
1773
3011
|
loadHooks(pluginDir) {
|
|
1774
|
-
const hooksPath = (0,
|
|
1775
|
-
if (!(0,
|
|
3012
|
+
const hooksPath = (0, import_node_path6.join)(pluginDir, "hooks", "hooks.json");
|
|
3013
|
+
if (!(0, import_node_fs6.existsSync)(hooksPath)) return {};
|
|
1776
3014
|
try {
|
|
1777
|
-
const raw = (0,
|
|
3015
|
+
const raw = (0, import_node_fs6.readFileSync)(hooksPath, "utf-8");
|
|
1778
3016
|
const data = JSON.parse(raw);
|
|
1779
3017
|
if (typeof data === "object" && data !== null) {
|
|
1780
3018
|
return data;
|
|
@@ -1786,12 +3024,12 @@ var BundlePluginLoader = class {
|
|
|
1786
3024
|
}
|
|
1787
3025
|
/** Load MCP server configuration if present. Checks `.mcp.json` at plugin root first. */
|
|
1788
3026
|
loadMcpConfig(pluginDir) {
|
|
1789
|
-
const primaryPath = (0,
|
|
1790
|
-
const fallbackPath = (0,
|
|
1791
|
-
const mcpPath = (0,
|
|
1792
|
-
if (!(0,
|
|
3027
|
+
const primaryPath = (0, import_node_path6.join)(pluginDir, ".mcp.json");
|
|
3028
|
+
const fallbackPath = (0, import_node_path6.join)(pluginDir, ".claude-plugin", "mcp.json");
|
|
3029
|
+
const mcpPath = (0, import_node_fs6.existsSync)(primaryPath) ? primaryPath : fallbackPath;
|
|
3030
|
+
if (!(0, import_node_fs6.existsSync)(mcpPath)) return void 0;
|
|
1793
3031
|
try {
|
|
1794
|
-
const raw = (0,
|
|
3032
|
+
const raw = (0, import_node_fs6.readFileSync)(mcpPath, "utf-8");
|
|
1795
3033
|
return JSON.parse(raw);
|
|
1796
3034
|
} catch {
|
|
1797
3035
|
return void 0;
|
|
@@ -1799,10 +3037,10 @@ var BundlePluginLoader = class {
|
|
|
1799
3037
|
}
|
|
1800
3038
|
/** Load agent definitions from agents/ directory if present. */
|
|
1801
3039
|
loadAgents(pluginDir) {
|
|
1802
|
-
const agentsDir = (0,
|
|
1803
|
-
if (!(0,
|
|
3040
|
+
const agentsDir = (0, import_node_path6.join)(pluginDir, "agents");
|
|
3041
|
+
if (!(0, import_node_fs6.existsSync)(agentsDir)) return [];
|
|
1804
3042
|
try {
|
|
1805
|
-
const entries = (0,
|
|
3043
|
+
const entries = (0, import_node_fs6.readdirSync)(agentsDir, { withFileTypes: true });
|
|
1806
3044
|
return entries.filter((e) => e.isDirectory() || e.name.endsWith(".md")).map((e) => e.name.replace(/\.md$/, ""));
|
|
1807
3045
|
} catch {
|
|
1808
3046
|
return [];
|
|
@@ -1811,9 +3049,9 @@ var BundlePluginLoader = class {
|
|
|
1811
3049
|
};
|
|
1812
3050
|
|
|
1813
3051
|
// src/plugins/bundle-plugin-installer.ts
|
|
1814
|
-
var
|
|
1815
|
-
var
|
|
1816
|
-
var
|
|
3052
|
+
var import_node_child_process2 = require("child_process");
|
|
3053
|
+
var import_node_fs7 = require("fs");
|
|
3054
|
+
var import_node_path7 = require("path");
|
|
1817
3055
|
var GIT_CLONE_TIMEOUT_MS = 6e4;
|
|
1818
3056
|
var BundlePluginInstaller = class {
|
|
1819
3057
|
pluginsDir;
|
|
@@ -1824,8 +3062,8 @@ var BundlePluginInstaller = class {
|
|
|
1824
3062
|
exec;
|
|
1825
3063
|
constructor(options) {
|
|
1826
3064
|
this.pluginsDir = options.pluginsDir;
|
|
1827
|
-
this.cacheDir = (0,
|
|
1828
|
-
this.registryPath = (0,
|
|
3065
|
+
this.cacheDir = (0, import_node_path7.join)(this.pluginsDir, "cache");
|
|
3066
|
+
this.registryPath = (0, import_node_path7.join)(this.pluginsDir, "installed_plugins.json");
|
|
1829
3067
|
this.settingsStore = options.settingsStore;
|
|
1830
3068
|
this.marketplaceClient = options.marketplaceClient;
|
|
1831
3069
|
this.exec = options.exec ?? this.defaultExec;
|
|
@@ -1845,8 +3083,8 @@ var BundlePluginInstaller = class {
|
|
|
1845
3083
|
throw new Error(`Plugin "${pluginName}" not found in marketplace "${marketplaceName}"`);
|
|
1846
3084
|
}
|
|
1847
3085
|
const version = this.resolveVersion(entry, marketplaceName);
|
|
1848
|
-
const targetDir = (0,
|
|
1849
|
-
if ((0,
|
|
3086
|
+
const targetDir = (0, import_node_path7.join)(this.cacheDir, marketplaceName, pluginName, version);
|
|
3087
|
+
if ((0, import_node_fs7.existsSync)(targetDir)) {
|
|
1850
3088
|
throw new Error(
|
|
1851
3089
|
`Plugin "${pluginName}" version "${version}" is already installed from "${marketplaceName}"`
|
|
1852
3090
|
);
|
|
@@ -1873,8 +3111,8 @@ var BundlePluginInstaller = class {
|
|
|
1873
3111
|
if (!record) {
|
|
1874
3112
|
throw new Error(`Plugin "${pluginId}" is not installed`);
|
|
1875
3113
|
}
|
|
1876
|
-
if ((0,
|
|
1877
|
-
(0,
|
|
3114
|
+
if ((0, import_node_fs7.existsSync)(record.installPath)) {
|
|
3115
|
+
(0, import_node_fs7.rmSync)(record.installPath, { recursive: true, force: true });
|
|
1878
3116
|
}
|
|
1879
3117
|
delete registry[pluginId];
|
|
1880
3118
|
this.writeRegistry(registry);
|
|
@@ -1920,18 +3158,18 @@ var BundlePluginInstaller = class {
|
|
|
1920
3158
|
}
|
|
1921
3159
|
/** Resolve the source and install the plugin. */
|
|
1922
3160
|
resolveAndInstall(rawSource, marketplaceName, pluginName, targetDir) {
|
|
1923
|
-
(0,
|
|
3161
|
+
(0, import_node_fs7.mkdirSync)(targetDir, { recursive: true });
|
|
1924
3162
|
const source = this.normalizeSource(rawSource);
|
|
1925
3163
|
try {
|
|
1926
3164
|
if (typeof source === "string") {
|
|
1927
3165
|
const marketplaceDir = this.marketplaceClient.getMarketplaceDir(marketplaceName);
|
|
1928
|
-
const sourcePath = (0,
|
|
1929
|
-
if (!(0,
|
|
3166
|
+
const sourcePath = (0, import_node_path7.join)(marketplaceDir, source);
|
|
3167
|
+
if (!(0, import_node_fs7.existsSync)(sourcePath)) {
|
|
1930
3168
|
throw new Error(
|
|
1931
3169
|
`Plugin source path "${source}" not found in marketplace "${marketplaceName}"`
|
|
1932
3170
|
);
|
|
1933
3171
|
}
|
|
1934
|
-
(0,
|
|
3172
|
+
(0, import_node_fs7.cpSync)(sourcePath, targetDir, { recursive: true });
|
|
1935
3173
|
} else if (source.type === "github") {
|
|
1936
3174
|
const repoUrl = `https://github.com/${source.repo}.git`;
|
|
1937
3175
|
this.cloneToDir(repoUrl, targetDir, pluginName);
|
|
@@ -1943,15 +3181,15 @@ var BundlePluginInstaller = class {
|
|
|
1943
3181
|
throw new Error(`Unknown source type: ${JSON.stringify(source)}`);
|
|
1944
3182
|
}
|
|
1945
3183
|
} catch (err) {
|
|
1946
|
-
if ((0,
|
|
1947
|
-
(0,
|
|
3184
|
+
if ((0, import_node_fs7.existsSync)(targetDir)) {
|
|
3185
|
+
(0, import_node_fs7.rmSync)(targetDir, { recursive: true, force: true });
|
|
1948
3186
|
}
|
|
1949
3187
|
throw err;
|
|
1950
3188
|
}
|
|
1951
3189
|
}
|
|
1952
3190
|
/** Clone a git repository to the target directory. */
|
|
1953
3191
|
cloneToDir(repoUrl, targetDir, pluginName) {
|
|
1954
|
-
(0,
|
|
3192
|
+
(0, import_node_fs7.rmSync)(targetDir, { recursive: true, force: true });
|
|
1955
3193
|
const command = `git clone --depth 1 ${repoUrl} ${targetDir}`;
|
|
1956
3194
|
try {
|
|
1957
3195
|
this.exec(command, { timeout: GIT_CLONE_TIMEOUT_MS, stdio: "pipe" });
|
|
@@ -1962,11 +3200,11 @@ var BundlePluginInstaller = class {
|
|
|
1962
3200
|
}
|
|
1963
3201
|
/** Read the installed_plugins.json registry. */
|
|
1964
3202
|
readRegistry() {
|
|
1965
|
-
if (!(0,
|
|
3203
|
+
if (!(0, import_node_fs7.existsSync)(this.registryPath)) {
|
|
1966
3204
|
return {};
|
|
1967
3205
|
}
|
|
1968
3206
|
try {
|
|
1969
|
-
const raw = (0,
|
|
3207
|
+
const raw = (0, import_node_fs7.readFileSync)(this.registryPath, "utf-8");
|
|
1970
3208
|
const data = JSON.parse(raw);
|
|
1971
3209
|
if (typeof data === "object" && data !== null) {
|
|
1972
3210
|
return data;
|
|
@@ -1978,32 +3216,32 @@ var BundlePluginInstaller = class {
|
|
|
1978
3216
|
}
|
|
1979
3217
|
/** Write the installed_plugins.json registry. */
|
|
1980
3218
|
writeRegistry(registry) {
|
|
1981
|
-
const dir = (0,
|
|
1982
|
-
if (!(0,
|
|
1983
|
-
(0,
|
|
3219
|
+
const dir = (0, import_node_path7.dirname)(this.registryPath);
|
|
3220
|
+
if (!(0, import_node_fs7.existsSync)(dir)) {
|
|
3221
|
+
(0, import_node_fs7.mkdirSync)(dir, { recursive: true });
|
|
1984
3222
|
}
|
|
1985
|
-
(0,
|
|
3223
|
+
(0, import_node_fs7.writeFileSync)(this.registryPath, JSON.stringify(registry, null, 2), "utf-8");
|
|
1986
3224
|
}
|
|
1987
3225
|
/** Default exec implementation using child_process. */
|
|
1988
3226
|
defaultExec(command, options) {
|
|
1989
|
-
return (0,
|
|
3227
|
+
return (0, import_node_child_process2.execSync)(command, { timeout: options.timeout, stdio: "pipe" });
|
|
1990
3228
|
}
|
|
1991
3229
|
};
|
|
1992
3230
|
|
|
1993
3231
|
// src/plugins/marketplace-client.ts
|
|
1994
|
-
var
|
|
1995
|
-
var
|
|
1996
|
-
var
|
|
3232
|
+
var import_node_child_process3 = require("child_process");
|
|
3233
|
+
var import_node_fs9 = require("fs");
|
|
3234
|
+
var import_node_path9 = require("path");
|
|
1997
3235
|
|
|
1998
3236
|
// src/plugins/marketplace-registry.ts
|
|
1999
|
-
var
|
|
2000
|
-
var
|
|
3237
|
+
var import_node_fs8 = require("fs");
|
|
3238
|
+
var import_node_path8 = require("path");
|
|
2001
3239
|
function readRegistry(registryPath) {
|
|
2002
|
-
if (!(0,
|
|
3240
|
+
if (!(0, import_node_fs8.existsSync)(registryPath)) {
|
|
2003
3241
|
return {};
|
|
2004
3242
|
}
|
|
2005
3243
|
try {
|
|
2006
|
-
const raw = (0,
|
|
3244
|
+
const raw = (0, import_node_fs8.readFileSync)(registryPath, "utf-8");
|
|
2007
3245
|
const data = JSON.parse(raw);
|
|
2008
3246
|
if (typeof data === "object" && data !== null) {
|
|
2009
3247
|
return data;
|
|
@@ -2014,18 +3252,18 @@ function readRegistry(registryPath) {
|
|
|
2014
3252
|
}
|
|
2015
3253
|
}
|
|
2016
3254
|
function writeRegistry(registryPath, registry) {
|
|
2017
|
-
const dir = (0,
|
|
2018
|
-
if (!(0,
|
|
2019
|
-
(0,
|
|
3255
|
+
const dir = (0, import_node_path8.dirname)(registryPath);
|
|
3256
|
+
if (!(0, import_node_fs8.existsSync)(dir)) {
|
|
3257
|
+
(0, import_node_fs8.mkdirSync)(dir, { recursive: true });
|
|
2020
3258
|
}
|
|
2021
|
-
(0,
|
|
3259
|
+
(0, import_node_fs8.writeFileSync)(registryPath, JSON.stringify(registry, null, 2), "utf-8");
|
|
2022
3260
|
}
|
|
2023
3261
|
function removeInstalledPluginsForMarketplace(pluginsDir, marketplaceName) {
|
|
2024
|
-
const installedPath = (0,
|
|
2025
|
-
if (!(0,
|
|
3262
|
+
const installedPath = (0, import_node_path8.join)(pluginsDir, "installed_plugins.json");
|
|
3263
|
+
if (!(0, import_node_fs8.existsSync)(installedPath)) return;
|
|
2026
3264
|
let registry;
|
|
2027
3265
|
try {
|
|
2028
|
-
const raw = (0,
|
|
3266
|
+
const raw = (0, import_node_fs8.readFileSync)(installedPath, "utf-8");
|
|
2029
3267
|
const data = JSON.parse(raw);
|
|
2030
3268
|
if (typeof data !== "object" || data === null) return;
|
|
2031
3269
|
registry = data;
|
|
@@ -2035,19 +3273,19 @@ function removeInstalledPluginsForMarketplace(pluginsDir, marketplaceName) {
|
|
|
2035
3273
|
let changed = false;
|
|
2036
3274
|
for (const [pluginId, record] of Object.entries(registry)) {
|
|
2037
3275
|
if (record.marketplace === marketplaceName) {
|
|
2038
|
-
if (record.installPath && (0,
|
|
2039
|
-
(0,
|
|
3276
|
+
if (record.installPath && (0, import_node_fs8.existsSync)(record.installPath)) {
|
|
3277
|
+
(0, import_node_fs8.rmSync)(record.installPath, { recursive: true, force: true });
|
|
2040
3278
|
}
|
|
2041
3279
|
delete registry[pluginId];
|
|
2042
3280
|
changed = true;
|
|
2043
3281
|
}
|
|
2044
3282
|
}
|
|
2045
3283
|
if (changed) {
|
|
2046
|
-
const dir = (0,
|
|
2047
|
-
if (!(0,
|
|
2048
|
-
(0,
|
|
3284
|
+
const dir = (0, import_node_path8.dirname)(installedPath);
|
|
3285
|
+
if (!(0, import_node_fs8.existsSync)(dir)) {
|
|
3286
|
+
(0, import_node_fs8.mkdirSync)(dir, { recursive: true });
|
|
2049
3287
|
}
|
|
2050
|
-
(0,
|
|
3288
|
+
(0, import_node_fs8.writeFileSync)(installedPath, JSON.stringify(registry, null, 2), "utf-8");
|
|
2051
3289
|
}
|
|
2052
3290
|
}
|
|
2053
3291
|
|
|
@@ -2061,8 +3299,8 @@ var MarketplaceClient = class {
|
|
|
2061
3299
|
constructor(options) {
|
|
2062
3300
|
this.pluginsDir = options.pluginsDir;
|
|
2063
3301
|
this.exec = options.exec ?? this.defaultExec;
|
|
2064
|
-
this.marketplacesDir = (0,
|
|
2065
|
-
this.registryPath = (0,
|
|
3302
|
+
this.marketplacesDir = (0, import_node_path9.join)(this.pluginsDir, "marketplaces");
|
|
3303
|
+
this.registryPath = (0, import_node_path9.join)(this.pluginsDir, "known_marketplaces.json");
|
|
2066
3304
|
}
|
|
2067
3305
|
/**
|
|
2068
3306
|
* Add a marketplace by cloning its repository.
|
|
@@ -2075,13 +3313,13 @@ var MarketplaceClient = class {
|
|
|
2075
3313
|
*/
|
|
2076
3314
|
addMarketplace(source) {
|
|
2077
3315
|
const tempName = "temp-" + Date.now().toString(36);
|
|
2078
|
-
const tempDir = (0,
|
|
2079
|
-
(0,
|
|
3316
|
+
const tempDir = (0, import_node_path9.join)(this.marketplacesDir, tempName);
|
|
3317
|
+
(0, import_node_fs9.mkdirSync)(this.marketplacesDir, { recursive: true });
|
|
2080
3318
|
if (source.type === "local") {
|
|
2081
|
-
if (!(0,
|
|
3319
|
+
if (!(0, import_node_fs9.existsSync)(source.path)) {
|
|
2082
3320
|
throw new Error(`Local marketplace path does not exist: ${source.path}`);
|
|
2083
3321
|
}
|
|
2084
|
-
(0,
|
|
3322
|
+
(0, import_node_fs9.cpSync)(source.path, tempDir, { recursive: true });
|
|
2085
3323
|
} else {
|
|
2086
3324
|
const cloneUrl = this.resolveCloneUrl(source);
|
|
2087
3325
|
const command = `git clone --depth 1 ${cloneUrl} ${tempDir}`;
|
|
@@ -2092,9 +3330,9 @@ var MarketplaceClient = class {
|
|
|
2092
3330
|
throw new Error(`Failed to clone marketplace: ${message}`);
|
|
2093
3331
|
}
|
|
2094
3332
|
}
|
|
2095
|
-
const manifestPath = (0,
|
|
2096
|
-
if (!(0,
|
|
2097
|
-
(0,
|
|
3333
|
+
const manifestPath = (0, import_node_path9.join)(tempDir, ".claude-plugin", "marketplace.json");
|
|
3334
|
+
if (!(0, import_node_fs9.existsSync)(manifestPath)) {
|
|
3335
|
+
(0, import_node_fs9.rmSync)(tempDir, { recursive: true, force: true });
|
|
2098
3336
|
throw new Error(
|
|
2099
3337
|
source.type === "local" ? "Local directory does not contain .claude-plugin/marketplace.json" : "Cloned repository does not contain .claude-plugin/marketplace.json"
|
|
2100
3338
|
);
|
|
@@ -2102,16 +3340,16 @@ var MarketplaceClient = class {
|
|
|
2102
3340
|
const manifest = this.readManifestFromPath(manifestPath);
|
|
2103
3341
|
const name = manifest.name;
|
|
2104
3342
|
if (!name) {
|
|
2105
|
-
(0,
|
|
3343
|
+
(0, import_node_fs9.rmSync)(tempDir, { recursive: true, force: true });
|
|
2106
3344
|
throw new Error('Marketplace manifest does not contain a "name" field');
|
|
2107
3345
|
}
|
|
2108
3346
|
const registry = readRegistry(this.registryPath);
|
|
2109
3347
|
if (registry[name]) {
|
|
2110
|
-
(0,
|
|
3348
|
+
(0, import_node_fs9.rmSync)(tempDir, { recursive: true, force: true });
|
|
2111
3349
|
throw new Error(`Marketplace "${name}" already exists`);
|
|
2112
3350
|
}
|
|
2113
|
-
const finalDir = (0,
|
|
2114
|
-
(0,
|
|
3351
|
+
const finalDir = (0, import_node_path9.join)(this.marketplacesDir, name);
|
|
3352
|
+
(0, import_node_fs9.renameSync)(tempDir, finalDir);
|
|
2115
3353
|
registry[name] = {
|
|
2116
3354
|
source,
|
|
2117
3355
|
installLocation: finalDir,
|
|
@@ -2132,8 +3370,8 @@ var MarketplaceClient = class {
|
|
|
2132
3370
|
throw new Error(`Marketplace "${name}" not found`);
|
|
2133
3371
|
}
|
|
2134
3372
|
removeInstalledPluginsForMarketplace(this.pluginsDir, name);
|
|
2135
|
-
if ((0,
|
|
2136
|
-
(0,
|
|
3373
|
+
if ((0, import_node_fs9.existsSync)(entry.installLocation)) {
|
|
3374
|
+
(0, import_node_fs9.rmSync)(entry.installLocation, { recursive: true, force: true });
|
|
2137
3375
|
}
|
|
2138
3376
|
delete registry[name];
|
|
2139
3377
|
writeRegistry(this.registryPath, registry);
|
|
@@ -2149,16 +3387,16 @@ var MarketplaceClient = class {
|
|
|
2149
3387
|
if (!entry) {
|
|
2150
3388
|
throw new Error(`Marketplace "${name}" not found`);
|
|
2151
3389
|
}
|
|
2152
|
-
if (!(0,
|
|
3390
|
+
if (!(0, import_node_fs9.existsSync)(entry.installLocation)) {
|
|
2153
3391
|
throw new Error(`Marketplace directory for "${name}" does not exist`);
|
|
2154
3392
|
}
|
|
2155
3393
|
if (entry.source.type === "local") {
|
|
2156
3394
|
const localSource = entry.source;
|
|
2157
|
-
if (!(0,
|
|
3395
|
+
if (!(0, import_node_fs9.existsSync)(localSource.path)) {
|
|
2158
3396
|
throw new Error(`Local marketplace path does not exist: ${localSource.path}`);
|
|
2159
3397
|
}
|
|
2160
|
-
(0,
|
|
2161
|
-
(0,
|
|
3398
|
+
(0, import_node_fs9.rmSync)(entry.installLocation, { recursive: true, force: true });
|
|
3399
|
+
(0, import_node_fs9.cpSync)(localSource.path, entry.installLocation, { recursive: true });
|
|
2162
3400
|
} else {
|
|
2163
3401
|
const command = `git -C ${entry.installLocation} pull`;
|
|
2164
3402
|
try {
|
|
@@ -2187,8 +3425,8 @@ var MarketplaceClient = class {
|
|
|
2187
3425
|
if (!entry) {
|
|
2188
3426
|
throw new Error(`Marketplace "${marketplaceName}" not found`);
|
|
2189
3427
|
}
|
|
2190
|
-
const manifestPath = (0,
|
|
2191
|
-
if (!(0,
|
|
3428
|
+
const manifestPath = (0, import_node_path9.join)(entry.installLocation, ".claude-plugin", "marketplace.json");
|
|
3429
|
+
if (!(0, import_node_fs9.existsSync)(manifestPath)) {
|
|
2192
3430
|
throw new Error(
|
|
2193
3431
|
`Marketplace "${marketplaceName}" does not contain .claude-plugin/marketplace.json`
|
|
2194
3432
|
);
|
|
@@ -2251,7 +3489,7 @@ var MarketplaceClient = class {
|
|
|
2251
3489
|
}
|
|
2252
3490
|
/** Read and parse a marketplace.json from a file path. */
|
|
2253
3491
|
readManifestFromPath(path) {
|
|
2254
|
-
const raw = (0,
|
|
3492
|
+
const raw = (0, import_node_fs9.readFileSync)(path, "utf-8");
|
|
2255
3493
|
const data = JSON.parse(raw);
|
|
2256
3494
|
if (typeof data !== "object" || data === null) {
|
|
2257
3495
|
throw new Error("Invalid marketplace manifest: not an object");
|
|
@@ -2264,14 +3502,14 @@ var MarketplaceClient = class {
|
|
|
2264
3502
|
}
|
|
2265
3503
|
/** Default exec implementation using child_process. */
|
|
2266
3504
|
defaultExec(command, options) {
|
|
2267
|
-
return (0,
|
|
3505
|
+
return (0, import_node_child_process3.execSync)(command, { timeout: options.timeout, stdio: "pipe" });
|
|
2268
3506
|
}
|
|
2269
3507
|
};
|
|
2270
3508
|
|
|
2271
3509
|
// src/plugins/plugin-hooks-merger.ts
|
|
2272
|
-
var
|
|
3510
|
+
var import_node_path10 = require("path");
|
|
2273
3511
|
function buildPluginEnv(plugin) {
|
|
2274
|
-
const dataDir = (0,
|
|
3512
|
+
const dataDir = (0, import_node_path10.join)((0, import_node_path10.dirname)((0, import_node_path10.dirname)(plugin.pluginDir)), "data", plugin.manifest.name);
|
|
2275
3513
|
return {
|
|
2276
3514
|
CLAUDE_PLUGIN_ROOT: plugin.pluginDir,
|
|
2277
3515
|
CLAUDE_PLUGIN_PATH: plugin.pluginDir,
|
|
@@ -2333,36 +3571,39 @@ function mergeHooksIntoConfig(configHooks, pluginHooks) {
|
|
|
2333
3571
|
}
|
|
2334
3572
|
|
|
2335
3573
|
// src/interactive/interactive-session-init.ts
|
|
2336
|
-
var
|
|
2337
|
-
var
|
|
3574
|
+
var import_node_os4 = require("os");
|
|
3575
|
+
var import_node_path11 = require("path");
|
|
2338
3576
|
async function createInteractiveSession(options) {
|
|
2339
3577
|
const cwd = options.cwd;
|
|
2340
3578
|
const [config, context, projectInfo] = await Promise.all([
|
|
2341
3579
|
loadConfig(cwd),
|
|
2342
|
-
loadContext(cwd),
|
|
2343
|
-
detectProject(cwd)
|
|
3580
|
+
options.bare ? Promise.resolve({ agentsMd: "", claudeMd: "" }) : loadContext(cwd),
|
|
3581
|
+
options.bare ? Promise.resolve({ type: "unknown", language: "unknown" }) : detectProject(cwd)
|
|
2344
3582
|
]);
|
|
2345
|
-
const pluginsDir = (0,
|
|
3583
|
+
const pluginsDir = (0, import_node_path11.join)((0, import_node_os4.homedir)(), ".robota", "plugins");
|
|
2346
3584
|
const pluginLoader = new BundlePluginLoader(pluginsDir);
|
|
2347
3585
|
let mergedConfig = config;
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
3586
|
+
if (!options.bare) {
|
|
3587
|
+
try {
|
|
3588
|
+
const plugins = pluginLoader.loadPluginsSync();
|
|
3589
|
+
if (plugins.length > 0) {
|
|
3590
|
+
const pluginHooks = mergePluginHooks(plugins);
|
|
3591
|
+
mergedConfig = {
|
|
3592
|
+
...config,
|
|
3593
|
+
hooks: mergeHooksIntoConfig(
|
|
3594
|
+
config.hooks,
|
|
3595
|
+
pluginHooks
|
|
3596
|
+
)
|
|
3597
|
+
};
|
|
3598
|
+
}
|
|
3599
|
+
} catch {
|
|
2359
3600
|
}
|
|
2360
|
-
} catch {
|
|
2361
3601
|
}
|
|
2362
3602
|
const paths = projectPaths(cwd);
|
|
2363
3603
|
const sessionId = options.resumeSessionId && !options.forkSession ? options.resumeSessionId : void 0;
|
|
2364
3604
|
return createSession({
|
|
2365
3605
|
config: mergedConfig,
|
|
3606
|
+
cwd,
|
|
2366
3607
|
context,
|
|
2367
3608
|
projectInfo,
|
|
2368
3609
|
permissionMode: options.permissionMode,
|
|
@@ -2373,7 +3614,22 @@ async function createInteractiveSession(options) {
|
|
|
2373
3614
|
provider: options.provider,
|
|
2374
3615
|
onTextDelta: options.onTextDelta,
|
|
2375
3616
|
onToolExecution: options.onToolExecution,
|
|
2376
|
-
sessionId
|
|
3617
|
+
sessionId,
|
|
3618
|
+
allowedTools: options.allowedTools,
|
|
3619
|
+
appendSystemPrompt: options.appendSystemPrompt,
|
|
3620
|
+
backgroundTaskRunners: options.backgroundTaskRunners,
|
|
3621
|
+
subagentRunnerFactory: options.subagentRunnerFactory,
|
|
3622
|
+
...options.commandModules?.some(
|
|
3623
|
+
(module2) => module2.sessionRequirements?.includes("agent-runtime")
|
|
3624
|
+
) ? { enableAgentRuntime: true } : {},
|
|
3625
|
+
...options.commandModules || options.commandDescriptors ? {
|
|
3626
|
+
commandDescriptors: [
|
|
3627
|
+
...options.commandDescriptors ?? [],
|
|
3628
|
+
...options.commandModules?.flatMap((module2) => module2.commandDescriptors ?? []) ?? []
|
|
3629
|
+
]
|
|
3630
|
+
} : {},
|
|
3631
|
+
modelCommandExecutor: options.modelCommandExecutor,
|
|
3632
|
+
isModelCommandInvocable: options.isModelCommandInvocable
|
|
2377
3633
|
});
|
|
2378
3634
|
}
|
|
2379
3635
|
function injectSavedMessage(session, msg) {
|
|
@@ -2392,9 +3648,25 @@ function injectSavedMessage(session, msg) {
|
|
|
2392
3648
|
function loadSessionRecord(sessionStore, resumeSessionId, forkSession, existingSession) {
|
|
2393
3649
|
const record = sessionStore.load(resumeSessionId);
|
|
2394
3650
|
if (!record) {
|
|
2395
|
-
return {
|
|
3651
|
+
return {
|
|
3652
|
+
history: [],
|
|
3653
|
+
sessionName: void 0,
|
|
3654
|
+
pendingRestoreMessages: null,
|
|
3655
|
+
backgroundTasks: [],
|
|
3656
|
+
backgroundTaskEvents: [],
|
|
3657
|
+
backgroundJobGroups: [],
|
|
3658
|
+
backgroundJobGroupEvents: []
|
|
3659
|
+
};
|
|
2396
3660
|
}
|
|
2397
3661
|
const history = record.history ?? [];
|
|
3662
|
+
const restoredBackgroundTasks = record.backgroundTasks ?? [];
|
|
3663
|
+
const restoredBackgroundTaskEvents = record.backgroundTaskEvents ?? [];
|
|
3664
|
+
const backgroundJobGroups = record.backgroundJobGroups ?? [];
|
|
3665
|
+
const backgroundJobGroupEvents = record.backgroundJobGroupEvents ?? [];
|
|
3666
|
+
const { backgroundTasks, backgroundTaskEvents } = reconcileRestoredBackgroundTasks(
|
|
3667
|
+
restoredBackgroundTasks,
|
|
3668
|
+
restoredBackgroundTaskEvents
|
|
3669
|
+
);
|
|
2398
3670
|
const sessionName = record.name;
|
|
2399
3671
|
let pendingRestoreMessages = null;
|
|
2400
3672
|
if (!forkSession && record.messages) {
|
|
@@ -2406,7 +3678,44 @@ function loadSessionRecord(sessionStore, resumeSessionId, forkSession, existingS
|
|
|
2406
3678
|
pendingRestoreMessages = record.messages;
|
|
2407
3679
|
}
|
|
2408
3680
|
}
|
|
2409
|
-
return {
|
|
3681
|
+
return {
|
|
3682
|
+
history,
|
|
3683
|
+
sessionName,
|
|
3684
|
+
pendingRestoreMessages,
|
|
3685
|
+
backgroundTasks,
|
|
3686
|
+
backgroundTaskEvents,
|
|
3687
|
+
backgroundJobGroups,
|
|
3688
|
+
backgroundJobGroupEvents
|
|
3689
|
+
};
|
|
3690
|
+
}
|
|
3691
|
+
function reconcileRestoredBackgroundTasks(tasks, events) {
|
|
3692
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3693
|
+
const syntheticEvents = [];
|
|
3694
|
+
const backgroundTasks = tasks.map((task) => {
|
|
3695
|
+
if (isRestoredTerminalStatus(task.status)) return task;
|
|
3696
|
+
const reconciled = {
|
|
3697
|
+
...task,
|
|
3698
|
+
status: "failed",
|
|
3699
|
+
timeoutReason: "stale_worker",
|
|
3700
|
+
error: {
|
|
3701
|
+
category: "timeout",
|
|
3702
|
+
message: "Restored background task is stale; worker cannot be reattached",
|
|
3703
|
+
recoverable: true
|
|
3704
|
+
},
|
|
3705
|
+
unread: true,
|
|
3706
|
+
completedAt: now,
|
|
3707
|
+
updatedAt: now
|
|
3708
|
+
};
|
|
3709
|
+
syntheticEvents.push({ type: "background_task_failed", task: reconciled });
|
|
3710
|
+
return reconciled;
|
|
3711
|
+
});
|
|
3712
|
+
return {
|
|
3713
|
+
backgroundTasks,
|
|
3714
|
+
backgroundTaskEvents: [...events, ...syntheticEvents]
|
|
3715
|
+
};
|
|
3716
|
+
}
|
|
3717
|
+
function isRestoredTerminalStatus(status) {
|
|
3718
|
+
return status === "completed" || status === "failed" || status === "cancelled";
|
|
2410
3719
|
}
|
|
2411
3720
|
|
|
2412
3721
|
// src/interactive/interactive-session.ts
|
|
@@ -2428,10 +3737,24 @@ var InteractiveSession = class {
|
|
|
2428
3737
|
sessionName;
|
|
2429
3738
|
cwd;
|
|
2430
3739
|
pendingRestoreMessages = null;
|
|
3740
|
+
backgroundTasks = [];
|
|
3741
|
+
backgroundTaskEvents = [];
|
|
3742
|
+
backgroundJobGroups = [];
|
|
3743
|
+
backgroundJobGroupEvents = [];
|
|
2431
3744
|
resumeSessionId;
|
|
2432
3745
|
forkSession;
|
|
3746
|
+
backgroundTaskUnsubscribe = null;
|
|
3747
|
+
backgroundJobUnsubscribe = null;
|
|
3748
|
+
backgroundJobOrchestrator = null;
|
|
3749
|
+
commandModules;
|
|
3750
|
+
shuttingDown = false;
|
|
3751
|
+
shutdownPromise = null;
|
|
2433
3752
|
constructor(options) {
|
|
2434
|
-
this.
|
|
3753
|
+
this.commandModules = "commandModules" in options ? options.commandModules ?? [] : [];
|
|
3754
|
+
this.commandExecutor = new SystemCommandExecutor([
|
|
3755
|
+
...createSystemCommands(),
|
|
3756
|
+
...this.commandModules.flatMap((module2) => module2.systemCommands ?? [])
|
|
3757
|
+
]);
|
|
2435
3758
|
this.sessionStore = options.sessionStore;
|
|
2436
3759
|
this.sessionName = options.sessionName;
|
|
2437
3760
|
this.cwd = ("cwd" in options ? options.cwd : void 0) ?? "";
|
|
@@ -2453,8 +3776,14 @@ var InteractiveSession = class {
|
|
|
2453
3776
|
);
|
|
2454
3777
|
if (restored.history.length > 0) this.history = restored.history;
|
|
2455
3778
|
if (restored.sessionName) this.sessionName = restored.sessionName;
|
|
3779
|
+
this.backgroundTasks = restored.backgroundTasks;
|
|
3780
|
+
this.backgroundTaskEvents = restored.backgroundTaskEvents;
|
|
3781
|
+
this.backgroundJobGroups = restored.backgroundJobGroups;
|
|
3782
|
+
this.backgroundJobGroupEvents = restored.backgroundJobGroupEvents;
|
|
2456
3783
|
this.pendingRestoreMessages = restored.pendingRestoreMessages;
|
|
2457
3784
|
}
|
|
3785
|
+
if (this.initialized) this.subscribeBackgroundTaskEvents();
|
|
3786
|
+
if (this.initialized) this.persistCurrentSession();
|
|
2458
3787
|
}
|
|
2459
3788
|
async initializeAsync(options) {
|
|
2460
3789
|
this.session = await createInteractiveSession({
|
|
@@ -2466,13 +3795,26 @@ var InteractiveSession = class {
|
|
|
2466
3795
|
resumeSessionId: this.resumeSessionId,
|
|
2467
3796
|
forkSession: this.forkSession,
|
|
2468
3797
|
onTextDelta: (delta) => this.handleTextDelta(delta),
|
|
2469
|
-
onToolExecution: (event) => this.handleToolExecution(event)
|
|
3798
|
+
onToolExecution: (event) => this.handleToolExecution(event),
|
|
3799
|
+
bare: options.bare,
|
|
3800
|
+
allowedTools: options.allowedTools,
|
|
3801
|
+
appendSystemPrompt: options.appendSystemPrompt,
|
|
3802
|
+
backgroundTaskRunners: options.backgroundTaskRunners,
|
|
3803
|
+
subagentRunnerFactory: options.subagentRunnerFactory,
|
|
3804
|
+
...options.commandModules ? { commandModules: options.commandModules } : {},
|
|
3805
|
+
commandDescriptors: this.commandExecutor.listModelInvocableCommands(),
|
|
3806
|
+
...this.commandExecutor.listModelInvocableCommands().length > 0 ? {
|
|
3807
|
+
modelCommandExecutor: (command, args) => this.executeModelCommand(command, args),
|
|
3808
|
+
isModelCommandInvocable: (command) => this.commandExecutor.isModelInvocable(command)
|
|
3809
|
+
} : {}
|
|
2470
3810
|
});
|
|
2471
3811
|
if (this.pendingRestoreMessages) {
|
|
2472
3812
|
for (const msg of this.pendingRestoreMessages) injectSavedMessage(this.session, msg);
|
|
2473
3813
|
this.pendingRestoreMessages = null;
|
|
2474
3814
|
}
|
|
2475
3815
|
this.initialized = true;
|
|
3816
|
+
this.subscribeBackgroundTaskEvents();
|
|
3817
|
+
this.persistCurrentSession();
|
|
2476
3818
|
}
|
|
2477
3819
|
async ensureInitialized() {
|
|
2478
3820
|
if (!this.initialized && this.initPromise) await this.initPromise;
|
|
@@ -2495,6 +3837,7 @@ var InteractiveSession = class {
|
|
|
2495
3837
|
}
|
|
2496
3838
|
async submit(input, displayInput, rawInput) {
|
|
2497
3839
|
await this.ensureInitialized();
|
|
3840
|
+
if (this.shuttingDown) throw new Error("Interactive session is shutting down.");
|
|
2498
3841
|
if (this.executing) {
|
|
2499
3842
|
this.pendingPrompt = input;
|
|
2500
3843
|
this.pendingDisplayInput = displayInput;
|
|
@@ -2507,16 +3850,68 @@ var InteractiveSession = class {
|
|
|
2507
3850
|
await this.ensureInitialized();
|
|
2508
3851
|
return this.commandExecutor.execute(name, this, args);
|
|
2509
3852
|
}
|
|
3853
|
+
async executeModelCommand(name, args) {
|
|
3854
|
+
await this.ensureInitialized();
|
|
3855
|
+
return this.commandExecutor.executeModelInvocable(name, this, args);
|
|
3856
|
+
}
|
|
3857
|
+
async executeSkillCommand(skill, args, displayInput, rawInput) {
|
|
3858
|
+
await this.ensureInitialized();
|
|
3859
|
+
if (skill.context === "fork") {
|
|
3860
|
+
return this.executeForkSkillCommand(skill, args, displayInput);
|
|
3861
|
+
}
|
|
3862
|
+
const result = await executeSkill(
|
|
3863
|
+
skill,
|
|
3864
|
+
args,
|
|
3865
|
+
{
|
|
3866
|
+
runInFork: (content, options) => this.runSkillInFork(content, options)
|
|
3867
|
+
},
|
|
3868
|
+
{ sessionId: this.getSessionOrThrow().getSessionId() }
|
|
3869
|
+
);
|
|
3870
|
+
if (result.mode === "inject") {
|
|
3871
|
+
if (result.prompt) {
|
|
3872
|
+
await this.submit(result.prompt, displayInput, rawInput);
|
|
3873
|
+
}
|
|
3874
|
+
return result;
|
|
3875
|
+
}
|
|
3876
|
+
await this.applyForkSkillResult(result.result ?? "(empty response)");
|
|
3877
|
+
return result;
|
|
3878
|
+
}
|
|
2510
3879
|
listCommands() {
|
|
2511
3880
|
return this.commandExecutor.listCommands().map((cmd) => ({
|
|
2512
3881
|
name: cmd.name,
|
|
2513
3882
|
description: cmd.description
|
|
2514
3883
|
}));
|
|
2515
3884
|
}
|
|
3885
|
+
listModelInvocableCommands() {
|
|
3886
|
+
return this.commandExecutor.listModelInvocableCommands().map((cmd) => ({
|
|
3887
|
+
name: cmd.name,
|
|
3888
|
+
description: cmd.description
|
|
3889
|
+
}));
|
|
3890
|
+
}
|
|
2516
3891
|
abort() {
|
|
2517
3892
|
this.clearPendingQueue();
|
|
2518
3893
|
this.session?.abort();
|
|
2519
3894
|
}
|
|
3895
|
+
shutdown(options = {}) {
|
|
3896
|
+
if (this.shutdownPromise) return this.shutdownPromise;
|
|
3897
|
+
this.shuttingDown = true;
|
|
3898
|
+
this.shutdownPromise = (async () => {
|
|
3899
|
+
await this.ensureInitialized();
|
|
3900
|
+
this.clearPendingQueue();
|
|
3901
|
+
const session = this.session;
|
|
3902
|
+
session?.abort();
|
|
3903
|
+
await this.getBackgroundTaskManager()?.shutdown(options.message ?? "Session shutdown");
|
|
3904
|
+
this.backgroundTaskUnsubscribe?.();
|
|
3905
|
+
this.backgroundTaskUnsubscribe = null;
|
|
3906
|
+
this.backgroundJobUnsubscribe?.();
|
|
3907
|
+
this.backgroundJobUnsubscribe = null;
|
|
3908
|
+
this.backgroundJobOrchestrator?.dispose();
|
|
3909
|
+
this.backgroundJobOrchestrator = null;
|
|
3910
|
+
this.persistCurrentSession();
|
|
3911
|
+
await session?.shutdown({ reason: options.reason ?? "other" });
|
|
3912
|
+
})();
|
|
3913
|
+
return this.shutdownPromise;
|
|
3914
|
+
}
|
|
2520
3915
|
cancelQueue() {
|
|
2521
3916
|
this.clearPendingQueue();
|
|
2522
3917
|
}
|
|
@@ -2552,494 +3947,451 @@ var InteractiveSession = class {
|
|
|
2552
3947
|
getSession() {
|
|
2553
3948
|
return this.getSessionOrThrow();
|
|
2554
3949
|
}
|
|
2555
|
-
|
|
2556
|
-
this.
|
|
2557
|
-
if (this.sessionStore && this.session) {
|
|
2558
|
-
try {
|
|
2559
|
-
const id = this.getSessionOrThrow().getSessionId();
|
|
2560
|
-
const existing = this.sessionStore.load(id);
|
|
2561
|
-
if (existing) {
|
|
2562
|
-
existing.name = name;
|
|
2563
|
-
existing.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2564
|
-
this.sessionStore.save(existing);
|
|
2565
|
-
}
|
|
2566
|
-
} catch {
|
|
2567
|
-
}
|
|
2568
|
-
}
|
|
3950
|
+
listBackgroundTasks(filter) {
|
|
3951
|
+
return this.getBackgroundTaskManagerOrThrow().list(filter);
|
|
2569
3952
|
}
|
|
2570
|
-
|
|
2571
|
-
|
|
3953
|
+
getBackgroundTask(taskId) {
|
|
3954
|
+
return this.getBackgroundTaskManagerOrThrow().get(taskId);
|
|
2572
3955
|
}
|
|
2573
|
-
async
|
|
2574
|
-
this.
|
|
2575
|
-
this.
|
|
2576
|
-
this.emit("thinking", true);
|
|
2577
|
-
this.history.push((0, import_agent_core.messageToHistoryEntry)((0, import_agent_core.createUserMessage)(displayInput ?? input)));
|
|
2578
|
-
const historyBefore = this.getSessionOrThrow().getHistory().length;
|
|
2579
|
-
try {
|
|
2580
|
-
const response = await this.getSessionOrThrow().run(input, rawInput);
|
|
2581
|
-
this.flushStreaming();
|
|
2582
|
-
pushToolSummaryToHistory({ activeTools: this.activeTools, history: this.history });
|
|
2583
|
-
this.clearStreaming();
|
|
2584
|
-
const result = buildResult(
|
|
2585
|
-
response || "(empty response)",
|
|
2586
|
-
this.getSessionOrThrow().getHistory(),
|
|
2587
|
-
this.history,
|
|
2588
|
-
historyBefore,
|
|
2589
|
-
this.getContextState()
|
|
2590
|
-
);
|
|
2591
|
-
this.history.push((0, import_agent_core.messageToHistoryEntry)((0, import_agent_core.createAssistantMessage)(result.response)));
|
|
2592
|
-
this.emit("complete", result);
|
|
2593
|
-
this.emit("context_update", this.getContextState());
|
|
2594
|
-
} catch (err) {
|
|
2595
|
-
this.flushStreaming();
|
|
2596
|
-
if (isAbortError(err)) {
|
|
2597
|
-
const result = buildInterruptedResult(
|
|
2598
|
-
this.getSessionOrThrow().getHistory(),
|
|
2599
|
-
this.history,
|
|
2600
|
-
historyBefore,
|
|
2601
|
-
this.getContextState()
|
|
2602
|
-
);
|
|
2603
|
-
pushToolSummaryToHistory({ activeTools: this.activeTools, history: this.history });
|
|
2604
|
-
this.clearStreaming();
|
|
2605
|
-
if (result.response)
|
|
2606
|
-
this.history.push((0, import_agent_core.messageToHistoryEntry)((0, import_agent_core.createAssistantMessage)(result.response)));
|
|
2607
|
-
this.history.push((0, import_agent_core.messageToHistoryEntry)((0, import_agent_core.createSystemMessage)("Interrupted by user.")));
|
|
2608
|
-
this.emit("interrupted", result);
|
|
2609
|
-
} else {
|
|
2610
|
-
pushToolSummaryToHistory({ activeTools: this.activeTools, history: this.history });
|
|
2611
|
-
this.clearStreaming();
|
|
2612
|
-
const errMsg = err instanceof Error ? err.message : String(err);
|
|
2613
|
-
this.history.push((0, import_agent_core.messageToHistoryEntry)((0, import_agent_core.createSystemMessage)(`Error: ${errMsg}`)));
|
|
2614
|
-
this.emit("error", err instanceof Error ? err : new Error(errMsg));
|
|
2615
|
-
}
|
|
2616
|
-
} finally {
|
|
2617
|
-
this.executing = false;
|
|
2618
|
-
this.emit("thinking", false);
|
|
2619
|
-
if (this.sessionStore && this.session) {
|
|
2620
|
-
persistSession(
|
|
2621
|
-
this.sessionStore,
|
|
2622
|
-
this.session,
|
|
2623
|
-
this.sessionName,
|
|
2624
|
-
this.cwd ?? "",
|
|
2625
|
-
this.history
|
|
2626
|
-
);
|
|
2627
|
-
}
|
|
2628
|
-
if (this.pendingPrompt) {
|
|
2629
|
-
const queued = this.pendingPrompt;
|
|
2630
|
-
const queuedDisplay = this.pendingDisplayInput;
|
|
2631
|
-
const queuedRaw = this.pendingRawInput;
|
|
2632
|
-
this.clearPendingQueue();
|
|
2633
|
-
setTimeout(() => this.executePrompt(queued, queuedDisplay, queuedRaw), 0);
|
|
2634
|
-
}
|
|
2635
|
-
}
|
|
3956
|
+
async cancelBackgroundTask(taskId, reason) {
|
|
3957
|
+
await this.ensureInitialized();
|
|
3958
|
+
await this.getBackgroundTaskManagerOrThrow().cancel(taskId, reason);
|
|
2636
3959
|
}
|
|
2637
|
-
|
|
2638
|
-
this.
|
|
2639
|
-
this.
|
|
2640
|
-
if (!this.flushTimer) {
|
|
2641
|
-
this.flushTimer = setTimeout(() => {
|
|
2642
|
-
this.flushTimer = null;
|
|
2643
|
-
}, STREAMING_FLUSH_INTERVAL_MS);
|
|
2644
|
-
}
|
|
3960
|
+
async closeBackgroundTask(taskId) {
|
|
3961
|
+
await this.ensureInitialized();
|
|
3962
|
+
await this.getBackgroundTaskManagerOrThrow().close(taskId);
|
|
2645
3963
|
}
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
3964
|
+
async sendBackgroundTask(taskId, input) {
|
|
3965
|
+
await this.ensureInitialized();
|
|
3966
|
+
await this.getBackgroundTaskManagerOrThrow().send(taskId, input);
|
|
3967
|
+
}
|
|
3968
|
+
async readBackgroundTaskLog(taskId, cursor) {
|
|
3969
|
+
await this.ensureInitialized();
|
|
3970
|
+
return this.getBackgroundTaskManagerOrThrow().readLog(taskId, cursor);
|
|
3971
|
+
}
|
|
3972
|
+
createBackgroundJobGroup(input) {
|
|
3973
|
+
const orchestrator = this.getBackgroundJobOrchestratorOrThrow();
|
|
3974
|
+
return orchestrator.createGroup({
|
|
3975
|
+
...input,
|
|
3976
|
+
parentSessionId: this.getSessionOrThrow().getSessionId()
|
|
3977
|
+
});
|
|
2657
3978
|
}
|
|
2658
|
-
|
|
2659
|
-
this.
|
|
2660
|
-
this.activeTools = [];
|
|
2661
|
-
if (this.flushTimer) {
|
|
2662
|
-
clearTimeout(this.flushTimer);
|
|
2663
|
-
this.flushTimer = null;
|
|
2664
|
-
}
|
|
3979
|
+
listBackgroundJobGroups() {
|
|
3980
|
+
return this.getBackgroundJobOrchestratorOrThrow().listGroups();
|
|
2665
3981
|
}
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
clearTimeout(this.flushTimer);
|
|
2669
|
-
this.flushTimer = null;
|
|
2670
|
-
}
|
|
3982
|
+
getBackgroundJobGroup(groupId) {
|
|
3983
|
+
return this.getBackgroundJobOrchestratorOrThrow().getGroup(groupId);
|
|
2671
3984
|
}
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
function createQuery(options) {
|
|
2676
|
-
const session = new InteractiveSession({
|
|
2677
|
-
cwd: options.cwd ?? process.cwd(),
|
|
2678
|
-
provider: options.provider,
|
|
2679
|
-
permissionMode: options.permissionMode ?? "bypassPermissions",
|
|
2680
|
-
maxTurns: options.maxTurns,
|
|
2681
|
-
permissionHandler: options.permissionHandler
|
|
2682
|
-
});
|
|
2683
|
-
if (options.onTextDelta) {
|
|
2684
|
-
session.on("text_delta", options.onTextDelta);
|
|
3985
|
+
async waitBackgroundJobGroup(groupId) {
|
|
3986
|
+
await this.ensureInitialized();
|
|
3987
|
+
return this.getBackgroundJobOrchestratorOrThrow().waitGroup(groupId);
|
|
2685
3988
|
}
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
3989
|
+
listAgentDefinitions() {
|
|
3990
|
+
const deps = retrieveAgentToolDeps(this.getSessionOrThrow());
|
|
3991
|
+
return (deps?.agentDefinitions ?? []).map((agent) => ({
|
|
3992
|
+
name: agent.name,
|
|
3993
|
+
description: agent.description
|
|
3994
|
+
}));
|
|
3995
|
+
}
|
|
3996
|
+
listAgentJobs() {
|
|
3997
|
+
return this.getSubagentManagerOrThrow().list();
|
|
3998
|
+
}
|
|
3999
|
+
async spawnAgentJob(input) {
|
|
4000
|
+
await this.ensureInitialized();
|
|
4001
|
+
const deps = this.getAgentToolDepsOrThrow();
|
|
4002
|
+
const definition = this.resolveAgentDefinition(input.agentType, deps);
|
|
4003
|
+
return this.getSubagentManagerOrThrow().spawn({
|
|
4004
|
+
type: input.agentType,
|
|
4005
|
+
label: input.label,
|
|
4006
|
+
parentSessionId: this.getSessionOrThrow().getSessionId(),
|
|
4007
|
+
mode: input.mode,
|
|
4008
|
+
depth: (deps.subagentDepth ?? 0) + 1,
|
|
4009
|
+
cwd: deps.cwd ?? this.cwd ?? process.cwd(),
|
|
4010
|
+
prompt: input.prompt,
|
|
4011
|
+
model: input.model ?? definition.model,
|
|
4012
|
+
isolation: input.isolation,
|
|
4013
|
+
allowedTools: definition.tools,
|
|
4014
|
+
disallowedTools: definition.disallowedTools
|
|
2712
4015
|
});
|
|
2713
|
-
};
|
|
2714
|
-
}
|
|
2715
|
-
|
|
2716
|
-
// src/commands/command-registry.ts
|
|
2717
|
-
var CommandRegistry = class {
|
|
2718
|
-
sources = [];
|
|
2719
|
-
addSource(source) {
|
|
2720
|
-
this.sources.push(source);
|
|
2721
4016
|
}
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
for (const source of this.sources) {
|
|
2726
|
-
all.push(...source.getCommands());
|
|
2727
|
-
}
|
|
2728
|
-
if (!filter) return all;
|
|
2729
|
-
const lower = filter.toLowerCase();
|
|
2730
|
-
return all.filter((cmd) => cmd.name.toLowerCase().startsWith(lower));
|
|
4017
|
+
async waitAgentJob(jobId) {
|
|
4018
|
+
await this.ensureInitialized();
|
|
4019
|
+
return this.getSubagentManagerOrThrow().wait(jobId);
|
|
2731
4020
|
}
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
(c) => c.source === "plugin" && c.name.includes(":") && c.name.endsWith(`:${shortName}`)
|
|
2736
|
-
);
|
|
2737
|
-
if (matches.length !== 1) return null;
|
|
2738
|
-
return matches[0].name;
|
|
4021
|
+
async sendAgentJob(jobId, prompt) {
|
|
4022
|
+
await this.ensureInitialized();
|
|
4023
|
+
await this.getSubagentManagerOrThrow().send(jobId, prompt);
|
|
2739
4024
|
}
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
4025
|
+
async cancelAgentJob(jobId, reason) {
|
|
4026
|
+
await this.ensureInitialized();
|
|
4027
|
+
await this.getSubagentManagerOrThrow().cancel(jobId, reason);
|
|
4028
|
+
}
|
|
4029
|
+
async closeAgentJob(jobId) {
|
|
4030
|
+
await this.ensureInitialized();
|
|
4031
|
+
await this.getSubagentManagerOrThrow().close(jobId);
|
|
4032
|
+
}
|
|
4033
|
+
setName(name) {
|
|
4034
|
+
this.sessionName = name;
|
|
4035
|
+
if (this.sessionStore && this.session) {
|
|
4036
|
+
try {
|
|
4037
|
+
const id = this.getSessionOrThrow().getSessionId();
|
|
4038
|
+
const existing = this.sessionStore.load(id);
|
|
4039
|
+
if (existing) {
|
|
4040
|
+
existing.name = name;
|
|
4041
|
+
existing.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4042
|
+
this.sessionStore.save(existing);
|
|
2747
4043
|
}
|
|
4044
|
+
} catch {
|
|
2748
4045
|
}
|
|
2749
4046
|
}
|
|
2750
|
-
return [];
|
|
2751
4047
|
}
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
4048
|
+
attachTransport(transport) {
|
|
4049
|
+
transport.attach(this);
|
|
4050
|
+
}
|
|
4051
|
+
async executeForkSkillCommand(skill, args, displayInput) {
|
|
4052
|
+
if (this.executing) {
|
|
4053
|
+
throw new Error("Cannot execute fork skill while another prompt is running.");
|
|
4054
|
+
}
|
|
4055
|
+
this.startForkSkillExecution(displayInput ?? `/${skill.name}`);
|
|
4056
|
+
try {
|
|
4057
|
+
const result = await executeSkill(
|
|
4058
|
+
skill,
|
|
4059
|
+
args,
|
|
4060
|
+
{ runInFork: (content, options) => this.runSkillInFork(content, options) },
|
|
4061
|
+
{ sessionId: this.getSessionOrThrow().getSessionId() }
|
|
4062
|
+
);
|
|
4063
|
+
await this.applyForkSkillResult(result.result ?? "(empty response)");
|
|
4064
|
+
return result;
|
|
4065
|
+
} catch (err) {
|
|
4066
|
+
this.recordForkSkillError(err instanceof Error ? err : new Error(String(err)));
|
|
4067
|
+
return { mode: "fork", result: "" };
|
|
4068
|
+
} finally {
|
|
4069
|
+
this.finishForkSkillExecution();
|
|
4070
|
+
}
|
|
4071
|
+
}
|
|
4072
|
+
getBackgroundTaskManagerOrThrow() {
|
|
4073
|
+
const manager = this.getBackgroundTaskManager();
|
|
4074
|
+
if (!manager) {
|
|
4075
|
+
throw new Error("Background task manager is not available for this session.");
|
|
4076
|
+
}
|
|
4077
|
+
return manager;
|
|
4078
|
+
}
|
|
4079
|
+
getBackgroundTaskManager() {
|
|
4080
|
+
if (!this.session) return void 0;
|
|
4081
|
+
return retrieveSessionBackgroundTaskManager(this.session) ?? retrieveAgentToolDeps(this.session)?.backgroundTaskManager;
|
|
4082
|
+
}
|
|
4083
|
+
getBackgroundJobOrchestratorOrThrow() {
|
|
4084
|
+
if (this.backgroundJobOrchestrator) return this.backgroundJobOrchestrator;
|
|
4085
|
+
const manager = this.getBackgroundTaskManagerOrThrow();
|
|
4086
|
+
this.backgroundJobOrchestrator = new BackgroundJobOrchestrator({
|
|
4087
|
+
manager,
|
|
4088
|
+
initialGroups: this.backgroundJobGroups
|
|
2766
4089
|
});
|
|
4090
|
+
this.subscribeBackgroundJobGroupEvents();
|
|
4091
|
+
return this.backgroundJobOrchestrator;
|
|
2767
4092
|
}
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
source: "builtin",
|
|
2778
|
-
subcommands: [
|
|
2779
|
-
{ name: "plan", description: "Plan only, no execution", source: "builtin" },
|
|
2780
|
-
{ name: "default", description: "Ask before risky actions", source: "builtin" },
|
|
2781
|
-
{ name: "acceptEdits", description: "Auto-approve file edits", source: "builtin" },
|
|
2782
|
-
{ name: "bypassPermissions", description: "Skip all permission checks", source: "builtin" }
|
|
2783
|
-
]
|
|
2784
|
-
},
|
|
2785
|
-
{
|
|
2786
|
-
name: "model",
|
|
2787
|
-
description: "Select AI model",
|
|
2788
|
-
source: "builtin",
|
|
2789
|
-
subcommands: buildModelSubcommands()
|
|
2790
|
-
},
|
|
2791
|
-
{
|
|
2792
|
-
name: "language",
|
|
2793
|
-
description: "Set response language",
|
|
2794
|
-
source: "builtin",
|
|
2795
|
-
subcommands: [
|
|
2796
|
-
{ name: "ko", description: "Korean", source: "builtin" },
|
|
2797
|
-
{ name: "en", description: "English", source: "builtin" },
|
|
2798
|
-
{ name: "ja", description: "Japanese", source: "builtin" },
|
|
2799
|
-
{ name: "zh", description: "Chinese", source: "builtin" }
|
|
2800
|
-
]
|
|
2801
|
-
},
|
|
2802
|
-
{ name: "compact", description: "Compress context window", source: "builtin" },
|
|
2803
|
-
{ name: "cost", description: "Show session info", source: "builtin" },
|
|
2804
|
-
{ name: "context", description: "Context window info", source: "builtin" },
|
|
2805
|
-
{ name: "permissions", description: "Permission rules", source: "builtin" },
|
|
2806
|
-
{ name: "resume", description: "Resume a previous session", source: "builtin" },
|
|
2807
|
-
{ name: "rename", description: "Rename the current session", source: "builtin" },
|
|
2808
|
-
{ name: "plugin", description: "Manage plugins", source: "builtin" },
|
|
2809
|
-
{ name: "reload-plugins", description: "Reload all plugin resources", source: "builtin" },
|
|
2810
|
-
{ name: "reset", description: "Delete settings and exit", source: "builtin" },
|
|
2811
|
-
{ name: "exit", description: "Exit CLI", source: "builtin" }
|
|
2812
|
-
];
|
|
2813
|
-
}
|
|
2814
|
-
var BuiltinCommandSource = class {
|
|
2815
|
-
name = "builtin";
|
|
2816
|
-
commands;
|
|
2817
|
-
constructor() {
|
|
2818
|
-
this.commands = createBuiltinCommands();
|
|
4093
|
+
getAgentToolDepsOrThrow() {
|
|
4094
|
+
const deps = retrieveAgentToolDeps(this.getSessionOrThrow());
|
|
4095
|
+
if (!deps) {
|
|
4096
|
+
throw new Error("Agent runtime dependencies are not available for this session.");
|
|
4097
|
+
}
|
|
4098
|
+
if (!deps.backgroundTaskManager) {
|
|
4099
|
+
throw new Error("Background task manager is not available for this session.");
|
|
4100
|
+
}
|
|
4101
|
+
return deps;
|
|
2819
4102
|
}
|
|
2820
|
-
|
|
2821
|
-
|
|
4103
|
+
getSubagentManagerOrThrow() {
|
|
4104
|
+
const deps = this.getAgentToolDepsOrThrow();
|
|
4105
|
+
if (!deps.subagentManager) {
|
|
4106
|
+
throw new Error("Subagent manager is not available for this session.");
|
|
4107
|
+
}
|
|
4108
|
+
return deps.subagentManager;
|
|
2822
4109
|
}
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
var import_node_path11 = require("path");
|
|
2828
|
-
var import_node_os4 = require("os");
|
|
2829
|
-
var BOOLEAN_KEYS = /* @__PURE__ */ new Set(["disable-model-invocation", "user-invocable"]);
|
|
2830
|
-
var LIST_KEYS2 = /* @__PURE__ */ new Set(["allowed-tools"]);
|
|
2831
|
-
function kebabToCamel(key) {
|
|
2832
|
-
return key.replace(/-([a-z])/g, (_match, letter) => letter.toUpperCase());
|
|
2833
|
-
}
|
|
2834
|
-
function parseFrontmatter2(content) {
|
|
2835
|
-
const lines = content.split("\n");
|
|
2836
|
-
if (lines[0]?.trim() !== "---") return null;
|
|
2837
|
-
const result = {};
|
|
2838
|
-
for (let i = 1; i < lines.length; i++) {
|
|
2839
|
-
const line = lines[i];
|
|
2840
|
-
if (line.trim() === "---") break;
|
|
2841
|
-
const match = line.match(/^([a-z][a-z0-9-]*):\s*(.+)/);
|
|
2842
|
-
if (!match) continue;
|
|
2843
|
-
const key = match[1];
|
|
2844
|
-
const rawValue = match[2].trim();
|
|
2845
|
-
const camelKey = kebabToCamel(key);
|
|
2846
|
-
if (BOOLEAN_KEYS.has(key)) {
|
|
2847
|
-
result[camelKey] = rawValue === "true";
|
|
2848
|
-
} else if (LIST_KEYS2.has(key)) {
|
|
2849
|
-
result[camelKey] = rawValue.split(",").map((s) => s.trim());
|
|
2850
|
-
} else {
|
|
2851
|
-
result[camelKey] = rawValue;
|
|
4110
|
+
resolveAgentDefinition(agentType, deps) {
|
|
4111
|
+
const definition = deps.customAgentRegistry?.(agentType);
|
|
4112
|
+
if (!definition) {
|
|
4113
|
+
throw new Error(`Unknown agent type: ${agentType}`);
|
|
2852
4114
|
}
|
|
4115
|
+
return definition;
|
|
4116
|
+
}
|
|
4117
|
+
subscribeBackgroundTaskEvents() {
|
|
4118
|
+
if (this.backgroundTaskUnsubscribe || !this.session) return;
|
|
4119
|
+
const manager = retrieveSessionBackgroundTaskManager(this.session) ?? retrieveAgentToolDeps(this.session)?.backgroundTaskManager;
|
|
4120
|
+
if (!manager) return;
|
|
4121
|
+
this.backgroundTaskUnsubscribe = manager.subscribe((event) => {
|
|
4122
|
+
this.recordBackgroundTaskEvent(event);
|
|
4123
|
+
this.emit("background_task_event", event);
|
|
4124
|
+
});
|
|
2853
4125
|
}
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
source: "skill",
|
|
2861
|
-
skillContent: content
|
|
2862
|
-
};
|
|
2863
|
-
if (frontmatter?.argumentHint !== void 0) cmd.argumentHint = frontmatter.argumentHint;
|
|
2864
|
-
if (frontmatter?.disableModelInvocation !== void 0)
|
|
2865
|
-
cmd.disableModelInvocation = frontmatter.disableModelInvocation;
|
|
2866
|
-
if (frontmatter?.userInvocable !== void 0) cmd.userInvocable = frontmatter.userInvocable;
|
|
2867
|
-
if (frontmatter?.allowedTools !== void 0) cmd.allowedTools = frontmatter.allowedTools;
|
|
2868
|
-
if (frontmatter?.model !== void 0) cmd.model = frontmatter.model;
|
|
2869
|
-
if (frontmatter?.effort !== void 0) cmd.effort = frontmatter.effort;
|
|
2870
|
-
if (frontmatter?.context !== void 0) cmd.context = frontmatter.context;
|
|
2871
|
-
if (frontmatter?.agent !== void 0) cmd.agent = frontmatter.agent;
|
|
2872
|
-
return cmd;
|
|
2873
|
-
}
|
|
2874
|
-
function scanSkillsDir(skillsDir) {
|
|
2875
|
-
if (!(0, import_node_fs9.existsSync)(skillsDir)) return [];
|
|
2876
|
-
const commands = [];
|
|
2877
|
-
const entries = (0, import_node_fs9.readdirSync)(skillsDir, { withFileTypes: true });
|
|
2878
|
-
for (const entry of entries) {
|
|
2879
|
-
if (!entry.isDirectory()) continue;
|
|
2880
|
-
const skillFile = (0, import_node_path11.join)(skillsDir, entry.name, "SKILL.md");
|
|
2881
|
-
if (!(0, import_node_fs9.existsSync)(skillFile)) continue;
|
|
2882
|
-
const content = (0, import_node_fs9.readFileSync)(skillFile, "utf-8");
|
|
2883
|
-
const frontmatter = parseFrontmatter2(content);
|
|
2884
|
-
commands.push(buildCommand(frontmatter, content, entry.name));
|
|
4126
|
+
subscribeBackgroundJobGroupEvents() {
|
|
4127
|
+
if (this.backgroundJobUnsubscribe || !this.backgroundJobOrchestrator) return;
|
|
4128
|
+
this.backgroundJobUnsubscribe = this.backgroundJobOrchestrator.subscribe((event) => {
|
|
4129
|
+
this.recordBackgroundJobGroupEvent(event);
|
|
4130
|
+
this.emit("background_job_group_event", event);
|
|
4131
|
+
});
|
|
2885
4132
|
}
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
const commands = [];
|
|
2891
|
-
const entries = (0, import_node_fs9.readdirSync)(commandsDir, { withFileTypes: true });
|
|
2892
|
-
for (const entry of entries) {
|
|
2893
|
-
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
2894
|
-
const filePath = (0, import_node_path11.join)(commandsDir, entry.name);
|
|
2895
|
-
const content = (0, import_node_fs9.readFileSync)(filePath, "utf-8");
|
|
2896
|
-
const frontmatter = parseFrontmatter2(content);
|
|
2897
|
-
const fallbackName = (0, import_node_path11.basename)(entry.name, ".md");
|
|
2898
|
-
commands.push(buildCommand(frontmatter, content, fallbackName));
|
|
4133
|
+
recordBackgroundTaskEvent(event) {
|
|
4134
|
+
this.backgroundTasks = this.getBackgroundTaskSnapshots();
|
|
4135
|
+
this.backgroundTaskEvents.push(event);
|
|
4136
|
+
this.persistCurrentSession();
|
|
2899
4137
|
}
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
4138
|
+
recordBackgroundJobGroupEvent(event) {
|
|
4139
|
+
this.backgroundJobGroups = this.getBackgroundJobGroupSnapshots();
|
|
4140
|
+
this.backgroundJobGroupEvents.push(event);
|
|
4141
|
+
this.persistCurrentSession();
|
|
4142
|
+
}
|
|
4143
|
+
getBackgroundTaskSnapshots() {
|
|
4144
|
+
try {
|
|
4145
|
+
return this.getBackgroundTaskManagerOrThrow().list();
|
|
4146
|
+
} catch {
|
|
4147
|
+
return this.backgroundTasks;
|
|
4148
|
+
}
|
|
2910
4149
|
}
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
4150
|
+
getBackgroundJobGroupSnapshots() {
|
|
4151
|
+
try {
|
|
4152
|
+
return this.backgroundJobOrchestrator?.listGroups() ?? this.backgroundJobGroups;
|
|
4153
|
+
} catch {
|
|
4154
|
+
return this.backgroundJobGroups;
|
|
4155
|
+
}
|
|
4156
|
+
}
|
|
4157
|
+
persistCurrentSession() {
|
|
4158
|
+
if (!this.sessionStore || !this.session) return;
|
|
4159
|
+
this.backgroundTasks = this.getBackgroundTaskSnapshots();
|
|
4160
|
+
this.backgroundJobGroups = this.getBackgroundJobGroupSnapshots();
|
|
4161
|
+
persistSession(
|
|
4162
|
+
this.sessionStore,
|
|
4163
|
+
this.session,
|
|
4164
|
+
this.sessionName,
|
|
4165
|
+
this.cwd ?? "",
|
|
4166
|
+
this.history,
|
|
4167
|
+
{
|
|
4168
|
+
tasks: this.backgroundTasks,
|
|
4169
|
+
events: this.backgroundTaskEvents,
|
|
4170
|
+
groups: this.backgroundJobGroups,
|
|
4171
|
+
groupEvents: this.backgroundJobGroupEvents
|
|
2927
4172
|
}
|
|
4173
|
+
);
|
|
4174
|
+
}
|
|
4175
|
+
startForkSkillExecution(displayInput) {
|
|
4176
|
+
this.executing = true;
|
|
4177
|
+
this.clearStreaming();
|
|
4178
|
+
this.emit("thinking", true);
|
|
4179
|
+
this.history.push((0, import_agent_core3.messageToHistoryEntry)((0, import_agent_core3.createUserMessage)(displayInput)));
|
|
4180
|
+
}
|
|
4181
|
+
finishForkSkillExecution() {
|
|
4182
|
+
this.executing = false;
|
|
4183
|
+
this.emit("thinking", false);
|
|
4184
|
+
this.persistCurrentSession();
|
|
4185
|
+
if (!this.shuttingDown && this.pendingPrompt) {
|
|
4186
|
+
const queued = this.pendingPrompt;
|
|
4187
|
+
const queuedDisplay = this.pendingDisplayInput;
|
|
4188
|
+
const queuedRaw = this.pendingRawInput;
|
|
4189
|
+
this.clearPendingQueue();
|
|
4190
|
+
setTimeout(() => this.executePrompt(queued, queuedDisplay, queuedRaw), 0);
|
|
2928
4191
|
}
|
|
2929
|
-
this.cachedCommands = merged;
|
|
2930
|
-
return this.cachedCommands;
|
|
2931
4192
|
}
|
|
2932
|
-
|
|
2933
|
-
|
|
4193
|
+
recordForkSkillError(err) {
|
|
4194
|
+
this.history.push((0, import_agent_core3.messageToHistoryEntry)((0, import_agent_core3.createSystemMessage)(`Error: ${err.message}`)));
|
|
4195
|
+
this.emit("error", err);
|
|
2934
4196
|
}
|
|
2935
|
-
|
|
2936
|
-
|
|
4197
|
+
resolveForkAgentDefinition(agentType, options) {
|
|
4198
|
+
const deps = retrieveAgentToolDeps(this.getSessionOrThrow());
|
|
4199
|
+
const definition = deps?.customAgentRegistry?.(agentType) ?? getBuiltInAgent(agentType);
|
|
4200
|
+
if (!definition) {
|
|
4201
|
+
throw new Error(`Unknown agent type: ${agentType}`);
|
|
4202
|
+
}
|
|
4203
|
+
if (options.allowedTools) {
|
|
4204
|
+
return { ...definition, tools: options.allowedTools };
|
|
4205
|
+
}
|
|
4206
|
+
return definition;
|
|
2937
4207
|
}
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
this.
|
|
4208
|
+
async runSkillInFork(content, options) {
|
|
4209
|
+
const parentSession = this.getSessionOrThrow();
|
|
4210
|
+
const deps = retrieveAgentToolDeps(parentSession);
|
|
4211
|
+
if (!deps) {
|
|
4212
|
+
throw new Error("Fork execution is not available. Agent tool deps may not be initialized.");
|
|
4213
|
+
}
|
|
4214
|
+
const agentType = options.agent ?? "general-purpose";
|
|
4215
|
+
const agentDefinition = this.resolveForkAgentDefinition(agentType, options);
|
|
4216
|
+
const forkSession = createSubagentSession({
|
|
4217
|
+
agentDefinition,
|
|
4218
|
+
parentConfig: deps.config,
|
|
4219
|
+
parentContext: deps.context,
|
|
4220
|
+
parentTools: deps.tools,
|
|
4221
|
+
provider: deps.provider,
|
|
4222
|
+
terminal: deps.terminal,
|
|
4223
|
+
isForkWorker: true,
|
|
4224
|
+
permissionMode: deps.permissionMode,
|
|
4225
|
+
permissionHandler: deps.permissionHandler,
|
|
4226
|
+
hooks: deps.hooks,
|
|
4227
|
+
hookTypeExecutors: deps.hookTypeExecutors,
|
|
4228
|
+
onTextDelta: deps.onTextDelta,
|
|
4229
|
+
onToolExecution: deps.onToolExecution
|
|
4230
|
+
});
|
|
4231
|
+
return forkSession.run(content);
|
|
2946
4232
|
}
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
4233
|
+
async applyForkSkillResult(result) {
|
|
4234
|
+
this.flushStreaming();
|
|
4235
|
+
pushToolSummaryToHistory({ activeTools: this.activeTools, history: this.history });
|
|
4236
|
+
this.clearStreaming();
|
|
4237
|
+
const executionResult = {
|
|
4238
|
+
response: result,
|
|
4239
|
+
history: this.history,
|
|
4240
|
+
toolSummaries: [],
|
|
4241
|
+
contextState: this.getContextState()
|
|
4242
|
+
};
|
|
4243
|
+
this.history.push((0, import_agent_core3.messageToHistoryEntry)((0, import_agent_core3.createAssistantMessage)(result)));
|
|
4244
|
+
this.emit("complete", executionResult);
|
|
4245
|
+
this.emit("context_update", this.getContextState());
|
|
4246
|
+
}
|
|
4247
|
+
async executePrompt(input, displayInput, rawInput) {
|
|
4248
|
+
this.executing = true;
|
|
4249
|
+
this.clearStreaming();
|
|
4250
|
+
this.emit("thinking", true);
|
|
4251
|
+
this.history.push((0, import_agent_core3.messageToHistoryEntry)((0, import_agent_core3.createUserMessage)(displayInput ?? input)));
|
|
4252
|
+
const historyBefore = this.getSessionOrThrow().getHistory().length;
|
|
4253
|
+
try {
|
|
4254
|
+
const response = await this.getSessionOrThrow().run(input, rawInput);
|
|
4255
|
+
this.flushStreaming();
|
|
4256
|
+
pushToolSummaryToHistory({ activeTools: this.activeTools, history: this.history });
|
|
4257
|
+
this.clearStreaming();
|
|
4258
|
+
const result = buildResult(
|
|
4259
|
+
response || "(empty response)",
|
|
4260
|
+
this.getSessionOrThrow().getHistory(),
|
|
4261
|
+
this.history,
|
|
4262
|
+
historyBefore,
|
|
4263
|
+
this.getContextState()
|
|
4264
|
+
);
|
|
4265
|
+
this.history.push((0, import_agent_core3.messageToHistoryEntry)((0, import_agent_core3.createAssistantMessage)(result.response)));
|
|
4266
|
+
this.emit("complete", result);
|
|
4267
|
+
this.emit("context_update", this.getContextState());
|
|
4268
|
+
} catch (err) {
|
|
4269
|
+
this.flushStreaming();
|
|
4270
|
+
if (isAbortError(err)) {
|
|
4271
|
+
const result = buildInterruptedResult(
|
|
4272
|
+
this.getSessionOrThrow().getHistory(),
|
|
4273
|
+
this.history,
|
|
4274
|
+
historyBefore,
|
|
4275
|
+
this.getContextState()
|
|
4276
|
+
);
|
|
4277
|
+
pushToolSummaryToHistory({ activeTools: this.activeTools, history: this.history });
|
|
4278
|
+
this.clearStreaming();
|
|
4279
|
+
if (result.response)
|
|
4280
|
+
this.history.push((0, import_agent_core3.messageToHistoryEntry)((0, import_agent_core3.createAssistantMessage)(result.response)));
|
|
4281
|
+
this.history.push((0, import_agent_core3.messageToHistoryEntry)((0, import_agent_core3.createSystemMessage)("Interrupted by user.")));
|
|
4282
|
+
this.emit("interrupted", result);
|
|
4283
|
+
} else {
|
|
4284
|
+
pushToolSummaryToHistory({ activeTools: this.activeTools, history: this.history });
|
|
4285
|
+
this.clearStreaming();
|
|
4286
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
4287
|
+
this.history.push((0, import_agent_core3.messageToHistoryEntry)((0, import_agent_core3.createSystemMessage)(`Error: ${errMsg}`)));
|
|
4288
|
+
this.emit("error", err instanceof Error ? err : new Error(errMsg));
|
|
2959
4289
|
}
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
4290
|
+
} finally {
|
|
4291
|
+
this.executing = false;
|
|
4292
|
+
this.emit("thinking", false);
|
|
4293
|
+
this.persistCurrentSession();
|
|
4294
|
+
if (!this.shuttingDown && this.pendingPrompt) {
|
|
4295
|
+
const queued = this.pendingPrompt;
|
|
4296
|
+
const queuedDisplay = this.pendingDisplayInput;
|
|
4297
|
+
const queuedRaw = this.pendingRawInput;
|
|
4298
|
+
this.clearPendingQueue();
|
|
4299
|
+
setTimeout(() => this.executePrompt(queued, queuedDisplay, queuedRaw), 0);
|
|
2968
4300
|
}
|
|
2969
4301
|
}
|
|
2970
|
-
return commands;
|
|
2971
4302
|
}
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
return argParts[Number(index)] ?? "";
|
|
2981
|
-
});
|
|
2982
|
-
result = result.replace(/\$ARGUMENTS/g, args);
|
|
2983
|
-
result = result.replace(/\$(\d)(?!\d|\w|\[)/g, (_match, digit) => {
|
|
2984
|
-
return argParts[Number(digit)] ?? "";
|
|
2985
|
-
});
|
|
2986
|
-
result = result.replace(/\$\{CLAUDE_SESSION_ID}/g, context?.sessionId ?? "");
|
|
2987
|
-
result = result.replace(/\$\{CLAUDE_SKILL_DIR}/g, context?.skillDir ?? "");
|
|
2988
|
-
return result;
|
|
2989
|
-
}
|
|
2990
|
-
async function preprocessShellCommands(content) {
|
|
2991
|
-
const shellPattern = /!`([^`]+)`/g;
|
|
2992
|
-
if (!shellPattern.test(content)) {
|
|
2993
|
-
return content;
|
|
4303
|
+
handleTextDelta(delta) {
|
|
4304
|
+
this.streamingText += delta;
|
|
4305
|
+
this.emit("text_delta", delta);
|
|
4306
|
+
if (!this.flushTimer) {
|
|
4307
|
+
this.flushTimer = setTimeout(() => {
|
|
4308
|
+
this.flushTimer = null;
|
|
4309
|
+
}, STREAMING_FLUSH_INTERVAL_MS);
|
|
4310
|
+
}
|
|
2994
4311
|
}
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
4312
|
+
handleToolExecution(event) {
|
|
4313
|
+
const streamingState = { activeTools: this.activeTools, history: this.history };
|
|
4314
|
+
if (event.type === "start") {
|
|
4315
|
+
const toolState = applyToolStart(streamingState, event);
|
|
4316
|
+
this.activeTools = streamingState.activeTools;
|
|
4317
|
+
this.emit("tool_start", toolState);
|
|
4318
|
+
} else {
|
|
4319
|
+
const finished = applyToolEnd(streamingState, event);
|
|
4320
|
+
this.activeTools = streamingState.activeTools;
|
|
4321
|
+
if (finished) this.emit("tool_end", finished);
|
|
4322
|
+
}
|
|
3001
4323
|
}
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
3009
|
-
}).trimEnd();
|
|
3010
|
-
} catch {
|
|
3011
|
-
output = "";
|
|
4324
|
+
clearStreaming() {
|
|
4325
|
+
this.streamingText = "";
|
|
4326
|
+
this.activeTools = [];
|
|
4327
|
+
if (this.flushTimer) {
|
|
4328
|
+
clearTimeout(this.flushTimer);
|
|
4329
|
+
this.flushTimer = null;
|
|
3012
4330
|
}
|
|
3013
|
-
result = result.replace(full, output);
|
|
3014
4331
|
}
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
const args = parts.slice(1).join(" ").trim();
|
|
3023
|
-
const userInstruction = args || skillCmd.description;
|
|
3024
|
-
if (skillCmd.skillContent) {
|
|
3025
|
-
let processed = await preprocessShellCommands(skillCmd.skillContent);
|
|
3026
|
-
processed = substituteVariables(processed, args, context);
|
|
3027
|
-
return `<skill name="${cmd}">
|
|
3028
|
-
${processed}
|
|
3029
|
-
</skill>
|
|
4332
|
+
flushStreaming() {
|
|
4333
|
+
if (this.flushTimer) {
|
|
4334
|
+
clearTimeout(this.flushTimer);
|
|
4335
|
+
this.flushTimer = null;
|
|
4336
|
+
}
|
|
4337
|
+
}
|
|
4338
|
+
};
|
|
3030
4339
|
|
|
3031
|
-
|
|
4340
|
+
// src/query.ts
|
|
4341
|
+
function createQuery(options) {
|
|
4342
|
+
const session = new InteractiveSession({
|
|
4343
|
+
cwd: options.cwd ?? process.cwd(),
|
|
4344
|
+
provider: options.provider,
|
|
4345
|
+
permissionMode: options.permissionMode ?? "bypassPermissions",
|
|
4346
|
+
maxTurns: options.maxTurns,
|
|
4347
|
+
permissionHandler: options.permissionHandler
|
|
4348
|
+
});
|
|
4349
|
+
if (options.onTextDelta) {
|
|
4350
|
+
session.on("text_delta", options.onTextDelta);
|
|
3032
4351
|
}
|
|
3033
|
-
return
|
|
4352
|
+
return async (prompt) => {
|
|
4353
|
+
return new Promise((resolve2, reject) => {
|
|
4354
|
+
const onComplete = (result) => {
|
|
4355
|
+
cleanup();
|
|
4356
|
+
resolve2(result.response);
|
|
4357
|
+
};
|
|
4358
|
+
const onInterrupted = (result) => {
|
|
4359
|
+
cleanup();
|
|
4360
|
+
resolve2(result.response);
|
|
4361
|
+
};
|
|
4362
|
+
const onError = (error) => {
|
|
4363
|
+
cleanup();
|
|
4364
|
+
reject(error);
|
|
4365
|
+
};
|
|
4366
|
+
const cleanup = () => {
|
|
4367
|
+
session.off("complete", onComplete);
|
|
4368
|
+
session.off("interrupted", onInterrupted);
|
|
4369
|
+
session.off("error", onError);
|
|
4370
|
+
};
|
|
4371
|
+
session.on("complete", onComplete);
|
|
4372
|
+
session.on("interrupted", onInterrupted);
|
|
4373
|
+
session.on("error", onError);
|
|
4374
|
+
session.submit(prompt).catch((err) => {
|
|
4375
|
+
cleanup();
|
|
4376
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
4377
|
+
});
|
|
4378
|
+
});
|
|
4379
|
+
};
|
|
3034
4380
|
}
|
|
3035
4381
|
|
|
3036
4382
|
// src/types.ts
|
|
3037
|
-
var
|
|
4383
|
+
var import_agent_core4 = require("@robota-sdk/agent-core");
|
|
3038
4384
|
|
|
3039
4385
|
// src/index.ts
|
|
3040
|
-
var import_agent_core4 = require("@robota-sdk/agent-core");
|
|
3041
4386
|
var import_agent_core5 = require("@robota-sdk/agent-core");
|
|
3042
4387
|
|
|
4388
|
+
// src/subagents/index.ts
|
|
4389
|
+
var import_agent_runtime7 = require("@robota-sdk/agent-runtime");
|
|
4390
|
+
var import_agent_runtime8 = require("@robota-sdk/agent-runtime");
|
|
4391
|
+
|
|
4392
|
+
// src/index.ts
|
|
4393
|
+
var import_agent_core6 = require("@robota-sdk/agent-core");
|
|
4394
|
+
|
|
3043
4395
|
// src/permissions/permission-prompt.ts
|
|
3044
4396
|
var import_chalk = __toESM(require("chalk"), 1);
|
|
3045
4397
|
var PERMISSION_OPTIONS = ["Allow", "Deny"];
|
|
@@ -3061,11 +4413,14 @@ async function promptForApproval(terminal, toolName, toolArgs) {
|
|
|
3061
4413
|
}
|
|
3062
4414
|
|
|
3063
4415
|
// src/index.ts
|
|
3064
|
-
var
|
|
4416
|
+
var import_agent_core7 = require("@robota-sdk/agent-core");
|
|
3065
4417
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3066
4418
|
0 && (module.exports = {
|
|
3067
4419
|
AgentExecutor,
|
|
3068
4420
|
BUILT_IN_AGENTS,
|
|
4421
|
+
BackgroundJobOrchestrator,
|
|
4422
|
+
BackgroundTaskError,
|
|
4423
|
+
BackgroundTaskManager,
|
|
3069
4424
|
BuiltinCommandSource,
|
|
3070
4425
|
BundlePluginInstaller,
|
|
3071
4426
|
BundlePluginLoader,
|
|
@@ -3076,20 +4431,31 @@ var import_agent_core6 = require("@robota-sdk/agent-core");
|
|
|
3076
4431
|
PluginSettingsStore,
|
|
3077
4432
|
PromptExecutor,
|
|
3078
4433
|
SkillCommandSource,
|
|
4434
|
+
SubagentManager,
|
|
4435
|
+
SystemCommandExecutor,
|
|
3079
4436
|
TRUST_TO_MODE,
|
|
4437
|
+
WorktreeSubagentRunner,
|
|
3080
4438
|
assembleSubagentPrompt,
|
|
3081
4439
|
buildSkillPrompt,
|
|
3082
4440
|
chatEntryToMessage,
|
|
3083
4441
|
createAgentTool,
|
|
4442
|
+
createBackgroundProcessTool,
|
|
4443
|
+
createCommandExecutionTool,
|
|
4444
|
+
createDefaultTools,
|
|
3084
4445
|
createQuery,
|
|
3085
4446
|
createSubagentLogger,
|
|
3086
4447
|
createSubagentSession,
|
|
4448
|
+
createSystemCommands,
|
|
4449
|
+
createWorktreeSubagentRunner,
|
|
3087
4450
|
evaluatePermission,
|
|
4451
|
+
executeSkill,
|
|
4452
|
+
getBackgroundTaskTransitions,
|
|
3088
4453
|
getBuiltInAgent,
|
|
3089
4454
|
getForkWorkerSuffix,
|
|
3090
4455
|
getMessagesForAPI,
|
|
3091
4456
|
getSubagentSuffix,
|
|
3092
4457
|
isChatEntry,
|
|
4458
|
+
isTerminalBackgroundTaskStatus,
|
|
3093
4459
|
messageToHistoryEntry,
|
|
3094
4460
|
parseFrontmatter,
|
|
3095
4461
|
preprocessShellCommands,
|
|
@@ -3100,5 +4466,7 @@ var import_agent_core6 = require("@robota-sdk/agent-core");
|
|
|
3100
4466
|
runHooks,
|
|
3101
4467
|
storeAgentToolDeps,
|
|
3102
4468
|
substituteVariables,
|
|
4469
|
+
summarizeBackgroundJobGroup,
|
|
4470
|
+
transitionBackgroundTaskStatus,
|
|
3103
4471
|
userPaths
|
|
3104
4472
|
});
|