@robota-sdk/agent-sdk 3.0.0-beta.59 → 3.0.0-beta.60

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.
@@ -30,7 +30,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ AUTO_COMPACT_THRESHOLD_SETTINGS_KEY: () => AUTO_COMPACT_THRESHOLD_SETTINGS_KEY,
33
34
  AgentExecutor: () => AgentExecutor,
35
+ BACKGROUND_COMMAND_DESCRIPTION: () => BACKGROUND_COMMAND_DESCRIPTION,
36
+ BACKGROUND_COMMAND_USAGE: () => BACKGROUND_COMMAND_USAGE,
34
37
  BUILT_IN_AGENTS: () => BUILT_IN_AGENTS,
35
38
  BackgroundJobOrchestrator: () => BackgroundJobOrchestrator,
36
39
  BackgroundTaskError: () => import_agent_runtime5.BackgroundTaskError,
@@ -38,71 +41,178 @@ __export(index_exports, {
38
41
  BuiltinCommandSource: () => BuiltinCommandSource,
39
42
  BundlePluginInstaller: () => BundlePluginInstaller,
40
43
  BundlePluginLoader: () => BundlePluginLoader,
44
+ CLEAR_COMMAND_DESCRIPTION: () => CLEAR_COMMAND_DESCRIPTION,
45
+ COST_COMMAND_DESCRIPTION: () => COST_COMMAND_DESCRIPTION,
41
46
  CommandRegistry: () => CommandRegistry,
47
+ DEFAULT_AUTO_COMPACT_THRESHOLD: () => DEFAULT_AUTO_COMPACT_THRESHOLD,
48
+ DEFAULT_STATUS_LINE_COMMAND_SETTINGS: () => DEFAULT_STATUS_LINE_COMMAND_SETTINGS,
49
+ EXIT_COMMAND_DESCRIPTION: () => EXIT_COMMAND_DESCRIPTION,
42
50
  EditCheckpointStore: () => EditCheckpointStore,
51
+ HELP_COMMAND_DESCRIPTION: () => HELP_COMMAND_DESCRIPTION,
43
52
  InteractiveSession: () => InteractiveSession,
53
+ LANGUAGE_COMMAND_ARGUMENT_HINT: () => LANGUAGE_COMMAND_ARGUMENT_HINT,
54
+ LANGUAGE_COMMAND_DESCRIPTION: () => LANGUAGE_COMMAND_DESCRIPTION,
55
+ MEMORY_COMMAND_ARGUMENT_HINT: () => MEMORY_COMMAND_ARGUMENT_HINT,
56
+ MEMORY_COMMAND_DESCRIPTION: () => MEMORY_COMMAND_DESCRIPTION,
57
+ MEMORY_COMMAND_USAGE: () => MEMORY_COMMAND_USAGE,
44
58
  MEMORY_INDEX_MAX_BYTES: () => MEMORY_INDEX_MAX_BYTES,
45
59
  MEMORY_INDEX_MAX_LINES: () => MEMORY_INDEX_MAX_LINES,
60
+ MODEL_COMMAND_ARGUMENT_HINT: () => MODEL_COMMAND_ARGUMENT_HINT,
61
+ MODEL_COMMAND_DESCRIPTION: () => MODEL_COMMAND_DESCRIPTION,
46
62
  MarketplaceClient: () => MarketplaceClient,
63
+ PERMISSIONS_COMMAND_DESCRIPTION: () => PERMISSIONS_COMMAND_DESCRIPTION,
64
+ PERMISSION_MODE_ARGUMENT_HINT: () => PERMISSION_MODE_ARGUMENT_HINT,
65
+ PERMISSION_MODE_COMMAND_DESCRIPTION: () => PERMISSION_MODE_COMMAND_DESCRIPTION,
66
+ PLUGIN_COMMAND_ARGUMENT_HINT: () => PLUGIN_COMMAND_ARGUMENT_HINT,
67
+ PLUGIN_COMMAND_DESCRIPTION: () => PLUGIN_COMMAND_DESCRIPTION,
47
68
  PluginCommandSource: () => PluginCommandSource,
48
69
  PluginSettingsStore: () => PluginSettingsStore,
49
70
  ProjectMemoryStore: () => ProjectMemoryStore,
50
71
  PromptExecutor: () => PromptExecutor,
72
+ RECOMMENDED_RESPONSE_LANGUAGES: () => RECOMMENDED_RESPONSE_LANGUAGES,
73
+ RELOAD_PLUGINS_COMMAND_DESCRIPTION: () => RELOAD_PLUGINS_COMMAND_DESCRIPTION,
74
+ RENAME_COMMAND_DESCRIPTION: () => RENAME_COMMAND_DESCRIPTION,
75
+ RENAME_COMMAND_USAGE: () => RENAME_COMMAND_USAGE,
76
+ RESUME_COMMAND_DESCRIPTION: () => RESUME_COMMAND_DESCRIPTION,
77
+ REWIND_COMMAND_ARGUMENT_HINT: () => REWIND_COMMAND_ARGUMENT_HINT,
78
+ REWIND_COMMAND_DESCRIPTION: () => REWIND_COMMAND_DESCRIPTION,
79
+ STATUSLINE_COMMAND_ARGUMENT_HINT: () => STATUSLINE_COMMAND_ARGUMENT_HINT,
80
+ STATUSLINE_COMMAND_DESCRIPTION: () => STATUSLINE_COMMAND_DESCRIPTION,
51
81
  SkillCommandSource: () => SkillCommandSource,
52
82
  SubagentManager: () => import_agent_runtime7.SubagentManager,
53
83
  SystemCommandExecutor: () => SystemCommandExecutor,
54
- TRUST_TO_MODE: () => import_agent_core5.TRUST_TO_MODE,
84
+ TRUST_TO_MODE: () => import_agent_core8.TRUST_TO_MODE,
85
+ VALID_PERMISSION_MODES: () => VALID_PERMISSION_MODES,
55
86
  WorktreeSubagentRunner: () => import_agent_runtime8.WorktreeSubagentRunner,
56
87
  assembleSubagentPrompt: () => assembleSubagentPrompt,
88
+ buildBackgroundCommandSubcommands: () => buildBackgroundCommandSubcommands,
89
+ buildLanguageCommandSubcommands: () => buildLanguageCommandSubcommands,
90
+ buildMemoryCommandSubcommands: () => buildMemoryCommandSubcommands,
91
+ buildModelCommandSubcommands: () => buildModelCommandSubcommands,
92
+ buildPermissionModeSubcommands: () => buildPermissionModeSubcommands,
93
+ buildPluginCommandSubcommands: () => buildPluginCommandSubcommands,
94
+ buildProviderProfile: () => buildProviderProfile,
95
+ buildProviderSetupPatch: () => buildProviderSetupPatch,
96
+ buildRewindCommandSubcommands: () => buildRewindCommandSubcommands,
57
97
  buildSkillPrompt: () => buildSkillPrompt,
58
- chatEntryToMessage: () => import_agent_core6.chatEntryToMessage,
98
+ buildStatusLineCommandSubcommands: () => buildStatusLineCommandSubcommands,
99
+ cancelCommandBackgroundTask: () => cancelCommandBackgroundTask,
100
+ chatEntryToMessage: () => import_agent_core9.chatEntryToMessage,
101
+ clearConversationHistory: () => clearConversationHistory,
102
+ closeCommandBackgroundTask: () => closeCommandBackgroundTask,
103
+ compactCommandContext: () => compactCommandContext,
59
104
  createAgentTool: () => createAgentTool,
60
105
  createBackgroundProcessTool: () => createBackgroundProcessTool,
106
+ createBuiltinCommandModule: () => createBuiltinCommandModule,
61
107
  createCommandExecutionTool: () => createCommandExecutionTool,
108
+ createCommandMemoryStores: () => createCommandMemoryStores,
109
+ createCommandPendingMemoryStore: () => createCommandPendingMemoryStore,
110
+ createCommandProjectMemoryStore: () => createCommandProjectMemoryStore,
62
111
  createDefaultTools: () => createDefaultTools,
112
+ createPluginRegistryReloadRequestedEffect: () => createPluginRegistryReloadRequestedEffect,
113
+ createPluginTuiRequestedEffect: () => createPluginTuiRequestedEffect,
114
+ createProviderSetupFlow: () => createProviderSetupFlow,
63
115
  createQuery: () => createQuery,
116
+ createSessionExitRequestedEffect: () => createSessionExitRequestedEffect,
117
+ createSessionPickerRequestedEffect: () => createSessionPickerRequestedEffect,
118
+ createSessionRenamedEffect: () => createSessionRenamedEffect,
64
119
  createSubagentLogger: () => createSubagentLogger,
65
120
  createSubagentSession: () => createSubagentSession,
66
121
  createSystemCommands: () => createSystemCommands,
67
122
  createWorktreeSubagentRunner: () => import_agent_runtime8.createWorktreeSubagentRunner,
68
123
  discoverTaskFiles: () => discoverTaskFiles,
69
- evaluatePermission: () => import_agent_core7.evaluatePermission,
124
+ evaluatePermission: () => import_agent_core10.evaluatePermission,
125
+ evaluateReversibleToolSafety: () => evaluateReversibleToolSafety,
70
126
  executeSkill: () => executeSkill,
127
+ formatCommandBackgroundTask: () => formatCommandBackgroundTask,
128
+ formatCommandBackgroundTaskList: () => formatCommandBackgroundTaskList,
129
+ formatCommandHelpMessage: () => formatCommandHelpMessage,
130
+ formatCommandPermissionsMessage: () => formatCommandPermissionsMessage,
131
+ formatEnvReference: () => formatEnvReference,
132
+ formatInvalidPermissionModeMessage: () => formatInvalidPermissionModeMessage,
133
+ formatLanguageUsageMessage: () => formatLanguageUsageMessage,
134
+ formatProviderSetupChoiceLabel: () => formatProviderSetupChoiceLabel,
135
+ formatProviderSetupPromptLabel: () => formatProviderSetupPromptLabel,
136
+ formatProviderSetupSelectionPrompt: () => formatProviderSetupSelectionPrompt,
71
137
  formatTaskContext: () => formatTaskContext,
72
138
  getBackgroundTaskTransitions: () => import_agent_runtime4.getBackgroundTaskTransitions,
73
139
  getBuiltInAgent: () => getBuiltInAgent,
74
140
  getForkWorkerSuffix: () => getForkWorkerSuffix,
75
- getMessagesForAPI: () => import_agent_core6.getMessagesForAPI,
141
+ getMessagesForAPI: () => import_agent_core9.getMessagesForAPI,
142
+ getProviderSetupStep: () => getProviderSetupStep,
76
143
  getSubagentSuffix: () => getSubagentSuffix,
77
- isChatEntry: () => import_agent_core6.isChatEntry,
144
+ hasSensitiveCommandMemoryContent: () => hasSensitiveCommandMemoryContent,
145
+ hasUsableSecretReference: () => hasUsableSecretReference,
146
+ inspectCommandEditCheckpoint: () => inspectCommandEditCheckpoint,
147
+ isChatEntry: () => import_agent_core9.isChatEntry,
148
+ isCommandMemoryType: () => isCommandMemoryType,
149
+ isEnvReference: () => isEnvReference,
78
150
  isMemoryType: () => isMemoryType,
151
+ isPermissionMode: () => isPermissionMode,
152
+ isStatusLineCommandSettingsPatch: () => isStatusLineCommandSettingsPatch,
79
153
  isTerminalBackgroundTaskStatus: () => import_agent_runtime4.isTerminalBackgroundTaskStatus,
154
+ listCommandBackgroundTasks: () => listCommandBackgroundTasks,
155
+ listCommandEditCheckpoints: () => listCommandEditCheckpoints,
156
+ listCommandSessionAllowedTools: () => listCommandSessionAllowedTools,
157
+ listCommandUsedMemoryReferences: () => listCommandUsedMemoryReferences,
80
158
  loadTaskContext: () => loadTaskContext,
81
- messageToHistoryEntry: () => import_agent_core6.messageToHistoryEntry,
159
+ mergeProviderPatch: () => mergeProviderPatch,
160
+ messageToHistoryEntry: () => import_agent_core9.messageToHistoryEntry,
161
+ parseCommandBackgroundLogCursor: () => parseCommandBackgroundLogCursor,
82
162
  parseFrontmatter: () => parseFrontmatter,
163
+ parseLanguageArgument: () => parseLanguageArgument,
164
+ parsePermissionModeArgument: () => parsePermissionModeArgument,
165
+ parseSessionNameArgument: () => parseSessionNameArgument,
83
166
  parseTaskFile: () => parseTaskFile,
84
167
  planSelfHostingVerification: () => planSelfHostingVerification,
85
168
  preprocessShellCommands: () => preprocessShellCommands,
169
+ probeProviderProfile: () => probeProviderProfile,
86
170
  projectPaths: () => projectPaths,
87
171
  promptForApproval: () => promptForApproval,
172
+ readAutoCompactThreshold: () => readAutoCompactThreshold,
173
+ readAutoCompactThresholdSource: () => readAutoCompactThresholdSource,
174
+ readCommandBackgroundTaskLog: () => readCommandBackgroundTaskLog,
175
+ readCommandContextState: () => readCommandContextState,
176
+ readCommandPermissionMode: () => readCommandPermissionMode,
177
+ readCommandPermissionsState: () => readCommandPermissionsState,
178
+ readCommandSessionInfo: () => readCommandSessionInfo,
88
179
  readCurrentGitBranch: () => readCurrentGitBranch,
180
+ recordCommandMemoryEvent: () => recordCommandMemoryEvent,
181
+ resetAutoCompactThresholdSetting: () => resetAutoCompactThresholdSetting,
182
+ resolveEnvReference: () => resolveEnvReference,
183
+ resolvePermissionModeAdapter: () => resolvePermissionModeAdapter,
184
+ resolvePluginCommandAdapter: () => resolvePluginCommandAdapter,
185
+ resolveProviderSetupSelection: () => resolveProviderSetupSelection,
89
186
  resolveSubagentLogDir: () => resolveSubagentLogDir,
187
+ restoreCommandEditCheckpoint: () => restoreCommandEditCheckpoint,
90
188
  retrieveAgentToolDeps: () => retrieveAgentToolDeps,
91
- runHooks: () => import_agent_core8.runHooks,
189
+ rollbackCommandEditCheckpoint: () => rollbackCommandEditCheckpoint,
190
+ runHooks: () => import_agent_core11.runHooks,
191
+ runProviderSetupPromptFlow: () => runProviderSetupPromptFlow,
92
192
  selectRelevantTasks: () => selectRelevantTasks,
193
+ setCommandAutoCompactThreshold: () => setCommandAutoCompactThreshold,
194
+ setCurrentProvider: () => setCurrentProvider,
93
195
  storeAgentToolDeps: () => storeAgentToolDeps,
196
+ submitProviderSetupValue: () => submitProviderSetupValue,
94
197
  substituteVariables: () => substituteVariables,
95
198
  summarizeBackgroundJobGroup: () => summarizeBackgroundJobGroup,
199
+ testProviderProfileCommand: () => testProviderProfileCommand,
96
200
  transitionBackgroundTaskStatus: () => import_agent_runtime4.transitionBackgroundTaskStatus,
97
201
  transitionSelfHostingLoop: () => transitionSelfHostingLoop,
98
202
  updateTaskFileStatus: () => updateTaskFileStatus,
203
+ upsertProviderProfile: () => upsertProviderProfile,
99
204
  userPaths: () => userPaths,
100
- wrapEditCheckpointTools: () => wrapEditCheckpointTools
205
+ validateProviderProfile: () => validateProviderProfile,
206
+ validateProviderSetupValue: () => validateProviderSetupValue,
207
+ wrapEditCheckpointTools: () => wrapEditCheckpointTools,
208
+ wrapReversibleExecutionTools: () => wrapReversibleExecutionTools,
209
+ writeAutoCompactThresholdSetting: () => writeAutoCompactThresholdSetting,
210
+ writeCommandPermissionMode: () => writeCommandPermissionMode
101
211
  });
102
212
  module.exports = __toCommonJS(index_exports);
103
213
 
104
214
  // src/interactive/interactive-session.ts
105
- var import_agent_core4 = require("@robota-sdk/agent-core");
215
+ var import_agent_core7 = require("@robota-sdk/agent-core");
106
216
 
107
217
  // src/commands/capability-descriptors.ts
