@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.
@@ -31,6 +31,12 @@ var CommandRegistry = class {
31
31
  addSource(source) {
32
32
  this.sources.push(source);
33
33
  }
34
+ replaceSource(name, source) {
35
+ this.sources = this.sources.filter((candidate) => candidate.name !== name);
36
+ if (source !== void 0) {
37
+ this.sources.push(source);
38
+ }
39
+ }
34
40
  addModule(module) {
35
41
  for (const source of module.commandSources ?? []) {
36
42
  this.addSource(source);
@@ -71,138 +77,222 @@ var CommandRegistry = class {
71
77
  }
72
78
  };
73
79
 
74
- // src/commands/builtin-source.ts
75
- import { CLAUDE_MODELS, formatTokenCount } from "@robota-sdk/agent-core";
76
- function buildModelSubcommands() {
77
- const seen = /* @__PURE__ */ new Set();
78
- const commands = [];
79
- for (const model of Object.values(CLAUDE_MODELS)) {
80
- if (seen.has(model.name)) continue;
81
- seen.add(model.name);
82
- commands.push({
83
- name: model.id,
84
- description: `${model.name} (${formatTokenCount(model.contextWindow).toUpperCase()})`,
85
- source: "builtin"
86
- });
87
- }
88
- return commands;
89
- }
90
- function buildProviderSubcommands() {
91
- return [
92
- { name: "current", description: "Show current provider", source: "builtin" },
93
- { name: "list", description: "List provider profiles", source: "builtin" },
94
- { name: "use", description: "Switch provider profile", source: "builtin" },
95
- { name: "test", description: "Test provider profile", source: "builtin" }
96
- ];
97
- }
98
- function buildBackgroundSubcommands() {
99
- return [
100
- { name: "list", description: "List background tasks", source: "builtin" },
101
- { name: "read", description: "Read a background task log page", source: "builtin" },
102
- { name: "cancel", description: "Cancel a running background task", source: "builtin" },
103
- { name: "close", description: "Dismiss a terminal background task", source: "builtin" }
104
- ];
105
- }
106
- function buildRewindSubcommands() {
107
- return [
108
- { name: "list", description: "List edit checkpoints", source: "builtin" },
109
- { name: "restore", description: "Restore code to a checkpoint", source: "builtin" },
110
- { name: "code", description: "Restore code to a checkpoint", source: "builtin" }
111
- ];
112
- }
113
- function buildMemorySubcommands() {
114
- return [
115
- { name: "list", description: "List project memory topics", source: "builtin" },
116
- { name: "show", description: "Show project memory index or a topic", source: "builtin" },
117
- { name: "add", description: "Save durable project memory", source: "builtin" },
118
- { name: "pending", description: "List pending memory candidates", source: "builtin" },
119
- { name: "approve", description: "Approve a pending memory candidate", source: "builtin" },
120
- { name: "reject", description: "Reject a pending memory candidate", source: "builtin" },
121
- {
122
- name: "used",
123
- description: "Show memory references used in the current turn",
124
- source: "builtin"
80
+ // src/commands/system-command-executor.ts
81
+ var SystemCommandExecutor = class {
82
+ commands;
83
+ constructor(commands) {
84
+ this.commands = /* @__PURE__ */ new Map();
85
+ for (const cmd of commands ?? createSystemCommands()) {
86
+ this.commands.set(cmd.name, cmd);
125
87
  }
126
- ];
88
+ }
89
+ /** Register an additional command. */
90
+ register(command) {
91
+ this.commands.set(command.name, command);
92
+ }
93
+ /** Execute a command by name. Returns null if command not found. */
94
+ async execute(name, session, args) {
95
+ const cmd = this.getCommand(name);
96
+ if (!cmd) return null;
97
+ return await this.executeCommand(cmd, session, args);
98
+ }
99
+ getCommand(name) {
100
+ return this.commands.get(name);
101
+ }
102
+ async executeCommand(command, session, args) {
103
+ return await command.execute(session, args);
104
+ }
105
+ /** List all registered commands. */
106
+ listCommands() {
107
+ return [...this.commands.values()];
108
+ }
109
+ listModelInvocableCommands() {
110
+ return this.listCommands().filter((command) => command.modelInvocable === true).map((command) => ({
111
+ name: `/${command.name}`,
112
+ kind: "builtin-command",
113
+ description: command.description,
114
+ userInvocable: command.userInvocable !== false,
115
+ modelInvocable: true,
116
+ ...command.argumentHint ? { argumentHint: command.argumentHint } : {},
117
+ ...command.safety ? { safety: command.safety } : {}
118
+ }));
119
+ }
120
+ isModelInvocable(name) {
121
+ return this.commands.get(name)?.modelInvocable === true;
122
+ }
123
+ async executeModelInvocable(name, session, args) {
124
+ if (!this.isModelInvocable(name)) return null;
125
+ return this.execute(name, session, args);
126
+ }
127
+ /** Check if a command exists. */
128
+ hasCommand(name) {
129
+ return this.commands.has(name);
130
+ }
131
+ };
132
+
133
+ // src/commands/system-command.ts
134
+ function createSystemCommands() {
135
+ return [];
127
136
  }
128
- function createBuiltinCommands() {
129
- return [
130
- { name: "help", description: "Show available commands", source: "builtin" },
131
- { name: "clear", description: "Clear conversation history", source: "builtin" },
132
- {
133
- name: "mode",
134
- description: "Permission mode",
135
- source: "builtin",
136
- subcommands: [
137
- { name: "plan", description: "Plan only, no execution", source: "builtin" },
138
- { name: "default", description: "Ask before risky actions", source: "builtin" },
139
- { name: "acceptEdits", description: "Auto-approve file edits", source: "builtin" },
140
- { name: "bypassPermissions", description: "Skip all permission checks", source: "builtin" }
141
- ]
142
- },
143
- {
144
- name: "model",
145
- description: "Select AI model",
146
- source: "builtin",
147
- subcommands: buildModelSubcommands()
148
- },
149
- {
150
- name: "language",
151
- description: "Set response language",
152
- source: "builtin",
153
- subcommands: [
154
- { name: "ko", description: "Korean", source: "builtin" },
155
- { name: "en", description: "English", source: "builtin" },
156
- { name: "ja", description: "Japanese", source: "builtin" },
157
- { name: "zh", description: "Chinese", source: "builtin" }
158
- ]
159
- },
160
- { name: "compact", description: "Compress context window", source: "builtin" },
161
- { name: "cost", description: "Show session info", source: "builtin" },
162
- { name: "context", description: "Context window info", source: "builtin" },
163
- { name: "permissions", description: "Permission rules", source: "builtin" },
164
- {
165
- name: "memory",
166
- description: "Inspect, save, review, and audit project memory",
167
- source: "builtin",
168
- subcommands: buildMemorySubcommands()
169
- },
170
- {
171
- name: "rewind",
172
- description: "List and restore edit checkpoints",
173
- source: "builtin",
174
- subcommands: buildRewindSubcommands()
175
- },
176
- {
177
- name: "provider",
178
- description: "Manage provider profiles",
179
- source: "builtin",
180
- subcommands: buildProviderSubcommands()
181
- },
182
- { name: "resume", description: "Resume a previous session", source: "builtin" },
183
- {
184
- name: "background",
185
- description: "List and control background tasks",
186
- source: "builtin",
187
- subcommands: buildBackgroundSubcommands()
188
- },
189
- { name: "rename", description: "Rename the current session", source: "builtin" },
190
- { name: "plugin", description: "Manage plugins", source: "builtin" },
191
- { name: "reload-plugins", description: "Reload all plugin resources", source: "builtin" },
192
- { name: "reset", description: "Delete settings and exit", source: "builtin" },
193
- { name: "exit", description: "Exit CLI", source: "builtin" }
194
- ];
137
+
138
+ // src/commands/builtin-source.ts
139
+ function commandToPaletteEntry(command) {
140
+ return {
141
+ name: command.name,
142
+ description: command.description,
143
+ source: "builtin",
144
+ ...command.subcommands ? { subcommands: [...command.subcommands] } : {},
145
+ ...command.argumentHint ? { argumentHint: command.argumentHint } : {},
146
+ ...command.modelInvocable !== void 0 ? { modelInvocable: command.modelInvocable } : {},
147
+ ...command.userInvocable !== void 0 ? { userInvocable: command.userInvocable } : {},
148
+ ...command.safety ? { safety: command.safety } : {}
149
+ };
195
150
  }
196
151
  var BuiltinCommandSource = class {
197
152
  name = "builtin";
198
153
  commands;
199
- constructor() {
200
- this.commands = createBuiltinCommands();
154
+ constructor(systemCommands = createSystemCommands()) {
155
+ this.commands = systemCommands.map(commandToPaletteEntry);
201
156
  }
202
157
  getCommands() {
203
158
  return this.commands;
204
159
  }
205
160
  };
161
+ function createBuiltinCommandModule() {
162
+ const systemCommands = createSystemCommands();
163
+ return {
164
+ name: "sdk-builtin",
165
+ commandSources: [new BuiltinCommandSource(systemCommands)],
166
+ systemCommands
167
+ };
168
+ }
169
+
170
+ // src/command-api/provider/provider-command-probe.ts
171
+ import { findProviderDefinition as findProviderDefinition2 } from "@robota-sdk/agent-core";
172
+
173
+ // src/command-api/provider/provider-settings.ts
174
+ import { findProviderDefinition } from "@robota-sdk/agent-core";
175
+
176
+ // src/command-api/provider/provider-env-ref.ts
177
+ var ENV_REFERENCE_PREFIX = "$ENV:";
178
+ function isEnvReference(value) {
179
+ return value.startsWith(ENV_REFERENCE_PREFIX);
180
+ }
181
+ function formatEnvReference(name) {
182
+ return `${ENV_REFERENCE_PREFIX}${name}`;
183
+ }
184
+ function resolveEnvReference(value) {
185
+ if (!isEnvReference(value)) {
186
+ return value;
187
+ }
188
+ const envName = value.slice(ENV_REFERENCE_PREFIX.length).trim();
189
+ if (envName.length === 0) {
190
+ return void 0;
191
+ }
192
+ return process.env[envName];
193
+ }
194
+ function hasUsableSecretReference(value) {
195
+ if (value === void 0 || value.length === 0) {
196
+ return false;
197
+ }
198
+ return resolveEnvReference(value) !== void 0;
199
+ }
200
+
201
+ // src/command-api/provider/provider-settings.ts
202
+ function upsertProviderProfile(settings, profileName, profile) {
203
+ return {
204
+ ...settings,
205
+ providers: {
206
+ ...settings.providers ?? {},
207
+ [profileName]: profile
208
+ }
209
+ };
210
+ }
211
+ function setCurrentProvider(settings, profileName) {
212
+ if (!settings.providers?.[profileName]) {
213
+ throw new Error(`Provider profile "${profileName}" was not found`);
214
+ }
215
+ return {
216
+ ...settings,
217
+ currentProvider: profileName
218
+ };
219
+ }
220
+ function validateProviderProfile(profileName, profile, options = {}) {
221
+ if (!profile.type) {
222
+ throw new Error(`Provider profile "${profileName}" is missing type`);
223
+ }
224
+ if (!profile.model) {
225
+ throw new Error(`Provider profile "${profileName}" is missing model`);
226
+ }
227
+ const definition = findProviderDefinition(options.providerDefinitions ?? [], profile.type);
228
+ if (definition?.requiresApiKey === true && !hasUsableSecretReference(profile.apiKey ?? definition.defaults?.apiKey)) {
229
+ throw new Error(`Provider profile "${profileName}" is missing apiKey`);
230
+ }
231
+ }
232
+ function buildProviderSetupPatch(input, options = {}) {
233
+ const profile = buildProviderProfile(input, options);
234
+ validateProviderProfile(input.profile, profile, options);
235
+ return {
236
+ ...input.setCurrent && { currentProvider: input.profile },
237
+ providers: {
238
+ [input.profile]: profile
239
+ }
240
+ };
241
+ }
242
+ function buildProviderProfile(input, options = {}) {
243
+ const defaults = getProviderDefaults(input.type, options.providerDefinitions ?? []);
244
+ const apiKey = input.apiKeyEnv !== void 0 ? formatEnvReference(input.apiKeyEnv) : input.apiKey ?? defaults.apiKey;
245
+ const baseURL = input.baseURL ?? defaults.baseURL;
246
+ return {
247
+ type: input.type,
248
+ model: input.model ?? defaults.model,
249
+ ...apiKey !== void 0 && { apiKey },
250
+ ...baseURL !== void 0 && { baseURL },
251
+ ...input.timeout !== void 0 && { timeout: input.timeout }
252
+ };
253
+ }
254
+ function mergeProviderPatch(settings, patch) {
255
+ const [profileName, profile] = Object.entries(patch.providers)[0] ?? [];
256
+ if (!profileName || !profile) {
257
+ return settings;
258
+ }
259
+ const withProfile = upsertProviderProfile(settings, profileName, profile);
260
+ return patch.currentProvider ? setCurrentProvider(withProfile, patch.currentProvider) : withProfile;
261
+ }
262
+ function getProviderDefaults(type, providerDefinitions) {
263
+ return findProviderDefinition(providerDefinitions, type)?.defaults ?? {};
264
+ }
265
+
266
+ // src/command-api/provider/provider-command-probe.ts
267
+ async function testProviderProfileCommand(currentProvider, providers, profileArg, options) {
268
+ const profileName = profileArg ?? currentProvider;
269
+ if (!profileName) {
270
+ return { message: "No provider profile selected.", success: false };
271
+ }
272
+ const profile = providers?.[profileName];
273
+ if (!profile) {
274
+ return { message: `Provider profile "${profileName}" was not found.`, success: false };
275
+ }
276
+ try {
277
+ validateProviderProfile(profileName, profile, {
278
+ providerDefinitions: options.providerDefinitions
279
+ });
280
+ } catch (error) {
281
+ return { message: error instanceof Error ? error.message : String(error), success: false };
282
+ }
283
+ const definition = profile.type ? findProviderDefinition2(options.providerDefinitions, profile.type) : void 0;
284
+ const probe = definition?.probeProfile ?? probeProviderProfile;
285
+ const result = await probe(profile);
286
+ return {
287
+ message: result.ok ? `Provider "${profileName}" test passed: ${result.message}` : `Provider "${profileName}" test failed: ${result.message}; manual configuration can continue.`,
288
+ success: true,
289
+ data: { providerTest: { profile: profileName } }
290
+ };
291
+ }
292
+ async function probeProviderProfile(profile) {
293
+ void profile;
294
+ return { ok: true, message: "Profile fields are valid; no endpoint probe configured." };
295
+ }
206
296
 
207
297
  // src/commands/skill-source.ts
208
298
  import { readdirSync, readFileSync, existsSync } from "fs";
@@ -357,66 +447,523 @@ var PluginCommandSource = class {
357
447
  }
358
448
  };
359
449
 
360
- // src/commands/background-command.ts
450
+ // src/command-api/context/context-command-api.ts
451
+ import { AUTO_COMPACT_THRESHOLD } from "@robota-sdk/agent-sessions";
452
+ var DEFAULT_AUTO_COMPACT_THRESHOLD = AUTO_COMPACT_THRESHOLD;
453
+ var AUTO_COMPACT_THRESHOLD_SETTINGS_KEY = "autoCompactThreshold";
454
+ function readCommandContextState(context) {
455
+ return context.getContextState();
456
+ }
457
+ function readAutoCompactThreshold(context) {
458
+ return context.getAutoCompactThreshold();
459
+ }
460
+ function readAutoCompactThresholdSource(context) {
461
+ return context.getAutoCompactThresholdSource?.() ?? "session";
462
+ }
463
+ function setCommandAutoCompactThreshold(context, threshold, source) {
464
+ if (context.setAutoCompactThreshold) {
465
+ context.setAutoCompactThreshold(threshold, source);
466
+ return;
467
+ }
468
+ const session = context.getSession();
469
+ if (!session.setAutoCompactThreshold) {
470
+ throw new Error("Command host does not support changing auto-compact threshold.");
471
+ }
472
+ session.setAutoCompactThreshold(threshold);
473
+ }
474
+ function writeAutoCompactThresholdSetting(context, threshold) {
475
+ const settings = getSettingsAdapter(context);
476
+ if (!settings) return false;
477
+ settings.write({
478
+ ...settings.read(),
479
+ [AUTO_COMPACT_THRESHOLD_SETTINGS_KEY]: threshold
480
+ });
481
+ return true;
482
+ }
483
+ function resetAutoCompactThresholdSetting(context) {
484
+ const settings = getSettingsAdapter(context);
485
+ if (!settings) return false;
486
+ const next = { ...settings.read() };
487
+ delete next[AUTO_COMPACT_THRESHOLD_SETTINGS_KEY];
488
+ settings.write(next);
489
+ return true;
490
+ }
491
+ async function compactCommandContext(context, instructions) {
492
+ const before = readCommandContextState(context);
493
+ await context.compactContext(instructions);
494
+ const after = readCommandContextState(context);
495
+ return { before, after };
496
+ }
497
+ function getSettingsAdapter(context) {
498
+ return context.getCommandHostAdapters?.().settings;
499
+ }
500
+
501
+ // src/command-api/provider/provider-setup-flow.ts
502
+ import { findProviderDefinition as findProviderDefinition3, formatSupportedProviderTypes } from "@robota-sdk/agent-core";
503
+ function createProviderSetupFlow(type, providerDefinitions) {
504
+ return {
505
+ type,
506
+ steps: getProviderSetupSteps(type, providerDefinitions),
507
+ stepIndex: 0,
508
+ values: {}
509
+ };
510
+ }
511
+ function formatProviderSetupSelectionPrompt(providerDefinitions) {
512
+ if (providerDefinitions.length === 0) {
513
+ return " No providers are available.";
514
+ }
515
+ const lines = [
516
+ " Select provider:",
517
+ ...providerDefinitions.map(
518
+ (definition, index) => ` ${index + 1}. ${formatProviderSetupChoiceLabel(definition)}`
519
+ ),
520
+ ` Provider [1-${providerDefinitions.length}] (default: 1): `
521
+ ];
522
+ return lines.join("\n");
523
+ }
524
+ function resolveProviderSetupSelection(rawValue, providerDefinitions) {
525
+ const value = rawValue.trim();
526
+ const selectedValue = value.length > 0 ? value : "1";
527
+ const index = parseProviderSelectionIndex(selectedValue);
528
+ if (index !== void 0) {
529
+ const definition2 = providerDefinitions[index];
530
+ if (definition2 !== void 0) {
531
+ return definition2.type;
532
+ }
533
+ throw new Error(
534
+ `Provider selection ${selectedValue} is out of range. Currently supported: ${formatSupportedProviderTypes(providerDefinitions)}`
535
+ );
536
+ }
537
+ const definition = findProviderDefinition3(providerDefinitions, selectedValue);
538
+ if (definition === void 0) {
539
+ throw new Error(
540
+ `Unknown provider: ${selectedValue}. Currently supported: ${formatSupportedProviderTypes(providerDefinitions)}`
541
+ );
542
+ }
543
+ return definition.type;
544
+ }
545
+ function getProviderSetupStep(state) {
546
+ const step = state.steps[state.stepIndex];
547
+ if (step === void 0) {
548
+ throw new Error(`Provider setup step ${state.stepIndex} is out of range`);
549
+ }
550
+ return step;
551
+ }
552
+ function submitProviderSetupValue(state, rawValue) {
553
+ const step = getProviderSetupStep(state);
554
+ const value = rawValue.trim() || step.defaultValue || "";
555
+ const validationMessage = validateProviderSetupValue(step, value);
556
+ if (validationMessage !== void 0) {
557
+ return { status: "error", state, message: validationMessage };
558
+ }
559
+ const nextState = {
560
+ ...state,
561
+ stepIndex: state.stepIndex + 1,
562
+ values: { ...state.values, [step.key]: value }
563
+ };
564
+ if (nextState.stepIndex < state.steps.length) {
565
+ return { status: "next", state: nextState };
566
+ }
567
+ return { status: "complete", input: buildProviderSetupInput(nextState) };
568
+ }
569
+ async function runProviderSetupPromptFlow(type, promptInput, providerDefinitions) {
570
+ let state = createProviderSetupFlow(type, providerDefinitions);
571
+ const stepCount = state.steps.length;
572
+ while (state.stepIndex < stepCount) {
573
+ const step = getProviderSetupStep(state);
574
+ const value = await promptInput(formatProviderSetupPromptLabel(step), step.masked === true);
575
+ const result = submitProviderSetupValue(state, value);
576
+ if (result.status === "complete") {
577
+ return result.input;
578
+ }
579
+ if (result.status === "error") {
580
+ throw new Error(result.message);
581
+ }
582
+ state = result.state;
583
+ }
584
+ throw new Error("Provider setup flow ended without completion");
585
+ }
586
+ function formatProviderSetupPromptLabel(step) {
587
+ const suffix = step.defaultValue !== void 0 ? ` (default: ${step.defaultValue})` : "";
588
+ return ` ${step.title}${suffix}: `;
589
+ }
590
+ function formatProviderSetupChoiceLabel(definition) {
591
+ const label = definition.displayName !== void 0 ? `${definition.displayName} (${definition.type})` : definition.type;
592
+ return definition.description !== void 0 ? `${label} - ${definition.description}` : label;
593
+ }
594
+ function parseProviderSelectionIndex(value) {
595
+ if (!/^\d+$/.test(value)) {
596
+ return void 0;
597
+ }
598
+ return Number(value) - 1;
599
+ }
600
+ function validateProviderSetupValue(step, value) {
601
+ if (step.required === true && value.length === 0) {
602
+ return "Required";
603
+ }
604
+ return void 0;
605
+ }
606
+ function getProviderSetupSteps(type, providerDefinitions) {
607
+ const definition = findProviderDefinition3(providerDefinitions, type);
608
+ if (definition === void 0) {
609
+ throw new Error(
610
+ `Unknown provider: ${type}. Currently supported: ${formatSupportedProviderTypes(providerDefinitions)}`
611
+ );
612
+ }
613
+ if (definition.setupSteps !== void 0) {
614
+ return [...definition.setupSteps];
615
+ }
616
+ const steps = [
617
+ {
618
+ key: "model",
619
+ title: `${definition.type} model`,
620
+ defaultValue: definition.defaults?.model,
621
+ required: definition.defaults?.model === void 0
622
+ }
623
+ ];
624
+ if (definition.defaults?.baseURL !== void 0) {
625
+ steps.unshift({
626
+ key: "baseURL",
627
+ title: `${definition.type} base URL`,
628
+ defaultValue: definition.defaults.baseURL
629
+ });
630
+ }
631
+ if (definition.requiresApiKey === true) {
632
+ steps.push({
633
+ key: "apiKey",
634
+ title: `${definition.type} API key`,
635
+ defaultValue: definition.defaults?.apiKey,
636
+ required: definition.defaults?.apiKey === void 0,
637
+ masked: true
638
+ });
639
+ }
640
+ return steps;
641
+ }
642
+ function buildProviderSetupInput(state) {
643
+ return {
644
+ profile: state.type,
645
+ type: state.type,
646
+ model: state.values.model,
647
+ apiKey: state.values.apiKey,
648
+ ...state.values.baseURL !== void 0 && { baseURL: state.values.baseURL },
649
+ setCurrent: true
650
+ };
651
+ }
652
+
653
+ // src/command-api/help/help-command-api.ts
654
+ var HELP_COMMAND_DESCRIPTION = "Show available commands";
655
+ var HELP_COMMAND_NAME_COLUMN_WIDTH = 16;
656
+ function readCommandList(context) {
657
+ return context.listCommands?.() ?? [];
658
+ }
659
+ function formatCommandHelpMessage(context) {
660
+ const commands = readCommandList(context);
661
+ return [
662
+ "Available commands:",
663
+ ...commands.map(
664
+ (command) => ` ${command.name.padEnd(HELP_COMMAND_NAME_COLUMN_WIDTH)} \u2014 ${command.description}`
665
+ )
666
+ ].join("\n");
667
+ }
668
+
669
+ // src/command-api/background/background-command-api.ts
361
670
  var DECIMAL_RADIX = 10;
362
- function parseCommandParts(args) {
363
- return args.trim().split(/\s+/).filter(Boolean);
671
+ var INLINE_METADATA_LIMIT = 160;
672
+ var BACKGROUND_COMMAND_DESCRIPTION = "List and control background tasks";
673
+ var BACKGROUND_COMMAND_USAGE = "Usage: background list | background read <task-id> [offset] | background cancel <task-id> | background close <task-id>";
674
+ function buildBackgroundCommandSubcommands() {
675
+ return [
676
+ { name: "list", description: "List background tasks", source: "background" },
677
+ { name: "read", description: "Read a background task log page", source: "background" },
678
+ { name: "cancel", description: "Cancel a running background task", source: "background" },
679
+ { name: "close", description: "Dismiss a terminal background task", source: "background" }
680
+ ];
364
681
  }
365
- function formatBackgroundTask(task) {
682
+ function formatCommandBackgroundTask(task) {
366
683
  const preview = task.promptPreview ?? task.commandPreview ?? "";
367
684
  const unread = task.unread ? " unread" : "";
368
685
  const action = task.currentAction ? ` (${task.currentAction})` : "";
369
686
  const timeout = task.timeoutReason ? ` timeout=${task.timeoutReason}` : "";
370
687
  const activity = task.lastActivityAt ? ` lastActivityAt=${task.lastActivityAt}` : "";
688
+ const worktree = formatWorktreeMetadata(task);
371
689
  const suffix = preview ? ` \u2014 ${preview}` : "";
372
- return `${task.id} [${task.status}${unread}${timeout}${activity}] ${task.kind}:${task.label}${action}${suffix}`;
690
+ return `${task.id} [${task.status}${unread}${timeout}${activity}${worktree}] ${task.kind}:${task.label}${action}${suffix}`;
373
691
  }
374
- function formatBackgroundTaskList(tasks) {
692
+ function formatCommandBackgroundTaskList(tasks) {
375
693
  if (tasks.length === 0) return "No background tasks.";
376
- return ["Background tasks:", ...tasks.map((task) => ` ${formatBackgroundTask(task)}`)].join(
377
- "\n"
378
- );
694
+ return [
695
+ "Background tasks:",
696
+ ...tasks.map((task) => ` ${formatCommandBackgroundTask(task)}`)
697
+ ].join("\n");
379
698
  }
380
- function parseCursor(value) {
699
+ function parseCommandBackgroundLogCursor(value) {
381
700
  if (!value) return void 0;
382
701
  const offset = Number.parseInt(value, DECIMAL_RADIX);
383
702
  return Number.isNaN(offset) ? void 0 : { offset };
384
703
  }
385
- async function executeBackgroundCommand(session, args) {
386
- const [action = "list", taskId, ...reasonParts] = parseCommandParts(args);
387
- if (action === "list") {
388
- const tasks = session.listBackgroundTasks();
389
- return {
390
- message: formatBackgroundTaskList(tasks),
391
- success: true,
392
- data: { count: tasks.length }
393
- };
704
+ function formatWorktreeMetadata(task) {
705
+ const segments = [];
706
+ if (task.worktreePath) segments.push(`worktree=${task.worktreePath}`);
707
+ if (task.branchName) segments.push(`branch=${task.branchName}`);
708
+ if (task.worktreeStatus) {
709
+ segments.push(`worktreeStatus="${formatInlineMetadata(task.worktreeStatus)}"`);
394
710
  }
395
- if (!taskId) {
396
- return {
397
- message: "Usage: background list | background read <task-id> [offset] | background cancel <task-id> | background close <task-id>",
398
- success: false
399
- };
711
+ if (task.worktreeNextAction) {
712
+ segments.push(`next="${formatInlineMetadata(task.worktreeNextAction)}"`);
400
713
  }
401
- if (action === "read" || action === "log" || action === "open") {
402
- const page = await session.readBackgroundTaskLog(taskId, parseCursor(reasonParts[0]));
403
- const next = page.nextCursor ? `
404
- Next offset: ${page.nextCursor.offset}` : "";
405
- return {
406
- message: page.lines.length > 0 ? `${page.lines.join("\n")}${next}` : `No log lines: ${taskId}`,
407
- success: true,
408
- data: { taskId, nextOffset: page.nextCursor?.offset }
409
- };
714
+ if (segments.length === 0) return "";
715
+ return ` ${segments.join(" ")}`;
716
+ }
717
+ function formatInlineMetadata(value) {
718
+ const normalized = value.trim().replace(/\s+/g, " ");
719
+ return normalized.length > INLINE_METADATA_LIMIT ? `${normalized.slice(0, INLINE_METADATA_LIMIT)}...` : normalized;
720
+ }
721
+ function listCommandBackgroundTasks(context, filter) {
722
+ return context.listBackgroundTasks(filter);
723
+ }
724
+ function readCommandBackgroundTaskLog(context, taskId, cursor) {
725
+ return context.readBackgroundTaskLog(taskId, cursor);
726
+ }
727
+ function cancelCommandBackgroundTask(context, taskId, reason) {
728
+ return context.cancelBackgroundTask(taskId, reason);
729
+ }
730
+ function closeCommandBackgroundTask(context, taskId) {
731
+ return context.closeBackgroundTask(taskId);
732
+ }
733
+
734
+ // src/command-api/model/model-command-api.ts
735
+ import { CLAUDE_MODELS, formatTokenCount } from "@robota-sdk/agent-core";
736
+ var MODEL_COMMAND_DESCRIPTION = "Change AI model";
737
+ var MODEL_COMMAND_ARGUMENT_HINT = "<model-id>";
738
+ function buildModelCommandSubcommands(source = "model") {
739
+ const seen = /* @__PURE__ */ new Set();
740
+ const commands = [];
741
+ for (const model of Object.values(CLAUDE_MODELS)) {
742
+ if (seen.has(model.name)) continue;
743
+ seen.add(model.name);
744
+ commands.push({
745
+ name: model.id,
746
+ description: `${model.name} (${formatTokenCount(model.contextWindow).toUpperCase()})`,
747
+ source
748
+ });
749
+ }
750
+ return commands;
751
+ }
752
+
753
+ // src/command-api/language/language-command-api.ts
754
+ var LANGUAGE_COMMAND_DESCRIPTION = "Set response language";
755
+ var LANGUAGE_COMMAND_ARGUMENT_HINT = "<code>";
756
+ var RECOMMENDED_RESPONSE_LANGUAGES = [
757
+ { code: "ko", description: "Korean" },
758
+ { code: "en", description: "English" },
759
+ { code: "ja", description: "Japanese" },
760
+ { code: "zh", description: "Chinese" }
761
+ ];
762
+ function buildLanguageCommandSubcommands(source = "language") {
763
+ return RECOMMENDED_RESPONSE_LANGUAGES.map((language) => ({
764
+ name: language.code,
765
+ description: language.description,
766
+ source
767
+ }));
768
+ }
769
+ function parseLanguageArgument(args) {
770
+ const language = args.trim().split(/\s+/)[0];
771
+ return language !== void 0 && language.length > 0 ? language : void 0;
772
+ }
773
+ function formatLanguageUsageMessage(commandName = "language") {
774
+ return `Usage: ${commandName} <code> (e.g., ko, en, ja, zh)`;
775
+ }
776
+
777
+ // src/command-api/permissions/permission-mode-command-api.ts
778
+ var PERMISSION_MODE_COMMAND_DESCRIPTION = "Show/change permission mode";
779
+ var PERMISSION_MODE_ARGUMENT_HINT = "plan | default | acceptEdits | bypassPermissions";
780
+ var PERMISSIONS_COMMAND_DESCRIPTION = "Show permission rules";
781
+ var VALID_PERMISSION_MODES = [
782
+ "plan",
783
+ "default",
784
+ "acceptEdits",
785
+ "bypassPermissions"
786
+ ];
787
+ function buildPermissionModeSubcommands(source = "mode") {
788
+ return [
789
+ { name: "plan", description: "Plan only, no execution", source },
790
+ { name: "default", description: "Ask before risky actions", source },
791
+ { name: "acceptEdits", description: "Auto-approve file edits", source },
792
+ { name: "bypassPermissions", description: "Skip all permission checks", source }
793
+ ];
794
+ }
795
+ function parsePermissionModeArgument(args) {
796
+ const mode = args.trim().split(/\s+/)[0];
797
+ return mode !== void 0 && mode.length > 0 ? mode : void 0;
798
+ }
799
+ function isPermissionMode(value) {
800
+ return VALID_PERMISSION_MODES.includes(value);
801
+ }
802
+ function formatInvalidPermissionModeMessage() {
803
+ return `Invalid mode. Valid: ${VALID_PERMISSION_MODES.join(" | ")}`;
804
+ }
805
+ function resolvePermissionModeAdapter(context) {
806
+ const adapter = context.getCommandHostAdapters?.().permissionMode;
807
+ if (adapter !== void 0) {
808
+ return adapter;
809
+ }
810
+ const runtime = context.getSession();
811
+ return {
812
+ getPermissionMode: () => runtime.getPermissionMode(),
813
+ setPermissionMode: (mode) => runtime.setPermissionMode(mode),
814
+ listSessionAllowedTools: () => runtime.getSessionAllowedTools()
815
+ };
816
+ }
817
+ function readCommandPermissionMode(context) {
818
+ return resolvePermissionModeAdapter(context).getPermissionMode();
819
+ }
820
+ function writeCommandPermissionMode(context, mode) {
821
+ resolvePermissionModeAdapter(context).setPermissionMode(mode);
822
+ }
823
+ function listCommandSessionAllowedTools(context) {
824
+ return resolvePermissionModeAdapter(context).listSessionAllowedTools();
825
+ }
826
+ function readCommandPermissionsState(context) {
827
+ return {
828
+ mode: readCommandPermissionMode(context),
829
+ sessionAllowed: listCommandSessionAllowedTools(context)
830
+ };
831
+ }
832
+ function formatCommandPermissionsMessage(state) {
833
+ const lines = [`Permission mode: ${state.mode}`];
834
+ if (state.sessionAllowed.length > 0) {
835
+ lines.push(`Session-approved tools: ${state.sessionAllowed.join(", ")}`);
836
+ } else {
837
+ lines.push("No session-approved tools.");
410
838
  }
411
- if (action === "cancel" || action === "stop") {
412
- await session.cancelBackgroundTask(taskId, reasonParts.join(" ") || void 0);
413
- return { message: `Background task cancelled: ${taskId}`, success: true, data: { taskId } };
839
+ return lines.join("\n");
840
+ }
841
+
842
+ // src/command-api/statusline/statusline-command-api.ts
843
+ var STATUSLINE_COMMAND_DESCRIPTION = "Configure TUI status-line visibility and fields such as model, context, tokens, session, and git branch.";
844
+ var STATUSLINE_COMMAND_ARGUMENT_HINT = "on | off | reset | git on | git off";
845
+ var DEFAULT_STATUS_LINE_COMMAND_SETTINGS = {
846
+ enabled: true,
847
+ gitBranch: true
848
+ };
849
+ function buildStatusLineCommandSubcommands(source = "statusline") {
850
+ return [
851
+ { name: "on", description: "Show the status line", source },
852
+ { name: "off", description: "Hide the status line", source },
853
+ { name: "reset", description: "Restore default status-line fields", source },
854
+ { name: "git", description: "Show or hide git branch field", source }
855
+ ];
856
+ }
857
+ function isStatusLineCommandSettingsPatch(value) {
858
+ return (value.enabled === void 0 || typeof value.enabled === "boolean") && (value.gitBranch === void 0 || typeof value.gitBranch === "boolean");
859
+ }
860
+
861
+ // src/command-api/plugin/plugin-command-api.ts
862
+ var PLUGIN_COMMAND_DESCRIPTION = "Manage plugins";
863
+ var PLUGIN_COMMAND_ARGUMENT_HINT = "manage | install <name@marketplace> | uninstall <name@marketplace> | enable <name@marketplace> | disable <name@marketplace> | marketplace <action>";
864
+ var RELOAD_PLUGINS_COMMAND_DESCRIPTION = "Reload all plugin resources";
865
+ function createPluginTuiRequestedEffect() {
866
+ return { type: "plugin-tui-requested" };
867
+ }
868
+ function createPluginRegistryReloadRequestedEffect() {
869
+ return { type: "plugin-registry-reload-requested" };
870
+ }
871
+ function resolvePluginCommandAdapter(context) {
872
+ return context.getCommandHostAdapters?.().plugin;
873
+ }
874
+ function buildPluginCommandSubcommands() {
875
+ return [
876
+ { name: "manage", description: "Open plugin manager", source: "plugin-manager" },
877
+ { name: "install", description: "Install a plugin", source: "plugin-manager" },
878
+ { name: "uninstall", description: "Uninstall a plugin", source: "plugin-manager" },
879
+ { name: "enable", description: "Enable a plugin", source: "plugin-manager" },
880
+ { name: "disable", description: "Disable a plugin", source: "plugin-manager" },
881
+ {
882
+ name: "marketplace",
883
+ description: "Manage plugin marketplaces",
884
+ source: "plugin-manager",
885
+ subcommands: [
886
+ { name: "add", description: "Add marketplace source", source: "plugin-manager" },
887
+ { name: "remove", description: "Remove marketplace source", source: "plugin-manager" },
888
+ { name: "update", description: "Update marketplace source", source: "plugin-manager" },
889
+ { name: "list", description: "List marketplace sources", source: "plugin-manager" }
890
+ ]
891
+ }
892
+ ];
893
+ }
894
+
895
+ // src/command-api/session/session-command-api.ts
896
+ var CLEAR_COMMAND_DESCRIPTION = "Clear conversation history";
897
+ var RENAME_COMMAND_DESCRIPTION = "Rename the current session";
898
+ var RENAME_COMMAND_USAGE = "Usage: rename <name>";
899
+ var RESUME_COMMAND_DESCRIPTION = "Resume a previous session";
900
+ var COST_COMMAND_DESCRIPTION = "Show session info";
901
+ var EXIT_COMMAND_DESCRIPTION = "Exit CLI";
902
+ function clearConversationHistory(context) {
903
+ if (context.clearConversationHistory !== void 0) {
904
+ context.clearConversationHistory();
905
+ return;
414
906
  }
415
- if (action === "close" || action === "dismiss") {
416
- await session.closeBackgroundTask(taskId);
417
- return { message: `Background task closed: ${taskId}`, success: true, data: { taskId } };
907
+ context.getSession().clearHistory();
908
+ }
909
+ function parseSessionNameArgument(args) {
910
+ const name = args.trim();
911
+ return name.length > 0 ? name : void 0;
912
+ }
913
+ function createSessionRenamedEffect(name) {
914
+ return { type: "session-renamed", name };
915
+ }
916
+ function createSessionPickerRequestedEffect() {
917
+ return { type: "session-picker-requested" };
918
+ }
919
+ function createSessionExitRequestedEffect() {
920
+ return { type: "session-exit-requested" };
921
+ }
922
+ function readCommandSessionInfo(context) {
923
+ const session = context.getSession();
924
+ return {
925
+ sessionId: session.getSessionId(),
926
+ messageCount: session.getMessageCount()
927
+ };
928
+ }
929
+
930
+ // src/command-api/checkpoint/rewind-command-api.ts
931
+ var REWIND_COMMAND_DESCRIPTION = "List, inspect, restore, or rollback edit checkpoints.";
932
+ var REWIND_COMMAND_ARGUMENT_HINT = "list | inspect CHECKPOINT_ID | restore CHECKPOINT_ID | code CHECKPOINT_ID | rollback CHECKPOINT_ID";
933
+ function buildRewindCommandSubcommands(source = "rewind") {
934
+ return [
935
+ { name: "list", description: "List edit checkpoints", source },
936
+ { name: "inspect", description: "Inspect captured files and restore plans", source },
937
+ { name: "restore", description: "Restore code to a checkpoint", source },
938
+ { name: "code", description: "Restore code to a checkpoint", source },
939
+ { name: "rollback", description: "Rollback code through a checkpoint", source }
940
+ ];
941
+ }
942
+ function listCommandEditCheckpoints(context) {
943
+ return context.listEditCheckpoints();
944
+ }
945
+ function inspectCommandEditCheckpoint(context, checkpointId) {
946
+ if (!context.inspectEditCheckpoint) {
947
+ throw new Error("Checkpoint inspection is not available in this command host.");
418
948
  }
419
- return { message: `Unknown background action: ${action}`, success: false };
949
+ return context.inspectEditCheckpoint(checkpointId);
950
+ }
951
+ function restoreCommandEditCheckpoint(context, checkpointId) {
952
+ return context.restoreEditCheckpoint(checkpointId);
953
+ }
954
+ function rollbackCommandEditCheckpoint(context, checkpointId) {
955
+ return context.rollbackEditCheckpoint(checkpointId);
956
+ }
957
+
958
+ // src/memory/memory-policy-evaluator.ts
959
+ var SENSITIVE_PATTERNS = [
960
+ /\b(api[_-]?key|secret|token|password|private key)\b/i,
961
+ /\b\d{3}-\d{2}-\d{4}\b/,
962
+ /\b\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}\b/,
963
+ /주민등록|비밀번호|시크릿|토큰/u
964
+ ];
965
+ function containsSensitiveMemoryContent(text) {
966
+ return SENSITIVE_PATTERNS.some((pattern) => pattern.test(text));
420
967
  }
421
968
 
422
969
  // src/memory/pending-memory-store.ts
@@ -616,529 +1163,52 @@ var ProjectMemoryStore = class {
616
1163
  }
617
1164
  };
618
1165
 
619
- // src/memory/memory-policy-evaluator.ts
620
- var SENSITIVE_PATTERNS = [
621
- /\b(api[_-]?key|secret|token|password|private key)\b/i,
622
- /\b\d{3}-\d{2}-\d{4}\b/,
623
- /\b\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}\b/,
624
- /주민등록|비밀번호|시크릿|토큰/u
625
- ];
626
- function containsSensitiveMemoryContent(text) {
627
- return SENSITIVE_PATTERNS.some((pattern) => pattern.test(text));
628
- }
629
-
630
- // src/commands/memory-command.ts
631
- var SUBCOMMAND_INDEX = 0;
632
- var TYPE_INDEX = 1;
633
- var TOPIC_INDEX = 2;
634
- var TEXT_START_INDEX = 3;
635
- function usage() {
636
- return {
637
- 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",
638
- success: false
639
- };
640
- }
641
- function formatList(store) {
642
- const summary = store.list();
643
- const topics = summary.topics.length > 0 ? summary.topics.map((topic) => `- ${topic.name}: ${topic.path}`).join("\n") : "(none)";
644
- return {
645
- message: [
646
- `Memory index: ${summary.indexPath}`,
647
- `Topics directory: ${summary.topicsPath}`,
648
- "Topics:",
649
- topics
650
- ].join("\n"),
651
- success: true,
652
- data: {
653
- indexPath: summary.indexPath,
654
- topicsPath: summary.topicsPath,
655
- topicCount: summary.topics.length
1166
+ // src/command-api/memory/memory-command-api.ts
1167
+ 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.";
1168
+ var MEMORY_COMMAND_ARGUMENT_HINT = "list | show [topic] | add <user|feedback|project|reference> <topic> <text> | pending | approve <id> | reject <id> | used";
1169
+ 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";
1170
+ function buildMemoryCommandSubcommands(source = "memory") {
1171
+ return [
1172
+ { name: "list", description: "List project memory topics", source },
1173
+ { name: "show", description: "Show project memory index or a topic", source },
1174
+ { name: "add", description: "Save durable project memory", source },
1175
+ { name: "pending", description: "List pending memory candidates", source },
1176
+ { name: "approve", description: "Approve a pending memory candidate", source },
1177
+ { name: "reject", description: "Reject a pending memory candidate", source },
1178
+ {
1179
+ name: "used",
1180
+ description: "Show memory references used in the current turn",
1181
+ source
656
1182
  }
657
- };
658
- }
659
- function formatShow(store, topic) {
660
- if (!topic || topic === "index") {
661
- const memory = store.loadStartupMemory();
662
- return {
663
- message: memory.content || "(empty memory index)",
664
- success: true,
665
- data: {
666
- path: memory.path,
667
- lineCount: memory.lineCount,
668
- truncated: memory.truncated
669
- }
670
- };
671
- }
672
- const content = store.readTopic(topic);
673
- return {
674
- message: content || `(empty memory topic: ${topic})`,
675
- success: true,
676
- data: { topic }
677
- };
678
- }
679
- function parseAdd(args) {
680
- const type = args[TYPE_INDEX];
681
- const topic = args[TOPIC_INDEX];
682
- const text = args.slice(TEXT_START_INDEX).join(" ").trim();
683
- if (!type || !isMemoryType(type) || !topic || text.length === 0) return void 0;
684
- return { type, topic, text };
685
- }
686
- function formatPending(store) {
687
- const records = store.list("pending");
688
- const lines = records.length > 0 ? records.map(
689
- (record) => `- ${record.id} ${record.type}/${record.topic} confidence=${record.confidence}: ${record.text}`
690
- ) : ["(no pending memory candidates)"];
691
- return {
692
- message: ["Pending memory candidates:", ...lines].join("\n"),
693
- success: true,
694
- data: { count: records.length }
695
- };
696
- }
697
- function recordEvent(session, event) {
698
- session.recordMemoryEvent({
699
- ...event,
700
- at: (/* @__PURE__ */ new Date()).toISOString()
701
- });
702
- }
703
- function approvePending(session, pendingStore, memoryStore, id) {
704
- if (!id) return usage();
705
- try {
706
- const approved = pendingStore.mark(id, "approved", "approved-by-user");
707
- const saved = memoryStore.append(approved);
708
- const record = pendingStore.mark(id, "saved", "approved-and-saved");
709
- recordEvent(session, {
710
- type: "memory_candidate_approved",
711
- candidateId: record.id,
712
- topic: record.topic,
713
- reason: "approved-by-user"
714
- });
715
- recordEvent(session, {
716
- type: "memory_candidate_saved",
717
- candidateId: record.id,
718
- topic: record.topic,
719
- reason: saved.deduplicated ? "deduplicated" : "approved-and-saved"
720
- });
721
- return {
722
- message: saved.deduplicated ? `Saved memory candidate ${id} was already present in ${saved.topicPath}` : `Saved memory candidate ${id} to ${saved.topicPath}`,
723
- success: true,
724
- data: {
725
- id,
726
- status: record.status,
727
- topic: saved.topic,
728
- topicPath: saved.topicPath,
729
- deduplicated: saved.deduplicated
730
- }
731
- };
732
- } catch (error) {
733
- return {
734
- message: error instanceof Error ? error.message : String(error),
735
- success: false
736
- };
737
- }
738
- }
739
- function rejectPending(session, pendingStore, id) {
740
- if (!id) return usage();
741
- try {
742
- const record = pendingStore.mark(id, "rejected", "rejected-by-user");
743
- recordEvent(session, {
744
- type: "memory_candidate_rejected",
745
- candidateId: record.id,
746
- topic: record.topic,
747
- reason: "rejected-by-user"
748
- });
749
- return {
750
- message: `Rejected memory candidate ${id}`,
751
- success: true,
752
- data: { id, status: record.status }
753
- };
754
- } catch (error) {
755
- return {
756
- message: error instanceof Error ? error.message : String(error),
757
- success: false
758
- };
759
- }
1183
+ ];
760
1184
  }
761
- function formatUsed(session) {
762
- const references = session.getUsedMemoryReferences();
763
- const lines = references.length > 0 ? references.map((reference) => {
764
- const suffix = reference.truncated ? " truncated=true" : "";
765
- return `- ${reference.topic} score=${reference.score}${suffix}: ${reference.path}`;
766
- }) : ["(no memory used in current turn)"];
767
- return {
768
- message: ["Used memory references:", ...lines].join("\n"),
769
- success: true,
770
- data: { count: references.length, references }
771
- };
1185
+ function createCommandProjectMemoryStore(cwd, now) {
1186
+ return new ProjectMemoryStore(cwd, now);
772
1187
  }
773
- function executeMemoryCommand(session, rawArgs) {
774
- const args = rawArgs.trim().split(/\s+/).filter(Boolean);
775
- const subcommand = args[SUBCOMMAND_INDEX] ?? "list";
776
- const store = new ProjectMemoryStore(session.getCwd());
777
- const pendingStore = new PendingMemoryStore(session.getCwd());
778
- if (subcommand === "list") return formatList(store);
779
- if (subcommand === "show") return formatShow(store, args[TYPE_INDEX]);
780
- if (subcommand === "pending") return formatPending(pendingStore);
781
- if (subcommand === "approve")
782
- return approvePending(session, pendingStore, store, args[TYPE_INDEX]);
783
- if (subcommand === "reject") return rejectPending(session, pendingStore, args[TYPE_INDEX]);
784
- if (subcommand === "used") return formatUsed(session);
785
- if (subcommand === "add") {
786
- const input = parseAdd(args);
787
- if (!input) return usage();
788
- if (containsSensitiveMemoryContent(input.text)) {
789
- return {
790
- message: "Refusing to save sensitive memory content.",
791
- success: false
792
- };
793
- }
794
- const result = store.append(input);
795
- return {
796
- message: result.deduplicated ? `${input.type} memory already exists in ${result.topicPath}` : `Saved ${input.type} memory to ${result.topicPath}`,
797
- success: true,
798
- data: {
799
- indexPath: result.indexPath,
800
- topicPath: result.topicPath,
801
- topic: result.topic,
802
- deduplicated: result.deduplicated
803
- }
804
- };
805
- }
806
- return usage();
1188
+ function createCommandPendingMemoryStore(cwd, now) {
1189
+ return new PendingMemoryStore(cwd, now);
807
1190
  }
808
-
809
- // src/commands/rewind-command.ts
810
- var SUBCOMMAND_INDEX2 = 0;
811
- var CHECKPOINT_ID_INDEX = 1;
812
- var PROMPT_PREVIEW_LENGTH = 120;
813
- var ELLIPSIS_LENGTH = 3;
814
- function usage2() {
1191
+ function createCommandMemoryStores(context, now) {
1192
+ const cwd = context.getCwd();
815
1193
  return {
816
- message: "Usage: rewind [list] | rewind restore <checkpoint-id> | rewind code <checkpoint-id>",
817
- success: false
1194
+ project: createCommandProjectMemoryStore(cwd, now),
1195
+ pending: createCommandPendingMemoryStore(cwd, now)
818
1196
  };
819
1197
  }
820
- function formatPrompt(prompt) {
821
- const compact = prompt.replace(/\s+/g, " ").trim();
822
- if (compact.length <= PROMPT_PREVIEW_LENGTH) return compact;
823
- return `${compact.slice(0, PROMPT_PREVIEW_LENGTH - ELLIPSIS_LENGTH)}...`;
824
- }
825
- function formatList2(checkpoints) {
826
- const lines = checkpoints.length > 0 ? checkpoints.map(
827
- (checkpoint) => `- ${checkpoint.id} files=${checkpoint.fileCount} ${checkpoint.createdAt} ${formatPrompt(
828
- checkpoint.prompt
829
- )}`
830
- ) : ["(no edit checkpoints)"];
831
- return {
832
- message: ["Edit checkpoints:", ...lines].join("\n"),
833
- success: true,
834
- data: { count: checkpoints.length, checkpoints: [...checkpoints] }
835
- };
1198
+ function isCommandMemoryType(value) {
1199
+ return isMemoryType(value);
836
1200
  }
837
- async function restore(session, checkpointId) {
838
- if (!checkpointId) return usage2();
839
- try {
840
- const result = await session.restoreEditCheckpoint(checkpointId);
841
- return {
842
- message: [
843
- `Restored code to ${result.target.id}.`,
844
- `Restored files: ${result.restoredFileCount}`,
845
- `Rolled back checkpoints: ${result.restoredCheckpointCount}`
846
- ].join("\n"),
847
- success: true,
848
- data: {
849
- target: result.target,
850
- restoredCheckpointCount: result.restoredCheckpointCount,
851
- restoredFileCount: result.restoredFileCount,
852
- removedCheckpointCount: result.removedCheckpointCount
853
- }
854
- };
855
- } catch (error) {
856
- return {
857
- message: error instanceof Error ? error.message : String(error),
858
- success: false
859
- };
860
- }
1201
+ function hasSensitiveCommandMemoryContent(text) {
1202
+ return containsSensitiveMemoryContent(text);
861
1203
  }
862
- async function executeRewindCommand(session, rawArgs) {
863
- const args = rawArgs.trim().split(/\s+/).filter(Boolean);
864
- const subcommand = args[SUBCOMMAND_INDEX2] ?? "list";
865
- if (subcommand === "list") {
866
- return formatList2(session.listEditCheckpoints());
867
- }
868
- if (subcommand === "restore" || subcommand === "code") {
869
- return restore(session, args[CHECKPOINT_ID_INDEX]);
870
- }
871
- return usage2();
1204
+ function listCommandUsedMemoryReferences(context) {
1205
+ return context.getUsedMemoryReferences();
872
1206
  }
873
-
874
- // src/commands/system-command-executor.ts
875
- var SystemCommandExecutor = class {
876
- commands;
877
- constructor(commands) {
878
- this.commands = /* @__PURE__ */ new Map();
879
- for (const cmd of commands ?? createSystemCommands()) {
880
- this.commands.set(cmd.name, cmd);
881
- }
882
- }
883
- /** Register an additional command. */
884
- register(command) {
885
- this.commands.set(command.name, command);
886
- }
887
- /** Execute a command by name. Returns null if command not found. */
888
- async execute(name, session, args) {
889
- const cmd = this.commands.get(name);
890
- if (!cmd) return null;
891
- return await cmd.execute(session, args);
892
- }
893
- /** List all registered commands. */
894
- listCommands() {
895
- return [...this.commands.values()];
896
- }
897
- listModelInvocableCommands() {
898
- return this.listCommands().filter((command) => command.modelInvocable === true).map((command) => ({
899
- name: `/${command.name}`,
900
- kind: "builtin-command",
901
- description: command.description,
902
- userInvocable: command.userInvocable !== false,
903
- modelInvocable: true,
904
- ...command.argumentHint ? { argumentHint: command.argumentHint } : {},
905
- ...command.safety ? { safety: command.safety } : {}
906
- }));
907
- }
908
- isModelInvocable(name) {
909
- return this.commands.get(name)?.modelInvocable === true;
910
- }
911
- async executeModelInvocable(name, session, args) {
912
- if (!this.isModelInvocable(name)) return null;
913
- return this.execute(name, session, args);
914
- }
915
- /** Check if a command exists. */
916
- hasCommand(name) {
917
- return this.commands.has(name);
918
- }
919
- };
920
-
921
- // src/commands/system-command.ts
922
- var VALID_MODES = ["plan", "default", "acceptEdits", "bypassPermissions"];
923
- 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.";
924
- var MEMORY_COMMAND_ARGUMENT_HINT = "list | show [topic] | add <user|feedback|project|reference> <topic> <text> | pending | approve <id> | reject <id> | used";
925
- function createSystemCommands() {
926
- return [
927
- {
928
- name: "help",
929
- description: "Show available commands",
930
- execute: (_session, _args) => ({
931
- message: [
932
- "Available commands:",
933
- " help \u2014 Show this help",
934
- " clear \u2014 Clear conversation",
935
- " compact [instr] \u2014 Compact context (optional focus instructions)",
936
- " mode [m] \u2014 Show/change permission mode",
937
- " model <id> \u2014 Change AI model",
938
- " language <code> \u2014 Set response language (ko, en, ja, zh)",
939
- " cost \u2014 Show session info",
940
- " context \u2014 Context window info",
941
- " permissions \u2014 Permission rules",
942
- " memory \u2014 Manage project memory and pending candidates",
943
- " rewind \u2014 List or restore edit checkpoints",
944
- " provider \u2014 Provider profile status and switching",
945
- " resume \u2014 Resume a previous session",
946
- " background \u2014 List/cancel/close background tasks",
947
- " rename <name> \u2014 Rename the current session",
948
- " reset \u2014 Delete settings and exit"
949
- ].join("\n"),
950
- success: true
951
- })
952
- },
953
- {
954
- name: "clear",
955
- description: "Clear conversation history",
956
- execute: (session, _args) => {
957
- const underlying = session.getSession();
958
- underlying.clearHistory();
959
- return { message: "Conversation cleared.", success: true };
960
- }
961
- },
962
- {
963
- name: "compact",
964
- description: "Compress context window",
965
- execute: async (session, args) => {
966
- const underlying = session.getSession();
967
- const instructions = args.trim() || void 0;
968
- const before = underlying.getContextState().usedPercentage;
969
- await underlying.compact(instructions);
970
- const after = underlying.getContextState().usedPercentage;
971
- return {
972
- message: `Context compacted: ${Math.round(before)}% -> ${Math.round(after)}%`,
973
- success: true,
974
- data: { before, after }
975
- };
976
- }
977
- },
978
- {
979
- name: "mode",
980
- description: "Show/change permission mode",
981
- execute: (session, args) => {
982
- const underlying = session.getSession();
983
- const arg = args.trim().split(/\s+/)[0];
984
- if (!arg) {
985
- return {
986
- message: `Current mode: ${underlying.getPermissionMode()}`,
987
- success: true,
988
- data: { mode: underlying.getPermissionMode() }
989
- };
990
- }
991
- if (VALID_MODES.includes(arg)) {
992
- underlying.setPermissionMode(arg);
993
- return {
994
- message: `Permission mode set to: ${arg}`,
995
- success: true,
996
- data: { mode: arg }
997
- };
998
- }
999
- return {
1000
- message: `Invalid mode. Valid: ${VALID_MODES.join(" | ")}`,
1001
- success: false
1002
- };
1003
- }
1004
- },
1005
- {
1006
- name: "model",
1007
- description: "Change AI model",
1008
- execute: (_session, args) => {
1009
- const modelId = args.trim().split(/\s+/)[0];
1010
- if (!modelId) {
1011
- return { message: "Usage: model <model-id>", success: false };
1012
- }
1013
- return {
1014
- message: `Model change requested: ${modelId}`,
1015
- success: true,
1016
- data: { modelId }
1017
- };
1018
- }
1019
- },
1020
- {
1021
- name: "language",
1022
- description: "Set response language",
1023
- execute: (_session, args) => {
1024
- const lang = args.trim().split(/\s+/)[0];
1025
- if (!lang) {
1026
- return { message: "Usage: language <code> (e.g., ko, en, ja, zh)", success: false };
1027
- }
1028
- return {
1029
- message: `Language set to "${lang}".`,
1030
- success: true,
1031
- data: { language: lang }
1032
- };
1033
- }
1034
- },
1035
- {
1036
- name: "cost",
1037
- description: "Show session info",
1038
- execute: (session, _args) => {
1039
- const underlying = session.getSession();
1040
- const sessionId = underlying.getSessionId();
1041
- const messageCount = underlying.getMessageCount();
1042
- return {
1043
- message: `Session: ${sessionId}
1044
- Messages: ${messageCount}`,
1045
- success: true,
1046
- data: { sessionId, messageCount }
1047
- };
1048
- }
1049
- },
1050
- {
1051
- name: "context",
1052
- description: "Context window info",
1053
- execute: (session, _args) => {
1054
- const ctx = session.getContextState();
1055
- return {
1056
- message: `Context: ${ctx.usedTokens.toLocaleString()} / ${ctx.maxTokens.toLocaleString()} tokens (${Math.round(ctx.usedPercentage)}%)`,
1057
- success: true,
1058
- data: {
1059
- usedTokens: ctx.usedTokens,
1060
- maxTokens: ctx.maxTokens,
1061
- percentage: ctx.usedPercentage
1062
- }
1063
- };
1064
- }
1065
- },
1066
- {
1067
- name: "permissions",
1068
- description: "Show permission rules",
1069
- execute: (session, _args) => {
1070
- const underlying = session.getSession();
1071
- const mode = underlying.getPermissionMode();
1072
- const sessionAllowed = underlying.getSessionAllowedTools();
1073
- const lines = [`Permission mode: ${mode}`];
1074
- if (sessionAllowed.length > 0) {
1075
- lines.push(`Session-approved tools: ${sessionAllowed.join(", ")}`);
1076
- } else {
1077
- lines.push("No session-approved tools.");
1078
- }
1079
- return {
1080
- message: lines.join("\n"),
1081
- success: true,
1082
- data: { mode, sessionAllowed }
1083
- };
1084
- }
1085
- },
1086
- {
1087
- name: "memory",
1088
- description: MEMORY_COMMAND_DESCRIPTION,
1089
- modelInvocable: true,
1090
- argumentHint: MEMORY_COMMAND_ARGUMENT_HINT,
1091
- safety: "write",
1092
- execute: executeMemoryCommand
1093
- },
1094
- {
1095
- name: "rewind",
1096
- description: "List edit checkpoints or restore code to a previous checkpoint.",
1097
- argumentHint: "list | restore CHECKPOINT_ID | code CHECKPOINT_ID",
1098
- safety: "write",
1099
- execute: executeRewindCommand
1100
- },
1101
- {
1102
- name: "resume",
1103
- description: "Resume a previous session",
1104
- execute: (_session, _args) => ({
1105
- message: "Opening session picker...",
1106
- success: true,
1107
- data: { triggerResumePicker: true }
1108
- })
1109
- },
1110
- {
1111
- name: "background",
1112
- description: "List and control background tasks",
1113
- execute: executeBackgroundCommand
1114
- },
1115
- {
1116
- name: "rename",
1117
- description: "Rename the current session",
1118
- execute: (_session, args) => {
1119
- const name = args.trim();
1120
- if (!name) {
1121
- return { message: "Usage: rename <name>", success: false };
1122
- }
1123
- return {
1124
- message: `Session renamed to "${name}".`,
1125
- success: true,
1126
- data: { name }
1127
- };
1128
- }
1129
- },
1130
- {
1131
- name: "reset",
1132
- description: "Delete settings",
1133
- execute: (_session, _args) => {
1134
- return {
1135
- message: "Reset requested.",
1136
- success: true,
1137
- data: { resetRequested: true }
1138
- };
1139
- }
1140
- }
1141
- ];
1207
+ function recordCommandMemoryEvent(context, event, now = () => /* @__PURE__ */ new Date()) {
1208
+ context.recordMemoryEvent({
1209
+ ...event,
1210
+ at: now().toISOString()
1211
+ });
1142
1212
  }
1143
1213
 
1144
1214
  // src/utils/skill-prompt.ts
@@ -1470,15 +1540,149 @@ function createInProcessSubagentRunner(deps) {
1470
1540
  };
1471
1541
  }
1472
1542
 
1543
+ // src/tools/agent-tool-batch.ts
1544
+ function stringifyAgentBatchResult(input) {
1545
+ const successfulJobs = input.jobs.filter((job) => job.success);
1546
+ const agentIds = input.jobs.map((job) => job.agentId).filter((agentId) => typeof agentId === "string" && agentId.length > 0);
1547
+ const failedJobCount = input.jobs.filter((job) => !job.success).length;
1548
+ return JSON.stringify({
1549
+ success: input.jobs.every((job) => job.success),
1550
+ mode: "batch",
1551
+ output: successfulJobs.map((job) => job.output ?? "").filter(Boolean).join("\n\n"),
1552
+ groupId: input.groupId,
1553
+ requestedJobCount: input.requestedJobCount,
1554
+ startedJobCount: agentIds.length,
1555
+ failedJobCount,
1556
+ agentIds,
1557
+ jobs: input.jobs,
1558
+ provenance: {
1559
+ source: "agent-tool-batch",
1560
+ groupId: input.groupId,
1561
+ requestedJobCount: input.requestedJobCount,
1562
+ startedJobCount: agentIds.length,
1563
+ failedJobCount
1564
+ }
1565
+ });
1566
+ }
1567
+ function createBatchGroupId() {
1568
+ const idRadix = 36;
1569
+ const randomStartIndex = 2;
1570
+ const randomEndIndex = 10;
1571
+ return `agent_group_${Date.now()}_${Math.random().toString(idRadix).slice(randomStartIndex, randomEndIndex)}`;
1572
+ }
1573
+ function normalizeJobLabel(label, fallback) {
1574
+ const trimmed = label?.trim();
1575
+ return trimmed && trimmed.length > 0 ? trimmed : fallback;
1576
+ }
1577
+ function resolveBatchJob(job, index, input) {
1578
+ const agentType = job.subagent_type ?? "general-purpose";
1579
+ const agentDef = input.resolveAgentDefinition(agentType, input.deps.customAgentRegistry);
1580
+ const label = normalizeJobLabel(job.label, agentDef?.name ?? agentType);
1581
+ return { index, job, agentType, agentDef, label };
1582
+ }
1583
+ function isValidBatchJob(job) {
1584
+ return job.agentDef !== void 0;
1585
+ }
1586
+ function createUnknownAgentBatchResult(job, groupId) {
1587
+ return {
1588
+ index: job.index,
1589
+ success: false,
1590
+ groupId,
1591
+ label: job.label,
1592
+ subagent_type: job.agentType,
1593
+ prompt: job.job.prompt,
1594
+ error: `Unknown agent type: ${job.agentType}`
1595
+ };
1596
+ }
1597
+ async function spawnBatchJob(job, input) {
1598
+ try {
1599
+ const state = await input.manager.spawn(
1600
+ input.createSpawnRequest(job.job, job.agentType, job.agentDef, input.deps, job.label)
1601
+ );
1602
+ return { ...job, agentId: state.id };
1603
+ } catch (error) {
1604
+ const message = error instanceof Error ? error.message : String(error);
1605
+ return { ...job, spawnError: message };
1606
+ }
1607
+ }
1608
+ function createBatchSpawnErrorResult(job, groupId) {
1609
+ return {
1610
+ index: job.index,
1611
+ success: false,
1612
+ groupId,
1613
+ label: job.label,
1614
+ subagent_type: job.agentType,
1615
+ prompt: job.job.prompt,
1616
+ error: `Sub-agent error: ${job.spawnError ?? "missing agent id"}`
1617
+ };
1618
+ }
1619
+ function createBatchSuccessResult(job, groupId, result) {
1620
+ return {
1621
+ index: job.index,
1622
+ success: true,
1623
+ groupId,
1624
+ label: job.label,
1625
+ agentId: result.jobId,
1626
+ subagent_type: job.agentType,
1627
+ prompt: job.job.prompt,
1628
+ output: result.output,
1629
+ metadata: result.metadata
1630
+ };
1631
+ }
1632
+ function createBatchWaitErrorResult(job, groupId, message) {
1633
+ return {
1634
+ index: job.index,
1635
+ success: false,
1636
+ groupId,
1637
+ label: job.label,
1638
+ agentId: job.agentId,
1639
+ subagent_type: job.agentType,
1640
+ prompt: job.job.prompt,
1641
+ error: `Sub-agent error: ${message}`
1642
+ };
1643
+ }
1644
+ async function waitBatchJob(job, groupId, manager) {
1645
+ if (job.agentId === void 0) {
1646
+ return createBatchSpawnErrorResult(job, groupId);
1647
+ }
1648
+ try {
1649
+ const result = await manager.wait(job.agentId);
1650
+ return createBatchSuccessResult({ ...job, agentId: job.agentId }, groupId, result);
1651
+ } catch (error) {
1652
+ const message = error instanceof Error ? error.message : String(error);
1653
+ return createBatchWaitErrorResult({ ...job, agentId: job.agentId }, groupId, message);
1654
+ }
1655
+ }
1656
+ async function runManagedAgentBatch(input) {
1657
+ const groupId = createBatchGroupId();
1658
+ const resolvedJobs = input.jobs.map((job, index) => resolveBatchJob(job, index, input));
1659
+ const invalidJobs = resolvedJobs.filter((job) => !isValidBatchJob(job)).map((job) => createUnknownAgentBatchResult(job, groupId));
1660
+ const startedJobs = await Promise.all(
1661
+ resolvedJobs.filter(isValidBatchJob).map((job) => spawnBatchJob(job, input))
1662
+ );
1663
+ const terminalJobs = await Promise.all(
1664
+ startedJobs.map((job) => waitBatchJob(job, groupId, input.manager))
1665
+ );
1666
+ const batchJobs = [...invalidJobs, ...terminalJobs].sort(
1667
+ (left, right) => left.index - right.index
1668
+ );
1669
+ return stringifyAgentBatchResult({
1670
+ groupId,
1671
+ requestedJobCount: input.jobs.length,
1672
+ jobs: batchJobs
1673
+ });
1674
+ }
1675
+
1473
1676
  // src/tools/agent-tool.ts
1474
1677
  var AGENT_TOOL_DESCRIPTION = [
1475
1678
  "Creates delegated subagent jobs in isolated contexts.",
1476
1679
  "Without jobs, one tool call creates one subagent job from prompt.",
1477
- "For explicit multi-agent or parallel-agent requests, use one Agent tool call with jobs containing one entry per requested role.",
1680
+ "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.",
1478
1681
  "When the user explicitly asks to create, run, spawn, delegate to, or use agents/subagents, start the requested subagent job immediately.",
1479
1682
  "Do not ask a follow-up question unless execution is impossible or unsafe.",
1480
1683
  "Subagent jobs run as background tasks by default.",
1481
- "The tool waits for a terminal result and returns completed, failed, or timed-out outcome data to the parent conversation.",
1684
+ "The tool waits for a terminal result and returns completed, failed, or timed-out outcome data with structured requested/started job counts.",
1685
+ "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.",
1482
1686
  "Execution is represented by a real tool call and runtime background task event."
1483
1687
  ].join(" ");
1484
1688
  function createAgentToolPromptDescription(agentDefinitions = []) {
@@ -1486,10 +1690,11 @@ function createAgentToolPromptDescription(agentDefinitions = []) {
1486
1690
  return [
1487
1691
  "Agent \u2014 creates isolated subagent jobs.",
1488
1692
  "Without jobs, one Agent tool call corresponds to one subagent job.",
1489
- "For explicit multi-agent or parallel-agent requests, use one Agent tool call with jobs containing one entry per requested role.",
1693
+ "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.",
1490
1694
  "When the user explicitly asks to create, run, spawn, delegate to, or use agents/subagents, start the requested subagent job immediately.",
1491
1695
  "Do not ask a follow-up question unless execution is impossible or unsafe.",
1492
- "The tool returns terminal result data.",
1696
+ "The tool returns terminal result data with mode, requestedJobCount, startedJobCount, failedJobCount, and provenance.",
1697
+ "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.",
1493
1698
  "Runtime mode is background.",
1494
1699
  availableAgents
1495
1700
  ].join(" ").replace(/\s+/g, " ").trim();
@@ -1504,6 +1709,7 @@ var AgentSchema = z.object({
1504
1709
  isolation: z.enum(["none", "worktree"]).optional().describe('Optional runtime isolation mode. "worktree" runs in a Git worktree.'),
1505
1710
  jobs: z.array(
1506
1711
  z.object({
1712
+ label: z.string().optional().describe("Stable role label for this batch job"),
1507
1713
  prompt: z.string().describe("The task for this subagent to perform"),
1508
1714
  subagent_type: z.string().optional().describe("Agent type for this job"),
1509
1715
  model: z.string().optional().describe("Optional model override for this job"),
@@ -1532,10 +1738,10 @@ function createSubagentManager(deps) {
1532
1738
  runner: createInProcessSubagentRunner(deps)
1533
1739
  });
1534
1740
  }
1535
- function createSpawnRequest(args, agentType, agentDef, deps) {
1741
+ function createSpawnRequest(args, agentType, agentDef, deps, label = agentDef.name) {
1536
1742
  return {
1537
1743
  type: agentType,
1538
- label: agentDef.name,
1744
+ label,
1539
1745
  parentSessionId: deps.parentSessionId ?? "unknown-session",
1540
1746
  mode: "background",
1541
1747
  depth: deps.subagentDepth ?? 1,
@@ -1548,39 +1754,65 @@ function createSpawnRequest(args, agentType, agentDef, deps) {
1548
1754
  function stringifyUnknownAgentType(agentType) {
1549
1755
  return JSON.stringify({
1550
1756
  success: false,
1757
+ mode: "single",
1758
+ requestedJobCount: 1,
1759
+ startedJobCount: 0,
1760
+ failedJobCount: 1,
1551
1761
  output: "",
1552
- error: `Unknown agent type: ${agentType}`
1762
+ error: `Unknown agent type: ${agentType}`,
1763
+ provenance: {
1764
+ source: "agent-tool-single",
1765
+ requestedJobCount: 1,
1766
+ startedJobCount: 0,
1767
+ failedJobCount: 1
1768
+ }
1553
1769
  });
1554
1770
  }
1555
1771
  function stringifyAgentSuccess(result) {
1556
1772
  const worktreePath = result.metadata?.["worktreePath"];
1557
1773
  const branchName = result.metadata?.["branchName"];
1774
+ const worktreeStatus = result.metadata?.["worktreeStatus"];
1775
+ const worktreeNextAction = result.metadata?.["worktreeNextAction"];
1558
1776
  return JSON.stringify({
1559
1777
  success: true,
1778
+ mode: "single",
1779
+ requestedJobCount: 1,
1780
+ startedJobCount: 1,
1781
+ failedJobCount: 0,
1560
1782
  output: result.output,
1561
1783
  agentId: result.jobId,
1784
+ agentIds: [result.jobId],
1785
+ provenance: {
1786
+ source: "agent-tool-single",
1787
+ requestedJobCount: 1,
1788
+ startedJobCount: 1,
1789
+ failedJobCount: 0
1790
+ },
1562
1791
  metadata: result.metadata,
1563
1792
  ...typeof worktreePath === "string" ? { worktreePath } : {},
1564
- ...typeof branchName === "string" ? { branchName } : {}
1793
+ ...typeof branchName === "string" ? { branchName } : {},
1794
+ ...typeof worktreeStatus === "string" ? { worktreeStatus } : {},
1795
+ ...typeof worktreeNextAction === "string" ? { worktreeNextAction } : {}
1565
1796
  });
1566
1797
  }
1567
1798
  function stringifyAgentError(message, agentId) {
1799
+ const startedJobCount = agentId === void 0 ? 0 : 1;
1568
1800
  return JSON.stringify({
1569
1801
  success: false,
1802
+ mode: "single",
1803
+ requestedJobCount: 1,
1804
+ startedJobCount,
1805
+ failedJobCount: 1,
1570
1806
  output: "",
1571
1807
  error: `Sub-agent error: ${message}`,
1572
- agentId
1573
- });
1574
- }
1575
- function stringifyAgentBatchResult(input) {
1576
- const successfulJobs = input.jobs.filter((job) => job.success);
1577
- const agentIds = input.jobs.map((job) => job.agentId).filter((agentId) => typeof agentId === "string" && agentId.length > 0);
1578
- return JSON.stringify({
1579
- success: input.jobs.every((job) => job.success),
1580
- output: successfulJobs.map((job) => job.output ?? "").filter(Boolean).join("\n\n"),
1581
- groupId: input.groupId,
1582
- agentIds,
1583
- jobs: input.jobs
1808
+ agentId,
1809
+ ...agentId !== void 0 ? { agentIds: [agentId] } : {},
1810
+ provenance: {
1811
+ source: "agent-tool-single",
1812
+ requestedJobCount: 1,
1813
+ startedJobCount,
1814
+ failedJobCount: 1
1815
+ }
1584
1816
  });
1585
1817
  }
1586
1818
  async function runManagedAgent(args, deps, manager) {
@@ -1604,75 +1836,6 @@ async function runManagedAgent(args, deps, manager) {
1604
1836
  return stringifyAgentError(message, agentId);
1605
1837
  }
1606
1838
  }
1607
- function createBatchGroupId() {
1608
- return `agent_group_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
1609
- }
1610
- async function runManagedAgentBatch(jobs, deps, manager) {
1611
- const groupId = createBatchGroupId();
1612
- const resolvedJobs = jobs.map((job, index) => {
1613
- const agentType = job.subagent_type ?? "general-purpose";
1614
- const agentDef = resolveAgentDefinition2(agentType, deps.customAgentRegistry);
1615
- return { index, job, agentType, agentDef };
1616
- });
1617
- const invalidJobs = resolvedJobs.filter((job) => job.agentDef === void 0).map((job) => ({
1618
- index: job.index,
1619
- success: false,
1620
- subagent_type: job.agentType,
1621
- error: `Unknown agent type: ${job.agentType}`
1622
- }));
1623
- const validJobs = resolvedJobs.filter(
1624
- (job) => job.agentDef !== void 0
1625
- );
1626
- const startedJobs = await Promise.all(
1627
- validJobs.map(async (job) => {
1628
- try {
1629
- const state = await manager.spawn(
1630
- createSpawnRequest(job.job, job.agentType, job.agentDef, deps)
1631
- );
1632
- return { ...job, agentId: state.id, spawnError: void 0 };
1633
- } catch (error) {
1634
- const message = error instanceof Error ? error.message : String(error);
1635
- return { ...job, agentId: void 0, spawnError: message };
1636
- }
1637
- })
1638
- );
1639
- const terminalJobs = await Promise.all(
1640
- startedJobs.map(async (job) => {
1641
- if (job.spawnError || !job.agentId) {
1642
- return {
1643
- index: job.index,
1644
- success: false,
1645
- subagent_type: job.agentType,
1646
- error: `Sub-agent error: ${job.spawnError ?? "missing agent id"}`
1647
- };
1648
- }
1649
- try {
1650
- const result = await manager.wait(job.agentId);
1651
- return {
1652
- index: job.index,
1653
- success: true,
1654
- agentId: result.jobId,
1655
- subagent_type: job.agentType,
1656
- output: result.output,
1657
- metadata: result.metadata
1658
- };
1659
- } catch (error) {
1660
- const message = error instanceof Error ? error.message : String(error);
1661
- return {
1662
- index: job.index,
1663
- success: false,
1664
- agentId: job.agentId,
1665
- subagent_type: job.agentType,
1666
- error: `Sub-agent error: ${message}`
1667
- };
1668
- }
1669
- })
1670
- );
1671
- const batchJobs = [...invalidJobs, ...terminalJobs].sort(
1672
- (left, right) => left.index - right.index
1673
- );
1674
- return stringifyAgentBatchResult({ groupId, jobs: batchJobs });
1675
- }
1676
1839
  function createAgentTool(deps) {
1677
1840
  const manager = createSubagentManager(deps);
1678
1841
  return createZodFunctionTool(
@@ -1682,7 +1845,13 @@ function createAgentTool(deps) {
1682
1845
  async (params) => {
1683
1846
  const args = params;
1684
1847
  if (Array.isArray(args.jobs) && args.jobs.length > 0) {
1685
- return runManagedAgentBatch(args.jobs, deps, manager);
1848
+ return runManagedAgentBatch({
1849
+ jobs: args.jobs,
1850
+ deps,
1851
+ manager,
1852
+ resolveAgentDefinition: resolveAgentDefinition2,
1853
+ createSpawnRequest
1854
+ });
1686
1855
  }
1687
1856
  return runManagedAgent(
1688
1857
  {
@@ -1925,13 +2094,13 @@ function extractToolSummaries(history, historyBefore) {
1925
2094
  }
1926
2095
  function buildResult(response, sessionHistory, interactiveHistory, historyBefore, contextState) {
1927
2096
  const toolSummaries = extractToolSummaries(sessionHistory, historyBefore);
1928
- const usage3 = extractTurnUsage(sessionHistory, historyBefore, contextState);
2097
+ const usage = extractTurnUsage(sessionHistory, historyBefore, contextState);
1929
2098
  return {
1930
2099
  response,
1931
2100
  history: interactiveHistory,
1932
2101
  toolSummaries,
1933
2102
  contextState,
1934
- ...usage3 && { usage: usage3 }
2103
+ ...usage && { usage }
1935
2104
  };
1936
2105
  }
1937
2106
  function buildInterruptedResult(sessionHistory, interactiveHistory, historyBefore, contextState) {
@@ -1941,22 +2110,22 @@ function buildInterruptedResult(sessionHistory, interactiveHistory, historyBefor
1941
2110
  const msg = sessionHistory[i];
1942
2111
  if (msg?.role === "assistant" && msg.content) parts.push(msg.content);
1943
2112
  }
1944
- const usage3 = extractTurnUsage(sessionHistory, historyBefore, contextState);
2113
+ const usage = extractTurnUsage(sessionHistory, historyBefore, contextState);
1945
2114
  return {
1946
2115
  response: parts.join("\n\n"),
1947
2116
  history: interactiveHistory,
1948
2117
  toolSummaries,
1949
2118
  contextState,
1950
- ...usage3 && { usage: usage3 }
2119
+ ...usage && { usage }
1951
2120
  };
1952
2121
  }
1953
- function createUsageSummaryEntry(usage3) {
2122
+ function createUsageSummaryEntry(usage) {
1954
2123
  return {
1955
2124
  id: `usage_${randomUUID()}`,
1956
2125
  timestamp: /* @__PURE__ */ new Date(),
1957
2126
  category: "event",
1958
2127
  type: "usage-summary",
1959
- data: usage3
2128
+ data: usage
1960
2129
  };
1961
2130
  }
1962
2131
  function extractTurnUsage(sessionHistory, historyBefore, contextState) {
@@ -1966,11 +2135,11 @@ function extractTurnUsage(sessionHistory, historyBefore, contextState) {
1966
2135
  let foundUsage = false;
1967
2136
  for (const message of turnMessages) {
1968
2137
  if (message.role !== "assistant") continue;
1969
- const usage3 = collectAssistantUsageMetadata(message);
1970
- if (!usage3) continue;
2138
+ const usage = collectAssistantUsageMetadata(message);
2139
+ if (!usage) continue;
1971
2140
  foundUsage = true;
1972
- promptTokens += usage3.inputTokens;
1973
- completionTokens += usage3.outputTokens;
2141
+ promptTokens += usage.inputTokens;
2142
+ completionTokens += usage.outputTokens;
1974
2143
  }
1975
2144
  if (!foundUsage) return void 0;
1976
2145
  return {
@@ -2300,6 +2469,7 @@ var MarketplaceSourceSchema = z2.object({
2300
2469
  })
2301
2470
  });
2302
2471
  var ExtraKnownMarketplacesSchema = z2.record(MarketplaceSourceSchema).optional().catch(void 0);
2472
+ var AutoCompactThresholdSchema = z2.union([z2.number().gt(0).lte(1), z2.literal(false)]).optional();
2303
2473
  var SettingsSchema = z2.object({
2304
2474
  /** Trust level used when no --permission-mode flag is given */
2305
2475
  defaultTrustLevel: z2.enum(["safe", "moderate", "full"]).optional(),
@@ -2317,7 +2487,9 @@ var SettingsSchema = z2.object({
2317
2487
  /** Plugin enablement map: plugin name -> enabled/disabled */
2318
2488
  enabledPlugins: EnabledPluginsSchema,
2319
2489
  /** Extra marketplace URLs for BundlePlugin discovery */
2320
- extraKnownMarketplaces: ExtraKnownMarketplacesSchema
2490
+ extraKnownMarketplaces: ExtraKnownMarketplacesSchema,
2491
+ /** Auto-compact threshold as a 0-1 fraction. Set false to disable automatic compaction. */
2492
+ autoCompactThreshold: AutoCompactThresholdSchema
2321
2493
  });
2322
2494
 
2323
2495
  // src/config/config-loader.ts
@@ -2401,7 +2573,8 @@ function mergeSettings(layers) {
2401
2573
  },
2402
2574
  providers: merged.providers !== void 0 || layer.providers !== void 0 ? mergeProviders(merged.providers, layer.providers) : void 0,
2403
2575
  enabledPlugins: merged.enabledPlugins !== void 0 || layer.enabledPlugins !== void 0 ? { ...merged.enabledPlugins ?? {}, ...layer.enabledPlugins ?? {} } : void 0,
2404
- extraKnownMarketplaces: layer.extraKnownMarketplaces ?? merged.extraKnownMarketplaces
2576
+ extraKnownMarketplaces: layer.extraKnownMarketplaces ?? merged.extraKnownMarketplaces,
2577
+ autoCompactThreshold: layer.autoCompactThreshold ?? merged.autoCompactThreshold
2405
2578
  };
2406
2579
  }, {});
2407
2580
  }
@@ -2455,7 +2628,8 @@ function toResolvedConfig(merged) {
2455
2628
  env: merged.env ?? DEFAULTS.env,
2456
2629
  hooks: merged.hooks ?? void 0,
2457
2630
  enabledPlugins: merged.enabledPlugins ?? void 0,
2458
- extraKnownMarketplaces: merged.extraKnownMarketplaces ?? void 0
2631
+ extraKnownMarketplaces: merged.extraKnownMarketplaces ?? void 0,
2632
+ autoCompactThreshold: merged.autoCompactThreshold
2459
2633
  };
2460
2634
  }
2461
2635
  function getSettingsPaths(cwd) {
@@ -2794,7 +2968,8 @@ var DEFAULT_TOOL_DESCRIPTIONS = [
2794
2968
  "Edit \u2014 replace a string in a file",
2795
2969
  "Glob \u2014 find files matching a pattern",
2796
2970
  "Grep \u2014 search file contents with regex",
2797
- "WebSearch \u2014 search the internet (Anthropic built-in)"
2971
+ "WebFetch \u2014 fetch URL content as text",
2972
+ "WebSearch \u2014 search the internet through the configured local tool"
2798
2973
  ];
2799
2974
  function createDefaultTools() {
2800
2975
  return [
@@ -2960,6 +3135,200 @@ function extractFilePath(parameters) {
2960
3135
  return typeof value === "string" && value.length > 0 ? value : void 0;
2961
3136
  }
2962
3137
 
3138
+ // src/reversible-execution/reversible-execution-policy.ts
3139
+ var FILE_MUTATION_TOOLS = /* @__PURE__ */ new Set(["Write", "Edit"]);
3140
+ var HOST_SHELL_TOOLS = /* @__PURE__ */ new Set(["Bash", "BackgroundProcess"]);
3141
+ var READ_ONLY_TOOLS = /* @__PURE__ */ new Set(["Read", "Glob", "Grep", "WebFetch", "WebSearch"]);
3142
+ function evaluateReversibleToolSafety(input) {
3143
+ const toolName = input.toolName;
3144
+ if (READ_ONLY_TOOLS.has(toolName)) {
3145
+ return {
3146
+ toolName,
3147
+ reversible: true,
3148
+ sideEffect: "none",
3149
+ rollbackLayer: "none",
3150
+ status: "read-only",
3151
+ message: `${toolName} does not mutate the local workspace.`
3152
+ };
3153
+ }
3154
+ if (FILE_MUTATION_TOOLS.has(toolName)) {
3155
+ if (input.context.checkpointAvailable) {
3156
+ return {
3157
+ toolName,
3158
+ reversible: true,
3159
+ sideEffect: "file-mutation",
3160
+ rollbackLayer: "edit-checkpoint",
3161
+ status: "reversible",
3162
+ message: `${toolName} is reversible through the active edit checkpoint.`
3163
+ };
3164
+ }
3165
+ return {
3166
+ toolName,
3167
+ reversible: false,
3168
+ sideEffect: "file-mutation",
3169
+ rollbackLayer: "none",
3170
+ status: "requires-checkpoint",
3171
+ message: `${toolName} requires an edit checkpoint before file mutation.`
3172
+ };
3173
+ }
3174
+ if (HOST_SHELL_TOOLS.has(toolName)) {
3175
+ return evaluateIsolatedSideEffect(toolName, "shell-process", input.context);
3176
+ }
3177
+ if (toolName === "Agent") {
3178
+ return evaluateAgentSafety(input.toolArgs, input.context);
3179
+ }
3180
+ return {
3181
+ toolName,
3182
+ reversible: false,
3183
+ sideEffect: "unknown",
3184
+ rollbackLayer: "none",
3185
+ status: "unknown",
3186
+ message: `${toolName} has no reversible execution contract.`
3187
+ };
3188
+ }
3189
+ function wrapReversibleExecutionTools(tools, options) {
3190
+ const safetyContext = {
3191
+ checkpointAvailable: options.checkpointAvailable,
3192
+ isolation: options.isolation ?? "none"
3193
+ };
3194
+ const enforceUntrackedSideEffects = options.enforceUntrackedSideEffects ?? true;
3195
+ return tools.map(
3196
+ (tool) => new ReversibleExecutionToolWrapper(tool, {
3197
+ safetyContext,
3198
+ enforceUntrackedSideEffects
3199
+ })
3200
+ );
3201
+ }
3202
+ var ReversibleExecutionToolWrapper = class {
3203
+ constructor(delegate, options) {
3204
+ this.delegate = delegate;
3205
+ this.options = options;
3206
+ this.schema = delegate.schema;
3207
+ }
3208
+ schema;
3209
+ setEventService(eventService) {
3210
+ this.delegate.setEventService(eventService);
3211
+ }
3212
+ async execute(parameters, context) {
3213
+ const report = evaluateReversibleToolSafety({
3214
+ toolName: this.getName(),
3215
+ toolArgs: toToolArgs(parameters),
3216
+ context: this.options.safetyContext
3217
+ });
3218
+ if (!report.reversible && this.options.enforceUntrackedSideEffects) {
3219
+ return createBlockedResult(report);
3220
+ }
3221
+ return this.delegate.execute(parameters, context);
3222
+ }
3223
+ validate(parameters) {
3224
+ return this.delegate.validate(parameters);
3225
+ }
3226
+ validateParameters(parameters) {
3227
+ return this.delegate.validateParameters(parameters);
3228
+ }
3229
+ getDescription() {
3230
+ return this.delegate.getDescription();
3231
+ }
3232
+ getName() {
3233
+ return this.delegate.getName();
3234
+ }
3235
+ };
3236
+ function evaluateIsolatedSideEffect(toolName, sideEffect, context) {
3237
+ if (context.isolation === "worktree") {
3238
+ return {
3239
+ toolName,
3240
+ reversible: true,
3241
+ sideEffect,
3242
+ rollbackLayer: "worktree",
3243
+ status: "reversible",
3244
+ message: `${toolName} side effects are contained in an isolated Git worktree.`
3245
+ };
3246
+ }
3247
+ if (context.isolation === "provider-sandbox") {
3248
+ return {
3249
+ toolName,
3250
+ reversible: true,
3251
+ sideEffect,
3252
+ rollbackLayer: "provider-sandbox",
3253
+ status: "reversible",
3254
+ message: `${toolName} side effects are contained in a provider sandbox snapshot.`
3255
+ };
3256
+ }
3257
+ return {
3258
+ toolName,
3259
+ reversible: false,
3260
+ sideEffect,
3261
+ rollbackLayer: "none",
3262
+ status: "requires-isolation",
3263
+ message: `${toolName} can create host shell side effects that edit checkpoints cannot restore; use worktree or provider sandbox isolation.`
3264
+ };
3265
+ }
3266
+ function evaluateAgentSafety(toolArgs, context) {
3267
+ if (context.isolation === "worktree" || context.isolation === "provider-sandbox") {
3268
+ return evaluateIsolatedSideEffect("Agent", "subagent", context);
3269
+ }
3270
+ if (agentRequestUsesWorktree(toolArgs)) {
3271
+ return {
3272
+ toolName: "Agent",
3273
+ reversible: true,
3274
+ sideEffect: "subagent",
3275
+ rollbackLayer: "worktree",
3276
+ status: "reversible",
3277
+ message: "Agent jobs request worktree isolation, so shell side effects stay outside the parent workspace."
3278
+ };
3279
+ }
3280
+ return {
3281
+ toolName: "Agent",
3282
+ reversible: false,
3283
+ sideEffect: "subagent",
3284
+ rollbackLayer: "none",
3285
+ status: "requires-isolation",
3286
+ message: "Agent jobs must request worktree isolation to be reversible in local-first mode."
3287
+ };
3288
+ }
3289
+ function agentRequestUsesWorktree(toolArgs) {
3290
+ if (!toolArgs) return false;
3291
+ const jobs = toolArgs.jobs;
3292
+ if (Array.isArray(jobs)) {
3293
+ return jobs.length > 0 && jobs.every((job) => {
3294
+ if (!isToolArgRecord(job)) return false;
3295
+ return readIsolation(job) === "worktree";
3296
+ });
3297
+ }
3298
+ return readIsolation(toolArgs) === "worktree";
3299
+ }
3300
+ function readIsolation(value) {
3301
+ const isolation = value["isolation"];
3302
+ return typeof isolation === "string" ? isolation : void 0;
3303
+ }
3304
+ function isToolArgRecord(value) {
3305
+ return value !== void 0 && typeof value === "object" && !Array.isArray(value);
3306
+ }
3307
+ function toToolArgs(parameters) {
3308
+ if (!parameters || typeof parameters !== "object" || Array.isArray(parameters)) return void 0;
3309
+ return parameters;
3310
+ }
3311
+ function createBlockedResult(report) {
3312
+ return {
3313
+ success: true,
3314
+ data: {
3315
+ success: false,
3316
+ output: "",
3317
+ error: report.message,
3318
+ reversibleSafety: {
3319
+ toolName: report.toolName,
3320
+ sideEffect: report.sideEffect,
3321
+ rollbackLayer: report.rollbackLayer,
3322
+ status: report.status
3323
+ }
3324
+ },
3325
+ metadata: {
3326
+ reversibleSafetyStatus: report.status,
3327
+ rollbackLayer: report.rollbackLayer
3328
+ }
3329
+ };
3330
+ }
3331
+
2963
3332
  // src/assembly/create-session.ts
2964
3333
  import { BackgroundTaskManager as BackgroundTaskManager2, SubagentManager as SubagentManager2 } from "@robota-sdk/agent-runtime";
2965
3334
 
@@ -3131,7 +3500,11 @@ function createSession(options) {
3131
3500
  const cwd = options.cwd ?? process.cwd();
3132
3501
  const sessionId = options.sessionId ?? createSessionId();
3133
3502
  const defaultTools = options.editCheckpointRecorder ? wrapEditCheckpointTools(createDefaultTools(), options.editCheckpointRecorder) : createDefaultTools();
3134
- const tools = [...defaultTools, ...options.additionalTools ?? []];
3503
+ const assembledTools = [...defaultTools, ...options.additionalTools ?? []];
3504
+ const tools = options.reversibleExecution ? wrapReversibleExecutionTools(assembledTools, {
3505
+ ...options.reversibleExecution,
3506
+ checkpointAvailable: options.editCheckpointRecorder !== void 0
3507
+ }) : assembledTools;
3135
3508
  if (options.modelCommandExecutor && options.isModelCommandInvocable) {
3136
3509
  tools.push(
3137
3510
  createCommandExecutionTool({
@@ -3270,7 +3643,8 @@ ${options.appendSystemPrompt}` : systemMessage;
3270
3643
  allow: [...defaultAllow, ...options.config.permissions.allow ?? [], ...allowedToolPatterns],
3271
3644
  deny: options.config.permissions.deny ?? []
3272
3645
  };
3273
- const session = new Session2({
3646
+ const SessionWithAutoCompact = Session2;
3647
+ const session = new SessionWithAutoCompact({
3274
3648
  tools,
3275
3649
  provider,
3276
3650
  systemMessage: finalSystemMessage,
@@ -3290,7 +3664,9 @@ ${options.appendSystemPrompt}` : systemMessage;
3290
3664
  onToolExecution: options.onToolExecution,
3291
3665
  promptForApproval: options.promptForApproval,
3292
3666
  onCompact: options.onCompact,
3667
+ onCompactEvent: options.onCompactEvent,
3293
3668
  compactInstructions: options.compactInstructions ?? options.context.compactInstructions,
3669
+ autoCompactThreshold: options.autoCompactThreshold ?? options.config.autoCompactThreshold,
3294
3670
  sessionLogger: options.sessionLogger,
3295
3671
  hookTypeExecutors: hookTypeExecutors.length > 0 ? hookTypeExecutors : void 0
3296
3672
  });
@@ -4546,6 +4922,7 @@ async function createInteractiveSession(options) {
4546
4922
  provider: options.provider,
4547
4923
  onTextDelta: options.onTextDelta,
4548
4924
  onContextUpdate: options.onContextUpdate,
4925
+ onCompactEvent: options.onCompactEvent,
4549
4926
  onToolExecution: options.onToolExecution,
4550
4927
  sessionId,
4551
4928
  allowedTools: options.allowedTools,
@@ -4563,7 +4940,8 @@ async function createInteractiveSession(options) {
4563
4940
  } : {},
4564
4941
  modelCommandExecutor: options.modelCommandExecutor,
4565
4942
  isModelCommandInvocable: options.isModelCommandInvocable,
4566
- editCheckpointRecorder: options.editCheckpointRecorder
4943
+ editCheckpointRecorder: options.editCheckpointRecorder,
4944
+ reversibleExecution: options.reversibleExecution
4567
4945
  });
4568
4946
  }
4569
4947
  function injectSavedMessage(session, msg) {
@@ -4661,7 +5039,59 @@ function isRestoredTerminalStatus(status) {
4661
5039
  // src/checkpoints/edit-checkpoint-store.ts
4662
5040
  import { access, copyFile, mkdir, rename, rm, writeFile } from "fs/promises";
4663
5041
  import { constants, readdirSync as readdirSync7, readFileSync as readFileSync15 } from "fs";
4664
- import { dirname as dirname8, join as join17, relative as relative2, resolve as resolve3 } from "path";
5042
+ import { dirname as dirname8, join as join18, relative as relative3, resolve as resolve3 } from "path";
5043
+
5044
+ // src/checkpoints/edit-checkpoint-inspection.ts
5045
+ import { statSync as statSync2 } from "fs";
5046
+ import { join as join17, relative as relative2 } from "path";
5047
+ function buildEditCheckpointInspection(input) {
5048
+ const later = input.manifests.filter((manifest) => manifest.sequence > input.target.sequence);
5049
+ const rollbackRange = input.manifests.filter(
5050
+ (manifest) => manifest.sequence >= input.target.sequence
5051
+ );
5052
+ return {
5053
+ target: toSummary(input.target),
5054
+ capturedFiles: input.target.files.map((file) => {
5055
+ const snapshotPath = file.snapshotFile ? join17(input.checkpointDir(input.sessionId, input.target.id), file.snapshotFile) : void 0;
5056
+ const snapshotStats = snapshotPath ? statSafe(snapshotPath) : void 0;
5057
+ return {
5058
+ originalPath: file.originalPath,
5059
+ relativePath: relative2(input.cwd, file.originalPath),
5060
+ existed: file.existed,
5061
+ restoreAction: file.existed ? "restore-preimage" : "delete-created-file",
5062
+ snapshotAvailable: file.existed ? snapshotStats !== void 0 : false,
5063
+ ...snapshotStats ? { snapshotSizeBytes: snapshotStats.size } : {}
5064
+ };
5065
+ }),
5066
+ restoreToCheckpoint: toInspectionPlan(later),
5067
+ rollbackThroughCheckpoint: toInspectionPlan(rollbackRange)
5068
+ };
5069
+ }
5070
+ function toSummary(manifest) {
5071
+ return {
5072
+ id: manifest.id,
5073
+ sessionId: manifest.sessionId,
5074
+ sequence: manifest.sequence,
5075
+ prompt: manifest.prompt,
5076
+ createdAt: manifest.createdAt,
5077
+ fileCount: manifest.fileCount
5078
+ };
5079
+ }
5080
+ function toInspectionPlan(manifests) {
5081
+ return {
5082
+ checkpointIds: manifests.map((manifest) => manifest.id),
5083
+ fileCount: manifests.reduce((count, manifest) => count + manifest.fileCount, 0)
5084
+ };
5085
+ }
5086
+ function statSafe(path) {
5087
+ try {
5088
+ return statSync2(path);
5089
+ } catch {
5090
+ return void 0;
5091
+ }
5092
+ }
5093
+
5094
+ // src/checkpoints/edit-checkpoint-store.ts
4665
5095
  var MANIFEST_FILE = "manifest.json";
4666
5096
  var SNAPSHOT_DIR = "files";
4667
5097
  var ID_PAD = 4;
@@ -4682,8 +5112,8 @@ var EditCheckpointStore = class {
4682
5112
  }
4683
5113
  const nextSequence = this.nextSequence(input.sessionId);
4684
5114
  const id = `turn-${String(nextSequence).padStart(ID_PAD, "0")}`;
4685
- const dir = join17(this.sessionDir(input.sessionId), id);
4686
- await mkdir(join17(dir, SNAPSHOT_DIR), { recursive: true });
5115
+ const dir = join18(this.sessionDir(input.sessionId), id);
5116
+ await mkdir(join18(dir, SNAPSHOT_DIR), { recursive: true });
4687
5117
  const manifest = {
4688
5118
  version: 1,
4689
5119
  id,
@@ -4699,7 +5129,7 @@ var EditCheckpointStore = class {
4699
5129
  dir,
4700
5130
  capturedPaths: /* @__PURE__ */ new Set()
4701
5131
  };
4702
- return toSummary(manifest);
5132
+ return toSummary2(manifest);
4703
5133
  }
4704
5134
  async captureFile(filePath) {
4705
5135
  if (!this.activeTurn) return;
@@ -4716,10 +5146,24 @@ var EditCheckpointStore = class {
4716
5146
  const active = this.activeTurn;
4717
5147
  this.activeTurn = null;
4718
5148
  await this.writeManifest(active.dir, active.manifest);
4719
- return toSummary(active.manifest);
5149
+ return toSummary2(active.manifest);
4720
5150
  }
4721
5151
  list(sessionId) {
4722
- return this.loadManifests(sessionId).map(toSummary);
5152
+ return this.loadManifests(sessionId).map(toSummary2);
5153
+ }
5154
+ inspect(sessionId, checkpointId) {
5155
+ const manifests = this.loadManifests(sessionId);
5156
+ const target = manifests.find((manifest) => manifest.id === checkpointId);
5157
+ if (!target) {
5158
+ throw new Error(`Unknown edit checkpoint: ${checkpointId}`);
5159
+ }
5160
+ return buildEditCheckpointInspection({
5161
+ cwd: this.cwd,
5162
+ sessionId,
5163
+ target,
5164
+ manifests,
5165
+ checkpointDir: (inputSessionId, inputCheckpointId) => this.checkpointDir(inputSessionId, inputCheckpointId)
5166
+ });
4723
5167
  }
4724
5168
  async restoreToCheckpoint(sessionId, checkpointId) {
4725
5169
  const manifests = this.loadManifests(sessionId);
@@ -4739,12 +5183,36 @@ var EditCheckpointStore = class {
4739
5183
  await rm(this.checkpointDir(sessionId, manifest.id), { recursive: true, force: true });
4740
5184
  }
4741
5185
  return {
4742
- target: toSummary(target),
5186
+ target: toSummary2(target),
4743
5187
  restoredCheckpointCount: later.length,
4744
5188
  restoredFileCount,
4745
5189
  removedCheckpointCount: later.length
4746
5190
  };
4747
5191
  }
5192
+ async rollbackThroughCheckpoint(sessionId, checkpointId) {
5193
+ const manifests = this.loadManifests(sessionId);
5194
+ const target = manifests.find((manifest) => manifest.id === checkpointId);
5195
+ if (!target) {
5196
+ throw new Error(`Unknown edit checkpoint: ${checkpointId}`);
5197
+ }
5198
+ const rollbackRange = manifests.filter((manifest) => manifest.sequence >= target.sequence).sort((a, b) => b.sequence - a.sequence);
5199
+ let restoredFileCount = 0;
5200
+ for (const manifest of rollbackRange) {
5201
+ for (const file of manifest.files) {
5202
+ await this.restoreFile(sessionId, manifest.id, file);
5203
+ restoredFileCount += 1;
5204
+ }
5205
+ }
5206
+ for (const manifest of rollbackRange) {
5207
+ await rm(this.checkpointDir(sessionId, manifest.id), { recursive: true, force: true });
5208
+ }
5209
+ return {
5210
+ target: toSummary2(target),
5211
+ restoredCheckpointCount: rollbackRange.length,
5212
+ restoredFileCount,
5213
+ removedCheckpointCount: rollbackRange.length
5214
+ };
5215
+ }
4748
5216
  async createFileRecord(originalPath, active) {
4749
5217
  const existed = await pathExists(originalPath);
4750
5218
  if (!existed) {
@@ -4753,11 +5221,11 @@ var EditCheckpointStore = class {
4753
5221
  existed: false
4754
5222
  };
4755
5223
  }
4756
- const snapshotFile = join17(
5224
+ const snapshotFile = join18(
4757
5225
  SNAPSHOT_DIR,
4758
5226
  `${String(active.manifest.files.length + 1).padStart(SNAPSHOT_PAD, "0")}.content`
4759
5227
  );
4760
- await copyFile(originalPath, join17(active.dir, snapshotFile));
5228
+ await copyFile(originalPath, join18(active.dir, snapshotFile));
4761
5229
  return {
4762
5230
  originalPath,
4763
5231
  existed: true,
@@ -4774,13 +5242,13 @@ var EditCheckpointStore = class {
4774
5242
  }
4775
5243
  await mkdir(dirname8(record.originalPath), { recursive: true });
4776
5244
  await copyFile(
4777
- join17(this.checkpointDir(sessionId, checkpointId), record.snapshotFile),
5245
+ join18(this.checkpointDir(sessionId, checkpointId), record.snapshotFile),
4778
5246
  record.originalPath
4779
5247
  );
4780
5248
  }
4781
5249
  loadManifests(sessionId) {
4782
5250
  const dir = this.sessionDir(sessionId);
4783
- return readDirSyncSafe(dir).map((entry) => join17(dir, entry, MANIFEST_FILE)).map((manifestPath) => readJsonManifest(manifestPath)).filter((manifest) => manifest !== void 0).sort((a, b) => a.sequence - b.sequence);
5251
+ return readDirSyncSafe(dir).map((entry) => join18(dir, entry, MANIFEST_FILE)).map((manifestPath) => readJsonManifest(manifestPath)).filter((manifest) => manifest !== void 0).sort((a, b) => a.sequence - b.sequence);
4784
5252
  }
4785
5253
  nextSequence(sessionId) {
4786
5254
  const last = this.list(sessionId).at(-1);
@@ -4788,19 +5256,19 @@ var EditCheckpointStore = class {
4788
5256
  }
4789
5257
  async writeManifest(dir, manifest) {
4790
5258
  await mkdir(dir, { recursive: true });
4791
- const path = join17(dir, MANIFEST_FILE);
5259
+ const path = join18(dir, MANIFEST_FILE);
4792
5260
  const tmp = `${path}.tmp`;
4793
5261
  await writeFile(tmp, JSON.stringify(manifest, null, 2), "utf8");
4794
5262
  await rename(tmp, path);
4795
5263
  }
4796
5264
  sessionDir(sessionId) {
4797
- return join17(this.rootDir, safePathSegment(sessionId));
5265
+ return join18(this.rootDir, safePathSegment(sessionId));
4798
5266
  }
4799
5267
  checkpointDir(sessionId, checkpointId) {
4800
- return join17(this.sessionDir(sessionId), safePathSegment(checkpointId));
5268
+ return join18(this.sessionDir(sessionId), safePathSegment(checkpointId));
4801
5269
  }
4802
5270
  };
4803
- function toSummary(manifest) {
5271
+ function toSummary2(manifest) {
4804
5272
  return {
4805
5273
  id: manifest.id,
4806
5274
  sessionId: manifest.sessionId,
@@ -4814,7 +5282,7 @@ function safePathSegment(value) {
4814
5282
  return value.replace(/[^a-zA-Z0-9._-]/g, "_");
4815
5283
  }
4816
5284
  function isInside(parent, child) {
4817
- const rel = relative2(parent, child);
5285
+ const rel = relative3(parent, child);
4818
5286
  return rel.length === 0 || !rel.startsWith("..") && !rel.startsWith("/");
4819
5287
  }
4820
5288
  async function pathExists(path) {
@@ -4873,14 +5341,19 @@ var InteractiveSession = class {
4873
5341
  backgroundJobUnsubscribe = null;
4874
5342
  backgroundJobOrchestrator = null;
4875
5343
  commandModules;
5344
+ commandHostAdapters;
5345
+ autoCompactThresholdSource = "default";
4876
5346
  shuttingDown = false;
4877
5347
  shutdownPromise = null;
4878
5348
  constructor(options) {
4879
- this.commandModules = "commandModules" in options ? options.commandModules ?? [] : [];
4880
- this.commandExecutor = new SystemCommandExecutor([
4881
- ...createSystemCommands(),
4882
- ...this.commandModules.flatMap((module) => module.systemCommands ?? [])
4883
- ]);
5349
+ const sdkBuiltinModule = createBuiltinCommandModule();
5350
+ this.commandModules = [
5351
+ sdkBuiltinModule,
5352
+ ..."commandModules" in options ? options.commandModules ?? [] : []
5353
+ ];
5354
+ this.commandExecutor = new SystemCommandExecutor(
5355
+ this.commandModules.flatMap((module) => module.systemCommands ?? [])
5356
+ );
4884
5357
  this.sessionStore = options.sessionStore;
4885
5358
  this.sessionName = options.sessionName;
4886
5359
  this.cwd = ("cwd" in options ? options.cwd : void 0) ?? "";
@@ -4889,8 +5362,10 @@ var InteractiveSession = class {
4889
5362
  }
4890
5363
  this.resumeSessionId = options.resumeSessionId;
4891
5364
  this.forkSession = options.forkSession ?? false;
5365
+ this.commandHostAdapters = "commandHostAdapters" in options ? options.commandHostAdapters : void 0;
4892
5366
  if ("session" in options && options.session) {
4893
5367
  this.session = options.session;
5368
+ this.autoCompactThresholdSource = "session";
4894
5369
  this.initialized = true;
4895
5370
  } else {
4896
5371
  const stdOpts = options;
@@ -4917,7 +5392,8 @@ var InteractiveSession = class {
4917
5392
  if (this.initialized) this.persistCurrentSession();
4918
5393
  }
4919
5394
  async initializeAsync(options) {
4920
- const config = await loadConfig(options.cwd);
5395
+ const config = options.config ?? await loadConfig(options.cwd);
5396
+ this.autoCompactThresholdSource = config.autoCompactThreshold === void 0 ? "default" : "settings";
4921
5397
  this.editCheckpointStore = new EditCheckpointStore({ cwd: options.cwd });
4922
5398
  this.session = await createInteractiveSession({
4923
5399
  cwd: options.cwd,
@@ -4930,6 +5406,7 @@ var InteractiveSession = class {
4930
5406
  forkSession: this.forkSession,
4931
5407
  onTextDelta: (delta) => this.handleTextDelta(delta),
4932
5408
  onContextUpdate: (state) => this.emit("context_update", state),
5409
+ onCompactEvent: (event) => this.handleCompactEvent(event),
4933
5410
  onToolExecution: (event) => this.handleToolExecution(event),
4934
5411
  bare: options.bare,
4935
5412
  allowedTools: options.allowedTools,
@@ -4938,6 +5415,7 @@ var InteractiveSession = class {
4938
5415
  subagentRunnerFactory: options.subagentRunnerFactory,
4939
5416
  ...options.commandModules ? { commandModules: options.commandModules } : {},
4940
5417
  editCheckpointRecorder: this.editCheckpointStore,
5418
+ ...options.reversibleExecution ? { reversibleExecution: options.reversibleExecution } : {},
4941
5419
  commandDescriptors: this.commandExecutor.listModelInvocableCommands(),
4942
5420
  ...this.commandExecutor.listModelInvocableCommands().length > 0 ? {
4943
5421
  modelCommandExecutor: (command, args) => this.executeModelCommand(command, args),
@@ -4984,7 +5462,18 @@ var InteractiveSession = class {
4984
5462
  }
4985
5463
  async executeCommand(name, args) {
4986
5464
  await this.ensureInitialized();
4987
- return this.commandExecutor.execute(name, this, args);
5465
+ const command = this.commandExecutor.getCommand(name);
5466
+ if (!command) return null;
5467
+ if (this.executing) {
5468
+ return {
5469
+ success: false,
5470
+ message: "Another prompt or command is already running. Wait for it to finish."
5471
+ };
5472
+ }
5473
+ if (command.lifecycle === "blocking") {
5474
+ return this.executeForegroundCommand(command, args);
5475
+ }
5476
+ return this.commandExecutor.executeCommand(command, this, args);
4988
5477
  }
4989
5478
  async executeModelCommand(name, args) {
4990
5479
  await this.ensureInitialized();
@@ -5077,6 +5566,30 @@ var InteractiveSession = class {
5077
5566
  getContextState() {
5078
5567
  return this.getSessionOrThrow().getContextState();
5079
5568
  }
5569
+ getAutoCompactThreshold() {
5570
+ return this.getSessionOrThrow().getAutoCompactThreshold();
5571
+ }
5572
+ getAutoCompactThresholdSource() {
5573
+ return this.autoCompactThresholdSource;
5574
+ }
5575
+ setAutoCompactThreshold(threshold, source = "session") {
5576
+ this.getSessionOrThrow().setAutoCompactThreshold(threshold);
5577
+ this.autoCompactThresholdSource = source;
5578
+ this.emit("context_update", this.getContextState());
5579
+ this.persistCurrentSession();
5580
+ }
5581
+ getCommandHostAdapters() {
5582
+ return this.commandHostAdapters ?? {};
5583
+ }
5584
+ clearConversationHistory() {
5585
+ this.getSessionOrThrow().clearHistory();
5586
+ this.history = [];
5587
+ this.persistCurrentSession();
5588
+ this.emit("context_update", this.getContextState());
5589
+ }
5590
+ async compactContext(instructions) {
5591
+ await this.getSessionOrThrow().compact(instructions);
5592
+ }
5080
5593
  getName() {
5081
5594
  return this.sessionName;
5082
5595
  }
@@ -5090,6 +5603,10 @@ var InteractiveSession = class {
5090
5603
  const sessionId = this.getSessionOrThrow().getSessionId();
5091
5604
  return this.getEditCheckpointStore().list(sessionId);
5092
5605
  }
5606
+ inspectEditCheckpoint(checkpointId) {
5607
+ const sessionId = this.getSessionOrThrow().getSessionId();
5608
+ return this.getEditCheckpointStore().inspect(sessionId, checkpointId);
5609
+ }
5093
5610
  async restoreEditCheckpoint(checkpointId) {
5094
5611
  await this.ensureInitialized();
5095
5612
  if (this.executing) {
@@ -5105,6 +5622,21 @@ var InteractiveSession = class {
5105
5622
  this.persistCurrentSession();
5106
5623
  return result;
5107
5624
  }
5625
+ async rollbackEditCheckpoint(checkpointId) {
5626
+ await this.ensureInitialized();
5627
+ if (this.executing) {
5628
+ throw new Error("Cannot rollback edit checkpoint while a prompt is running.");
5629
+ }
5630
+ const result = await this.getEditCheckpointStore().rollbackThroughCheckpoint(
5631
+ this.getSessionOrThrow().getSessionId(),
5632
+ checkpointId
5633
+ );
5634
+ this.history.push(
5635
+ messageToHistoryEntry(createSystemMessage(`Rolled back edit checkpoint: ${checkpointId}`))
5636
+ );
5637
+ this.persistCurrentSession();
5638
+ return result;
5639
+ }
5108
5640
  getUsedMemoryReferences() {
5109
5641
  return [...this.usedMemoryReferences];
5110
5642
  }
@@ -5413,6 +5945,33 @@ var InteractiveSession = class {
5413
5945
  this.emit("complete", executionResult);
5414
5946
  this.emit("context_update", this.getContextState());
5415
5947
  }
5948
+ async executeForegroundCommand(command, args) {
5949
+ this.executing = true;
5950
+ this.clearStreaming();
5951
+ this.emit("thinking", true);
5952
+ try {
5953
+ const result = await this.commandExecutor.executeCommand(command, this, args);
5954
+ this.emit("context_update", this.getContextState());
5955
+ return result;
5956
+ } catch (err) {
5957
+ const errMsg = err instanceof Error ? err.message : String(err);
5958
+ return {
5959
+ success: false,
5960
+ message: `Error: ${errMsg}`
5961
+ };
5962
+ } finally {
5963
+ this.executing = false;
5964
+ this.emit("thinking", false);
5965
+ this.persistCurrentSession();
5966
+ if (!this.shuttingDown && this.pendingPrompt) {
5967
+ const queued = this.pendingPrompt;
5968
+ const queuedDisplay = this.pendingDisplayInput;
5969
+ const queuedRaw = this.pendingRawInput;
5970
+ this.clearPendingQueue();
5971
+ setTimeout(() => this.executePrompt(queued, queuedDisplay, queuedRaw), 0);
5972
+ }
5973
+ }
5974
+ }
5416
5975
  async executePrompt(input, displayInput, rawInput) {
5417
5976
  this.executing = true;
5418
5977
  this.clearStreaming();
@@ -5508,6 +6067,19 @@ var InteractiveSession = class {
5508
6067
  }, STREAMING_FLUSH_INTERVAL_MS);
5509
6068
  }
5510
6069
  }
6070
+ handleCompactEvent(event) {
6071
+ if (event.trigger === "auto") {
6072
+ this.history.push(
6073
+ messageToHistoryEntry(
6074
+ createSystemMessage(
6075
+ `Auto compacted context: ${Math.round(event.before.usedPercentage)}% -> ${Math.round(event.after.usedPercentage)}%`
6076
+ )
6077
+ )
6078
+ );
6079
+ }
6080
+ this.emit("compact", event);
6081
+ this.emit("context_update", event.after);
6082
+ }
5511
6083
  handleToolExecution(event) {
5512
6084
  const streamingState = { activeTools: this.activeTools, history: this.history };
5513
6085
  if (event.type === "start") {
@@ -5734,7 +6306,10 @@ async function promptForApproval(terminal, toolName, toolArgs) {
5734
6306
  // src/index.ts
5735
6307
  import { runHooks as runHooks2 } from "@robota-sdk/agent-core";
5736
6308
  export {
6309
+ AUTO_COMPACT_THRESHOLD_SETTINGS_KEY,
5737
6310
  AgentExecutor,
6311
+ BACKGROUND_COMMAND_DESCRIPTION,
6312
+ BACKGROUND_COMMAND_USAGE,
5738
6313
  BUILT_IN_AGENTS,
5739
6314
  BackgroundJobOrchestrator,
5740
6315
  BackgroundTaskError,
@@ -5742,64 +6317,171 @@ export {
5742
6317
  BuiltinCommandSource,
5743
6318
  BundlePluginInstaller,
5744
6319
  BundlePluginLoader,
6320
+ CLEAR_COMMAND_DESCRIPTION,
6321
+ COST_COMMAND_DESCRIPTION,
5745
6322
  CommandRegistry,
6323
+ DEFAULT_AUTO_COMPACT_THRESHOLD,
6324
+ DEFAULT_STATUS_LINE_COMMAND_SETTINGS,
6325
+ EXIT_COMMAND_DESCRIPTION,
5746
6326
  EditCheckpointStore,
6327
+ HELP_COMMAND_DESCRIPTION,
5747
6328
  InteractiveSession,
6329
+ LANGUAGE_COMMAND_ARGUMENT_HINT,
6330
+ LANGUAGE_COMMAND_DESCRIPTION,
6331
+ MEMORY_COMMAND_ARGUMENT_HINT,
6332
+ MEMORY_COMMAND_DESCRIPTION,
6333
+ MEMORY_COMMAND_USAGE,
5748
6334
  MEMORY_INDEX_MAX_BYTES,
5749
6335
  MEMORY_INDEX_MAX_LINES,
6336
+ MODEL_COMMAND_ARGUMENT_HINT,
6337
+ MODEL_COMMAND_DESCRIPTION,
5750
6338
  MarketplaceClient,
6339
+ PERMISSIONS_COMMAND_DESCRIPTION,
6340
+ PERMISSION_MODE_ARGUMENT_HINT,
6341
+ PERMISSION_MODE_COMMAND_DESCRIPTION,
6342
+ PLUGIN_COMMAND_ARGUMENT_HINT,
6343
+ PLUGIN_COMMAND_DESCRIPTION,
5751
6344
  PluginCommandSource,
5752
6345
  PluginSettingsStore,
5753
6346
  ProjectMemoryStore,
5754
6347
  PromptExecutor,
6348
+ RECOMMENDED_RESPONSE_LANGUAGES,
6349
+ RELOAD_PLUGINS_COMMAND_DESCRIPTION,
6350
+ RENAME_COMMAND_DESCRIPTION,
6351
+ RENAME_COMMAND_USAGE,
6352
+ RESUME_COMMAND_DESCRIPTION,
6353
+ REWIND_COMMAND_ARGUMENT_HINT,
6354
+ REWIND_COMMAND_DESCRIPTION,
6355
+ STATUSLINE_COMMAND_ARGUMENT_HINT,
6356
+ STATUSLINE_COMMAND_DESCRIPTION,
5755
6357
  SkillCommandSource,
5756
6358
  SubagentManager3 as SubagentManager,
5757
6359
  SystemCommandExecutor,
5758
6360
  TRUST_TO_MODE,
6361
+ VALID_PERMISSION_MODES,
5759
6362
  WorktreeSubagentRunner,
5760
6363
  assembleSubagentPrompt,
6364
+ buildBackgroundCommandSubcommands,
6365
+ buildLanguageCommandSubcommands,
6366
+ buildMemoryCommandSubcommands,
6367
+ buildModelCommandSubcommands,
6368
+ buildPermissionModeSubcommands,
6369
+ buildPluginCommandSubcommands,
6370
+ buildProviderProfile,
6371
+ buildProviderSetupPatch,
6372
+ buildRewindCommandSubcommands,
5761
6373
  buildSkillPrompt,
6374
+ buildStatusLineCommandSubcommands,
6375
+ cancelCommandBackgroundTask,
5762
6376
  chatEntryToMessage,
6377
+ clearConversationHistory,
6378
+ closeCommandBackgroundTask,
6379
+ compactCommandContext,
5763
6380
  createAgentTool,
5764
6381
  createBackgroundProcessTool,
6382
+ createBuiltinCommandModule,
5765
6383
  createCommandExecutionTool,
6384
+ createCommandMemoryStores,
6385
+ createCommandPendingMemoryStore,
6386
+ createCommandProjectMemoryStore,
5766
6387
  createDefaultTools,
6388
+ createPluginRegistryReloadRequestedEffect,
6389
+ createPluginTuiRequestedEffect,
6390
+ createProviderSetupFlow,
5767
6391
  createQuery,
6392
+ createSessionExitRequestedEffect,
6393
+ createSessionPickerRequestedEffect,
6394
+ createSessionRenamedEffect,
5768
6395
  createSubagentLogger,
5769
6396
  createSubagentSession,
5770
6397
  createSystemCommands,
5771
6398
  createWorktreeSubagentRunner,
5772
6399
  discoverTaskFiles,
5773
6400
  evaluatePermission,
6401
+ evaluateReversibleToolSafety,
5774
6402
  executeSkill,
6403
+ formatCommandBackgroundTask,
6404
+ formatCommandBackgroundTaskList,
6405
+ formatCommandHelpMessage,
6406
+ formatCommandPermissionsMessage,
6407
+ formatEnvReference,
6408
+ formatInvalidPermissionModeMessage,
6409
+ formatLanguageUsageMessage,
6410
+ formatProviderSetupChoiceLabel,
6411
+ formatProviderSetupPromptLabel,
6412
+ formatProviderSetupSelectionPrompt,
5775
6413
  formatTaskContext,
5776
6414
  getBackgroundTaskTransitions,
5777
6415
  getBuiltInAgent,
5778
6416
  getForkWorkerSuffix,
5779
6417
  getMessagesForAPI,
6418
+ getProviderSetupStep,
5780
6419
  getSubagentSuffix,
6420
+ hasSensitiveCommandMemoryContent,
6421
+ hasUsableSecretReference,
6422
+ inspectCommandEditCheckpoint,
5781
6423
  isChatEntry,
6424
+ isCommandMemoryType,
6425
+ isEnvReference,
5782
6426
  isMemoryType,
6427
+ isPermissionMode,
6428
+ isStatusLineCommandSettingsPatch,
5783
6429
  isTerminalBackgroundTaskStatus2 as isTerminalBackgroundTaskStatus,
6430
+ listCommandBackgroundTasks,
6431
+ listCommandEditCheckpoints,
6432
+ listCommandSessionAllowedTools,
6433
+ listCommandUsedMemoryReferences,
5784
6434
  loadTaskContext,
6435
+ mergeProviderPatch,
5785
6436
  messageToHistoryEntry2 as messageToHistoryEntry,
6437
+ parseCommandBackgroundLogCursor,
5786
6438
  parseFrontmatter,
6439
+ parseLanguageArgument,
6440
+ parsePermissionModeArgument,
6441
+ parseSessionNameArgument,
5787
6442
  parseTaskFile,
5788
6443
  planSelfHostingVerification,
5789
6444
  preprocessShellCommands,
6445
+ probeProviderProfile,
5790
6446
  projectPaths,
5791
6447
  promptForApproval,
6448
+ readAutoCompactThreshold,
6449
+ readAutoCompactThresholdSource,
6450
+ readCommandBackgroundTaskLog,
6451
+ readCommandContextState,
6452
+ readCommandPermissionMode,
6453
+ readCommandPermissionsState,
6454
+ readCommandSessionInfo,
5792
6455
  readCurrentGitBranch,
6456
+ recordCommandMemoryEvent,
6457
+ resetAutoCompactThresholdSetting,
6458
+ resolveEnvReference,
6459
+ resolvePermissionModeAdapter,
6460
+ resolvePluginCommandAdapter,
6461
+ resolveProviderSetupSelection,
5793
6462
  resolveSubagentLogDir,
6463
+ restoreCommandEditCheckpoint,
5794
6464
  retrieveAgentToolDeps,
6465
+ rollbackCommandEditCheckpoint,
5795
6466
  runHooks2 as runHooks,
6467
+ runProviderSetupPromptFlow,
5796
6468
  selectRelevantTasks,
6469
+ setCommandAutoCompactThreshold,
6470
+ setCurrentProvider,
5797
6471
  storeAgentToolDeps,
6472
+ submitProviderSetupValue,
5798
6473
  substituteVariables,
5799
6474
  summarizeBackgroundJobGroup,
6475
+ testProviderProfileCommand,
5800
6476
  transitionBackgroundTaskStatus,
5801
6477
  transitionSelfHostingLoop,
5802
6478
  updateTaskFileStatus,
6479
+ upsertProviderProfile,
5803
6480
  userPaths,
5804
- wrapEditCheckpointTools
6481
+ validateProviderProfile,
6482
+ validateProviderSetupValue,
6483
+ wrapEditCheckpointTools,
6484
+ wrapReversibleExecutionTools,
6485
+ writeAutoCompactThresholdSetting,
6486
+ writeCommandPermissionMode
5805
6487
  };