108
218
  function inferKind(command) {
@@ -129,6 +239,12 @@ var CommandRegistry = class {
129
239
  addSource(source) {
130
240
  this.sources.push(source);
131
241
  }
242
+ replaceSource(name, source) {
243
+ this.sources = this.sources.filter((candidate) => candidate.name !== name);
244
+ if (source !== void 0) {
245
+ this.sources.push(source);
246
+ }
247
+ }
132
248
  addModule(module2) {
133
249
  for (const source of module2.commandSources ?? []) {
134
250
  this.addSource(source);
@@ -169,138 +285,222 @@ var CommandRegistry = class {
169
285
  }
170
286
  };
171
287
 
288
+ // src/commands/system-command-executor.ts
289
+ var SystemCommandExecutor = class {
290
+ commands;
291
+ constructor(commands) {
292
+ this.commands = /* @__PURE__ */ new Map();
293
+ for (const cmd of commands ?? createSystemCommands()) {
294
+ this.commands.set(cmd.name, cmd);
295
+ }
296
+ }
297
+ /** Register an additional command. */
298
+ register(command) {
299
+ this.commands.set(command.name, command);
300
+ }
301
+ /** Execute a command by name. Returns null if command not found. */
302
+ async execute(name, session, args) {
303
+ const cmd = this.getCommand(name);
304
+ if (!cmd) return null;
305
+ return await this.executeCommand(cmd, session, args);
306
+ }
307
+ getCommand(name) {
308
+ return this.commands.get(name);
309
+ }
310
+ async executeCommand(command, session, args) {
311
+ return await command.execute(session, args);
312
+ }
313
+ /** List all registered commands. */
314
+ listCommands() {
315
+ return [...this.commands.values()];
316
+ }
317
+ listModelInvocableCommands() {
318
+ return this.listCommands().filter((command) => command.modelInvocable === true).map((command) => ({
319
+ name: `/${command.name}`,
320
+ kind: "builtin-command",
321
+ description: command.description,
322
+ userInvocable: command.userInvocable !== false,
323
+ modelInvocable: true,
324
+ ...command.argumentHint ? { argumentHint: command.argumentHint } : {},
325
+ ...command.safety ? { safety: command.safety } : {}
326
+ }));
327
+ }
328
+ isModelInvocable(name) {
329
+ return this.commands.get(name)?.modelInvocable === true;
330
+ }
331
+ async executeModelInvocable(name, session, args) {
332
+ if (!this.isModelInvocable(name)) return null;
333
+ return this.execute(name, session, args);
334
+ }
335
+ /** Check if a command exists. */
336
+ hasCommand(name) {
337
+ return this.commands.has(name);
338
+ }
339
+ };
340
+
341
+ // src/commands/system-command.ts
342
+ function createSystemCommands() {
343
+ return [];
344
+ }
345
+
172
346
  // src/commands/builtin-source.ts
347
+ function commandToPaletteEntry(command) {
348
+ return {
349
+ name: command.name,
350
+ description: command.description,
351
+ source: "builtin",
352
+ ...command.subcommands ? { subcommands: [...command.subcommands] } : {},
353
+ ...command.argumentHint ? { argumentHint: command.argumentHint } : {},
354
+ ...command.modelInvocable !== void 0 ? { modelInvocable: command.modelInvocable } : {},
355
+ ...command.userInvocable !== void 0 ? { userInvocable: command.userInvocable } : {},
356
+ ...command.safety ? { safety: command.safety } : {}
357
+ };
358
+ }
359
+ var BuiltinCommandSource = class {
360
+ name = "builtin";
361
+ commands;
362
+ constructor(systemCommands = createSystemCommands()) {
363
+ this.commands = systemCommands.map(commandToPaletteEntry);
364
+ }
365
+ getCommands() {
366
+ return this.commands;
367
+ }
368
+ };
369
+ function createBuiltinCommandModule() {
370
+ const systemCommands = createSystemCommands();
371
+ return {
372
+ name: "sdk-builtin",
373
+ commandSources: [new BuiltinCommandSource(systemCommands)],
374
+ systemCommands
375
+ };
376
+ }
377
+
378
+ // src/command-api/provider/provider-command-probe.ts
379
+ var import_agent_core2 = require("@robota-sdk/agent-core");
380
+
381
+ // src/command-api/provider/provider-settings.ts
173
382
  var import_agent_core = require("@robota-sdk/agent-core");
174
- function buildModelSubcommands() {
175
- const seen = /* @__PURE__ */ new Set();
176
- const commands = [];
177
- for (const model of Object.values(import_agent_core.CLAUDE_MODELS)) {
178
- if (seen.has(model.name)) continue;
179
- seen.add(model.name);
180
- commands.push({
181
- name: model.id,
182
- description: `${model.name} (${(0, import_agent_core.formatTokenCount)(model.contextWindow).toUpperCase()})`,
183
- source: "builtin"
184
- });
383
+
384
+ // src/command-api/provider/provider-env-ref.ts
385
+ var ENV_REFERENCE_PREFIX = "$ENV:";
386
+ function isEnvReference(value) {
387
+ return value.startsWith(ENV_REFERENCE_PREFIX);
388
+ }
389
+ function formatEnvReference(name) {
390
+ return `${ENV_REFERENCE_PREFIX}${name}`;
391
+ }
392
+ function resolveEnvReference(value) {
393
+ if (!isEnvReference(value)) {
394
+ return value;
185
395
  }
186
- return commands;
396
+ const envName = value.slice(ENV_REFERENCE_PREFIX.length).trim();
397
+ if (envName.length === 0) {
398
+ return void 0;
399
+ }
400
+ return process.env[envName];
187
401
  }
188
- function buildProviderSubcommands() {
189
- return [
190
- { name: "current", description: "Show current provider", source: "builtin" },
191
- { name: "list", description: "List provider profiles", source: "builtin" },
192
- { name: "use", description: "Switch provider profile", source: "builtin" },
193
- { name: "test", description: "Test provider profile", source: "builtin" }
194
- ];
402
+ function hasUsableSecretReference(value) {
403
+ if (value === void 0 || value.length === 0) {
404
+ return false;
405
+ }
406
+ return resolveEnvReference(value) !== void 0;
195
407
  }
196
- function buildBackgroundSubcommands() {
197
- return [
198
- { name: "list", description: "List background tasks", source: "builtin" },
199
- { name: "read", description: "Read a background task log page", source: "builtin" },
200
- { name: "cancel", description: "Cancel a running background task", source: "builtin" },
201
- { name: "close", description: "Dismiss a terminal background task", source: "builtin" }
202
- ];
408
+
409
+ // src/command-api/provider/provider-settings.ts
410
+ function upsertProviderProfile(settings, profileName, profile) {
411
+ return {
412
+ ...settings,
413
+ providers: {
414
+ ...settings.providers ?? {},
415
+ [profileName]: profile
416
+ }
417
+ };
203
418
  }
204
- function buildRewindSubcommands() {
205
- return [
206
- { name: "list", description: "List edit checkpoints", source: "builtin" },
207
- { name: "restore", description: "Restore code to a checkpoint", source: "builtin" },
208
- { name: "code", description: "Restore code to a checkpoint", source: "builtin" }
209
- ];
419
+ function setCurrentProvider(settings, profileName) {
420
+ if (!settings.providers?.[profileName]) {
421
+ throw new Error(`Provider profile "${profileName}" was not found`);
422
+ }
423
+ return {
424
+ ...settings,
425
+ currentProvider: profileName
426
+ };
210
427
  }
211
- function buildMemorySubcommands() {
212
- return [
213
- { name: "list", description: "List project memory topics", source: "builtin" },
214
- { name: "show", description: "Show project memory index or a topic", source: "builtin" },
215
- { name: "add", description: "Save durable project memory", source: "builtin" },
216
- { name: "pending", description: "List pending memory candidates", source: "builtin" },
217
- { name: "approve", description: "Approve a pending memory candidate", source: "builtin" },
218
- { name: "reject", description: "Reject a pending memory candidate", source: "builtin" },
219
- {
220
- name: "used",
221
- description: "Show memory references used in the current turn",
222
- source: "builtin"
428
+ function validateProviderProfile(profileName, profile, options = {}) {
429
+ if (!profile.type) {
430
+ throw new Error(`Provider profile "${profileName}" is missing type`);
431
+ }
432
+ if (!profile.model) {
433
+ throw new Error(`Provider profile "${profileName}" is missing model`);
434
+ }
435
+ const definition = (0, import_agent_core.findProviderDefinition)(options.providerDefinitions ?? [], profile.type);
436
+ if (definition?.requiresApiKey === true && !hasUsableSecretReference(profile.apiKey ?? definition.defaults?.apiKey)) {
437
+ throw new Error(`Provider profile "${profileName}" is missing apiKey`);
438
+ }
439
+ }
440
+ function buildProviderSetupPatch(input, options = {}) {
441
+ const profile = buildProviderProfile(input, options);
442
+ validateProviderProfile(input.profile, profile, options);
443
+ return {
444
+ ...input.setCurrent && { currentProvider: input.profile },
445
+ providers: {
446
+ [input.profile]: profile
223
447
  }
224
- ];
448
+ };
225
449
  }
226
- function createBuiltinCommands() {
227
- return [
228
- { name: "help", description: "Show available commands", source: "builtin" },
229
- { name: "clear", description: "Clear conversation history", source: "builtin" },
230
- {
231
- name: "mode",
232
- description: "Permission mode",
233
- source: "builtin",
234
- subcommands: [
235
- { name: "plan", description: "Plan only, no execution", source: "builtin" },
236
- { name: "default", description: "Ask before risky actions", source: "builtin" },
237
- { name: "acceptEdits", description: "Auto-approve file edits", source: "builtin" },
238
- { name: "bypassPermissions", description: "Skip all permission checks", source: "builtin" }
239
- ]
240
- },
241
- {
242
- name: "model",
243
- description: "Select AI model",
244
- source: "builtin",
245
- subcommands: buildModelSubcommands()
246
- },
247
- {
248
- name: "language",
249
- description: "Set response language",
250
- source: "builtin",
251
- subcommands: [
252
- { name: "ko", description: "Korean", source: "builtin" },
253
- { name: "en", description: "English", source: "builtin" },
254
- { name: "ja", description: "Japanese", source: "builtin" },
255
- { name: "zh", description: "Chinese", source: "builtin" }
256
- ]
257
- },
258
- { name: "compact", description: "Compress context window", source: "builtin" },
259
- { name: "cost", description: "Show session info", source: "builtin" },
260
- { name: "context", description: "Context window info", source: "builtin" },
261
- { name: "permissions", description: "Permission rules", source: "builtin" },
262
- {
263
- name: "memory",
264
- description: "Inspect, save, review, and audit project memory",
265
- source: "builtin",
266
- subcommands: buildMemorySubcommands()
267
- },
268
- {
269
- name: "rewind",
270
- description: "List and restore edit checkpoints",
271
- source: "builtin",
272
- subcommands: buildRewindSubcommands()
273
- },
274
- {
275
- name: "provider",
276
- description: "Manage provider profiles",
277
- source: "builtin",
278
- subcommands: buildProviderSubcommands()
279
- },
280
- { name: "resume", description: "Resume a previous session", source: "builtin" },
281
- {
282
- name: "background",
283
- description: "List and control background tasks",
284
- source: "builtin",
285
- subcommands: buildBackgroundSubcommands()
286
- },
287
- { name: "rename", description: "Rename the current session", source: "builtin" },
288
- { name: "plugin", description: "Manage plugins", source: "builtin" },
289
- { name: "reload-plugins", description: "Reload all plugin resources", source: "builtin" },
290
- { name: "reset", description: "Delete settings and exit", source: "builtin" },
291
- { name: "exit", description: "Exit CLI", source: "builtin" }
292
- ];
450
+ function buildProviderProfile(input, options = {}) {
451
+ const defaults = getProviderDefaults(input.type, options.providerDefinitions ?? []);
452
+ const apiKey = input.apiKeyEnv !== void 0 ? formatEnvReference(input.apiKeyEnv) : input.apiKey ?? defaults.apiKey;
453
+ const baseURL = input.baseURL ?? defaults.baseURL;
454
+ return {
455
+ type: input.type,
456
+ model: input.model ?? defaults.model,
457
+ ...apiKey !== void 0 && { apiKey },
458
+ ...baseURL !== void 0 && { baseURL },
459
+ ...input.timeout !== void 0 && { timeout: input.timeout }
460
+ };
293
461
  }
294
- var BuiltinCommandSource = class {
295
- name = "builtin";
296
- commands;
297
- constructor() {
298
- this.commands = createBuiltinCommands();
462
+ function mergeProviderPatch(settings, patch) {
463
+ const [profileName, profile] = Object.entries(patch.providers)[0] ?? [];
464
+ if (!profileName || !profile) {
465
+ return settings;
299
466
  }
300
- getCommands() {
301
- return this.commands;
467
+ const withProfile = upsertProviderProfile(settings, profileName, profile);
468
+ return patch.currentProvider ? setCurrentProvider(withProfile, patch.currentProvider) : withProfile;
469
+ }
470
+ function getProviderDefaults(type, providerDefinitions) {
471
+ return (0, import_agent_core.findProviderDefinition)(providerDefinitions, type)?.defaults ?? {};
472
+ }
473
+
474
+ // src/command-api/provider/provider-command-probe.ts
475
+ async function testProviderProfileCommand(currentProvider, providers, profileArg, options) {
476
+ const profileName = profileArg ?? currentProvider;
477
+ if (!profileName) {
478
+ return { message: "No provider profile selected.", success: false };
302
479
  }
303
- };
480
+ const profile = providers?.[profileName];
481
+ if (!profile) {
482
+ return { message: `Provider profile "${profileName}" was not found.`, success: false };
483
+ }
484
+ try {
485
+ validateProviderProfile(profileName, profile, {
486
+ providerDefinitions: options.providerDefinitions
487
+ });
488
+ } catch (error) {
489
+ return { message: error instanceof Error ? error.message : String(error), success: false };
490
+ }
491
+ const definition = profile.type ? (0, import_agent_core2.findProviderDefinition)(options.providerDefinitions, profile.type) : void 0;
492
+ const probe = definition?.probeProfile ?? probeProviderProfile;
493
+ const result = await probe(profile);
494
+ return {
495
+ message: result.ok ? `Provider "${profileName}" test passed: ${result.message}` : `Provider "${profileName}" test failed: ${result.message}; manual configuration can continue.`,
496
+ success: true,
497
+ data: { providerTest: { profile: profileName } }
498
+ };
499
+ }
500
+ async function probeProviderProfile(profile) {
501
+ void profile;
502
+ return { ok: true, message: "Profile fields are valid; no endpoint probe configured." };
503
+ }
304
504
 
305
505
  // src/commands/skill-source.ts
306
506
  var import_node_fs = require("fs");
@@ -455,66 +655,523 @@ var PluginCommandSource = class {
455
655
  }
456
656
  };
457
657
 
458
- // src/commands/background-command.ts
658
+ // src/command-api/context/context-command-api.ts
659
+ var import_agent_sessions = require("@robota-sdk/agent-sessions");
660
+ var DEFAULT_AUTO_COMPACT_THRESHOLD = import_agent_sessions.AUTO_COMPACT_THRESHOLD;
661
+ var AUTO_COMPACT_THRESHOLD_SETTINGS_KEY = "autoCompactThreshold";
662
+ function readCommandContextState(context) {
663
+ return context.getContextState();
664
+ }
665
+ function readAutoCompactThreshold(context) {
666
+ return context.getAutoCompactThreshold();
667
+ }
668
+ function readAutoCompactThresholdSource(context) {
669
+ return context.getAutoCompactThresholdSource?.() ?? "session";
670
+ }
671
+ function setCommandAutoCompactThreshold(context, threshold, source) {
672
+ if (context.setAutoCompactThreshold) {
673
+ context.setAutoCompactThreshold(threshold, source);
674
+ return;
675
+ }
676
+ const session = context.getSession();
677
+ if (!session.setAutoCompactThreshold) {
678
+ throw new Error("Command host does not support changing auto-compact threshold.");
679
+ }
680
+ session.setAutoCompactThreshold(threshold);
681
+ }
682
+ function writeAutoCompactThresholdSetting(context, threshold) {
683
+ const settings = getSettingsAdapter(context);
684
+ if (!settings) return false;
685
+ settings.write({
686
+ ...settings.read(),
687
+ [AUTO_COMPACT_THRESHOLD_SETTINGS_KEY]: threshold
688
+ });
689
+ return true;
690
+ }
691
+ function resetAutoCompactThresholdSetting(context) {
692
+ const settings = getSettingsAdapter(context);
693
+ if (!settings) return false;
694
+ const next = { ...settings.read() };
695
+ delete next[AUTO_COMPACT_THRESHOLD_SETTINGS_KEY];
696
+ settings.write(next);
697
+ return true;
698
+ }
699
+ async function compactCommandContext(context, instructions) {
700
+ const before = readCommandContextState(context);
701
+ await context.compactContext(instructions);
702
+ const after = readCommandContextState(context);
703
+ return { before, after };
704
+ }
705
+ function getSettingsAdapter(context) {
706
+ return context.getCommandHostAdapters?.().settings;
707
+ }
708
+
709
+ // src/command-api/provider/provider-setup-flow.ts
710
+ var import_agent_core3 = require("@robota-sdk/agent-core");
711
+ function createProviderSetupFlow(type, providerDefinitions) {
712
+ return {
713
+ type,
714
+ steps: getProviderSetupSteps(type, providerDefinitions),
715
+ stepIndex: 0,
716
+ values: {}
717
+ };
718
+ }
719
+ function formatProviderSetupSelectionPrompt(providerDefinitions) {
720
+ if (providerDefinitions.length === 0) {
721
+ return " No providers are available.";
722
+ }
723
+ const lines = [
724
+ " Select provider:",
725
+ ...providerDefinitions.map(
726
+ (definition, index) => ` ${index + 1}. ${formatProviderSetupChoiceLabel(definition)}`
727
+ ),
728
+ ` Provider [1-${providerDefinitions.length}] (default: 1): `
729
+ ];
730
+ return lines.join("\n");
731
+ }
732
+ function resolveProviderSetupSelection(rawValue, providerDefinitions) {
733
+ const value = rawValue.trim();
734
+ const selectedValue = value.length > 0 ? value : "1";
735
+ const index = parseProviderSelectionIndex(selectedValue);
736
+ if (index !== void 0) {
737
+ const definition2 = providerDefinitions[index];
738
+ if (definition2 !== void 0) {
739
+ return definition2.type;
740
+ }
741
+ throw new Error(
742
+ `Provider selection ${selectedValue} is out of range. Currently supported: ${(0, import_agent_core3.formatSupportedProviderTypes)(providerDefinitions)}`
743
+ );
744
+ }
745
+ const definition = (0, import_agent_core3.findProviderDefinition)(providerDefinitions, selectedValue);
746
+ if (definition === void 0) {
747
+ throw new Error(
748
+ `Unknown provider: ${selectedValue}. Currently supported: ${(0, import_agent_core3.formatSupportedProviderTypes)(providerDefinitions)}`
749
+ );
750
+ }
751
+ return definition.type;
752
+ }
753
+ function getProviderSetupStep(state) {
754
+ const step = state.steps[state.stepIndex];
755
+ if (step === void 0) {
756
+ throw new Error(`Provider setup step ${state.stepIndex} is out of range`);
757
+ }
758
+ return step;
759
+ }
760
+ function submitProviderSetupValue(state, rawValue) {
761
+ const step = getProviderSetupStep(state);
762
+ const value = rawValue.trim() || step.defaultValue || "";
763
+ const validationMessage = validateProviderSetupValue(step, value);
764
+ if (validationMessage !== void 0) {
765
+ return { status: "error", state, message: validationMessage };
766
+ }
767
+ const nextState = {
768
+ ...state,
769
+ stepIndex: state.stepIndex + 1,
770
+ values: { ...state.values, [step.key]: value }
771
+ };
772
+ if (nextState.stepIndex < state.steps.length) {
773
+ return { status: "next", state: nextState };
774
+ }
775
+ return { status: "complete", input: buildProviderSetupInput(nextState) };
776
+ }
777
+ async function runProviderSetupPromptFlow(type, promptInput, providerDefinitions) {
778
+ let state = createProviderSetupFlow(type, providerDefinitions);
779
+ const stepCount = state.steps.length;
780
+ while (state.stepIndex < stepCount) {
781
+ const step = getProviderSetupStep(state);
782
+ const value = await promptInput(formatProviderSetupPromptLabel(step), step.masked === true);
783
+ const result = submitProviderSetupValue(state, value);
784
+ if (result.status === "complete") {
785
+ return result.input;
786
+ }
787
+ if (result.status === "error") {
788
+ throw new Error(result.message);
789
+ }
790
+ state = result.state;
791
+ }
792
+ throw new Error("Provider setup flow ended without completion");
793
+ }
794
+ function formatProviderSetupPromptLabel(step) {
795
+ const suffix = step.defaultValue !== void 0 ? ` (default: ${step.defaultValue})` : "";
796
+ return ` ${step.title}${suffix}: `;
797
+ }
798
+ function formatProviderSetupChoiceLabel(definition) {
799
+ const label = definition.displayName !== void 0 ? `${definition.displayName} (${definition.type})` : definition.type;
800
+ return definition.description !== void 0 ? `${label} - ${definition.description}` : label;
801
+ }
802
+ function parseProviderSelectionIndex(value) {
803
+ if (!/^\d+$/.test(value)) {
804
+ return void 0;
805
+ }
806
+ return Number(value) - 1;
807
+ }
808
+ function validateProviderSetupValue(step, value) {
809
+ if (step.required === true && value.length === 0) {
810
+ return "Required";
811
+ }
812
+ return void 0;
813
+ }
814
+ function getProviderSetupSteps(type, providerDefinitions) {
815
+ const definition = (0, import_agent_core3.findProviderDefinition)(providerDefinitions, type);
816
+ if (definition === void 0) {
817
+ throw new Error(
818
+ `Unknown provider: ${type}. Currently supported: ${(0, import_agent_core3.formatSupportedProviderTypes)(providerDefinitions)}`
819
+ );
820
+ }
821
+ if (definition.setupSteps !== void 0) {
822
+ return [...definition.setupSteps];
823
+ }
824
+ const steps = [
825
+ {
826
+ key: "model",
827
+ title: `${definition.type} model`,
828
+ defaultValue: definition.defaults?.model,
829
+ required: definition.defaults?.model === void 0
830
+ }
831
+ ];
832
+ if (definition.defaults?.baseURL !== void 0) {
833
+ steps.unshift({
834
+ key: "baseURL",
835
+ title: `${definition.type} base URL`,
836
+ defaultValue: definition.defaults.baseURL
837
+ });
838
+ }
839
+ if (definition.requiresApiKey === true) {
840
+ steps.push({
841
+ key: "apiKey",
842
+ title: `${definition.type} API key`,
843
+ defaultValue: definition.defaults?.apiKey,
844
+ required: definition.defaults?.apiKey === void 0,
845
+ masked: true
846
+ });
847
+ }
848
+ return steps;
849
+ }
850
+ function buildProviderSetupInput(state) {
851
+ return {
852
+ profile: state.type,
853
+ type: state.type,
854
+ model: state.values.model,
855
+ apiKey: state.values.apiKey,
856
+ ...state.values.baseURL !== void 0 && { baseURL: state.values.baseURL },
857
+ setCurrent: true
858
+ };
859
+ }
860
+
861
+ // src/command-api/help/help-command-api.ts
862
+ var HELP_COMMAND_DESCRIPTION = "Show available commands";
863
+ var HELP_COMMAND_NAME_COLUMN_WIDTH = 16;
864
+ function readCommandList(context) {
865
+ return context.listCommands?.() ?? [];
866
+ }
867
+ function formatCommandHelpMessage(context) {
868
+ const commands = readCommandList(context);
869
+ return [
870
+ "Available commands:",
871
+ ...commands.map(
872
+ (command) => ` ${command.name.padEnd(HELP_COMMAND_NAME_COLUMN_WIDTH)} \u2014 ${command.description}`
873
+ )
874
+ ].join("\n");
875
+ }
876
+
877
+ // src/command-api/background/background-command-api.ts
459
878
  var DECIMAL_RADIX = 10;
460
- function parseCommandParts(args) {
461
- return args.trim().split(/\s+/).filter(Boolean);
879
+ var INLINE_METADATA_LIMIT = 160;
880
+ var BACKGROUND_COMMAND_DESCRIPTION = "List and control background tasks";
881
+ var BACKGROUND_COMMAND_USAGE = "Usage: background list | background read <task-id> [offset] | background cancel <task-id> | background close <task-id>";
882
+ function buildBackgroundCommandSubcommands() {
883
+ return [
884
+ { name: "list", description: "List background tasks", source: "background" },
885
+ { name: "read", description: "Read a background task log page", source: "background" },
886
+ { name: "cancel", description: "Cancel a running background task", source: "background" },
887
+ { name: "close", description: "Dismiss a terminal background task", source: "background" }
888
+ ];
462
889
  }
463
- function formatBackgroundTask(task) {
890
+ function formatCommandBackgroundTask(task) {
464
891
  const preview = task.promptPreview ?? task.commandPreview ?? "";
465
892
  const unread = task.unread ? " unread" : "";
466
893
  const action = task.currentAction ? ` (${task.currentAction})` : "";
467
894
  const timeout = task.timeoutReason ? ` timeout=${task.timeoutReason}` : "";
468
895
  const activity = task.lastActivityAt ? ` lastActivityAt=${task.lastActivityAt}` : "";
896
+ const worktree = formatWorktreeMetadata(task);
469
897
  const suffix = preview ? ` \u2014 ${preview}` : "";
470
- return `${task.id} [${task.status}${unread}${timeout}${activity}] ${task.kind}:${task.label}${action}${suffix}`;
898
+ return `${task.id} [${task.status}${unread}${timeout}${activity}${worktree}] ${task.kind}:${task.label}${action}${suffix}`;
471
899
  }
472
- function formatBackgroundTaskList(tasks) {
900
+ function formatCommandBackgroundTaskList(tasks) {
473
901
  if (tasks.length === 0) return "No background tasks.";
474
- return ["Background tasks:", ...tasks.map((task) => ` ${formatBackgroundTask(task)}`)].join(
475
- "\n"
476
- );
902
+ return [
903
+ "Background tasks:",
904
+ ...tasks.map((task) => ` ${formatCommandBackgroundTask(task)}`)
905
+ ].join("\n");
477
906
  }
478
- function parseCursor(value) {
907
+ function parseCommandBackgroundLogCursor(value) {
479
908
  if (!value) return void 0;
480
909
  const offset = Number.parseInt(value, DECIMAL_RADIX);
481
910
  return Number.isNaN(offset) ? void 0 : { offset };
482
911
  }
483
- async function executeBackgroundCommand(session, args) {
484
- const [action = "list", taskId, ...reasonParts] = parseCommandParts(args);
485
- if (action === "list") {
486
- const tasks = session.listBackgroundTasks();
487
- return {
488
- message: formatBackgroundTaskList(tasks),
489
- success: true,
490
- data: { count: tasks.length }
491
- };
912
+ function formatWorktreeMetadata(task) {
913
+ const segments = [];
914
+ if (task.worktreePath) segments.push(`worktree=${task.worktreePath}`);
915
+ if (task.branchName) segments.push(`branch=${task.branchName}`);
916
+ if (task.worktreeStatus) {
917
+ segments.push(`worktreeStatus="${formatInlineMetadata(task.worktreeStatus)}"`);
492
918
  }
493
- if (!taskId) {
494
- return {
495
- message: "Usage: background list | background read <task-id> [offset] | background cancel <task-id> | background close <task-id>",
496
- success: false
497
- };
919
+ if (task.worktreeNextAction) {
920
+ segments.push(`next="${formatInlineMetadata(task.worktreeNextAction)}"`);
498
921
  }
499
- if (action === "read" || action === "log" || action === "open") {
500
- const page = await session.readBackgroundTaskLog(taskId, parseCursor(reasonParts[0]));
501
- const next = page.nextCursor ? `
502
- Next offset: ${page.nextCursor.offset}` : "";
503
- return {
504
- message: page.lines.length > 0 ? `${page.lines.join("\n")}${next}` : `No log lines: ${taskId}`,
505
- success: true,
506
- data: { taskId, nextOffset: page.nextCursor?.offset }
507
- };
922
+ if (segments.length === 0) return "";
923
+ return ` ${segments.join(" ")}`;
924
+ }
925
+ function formatInlineMetadata(value) {
926
+ const normalized = value.trim().replace(/\s+/g, " ");
927
+ return normalized.length > INLINE_METADATA_LIMIT ? `${normalized.slice(0, INLINE_METADATA_LIMIT)}...` : normalized;
928
+ }
929
+ function listCommandBackgroundTasks(context, filter) {
930
+ return context.listBackgroundTasks(filter);
931
+ }
932
+ function readCommandBackgroundTaskLog(context, taskId, cursor) {
933
+ return context.readBackgroundTaskLog(taskId, cursor);
934
+ }
935
+ function cancelCommandBackgroundTask(context, taskId, reason) {
936
+ return context.cancelBackgroundTask(taskId, reason);
937
+ }
938
+ function closeCommandBackgroundTask(context, taskId) {
939
+ return context.closeBackgroundTask(taskId);
940
+ }
941
+
942
+ // src/command-api/model/model-command-api.ts
943
+ var import_agent_core4 = require("@robota-sdk/agent-core");
944
+ var MODEL_COMMAND_DESCRIPTION = "Change AI model";
945
+ var MODEL_COMMAND_ARGUMENT_HINT = "<model-id>";
946
+ function buildModelCommandSubcommands(source = "model") {
947
+ const seen = /* @__PURE__ */ new Set();
948
+ const commands = [];
949
+ for (const model of Object.values(import_agent_core4.CLAUDE_MODELS)) {
950
+ if (seen.has(model.name)) continue;
951
+ seen.add(model.name);
952
+ commands.push({
953
+ name: model.id,
954
+ description: `${model.name} (${(0, import_agent_core4.formatTokenCount)(model.contextWindow).toUpperCase()})`,
955
+ source
956
+ });
508
957
  }
509
- if (action === "cancel" || action === "stop") {
510
- await session.cancelBackgroundTask(taskId, reasonParts.join(" ") || void 0);
511
- return { message: `Background task cancelled: ${taskId}`, success: true, data: { taskId } };
958
+ return commands;
959
+ }
960
+
961
+ // src/command-api/language/language-command-api.ts
962
+ var LANGUAGE_COMMAND_DESCRIPTION = "Set response language";
963
+ var LANGUAGE_COMMAND_ARGUMENT_HINT = "<code>";
964
+ var RECOMMENDED_RESPONSE_LANGUAGES = [
965
+ { code: "ko", description: "Korean" },
966
+ { code: "en", description: "English" },
967
+ { code: "ja", description: "Japanese" },
968
+ { code: "zh", description: "Chinese" }
969
+ ];
970
+ function buildLanguageCommandSubcommands(source = "language") {
971
+ return RECOMMENDED_RESPONSE_LANGUAGES.map((language) => ({
972
+ name: language.code,
973
+ description: language.description,
974
+ source
975
+ }));
976
+ }
977
+ function parseLanguageArgument(args) {
978
+ const language = args.trim().split(/\s+/)[0];
979
+ return language !== void 0 && language.length > 0 ? language : void 0;
980
+ }
981
+ function formatLanguageUsageMessage(commandName = "language") {
982
+ return `Usage: ${commandName} <code> (e.g., ko, en, ja, zh)`;
983
+ }
984
+
985
+ // src/command-api/permissions/permission-mode-command-api.ts
986
+ var PERMISSION_MODE_COMMAND_DESCRIPTION = "Show/change permission mode";
987
+ var PERMISSION_MODE_ARGUMENT_HINT = "plan | default | acceptEdits | bypassPermissions";
988
+ var PERMISSIONS_COMMAND_DESCRIPTION = "Show permission rules";
989
+ var VALID_PERMISSION_MODES = [
990
+ "plan",
991
+ "default",
992
+ "acceptEdits",
993
+ "bypassPermissions"
994
+ ];
995
+ function buildPermissionModeSubcommands(source = "mode") {
996
+ return [
997
+ { name: "plan", description: "Plan only, no execution", source },
998
+ { name: "default", description: "Ask before risky actions", source },
999
+ { name: "acceptEdits", description: "Auto-approve file edits", source },
1000
+ { name: "bypassPermissions", description: "Skip all permission checks", source }
1001
+ ];
1002
+ }
1003
+ function parsePermissionModeArgument(args) {
1004
+ const mode = args.trim().split(/\s+/)[0];
1005
+ return mode !== void 0 && mode.length > 0 ? mode : void 0;
1006
+ }
1007
+ function isPermissionMode(value) {
1008
+ return VALID_PERMISSION_MODES.includes(value);
1009
+ }
1010
+ function formatInvalidPermissionModeMessage() {
1011
+ return `Invalid mode. Valid: ${VALID_PERMISSION_MODES.join(" | ")}`;
1012
+ }
1013
+ function resolvePermissionModeAdapter(context) {
1014
+ const adapter = context.getCommandHostAdapters?.().permissionMode;
1015
+ if (adapter !== void 0) {
1016
+ return adapter;
512
1017
  }
513
- if (action === "close" || action === "dismiss") {
514
- await session.closeBackgroundTask(taskId);
515
- return { message: `Background task closed: ${taskId}`, success: true, data: { taskId } };
1018
+ const runtime = context.getSession();
1019
+ return {
1020
+ getPermissionMode: () => runtime.getPermissionMode(),
1021
+ setPermissionMode: (mode) => runtime.setPermissionMode(mode),
1022
+ listSessionAllowedTools: () => runtime.getSessionAllowedTools()
1023
+ };
1024
+ }
1025
+ function readCommandPermissionMode(context) {
1026
+ return resolvePermissionModeAdapter(context).getPermissionMode();
1027
+ }
1028
+ function writeCommandPermissionMode(context, mode) {
1029
+ resolvePermissionModeAdapter(context).setPermissionMode(mode);
1030
+ }
1031
+ function listCommandSessionAllowedTools(context) {
1032
+ return resolvePermissionModeAdapter(context).listSessionAllowedTools();
1033
+ }
1034
+ function readCommandPermissionsState(context) {
1035
+ return {
1036
+ mode: readCommandPermissionMode(context),
1037
+ sessionAllowed: listCommandSessionAllowedTools(context)
1038
+ };
1039
+ }
1040
+ function formatCommandPermissionsMessage(state) {
1041
+ const lines = [`Permission mode: ${state.mode}`];
1042
+ if (state.sessionAllowed.length > 0) {
1043
+ lines.push(`Session-approved tools: ${state.sessionAllowed.join(", ")}`);
1044
+ } else {
1045
+ lines.push("No session-approved tools.");
516
1046
  }
517
- return { message: `Unknown background action: ${action}`, success: false };
1047
+ return lines.join("\n");
1048
+ }
1049
+
1050
+ // src/command-api/statusline/statusline-command-api.ts
1051
+ var STATUSLINE_COMMAND_DESCRIPTION = "Configure TUI status-line visibility and fields such as model, context, tokens, session, and git branch.";
1052
+ var STATUSLINE_COMMAND_ARGUMENT_HINT = "on | off | reset | git on | git off";
1053
+ var DEFAULT_STATUS_LINE_COMMAND_SETTINGS = {
1054
+ enabled: true,
1055
+ gitBranch: true
1056
+ };
1057
+ function buildStatusLineCommandSubcommands(source = "statusline") {
1058
+ return [
1059
+ { name: "on", description: "Show the status line", source },
1060
+ { name: "off", description: "Hide the status line", source },
1061
+ { name: "reset", description: "Restore default status-line fields", source },
1062
+ { name: "git", description: "Show or hide git branch field", source }
1063
+ ];
1064
+ }
1065
+ function isStatusLineCommandSettingsPatch(value) {
1066
+ return (value.enabled === void 0 || typeof value.enabled === "boolean") && (value.gitBranch === void 0 || typeof value.gitBranch === "boolean");
1067
+ }
1068
+
1069
+ // src/command-api/plugin/plugin-command-api.ts
1070
+ var PLUGIN_COMMAND_DESCRIPTION = "Manage plugins";
1071
+ var PLUGIN_COMMAND_ARGUMENT_HINT = "manage | install <name@marketplace> | uninstall <name@marketplace> | enable <name@marketplace> | disable <name@marketplace> | marketplace <action>";
1072
+ var RELOAD_PLUGINS_COMMAND_DESCRIPTION = "Reload all plugin resources";
1073
+ function createPluginTuiRequestedEffect() {
1074
+ return { type: "plugin-tui-requested" };
1075
+ }
1076
+ function createPluginRegistryReloadRequestedEffect() {
1077
+ return { type: "plugin-registry-reload-requested" };
1078
+ }
1079
+ function resolvePluginCommandAdapter(context) {
1080
+ return context.getCommandHostAdapters?.().plugin;
1081
+ }
1082
+ function buildPluginCommandSubcommands() {
1083
+ return [
1084
+ { name: "manage", description: "Open plugin manager", source: "plugin-manager" },
1085
+ { name: "install", description: "Install a plugin", source: "plugin-manager" },
1086
+ { name: "uninstall", description: "Uninstall a plugin", source: "plugin-manager" },
1087
+ { name: "enable", description: "Enable a plugin", source: "plugin-manager" },
1088
+ { name: "disable", description: "Disable a plugin", source: "plugin-manager" },
1089
+ {
1090
+ name: "marketplace",
1091
+ description: "Manage plugin marketplaces",
1092
+ source: "plugin-manager",
1093
+ subcommands: [
1094
+ { name: "add", description: "Add marketplace source", source: "plugin-manager" },
1095
+ { name: "remove", description: "Remove marketplace source", source: "plugin-manager" },
1096
+ { name: "update", description: "Update marketplace source", source: "plugin-manager" },
1097
+ { name: "list", description: "List marketplace sources", source: "plugin-manager" }
1098
+ ]
1099
+ }
1100
+ ];
1101
+ }
1102
+
1103
+ // src/command-api/session/session-command-api.ts
1104
+ var CLEAR_COMMAND_DESCRIPTION = "Clear conversation history";
1105
+ var RENAME_COMMAND_DESCRIPTION = "Rename the current session";
1106
+ var RENAME_COMMAND_USAGE = "Usage: rename <name>";
1107
+ var RESUME_COMMAND_DESCRIPTION = "Resume a previous session";
1108
+ var COST_COMMAND_DESCRIPTION = "Show session info";
1109
+ var EXIT_COMMAND_DESCRIPTION = "Exit CLI";
1110
+ function clearConversationHistory(context) {
1111
+ if (context.clearConversationHistory !== void 0) {
1112
+ context.clearConversationHistory();
1113
+ return;
1114
+ }
1115
+ context.getSession().clearHistory();
1116
+ }
1117
+ function parseSessionNameArgument(args) {
1118
+ const name = args.trim();
1119
+ return name.length > 0 ? name : void 0;
1120
+ }
1121
+ function createSessionRenamedEffect(name) {
1122
+ return { type: "session-renamed", name };
1123
+ }
1124
+ function createSessionPickerRequestedEffect() {
1125
+ return { type: "session-picker-requested" };
1126
+ }
1127
+ function createSessionExitRequestedEffect() {
1128
+ return { type: "session-exit-requested" };
1129
+ }
1130
+ function readCommandSessionInfo(context) {
1131
+ const session = context.getSession();
1132
+ return {
1133
+ sessionId: session.getSessionId(),
1134
+ messageCount: session.getMessageCount()
1135
+ };
1136
+ }
1137
+
1138
+ // src/command-api/checkpoint/rewind-command-api.ts
1139
+ var REWIND_COMMAND_DESCRIPTION = "List, inspect, restore, or rollback edit checkpoints.";
1140
+ var REWIND_COMMAND_ARGUMENT_HINT = "list | inspect CHECKPOINT_ID | restore CHECKPOINT_ID | code CHECKPOINT_ID | rollback CHECKPOINT_ID";
1141
+ function buildRewindCommandSubcommands(source = "rewind") {
1142
+ return [
1143
+ { name: "list", description: "List edit checkpoints", source },
1144
+ { name: "inspect", description: "Inspect captured files and restore plans", source },
1145
+ { name: "restore", description: "Restore code to a checkpoint", source },
1146
+ { name: "code", description: "Restore code to a checkpoint", source },
1147
+ { name: "rollback", description: "Rollback code through a checkpoint", source }
1148
+ ];
1149
+ }
1150
+ function listCommandEditCheckpoints(context) {
1151
+ return context.listEditCheckpoints();
1152
+ }
1153
+ function inspectCommandEditCheckpoint(context, checkpointId) {
1154
+ if (!context.inspectEditCheckpoint) {
1155
+ throw new Error("Checkpoint inspection is not available in this command host.");
1156
+ }
1157
+ return context.inspectEditCheckpoint(checkpointId);
1158
+ }
1159
+ function restoreCommandEditCheckpoint(context, checkpointId) {
1160
+ return context.restoreEditCheckpoint(checkpointId);
1161
+ }
1162
+ function rollbackCommandEditCheckpoint(context, checkpointId) {
1163
+ return context.rollbackEditCheckpoint(checkpointId);
1164
+ }
1165
+
1166
+ // src/memory/memory-policy-evaluator.ts
1167
+ var SENSITIVE_PATTERNS = [
1168
+ /\b(api[_-]?key|secret|token|password|private key)\b/i,
1169
+ /\b\d{3}-\d{2}-\d{4}\b/,
1170
+ /\b\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}\b/,
1171
+ /주민등록|비밀번호|시크릿|토큰/u
1172
+ ];
1173
+ function containsSensitiveMemoryContent(text) {
1174
+ return SENSITIVE_PATTERNS.some((pattern) => pattern.test(text));
518
1175
  }
519
1176
 
520
1177
  // src/memory/pending-memory-store.ts
@@ -642,595 +1299,118 @@ var ProjectMemoryStore = class {
642
1299
  }
643
1300
  getIndexPath() {
644
1301
  return (0, import_path.join)(memoryRoot2(this.cwd), INDEX_FILENAME);
645
- }
646
- getTopicsPath() {
647
- return (0, import_path.join)(memoryRoot2(this.cwd), TOPICS_DIRNAME);
648
- }
649
- loadStartupMemory() {
650
- const path = this.getIndexPath();
651
- if (!(0, import_fs.existsSync)(path)) {
652
- return { content: "", path, lineCount: 0, truncated: false };
653
- }
654
- const raw = (0, import_fs.readFileSync)(path, "utf8");
655
- const byBytes = truncateToUtf8Bytes(raw, MEMORY_INDEX_MAX_BYTES);
656
- const byteTruncated = Buffer.byteLength(raw, "utf8") > MEMORY_INDEX_MAX_BYTES;
657
- const byLines = limitLines(byBytes, MEMORY_INDEX_MAX_LINES);
658
- return {
659
- content: byLines.content,
660
- path,
661
- lineCount: byLines.content.length === 0 ? 0 : byLines.content.split(/\r?\n/).length,
662
- truncated: byteTruncated || byLines.truncated
663
- };
664
- }
665
- list() {
666
- const topicsPath = this.getTopicsPath();
667
- const topics = (0, import_fs.existsSync)(topicsPath) ? (0, import_fs.readdirSync)(topicsPath, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(TOPIC_EXTENSION)).map((entry) => ({
668
- name: (0, import_path.basename)(entry.name, TOPIC_EXTENSION),
669
- path: (0, import_path.join)(topicsPath, entry.name)
670
- })).sort((a, b) => a.name.localeCompare(b.name)) : [];
671
- return {
672
- indexPath: this.getIndexPath(),
673
- topicsPath,
674
- topics
675
- };
676
- }
677
- readTopic(topic) {
678
- const normalized = sanitizeTopic(topic);
679
- const path = (0, import_path.join)(this.getTopicsPath(), `${normalized}${TOPIC_EXTENSION}`);
680
- if (!(0, import_fs.existsSync)(path)) return "";
681
- return (0, import_fs.readFileSync)(path, "utf8").trimEnd();
682
- }
683
- append(input) {
684
- const topic = sanitizeTopic(input.topic);
685
- const root = memoryRoot2(this.cwd);
686
- const topicsPath = this.getTopicsPath();
687
- (0, import_fs.mkdirSync)(topicsPath, { recursive: true });
688
- const indexPath = this.getIndexPath();
689
- const topicPath = (0, import_path.join)(topicsPath, `${topic}${TOPIC_EXTENSION}`);
690
- const entry = formatEntry(this.now(), input, topic);
691
- const topicHeader = (0, import_fs.existsSync)(topicPath) ? "" : `# ${topic}
692
-
693
- `;
694
- const normalizedText = normalizeMemoryText(input.text);
695
- if ((0, import_fs.existsSync)(topicPath) && (0, import_fs.readFileSync)(topicPath, "utf8").includes(`) ${normalizedText}`)) {
696
- return { indexPath, topicPath, topic, deduplicated: true };
697
- }
698
- if (!(0, import_fs.existsSync)(indexPath)) {
699
- (0, import_fs.mkdirSync)(root, { recursive: true });
700
- (0, import_fs.writeFileSync)(indexPath, "# Project Memory\n\n", "utf8");
701
- }
702
- (0, import_fs.appendFileSync)(indexPath, `- ${entry}
703
- `, "utf8");
704
- (0, import_fs.appendFileSync)(topicPath, `${topicHeader}- ${entry}
705
- `, "utf8");
706
- return { indexPath, topicPath, topic, deduplicated: false };
707
- }
708
- };
709
-
710
- // src/memory/memory-policy-evaluator.ts
711
- var SENSITIVE_PATTERNS = [
712
- /\b(api[_-]?key|secret|token|password|private key)\b/i,
713
- /\b\d{3}-\d{2}-\d{4}\b/,
714
- /\b\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}\b/,
715
- /주민등록|비밀번호|시크릿|토큰/u
716
- ];
717
- function containsSensitiveMemoryContent(text) {
718
- return SENSITIVE_PATTERNS.some((pattern) => pattern.test(text));
719
- }
720
-
721
- // src/commands/memory-command.ts
722
- var SUBCOMMAND_INDEX = 0;
723
- var TYPE_INDEX = 1;
724
- var TOPIC_INDEX = 2;
725
- var TEXT_START_INDEX = 3;
726
- function usage() {
727
- return {
728
- message: "Usage: memory list | memory show [topic] | memory add <user|feedback|project|reference> <topic> <text> | memory pending | memory approve <id> | memory reject <id> | memory used",
729
- success: false
730
- };
731
- }
732
- function formatList(store) {
733
- const summary = store.list();
734
- const topics = summary.topics.length > 0 ? summary.topics.map((topic) => `- ${topic.name}: ${topic.path}`).join("\n") : "(none)";
735
- return {
736
- message: [
737
- `Memory index: ${summary.indexPath}`,
738
- `Topics directory: ${summary.topicsPath}`,
739
- "Topics:",
740
- topics
741
- ].join("\n"),
742
- success: true,
743
- data: {
744
- indexPath: summary.indexPath,
745
- topicsPath: summary.topicsPath,
746
- topicCount: summary.topics.length
747
- }
748
- };
749
- }
750
- function formatShow(store, topic) {
751
- if (!topic || topic === "index") {
752
- const memory = store.loadStartupMemory();
753
- return {
754
- message: memory.content || "(empty memory index)",
755
- success: true,
756
- data: {
757
- path: memory.path,
758
- lineCount: memory.lineCount,
759
- truncated: memory.truncated
760
- }
761
- };
762
- }
763
- const content = store.readTopic(topic);
764
- return {
765
- message: content || `(empty memory topic: ${topic})`,
766
- success: true,
767
- data: { topic }
768
- };
769
- }
770
- function parseAdd(args) {
771
- const type = args[TYPE_INDEX];
772
- const topic = args[TOPIC_INDEX];
773
- const text = args.slice(TEXT_START_INDEX).join(" ").trim();
774
- if (!type || !isMemoryType(type) || !topic || text.length === 0) return void 0;
775
- return { type, topic, text };
776
- }
777
- function formatPending(store) {
778
- const records = store.list("pending");
779
- const lines = records.length > 0 ? records.map(
780
- (record) => `- ${record.id} ${record.type}/${record.topic} confidence=${record.confidence}: ${record.text}`
781
- ) : ["(no pending memory candidates)"];
782
- return {
783
- message: ["Pending memory candidates:", ...lines].join("\n"),
784
- success: true,
785
- data: { count: records.length }
786
- };
787
- }
788
- function recordEvent(session, event) {
789
- session.recordMemoryEvent({
790
- ...event,
791
- at: (/* @__PURE__ */ new Date()).toISOString()
792
- });
793
- }
794
- function approvePending(session, pendingStore, memoryStore, id) {
795
- if (!id) return usage();
796
- try {
797
- const approved = pendingStore.mark(id, "approved", "approved-by-user");
798
- const saved = memoryStore.append(approved);
799
- const record = pendingStore.mark(id, "saved", "approved-and-saved");
800
- recordEvent(session, {
801
- type: "memory_candidate_approved",
802
- candidateId: record.id,
803
- topic: record.topic,
804
- reason: "approved-by-user"
805
- });
806
- recordEvent(session, {
807
- type: "memory_candidate_saved",
808
- candidateId: record.id,
809
- topic: record.topic,
810
- reason: saved.deduplicated ? "deduplicated" : "approved-and-saved"
811
- });
812
- return {
813
- message: saved.deduplicated ? `Saved memory candidate ${id} was already present in ${saved.topicPath}` : `Saved memory candidate ${id} to ${saved.topicPath}`,
814
- success: true,
815
- data: {
816
- id,
817
- status: record.status,
818
- topic: saved.topic,
819
- topicPath: saved.topicPath,
820
- deduplicated: saved.deduplicated
821
- }
822
- };
823
- } catch (error) {
824
- return {
825
- message: error instanceof Error ? error.message : String(error),
826
- success: false
827
- };
828
- }
829
- }
830
- function rejectPending(session, pendingStore, id) {
831
- if (!id) return usage();
832
- try {
833
- const record = pendingStore.mark(id, "rejected", "rejected-by-user");
834
- recordEvent(session, {
835
- type: "memory_candidate_rejected",
836
- candidateId: record.id,
837
- topic: record.topic,
838
- reason: "rejected-by-user"
839
- });
840
- return {
841
- message: `Rejected memory candidate ${id}`,
842
- success: true,
843
- data: { id, status: record.status }
844
- };
845
- } catch (error) {
846
- return {
847
- message: error instanceof Error ? error.message : String(error),
848
- success: false
849
- };
850
- }
851
- }
852
- function formatUsed(session) {
853
- const references = session.getUsedMemoryReferences();
854
- const lines = references.length > 0 ? references.map((reference) => {
855
- const suffix = reference.truncated ? " truncated=true" : "";
856
- return `- ${reference.topic} score=${reference.score}${suffix}: ${reference.path}`;
857
- }) : ["(no memory used in current turn)"];
858
- return {
859
- message: ["Used memory references:", ...lines].join("\n"),
860
- success: true,
861
- data: { count: references.length, references }
862
- };
863
- }
864
- function executeMemoryCommand(session, rawArgs) {
865
- const args = rawArgs.trim().split(/\s+/).filter(Boolean);
866
- const subcommand = args[SUBCOMMAND_INDEX] ?? "list";
867
- const store = new ProjectMemoryStore(session.getCwd());
868
- const pendingStore = new PendingMemoryStore(session.getCwd());
869
- if (subcommand === "list") return formatList(store);
870
- if (subcommand === "show") return formatShow(store, args[TYPE_INDEX]);
871
- if (subcommand === "pending") return formatPending(pendingStore);
872
- if (subcommand === "approve")
873
- return approvePending(session, pendingStore, store, args[TYPE_INDEX]);
874
- if (subcommand === "reject") return rejectPending(session, pendingStore, args[TYPE_INDEX]);
875
- if (subcommand === "used") return formatUsed(session);
876
- if (subcommand === "add") {
877
- const input = parseAdd(args);
878
- if (!input) return usage();
879
- if (containsSensitiveMemoryContent(input.text)) {
880
- return {
881
- message: "Refusing to save sensitive memory content.",
882
- success: false
883
- };
1302
+ }
1303
+ getTopicsPath() {
1304
+ return (0, import_path.join)(memoryRoot2(this.cwd), TOPICS_DIRNAME);
1305
+ }
1306
+ loadStartupMemory() {
1307
+ const path = this.getIndexPath();
1308
+ if (!(0, import_fs.existsSync)(path)) {
1309
+ return { content: "", path, lineCount: 0, truncated: false };
884
1310
  }
885
- const result = store.append(input);
1311
+ const raw = (0, import_fs.readFileSync)(path, "utf8");
1312
+ const byBytes = truncateToUtf8Bytes(raw, MEMORY_INDEX_MAX_BYTES);
1313
+ const byteTruncated = Buffer.byteLength(raw, "utf8") > MEMORY_INDEX_MAX_BYTES;
1314
+ const byLines = limitLines(byBytes, MEMORY_INDEX_MAX_LINES);
886
1315
  return {
887
- message: result.deduplicated ? `${input.type} memory already exists in ${result.topicPath}` : `Saved ${input.type} memory to ${result.topicPath}`,
888
- success: true,
889
- data: {
890
- indexPath: result.indexPath,
891
- topicPath: result.topicPath,
892
- topic: result.topic,
893
- deduplicated: result.deduplicated
894
- }
1316
+ content: byLines.content,
1317
+ path,
1318
+ lineCount: byLines.content.length === 0 ? 0 : byLines.content.split(/\r?\n/).length,
1319
+ truncated: byteTruncated || byLines.truncated
895
1320
  };
896
1321
  }
897
- return usage();
898
- }
899
-
900
- // src/commands/rewind-command.ts
901
- var SUBCOMMAND_INDEX2 = 0;
902
- var CHECKPOINT_ID_INDEX = 1;
903
- var PROMPT_PREVIEW_LENGTH = 120;
904
- var ELLIPSIS_LENGTH = 3;
905
- function usage2() {
906
- return {
907
- message: "Usage: rewind [list] | rewind restore <checkpoint-id> | rewind code <checkpoint-id>",
908
- success: false
909
- };
910
- }
911
- function formatPrompt(prompt) {
912
- const compact = prompt.replace(/\s+/g, " ").trim();
913
- if (compact.length <= PROMPT_PREVIEW_LENGTH) return compact;
914
- return `${compact.slice(0, PROMPT_PREVIEW_LENGTH - ELLIPSIS_LENGTH)}...`;
915
- }
916
- function formatList2(checkpoints) {
917
- const lines = checkpoints.length > 0 ? checkpoints.map(
918
- (checkpoint) => `- ${checkpoint.id} files=${checkpoint.fileCount} ${checkpoint.createdAt} ${formatPrompt(
919
- checkpoint.prompt
920
- )}`
921
- ) : ["(no edit checkpoints)"];
922
- return {
923
- message: ["Edit checkpoints:", ...lines].join("\n"),
924
- success: true,
925
- data: { count: checkpoints.length, checkpoints: [...checkpoints] }
926
- };
927
- }
928
- async function restore(session, checkpointId) {
929
- if (!checkpointId) return usage2();
930
- try {
931
- const result = await session.restoreEditCheckpoint(checkpointId);
932
- return {
933
- message: [
934
- `Restored code to ${result.target.id}.`,
935
- `Restored files: ${result.restoredFileCount}`,
936
- `Rolled back checkpoints: ${result.restoredCheckpointCount}`
937
- ].join("\n"),
938
- success: true,
939
- data: {
940
- target: result.target,
941
- restoredCheckpointCount: result.restoredCheckpointCount,
942
- restoredFileCount: result.restoredFileCount,
943
- removedCheckpointCount: result.removedCheckpointCount
944
- }
945
- };
946
- } catch (error) {
1322
+ list() {
1323
+ const topicsPath = this.getTopicsPath();
1324
+ const topics = (0, import_fs.existsSync)(topicsPath) ? (0, import_fs.readdirSync)(topicsPath, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(TOPIC_EXTENSION)).map((entry) => ({
1325
+ name: (0, import_path.basename)(entry.name, TOPIC_EXTENSION),
1326
+ path: (0, import_path.join)(topicsPath, entry.name)
1327
+ })).sort((a, b) => a.name.localeCompare(b.name)) : [];
947
1328
  return {
948
- message: error instanceof Error ? error.message : String(error),
949
- success: false
1329
+ indexPath: this.getIndexPath(),
1330
+ topicsPath,
1331
+ topics
950
1332
  };
951
1333
  }
952
- }
953
- async function executeRewindCommand(session, rawArgs) {
954
- const args = rawArgs.trim().split(/\s+/).filter(Boolean);
955
- const subcommand = args[SUBCOMMAND_INDEX2] ?? "list";
956
- if (subcommand === "list") {
957
- return formatList2(session.listEditCheckpoints());
958
- }
959
- if (subcommand === "restore" || subcommand === "code") {
960
- return restore(session, args[CHECKPOINT_ID_INDEX]);
1334
+ readTopic(topic) {
1335
+ const normalized = sanitizeTopic(topic);
1336
+ const path = (0, import_path.join)(this.getTopicsPath(), `${normalized}${TOPIC_EXTENSION}`);
1337
+ if (!(0, import_fs.existsSync)(path)) return "";
1338
+ return (0, import_fs.readFileSync)(path, "utf8").trimEnd();
961
1339
  }
962
- return usage2();
963
- }
1340
+ append(input) {
1341
+ const topic = sanitizeTopic(input.topic);
1342
+ const root = memoryRoot2(this.cwd);
1343
+ const topicsPath = this.getTopicsPath();
1344
+ (0, import_fs.mkdirSync)(topicsPath, { recursive: true });
1345
+ const indexPath = this.getIndexPath();
1346
+ const topicPath = (0, import_path.join)(topicsPath, `${topic}${TOPIC_EXTENSION}`);
1347
+ const entry = formatEntry(this.now(), input, topic);
1348
+ const topicHeader = (0, import_fs.existsSync)(topicPath) ? "" : `# ${topic}
964
1349
 
965
- // src/commands/system-command-executor.ts
966
- var SystemCommandExecutor = class {
967
- commands;
968
- constructor(commands) {
969
- this.commands = /* @__PURE__ */ new Map();
970
- for (const cmd of commands ?? createSystemCommands()) {
971
- this.commands.set(cmd.name, cmd);
1350
+ `;
1351
+ const normalizedText = normalizeMemoryText(input.text);
1352
+ if ((0, import_fs.existsSync)(topicPath) && (0, import_fs.readFileSync)(topicPath, "utf8").includes(`) ${normalizedText}`)) {
1353
+ return { indexPath, topicPath, topic, deduplicated: true };
972
1354
  }
973
- }
974
- /** Register an additional command. */
975
- register(command) {
976
- this.commands.set(command.name, command);
977
- }
978
- /** Execute a command by name. Returns null if command not found. */
979
- async execute(name, session, args) {
980
- const cmd = this.commands.get(name);
981
- if (!cmd) return null;
982
- return await cmd.execute(session, args);
983
- }
984
- /** List all registered commands. */
985
- listCommands() {
986
- return [...this.commands.values()];
987
- }
988
- listModelInvocableCommands() {
989
- return this.listCommands().filter((command) => command.modelInvocable === true).map((command) => ({
990
- name: `/${command.name}`,
991
- kind: "builtin-command",
992
- description: command.description,
993
- userInvocable: command.userInvocable !== false,
994
- modelInvocable: true,
995
- ...command.argumentHint ? { argumentHint: command.argumentHint } : {},
996
- ...command.safety ? { safety: command.safety } : {}
997
- }));
998
- }
999
- isModelInvocable(name) {
1000
- return this.commands.get(name)?.modelInvocable === true;
1001
- }
1002
- async executeModelInvocable(name, session, args) {
1003
- if (!this.isModelInvocable(name)) return null;
1004
- return this.execute(name, session, args);
1005
- }
1006
- /** Check if a command exists. */
1007
- hasCommand(name) {
1008
- return this.commands.has(name);
1355
+ if (!(0, import_fs.existsSync)(indexPath)) {
1356
+ (0, import_fs.mkdirSync)(root, { recursive: true });
1357
+ (0, import_fs.writeFileSync)(indexPath, "# Project Memory\n\n", "utf8");
1358
+ }
1359
+ (0, import_fs.appendFileSync)(indexPath, `- ${entry}
1360
+ `, "utf8");
1361
+ (0, import_fs.appendFileSync)(topicPath, `${topicHeader}- ${entry}
1362
+ `, "utf8");
1363
+ return { indexPath, topicPath, topic, deduplicated: false };
1009
1364
  }
1010
1365
  };
1011
1366
 
1012
- // src/commands/system-command.ts
1013
- var VALID_MODES = ["plan", "default", "acceptEdits", "bypassPermissions"];
1367
+ // src/command-api/memory/memory-command-api.ts
1014
1368
  var MEMORY_COMMAND_DESCRIPTION = "Project memory command. Use it to inspect project memory when stored context may help, save durable preferences, project conventions, feedback, or references worth reusing across sessions, review pending candidates, and report memory provenance. Do not store secrets, credentials, or transient facts.";
1015
1369
  var MEMORY_COMMAND_ARGUMENT_HINT = "list | show [topic] | add <user|feedback|project|reference> <topic> <text> | pending | approve <id> | reject <id> | used";
1016
- function createSystemCommands() {
1370
+ var MEMORY_COMMAND_USAGE = "Usage: memory list | memory show [topic] | memory add <user|feedback|project|reference> <topic> <text> | memory pending | memory approve <id> | memory reject <id> | memory used";
1371
+ function buildMemoryCommandSubcommands(source = "memory") {
1017
1372
  return [
1373
+ { name: "list", description: "List project memory topics", source },
1374
+ { name: "show", description: "Show project memory index or a topic", source },
1375
+ { name: "add", description: "Save durable project memory", source },
1376
+ { name: "pending", description: "List pending memory candidates", source },
1377
+ { name: "approve", description: "Approve a pending memory candidate", source },
1378
+ { name: "reject", description: "Reject a pending memory candidate", source },
1018
1379
  {
1019
- name: "help",
1020
- description: "Show available commands",
1021
- execute: (_session, _args) => ({
1022
- message: [
1023
- "Available commands:",
1024
- " help \u2014 Show this help",
1025
- " clear \u2014 Clear conversation",
1026
- " compact [instr] \u2014 Compact context (optional focus instructions)",
1027
- " mode [m] \u2014 Show/change permission mode",
1028
- " model <id> \u2014 Change AI model",
1029
- " language <code> \u2014 Set response language (ko, en, ja, zh)",
1030
- " cost \u2014 Show session info",
1031
- " context \u2014 Context window info",
1032
- " permissions \u2014 Permission rules",
1033
- " memory \u2014 Manage project memory and pending candidates",
1034
- " rewind \u2014 List or restore edit checkpoints",
1035
- " provider \u2014 Provider profile status and switching",
1036
- " resume \u2014 Resume a previous session",
1037
- " background \u2014 List/cancel/close background tasks",
1038
- " rename <name> \u2014 Rename the current session",
1039
- " reset \u2014 Delete settings and exit"
1040
- ].join("\n"),
1041
- success: true
1042
- })
1043
- },
1044
- {
1045
- name: "clear",
1046
- description: "Clear conversation history",
1047
- execute: (session, _args) => {
1048
- const underlying = session.getSession();
1049
- underlying.clearHistory();
1050
- return { message: "Conversation cleared.", success: true };
1051
- }
1052
- },
1053
- {
1054
- name: "compact",
1055
- description: "Compress context window",
1056
- execute: async (session, args) => {
1057
- const underlying = session.getSession();
1058
- const instructions = args.trim() || void 0;
1059
- const before = underlying.getContextState().usedPercentage;
1060
- await underlying.compact(instructions);
1061
- const after = underlying.getContextState().usedPercentage;
1062
- return {
1063
- message: `Context compacted: ${Math.round(before)}% -> ${Math.round(after)}%`,
1064
- success: true,
1065
- data: { before, after }
1066
- };
1067
- }
1068
- },
1069
- {
1070
- name: "mode",
1071
- description: "Show/change permission mode",
1072
- execute: (session, args) => {
1073
- const underlying = session.getSession();
1074
- const arg = args.trim().split(/\s+/)[0];
1075
- if (!arg) {
1076
- return {
1077
- message: `Current mode: ${underlying.getPermissionMode()}`,
1078
- success: true,
1079
- data: { mode: underlying.getPermissionMode() }
1080
- };
1081
- }
1082
- if (VALID_MODES.includes(arg)) {
1083
- underlying.setPermissionMode(arg);
1084
- return {
1085
- message: `Permission mode set to: ${arg}`,
1086
- success: true,
1087
- data: { mode: arg }
1088
- };
1089
- }
1090
- return {
1091
- message: `Invalid mode. Valid: ${VALID_MODES.join(" | ")}`,
1092
- success: false
1093
- };
1094
- }
1095
- },
1096
- {
1097
- name: "model",
1098
- description: "Change AI model",
1099
- execute: (_session, args) => {
1100
- const modelId = args.trim().split(/\s+/)[0];
1101
- if (!modelId) {
1102
- return { message: "Usage: model <model-id>", success: false };
1103
- }
1104
- return {
1105
- message: `Model change requested: ${modelId}`,
1106
- success: true,
1107
- data: { modelId }
1108
- };
1109
- }
1110
- },
1111
- {
1112
- name: "language",
1113
- description: "Set response language",
1114
- execute: (_session, args) => {
1115
- const lang = args.trim().split(/\s+/)[0];
1116
- if (!lang) {
1117
- return { message: "Usage: language <code> (e.g., ko, en, ja, zh)", success: false };
1118
- }
1119
- return {
1120
- message: `Language set to "${lang}".`,
1121
- success: true,
1122
- data: { language: lang }
1123
- };
1124
- }
1125
- },
1126
- {
1127
- name: "cost",
1128
- description: "Show session info",
1129
- execute: (session, _args) => {
1130
- const underlying = session.getSession();
1131
- const sessionId = underlying.getSessionId();
1132
- const messageCount = underlying.getMessageCount();
1133
- return {
1134
- message: `Session: ${sessionId}
1135
- Messages: ${messageCount}`,
1136
- success: true,
1137
- data: { sessionId, messageCount }
1138
- };
1139
- }
1140
- },
1141
- {
1142
- name: "context",
1143
- description: "Context window info",
1144
- execute: (session, _args) => {
1145
- const ctx = session.getContextState();
1146
- return {
1147
- message: `Context: ${ctx.usedTokens.toLocaleString()} / ${ctx.maxTokens.toLocaleString()} tokens (${Math.round(ctx.usedPercentage)}%)`,
1148
- success: true,
1149
- data: {
1150
- usedTokens: ctx.usedTokens,
1151
- maxTokens: ctx.maxTokens,
1152
- percentage: ctx.usedPercentage
1153
- }
1154
- };
1155
- }
1156
- },
1157
- {
1158
- name: "permissions",
1159
- description: "Show permission rules",
1160
- execute: (session, _args) => {
1161
- const underlying = session.getSession();
1162
- const mode = underlying.getPermissionMode();
1163
- const sessionAllowed = underlying.getSessionAllowedTools();
1164
- const lines = [`Permission mode: ${mode}`];
1165
- if (sessionAllowed.length > 0) {
1166
- lines.push(`Session-approved tools: ${sessionAllowed.join(", ")}`);
1167
- } else {
1168
- lines.push("No session-approved tools.");
1169
- }
1170
- return {
1171
- message: lines.join("\n"),
1172
- success: true,
1173
- data: { mode, sessionAllowed }
1174
- };
1175
- }
1176
- },
1177
- {
1178
- name: "memory",
1179
- description: MEMORY_COMMAND_DESCRIPTION,
1180
- modelInvocable: true,
1181
- argumentHint: MEMORY_COMMAND_ARGUMENT_HINT,
1182
- safety: "write",
1183
- execute: executeMemoryCommand
1184
- },
1185
- {
1186
- name: "rewind",
1187
- description: "List edit checkpoints or restore code to a previous checkpoint.",
1188
- argumentHint: "list | restore CHECKPOINT_ID | code CHECKPOINT_ID",
1189
- safety: "write",
1190
- execute: executeRewindCommand
1191
- },
1192
- {
1193
- name: "resume",
1194
- description: "Resume a previous session",
1195
- execute: (_session, _args) => ({
1196
- message: "Opening session picker...",
1197
- success: true,
1198
- data: { triggerResumePicker: true }
1199
- })
1200
- },
1201
- {
1202
- name: "background",
1203
- description: "List and control background tasks",
1204
- execute: executeBackgroundCommand
1205
- },
1206
- {
1207
- name: "rename",
1208
- description: "Rename the current session",
1209
- execute: (_session, args) => {
1210
- const name = args.trim();
1211
- if (!name) {
1212
- return { message: "Usage: rename <name>", success: false };
1213
- }
1214
- return {
1215
- message: `Session renamed to "${name}".`,
1216
- success: true,
1217
- data: { name }
1218
- };
1219
- }
1220
- },
1221
- {
1222
- name: "reset",
1223
- description: "Delete settings",
1224
- execute: (_session, _args) => {
1225
- return {
1226
- message: "Reset requested.",
1227
- success: true,
1228
- data: { resetRequested: true }
1229
- };
1230
- }
1380
+ name: "used",
1381
+ description: "Show memory references used in the current turn",
1382
+ source
1231
1383
  }
1232
1384
  ];
1233
1385
  }
1386
+ function createCommandProjectMemoryStore(cwd, now) {
1387
+ return new ProjectMemoryStore(cwd, now);
1388
+ }
1389
+ function createCommandPendingMemoryStore(cwd, now) {
1390
+ return new PendingMemoryStore(cwd, now);
1391
+ }
1392
+ function createCommandMemoryStores(context, now) {
1393
+ const cwd = context.getCwd();
1394
+ return {
1395
+ project: createCommandProjectMemoryStore(cwd, now),
1396
+ pending: createCommandPendingMemoryStore(cwd, now)
1397
+ };
1398
+ }
1399
+ function isCommandMemoryType(value) {
1400
+ return isMemoryType(value);
1401
+ }
1402
+ function hasSensitiveCommandMemoryContent(text) {
1403
+ return containsSensitiveMemoryContent(text);
1404
+ }
1405
+ function listCommandUsedMemoryReferences(context) {
1406
+ return context.getUsedMemoryReferences();
1407
+ }
1408
+ function recordCommandMemoryEvent(context, event, now = () => /* @__PURE__ */ new Date()) {
1409
+ context.recordMemoryEvent({
1410
+ ...event,
1411
+ at: now().toISOString()
1412
+ });
1413
+ }
1234
1414
 
1235
1415
  // src/utils/skill-prompt.ts
1236
1416
  var import_node_child_process = require("child_process");
@@ -1330,7 +1510,7 @@ async function executeSkill(skill, args, callbacks, context) {
1330
1510
  }
1331
1511
 
1332
1512
  // src/assembly/create-subagent-session.ts
1333
- var import_agent_sessions = require("@robota-sdk/agent-sessions");
1513
+ var import_agent_sessions2 = require("@robota-sdk/agent-sessions");
1334
1514
 
1335
1515
  // src/assembly/subagent-prompts.ts
1336
1516
  function getSubagentSuffix() {
@@ -1394,7 +1574,7 @@ function createSubagentSession(options) {
1394
1574
  isForkWorker: options.isForkWorker ?? false
1395
1575
  });
1396
1576
  const provider = options.provider;
1397
- return new import_agent_sessions.Session({
1577
+ return new import_agent_sessions2.Session({
1398
1578
  tools,
1399
1579
  provider,
1400
1580
  systemMessage,
@@ -1561,15 +1741,149 @@ function createInProcessSubagentRunner(deps) {
1561
1741
  };
1562
1742
  }
1563
1743
 
1744
+ // src/tools/agent-tool-batch.ts
1745
+ function stringifyAgentBatchResult(input) {
1746
+ const successfulJobs = input.jobs.filter((job) => job.success);
1747
+ const agentIds = input.jobs.map((job) => job.agentId).filter((agentId) => typeof agentId === "string" && agentId.length > 0);
1748
+ const failedJobCount = input.jobs.filter((job) => !job.success).length;
1749
+ return JSON.stringify({
1750
+ success: input.jobs.every((job) => job.success),
1751
+ mode: "batch",
1752
+ output: successfulJobs.map((job) => job.output ?? "").filter(Boolean).join("\n\n"),
1753
+ groupId: input.groupId,
1754
+ requestedJobCount: input.requestedJobCount,
1755
+ startedJobCount: agentIds.length,
1756
+ failedJobCount,
1757
+ agentIds,
1758
+ jobs: input.jobs,
1759
+ provenance: {
1760
+ source: "agent-tool-batch",
1761
+ groupId: input.groupId,
1762
+ requestedJobCount: input.requestedJobCount,
1763
+ startedJobCount: agentIds.length,
1764
+ failedJobCount
1765
+ }
1766
+ });
1767
+ }
1768
+ function createBatchGroupId() {
1769
+ const idRadix = 36;
1770
+ const randomStartIndex = 2;
1771
+ const randomEndIndex = 10;
1772
+ return `agent_group_${Date.now()}_${Math.random().toString(idRadix).slice(randomStartIndex, randomEndIndex)}`;
1773
+ }
1774
+ function normalizeJobLabel(label, fallback) {
1775
+ const trimmed = label?.trim();
1776
+ return trimmed && trimmed.length > 0 ? trimmed : fallback;
1777
+ }
1778
+ function resolveBatchJob(job, index, input) {
1779
+ const agentType = job.subagent_type ?? "general-purpose";
1780
+ const agentDef = input.resolveAgentDefinition(agentType, input.deps.customAgentRegistry);
1781
+ const label = normalizeJobLabel(job.label, agentDef?.name ?? agentType);
1782
+ return { index, job, agentType, agentDef, label };
1783
+ }
1784
+ function isValidBatchJob(job) {
1785
+ return job.agentDef !== void 0;
1786
+ }
1787
+ function createUnknownAgentBatchResult(job, groupId) {
1788
+ return {
1789
+ index: job.index,
1790
+ success: false,
1791
+ groupId,
1792
+ label: job.label,
1793
+ subagent_type: job.agentType,
1794
+ prompt: job.job.prompt,
1795
+ error: `Unknown agent type: ${job.agentType}`
1796
+ };
1797
+ }
1798
+ async function spawnBatchJob(job, input) {
1799
+ try {
1800
+ const state = await input.manager.spawn(
1801
+ input.createSpawnRequest(job.job, job.agentType, job.agentDef, input.deps, job.label)
1802
+ );
1803
+ return { ...job, agentId: state.id };
1804
+ } catch (error) {
1805
+ const message = error instanceof Error ? error.message : String(error);
1806
+ return { ...job, spawnError: message };
1807
+ }
1808
+ }
1809
+ function createBatchSpawnErrorResult(job, groupId) {
1810
+ return {
1811
+ index: job.index,
1812
+ success: false,
1813
+ groupId,
1814
+ label: job.label,
1815
+ subagent_type: job.agentType,
1816
+ prompt: job.job.prompt,
1817
+ error: `Sub-agent error: ${job.spawnError ?? "missing agent id"}`
1818
+ };
1819
+ }
1820
+ function createBatchSuccessResult(job, groupId, result) {
1821
+ return {
1822
+ index: job.index,
1823
+ success: true,
1824
+ groupId,
1825
+ label: job.label,
1826
+ agentId: result.jobId,
1827
+ subagent_type: job.agentType,
1828
+ prompt: job.job.prompt,
1829
+ output: result.output,
1830
+ metadata: result.metadata
1831
+ };
1832
+ }
1833
+ function createBatchWaitErrorResult(job, groupId, message) {
1834
+ return {
1835
+ index: job.index,
1836
+ success: false,
1837
+ groupId,
1838
+ label: job.label,
1839
+ agentId: job.agentId,
1840
+ subagent_type: job.agentType,
1841
+ prompt: job.job.prompt,
1842
+ error: `Sub-agent error: ${message}`
1843
+ };
1844
+ }
1845
+ async function waitBatchJob(job, groupId, manager) {
1846
+ if (job.agentId === void 0) {
1847
+ return createBatchSpawnErrorResult(job, groupId);
1848
+ }
1849
+ try {
1850
+ const result = await manager.wait(job.agentId);
1851
+ return createBatchSuccessResult({ ...job, agentId: job.agentId }, groupId, result);
1852
+ } catch (error) {
1853
+ const message = error instanceof Error ? error.message : String(error);
1854
+ return createBatchWaitErrorResult({ ...job, agentId: job.agentId }, groupId, message);
1855
+ }
1856
+ }
1857
+ async function runManagedAgentBatch(input) {
1858
+ const groupId = createBatchGroupId();
1859
+ const resolvedJobs = input.jobs.map((job, index) => resolveBatchJob(job, index, input));
1860
+ const invalidJobs = resolvedJobs.filter((job) => !isValidBatchJob(job)).map((job) => createUnknownAgentBatchResult(job, groupId));
1861
+ const startedJobs = await Promise.all(
1862
+ resolvedJobs.filter(isValidBatchJob).map((job) => spawnBatchJob(job, input))
1863
+ );
1864
+ const terminalJobs = await Promise.all(
1865
+ startedJobs.map((job) => waitBatchJob(job, groupId, input.manager))
1866
+ );
1867
+ const batchJobs = [...invalidJobs, ...terminalJobs].sort(
1868
+ (left, right) => left.index - right.index
1869
+ );
1870
+ return stringifyAgentBatchResult({
1871
+ groupId,
1872
+ requestedJobCount: input.jobs.length,
1873
+ jobs: batchJobs
1874
+ });
1875
+ }
1876
+
1564
1877
  // src/tools/agent-tool.ts
1565
1878
  var AGENT_TOOL_DESCRIPTION = [
1566
1879
  "Creates delegated subagent jobs in isolated contexts.",
1567
1880
  "Without jobs, one tool call creates one subagent job from prompt.",
1568
- "For explicit multi-agent or parallel-agent requests, use one Agent tool call with jobs containing one entry per requested role.",
1881
+ "For explicit multi-agent or parallel-agent requests, use one Agent tool call with jobs containing one entry per requested role and a stable label for each role.",
1569
1882
  "When the user explicitly asks to create, run, spawn, delegate to, or use agents/subagents, start the requested subagent job immediately.",
1570
1883
  "Do not ask a follow-up question unless execution is impossible or unsafe.",
1571
1884
  "Subagent jobs run as background tasks by default.",
1572
- "The tool waits for a terminal result and returns completed, failed, or timed-out outcome data to the parent conversation.",
1885
+ "The tool waits for a terminal result and returns completed, failed, or timed-out outcome data with structured requested/started job counts.",
1886
+ "After the tool returns, base user-facing claims on returned mode and counts; do not say parallel or multiple jobs started unless the result proves those jobs started.",
1573
1887
  "Execution is represented by a real tool call and runtime background task event."
1574
1888
  ].join(" ");
1575
1889
  function createAgentToolPromptDescription(agentDefinitions = []) {
@@ -1577,10 +1891,11 @@ function createAgentToolPromptDescription(agentDefinitions = []) {
1577
1891
  return [
1578
1892
  "Agent \u2014 creates isolated subagent jobs.",
1579
1893
  "Without jobs, one Agent tool call corresponds to one subagent job.",
1580
- "For explicit multi-agent or parallel-agent requests, use one Agent tool call with jobs containing one entry per requested role.",
1894
+ "For explicit multi-agent or parallel-agent requests, use one Agent tool call with jobs containing one entry per requested role and a stable label for each role.",
1581
1895
  "When the user explicitly asks to create, run, spawn, delegate to, or use agents/subagents, start the requested subagent job immediately.",
1582
1896
  "Do not ask a follow-up question unless execution is impossible or unsafe.",
1583
- "The tool returns terminal result data.",
1897
+ "The tool returns terminal result data with mode, requestedJobCount, startedJobCount, failedJobCount, and provenance.",
1898
+ "After the tool returns, base user-facing claims on returned mode and counts; do not say parallel or multiple jobs started unless the result proves those jobs started.",
1584
1899
  "Runtime mode is background.",
1585
1900
  availableAgents
1586
1901
  ].join(" ").replace(/\s+/g, " ").trim();
@@ -1595,6 +1910,7 @@ var AgentSchema = import_zod.z.object({
1595
1910
  isolation: import_zod.z.enum(["none", "worktree"]).optional().describe('Optional runtime isolation mode. "worktree" runs in a Git worktree.'),
1596
1911
  jobs: import_zod.z.array(
1597
1912
  import_zod.z.object({
1913
+ label: import_zod.z.string().optional().describe("Stable role label for this batch job"),
1598
1914
  prompt: import_zod.z.string().describe("The task for this subagent to perform"),
1599
1915
  subagent_type: import_zod.z.string().optional().describe("Agent type for this job"),
1600
1916
  model: import_zod.z.string().optional().describe("Optional model override for this job"),
@@ -1623,10 +1939,10 @@ function createSubagentManager(deps) {
1623
1939
  runner: createInProcessSubagentRunner(deps)
1624
1940
  });
1625
1941
  }
1626
- function createSpawnRequest(args, agentType, agentDef, deps) {
1942
+ function createSpawnRequest(args, agentType, agentDef, deps, label = agentDef.name) {
1627
1943
  return {
1628
1944
  type: agentType,
1629
- label: agentDef.name,
1945
+ label,
1630
1946
  parentSessionId: deps.parentSessionId ?? "unknown-session",
1631
1947
  mode: "background",
1632
1948
  depth: deps.subagentDepth ?? 1,
@@ -1639,39 +1955,65 @@ function createSpawnRequest(args, agentType, agentDef, deps) {
1639
1955
  function stringifyUnknownAgentType(agentType) {
1640
1956
  return JSON.stringify({
1641
1957
  success: false,
1958
+ mode: "single",
1959
+ requestedJobCount: 1,
1960
+ startedJobCount: 0,
1961
+ failedJobCount: 1,
1642
1962
  output: "",
1643
- error: `Unknown agent type: ${agentType}`
1963
+ error: `Unknown agent type: ${agentType}`,
1964
+ provenance: {
1965
+ source: "agent-tool-single",
1966
+ requestedJobCount: 1,
1967
+ startedJobCount: 0,
1968
+ failedJobCount: 1
1969
+ }
1644
1970
  });
1645
1971
  }
1646
1972
  function stringifyAgentSuccess(result) {
1647
1973
  const worktreePath = result.metadata?.["worktreePath"];
1648
1974
  const branchName = result.metadata?.["branchName"];
1975
+ const worktreeStatus = result.metadata?.["worktreeStatus"];
1976
+ const worktreeNextAction = result.metadata?.["worktreeNextAction"];
1649
1977
  return JSON.stringify({
1650
1978
  success: true,
1979
+ mode: "single",
1980
+ requestedJobCount: 1,
1981
+ startedJobCount: 1,
1982
+ failedJobCount: 0,
1651
1983
  output: result.output,
1652
1984
  agentId: result.jobId,
1985
+ agentIds: [result.jobId],
1986
+ provenance: {
1987
+ source: "agent-tool-single",
1988
+ requestedJobCount: 1,
1989
+ startedJobCount: 1,
1990
+ failedJobCount: 0
1991
+ },
1653
1992
  metadata: result.metadata,
1654
1993
  ...typeof worktreePath === "string" ? { worktreePath } : {},
1655
- ...typeof branchName === "string" ? { branchName } : {}
1994
+ ...typeof branchName === "string" ? { branchName } : {},
1995
+ ...typeof worktreeStatus === "string" ? { worktreeStatus } : {},
1996
+ ...typeof worktreeNextAction === "string" ? { worktreeNextAction } : {}
1656
1997
  });
1657
1998
  }
1658
1999
  function stringifyAgentError(message, agentId) {
2000
+ const startedJobCount = agentId === void 0 ? 0 : 1;
1659
2001
  return JSON.stringify({
1660
2002
  success: false,
2003
+ mode: "single",
2004
+ requestedJobCount: 1,
2005
+ startedJobCount,
2006
+ failedJobCount: 1,
1661
2007
  output: "",
1662
2008
  error: `Sub-agent error: ${message}`,
1663
- agentId
1664
- });
1665
- }
1666
- function stringifyAgentBatchResult(input) {
1667
- const successfulJobs = input.jobs.filter((job) => job.success);
1668
- const agentIds = input.jobs.map((job) => job.agentId).filter((agentId) => typeof agentId === "string" && agentId.length > 0);
1669
- return JSON.stringify({
1670
- success: input.jobs.every((job) => job.success),
1671
- output: successfulJobs.map((job) => job.output ?? "").filter(Boolean).join("\n\n"),
1672
- groupId: input.groupId,
1673
- agentIds,
1674
- jobs: input.jobs
2009
+ agentId,
2010
+ ...agentId !== void 0 ? { agentIds: [agentId] } : {},
2011
+ provenance: {
2012
+ source: "agent-tool-single",
2013
+ requestedJobCount: 1,
2014
+ startedJobCount,
2015
+ failedJobCount: 1
2016
+ }
1675
2017
  });
1676
2018
  }
1677
2019
  async function runManagedAgent(args, deps, manager) {
@@ -1695,75 +2037,6 @@ async function runManagedAgent(args, deps, manager) {
1695
2037
  return stringifyAgentError(message, agentId);
1696
2038
  }
1697
2039
  }
1698
- function createBatchGroupId() {
1699
- return `agent_group_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
1700
- }
1701
- async function runManagedAgentBatch(jobs, deps, manager) {
1702
- const groupId = createBatchGroupId();
1703
- const resolvedJobs = jobs.map((job, index) => {
1704
- const agentType = job.subagent_type ?? "general-purpose";
1705
- const agentDef = resolveAgentDefinition2(agentType, deps.customAgentRegistry);
1706
- return { index, job, agentType, agentDef };
1707
- });
1708
- const invalidJobs = resolvedJobs.filter((job) => job.agentDef === void 0).map((job) => ({
1709
- index: job.index,
1710
- success: false,
1711
- subagent_type: job.agentType,
1712
- error: `Unknown agent type: ${job.agentType}`
1713
- }));
1714
- const validJobs = resolvedJobs.filter(
1715
- (job) => job.agentDef !== void 0
1716
- );
1717
- const startedJobs = await Promise.all(
1718
- validJobs.map(async (job) => {
1719
- try {
1720
- const state = await manager.spawn(
1721
- createSpawnRequest(job.job, job.agentType, job.agentDef, deps)
1722
- );
1723
- return { ...job, agentId: state.id, spawnError: void 0 };
1724
- } catch (error) {
1725
- const message = error instanceof Error ? error.message : String(error);
1726
- return { ...job, agentId: void 0, spawnError: message };
1727
- }
1728
- })
1729
- );
1730
- const terminalJobs = await Promise.all(
1731
- startedJobs.map(async (job) => {
1732
- if (job.spawnError || !job.agentId) {
1733
- return {
1734
- index: job.index,
1735
- success: false,
1736
- subagent_type: job.agentType,
1737
- error: `Sub-agent error: ${job.spawnError ?? "missing agent id"}`
1738
- };
1739
- }
1740
- try {
1741
- const result = await manager.wait(job.agentId);
1742
- return {
1743
- index: job.index,
1744
- success: true,
1745
- agentId: result.jobId,
1746
- subagent_type: job.agentType,
1747
- output: result.output,
1748
- metadata: result.metadata
1749
- };
1750
- } catch (error) {
1751
- const message = error instanceof Error ? error.message : String(error);
1752
- return {
1753
- index: job.index,
1754
- success: false,
1755
- agentId: job.agentId,
1756
- subagent_type: job.agentType,
1757
- error: `Sub-agent error: ${message}`
1758
- };
1759
- }
1760
- })
1761
- );
1762
- const batchJobs = [...invalidJobs, ...terminalJobs].sort(
1763
- (left, right) => left.index - right.index
1764
- );
1765
- return stringifyAgentBatchResult({ groupId, jobs: batchJobs });
1766
- }
1767
2040
  function createAgentTool(deps) {
1768
2041
  const manager = createSubagentManager(deps);
1769
2042
  return (0, import_agent_tools.createZodFunctionTool)(
@@ -1773,7 +2046,13 @@ function createAgentTool(deps) {
1773
2046
  async (params) => {
1774
2047
  const args = params;
1775
2048
  if (Array.isArray(args.jobs) && args.jobs.length > 0) {
1776
- return runManagedAgentBatch(args.jobs, deps, manager);
2049
+ return runManagedAgentBatch({
2050
+ jobs: args.jobs,
2051
+ deps,
2052
+ manager,
2053
+ resolveAgentDefinition: resolveAgentDefinition2,
2054
+ createSpawnRequest
2055
+ });
1777
2056
  }
1778
2057
  return runManagedAgent(
1779
2058
  {
@@ -1992,7 +2271,7 @@ function retrieveSessionBackgroundTaskManager(key) {
1992
2271
 
1993
2272
  // src/interactive/interactive-session-execution.ts
1994
2273
  var import_node_crypto = require("crypto");
1995
- var import_agent_core2 = require("@robota-sdk/agent-core");
2274
+ var import_agent_core5 = require("@robota-sdk/agent-core");
1996
2275
  function isAbortError(err) {
1997
2276
  return err instanceof DOMException && err.name === "AbortError" || err instanceof Error && (err.message.includes("aborted") || err.message.includes("abort"));
1998
2277
  }
@@ -2010,13 +2289,13 @@ function extractToolSummaries(history, historyBefore) {
2010
2289
  }
2011
2290
  function buildResult(response, sessionHistory, interactiveHistory, historyBefore, contextState) {
2012
2291
  const toolSummaries = extractToolSummaries(sessionHistory, historyBefore);
2013
- const usage3 = extractTurnUsage(sessionHistory, historyBefore, contextState);
2292
+ const usage = extractTurnUsage(sessionHistory, historyBefore, contextState);
2014
2293
  return {
2015
2294
  response,
2016
2295
  history: interactiveHistory,
2017
2296
  toolSummaries,
2018
2297
  contextState,
2019
- ...usage3 && { usage: usage3 }
2298
+ ...usage && { usage }
2020
2299
  };
2021
2300
  }
2022
2301
  function buildInterruptedResult(sessionHistory, interactiveHistory, historyBefore, contextState) {
@@ -2026,22 +2305,22 @@ function buildInterruptedResult(sessionHistory, interactiveHistory, historyBefor
2026
2305
  const msg = sessionHistory[i];
2027
2306
  if (msg?.role === "assistant" && msg.content) parts.push(msg.content);
2028
2307
  }
2029
- const usage3 = extractTurnUsage(sessionHistory, historyBefore, contextState);
2308
+ const usage = extractTurnUsage(sessionHistory, historyBefore, contextState);
2030
2309
  return {
2031
2310
  response: parts.join("\n\n"),
2032
2311
  history: interactiveHistory,
2033
2312
  toolSummaries,
2034
2313
  contextState,
2035
- ...usage3 && { usage: usage3 }
2314
+ ...usage && { usage }
2036
2315
  };
2037
2316
  }
2038
- function createUsageSummaryEntry(usage3) {
2317
+ function createUsageSummaryEntry(usage) {
2039
2318
  return {
2040
2319
  id: `usage_${(0, import_node_crypto.randomUUID)()}`,
2041
2320
  timestamp: /* @__PURE__ */ new Date(),
2042
2321
  category: "event",
2043
2322
  type: "usage-summary",
2044
- data: usage3
2323
+ data: usage
2045
2324
  };
2046
2325
  }
2047
2326
  function extractTurnUsage(sessionHistory, historyBefore, contextState) {
@@ -2051,11 +2330,11 @@ function extractTurnUsage(sessionHistory, historyBefore, contextState) {
2051
2330
  let foundUsage = false;
2052
2331
  for (const message of turnMessages) {
2053
2332
  if (message.role !== "assistant") continue;
2054
- const usage3 = (0, import_agent_core2.collectAssistantUsageMetadata)(message);
2055
- if (!usage3) continue;
2333
+ const usage = (0, import_agent_core5.collectAssistantUsageMetadata)(message);
2334
+ if (!usage) continue;
2056
2335
  foundUsage = true;
2057
- promptTokens += usage3.inputTokens;
2058
- completionTokens += usage3.outputTokens;
2336
+ promptTokens += usage.inputTokens;
2337
+ completionTokens += usage.outputTokens;
2059
2338
  }
2060
2339
  if (!foundUsage) return void 0;
2061
2340
  return {
@@ -2385,6 +2664,7 @@ var MarketplaceSourceSchema = import_zod2.z.object({
2385
2664
  })
2386
2665
  });
2387
2666
  var ExtraKnownMarketplacesSchema = import_zod2.z.record(MarketplaceSourceSchema).optional().catch(void 0);
2667
+ var AutoCompactThresholdSchema = import_zod2.z.union([import_zod2.z.number().gt(0).lte(1), import_zod2.z.literal(false)]).optional();
2388
2668
  var SettingsSchema = import_zod2.z.object({
2389
2669
  /** Trust level used when no --permission-mode flag is given */
2390
2670
  defaultTrustLevel: import_zod2.z.enum(["safe", "moderate", "full"]).optional(),
@@ -2402,7 +2682,9 @@ var SettingsSchema = import_zod2.z.object({
2402
2682
  /** Plugin enablement map: plugin name -> enabled/disabled */
2403
2683
  enabledPlugins: EnabledPluginsSchema,
2404
2684
  /** Extra marketplace URLs for BundlePlugin discovery */
2405
- extraKnownMarketplaces: ExtraKnownMarketplacesSchema
2685
+ extraKnownMarketplaces: ExtraKnownMarketplacesSchema,
2686
+ /** Auto-compact threshold as a 0-1 fraction. Set false to disable automatic compaction. */
2687
+ autoCompactThreshold: AutoCompactThresholdSchema
2406
2688
  });
2407
2689
 
2408
2690
  // src/config/config-loader.ts
@@ -2486,7 +2768,8 @@ function mergeSettings(layers) {
2486
2768
  },
2487
2769
  providers: merged.providers !== void 0 || layer.providers !== void 0 ? mergeProviders(merged.providers, layer.providers) : void 0,
2488
2770
  enabledPlugins: merged.enabledPlugins !== void 0 || layer.enabledPlugins !== void 0 ? { ...merged.enabledPlugins ?? {}, ...layer.enabledPlugins ?? {} } : void 0,
2489
- extraKnownMarketplaces: layer.extraKnownMarketplaces ?? merged.extraKnownMarketplaces
2771
+ extraKnownMarketplaces: layer.extraKnownMarketplaces ?? merged.extraKnownMarketplaces,
2772
+ autoCompactThreshold: layer.autoCompactThreshold ?? merged.autoCompactThreshold
2490
2773
  };
2491
2774
  }, {});
2492
2775
  }
@@ -2540,7 +2823,8 @@ function toResolvedConfig(merged) {
2540
2823
  env: merged.env ?? DEFAULTS.env,
2541
2824
  hooks: merged.hooks ?? void 0,
2542
2825
  enabledPlugins: merged.enabledPlugins ?? void 0,
2543
- extraKnownMarketplaces: merged.extraKnownMarketplaces ?? void 0
2826
+ extraKnownMarketplaces: merged.extraKnownMarketplaces ?? void 0,
2827
+ autoCompactThreshold: merged.autoCompactThreshold
2544
2828
  };
2545
2829
  }
2546
2830
  function getSettingsPaths(cwd) {
@@ -2688,7 +2972,7 @@ Respond with JSON: { "ok": boolean, "reason"?: string }`;
2688
2972
  };
2689
2973
 
2690
2974
  // src/assembly/create-session.ts
2691
- var import_agent_sessions2 = require("@robota-sdk/agent-sessions");
2975
+ var import_agent_sessions3 = require("@robota-sdk/agent-sessions");
2692
2976
 
2693
2977
  // src/context/system-prompt-composer.ts
2694
2978
  function renderSection(section) {
@@ -2870,7 +3154,8 @@ var DEFAULT_TOOL_DESCRIPTIONS = [
2870
3154
  "Edit \u2014 replace a string in a file",
2871
3155
  "Glob \u2014 find files matching a pattern",
2872
3156
  "Grep \u2014 search file contents with regex",
2873
- "WebSearch \u2014 search the internet (Anthropic built-in)"
3157
+ "WebFetch \u2014 fetch URL content as text",
3158
+ "WebSearch \u2014 search the internet through the configured local tool"
2874
3159
  ];
2875
3160
  function createDefaultTools() {
2876
3161
  return [
@@ -3036,6 +3321,200 @@ function extractFilePath(parameters) {
3036
3321
  return typeof value === "string" && value.length > 0 ? value : void 0;
3037
3322
  }
3038
3323
 
3324
+ // src/reversible-execution/reversible-execution-policy.ts
3325
+ var FILE_MUTATION_TOOLS = /* @__PURE__ */ new Set(["Write", "Edit"]);
3326
+ var HOST_SHELL_TOOLS = /* @__PURE__ */ new Set(["Bash", "BackgroundProcess"]);
3327
+ var READ_ONLY_TOOLS = /* @__PURE__ */ new Set(["Read", "Glob", "Grep", "WebFetch", "WebSearch"]);
3328
+ function evaluateReversibleToolSafety(input) {
3329
+ const toolName = input.toolName;
3330
+ if (READ_ONLY_TOOLS.has(toolName)) {
3331
+ return {
3332
+ toolName,
3333
+ reversible: true,
3334
+ sideEffect: "none",
3335
+ rollbackLayer: "none",
3336
+ status: "read-only",
3337
+ message: `${toolName} does not mutate the local workspace.`
3338
+ };
3339
+ }
3340
+ if (FILE_MUTATION_TOOLS.has(toolName)) {
3341
+ if (input.context.checkpointAvailable) {
3342
+ return {
3343
+ toolName,
3344
+ reversible: true,
3345
+ sideEffect: "file-mutation",
3346
+ rollbackLayer: "edit-checkpoint",
3347
+ status: "reversible",
3348
+ message: `${toolName} is reversible through the active edit checkpoint.`
3349
+ };
3350
+ }
3351
+ return {
3352
+ toolName,
3353
+ reversible: false,
3354
+ sideEffect: "file-mutation",
3355
+ rollbackLayer: "none",
3356
+ status: "requires-checkpoint",
3357
+ message: `${toolName} requires an edit checkpoint before file mutation.`
3358
+ };
3359
+ }
3360
+ if (HOST_SHELL_TOOLS.has(toolName)) {
3361
+ return evaluateIsolatedSideEffect(toolName, "shell-process", input.context);
3362
+ }
3363
+ if (toolName === "Agent") {
3364
+ return evaluateAgentSafety(input.toolArgs, input.context);
3365
+ }
3366
+ return {
3367
+ toolName,
3368
+ reversible: false,
3369
+ sideEffect: "unknown",
3370
+ rollbackLayer: "none",
3371
+ status: "unknown",
3372
+ message: `${toolName} has no reversible execution contract.`
3373
+ };
3374
+ }
3375
+ function wrapReversibleExecutionTools(tools, options) {
3376
+ const safetyContext = {
3377
+ checkpointAvailable: options.checkpointAvailable,
3378
+ isolation: options.isolation ?? "none"
3379
+ };
3380
+ const enforceUntrackedSideEffects = options.enforceUntrackedSideEffects ?? true;
3381
+ return tools.map(
3382
+ (tool) => new ReversibleExecutionToolWrapper(tool, {
3383
+ safetyContext,
3384
+ enforceUntrackedSideEffects
3385
+ })
3386
+ );
3387
+ }
3388
+ var ReversibleExecutionToolWrapper = class {
3389
+ constructor(delegate, options) {
3390
+ this.delegate = delegate;
3391
+ this.options = options;
3392
+ this.schema = delegate.schema;
3393
+ }
3394
+ schema;
3395
+ setEventService(eventService) {
3396
+ this.delegate.setEventService(eventService);
3397
+ }
3398
+ async execute(parameters, context) {
3399
+ const report = evaluateReversibleToolSafety({
3400
+ toolName: this.getName(),
3401
+ toolArgs: toToolArgs(parameters),
3402
+ context: this.options.safetyContext
3403
+ });
3404
+ if (!report.reversible && this.options.enforceUntrackedSideEffects) {
3405
+ return createBlockedResult(report);
3406
+ }
3407
+ return this.delegate.execute(parameters, context);
3408
+ }
3409
+ validate(parameters) {
3410
+ return this.delegate.validate(parameters);
3411
+ }
3412
+ validateParameters(parameters) {
3413
+ return this.delegate.validateParameters(parameters);
3414
+ }
3415
+ getDescription() {
3416
+ return this.delegate.getDescription();
3417
+ }
3418
+ getName() {
3419
+ return this.delegate.getName();
3420
+ }
3421
+ };
3422
+ function evaluateIsolatedSideEffect(toolName, sideEffect, context) {
3423
+ if (context.isolation === "worktree") {
3424
+ return {
3425
+ toolName,
3426
+ reversible: true,
3427
+ sideEffect,
3428
+ rollbackLayer: "worktree",
3429
+ status: "reversible",
3430
+ message: `${toolName} side effects are contained in an isolated Git worktree.`
3431
+ };
3432
+ }
3433
+ if (context.isolation === "provider-sandbox") {
3434
+ return {
3435
+ toolName,
3436
+ reversible: true,
3437
+ sideEffect,
3438
+ rollbackLayer: "provider-sandbox",
3439
+ status: "reversible",
3440
+ message: `${toolName} side effects are contained in a provider sandbox snapshot.`
3441
+ };
3442
+ }
3443
+ return {
3444
+ toolName,
3445
+ reversible: false,
3446
+ sideEffect,
3447
+ rollbackLayer: "none",
3448
+ status: "requires-isolation",
3449
+ message: `${toolName} can create host shell side effects that edit checkpoints cannot restore; use worktree or provider sandbox isolation.`
3450
+ };
3451
+ }
3452
+ function evaluateAgentSafety(toolArgs, context) {
3453
+ if (context.isolation === "worktree" || context.isolation === "provider-sandbox") {
3454
+ return evaluateIsolatedSideEffect("Agent", "subagent", context);
3455
+ }
3456
+ if (agentRequestUsesWorktree(toolArgs)) {
3457
+ return {
3458
+ toolName: "Agent",
3459
+ reversible: true,
3460
+ sideEffect: "subagent",
3461
+ rollbackLayer: "worktree",
3462
+ status: "reversible",
3463
+ message: "Agent jobs request worktree isolation, so shell side effects stay outside the parent workspace."
3464
+ };
3465
+ }
3466
+ return {
3467
+ toolName: "Agent",
3468
+ reversible: false,
3469
+ sideEffect: "subagent",
3470
+ rollbackLayer: "none",
3471
+ status: "requires-isolation",
3472
+ message: "Agent jobs must request worktree isolation to be reversible in local-first mode."
3473
+ };
3474
+ }
3475
+ function agentRequestUsesWorktree(toolArgs) {
3476
+ if (!toolArgs) return false;
3477
+ const jobs = toolArgs.jobs;
3478
+ if (Array.isArray(jobs)) {
3479
+ return jobs.length > 0 && jobs.every((job) => {
3480
+ if (!isToolArgRecord(job)) return false;
3481
+ return readIsolation(job) === "worktree";
3482
+ });
3483
+ }
3484
+ return readIsolation(toolArgs) === "worktree";
3485
+ }
3486
+ function readIsolation(value) {
3487
+ const isolation = value["isolation"];
3488
+ return typeof isolation === "string" ? isolation : void 0;
3489
+ }
3490
+ function isToolArgRecord(value) {
3491
+ return value !== void 0 && typeof value === "object" && !Array.isArray(value);
3492
+ }
3493
+ function toToolArgs(parameters) {
3494
+ if (!parameters || typeof parameters !== "object" || Array.isArray(parameters)) return void 0;
3495
+ return parameters;
3496
+ }
3497
+ function createBlockedResult(report) {
3498
+ return {
3499
+ success: true,
3500
+ data: {
3501
+ success: false,
3502
+ output: "",
3503
+ error: report.message,
3504
+ reversibleSafety: {
3505
+ toolName: report.toolName,
3506
+ sideEffect: report.sideEffect,
3507
+ rollbackLayer: report.rollbackLayer,
3508
+ status: report.status
3509
+ }
3510
+ },
3511
+ metadata: {
3512
+ reversibleSafetyStatus: report.status,
3513
+ rollbackLayer: report.rollbackLayer
3514
+ }
3515
+ };
3516
+ }
3517
+
3039
3518
  // src/assembly/create-session.ts
3040
3519
  var import_agent_runtime6 = require("@robota-sdk/agent-runtime");
3041
3520
 
@@ -3155,7 +3634,7 @@ var AgentDefinitionLoader = class {
3155
3634
  };
3156
3635
 
3157
3636
  // src/assembly/background-task-hooks.ts
3158
- var import_agent_core3 = require("@robota-sdk/agent-core");
3637
+ var import_agent_core6 = require("@robota-sdk/agent-core");
3159
3638
  function getSubagentHookEvent(event) {
3160
3639
  if (event.type === "background_task_started" && event.task.kind === "agent") {
3161
3640
  return "SubagentStart";
@@ -3190,7 +3669,7 @@ function fireSubagentLifecycleHook(event, cwd, hooks, hookTypeExecutors) {
3190
3669
  ROBOTA_AGENT_TYPE: event.task.agentType ?? event.task.label
3191
3670
  }
3192
3671
  };
3193
- void (0, import_agent_core3.runHooks)(hooks, hookEventName, input, hookTypeExecutors).catch(() => void 0);
3672
+ void (0, import_agent_core6.runHooks)(hooks, hookEventName, input, hookTypeExecutors).catch(() => void 0);
3194
3673
  }
3195
3674
 
3196
3675
  // src/assembly/create-session.ts
@@ -3207,7 +3686,11 @@ function createSession(options) {
3207
3686
  const cwd = options.cwd ?? process.cwd();
3208
3687
  const sessionId = options.sessionId ?? createSessionId();
3209
3688
  const defaultTools = options.editCheckpointRecorder ? wrapEditCheckpointTools(createDefaultTools(), options.editCheckpointRecorder) : createDefaultTools();
3210
- const tools = [...defaultTools, ...options.additionalTools ?? []];
3689
+ const assembledTools = [...defaultTools, ...options.additionalTools ?? []];
3690
+ const tools = options.reversibleExecution ? wrapReversibleExecutionTools(assembledTools, {
3691
+ ...options.reversibleExecution,
3692
+ checkpointAvailable: options.editCheckpointRecorder !== void 0
3693
+ }) : assembledTools;
3211
3694
  if (options.modelCommandExecutor && options.isModelCommandInvocable) {
3212
3695
  tools.push(
3213
3696
  createCommandExecutionTool({
@@ -3346,7 +3829,8 @@ ${options.appendSystemPrompt}` : systemMessage;
3346
3829
  allow: [...defaultAllow, ...options.config.permissions.allow ?? [], ...allowedToolPatterns],
3347
3830
  deny: options.config.permissions.deny ?? []
3348
3831
  };
3349
- const session = new import_agent_sessions2.Session({
3832
+ const SessionWithAutoCompact = import_agent_sessions3.Session;
3833
+ const session = new SessionWithAutoCompact({
3350
3834
  tools,
3351
3835
  provider,
3352
3836
  systemMessage: finalSystemMessage,
@@ -3366,7 +3850,9 @@ ${options.appendSystemPrompt}` : systemMessage;
3366
3850
  onToolExecution: options.onToolExecution,
3367
3851
  promptForApproval: options.promptForApproval,
3368
3852
  onCompact: options.onCompact,
3853
+ onCompactEvent: options.onCompactEvent,
3369
3854
  compactInstructions: options.compactInstructions ?? options.context.compactInstructions,
3855
+ autoCompactThreshold: options.autoCompactThreshold ?? options.config.autoCompactThreshold,
3370
3856
  sessionLogger: options.sessionLogger,
3371
3857
  hookTypeExecutors: hookTypeExecutors.length > 0 ? hookTypeExecutors : void 0
3372
3858
  });
@@ -3389,18 +3875,18 @@ function logBackgroundTaskEvent(logger, sessionId, event) {
3389
3875
  // src/assembly/subagent-logger.ts
3390
3876
  var import_node_fs5 = require("fs");
3391
3877
  var import_node_path4 = require("path");
3392
- var import_agent_sessions3 = require("@robota-sdk/agent-sessions");
3878
+ var import_agent_sessions4 = require("@robota-sdk/agent-sessions");
3393
3879
  function createSubagentLogger(parentSessionId, _agentId, baseLogsDir) {
3394
3880
  const subagentDir = (0, import_node_path4.join)(baseLogsDir, parentSessionId, "subagents");
3395
3881
  (0, import_node_fs5.mkdirSync)(subagentDir, { recursive: true });
3396
- return new import_agent_sessions3.FileSessionLogger(subagentDir);
3882
+ return new import_agent_sessions4.FileSessionLogger(subagentDir);
3397
3883
  }
3398
3884
  function resolveSubagentLogDir(parentSessionId, baseLogsDir) {
3399
3885
  return (0, import_node_path4.join)(baseLogsDir, parentSessionId, "subagents");
3400
3886
  }
3401
3887
 
3402
3888
  // src/interactive/interactive-session-init.ts
3403
- var import_agent_sessions4 = require("@robota-sdk/agent-sessions");
3889
+ var import_agent_sessions5 = require("@robota-sdk/agent-sessions");
3404
3890
 
3405
3891
  // src/paths.ts
3406
3892
  var import_node_path5 = require("path");
@@ -4617,11 +5103,12 @@ async function createInteractiveSession(options) {
4617
5103
  permissionMode: options.permissionMode,
4618
5104
  maxTurns: options.maxTurns,
4619
5105
  terminal: NOOP_TERMINAL,
4620
- sessionLogger: new import_agent_sessions4.FileSessionLogger(paths.logs),
5106
+ sessionLogger: new import_agent_sessions5.FileSessionLogger(paths.logs),
4621
5107
  permissionHandler: options.permissionHandler,
4622
5108
  provider: options.provider,
4623
5109
  onTextDelta: options.onTextDelta,
4624
5110
  onContextUpdate: options.onContextUpdate,
5111
+ onCompactEvent: options.onCompactEvent,
4625
5112
  onToolExecution: options.onToolExecution,
4626
5113
  sessionId,
4627
5114
  allowedTools: options.allowedTools,
@@ -4639,7 +5126,8 @@ async function createInteractiveSession(options) {
4639
5126
  } : {},
4640
5127
  modelCommandExecutor: options.modelCommandExecutor,
4641
5128
  isModelCommandInvocable: options.isModelCommandInvocable,
4642
- editCheckpointRecorder: options.editCheckpointRecorder
5129
+ editCheckpointRecorder: options.editCheckpointRecorder,
5130
+ reversibleExecution: options.reversibleExecution
4643
5131
  });
4644
5132
  }
4645
5133
  function injectSavedMessage(session, msg) {
@@ -4736,8 +5224,60 @@ function isRestoredTerminalStatus(status) {
4736
5224
 
4737
5225
  // src/checkpoints/edit-checkpoint-store.ts
4738
5226
  var import_promises = require("fs/promises");
5227
+ var import_node_fs14 = require("fs");
5228
+ var import_node_path15 = require("path");
5229
+
5230
+ // src/checkpoints/edit-checkpoint-inspection.ts
4739
5231
  var import_node_fs13 = require("fs");
4740
5232
  var import_node_path14 = require("path");
5233
+ function buildEditCheckpointInspection(input) {
5234
+ const later = input.manifests.filter((manifest) => manifest.sequence > input.target.sequence);
5235
+ const rollbackRange = input.manifests.filter(
5236
+ (manifest) => manifest.sequence >= input.target.sequence
5237
+ );
5238
+ return {
5239
+ target: toSummary(input.target),
5240
+ capturedFiles: input.target.files.map((file) => {
5241
+ const snapshotPath = file.snapshotFile ? (0, import_node_path14.join)(input.checkpointDir(input.sessionId, input.target.id), file.snapshotFile) : void 0;
5242
+ const snapshotStats = snapshotPath ? statSafe(snapshotPath) : void 0;
5243
+ return {
5244
+ originalPath: file.originalPath,
5245
+ relativePath: (0, import_node_path14.relative)(input.cwd, file.originalPath),
5246
+ existed: file.existed,
5247
+ restoreAction: file.existed ? "restore-preimage" : "delete-created-file",
5248
+ snapshotAvailable: file.existed ? snapshotStats !== void 0 : false,
5249
+ ...snapshotStats ? { snapshotSizeBytes: snapshotStats.size } : {}
5250
+ };
5251
+ }),
5252
+ restoreToCheckpoint: toInspectionPlan(later),
5253
+ rollbackThroughCheckpoint: toInspectionPlan(rollbackRange)
5254
+ };
5255
+ }
5256
+ function toSummary(manifest) {
5257
+ return {
5258
+ id: manifest.id,
5259
+ sessionId: manifest.sessionId,
5260
+ sequence: manifest.sequence,
5261
+ prompt: manifest.prompt,
5262
+ createdAt: manifest.createdAt,
5263
+ fileCount: manifest.fileCount
5264
+ };
5265
+ }
5266
+ function toInspectionPlan(manifests) {
5267
+ return {
5268
+ checkpointIds: manifests.map((manifest) => manifest.id),
5269
+ fileCount: manifests.reduce((count, manifest) => count + manifest.fileCount, 0)
5270
+ };
5271
+ }
5272
+ function statSafe(path) {
5273
+ try {
5274
+ return (0, import_node_fs13.statSync)(path);
5275
+ } catch {
5276
+ return void 0;
5277
+ }
5278
+ }
5279
+
5280
+ // src/checkpoints/edit-checkpoint-store.ts
4741
5281
  var MANIFEST_FILE = "manifest.json";
4742
5282
  var SNAPSHOT_DIR = "files";
4743
5283
  var ID_PAD = 4;
@@ -4748,7 +5288,7 @@ var EditCheckpointStore = class {
4748
5288
  now;
4749
5289
  activeTurn = null;
4750
5290
  constructor(options) {
4751
- this.cwd = (0, import_node_path14.resolve)(options.cwd);
5291
+ this.cwd = (0, import_node_path15.resolve)(options.cwd);
4752
5292
  this.rootDir = projectPaths(this.cwd).checkpoints;
4753
5293
  this.now = options.now ?? (() => /* @__PURE__ */ new Date());
4754
5294
  }
@@ -4758,8 +5298,8 @@ var EditCheckpointStore = class {
4758
5298
  }
4759
5299
  const nextSequence = this.nextSequence(input.sessionId);
4760
5300
  const id = `turn-${String(nextSequence).padStart(ID_PAD, "0")}`;
4761
- const dir = (0, import_node_path14.join)(this.sessionDir(input.sessionId), id);
4762
- await (0, import_promises.mkdir)((0, import_node_path14.join)(dir, SNAPSHOT_DIR), { recursive: true });
5301
+ const dir = (0, import_node_path15.join)(this.sessionDir(input.sessionId), id);
5302
+ await (0, import_promises.mkdir)((0, import_node_path15.join)(dir, SNAPSHOT_DIR), { recursive: true });
4763
5303
  const manifest = {
4764
5304
  version: 1,
4765
5305
  id,
@@ -4775,11 +5315,11 @@ var EditCheckpointStore = class {
4775
5315
  dir,
4776
5316
  capturedPaths: /* @__PURE__ */ new Set()
4777
5317
  };
4778
- return toSummary(manifest);
5318
+ return toSummary2(manifest);
4779
5319
  }
4780
5320
  async captureFile(filePath) {
4781
5321
  if (!this.activeTurn) return;
4782
- const originalPath = (0, import_node_path14.resolve)(this.cwd, filePath);
5322
+ const originalPath = (0, import_node_path15.resolve)(this.cwd, filePath);
4783
5323
  if (this.activeTurn.capturedPaths.has(originalPath)) return;
4784
5324
  if (isInside(this.rootDir, originalPath)) return;
4785
5325
  const record = await this.createFileRecord(originalPath, this.activeTurn);
@@ -4792,10 +5332,24 @@ var EditCheckpointStore = class {
4792
5332
  const active = this.activeTurn;
4793
5333
  this.activeTurn = null;
4794
5334
  await this.writeManifest(active.dir, active.manifest);
4795
- return toSummary(active.manifest);
5335
+ return toSummary2(active.manifest);
4796
5336
  }
4797
5337
  list(sessionId) {
4798
- return this.loadManifests(sessionId).map(toSummary);
5338
+ return this.loadManifests(sessionId).map(toSummary2);
5339
+ }
5340
+ inspect(sessionId, checkpointId) {
5341
+ const manifests = this.loadManifests(sessionId);
5342
+ const target = manifests.find((manifest) => manifest.id === checkpointId);
5343
+ if (!target) {
5344
+ throw new Error(`Unknown edit checkpoint: ${checkpointId}`);
5345
+ }
5346
+ return buildEditCheckpointInspection({
5347
+ cwd: this.cwd,
5348
+ sessionId,
5349
+ target,
5350
+ manifests,
5351
+ checkpointDir: (inputSessionId, inputCheckpointId) => this.checkpointDir(inputSessionId, inputCheckpointId)
5352
+ });
4799
5353
  }
4800
5354
  async restoreToCheckpoint(sessionId, checkpointId) {
4801
5355
  const manifests = this.loadManifests(sessionId);
@@ -4815,12 +5369,36 @@ var EditCheckpointStore = class {
4815
5369
  await (0, import_promises.rm)(this.checkpointDir(sessionId, manifest.id), { recursive: true, force: true });
4816
5370
  }
4817
5371
  return {
4818
- target: toSummary(target),
5372
+ target: toSummary2(target),
4819
5373
  restoredCheckpointCount: later.length,
4820
5374
  restoredFileCount,
4821
5375
  removedCheckpointCount: later.length
4822
5376
  };
4823
5377
  }
5378
+ async rollbackThroughCheckpoint(sessionId, checkpointId) {
5379
+ const manifests = this.loadManifests(sessionId);
5380
+ const target = manifests.find((manifest) => manifest.id === checkpointId);
5381
+ if (!target) {
5382
+ throw new Error(`Unknown edit checkpoint: ${checkpointId}`);
5383
+ }
5384
+ const rollbackRange = manifests.filter((manifest) => manifest.sequence >= target.sequence).sort((a, b) => b.sequence - a.sequence);
5385
+ let restoredFileCount = 0;
5386
+ for (const manifest of rollbackRange) {
5387
+ for (const file of manifest.files) {
5388
+ await this.restoreFile(sessionId, manifest.id, file);
5389
+ restoredFileCount += 1;
5390
+ }
5391
+ }
5392
+ for (const manifest of rollbackRange) {
5393
+ await (0, import_promises.rm)(this.checkpointDir(sessionId, manifest.id), { recursive: true, force: true });
5394
+ }
5395
+ return {
5396
+ target: toSummary2(target),
5397
+ restoredCheckpointCount: rollbackRange.length,
5398
+ restoredFileCount,
5399
+ removedCheckpointCount: rollbackRange.length
5400
+ };
5401
+ }
4824
5402
  async createFileRecord(originalPath, active) {
4825
5403
  const existed = await pathExists(originalPath);
4826
5404
  if (!existed) {
@@ -4829,11 +5407,11 @@ var EditCheckpointStore = class {
4829
5407
  existed: false
4830
5408
  };
4831
5409
  }
4832
- const snapshotFile = (0, import_node_path14.join)(
5410
+ const snapshotFile = (0, import_node_path15.join)(
4833
5411
  SNAPSHOT_DIR,
4834
5412
  `${String(active.manifest.files.length + 1).padStart(SNAPSHOT_PAD, "0")}.content`
4835
5413
  );
4836
- await (0, import_promises.copyFile)(originalPath, (0, import_node_path14.join)(active.dir, snapshotFile));
5414
+ await (0, import_promises.copyFile)(originalPath, (0, import_node_path15.join)(active.dir, snapshotFile));
4837
5415
  return {
4838
5416
  originalPath,
4839
5417
  existed: true,
@@ -4848,15 +5426,15 @@ var EditCheckpointStore = class {
4848
5426
  if (!record.snapshotFile) {
4849
5427
  throw new Error(`Checkpoint file record is missing a snapshot: ${record.originalPath}`);
4850
5428
  }
4851
- await (0, import_promises.mkdir)((0, import_node_path14.dirname)(record.originalPath), { recursive: true });
5429
+ await (0, import_promises.mkdir)((0, import_node_path15.dirname)(record.originalPath), { recursive: true });
4852
5430
  await (0, import_promises.copyFile)(
4853
- (0, import_node_path14.join)(this.checkpointDir(sessionId, checkpointId), record.snapshotFile),
5431
+ (0, import_node_path15.join)(this.checkpointDir(sessionId, checkpointId), record.snapshotFile),
4854
5432
  record.originalPath
4855
5433
  );
4856
5434
  }
4857
5435
  loadManifests(sessionId) {
4858
5436
  const dir = this.sessionDir(sessionId);
4859
- return readDirSyncSafe(dir).map((entry) => (0, import_node_path14.join)(dir, entry, MANIFEST_FILE)).map((manifestPath) => readJsonManifest(manifestPath)).filter((manifest) => manifest !== void 0).sort((a, b) => a.sequence - b.sequence);
5437
+ return readDirSyncSafe(dir).map((entry) => (0, import_node_path15.join)(dir, entry, MANIFEST_FILE)).map((manifestPath) => readJsonManifest(manifestPath)).filter((manifest) => manifest !== void 0).sort((a, b) => a.sequence - b.sequence);
4860
5438
  }
4861
5439
  nextSequence(sessionId) {
4862
5440
  const last = this.list(sessionId).at(-1);
@@ -4864,19 +5442,19 @@ var EditCheckpointStore = class {
4864
5442
  }
4865
5443
  async writeManifest(dir, manifest) {
4866
5444
  await (0, import_promises.mkdir)(dir, { recursive: true });
4867
- const path = (0, import_node_path14.join)(dir, MANIFEST_FILE);
5445
+ const path = (0, import_node_path15.join)(dir, MANIFEST_FILE);
4868
5446
  const tmp = `${path}.tmp`;
4869
5447
  await (0, import_promises.writeFile)(tmp, JSON.stringify(manifest, null, 2), "utf8");
4870
5448
  await (0, import_promises.rename)(tmp, path);
4871
5449
  }
4872
5450
  sessionDir(sessionId) {
4873
- return (0, import_node_path14.join)(this.rootDir, safePathSegment(sessionId));
5451
+ return (0, import_node_path15.join)(this.rootDir, safePathSegment(sessionId));
4874
5452
  }
4875
5453
  checkpointDir(sessionId, checkpointId) {
4876
- return (0, import_node_path14.join)(this.sessionDir(sessionId), safePathSegment(checkpointId));
5454
+ return (0, import_node_path15.join)(this.sessionDir(sessionId), safePathSegment(checkpointId));
4877
5455
  }
4878
5456
  };
4879
- function toSummary(manifest) {
5457
+ function toSummary2(manifest) {
4880
5458
  return {
4881
5459
  id: manifest.id,
4882
5460
  sessionId: manifest.sessionId,
@@ -4890,12 +5468,12 @@ function safePathSegment(value) {
4890
5468
  return value.replace(/[^a-zA-Z0-9._-]/g, "_");
4891
5469
  }
4892
5470
  function isInside(parent, child) {
4893
- const rel = (0, import_node_path14.relative)(parent, child);
5471
+ const rel = (0, import_node_path15.relative)(parent, child);
4894
5472
  return rel.length === 0 || !rel.startsWith("..") && !rel.startsWith("/");
4895
5473
  }
4896
5474
  async function pathExists(path) {
4897
5475
  try {
4898
- await (0, import_promises.access)(path, import_node_fs13.constants.F_OK);
5476
+ await (0, import_promises.access)(path, import_node_fs14.constants.F_OK);
4899
5477
  return true;
4900
5478
  } catch {
4901
5479
  return false;
@@ -4903,14 +5481,14 @@ async function pathExists(path) {
4903
5481
  }
4904
5482
  function readDirSyncSafe(dir) {
4905
5483
  try {
4906
- return (0, import_node_fs13.readdirSync)(dir);
5484
+ return (0, import_node_fs14.readdirSync)(dir);
4907
5485
  } catch {
4908
5486
  return [];
4909
5487
  }
4910
5488
  }
4911
5489
  function readJsonManifest(path) {
4912
5490
  try {
4913
- const raw = (0, import_node_fs13.readFileSync)(path, "utf8");
5491
+ const raw = (0, import_node_fs14.readFileSync)(path, "utf8");
4914
5492
  return JSON.parse(raw);
4915
5493
  } catch {
4916
5494
  return void 0;
@@ -4949,14 +5527,19 @@ var InteractiveSession = class {
4949
5527
  backgroundJobUnsubscribe = null;
4950
5528
  backgroundJobOrchestrator = null;
4951
5529
  commandModules;
5530
+ commandHostAdapters;
5531
+ autoCompactThresholdSource = "default";
4952
5532
  shuttingDown = false;
4953
5533
  shutdownPromise = null;
4954
5534
  constructor(options) {
4955
- this.commandModules = "commandModules" in options ? options.commandModules ?? [] : [];
4956
- this.commandExecutor = new SystemCommandExecutor([
4957
- ...createSystemCommands(),
4958
- ...this.commandModules.flatMap((module2) => module2.systemCommands ?? [])
4959
- ]);
5535
+ const sdkBuiltinModule = createBuiltinCommandModule();
5536
+ this.commandModules = [
5537
+ sdkBuiltinModule,
5538
+ ..."commandModules" in options ? options.commandModules ?? [] : []
5539
+ ];
5540
+ this.commandExecutor = new SystemCommandExecutor(
5541
+ this.commandModules.flatMap((module2) => module2.systemCommands ?? [])
5542
+ );
4960
5543
  this.sessionStore = options.sessionStore;
4961
5544
  this.sessionName = options.sessionName;
4962
5545
  this.cwd = ("cwd" in options ? options.cwd : void 0) ?? "";
@@ -4965,8 +5548,10 @@ var InteractiveSession = class {
4965
5548
  }
4966
5549
  this.resumeSessionId = options.resumeSessionId;
4967
5550
  this.forkSession = options.forkSession ?? false;
5551
+ this.commandHostAdapters = "commandHostAdapters" in options ? options.commandHostAdapters : void 0;
4968
5552
  if ("session" in options && options.session) {
4969
5553
  this.session = options.session;
5554
+ this.autoCompactThresholdSource = "session";
4970
5555
  this.initialized = true;
4971
5556
  } else {
4972
5557
  const stdOpts = options;
@@ -4993,7 +5578,8 @@ var InteractiveSession = class {
4993
5578
  if (this.initialized) this.persistCurrentSession();
4994
5579
  }
4995
5580
  async initializeAsync(options) {
4996
- const config = await loadConfig(options.cwd);
5581
+ const config = options.config ?? await loadConfig(options.cwd);
5582
+ this.autoCompactThresholdSource = config.autoCompactThreshold === void 0 ? "default" : "settings";
4997
5583
  this.editCheckpointStore = new EditCheckpointStore({ cwd: options.cwd });
4998
5584
  this.session = await createInteractiveSession({
4999
5585
  cwd: options.cwd,
@@ -5006,6 +5592,7 @@ var InteractiveSession = class {
5006
5592
  forkSession: this.forkSession,
5007
5593
  onTextDelta: (delta) => this.handleTextDelta(delta),
5008
5594
  onContextUpdate: (state) => this.emit("context_update", state),
5595
+ onCompactEvent: (event) => this.handleCompactEvent(event),
5009
5596
  onToolExecution: (event) => this.handleToolExecution(event),
5010
5597
  bare: options.bare,
5011
5598
  allowedTools: options.allowedTools,
@@ -5014,6 +5601,7 @@ var InteractiveSession = class {
5014
5601
  subagentRunnerFactory: options.subagentRunnerFactory,
5015
5602
  ...options.commandModules ? { commandModules: options.commandModules } : {},
5016
5603
  editCheckpointRecorder: this.editCheckpointStore,
5604
+ ...options.reversibleExecution ? { reversibleExecution: options.reversibleExecution } : {},
5017
5605
  commandDescriptors: this.commandExecutor.listModelInvocableCommands(),
5018
5606
  ...this.commandExecutor.listModelInvocableCommands().length > 0 ? {
5019
5607
  modelCommandExecutor: (command, args) => this.executeModelCommand(command, args),
@@ -5060,7 +5648,18 @@ var InteractiveSession = class {
5060
5648
  }
5061
5649
  async executeCommand(name, args) {
5062
5650
  await this.ensureInitialized();
5063
- return this.commandExecutor.execute(name, this, args);
5651
+ const command = this.commandExecutor.getCommand(name);
5652
+ if (!command) return null;
5653
+ if (this.executing) {
5654
+ return {
5655
+ success: false,
5656
+ message: "Another prompt or command is already running. Wait for it to finish."
5657
+ };
5658
+ }
5659
+ if (command.lifecycle === "blocking") {
5660
+ return this.executeForegroundCommand(command, args);
5661
+ }
5662
+ return this.commandExecutor.executeCommand(command, this, args);
5064
5663
  }
5065
5664
  async executeModelCommand(name, args) {
5066
5665
  await this.ensureInitialized();
@@ -5153,6 +5752,30 @@ var InteractiveSession = class {
5153
5752
  getContextState() {
5154
5753
  return this.getSessionOrThrow().getContextState();
5155
5754
  }
5755
+ getAutoCompactThreshold() {
5756
+ return this.getSessionOrThrow().getAutoCompactThreshold();
5757
+ }
5758
+ getAutoCompactThresholdSource() {
5759
+ return this.autoCompactThresholdSource;
5760
+ }
5761
+ setAutoCompactThreshold(threshold, source = "session") {
5762
+ this.getSessionOrThrow().setAutoCompactThreshold(threshold);
5763
+ this.autoCompactThresholdSource = source;
5764
+ this.emit("context_update", this.getContextState());
5765
+ this.persistCurrentSession();
5766
+ }
5767
+ getCommandHostAdapters() {
5768
+ return this.commandHostAdapters ?? {};
5769
+ }
5770
+ clearConversationHistory() {
5771
+ this.getSessionOrThrow().clearHistory();
5772
+ this.history = [];
5773
+ this.persistCurrentSession();
5774
+ this.emit("context_update", this.getContextState());
5775
+ }
5776
+ async compactContext(instructions) {
5777
+ await this.getSessionOrThrow().compact(instructions);
5778
+ }
5156
5779
  getName() {
5157
5780
  return this.sessionName;
5158
5781
  }
@@ -5166,6 +5789,10 @@ var InteractiveSession = class {
5166
5789
  const sessionId = this.getSessionOrThrow().getSessionId();
5167
5790
  return this.getEditCheckpointStore().list(sessionId);
5168
5791
  }
5792
+ inspectEditCheckpoint(checkpointId) {
5793
+ const sessionId = this.getSessionOrThrow().getSessionId();
5794
+ return this.getEditCheckpointStore().inspect(sessionId, checkpointId);
5795
+ }
5169
5796
  async restoreEditCheckpoint(checkpointId) {
5170
5797
  await this.ensureInitialized();
5171
5798
  if (this.executing) {
@@ -5176,7 +5803,22 @@ var InteractiveSession = class {
5176
5803
  checkpointId
5177
5804
  );
5178
5805
  this.history.push(
5179
- (0, import_agent_core4.messageToHistoryEntry)((0, import_agent_core4.createSystemMessage)(`Restored edit checkpoint: ${checkpointId}`))
5806
+ (0, import_agent_core7.messageToHistoryEntry)((0, import_agent_core7.createSystemMessage)(`Restored edit checkpoint: ${checkpointId}`))
5807
+ );
5808
+ this.persistCurrentSession();
5809
+ return result;
5810
+ }
5811
+ async rollbackEditCheckpoint(checkpointId) {
5812
+ await this.ensureInitialized();
5813
+ if (this.executing) {
5814
+ throw new Error("Cannot rollback edit checkpoint while a prompt is running.");
5815
+ }
5816
+ const result = await this.getEditCheckpointStore().rollbackThroughCheckpoint(
5817
+ this.getSessionOrThrow().getSessionId(),
5818
+ checkpointId
5819
+ );
5820
+ this.history.push(
5821
+ (0, import_agent_core7.messageToHistoryEntry)((0, import_agent_core7.createSystemMessage)(`Rolled back edit checkpoint: ${checkpointId}`))
5180
5822
  );
5181
5823
  this.persistCurrentSession();
5182
5824
  return result;
@@ -5421,7 +6063,7 @@ var InteractiveSession = class {
5421
6063
  this.executing = true;
5422
6064
  this.clearStreaming();
5423
6065
  this.emit("thinking", true);
5424
- this.history.push((0, import_agent_core4.messageToHistoryEntry)((0, import_agent_core4.createUserMessage)(displayInput)));
6066
+ this.history.push((0, import_agent_core7.messageToHistoryEntry)((0, import_agent_core7.createUserMessage)(displayInput)));
5425
6067
  }
5426
6068
  finishForkSkillExecution() {
5427
6069
  this.executing = false;
@@ -5436,7 +6078,7 @@ var InteractiveSession = class {
5436
6078
  }
5437
6079
  }
5438
6080
  recordForkSkillError(err) {
5439
- this.history.push((0, import_agent_core4.messageToHistoryEntry)((0, import_agent_core4.createSystemMessage)(`Error: ${err.message}`)));
6081
+ this.history.push((0, import_agent_core7.messageToHistoryEntry)((0, import_agent_core7.createSystemMessage)(`Error: ${err.message}`)));
5440
6082
  this.emit("error", err);
5441
6083
  }
5442
6084
  resolveForkAgentDefinition(agentType, options) {
@@ -5485,15 +6127,42 @@ var InteractiveSession = class {
5485
6127
  toolSummaries: [],
5486
6128
  contextState: this.getContextState()
5487
6129
  };
5488
- this.history.push((0, import_agent_core4.messageToHistoryEntry)((0, import_agent_core4.createAssistantMessage)(result)));
6130
+ this.history.push((0, import_agent_core7.messageToHistoryEntry)((0, import_agent_core7.createAssistantMessage)(result)));
5489
6131
  this.emit("complete", executionResult);
5490
6132
  this.emit("context_update", this.getContextState());
5491
6133
  }
6134
+ async executeForegroundCommand(command, args) {
6135
+ this.executing = true;
6136
+ this.clearStreaming();
6137
+ this.emit("thinking", true);
6138
+ try {
6139
+ const result = await this.commandExecutor.executeCommand(command, this, args);
6140
+ this.emit("context_update", this.getContextState());
6141
+ return result;
6142
+ } catch (err) {
6143
+ const errMsg = err instanceof Error ? err.message : String(err);
6144
+ return {
6145
+ success: false,
6146
+ message: `Error: ${errMsg}`
6147
+ };
6148
+ } finally {
6149
+ this.executing = false;
6150
+ this.emit("thinking", false);
6151
+ this.persistCurrentSession();
6152
+ if (!this.shuttingDown && this.pendingPrompt) {
6153
+ const queued = this.pendingPrompt;
6154
+ const queuedDisplay = this.pendingDisplayInput;
6155
+ const queuedRaw = this.pendingRawInput;
6156
+ this.clearPendingQueue();
6157
+ setTimeout(() => this.executePrompt(queued, queuedDisplay, queuedRaw), 0);
6158
+ }
6159
+ }
6160
+ }
5492
6161
  async executePrompt(input, displayInput, rawInput) {
5493
6162
  this.executing = true;
5494
6163
  this.clearStreaming();
5495
6164
  this.emit("thinking", true);
5496
- this.history.push((0, import_agent_core4.messageToHistoryEntry)((0, import_agent_core4.createUserMessage)(displayInput ?? input)));
6165
+ this.history.push((0, import_agent_core7.messageToHistoryEntry)((0, import_agent_core7.createUserMessage)(displayInput ?? input)));
5497
6166
  const historyBefore = this.getSessionOrThrow().getHistory().length;
5498
6167
  this.usedMemoryReferences = [];
5499
6168
  try {
@@ -5509,7 +6178,7 @@ var InteractiveSession = class {
5509
6178
  historyBefore,
5510
6179
  this.getContextState()
5511
6180
  );
5512
- this.history.push((0, import_agent_core4.messageToHistoryEntry)((0, import_agent_core4.createAssistantMessage)(result.response)));
6181
+ this.history.push((0, import_agent_core7.messageToHistoryEntry)((0, import_agent_core7.createAssistantMessage)(result.response)));
5513
6182
  if (result.usage) this.history.push(createUsageSummaryEntry(result.usage));
5514
6183
  this.emit("complete", result);
5515
6184
  this.emit("context_update", this.getContextState());
@@ -5525,15 +6194,15 @@ var InteractiveSession = class {
5525
6194
  pushToolSummaryToHistory({ activeTools: this.activeTools, history: this.history });
5526
6195
  this.clearStreaming();
5527
6196
  if (result.response)
5528
- this.history.push((0, import_agent_core4.messageToHistoryEntry)((0, import_agent_core4.createAssistantMessage)(result.response)));
6197
+ this.history.push((0, import_agent_core7.messageToHistoryEntry)((0, import_agent_core7.createAssistantMessage)(result.response)));
5529
6198
  if (result.usage) this.history.push(createUsageSummaryEntry(result.usage));
5530
- this.history.push((0, import_agent_core4.messageToHistoryEntry)((0, import_agent_core4.createSystemMessage)("Interrupted by user.")));
6199
+ this.history.push((0, import_agent_core7.messageToHistoryEntry)((0, import_agent_core7.createSystemMessage)("Interrupted by user.")));
5531
6200
  this.emit("interrupted", result);
5532
6201
  } else {
5533
6202
  pushToolSummaryToHistory({ activeTools: this.activeTools, history: this.history });
5534
6203
  this.clearStreaming();
5535
6204
  const errMsg = err instanceof Error ? err.message : String(err);
5536
- this.history.push((0, import_agent_core4.messageToHistoryEntry)((0, import_agent_core4.createSystemMessage)(`Error: ${errMsg}`)));
6205
+ this.history.push((0, import_agent_core7.messageToHistoryEntry)((0, import_agent_core7.createSystemMessage)(`Error: ${errMsg}`)));
5537
6206
  this.emit("error", err instanceof Error ? err : new Error(errMsg));
5538
6207
  }
5539
6208
  } finally {
@@ -5570,7 +6239,7 @@ var InteractiveSession = class {
5570
6239
  } catch (error) {
5571
6240
  const err = error instanceof Error ? error : new Error(String(error));
5572
6241
  this.history.push(
5573
- (0, import_agent_core4.messageToHistoryEntry)((0, import_agent_core4.createSystemMessage)(`Checkpoint error: ${err.message}`))
6242
+ (0, import_agent_core7.messageToHistoryEntry)((0, import_agent_core7.createSystemMessage)(`Checkpoint error: ${err.message}`))
5574
6243
  );
5575
6244
  this.emit("error", err);
5576
6245
  }
@@ -5584,6 +6253,19 @@ var InteractiveSession = class {
5584
6253
  }, STREAMING_FLUSH_INTERVAL_MS);
5585
6254
  }
5586
6255
  }
6256
+ handleCompactEvent(event) {
6257
+ if (event.trigger === "auto") {
6258
+ this.history.push(
6259
+ (0, import_agent_core7.messageToHistoryEntry)(
6260
+ (0, import_agent_core7.createSystemMessage)(
6261
+ `Auto compacted context: ${Math.round(event.before.usedPercentage)}% -> ${Math.round(event.after.usedPercentage)}%`
6262
+ )
6263
+ )
6264
+ );
6265
+ }
6266
+ this.emit("compact", event);
6267
+ this.emit("context_update", event.after);
6268
+ }
5587
6269
  handleToolExecution(event) {
5588
6270
  const streamingState = { activeTools: this.activeTools, history: this.history };
5589
6271
  if (event.type === "start") {
@@ -5655,10 +6337,10 @@ function createQuery(options) {
5655
6337
  }
5656
6338
 
5657
6339
  // src/types.ts
5658
- var import_agent_core5 = require("@robota-sdk/agent-core");
6340
+ var import_agent_core8 = require("@robota-sdk/agent-core");
5659
6341
 
5660
6342
  // src/index.ts
5661
- var import_agent_core6 = require("@robota-sdk/agent-core");
6343
+ var import_agent_core9 = require("@robota-sdk/agent-core");
5662
6344
 
5663
6345
  // src/self-hosting/self-hosting-verification.ts
5664
6346
  var DEFAULT_BASE_REF = "origin/develop";
@@ -5780,7 +6462,7 @@ var import_agent_runtime7 = require("@robota-sdk/agent-runtime");
5780
6462
  var import_agent_runtime8 = require("@robota-sdk/agent-runtime");
5781
6463
 
5782
6464
  // src/index.ts
5783
- var import_agent_core7 = require("@robota-sdk/agent-core");
6465
+ var import_agent_core10 = require("@robota-sdk/agent-core");
5784
6466
 
5785
6467
  // src/permissions/permission-prompt.ts
5786
6468
  var import_chalk = __toESM(require("chalk"), 1);
@@ -5803,10 +6485,13 @@ async function promptForApproval(terminal, toolName, toolArgs) {
5803
6485
  }
5804
6486
 
5805
6487
  // src/index.ts
5806
- var import_agent_core8 = require("@robota-sdk/agent-core");
6488
+ var import_agent_core11 = require("@robota-sdk/agent-core");
5807
6489
  // Annotate the CommonJS export names for ESM import in node:
5808
6490
  0 && (module.exports = {
6491
+ AUTO_COMPACT_THRESHOLD_SETTINGS_KEY,
5809
6492
  AgentExecutor,
6493
+ BACKGROUND_COMMAND_DESCRIPTION,
6494
+ BACKGROUND_COMMAND_USAGE,
5810
6495
  BUILT_IN_AGENTS,
5811
6496
  BackgroundJobOrchestrator,
5812
6497
  BackgroundTaskError,
@@ -5814,64 +6499,171 @@ var import_agent_core8 = require("@robota-sdk/agent-core");
5814
6499
  BuiltinCommandSource,
5815
6500
  BundlePluginInstaller,
5816
6501
  BundlePluginLoader,
6502
+ CLEAR_COMMAND_DESCRIPTION,
6503
+ COST_COMMAND_DESCRIPTION,
5817
6504
  CommandRegistry,
6505
+ DEFAULT_AUTO_COMPACT_THRESHOLD,
6506
+ DEFAULT_STATUS_LINE_COMMAND_SETTINGS,
6507
+ EXIT_COMMAND_DESCRIPTION,
5818
6508
  EditCheckpointStore,
6509
+ HELP_COMMAND_DESCRIPTION,
5819
6510
  InteractiveSession,
6511
+ LANGUAGE_COMMAND_ARGUMENT_HINT,
6512
+ LANGUAGE_COMMAND_DESCRIPTION,
6513
+ MEMORY_COMMAND_ARGUMENT_HINT,
6514
+ MEMORY_COMMAND_DESCRIPTION,
6515
+ MEMORY_COMMAND_USAGE,
5820
6516
  MEMORY_INDEX_MAX_BYTES,
5821
6517
  MEMORY_INDEX_MAX_LINES,
6518
+ MODEL_COMMAND_ARGUMENT_HINT,
6519
+ MODEL_COMMAND_DESCRIPTION,
5822
6520
  MarketplaceClient,
6521
+ PERMISSIONS_COMMAND_DESCRIPTION,
6522
+ PERMISSION_MODE_ARGUMENT_HINT,
6523
+ PERMISSION_MODE_COMMAND_DESCRIPTION,
6524
+ PLUGIN_COMMAND_ARGUMENT_HINT,
6525
+ PLUGIN_COMMAND_DESCRIPTION,
5823
6526
  PluginCommandSource,
5824
6527
  PluginSettingsStore,
5825
6528
  ProjectMemoryStore,
5826
6529
  PromptExecutor,
6530
+ RECOMMENDED_RESPONSE_LANGUAGES,
6531
+ RELOAD_PLUGINS_COMMAND_DESCRIPTION,
6532
+ RENAME_COMMAND_DESCRIPTION,
6533
+ RENAME_COMMAND_USAGE,
6534
+ RESUME_COMMAND_DESCRIPTION,
6535
+ REWIND_COMMAND_ARGUMENT_HINT,
6536
+ REWIND_COMMAND_DESCRIPTION,
6537
+ STATUSLINE_COMMAND_ARGUMENT_HINT,
6538
+ STATUSLINE_COMMAND_DESCRIPTION,
5827
6539
  SkillCommandSource,
5828
6540
  SubagentManager,
5829
6541
  SystemCommandExecutor,
5830
6542
  TRUST_TO_MODE,
6543
+ VALID_PERMISSION_MODES,
5831
6544
  WorktreeSubagentRunner,
5832
6545
  assembleSubagentPrompt,
6546
+ buildBackgroundCommandSubcommands,
6547
+ buildLanguageCommandSubcommands,
6548
+ buildMemoryCommandSubcommands,
6549
+ buildModelCommandSubcommands,
6550
+ buildPermissionModeSubcommands,
6551
+ buildPluginCommandSubcommands,
6552
+ buildProviderProfile,
6553
+ buildProviderSetupPatch,
6554
+ buildRewindCommandSubcommands,
5833
6555
  buildSkillPrompt,
6556
+ buildStatusLineCommandSubcommands,
6557
+ cancelCommandBackgroundTask,
5834
6558
  chatEntryToMessage,
6559
+ clearConversationHistory,
6560
+ closeCommandBackgroundTask,
6561
+ compactCommandContext,
5835
6562
  createAgentTool,
5836
6563
  createBackgroundProcessTool,
6564
+ createBuiltinCommandModule,
5837
6565
  createCommandExecutionTool,
6566
+ createCommandMemoryStores,
6567
+ createCommandPendingMemoryStore,
6568
+ createCommandProjectMemoryStore,
5838
6569
  createDefaultTools,
6570
+ createPluginRegistryReloadRequestedEffect,
6571
+ createPluginTuiRequestedEffect,
6572
+ createProviderSetupFlow,
5839
6573
  createQuery,
6574
+ createSessionExitRequestedEffect,
6575
+ createSessionPickerRequestedEffect,
6576
+ createSessionRenamedEffect,
5840
6577
  createSubagentLogger,
5841
6578
  createSubagentSession,
5842
6579
  createSystemCommands,
5843
6580
  createWorktreeSubagentRunner,
5844
6581
  discoverTaskFiles,
5845
6582
  evaluatePermission,
6583
+ evaluateReversibleToolSafety,
5846
6584
  executeSkill,
6585
+ formatCommandBackgroundTask,
6586
+ formatCommandBackgroundTaskList,
6587
+ formatCommandHelpMessage,
6588
+ formatCommandPermissionsMessage,
6589
+ formatEnvReference,
6590
+ formatInvalidPermissionModeMessage,
6591
+ formatLanguageUsageMessage,
6592
+ formatProviderSetupChoiceLabel,
6593
+ formatProviderSetupPromptLabel,
6594
+ formatProviderSetupSelectionPrompt,
5847
6595
  formatTaskContext,
5848
6596
  getBackgroundTaskTransitions,
5849
6597
  getBuiltInAgent,
5850
6598
  getForkWorkerSuffix,
5851
6599
  getMessagesForAPI,
6600
+ getProviderSetupStep,
5852
6601
  getSubagentSuffix,
6602
+ hasSensitiveCommandMemoryContent,
6603
+ hasUsableSecretReference,
6604
+ inspectCommandEditCheckpoint,
5853
6605
  isChatEntry,
6606
+ isCommandMemoryType,
6607
+ isEnvReference,
5854
6608
  isMemoryType,
6609
+ isPermissionMode,
6610
+ isStatusLineCommandSettingsPatch,
5855
6611
  isTerminalBackgroundTaskStatus,
6612
+ listCommandBackgroundTasks,
6613
+ listCommandEditCheckpoints,
6614
+ listCommandSessionAllowedTools,
6615
+ listCommandUsedMemoryReferences,
5856
6616
  loadTaskContext,
6617
+ mergeProviderPatch,
5857
6618
  messageToHistoryEntry,
6619
+ parseCommandBackgroundLogCursor,
5858
6620
  parseFrontmatter,
6621
+ parseLanguageArgument,
6622
+ parsePermissionModeArgument,
6623
+ parseSessionNameArgument,
5859
6624
  parseTaskFile,
5860
6625
  planSelfHostingVerification,
5861
6626
  preprocessShellCommands,
6627
+ probeProviderProfile,
5862
6628
  projectPaths,
5863
6629
  promptForApproval,
6630
+ readAutoCompactThreshold,
6631
+ readAutoCompactThresholdSource,
6632
+ readCommandBackgroundTaskLog,
6633
+ readCommandContextState,
6634
+ readCommandPermissionMode,
6635
+ readCommandPermissionsState,
6636
+ readCommandSessionInfo,
5864
6637
  readCurrentGitBranch,
6638
+ recordCommandMemoryEvent,
6639
+ resetAutoCompactThresholdSetting,
6640
+ resolveEnvReference,
6641
+ resolvePermissionModeAdapter,
6642
+ resolvePluginCommandAdapter,
6643
+ resolveProviderSetupSelection,
5865
6644
  resolveSubagentLogDir,
6645
+ restoreCommandEditCheckpoint,
5866
6646
  retrieveAgentToolDeps,
6647
+ rollbackCommandEditCheckpoint,
5867
6648
  runHooks,
6649
+ runProviderSetupPromptFlow,
5868
6650
  selectRelevantTasks,
6651
+ setCommandAutoCompactThreshold,
6652
+ setCurrentProvider,
5869
6653
  storeAgentToolDeps,
6654
+ submitProviderSetupValue,
5870
6655
  substituteVariables,
5871
6656
  summarizeBackgroundJobGroup,
6657
+ testProviderProfileCommand,
5872
6658
  transitionBackgroundTaskStatus,
5873
6659
  transitionSelfHostingLoop,
5874
6660
  updateTaskFileStatus,
6661
+ upsertProviderProfile,
5875
6662
  userPaths,
5876
- wrapEditCheckpointTools
6663
+ validateProviderProfile,
6664
+ validateProviderSetupValue,
6665
+ wrapEditCheckpointTools,
6666
+ wrapReversibleExecutionTools,
6667
+ writeAutoCompactThresholdSetting,
6668
+ writeCommandPermissionMode
5877
6669
  });