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

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.
@@ -1,4 +1,5 @@
1
1
  // src/interactive/interactive-session.ts
2
+ import { randomUUID as randomUUID4 } from "crypto";
2
3
  import {
3
4
  createUserMessage,
4
5
  createAssistantMessage,
@@ -15,7 +16,7 @@ function inferKind(command) {
15
16
  function commandToCapabilityDescriptor(command) {
16
17
  const skillLike = command.source === "skill" || command.source === "plugin" && Boolean(command.skillContent);
17
18
  return {
18
- name: `/${command.name}`,
19
+ name: command.name,
19
20
  kind: inferKind(command),
20
21
  description: command.description,
21
22
  userInvocable: command.userInvocable !== false,
@@ -108,7 +109,7 @@ var SystemCommandExecutor = class {
108
109
  }
109
110
  listModelInvocableCommands() {
110
111
  return this.listCommands().filter((command) => command.modelInvocable === true).map((command) => ({
111
- name: `/${command.name}`,
112
+ name: command.name,
112
113
  kind: "builtin-command",
113
114
  description: command.description,
114
115
  userInvocable: command.userInvocable !== false,
@@ -171,7 +172,7 @@ function createBuiltinCommandModule() {
171
172
  import { findProviderDefinition as findProviderDefinition2 } from "@robota-sdk/agent-core";
172
173
 
173
174
  // src/command-api/provider/provider-settings.ts
174
- import { findProviderDefinition } from "@robota-sdk/agent-core";
175
+ import { findProviderDefinition, getProviderCredentialRequirement } from "@robota-sdk/agent-core";
175
176
 
176
177
  // src/command-api/provider/provider-env-ref.ts
177
178
  var ENV_REFERENCE_PREFIX = "$ENV:";
@@ -217,6 +218,32 @@ function setCurrentProvider(settings, profileName) {
217
218
  currentProvider: profileName
218
219
  };
219
220
  }
221
+ function deleteProviderProfile(settings, profileName, options = {}) {
222
+ if (!settings.providers?.[profileName]) {
223
+ throw new Error(`Provider profile "${profileName}" was not found`);
224
+ }
225
+ const providers = { ...settings.providers };
226
+ delete providers[profileName];
227
+ if (options.replacementCurrentProvider !== void 0 && providers[options.replacementCurrentProvider] === void 0) {
228
+ throw new Error(`Provider profile "${options.replacementCurrentProvider}" was not found`);
229
+ }
230
+ const next = {
231
+ ...settings,
232
+ providers
233
+ };
234
+ if (settings.currentProvider !== profileName) {
235
+ return next;
236
+ }
237
+ if (options.replacementCurrentProvider !== void 0) {
238
+ return {
239
+ ...next,
240
+ currentProvider: options.replacementCurrentProvider
241
+ };
242
+ }
243
+ const withoutCurrentProvider = { ...next };
244
+ delete withoutCurrentProvider.currentProvider;
245
+ return withoutCurrentProvider;
246
+ }
220
247
  function validateProviderProfile(profileName, profile, options = {}) {
221
248
  if (!profile.type) {
222
249
  throw new Error(`Provider profile "${profileName}" is missing type`);
@@ -225,8 +252,11 @@ function validateProviderProfile(profileName, profile, options = {}) {
225
252
  throw new Error(`Provider profile "${profileName}" is missing model`);
226
253
  }
227
254
  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`);
255
+ const credentialRequirement = getProviderCredentialRequirement(definition);
256
+ if (credentialRequirement !== void 0 && !hasUsableRequiredProviderCredential(profile, definition?.defaults, credentialRequirement)) {
257
+ throw new Error(
258
+ `Provider profile "${profileName}" is missing ${formatCredentialRequirement(credentialRequirement)}`
259
+ );
230
260
  }
231
261
  }
232
262
  function buildProviderSetupPatch(input, options = {}) {
@@ -246,7 +276,7 @@ function buildProviderProfile(input, options = {}) {
246
276
  return {
247
277
  type: input.type,
248
278
  model: input.model ?? defaults.model,
249
- ...apiKey !== void 0 && { apiKey },
279
+ ...isNonEmptyString(apiKey) && { apiKey },
250
280
  ...baseURL !== void 0 && { baseURL },
251
281
  ...input.timeout !== void 0 && { timeout: input.timeout }
252
282
  };
@@ -262,6 +292,20 @@ function mergeProviderPatch(settings, patch) {
262
292
  function getProviderDefaults(type, providerDefinitions) {
263
293
  return findProviderDefinition(providerDefinitions, type)?.defaults ?? {};
264
294
  }
295
+ function hasUsableRequiredProviderCredential(profile, defaults, requirement) {
296
+ return requirement.anyOf.some(
297
+ (field) => hasUsableSecretReference(resolveProviderCredentialValue(field, profile, defaults))
298
+ );
299
+ }
300
+ function resolveProviderCredentialValue(field, profile, defaults) {
301
+ return profile[field] ?? defaults?.[field];
302
+ }
303
+ function formatCredentialRequirement(requirement) {
304
+ return requirement.anyOf.join(" or ");
305
+ }
306
+ function isNonEmptyString(value) {
307
+ return value !== void 0 && value.length > 0;
308
+ }
265
309
 
266
310
  // src/command-api/provider/provider-command-probe.ts
267
311
  async function testProviderProfileCommand(currentProvider, providers, profileArg, options) {
@@ -494,18 +538,64 @@ async function compactCommandContext(context, instructions) {
494
538
  const after = readCommandContextState(context);
495
539
  return { before, after };
496
540
  }
541
+ function listCommandContextReferences(context) {
542
+ return context.listContextReferences?.() ?? [];
543
+ }
544
+ async function addCommandContextReference(context, path) {
545
+ if (!context.addContextReference) {
546
+ return {
547
+ evicted: [],
548
+ diagnostics: ["Command host does not support context reference additions."]
549
+ };
550
+ }
551
+ return context.addContextReference(path);
552
+ }
553
+ function removeCommandContextReference(context, path) {
554
+ return context.removeContextReference?.(path) ?? {};
555
+ }
556
+ function clearCommandContextReferences(context) {
557
+ return context.clearContextReferences?.() ?? { removed: [] };
558
+ }
497
559
  function getSettingsAdapter(context) {
498
560
  return context.getCommandHostAdapters?.().settings;
499
561
  }
500
562
 
563
+ // src/command-api/provider/provider-profile-names.ts
564
+ var FALLBACK_PROFILE_NAME = "provider";
565
+ var FIRST_DUPLICATE_SUFFIX = 2;
566
+ function suggestProviderProfileName(input, options = {}) {
567
+ const baseName = sanitizeProviderProfileName(input.model) ?? sanitizeProviderProfileName(input.type) ?? FALLBACK_PROFILE_NAME;
568
+ const existing = new Set(options.existingProfileNames ?? []);
569
+ if (!existing.has(baseName)) {
570
+ return baseName;
571
+ }
572
+ let suffix = FIRST_DUPLICATE_SUFFIX;
573
+ while (existing.has(`${baseName}-${suffix}`)) {
574
+ suffix += 1;
575
+ }
576
+ return `${baseName}-${suffix}`;
577
+ }
578
+ function sanitizeProviderProfileName(value) {
579
+ const normalized = value?.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
580
+ return normalized !== void 0 && normalized.length > 0 ? normalized : void 0;
581
+ }
582
+
501
583
  // src/command-api/provider/provider-setup-flow.ts
502
584
  import { findProviderDefinition as findProviderDefinition3, formatSupportedProviderTypes } from "@robota-sdk/agent-core";
503
- function createProviderSetupFlow(type, providerDefinitions) {
585
+ function createProviderSetupFlow(type, providerDefinitions, options = {}) {
586
+ const definition = getProviderSetupDefinition(type, providerDefinitions);
504
587
  return {
505
588
  type,
506
- steps: getProviderSetupSteps(type, providerDefinitions),
589
+ steps: applyProviderSetupInitialValues(
590
+ getProviderSetupSteps(definition),
591
+ options.initialValues
592
+ ),
593
+ setupHelpLinks: definition.setupHelpLinks ?? [],
507
594
  stepIndex: 0,
508
- values: {}
595
+ values: {},
596
+ existingProfileNames: options.existingProfileNames ?? [],
597
+ ...options.profileName !== void 0 ? { profileName: options.profileName } : {},
598
+ ...options.setCurrent !== void 0 ? { setCurrent: options.setCurrent } : {}
509
599
  };
510
600
  }
511
601
  function formatProviderSetupSelectionPrompt(providerDefinitions) {
@@ -566,12 +656,15 @@ function submitProviderSetupValue(state, rawValue) {
566
656
  }
567
657
  return { status: "complete", input: buildProviderSetupInput(nextState) };
568
658
  }
569
- async function runProviderSetupPromptFlow(type, promptInput, providerDefinitions) {
570
- let state = createProviderSetupFlow(type, providerDefinitions);
659
+ async function runProviderSetupPromptFlow(type, promptInput, providerDefinitions, options = {}) {
660
+ let state = createProviderSetupFlow(type, providerDefinitions, options);
571
661
  const stepCount = state.steps.length;
572
662
  while (state.stepIndex < stepCount) {
573
663
  const step = getProviderSetupStep(state);
574
- const value = await promptInput(formatProviderSetupPromptLabel(step), step.masked === true);
664
+ const value = await promptInput(
665
+ formatProviderSetupPromptLabel(step, state.setupHelpLinks),
666
+ step.masked === true
667
+ );
575
668
  const result = submitProviderSetupValue(state, value);
576
669
  if (result.status === "complete") {
577
670
  return result.input;
@@ -583,14 +676,25 @@ async function runProviderSetupPromptFlow(type, promptInput, providerDefinitions
583
676
  }
584
677
  throw new Error("Provider setup flow ended without completion");
585
678
  }
586
- function formatProviderSetupPromptLabel(step) {
679
+ function formatProviderSetupPromptLabel(step, setupHelpLinks = []) {
587
680
  const suffix = step.defaultValue !== void 0 ? ` (default: ${step.defaultValue})` : "";
588
- return ` ${step.title}${suffix}: `;
681
+ const setupHelp = formatProviderSetupHelpLinks(setupHelpLinks);
682
+ const prefix = setupHelp.length > 0 ? `${setupHelp}
683
+ ` : "";
684
+ return `${prefix} ${step.title}${suffix}: `;
589
685
  }
590
686
  function formatProviderSetupChoiceLabel(definition) {
591
687
  const label = definition.displayName !== void 0 ? `${definition.displayName} (${definition.type})` : definition.type;
592
688
  return definition.description !== void 0 ? `${label} - ${definition.description}` : label;
593
689
  }
690
+ function formatProviderSetupHelpLinks(setupHelpLinks = []) {
691
+ if (setupHelpLinks.length === 0) {
692
+ return "";
693
+ }
694
+ return setupHelpLinks.map(
695
+ (link) => ` Setup help: ${formatProviderSetupHelpLinkKind(link.kind)}: ${link.label} - ${link.url}`
696
+ ).join("\n");
697
+ }
594
698
  function parseProviderSelectionIndex(value) {
595
699
  if (!/^\d+$/.test(value)) {
596
700
  return void 0;
@@ -603,13 +707,16 @@ function validateProviderSetupValue(step, value) {
603
707
  }
604
708
  return void 0;
605
709
  }
606
- function getProviderSetupSteps(type, providerDefinitions) {
710
+ function getProviderSetupDefinition(type, providerDefinitions) {
607
711
  const definition = findProviderDefinition3(providerDefinitions, type);
608
712
  if (definition === void 0) {
609
713
  throw new Error(
610
714
  `Unknown provider: ${type}. Currently supported: ${formatSupportedProviderTypes(providerDefinitions)}`
611
715
  );
612
716
  }
717
+ return definition;
718
+ }
719
+ function getProviderSetupSteps(definition) {
613
720
  if (definition.setupSteps !== void 0) {
614
721
  return [...definition.setupSteps];
615
722
  }
@@ -639,14 +746,44 @@ function getProviderSetupSteps(type, providerDefinitions) {
639
746
  }
640
747
  return steps;
641
748
  }
749
+ function formatProviderSetupHelpLinkKind(kind) {
750
+ if (kind === "api-key") {
751
+ return "API key";
752
+ }
753
+ if (kind === "console") {
754
+ return "Console";
755
+ }
756
+ return "Official";
757
+ }
758
+ function applyProviderSetupInitialValues(steps, initialValues) {
759
+ if (initialValues === void 0) {
760
+ return [...steps];
761
+ }
762
+ return steps.map((step) => {
763
+ const initialValue = initialValues[step.key];
764
+ if (initialValue === void 0) {
765
+ return step;
766
+ }
767
+ return {
768
+ ...step,
769
+ defaultValue: initialValue,
770
+ required: false
771
+ };
772
+ });
773
+ }
642
774
  function buildProviderSetupInput(state) {
775
+ const profile = state.profileName ?? suggestProviderProfileName(
776
+ { type: state.type, model: state.values.model },
777
+ { existingProfileNames: state.existingProfileNames }
778
+ );
779
+ const apiKey = state.values.apiKey;
643
780
  return {
644
- profile: state.type,
781
+ profile,
645
782
  type: state.type,
646
783
  model: state.values.model,
647
- apiKey: state.values.apiKey,
784
+ ...apiKey !== void 0 && apiKey.length > 0 && { apiKey },
648
785
  ...state.values.baseURL !== void 0 && { baseURL: state.values.baseURL },
649
- setCurrent: true
786
+ setCurrent: state.setCurrent ?? true
650
787
  };
651
788
  }
652
789
 
@@ -732,10 +869,74 @@ function closeCommandBackgroundTask(context, taskId) {
732
869
  }
733
870
 
734
871
  // src/command-api/model/model-command-api.ts
735
- import { CLAUDE_MODELS, formatTokenCount } from "@robota-sdk/agent-core";
872
+ import {
873
+ CLAUDE_MODELS,
874
+ findProviderDefinition as findProviderDefinition4,
875
+ formatTokenCount
876
+ } from "@robota-sdk/agent-core";
736
877
  var MODEL_COMMAND_DESCRIPTION = "Change AI model";
737
878
  var MODEL_COMMAND_ARGUMENT_HINT = "<model-id>";
738
- function buildModelCommandSubcommands(source = "model") {
879
+ function buildModelCommandSubcommands(sourceOrOptions = "model") {
880
+ const options = typeof sourceOrOptions === "string" ? { source: sourceOrOptions } : sourceOrOptions;
881
+ const source = options.source ?? "model";
882
+ const catalog = resolveActiveProviderModelCatalog(options.settings, options.providerDefinitions);
883
+ if (catalog !== void 0) {
884
+ return buildCatalogSubcommands(catalog, source);
885
+ }
886
+ if (options.settings !== void 0) {
887
+ return [];
888
+ }
889
+ return buildClaudeModelSubcommands(source);
890
+ }
891
+ function formatModelCommandUsageMessage(options = {}) {
892
+ const snapshot = resolveActiveProviderModelCatalogSnapshot(
893
+ options.settings,
894
+ options.providerDefinitions
895
+ );
896
+ return formatModelUsageMessage(snapshot === void 0 ? void 0 : toCatalogState(snapshot));
897
+ }
898
+ async function formatModelCommandUsageMessageAsync(options = {}) {
899
+ return formatModelUsageMessage(await resolveActiveProviderModelCatalogState(options));
900
+ }
901
+ function resolveActiveProviderModelCatalog(settings, providerDefinitions = []) {
902
+ return resolveActiveProviderModelCatalogSnapshot(settings, providerDefinitions)?.catalog;
903
+ }
904
+ async function resolveActiveProviderModelCatalogState(options) {
905
+ const snapshot = resolveActiveProviderModelCatalogSnapshot(
906
+ options.settings,
907
+ options.providerDefinitions
908
+ );
909
+ if (snapshot === void 0) return void 0;
910
+ if (options.refresh !== true || snapshot.definition?.refreshModelCatalog === void 0) {
911
+ return toCatalogState(snapshot);
912
+ }
913
+ try {
914
+ const refreshed = await snapshot.definition.refreshModelCatalog({
915
+ profile: resolveRefreshProfile(snapshot)
916
+ });
917
+ if (refreshed.status !== "unavailable") {
918
+ return {
919
+ providerType: snapshot.providerType,
920
+ catalog: refreshed,
921
+ refreshAttempted: true
922
+ };
923
+ }
924
+ return {
925
+ providerType: snapshot.providerType,
926
+ catalog: snapshot.catalog ?? refreshed,
927
+ refreshAttempted: true,
928
+ ...refreshed.message !== void 0 ? { refreshMessage: refreshed.message } : {}
929
+ };
930
+ } catch (error) {
931
+ return {
932
+ providerType: snapshot.providerType,
933
+ ...snapshot.catalog !== void 0 ? { catalog: snapshot.catalog } : {},
934
+ refreshAttempted: true,
935
+ refreshMessage: error instanceof Error ? error.message : String(error)
936
+ };
937
+ }
938
+ }
939
+ function buildClaudeModelSubcommands(source) {
739
940
  const seen = /* @__PURE__ */ new Set();
740
941
  const commands = [];
741
942
  for (const model of Object.values(CLAUDE_MODELS)) {
@@ -749,6 +950,97 @@ function buildModelCommandSubcommands(source = "model") {
749
950
  }
750
951
  return commands;
751
952
  }
953
+ function buildCatalogSubcommands(catalog, source) {
954
+ return (catalog.entries ?? []).filter((entry) => entry.lifecycle !== "unavailable").map((entry) => ({
955
+ name: entry.id,
956
+ description: formatCatalogEntryDescription(entry),
957
+ source
958
+ }));
959
+ }
960
+ function formatCatalogEntryDescription(entry) {
961
+ if (entry.contextWindow === void 0) {
962
+ return entry.displayName;
963
+ }
964
+ return `${entry.displayName} (${formatTokenCount(entry.contextWindow).toUpperCase()})`;
965
+ }
966
+ function resolveActiveProviderModelCatalogSnapshot(settings, providerDefinitions = []) {
967
+ const profile = resolveActiveProviderProfile(settings);
968
+ const providerType = profile?.type ?? profile?.name;
969
+ if (providerType === void 0) {
970
+ return void 0;
971
+ }
972
+ const definition = findProviderDefinition4(providerDefinitions, providerType);
973
+ return {
974
+ providerType,
975
+ ...profile !== void 0 ? { profile } : {},
976
+ ...definition !== void 0 ? { definition } : {},
977
+ ...definition?.modelCatalog !== void 0 ? { catalog: definition.modelCatalog } : {}
978
+ };
979
+ }
980
+ function resolveActiveProviderProfile(settings) {
981
+ if (settings?.currentProvider !== void 0) {
982
+ return settings.providers?.[settings.currentProvider];
983
+ }
984
+ return settings?.provider;
985
+ }
986
+ function toCatalogState(snapshot) {
987
+ return {
988
+ providerType: snapshot.providerType,
989
+ ...snapshot.catalog !== void 0 ? { catalog: snapshot.catalog } : {},
990
+ refreshAttempted: false
991
+ };
992
+ }
993
+ function resolveRefreshProfile(snapshot) {
994
+ const profile = snapshot.profile;
995
+ const defaults = snapshot.definition?.defaults;
996
+ const apiKey = resolveOptionalEnvReference(profile?.apiKey ?? defaults?.apiKey);
997
+ const model = resolveProfileValue(profile?.model, defaults?.model);
998
+ const baseURL = resolveProfileValue(profile?.baseURL, defaults?.baseURL);
999
+ const timeout = resolveProfileValue(profile?.timeout, defaults?.timeout);
1000
+ const options = resolveProfileValue(profile?.options, defaults?.options);
1001
+ const refreshProfile = {
1002
+ type: profile?.type ?? snapshot.providerType
1003
+ };
1004
+ if (model !== void 0) refreshProfile.model = model;
1005
+ if (apiKey !== void 0) refreshProfile.apiKey = apiKey;
1006
+ if (baseURL !== void 0) refreshProfile.baseURL = baseURL;
1007
+ if (timeout !== void 0) refreshProfile.timeout = timeout;
1008
+ if (options !== void 0) refreshProfile.options = options;
1009
+ return refreshProfile;
1010
+ }
1011
+ function resolveProfileValue(profileValue, defaultValue) {
1012
+ return profileValue ?? defaultValue;
1013
+ }
1014
+ function resolveOptionalEnvReference(value) {
1015
+ return value === void 0 ? void 0 : resolveEnvReference(value);
1016
+ }
1017
+ function formatModelUsageMessage(active) {
1018
+ const base = active?.providerType !== void 0 && (active.catalog?.entries === void 0 || active.catalog.entries.length === 0) ? `No model catalog available for provider ${active.providerType}. Usage: model <model-id>` : "Usage: model <model-id>";
1019
+ const freshness = formatCatalogFreshness(active);
1020
+ return freshness === void 0 ? base : `${base}
1021
+ ${freshness}`;
1022
+ }
1023
+ function formatCatalogFreshness(active) {
1024
+ const catalog = active?.catalog;
1025
+ if (catalog === void 0) return void 0;
1026
+ const parts = [`Catalog: ${catalog.status}`];
1027
+ if (catalog.entries !== void 0) {
1028
+ parts.push(`${catalog.entries.length} model(s)`);
1029
+ }
1030
+ if (catalog.lastVerifiedAt !== void 0) {
1031
+ parts.push(`verified ${catalog.lastVerifiedAt}`);
1032
+ }
1033
+ if (catalog.sourceUrl !== void 0) {
1034
+ parts.push(`source ${catalog.sourceUrl}`);
1035
+ }
1036
+ const refreshMessage = active?.refreshMessage;
1037
+ if (refreshMessage !== void 0) {
1038
+ parts.push(`refresh ${refreshMessage}`);
1039
+ } else if (catalog.message !== void 0) {
1040
+ parts.push(catalog.message);
1041
+ }
1042
+ return parts.join("; ");
1043
+ }
752
1044
 
753
1045
  // src/command-api/language/language-command-api.ts
754
1046
  var LANGUAGE_COMMAND_DESCRIPTION = "Set response language";
@@ -777,7 +1069,7 @@ function formatLanguageUsageMessage(commandName = "language") {
777
1069
  // src/command-api/permissions/permission-mode-command-api.ts
778
1070
  var PERMISSION_MODE_COMMAND_DESCRIPTION = "Show/change permission mode";
779
1071
  var PERMISSION_MODE_ARGUMENT_HINT = "plan | default | acceptEdits | bypassPermissions";
780
- var PERMISSIONS_COMMAND_DESCRIPTION = "Show permission rules";
1072
+ var PERMISSIONS_COMMAND_DESCRIPTION = "Show/change permission mode and permission rules";
781
1073
  var VALID_PERMISSION_MODES = [
782
1074
  "plan",
783
1075
  "default",
@@ -892,12 +1184,39 @@ function buildPluginCommandSubcommands() {
892
1184
  ];
893
1185
  }
894
1186
 
1187
+ // src/command-api/session/session-command-api.ts
1188
+ import { join as join3 } from "path";
1189
+ import { loadSessionLogEntries, validateSessionReplayLogEntries } from "@robota-sdk/agent-sessions";
1190
+
1191
+ // src/paths.ts
1192
+ import { join as join2 } from "path";
1193
+ import { homedir as homedir2 } from "os";
1194
+ function projectPaths(cwd) {
1195
+ const base = join2(cwd, ".robota");
1196
+ return {
1197
+ settings: join2(base, "settings.json"),
1198
+ settingsLocal: join2(base, "settings.local.json"),
1199
+ logs: join2(base, "logs"),
1200
+ sessions: join2(base, "sessions"),
1201
+ memory: join2(base, "memory"),
1202
+ checkpoints: join2(base, "checkpoints")
1203
+ };
1204
+ }
1205
+ function userPaths() {
1206
+ const base = join2(homedir2(), ".robota");
1207
+ return {
1208
+ settings: join2(base, "settings.json"),
1209
+ sessions: join2(base, "sessions")
1210
+ };
1211
+ }
1212
+
895
1213
  // src/command-api/session/session-command-api.ts
896
1214
  var CLEAR_COMMAND_DESCRIPTION = "Clear conversation history";
897
1215
  var RENAME_COMMAND_DESCRIPTION = "Rename the current session";
898
1216
  var RENAME_COMMAND_USAGE = "Usage: rename <name>";
899
1217
  var RESUME_COMMAND_DESCRIPTION = "Resume a previous session";
900
1218
  var COST_COMMAND_DESCRIPTION = "Show session info";
1219
+ var VALIDATE_SESSION_COMMAND_DESCRIPTION = "Validate current session replay log";
901
1220
  var EXIT_COMMAND_DESCRIPTION = "Exit CLI";
902
1221
  function clearConversationHistory(context) {
903
1222
  if (context.clearConversationHistory !== void 0) {
@@ -926,6 +1245,45 @@ function readCommandSessionInfo(context) {
926
1245
  messageCount: session.getMessageCount()
927
1246
  };
928
1247
  }
1248
+ function validateCommandSessionReplayLog(context) {
1249
+ const hostReport = context.validateCurrentSessionReplayLog?.();
1250
+ if (hostReport !== void 0) {
1251
+ return hostReport;
1252
+ }
1253
+ const sessionId = context.getSession().getSessionId();
1254
+ const logFile = join3(projectPaths(context.getCwd()).logs, `${sessionId}.jsonl`);
1255
+ const entries = loadSessionLogEntries(logFile);
1256
+ return {
1257
+ logFile,
1258
+ entryCount: entries.length,
1259
+ validation: validateSessionReplayLogEntries(entries)
1260
+ };
1261
+ }
1262
+ function formatCommandSessionReplayValidationReport(report) {
1263
+ const header = report.validation.ok ? "Session replay log is valid." : `Session replay log has ${report.validation.issues.length} issue(s).`;
1264
+ const details = [`Log: ${report.logFile}`, `Entries: ${report.entryCount}`];
1265
+ if (report.validation.ok) {
1266
+ return [header, ...details].join("\n");
1267
+ }
1268
+ const issueLines = report.validation.issues.map((issue, index) => {
1269
+ const location = formatReplayValidationIssueLocation(issue);
1270
+ return `${index + 1}. ${issue.code}${location}: ${issue.message}`;
1271
+ });
1272
+ return [header, ...details, "", ...issueLines].join("\n");
1273
+ }
1274
+ function formatReplayValidationIssueLocation(issue) {
1275
+ const parts = [];
1276
+ if (issue.executionId !== void 0) {
1277
+ parts.push(`execution=${issue.executionId}`);
1278
+ }
1279
+ if (issue.round !== void 0) {
1280
+ parts.push(`round=${issue.round}`);
1281
+ }
1282
+ if (issue.toolCallId !== void 0) {
1283
+ parts.push(`tool=${issue.toolCallId}`);
1284
+ }
1285
+ return parts.length > 0 ? ` (${parts.join(", ")})` : "";
1286
+ }
929
1287
 
930
1288
  // src/command-api/checkpoint/rewind-command-api.ts
931
1289
  var REWIND_COMMAND_DESCRIPTION = "List, inspect, restore, or rollback edit checkpoints.";
@@ -968,10 +1326,10 @@ function containsSensitiveMemoryContent(text) {
968
1326
 
969
1327
  // src/memory/pending-memory-store.ts
970
1328
  import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, writeFileSync } from "fs";
971
- import { dirname, join as join2 } from "path";
1329
+ import { dirname, join as join4 } from "path";
972
1330
  var PENDING_FILENAME = "pending.json";
973
1331
  function memoryRoot(cwd) {
974
- return join2(cwd, ".robota", "memory");
1332
+ return join4(cwd, ".robota", "memory");
975
1333
  }
976
1334
  function emptyDocument() {
977
1335
  return { version: 1, records: [] };
@@ -980,7 +1338,7 @@ var PendingMemoryStore = class {
980
1338
  path;
981
1339
  now;
982
1340
  constructor(cwd, now = () => /* @__PURE__ */ new Date()) {
983
- this.path = join2(memoryRoot(cwd), PENDING_FILENAME);
1341
+ this.path = join4(memoryRoot(cwd), PENDING_FILENAME);
984
1342
  this.now = now;
985
1343
  }
986
1344
  getPath() {
@@ -1048,7 +1406,7 @@ import {
1048
1406
  writeFileSync as writeFileSync2,
1049
1407
  appendFileSync
1050
1408
  } from "fs";
1051
- import { basename as basename2, join as join3 } from "path";
1409
+ import { basename as basename2, join as join5 } from "path";
1052
1410
  var MEMORY_INDEX_MAX_LINES = 200;
1053
1411
  var MEMORY_INDEX_MAX_BYTES = Number("25600");
1054
1412
  var INDEX_FILENAME = "MEMORY.md";
@@ -1062,7 +1420,7 @@ function isMemoryType(value) {
1062
1420
  return VALID_TYPES.includes(value);
1063
1421
  }
1064
1422
  function memoryRoot2(cwd) {
1065
- return join3(cwd, ".robota", "memory");
1423
+ return join5(cwd, ".robota", "memory");
1066
1424
  }
1067
1425
  function truncateToUtf8Bytes(value, maxBytes) {
1068
1426
  const buffer = Buffer.from(value, "utf8");
@@ -1097,10 +1455,10 @@ var ProjectMemoryStore = class {
1097
1455
  this.now = now;
1098
1456
  }
1099
1457
  getIndexPath() {
1100
- return join3(memoryRoot2(this.cwd), INDEX_FILENAME);
1458
+ return join5(memoryRoot2(this.cwd), INDEX_FILENAME);
1101
1459
  }
1102
1460
  getTopicsPath() {
1103
- return join3(memoryRoot2(this.cwd), TOPICS_DIRNAME);
1461
+ return join5(memoryRoot2(this.cwd), TOPICS_DIRNAME);
1104
1462
  }
1105
1463
  loadStartupMemory() {
1106
1464
  const path = this.getIndexPath();
@@ -1122,7 +1480,7 @@ var ProjectMemoryStore = class {
1122
1480
  const topicsPath = this.getTopicsPath();
1123
1481
  const topics = existsSync3(topicsPath) ? readdirSync2(topicsPath, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(TOPIC_EXTENSION)).map((entry) => ({
1124
1482
  name: basename2(entry.name, TOPIC_EXTENSION),
1125
- path: join3(topicsPath, entry.name)
1483
+ path: join5(topicsPath, entry.name)
1126
1484
  })).sort((a, b) => a.name.localeCompare(b.name)) : [];
1127
1485
  return {
1128
1486
  indexPath: this.getIndexPath(),
@@ -1132,7 +1490,7 @@ var ProjectMemoryStore = class {
1132
1490
  }
1133
1491
  readTopic(topic) {
1134
1492
  const normalized = sanitizeTopic(topic);
1135
- const path = join3(this.getTopicsPath(), `${normalized}${TOPIC_EXTENSION}`);
1493
+ const path = join5(this.getTopicsPath(), `${normalized}${TOPIC_EXTENSION}`);
1136
1494
  if (!existsSync3(path)) return "";
1137
1495
  return readFileSync3(path, "utf8").trimEnd();
1138
1496
  }
@@ -1142,7 +1500,7 @@ var ProjectMemoryStore = class {
1142
1500
  const topicsPath = this.getTopicsPath();
1143
1501
  mkdirSync2(topicsPath, { recursive: true });
1144
1502
  const indexPath = this.getIndexPath();
1145
- const topicPath = join3(topicsPath, `${topic}${TOPIC_EXTENSION}`);
1503
+ const topicPath = join5(topicsPath, `${topic}${TOPIC_EXTENSION}`);
1146
1504
  const entry = formatEntry(this.now(), input, topic);
1147
1505
  const topicHeader = existsSync3(topicPath) ? "" : `# ${topic}
1148
1506
 
@@ -1254,24 +1612,6 @@ async function preprocessShellCommands(content) {
1254
1612
  }
1255
1613
  return result;
1256
1614
  }
1257
- async function buildSkillPrompt(input, registry, context) {
1258
- const parts = input.slice(1).split(/\s+/);
1259
- const cmd = parts[0]?.toLowerCase() ?? "";
1260
- const skillCmd = registry.getCommands().find((c) => c.name === cmd && (c.source === "skill" || c.source === "plugin"));
1261
- if (!skillCmd) return null;
1262
- const args = parts.slice(1).join(" ").trim();
1263
- const userInstruction = args || skillCmd.description;
1264
- if (skillCmd.skillContent) {
1265
- let processed = await preprocessShellCommands(skillCmd.skillContent);
1266
- processed = substituteVariables(processed, args, context);
1267
- return `<skill name="${cmd}">
1268
- ${processed}
1269
- </skill>
1270
-
1271
- Execute the "${cmd}" skill: ${userInstruction}`;
1272
- }
1273
- return `Use the "${cmd}" skill: ${userInstruction}`;
1274
- }
1275
1615
 
1276
1616
  // src/commands/skill-executor.ts
1277
1617
  async function buildProcessedContent(skill, args, context) {
@@ -1294,7 +1634,9 @@ Execute the "${skill.name}" skill: ${userInstruction}`;
1294
1634
  async function executeSkill(skill, args, callbacks, context) {
1295
1635
  if (skill.context === "fork") {
1296
1636
  if (!callbacks.runInFork) {
1297
- throw new Error("Fork execution is not available. Agent tool deps may not be initialized.");
1637
+ throw new Error(
1638
+ "Fork execution is not available. Agent runtime deps may not be initialized."
1639
+ );
1298
1640
  }
1299
1641
  const content = await buildProcessedContent(skill, args, context);
1300
1642
  const prompt2 = content ?? `Use the "${skill.name}" skill: ${args || skill.description}`;
@@ -1308,6 +1650,37 @@ async function executeSkill(skill, args, callbacks, context) {
1308
1650
  return { mode: "inject", prompt };
1309
1651
  }
1310
1652
 
1653
+ // src/commands/skill-activation-events.ts
1654
+ function getSkillActivationSource(skill) {
1655
+ return skill.source === "plugin" ? "plugin" : "skill";
1656
+ }
1657
+ function getSkillActivationMode(skill) {
1658
+ return skill.context === "fork" ? "fork" : "inject";
1659
+ }
1660
+ function createSkillActivationEvent(input) {
1661
+ return {
1662
+ type: "skill-activation",
1663
+ skillName: input.skill.name,
1664
+ source: getSkillActivationSource(input.skill),
1665
+ invocation: input.invocation,
1666
+ mode: getSkillActivationMode(input.skill),
1667
+ status: input.status,
1668
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1669
+ ...input.qualifiedName !== void 0 ? { qualifiedName: input.qualifiedName } : {},
1670
+ ...input.error !== void 0 ? { error: input.error } : {}
1671
+ };
1672
+ }
1673
+ function formatSkillActivationMessage(event) {
1674
+ const sourceLabel = event.source === "plugin" ? "plugin skill" : "skill";
1675
+ if (event.status === "failed") {
1676
+ return `Skill failed: ${event.skillName}${event.error ? ` (${event.error})` : ""}`;
1677
+ }
1678
+ if (event.status === "completed") {
1679
+ return `Skill completed: ${event.skillName}`;
1680
+ }
1681
+ return `Invoking ${sourceLabel}: ${event.skillName}`;
1682
+ }
1683
+
1311
1684
  // src/assembly/create-subagent-session.ts
1312
1685
  import { Session } from "@robota-sdk/agent-sessions";
1313
1686
 
@@ -1340,12 +1713,147 @@ function assembleSubagentPrompt(options) {
1340
1713
  return parts.join("\n\n");
1341
1714
  }
1342
1715
 
1716
+ // src/tools/model-command-tool-projection.ts
1717
+ import { createHash } from "crypto";
1718
+ import { z } from "zod";
1719
+ import { createZodFunctionTool } from "@robota-sdk/agent-tools";
1720
+ var MODEL_COMMAND_TOOL_PREFIX = "robota_command_";
1721
+ var PROVIDER_SAFE_TOOL_NAME_PATTERN = /^[A-Za-z0-9_-]{1,64}$/;
1722
+ var MAX_PROVIDER_TOOL_NAME_LENGTH = 64;
1723
+ var HASH_LENGTH = 8;
1724
+ var HASH_SEPARATOR_LENGTH = 1;
1725
+ function asZodSchema(schema) {
1726
+ return schema;
1727
+ }
1728
+ function normalizeModelCommandName(command) {
1729
+ return command.trim().replace(/^\/+/, "").split(/\s+/)[0] ?? "";
1730
+ }
1731
+ function createProviderSafeModelCommandToolName(commandName) {
1732
+ const normalizedCommandName = normalizeModelCommandName(commandName);
1733
+ if (!normalizedCommandName) {
1734
+ throw new Error("Model command descriptor name must not be empty.");
1735
+ }
1736
+ const safeBody = normalizedCommandName.replace(/[^A-Za-z0-9_-]/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "");
1737
+ if (!safeBody) {
1738
+ throw new Error(`Model command descriptor name cannot be projected safely: ${commandName}`);
1739
+ }
1740
+ const rawToolName = `${MODEL_COMMAND_TOOL_PREFIX}${safeBody}`;
1741
+ if (PROVIDER_SAFE_TOOL_NAME_PATTERN.test(rawToolName)) {
1742
+ return rawToolName;
1743
+ }
1744
+ const hash = createHash("sha256").update(normalizedCommandName).digest("hex").slice(0, HASH_LENGTH);
1745
+ const maxBodyLength = MAX_PROVIDER_TOOL_NAME_LENGTH - MODEL_COMMAND_TOOL_PREFIX.length - HASH_SEPARATOR_LENGTH - HASH_LENGTH;
1746
+ if (maxBodyLength < 1) {
1747
+ throw new Error("Model command tool prefix leaves no room for command names.");
1748
+ }
1749
+ const truncatedBody = safeBody.slice(0, maxBodyLength).replace(/[_-]+$/g, "") || "command";
1750
+ const toolName = `${MODEL_COMMAND_TOOL_PREFIX}${truncatedBody}_${hash}`;
1751
+ if (!PROVIDER_SAFE_TOOL_NAME_PATTERN.test(toolName)) {
1752
+ throw new Error(`Projected model command tool name is not provider-safe: ${toolName}`);
1753
+ }
1754
+ return toolName;
1755
+ }
1756
+ function createModelCommandToolProjection(commandDescriptors) {
1757
+ const commandNames = /* @__PURE__ */ new Set();
1758
+ const toolNameToCommandName = /* @__PURE__ */ new Map();
1759
+ const commandNameToToolName = /* @__PURE__ */ new Map();
1760
+ const commandTools = [];
1761
+ for (const descriptor of commandDescriptors) {
1762
+ const commandName = normalizeModelCommandName(descriptor.name);
1763
+ if (!commandName) {
1764
+ throw new Error("Model command descriptor name must not be empty.");
1765
+ }
1766
+ if (commandNames.has(commandName)) {
1767
+ throw new Error(`Duplicate model command descriptor: ${commandName}`);
1768
+ }
1769
+ commandNames.add(commandName);
1770
+ const toolName = createProviderSafeModelCommandToolName(commandName);
1771
+ const existingCommandName = toolNameToCommandName.get(toolName);
1772
+ if (existingCommandName !== void 0) {
1773
+ throw new Error(
1774
+ `Model command projection collision: ${existingCommandName} and ${commandName} both map to ${toolName}`
1775
+ );
1776
+ }
1777
+ toolNameToCommandName.set(toolName, commandName);
1778
+ commandNameToToolName.set(commandName, toolName);
1779
+ commandTools.push({
1780
+ commandName,
1781
+ toolName,
1782
+ description: formatProjectedModelCommandToolDescription(commandName, descriptor),
1783
+ descriptor
1784
+ });
1785
+ }
1786
+ return {
1787
+ commandTools,
1788
+ toolNameToCommandName,
1789
+ commandNameToToolName
1790
+ };
1791
+ }
1792
+ function formatProjectedModelCommandToolPromptDescription(projection) {
1793
+ return `${projection.toolName} \u2014 ${projection.descriptor.description}`;
1794
+ }
1795
+ function stringifyModelCommandResult(command, result) {
1796
+ if (!result) {
1797
+ return JSON.stringify({
1798
+ success: false,
1799
+ command,
1800
+ error: `Unknown command: ${command}`
1801
+ });
1802
+ }
1803
+ return JSON.stringify({
1804
+ success: result.success,
1805
+ command,
1806
+ message: result.message,
1807
+ data: result.data
1808
+ });
1809
+ }
1810
+ function createProjectedCommandExecutionTools(deps) {
1811
+ const projection = createModelCommandToolProjection(deps.commandDescriptors);
1812
+ return projection.commandTools.map((projectedTool) => {
1813
+ const schema = createProjectedCommandArgsSchema(projectedTool.descriptor);
1814
+ return createZodFunctionTool(
1815
+ projectedTool.toolName,
1816
+ projectedTool.description,
1817
+ asZodSchema(schema),
1818
+ async (params) => {
1819
+ const parsedParams = schema.parse(params);
1820
+ if (!deps.isModelInvocable(projectedTool.commandName)) {
1821
+ return JSON.stringify({
1822
+ success: false,
1823
+ command: projectedTool.commandName,
1824
+ error: `Command is not model-invocable: ${projectedTool.commandName}`
1825
+ });
1826
+ }
1827
+ return stringifyModelCommandResult(
1828
+ projectedTool.commandName,
1829
+ await deps.execute(projectedTool.commandName, parsedParams.args ?? "")
1830
+ );
1831
+ }
1832
+ );
1833
+ });
1834
+ }
1835
+ function createProjectedCommandArgsSchema(descriptor) {
1836
+ const argsDescription = descriptor.argumentHint ? `Arguments for the command. Expected grammar: ${descriptor.argumentHint}` : "Arguments for the command as a single string.";
1837
+ return z.object({
1838
+ args: z.string().optional().describe(argsDescription)
1839
+ });
1840
+ }
1841
+ function formatProjectedModelCommandToolDescription(commandName, descriptor) {
1842
+ const lines = [descriptor.description.trim(), `Robota command id: ${commandName}.`];
1843
+ if (descriptor.argumentHint) {
1844
+ lines.push(`Argument grammar: ${descriptor.argumentHint}`);
1845
+ }
1846
+ return lines.filter((line) => line.length > 0).join("\n\n");
1847
+ }
1848
+
1343
1849
  // src/assembly/create-subagent-session.ts
1344
1850
  var MODEL_SHORTCUTS = {
1345
1851
  sonnet: "claude-sonnet-4-6",
1346
1852
  haiku: "claude-haiku-4-5",
1347
1853
  opus: "claude-opus-4-6"
1348
1854
  };
1855
+ var LEGACY_AGENT_TOOL_NAME = "Agent";
1856
+ var PROJECTED_AGENT_COMMAND_TOOL_NAME = createProviderSafeModelCommandToolName("agent");
1349
1857
  function resolveModelId(shortName, _parentModel) {
1350
1858
  return MODEL_SHORTCUTS[shortName] ?? shortName;
1351
1859
  }
@@ -1359,7 +1867,9 @@ function filterTools(parentTools, agentDefinition) {
1359
1867
  const allowSet = new Set(agentDefinition.tools);
1360
1868
  tools = tools.filter((t) => allowSet.has(t.getName()));
1361
1869
  }
1362
- tools = tools.filter((t) => t.getName() !== "Agent");
1870
+ tools = tools.filter(
1871
+ (t) => t.getName() !== LEGACY_AGENT_TOOL_NAME && t.getName() !== PROJECTED_AGENT_COMMAND_TOOL_NAME
1872
+ );
1363
1873
  return tools;
1364
1874
  }
1365
1875
  function createSubagentSession(options) {
@@ -1454,8 +1964,8 @@ function getBuiltInAgent(name) {
1454
1964
  }
1455
1965
 
1456
1966
  // src/tools/agent-tool.ts
1457
- import { z } from "zod";
1458
- import { createZodFunctionTool } from "@robota-sdk/agent-tools";
1967
+ import { z as z2 } from "zod";
1968
+ import { createZodFunctionTool as createZodFunctionTool2 } from "@robota-sdk/agent-tools";
1459
1969
  import { SubagentManager } from "@robota-sdk/agent-runtime";
1460
1970
 
1461
1971
  // src/subagents/in-process-subagent-runner.ts
@@ -1685,35 +2195,21 @@ var AGENT_TOOL_DESCRIPTION = [
1685
2195
  "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.",
1686
2196
  "Execution is represented by a real tool call and runtime background task event."
1687
2197
  ].join(" ");
1688
- function createAgentToolPromptDescription(agentDefinitions = []) {
1689
- const availableAgents = agentDefinitions.length > 0 ? ` Available agent types: ${agentDefinitions.map((agent) => `${agent.name} (${agent.description})`).join(", ")}.` : "";
1690
- return [
1691
- "Agent \u2014 creates isolated subagent jobs.",
1692
- "Without jobs, one Agent tool call corresponds to one subagent job.",
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.",
1694
- "When the user explicitly asks to create, run, spawn, delegate to, or use agents/subagents, start the requested subagent job immediately.",
1695
- "Do not ask a follow-up question unless execution is impossible or unsafe.",
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.",
1698
- "Runtime mode is background.",
1699
- availableAgents
1700
- ].join(" ").replace(/\s+/g, " ").trim();
1701
- }
1702
- function asZodSchema(schema) {
2198
+ function asZodSchema2(schema) {
1703
2199
  return schema;
1704
2200
  }
1705
- var AgentSchema = z.object({
1706
- prompt: z.string().optional().describe("The task for a single subagent to perform. Required when jobs is omitted."),
1707
- subagent_type: z.string().optional().describe('Agent type: "general-purpose", "Explore", "Plan", or a custom agent name'),
1708
- model: z.string().optional().describe("Optional model override"),
1709
- isolation: z.enum(["none", "worktree"]).optional().describe('Optional runtime isolation mode. "worktree" runs in a Git worktree.'),
1710
- jobs: z.array(
1711
- z.object({
1712
- label: z.string().optional().describe("Stable role label for this batch job"),
1713
- prompt: z.string().describe("The task for this subagent to perform"),
1714
- subagent_type: z.string().optional().describe("Agent type for this job"),
1715
- model: z.string().optional().describe("Optional model override for this job"),
1716
- isolation: z.enum(["none", "worktree"]).optional().describe("Isolation for this job")
2201
+ var AgentSchema = z2.object({
2202
+ prompt: z2.string().optional().describe("The task for a single subagent to perform. Required when jobs is omitted."),
2203
+ subagent_type: z2.string().optional().describe('Agent type: "general-purpose", "Explore", "Plan", or a custom agent name'),
2204
+ model: z2.string().optional().describe("Optional model override"),
2205
+ isolation: z2.enum(["none", "worktree"]).optional().describe('Optional runtime isolation mode. "worktree" runs in a Git worktree.'),
2206
+ jobs: z2.array(
2207
+ z2.object({
2208
+ label: z2.string().optional().describe("Stable role label for this batch job"),
2209
+ prompt: z2.string().describe("The task for this subagent to perform"),
2210
+ subagent_type: z2.string().optional().describe("Agent type for this job"),
2211
+ model: z2.string().optional().describe("Optional model override for this job"),
2212
+ isolation: z2.enum(["none", "worktree"]).optional().describe("Isolation for this job")
1717
2213
  }).passthrough()
1718
2214
  ).optional().describe("Batch of subagent jobs to start in one Agent tool call")
1719
2215
  }).passthrough();
@@ -1838,10 +2334,10 @@ async function runManagedAgent(args, deps, manager) {
1838
2334
  }
1839
2335
  function createAgentTool(deps) {
1840
2336
  const manager = createSubagentManager(deps);
1841
- return createZodFunctionTool(
2337
+ return createZodFunctionTool2(
1842
2338
  "Agent",
1843
2339
  AGENT_TOOL_DESCRIPTION,
1844
- asZodSchema(AgentSchema),
2340
+ asZodSchema2(AgentSchema),
1845
2341
  async (params) => {
1846
2342
  const args = params;
1847
2343
  if (Array.isArray(args.jobs) && args.jobs.length > 0) {
@@ -1945,8 +2441,8 @@ var BackgroundJobOrchestrator = class {
1945
2441
  createRecord(state) {
1946
2442
  let resolveGroup = () => {
1947
2443
  };
1948
- const completion = new Promise((resolve4) => {
1949
- resolveGroup = resolve4;
2444
+ const completion = new Promise((resolve6) => {
2445
+ resolveGroup = resolve6;
1950
2446
  });
1951
2447
  return { state, completion, resolve: resolveGroup };
1952
2448
  }
@@ -2061,7 +2557,11 @@ function cloneGroup(group) {
2061
2557
  import {
2062
2558
  getBackgroundTaskTransitions,
2063
2559
  isTerminalBackgroundTaskStatus as isTerminalBackgroundTaskStatus2,
2064
- transitionBackgroundTaskStatus
2560
+ transitionBackgroundTaskStatus,
2561
+ appendPrefixedLogLines,
2562
+ createBackgroundTaskLogPage,
2563
+ createLimitedOutputCapture,
2564
+ DEFAULT_BACKGROUND_TASK_LOG_PAGE_SIZE
2065
2565
  } from "@robota-sdk/agent-runtime";
2066
2566
  import { BackgroundTaskError } from "@robota-sdk/agent-runtime";
2067
2567
 
@@ -2075,8 +2575,385 @@ function retrieveSessionBackgroundTaskManager(key) {
2075
2575
  }
2076
2576
 
2077
2577
  // src/interactive/interactive-session-execution.ts
2078
- import { randomUUID } from "crypto";
2578
+ import { randomUUID as randomUUID2 } from "crypto";
2079
2579
  import { collectAssistantUsageMetadata } from "@robota-sdk/agent-core";
2580
+
2581
+ // src/context/context-reference-inventory.ts
2582
+ var DEFAULT_MAX_ACTIVE_REFERENCES = Number("8");
2583
+ var BYTES_PER_KIB = Number("1024");
2584
+ var DEFAULT_MAX_ACTIVE_BYTES = Number("256") * BYTES_PER_KIB;
2585
+ var DEFAULT_MAX_OBSERVED_REFERENCES = Number("32");
2586
+ function createContextReferenceItem(record, loadType, status, timestamp = (/* @__PURE__ */ new Date()).toISOString()) {
2587
+ return {
2588
+ id: `${loadType}:${record.relativePath}`,
2589
+ sourcePath: record.sourcePath,
2590
+ relativePath: record.relativePath,
2591
+ originalReference: record.originalReference,
2592
+ loadType,
2593
+ status,
2594
+ byteLength: record.byteLength,
2595
+ loadedAt: timestamp,
2596
+ lastUsedAt: timestamp
2597
+ };
2598
+ }
2599
+ function upsertContextReference(references, item, limits) {
2600
+ const existing = references.find((reference) => reference.sourcePath === item.sourcePath);
2601
+ const retained = references.filter((reference) => reference.sourcePath !== item.sourcePath);
2602
+ const nextItem = existing ? mergeContextReference(existing, item) : item;
2603
+ return enforceContextReferenceLimits([...retained, nextItem], limits);
2604
+ }
2605
+ function removeContextReference(references, query) {
2606
+ const normalized = normalizeReferenceQuery(query);
2607
+ const removed = references.find((reference) => matchesContextReference(reference, normalized));
2608
+ if (!removed) return { references: [...references], result: {} };
2609
+ return {
2610
+ references: references.filter((reference) => reference.sourcePath !== removed.sourcePath),
2611
+ result: { removed }
2612
+ };
2613
+ }
2614
+ function clearContextReferences(references) {
2615
+ return { removed: [...references] };
2616
+ }
2617
+ function listActiveContextReferences(references) {
2618
+ return references.filter((reference) => reference.status === "active");
2619
+ }
2620
+ function toContextReferenceRecords(references) {
2621
+ return references.map((reference) => ({
2622
+ originalReference: reference.originalReference,
2623
+ sourcePath: reference.sourcePath,
2624
+ relativePath: reference.relativePath,
2625
+ reason: reference.loadType,
2626
+ depth: 0,
2627
+ byteLength: reference.byteLength
2628
+ }));
2629
+ }
2630
+ function mergeContextReference(existing, incoming) {
2631
+ if (incoming.status === "active") return { ...incoming, loadedAt: existing.loadedAt };
2632
+ return {
2633
+ ...existing,
2634
+ byteLength: incoming.byteLength,
2635
+ originalReference: incoming.originalReference,
2636
+ lastUsedAt: incoming.lastUsedAt
2637
+ };
2638
+ }
2639
+ function enforceContextReferenceLimits(references, limits) {
2640
+ const maxActiveReferences = limits?.maxActiveReferences ?? DEFAULT_MAX_ACTIVE_REFERENCES;
2641
+ const maxActiveBytes = limits?.maxActiveBytes ?? DEFAULT_MAX_ACTIVE_BYTES;
2642
+ const maxObservedReferences = limits?.maxObservedReferences ?? DEFAULT_MAX_OBSERVED_REFERENCES;
2643
+ const evicted = [];
2644
+ let next = [...references];
2645
+ while (countActiveReferences(next) > maxActiveReferences || countActiveBytes(next) > maxActiveBytes) {
2646
+ const candidate = next.find((reference) => reference.status === "active");
2647
+ if (!candidate) break;
2648
+ evicted.push(candidate);
2649
+ next = next.filter((reference) => reference.sourcePath !== candidate.sourcePath);
2650
+ }
2651
+ const observed = next.filter((reference) => reference.status === "observed");
2652
+ if (observed.length > maxObservedReferences) {
2653
+ const overflow = observed.slice(0, observed.length - maxObservedReferences);
2654
+ evicted.push(...overflow);
2655
+ next = next.filter(
2656
+ (reference) => reference.status !== "observed" || !overflow.some((removed) => removed.sourcePath === reference.sourcePath)
2657
+ );
2658
+ }
2659
+ return { references: next, evicted };
2660
+ }
2661
+ function countActiveReferences(references) {
2662
+ return references.filter((reference) => reference.status === "active").length;
2663
+ }
2664
+ function countActiveBytes(references) {
2665
+ return references.reduce(
2666
+ (total, reference) => total + (reference.status === "active" ? reference.byteLength : 0),
2667
+ 0
2668
+ );
2669
+ }
2670
+ function normalizeReferenceQuery(query) {
2671
+ return query.startsWith("@") ? query.slice(1) : query;
2672
+ }
2673
+ function matchesContextReference(reference, query) {
2674
+ return reference.relativePath === query || reference.sourcePath === query || reference.originalReference === query || reference.originalReference === `@${query}`;
2675
+ }
2676
+
2677
+ // src/context/prompt-file-reference-format.ts
2678
+ import { randomUUID } from "crypto";
2679
+ function buildPromptWithFileReferences(input, references) {
2680
+ if (references.length === 0) return input;
2681
+ const blocks = references.map((reference) => {
2682
+ const content = reference.content.replaceAll("</file>", "<\\/file>");
2683
+ return [
2684
+ `<file path="${escapeAttribute(reference.relativePath)}" bytes="${reference.byteLength}" reason="${reference.reason}">`,
2685
+ content,
2686
+ "</file>"
2687
+ ].join("\n");
2688
+ });
2689
+ return [input, "<robota_file_references>", ...blocks, "</robota_file_references>"].join("\n\n");
2690
+ }
2691
+ function hasBlockingPromptFileReferenceDiagnostics(diagnostics) {
2692
+ return diagnostics.some((diagnostic) => diagnostic.severity === "error");
2693
+ }
2694
+ function formatPromptFileReferenceDiagnostics(diagnostics) {
2695
+ if (diagnostics.length === 0) return "";
2696
+ return [
2697
+ "File reference error:",
2698
+ ...diagnostics.map((diagnostic) => `- ${diagnostic.reference}: ${diagnostic.message}`)
2699
+ ].join("\n");
2700
+ }
2701
+ function toPromptFileReferenceRecords(references) {
2702
+ return references.map(({ content: _content, ...record }) => record);
2703
+ }
2704
+ function createPromptFileReferenceHistoryEntry(references) {
2705
+ const records = toPromptFileReferenceRecords(references);
2706
+ return {
2707
+ id: `prompt_file_reference_${randomUUID()}`,
2708
+ timestamp: /* @__PURE__ */ new Date(),
2709
+ category: "event",
2710
+ type: "prompt-file-reference",
2711
+ data: {
2712
+ message: formatLoadedPromptFileReferencesMessage(records),
2713
+ references: records
2714
+ }
2715
+ };
2716
+ }
2717
+ function escapeAttribute(value) {
2718
+ return value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
2719
+ }
2720
+ function formatLoadedPromptFileReferencesMessage(references) {
2721
+ const list = references.map((reference) => `${reference.relativePath} (${reference.byteLength} B)`).join(", ");
2722
+ return `Loaded file references: ${list}`;
2723
+ }
2724
+
2725
+ // src/context/prompt-file-reference-parser.ts
2726
+ var REFERENCE_PATTERN = /(^|[\s([{])@([^\s)\]}>,;"'`]+)/g;
2727
+ function parsePromptFileReferences(input) {
2728
+ const references = [];
2729
+ for (const match of input.matchAll(REFERENCE_PATTERN)) {
2730
+ const token = stripTrailingPunctuation(match[2] ?? "");
2731
+ if (!isPathLikeReference(token)) continue;
2732
+ references.push({
2733
+ original: `@${token}`,
2734
+ path: token,
2735
+ index: match.index ?? 0
2736
+ });
2737
+ }
2738
+ return references;
2739
+ }
2740
+ function stripTrailingPunctuation(token) {
2741
+ let end = token.length;
2742
+ while (end > 0 && /[.,:;!?]/.test(token[end - 1] ?? "")) {
2743
+ end -= 1;
2744
+ }
2745
+ return token.slice(0, end);
2746
+ }
2747
+ function isPathLikeReference(referencePath) {
2748
+ if (referencePath.length === 0) return false;
2749
+ if (referencePath.includes("://")) return false;
2750
+ return referencePath.startsWith("./") || referencePath.startsWith("../") || referencePath.startsWith("/") || referencePath.startsWith("~/") || referencePath.startsWith(".") || referencePath.includes(".");
2751
+ }
2752
+
2753
+ // src/context/prompt-file-reference-resolver.ts
2754
+ import { readFile, realpath, stat } from "fs/promises";
2755
+ import { resolve as resolve2 } from "path";
2756
+
2757
+ // src/context/prompt-file-reference-paths.ts
2758
+ import { homedir as homedir3 } from "os";
2759
+ import { isAbsolute, relative as pathRelative, resolve, sep as pathSeparator } from "path";
2760
+ function resolveCandidatePath(referencePath, rootPath) {
2761
+ if (referencePath.startsWith("~/")) {
2762
+ return resolve(homedir3(), referencePath.slice("~/".length));
2763
+ }
2764
+ if (isAbsolute(referencePath)) {
2765
+ return resolve(referencePath);
2766
+ }
2767
+ return resolve(rootPath, referencePath);
2768
+ }
2769
+ function isPathWithinRoot(candidatePath, rootPath) {
2770
+ const relativePath = pathRelative(rootPath, candidatePath);
2771
+ return relativePath === "" || !relativePath.startsWith("..") && !isAbsolute(relativePath);
2772
+ }
2773
+ function normalizeRelativePath(rootPath, sourcePath) {
2774
+ return pathRelative(rootPath, sourcePath).split(pathSeparator).join("/");
2775
+ }
2776
+
2777
+ // src/context/prompt-file-reference-resolver.ts
2778
+ var DEFAULT_MAX_DEPTH = Number("2");
2779
+ var DEFAULT_MAX_REFERENCES = Number("8");
2780
+ var BYTES_PER_KIB2 = Number("1024");
2781
+ var DEFAULT_MAX_FILE_BYTES = Number("64") * BYTES_PER_KIB2;
2782
+ var DEFAULT_MAX_TOTAL_BYTES = Number("256") * BYTES_PER_KIB2;
2783
+ async function resolvePromptFileReferences(input, options) {
2784
+ const state = await createResolveState(options);
2785
+ for (const reference of parsePromptFileReferences(input)) {
2786
+ await resolveReference(reference, 0, [], state);
2787
+ }
2788
+ return toResolvedReferences(state);
2789
+ }
2790
+ async function resolvePromptFileReferencePaths(referencePaths, options) {
2791
+ const state = await createResolveState(options);
2792
+ for (const referencePath of referencePaths) {
2793
+ await resolveReference(
2794
+ { original: `@${referencePath}`, path: referencePath, index: 0 },
2795
+ 0,
2796
+ [],
2797
+ state
2798
+ );
2799
+ }
2800
+ return toResolvedReferences(state);
2801
+ }
2802
+ async function createResolveState(options) {
2803
+ return {
2804
+ rootPath: await resolveWorkspaceRoot(options.cwd),
2805
+ limits: resolveLimits(options.limits),
2806
+ reason: options.reason ?? "prompt-reference",
2807
+ references: [],
2808
+ diagnostics: [],
2809
+ loadedPaths: /* @__PURE__ */ new Set(),
2810
+ totalBytes: 0
2811
+ };
2812
+ }
2813
+ function toResolvedReferences(state) {
2814
+ return {
2815
+ references: state.references,
2816
+ diagnostics: state.diagnostics
2817
+ };
2818
+ }
2819
+ function resolveLimits(limits) {
2820
+ return {
2821
+ maxDepth: limits?.maxDepth ?? DEFAULT_MAX_DEPTH,
2822
+ maxReferences: limits?.maxReferences ?? DEFAULT_MAX_REFERENCES,
2823
+ maxFileBytes: limits?.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES,
2824
+ maxTotalBytes: limits?.maxTotalBytes ?? DEFAULT_MAX_TOTAL_BYTES
2825
+ };
2826
+ }
2827
+ async function resolveWorkspaceRoot(cwd) {
2828
+ try {
2829
+ return await realpath(cwd);
2830
+ } catch {
2831
+ return resolve2(cwd);
2832
+ }
2833
+ }
2834
+ async function resolveReference(reference, depth, activePaths, state) {
2835
+ if (!checkReferenceBudget(reference, depth, state)) return;
2836
+ const sourcePath = await resolveReferencePath(reference, state);
2837
+ if (sourcePath === void 0) return;
2838
+ if (!checkReferenceCycleAndDuplicate(reference, sourcePath, activePaths, state)) return;
2839
+ const fileInfo = await inspectReferenceFile(reference, sourcePath, state);
2840
+ if (fileInfo === void 0) return;
2841
+ const content = await readReferenceFile(reference, sourcePath, state);
2842
+ if (content === void 0) return;
2843
+ state.loadedPaths.add(sourcePath);
2844
+ state.totalBytes += fileInfo.byteLength;
2845
+ state.references.push(buildResolvedReference(reference, fileInfo, depth, content, state));
2846
+ await resolveNestedReferences(content, depth, [...activePaths, sourcePath], state);
2847
+ }
2848
+ function checkReferenceBudget(reference, depth, state) {
2849
+ if (state.references.length >= state.limits.maxReferences) {
2850
+ pushDiagnostic(state, "too-many-references", reference, "Too many file references.");
2851
+ return false;
2852
+ }
2853
+ if (depth > state.limits.maxDepth) {
2854
+ pushDiagnostic(state, "max-depth", reference, "File reference nesting is too deep.");
2855
+ return false;
2856
+ }
2857
+ return true;
2858
+ }
2859
+ async function resolveReferencePath(reference, state) {
2860
+ const candidatePath = resolveCandidatePath(reference.path, state.rootPath);
2861
+ if (!isPathWithinRoot(candidatePath, state.rootPath)) {
2862
+ pushDiagnostic(state, "outside-root", reference, "Referenced path is outside the workspace.");
2863
+ return void 0;
2864
+ }
2865
+ try {
2866
+ const sourcePath = await realpath(candidatePath);
2867
+ if (isPathWithinRoot(sourcePath, state.rootPath)) return sourcePath;
2868
+ pushDiagnostic(
2869
+ state,
2870
+ "outside-root",
2871
+ reference,
2872
+ "Referenced path resolves outside the workspace."
2873
+ );
2874
+ } catch {
2875
+ pushDiagnostic(state, "not-found", reference, "Referenced file was not found.");
2876
+ }
2877
+ return void 0;
2878
+ }
2879
+ function checkReferenceCycleAndDuplicate(reference, sourcePath, activePaths, state) {
2880
+ if (activePaths.includes(sourcePath)) {
2881
+ pushDiagnostic(state, "circular-reference", reference, "Circular file reference detected.");
2882
+ return false;
2883
+ }
2884
+ return !state.loadedPaths.has(sourcePath);
2885
+ }
2886
+ async function inspectReferenceFile(reference, sourcePath, state) {
2887
+ try {
2888
+ const fileStat = await stat(sourcePath);
2889
+ if (fileStat.isDirectory()) {
2890
+ pushDiagnostic(
2891
+ state,
2892
+ "directory-not-supported",
2893
+ reference,
2894
+ "Directory references are not supported."
2895
+ );
2896
+ return void 0;
2897
+ }
2898
+ if (fileStat.size > state.limits.maxFileBytes) {
2899
+ pushDiagnostic(
2900
+ state,
2901
+ "file-too-large",
2902
+ reference,
2903
+ "Referenced file exceeds the per-file size limit."
2904
+ );
2905
+ return void 0;
2906
+ }
2907
+ if (state.totalBytes + fileStat.size > state.limits.maxTotalBytes) {
2908
+ pushDiagnostic(
2909
+ state,
2910
+ "total-too-large",
2911
+ reference,
2912
+ "Referenced files exceed the total size limit."
2913
+ );
2914
+ return void 0;
2915
+ }
2916
+ return { sourcePath, byteLength: fileStat.size };
2917
+ } catch {
2918
+ pushDiagnostic(state, "unreadable", reference, "Referenced file could not be inspected.");
2919
+ return void 0;
2920
+ }
2921
+ }
2922
+ async function readReferenceFile(reference, sourcePath, state) {
2923
+ try {
2924
+ return await readFile(sourcePath, "utf8");
2925
+ } catch {
2926
+ pushDiagnostic(state, "unreadable", reference, "Referenced file could not be read.");
2927
+ return void 0;
2928
+ }
2929
+ }
2930
+ function buildResolvedReference(reference, fileInfo, depth, content, state) {
2931
+ return {
2932
+ originalReference: reference.original,
2933
+ sourcePath: fileInfo.sourcePath,
2934
+ relativePath: normalizeRelativePath(state.rootPath, fileInfo.sourcePath),
2935
+ reason: state.reason,
2936
+ depth,
2937
+ byteLength: fileInfo.byteLength,
2938
+ content
2939
+ };
2940
+ }
2941
+ async function resolveNestedReferences(content, depth, activePaths, state) {
2942
+ for (const nestedReference of parsePromptFileReferences(content)) {
2943
+ await resolveReference(nestedReference, depth + 1, activePaths, state);
2944
+ }
2945
+ }
2946
+ function pushDiagnostic(state, code, reference, message) {
2947
+ state.diagnostics.push({
2948
+ code,
2949
+ severity: "error",
2950
+ reference: reference.original,
2951
+ message,
2952
+ path: reference.path
2953
+ });
2954
+ }
2955
+
2956
+ // src/interactive/interactive-session-execution.ts
2080
2957
  function isAbortError(err) {
2081
2958
  return err instanceof DOMException && err.name === "AbortError" || err instanceof Error && (err.message.includes("aborted") || err.message.includes("abort"));
2082
2959
  }
@@ -2092,7 +2969,7 @@ function extractToolSummaries(history, historyBefore) {
2092
2969
  }
2093
2970
  return summaries;
2094
2971
  }
2095
- function buildResult(response, sessionHistory, interactiveHistory, historyBefore, contextState) {
2972
+ function buildResult(response, sessionHistory, interactiveHistory, historyBefore, contextState, promptFileReferences) {
2096
2973
  const toolSummaries = extractToolSummaries(sessionHistory, historyBefore);
2097
2974
  const usage = extractTurnUsage(sessionHistory, historyBefore, contextState);
2098
2975
  return {
@@ -2100,7 +2977,8 @@ function buildResult(response, sessionHistory, interactiveHistory, historyBefore
2100
2977
  history: interactiveHistory,
2101
2978
  toolSummaries,
2102
2979
  contextState,
2103
- ...usage && { usage }
2980
+ ...usage && { usage },
2981
+ ...promptFileReferences && promptFileReferences.length > 0 ? { promptFileReferences: [...promptFileReferences] } : {}
2104
2982
  };
2105
2983
  }
2106
2984
  function buildInterruptedResult(sessionHistory, interactiveHistory, historyBefore, contextState) {
@@ -2121,13 +2999,50 @@ function buildInterruptedResult(sessionHistory, interactiveHistory, historyBefor
2121
2999
  }
2122
3000
  function createUsageSummaryEntry(usage) {
2123
3001
  return {
2124
- id: `usage_${randomUUID()}`,
3002
+ id: `usage_${randomUUID2()}`,
2125
3003
  timestamp: /* @__PURE__ */ new Date(),
2126
3004
  category: "event",
2127
3005
  type: "usage-summary",
2128
3006
  data: usage
2129
3007
  };
2130
3008
  }
3009
+ async function preparePromptInput(input, cwd, rawInput, contextReferences = []) {
3010
+ const activeReferenceResult = await resolvePromptFileReferencePaths(
3011
+ listActiveContextReferences(contextReferences).map((reference) => reference.sourcePath),
3012
+ { cwd, reason: "manual" }
3013
+ );
3014
+ const promptFileReferenceResult = await resolvePromptFileReferences(input, { cwd });
3015
+ const diagnostics = [
3016
+ ...activeReferenceResult.diagnostics,
3017
+ ...promptFileReferenceResult.diagnostics
3018
+ ];
3019
+ if (hasBlockingPromptFileReferenceDiagnostics(diagnostics)) {
3020
+ throw new Error(formatPromptFileReferenceDiagnostics(diagnostics));
3021
+ }
3022
+ const resolvedReferences = dedupeResolvedReferences([
3023
+ ...activeReferenceResult.references,
3024
+ ...promptFileReferenceResult.references
3025
+ ]);
3026
+ const modelInput = buildPromptWithFileReferences(input, resolvedReferences);
3027
+ const hookInput = rawInput ?? (modelInput === input ? void 0 : input);
3028
+ const activeContextReferenceRecords = toPromptFileReferenceRecords(
3029
+ activeReferenceResult.references
3030
+ );
3031
+ const promptFileReferenceRecords = toPromptFileReferenceRecords(
3032
+ promptFileReferenceResult.references
3033
+ );
3034
+ const promptFileReferenceEntry = promptFileReferenceResult.references.length > 0 ? createPromptFileReferenceHistoryEntry(promptFileReferenceResult.references) : void 0;
3035
+ return {
3036
+ modelInput,
3037
+ ...hookInput !== void 0 ? { hookInput } : {},
3038
+ activeContextReferenceRecords,
3039
+ promptFileReferenceRecords,
3040
+ ...promptFileReferenceEntry !== void 0 ? { promptFileReferenceEntry } : {}
3041
+ };
3042
+ }
3043
+ function dedupeResolvedReferences(references) {
3044
+ return [...new Map(references.map((reference) => [reference.sourcePath, reference])).values()];
3045
+ }
2131
3046
  function extractTurnUsage(sessionHistory, historyBefore, contextState) {
2132
3047
  const turnMessages = sessionHistory.slice(historyBefore);
2133
3048
  let promptTokens = 0;
@@ -2154,34 +3069,6 @@ function extractTurnUsage(sessionHistory, historyBefore, contextState) {
2154
3069
  costStatus: "unknown"
2155
3070
  };
2156
3071
  }
2157
- function persistSession(sessionStore, session, sessionName, cwd, history, backgroundState, memoryState) {
2158
- try {
2159
- const sessionId = session.getSessionId();
2160
- const existing = sessionStore.load(sessionId);
2161
- sessionStore.save({
2162
- id: sessionId,
2163
- name: sessionName ?? existing?.name,
2164
- cwd,
2165
- createdAt: existing?.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
2166
- updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
2167
- messages: session.getHistory(),
2168
- history,
2169
- systemPrompt: session.getSystemMessage(),
2170
- toolSchemas: session.getToolSchemas(),
2171
- ...backgroundState ? {
2172
- backgroundTasks: [...backgroundState.tasks],
2173
- backgroundTaskEvents: [...backgroundState.events],
2174
- backgroundJobGroups: [...backgroundState.groups ?? []],
2175
- backgroundJobGroupEvents: [...backgroundState.groupEvents ?? []]
2176
- } : {},
2177
- ...memoryState ? {
2178
- memoryEvents: [...memoryState.events],
2179
- usedMemoryReferences: [...memoryState.usedReferences]
2180
- } : {}
2181
- });
2182
- } catch {
2183
- }
2184
- }
2185
3072
  var NOOP_TERMINAL = {
2186
3073
  write: () => {
2187
3074
  },
@@ -2198,8 +3085,75 @@ var NOOP_TERMINAL = {
2198
3085
  } })
2199
3086
  };
2200
3087
 
3088
+ // src/interactive/interactive-session-persistence.ts
3089
+ function persistSession(sessionStore, session, sessionName, cwd, history, backgroundState, memoryState, skillActivationState, contextReferenceState, sandboxState) {
3090
+ try {
3091
+ const sessionId = session.getSessionId();
3092
+ const existing = sessionStore.load(sessionId);
3093
+ const sandboxSnapshotId = sandboxState?.snapshotId ?? existing?.sandboxSnapshotId;
3094
+ sessionStore.save(
3095
+ buildInteractiveSessionRecord({
3096
+ session,
3097
+ sessionId,
3098
+ sessionName: sessionName ?? existing?.name,
3099
+ cwd,
3100
+ history,
3101
+ createdAt: existing?.createdAt,
3102
+ backgroundState,
3103
+ memoryState,
3104
+ skillActivationState,
3105
+ contextReferenceState,
3106
+ ...sandboxSnapshotId !== void 0 ? { sandboxSnapshotId } : {}
3107
+ })
3108
+ );
3109
+ } catch {
3110
+ }
3111
+ }
3112
+ function buildInteractiveSessionRecord(input) {
3113
+ return {
3114
+ id: input.sessionId,
3115
+ ...input.sessionName !== void 0 ? { name: input.sessionName } : {},
3116
+ cwd: input.cwd,
3117
+ createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
3118
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
3119
+ messages: input.session.getHistory(),
3120
+ history: input.history,
3121
+ systemPrompt: input.session.getSystemMessage(),
3122
+ toolSchemas: input.session.getToolSchemas(),
3123
+ ...input.sandboxSnapshotId !== void 0 ? { sandboxSnapshotId: input.sandboxSnapshotId } : {},
3124
+ ...buildBackgroundRecordFields(input.backgroundState),
3125
+ ...buildMemoryRecordFields(input.memoryState),
3126
+ ...buildSkillActivationRecordFields(input.skillActivationState),
3127
+ ...buildContextReferenceRecordFields(input.contextReferenceState)
3128
+ };
3129
+ }
3130
+ function buildBackgroundRecordFields(state) {
3131
+ if (!state) return {};
3132
+ return {
3133
+ backgroundTasks: [...state.tasks],
3134
+ backgroundTaskEvents: [...state.events],
3135
+ backgroundJobGroups: [...state.groups ?? []],
3136
+ backgroundJobGroupEvents: [...state.groupEvents ?? []]
3137
+ };
3138
+ }
3139
+ function buildMemoryRecordFields(state) {
3140
+ if (!state) return {};
3141
+ return {
3142
+ memoryEvents: [...state.events],
3143
+ usedMemoryReferences: [...state.usedReferences]
3144
+ };
3145
+ }
3146
+ function buildSkillActivationRecordFields(state) {
3147
+ if (!state) return {};
3148
+ return { skillActivationEvents: [...state.events] };
3149
+ }
3150
+ function buildContextReferenceRecordFields(state) {
3151
+ if (!state) return {};
3152
+ return { contextReferences: [...state.references] };
3153
+ }
3154
+
2201
3155
  // src/interactive/interactive-session-streaming.ts
2202
- import { randomUUID as randomUUID2 } from "crypto";
3156
+ import { randomUUID as randomUUID3 } from "crypto";
2203
3157
  import { readFileSync as readFileSync4 } from "fs";
2204
3158
  var TOOL_ARG_DISPLAY_MAX = 80;
2205
3159
  var TAIL_KEEP = 30;
@@ -2297,7 +3251,7 @@ function pushToolSummaryToHistory(state) {
2297
3251
  return `${status} ${t.toolName}${t.firstArg ? `(${t.firstArg})` : ""}`;
2298
3252
  }).join("\n");
2299
3253
  state.history.push({
2300
- id: randomUUID2(),
3254
+ id: randomUUID3(),
2301
3255
  timestamp: /* @__PURE__ */ new Date(),
2302
3256
  category: "event",
2303
3257
  type: "tool-summary",
@@ -2333,7 +3287,7 @@ function applyToolStart(state, event) {
2333
3287
  const toolState = { toolName: event.toolName, firstArg, isRunning: true };
2334
3288
  state.activeTools.push(toolState);
2335
3289
  state.history.push({
2336
- id: randomUUID2(),
3290
+ id: randomUUID3(),
2337
3291
  timestamp: /* @__PURE__ */ new Date(),
2338
3292
  category: "event",
2339
3293
  type: "tool-start",
@@ -2355,7 +3309,7 @@ function applyToolEnd(state, event) {
2355
3309
  state.activeTools[idx] = finished;
2356
3310
  state.activeTools = trimCompletedTools(state.activeTools);
2357
3311
  state.history.push({
2358
- id: randomUUID2(),
3312
+ id: randomUUID3(),
2359
3313
  timestamp: /* @__PURE__ */ new Date(),
2360
3314
  category: "event",
2361
3315
  type: "tool-end",
@@ -2372,113 +3326,113 @@ function applyToolEnd(state, event) {
2372
3326
 
2373
3327
  // src/config/config-loader.ts
2374
3328
  import { readFileSync as readFileSync5, existsSync as existsSync4 } from "fs";
2375
- import { join as join4 } from "path";
3329
+ import { join as join6 } from "path";
2376
3330
 
2377
3331
  // src/config/config-types.ts
2378
- import { z as z2 } from "zod";
2379
- var UniversalValueSchema = z2.lazy(
2380
- () => z2.union([
2381
- z2.string(),
2382
- z2.number(),
2383
- z2.boolean(),
2384
- z2.null(),
2385
- z2.undefined(),
2386
- z2.date(),
2387
- z2.array(UniversalValueSchema),
2388
- z2.record(UniversalValueSchema)
3332
+ import { z as z3 } from "zod";
3333
+ var UniversalValueSchema = z3.lazy(
3334
+ () => z3.union([
3335
+ z3.string(),
3336
+ z3.number(),
3337
+ z3.boolean(),
3338
+ z3.null(),
3339
+ z3.undefined(),
3340
+ z3.date(),
3341
+ z3.array(UniversalValueSchema),
3342
+ z3.record(UniversalValueSchema)
2389
3343
  ])
2390
3344
  );
2391
- var ProviderSchema = z2.object({
2392
- name: z2.string().optional(),
2393
- model: z2.string().optional(),
2394
- apiKey: z2.string().optional(),
2395
- baseURL: z2.string().optional(),
2396
- timeout: z2.number().optional(),
2397
- options: z2.record(UniversalValueSchema).optional()
3345
+ var ProviderSchema = z3.object({
3346
+ name: z3.string().optional(),
3347
+ model: z3.string().optional(),
3348
+ apiKey: z3.string().optional(),
3349
+ baseURL: z3.string().optional(),
3350
+ timeout: z3.number().optional(),
3351
+ options: z3.record(UniversalValueSchema).optional()
2398
3352
  });
2399
- var ProviderProfileSchema = z2.object({
2400
- type: z2.string().optional(),
2401
- model: z2.string().optional(),
2402
- apiKey: z2.string().optional(),
2403
- baseURL: z2.string().optional(),
2404
- timeout: z2.number().optional(),
2405
- options: z2.record(UniversalValueSchema).optional()
3353
+ var ProviderProfileSchema = z3.object({
3354
+ type: z3.string().optional(),
3355
+ model: z3.string().optional(),
3356
+ apiKey: z3.string().optional(),
3357
+ baseURL: z3.string().optional(),
3358
+ timeout: z3.number().optional(),
3359
+ options: z3.record(UniversalValueSchema).optional()
2406
3360
  });
2407
- var PermissionsSchema = z2.object({
3361
+ var PermissionsSchema = z3.object({
2408
3362
  /** Patterns that are always approved without prompting */
2409
- allow: z2.array(z2.string()).optional(),
3363
+ allow: z3.array(z3.string()).optional(),
2410
3364
  /** Patterns that are always denied */
2411
- deny: z2.array(z2.string()).optional()
3365
+ deny: z3.array(z3.string()).optional()
2412
3366
  });
2413
- var EnvSchema = z2.record(z2.string()).optional();
2414
- var CommandHookDefinitionSchema = z2.object({
2415
- type: z2.literal("command"),
2416
- command: z2.string(),
2417
- timeout: z2.number().optional()
3367
+ var EnvSchema = z3.record(z3.string()).optional();
3368
+ var CommandHookDefinitionSchema = z3.object({
3369
+ type: z3.literal("command"),
3370
+ command: z3.string(),
3371
+ timeout: z3.number().optional()
2418
3372
  });
2419
- var HttpHookDefinitionSchema = z2.object({
2420
- type: z2.literal("http"),
2421
- url: z2.string(),
2422
- headers: z2.record(z2.string()).optional(),
2423
- timeout: z2.number().optional()
3373
+ var HttpHookDefinitionSchema = z3.object({
3374
+ type: z3.literal("http"),
3375
+ url: z3.string(),
3376
+ headers: z3.record(z3.string()).optional(),
3377
+ timeout: z3.number().optional()
2424
3378
  });
2425
- var PromptHookDefinitionSchema = z2.object({
2426
- type: z2.literal("prompt"),
2427
- prompt: z2.string(),
2428
- model: z2.string().optional()
3379
+ var PromptHookDefinitionSchema = z3.object({
3380
+ type: z3.literal("prompt"),
3381
+ prompt: z3.string(),
3382
+ model: z3.string().optional()
2429
3383
  });
2430
- var AgentHookDefinitionSchema = z2.object({
2431
- type: z2.literal("agent"),
2432
- agent: z2.string(),
2433
- maxTurns: z2.number().optional(),
2434
- timeout: z2.number().optional()
3384
+ var AgentHookDefinitionSchema = z3.object({
3385
+ type: z3.literal("agent"),
3386
+ agent: z3.string(),
3387
+ maxTurns: z3.number().optional(),
3388
+ timeout: z3.number().optional()
2435
3389
  });
2436
- var HookDefinitionSchema = z2.discriminatedUnion("type", [
3390
+ var HookDefinitionSchema = z3.discriminatedUnion("type", [
2437
3391
  CommandHookDefinitionSchema,
2438
3392
  HttpHookDefinitionSchema,
2439
3393
  PromptHookDefinitionSchema,
2440
3394
  AgentHookDefinitionSchema
2441
3395
  ]);
2442
- var HookGroupSchema = z2.object({
2443
- matcher: z2.string(),
2444
- hooks: z2.array(HookDefinitionSchema)
3396
+ var HookGroupSchema = z3.object({
3397
+ matcher: z3.string(),
3398
+ hooks: z3.array(HookDefinitionSchema)
2445
3399
  });
2446
- var HooksSchema = z2.object({
2447
- PreToolUse: z2.array(HookGroupSchema).optional(),
2448
- PostToolUse: z2.array(HookGroupSchema).optional(),
2449
- SessionStart: z2.array(HookGroupSchema).optional(),
2450
- SessionEnd: z2.array(HookGroupSchema).optional(),
2451
- Stop: z2.array(HookGroupSchema).optional(),
2452
- StopFailure: z2.array(HookGroupSchema).optional(),
2453
- PreCompact: z2.array(HookGroupSchema).optional(),
2454
- PostCompact: z2.array(HookGroupSchema).optional(),
2455
- UserPromptSubmit: z2.array(HookGroupSchema).optional(),
2456
- SubagentStart: z2.array(HookGroupSchema).optional(),
2457
- SubagentStop: z2.array(HookGroupSchema).optional(),
2458
- WorktreeCreate: z2.array(HookGroupSchema).optional(),
2459
- WorktreeRemove: z2.array(HookGroupSchema).optional()
3400
+ var HooksSchema = z3.object({
3401
+ PreToolUse: z3.array(HookGroupSchema).optional(),
3402
+ PostToolUse: z3.array(HookGroupSchema).optional(),
3403
+ SessionStart: z3.array(HookGroupSchema).optional(),
3404
+ SessionEnd: z3.array(HookGroupSchema).optional(),
3405
+ Stop: z3.array(HookGroupSchema).optional(),
3406
+ StopFailure: z3.array(HookGroupSchema).optional(),
3407
+ PreCompact: z3.array(HookGroupSchema).optional(),
3408
+ PostCompact: z3.array(HookGroupSchema).optional(),
3409
+ UserPromptSubmit: z3.array(HookGroupSchema).optional(),
3410
+ SubagentStart: z3.array(HookGroupSchema).optional(),
3411
+ SubagentStop: z3.array(HookGroupSchema).optional(),
3412
+ WorktreeCreate: z3.array(HookGroupSchema).optional(),
3413
+ WorktreeRemove: z3.array(HookGroupSchema).optional()
2460
3414
  }).optional();
2461
- var EnabledPluginsSchema = z2.record(z2.boolean()).optional();
2462
- var MarketplaceSourceSchema = z2.object({
2463
- source: z2.object({
2464
- type: z2.enum(["github", "git", "local", "url"]),
2465
- repo: z2.string().optional(),
2466
- url: z2.string().optional(),
2467
- path: z2.string().optional(),
2468
- ref: z2.string().optional()
3415
+ var EnabledPluginsSchema = z3.record(z3.boolean()).optional();
3416
+ var MarketplaceSourceSchema = z3.object({
3417
+ source: z3.object({
3418
+ type: z3.enum(["github", "git", "local", "url"]),
3419
+ repo: z3.string().optional(),
3420
+ url: z3.string().optional(),
3421
+ path: z3.string().optional(),
3422
+ ref: z3.string().optional()
2469
3423
  })
2470
3424
  });
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();
2473
- var SettingsSchema = z2.object({
3425
+ var ExtraKnownMarketplacesSchema = z3.record(MarketplaceSourceSchema).optional().catch(void 0);
3426
+ var AutoCompactThresholdSchema = z3.union([z3.number().gt(0).lte(1), z3.literal(false)]).optional();
3427
+ var SettingsSchema = z3.object({
2474
3428
  /** Trust level used when no --permission-mode flag is given */
2475
- defaultTrustLevel: z2.enum(["safe", "moderate", "full"]).optional(),
3429
+ defaultTrustLevel: z3.enum(["safe", "moderate", "full"]).optional(),
2476
3430
  /** Response language (e.g., "ko", "en", "ja"). Injected into system prompt. */
2477
- language: z2.string().optional(),
3431
+ language: z3.string().optional(),
2478
3432
  /** Active provider profile key from providers. */
2479
- currentProvider: z2.string().optional(),
3433
+ currentProvider: z3.string().optional(),
2480
3434
  /** Provider profiles keyed by user-facing profile name. */
2481
- providers: z2.record(ProviderProfileSchema).optional(),
3435
+ providers: z3.record(ProviderProfileSchema).optional(),
2482
3436
  /** Legacy single-provider settings. Prefer currentProvider + providers for new config. */
2483
3437
  provider: ProviderSchema.optional(),
2484
3438
  permissions: PermissionsSchema.optional(),
@@ -2532,18 +3486,12 @@ function resolveEnvRef(value) {
2532
3486
  return value;
2533
3487
  }
2534
3488
  function resolveEnvRefs(settings) {
2535
- const provider = settings.provider?.apiKey !== void 0 ? {
2536
- ...settings.provider,
2537
- apiKey: resolveEnvRef(settings.provider.apiKey)
2538
- } : settings.provider;
3489
+ const provider = settings.provider?.apiKey !== void 0 ? resolveProviderCredentialEnvRefs(settings.provider) : settings.provider;
2539
3490
  if (settings.providers !== void 0) {
2540
3491
  const providers = Object.fromEntries(
2541
3492
  Object.entries(settings.providers).map(([name, profile]) => [
2542
3493
  name,
2543
- {
2544
- ...profile,
2545
- ...profile.apiKey !== void 0 && { apiKey: resolveEnvRef(profile.apiKey) }
2546
- }
3494
+ resolveProviderCredentialEnvRefs(profile)
2547
3495
  ])
2548
3496
  );
2549
3497
  return {
@@ -2557,6 +3505,12 @@ function resolveEnvRefs(settings) {
2557
3505
  provider
2558
3506
  };
2559
3507
  }
3508
+ function resolveProviderCredentialEnvRefs(provider) {
3509
+ return {
3510
+ ...provider,
3511
+ ...provider.apiKey !== void 0 && { apiKey: resolveEnvRef(provider.apiKey) }
3512
+ };
3513
+ }
2560
3514
  function mergeSettings(layers) {
2561
3515
  return layers.reduce((merged, layer) => {
2562
3516
  return {
@@ -2590,22 +3544,32 @@ function mergeProviders(base, override) {
2590
3544
  }
2591
3545
  function resolveProvider(merged) {
2592
3546
  if (merged.currentProvider !== void 0) {
2593
- const profile = merged.providers?.[merged.currentProvider];
2594
- if (profile === void 0) {
2595
- throw new Error(`currentProvider "${merged.currentProvider}" was not found in providers`);
2596
- }
2597
- if (profile.type === void 0) {
2598
- throw new Error(`Provider profile "${merged.currentProvider}" is missing type`);
2599
- }
2600
- return {
2601
- name: profile.type,
2602
- model: profile.model ?? DEFAULTS.provider.model,
2603
- apiKey: profile.apiKey ?? DEFAULTS.provider.apiKey,
2604
- ...profile.baseURL !== void 0 && { baseURL: profile.baseURL },
2605
- ...profile.timeout !== void 0 && { timeout: profile.timeout },
2606
- ...profile.options !== void 0 && { options: profile.options }
2607
- };
3547
+ return resolveActiveProviderProfile2(merged);
3548
+ }
3549
+ return resolveLegacyProvider(merged);
3550
+ }
3551
+ function resolveActiveProviderProfile2(merged) {
3552
+ const currentProvider = merged.currentProvider;
3553
+ if (currentProvider === void 0) {
3554
+ throw new Error("currentProvider is required");
3555
+ }
3556
+ const profile = merged.providers?.[currentProvider];
3557
+ if (profile === void 0) {
3558
+ throw new Error(`currentProvider "${currentProvider}" was not found in providers`);
2608
3559
  }
3560
+ if (profile.type === void 0) {
3561
+ throw new Error(`Provider profile "${currentProvider}" is missing type`);
3562
+ }
3563
+ return {
3564
+ name: profile.type,
3565
+ model: profile.model ?? DEFAULTS.provider.model,
3566
+ apiKey: profile.apiKey ?? DEFAULTS.provider.apiKey,
3567
+ ...profile.baseURL !== void 0 && { baseURL: profile.baseURL },
3568
+ ...profile.timeout !== void 0 && { timeout: profile.timeout },
3569
+ ...profile.options !== void 0 && { options: profile.options }
3570
+ };
3571
+ }
3572
+ function resolveLegacyProvider(merged) {
2609
3573
  return {
2610
3574
  name: merged.provider?.name ?? DEFAULTS.provider.name,
2611
3575
  model: merged.provider?.model ?? DEFAULTS.provider.model,
@@ -2635,17 +3599,17 @@ function toResolvedConfig(merged) {
2635
3599
  function getSettingsPaths(cwd) {
2636
3600
  const home = getHomeDir();
2637
3601
  return [
2638
- join4(home, ".robota", "settings.json"),
3602
+ join6(home, ".robota", "settings.json"),
2639
3603
  // 1. user (lowest)
2640
- join4(home, ".claude", "settings.json"),
3604
+ join6(home, ".claude", "settings.json"),
2641
3605
  // 1b. user (Claude Code compat)
2642
- join4(cwd, ".robota", "settings.json"),
3606
+ join6(cwd, ".robota", "settings.json"),
2643
3607
  // 2. project
2644
- join4(cwd, ".robota", "settings.local.json"),
3608
+ join6(cwd, ".robota", "settings.local.json"),
2645
3609
  // 3. project-local
2646
- join4(cwd, ".claude", "settings.json"),
3610
+ join6(cwd, ".claude", "settings.json"),
2647
3611
  // 4. project, Claude Code compat
2648
- join4(cwd, ".claude", "settings.local.json")
3612
+ join6(cwd, ".claude", "settings.local.json")
2649
3613
  // 5. project-local (highest)
2650
3614
  ];
2651
3615
  }
@@ -2882,9 +3846,15 @@ function formatCapability(descriptor) {
2882
3846
  return `- ${descriptor.name}${arg}: ${descriptor.description}`;
2883
3847
  }
2884
3848
  function createCapabilityKindSection(kind, title, priority, source, descriptors) {
2885
- const content = descriptors.filter((descriptor) => descriptor.modelInvocable && descriptor.kind === kind).map(formatCapability).join("\n");
2886
- if (content.trim().length === 0) return void 0;
2887
- return createSection(`capability-${kind}`, title, priority, content, source);
3849
+ const formattedDescriptors = descriptors.filter((descriptor) => descriptor.modelInvocable && descriptor.kind === kind).map(formatCapability);
3850
+ if (formattedDescriptors.length === 0) return void 0;
3851
+ return createSection(
3852
+ `capability-${kind}`,
3853
+ title,
3854
+ priority,
3855
+ formattedDescriptors.join("\n"),
3856
+ source
3857
+ );
2888
3858
  }
2889
3859
  function createCapabilitySections(descriptors) {
2890
3860
  const sections = [];
@@ -2952,10 +3922,10 @@ function buildSystemPrompt(params) {
2952
3922
 
2953
3923
  // src/assembly/create-tools.ts
2954
3924
  import {
2955
- bashTool,
2956
- readTool,
2957
- writeTool,
2958
- editTool,
3925
+ createBashTool,
3926
+ createReadTool,
3927
+ createWriteTool,
3928
+ createEditTool,
2959
3929
  globTool,
2960
3930
  grepTool,
2961
3931
  webFetchTool,
@@ -2971,12 +3941,12 @@ var DEFAULT_TOOL_DESCRIPTIONS = [
2971
3941
  "WebFetch \u2014 fetch URL content as text",
2972
3942
  "WebSearch \u2014 search the internet through the configured local tool"
2973
3943
  ];
2974
- function createDefaultTools() {
3944
+ function createDefaultTools(options = {}) {
2975
3945
  return [
2976
- bashTool,
2977
- readTool,
2978
- writeTool,
2979
- editTool,
3946
+ createBashTool(options),
3947
+ createReadTool(options),
3948
+ createWriteTool(options),
3949
+ createEditTool(options),
2980
3950
  globTool,
2981
3951
  grepTool,
2982
3952
  webFetchTool,
@@ -2985,18 +3955,18 @@ function createDefaultTools() {
2985
3955
  }
2986
3956
 
2987
3957
  // src/tools/background-process-tool.ts
2988
- import { z as z3 } from "zod";
2989
- import { createZodFunctionTool as createZodFunctionTool2 } from "@robota-sdk/agent-tools";
3958
+ import { z as z4 } from "zod";
3959
+ import { createZodFunctionTool as createZodFunctionTool3 } from "@robota-sdk/agent-tools";
2990
3960
  var DEFAULT_PROCESS_TIMEOUT_MS = 12e4;
2991
- function asZodSchema2(schema) {
3961
+ function asZodSchema3(schema) {
2992
3962
  return schema;
2993
3963
  }
2994
- var BackgroundProcessSchema = z3.object({
2995
- command: z3.string().describe("The shell command to start in the background"),
2996
- timeout: z3.number().optional().describe("Optional timeout in milliseconds. Default is 120000."),
2997
- workingDirectory: z3.string().optional().describe("Working directory for the command. Defaults to the current project directory."),
2998
- stdin: z3.string().optional().describe("Optional stdin to write after the process starts."),
2999
- outputLimitBytes: z3.number().optional().describe("Maximum captured output bytes kept in the task result.")
3964
+ var BackgroundProcessSchema = z4.object({
3965
+ command: z4.string().describe("The shell command to start in the background"),
3966
+ timeout: z4.number().optional().describe("Optional timeout in milliseconds. Default is 120000."),
3967
+ workingDirectory: z4.string().optional().describe("Working directory for the command. Defaults to the current project directory."),
3968
+ stdin: z4.string().optional().describe("Optional stdin to write after the process starts."),
3969
+ outputLimitBytes: z4.number().optional().describe("Maximum captured output bytes kept in the task result.")
3000
3970
  });
3001
3971
  function stringifyStarted(taskId, status, command) {
3002
3972
  return JSON.stringify({
@@ -3027,68 +3997,20 @@ async function startBackgroundProcess(args, deps) {
3027
3997
  cwd: args.workingDirectory ?? deps.cwd ?? process.cwd(),
3028
3998
  command: args.command,
3029
3999
  stdin: args.stdin,
3030
- timeoutMs: args.timeout ?? DEFAULT_PROCESS_TIMEOUT_MS,
3031
- outputLimitBytes: args.outputLimitBytes
3032
- });
3033
- return stringifyStarted(state.id, state.status, args.command);
3034
- } catch (error) {
3035
- return stringifyProcessError(error instanceof Error ? error.message : String(error));
3036
- }
3037
- }
3038
- function createBackgroundProcessTool(deps) {
3039
- return createZodFunctionTool2(
3040
- "BackgroundProcess",
3041
- "Start a shell command as a managed background task. Use this for long-running commands that should not block the current conversation. Use /background list, /background read <taskId>, /background cancel <taskId>, or /background close <taskId> to inspect or control it.",
3042
- asZodSchema2(BackgroundProcessSchema),
3043
- async (params) => startBackgroundProcess(params, deps)
3044
- );
3045
- }
3046
-
3047
- // src/tools/command-execution-tool.ts
3048
- import { z as z4 } from "zod";
3049
- import { createZodFunctionTool as createZodFunctionTool3 } from "@robota-sdk/agent-tools";
3050
- var CommandExecutionSchema = z4.object({
3051
- command: z4.string().describe("Command name to execute, with or without a leading slash"),
3052
- args: z4.string().optional().describe("Arguments to pass to the command")
3053
- });
3054
- function asZodSchema3(schema) {
3055
- return schema;
3056
- }
3057
- function normalizeCommand(command) {
3058
- return command.trim().replace(/^\/+/, "").split(/\s+/)[0] ?? "";
3059
- }
3060
- function stringifyCommandResult(command, result) {
3061
- if (!result) {
3062
- return JSON.stringify({
3063
- success: false,
3064
- command,
3065
- error: `Unknown command: ${command}`
4000
+ timeoutMs: args.timeout ?? DEFAULT_PROCESS_TIMEOUT_MS,
4001
+ outputLimitBytes: args.outputLimitBytes
3066
4002
  });
4003
+ return stringifyStarted(state.id, state.status, args.command);
4004
+ } catch (error) {
4005
+ return stringifyProcessError(error instanceof Error ? error.message : String(error));
3067
4006
  }
3068
- return JSON.stringify({
3069
- success: result.success,
3070
- command,
3071
- message: result.message,
3072
- data: result.data
3073
- });
3074
4007
  }
3075
- function createCommandExecutionTool(deps) {
4008
+ function createBackgroundProcessTool(deps) {
3076
4009
  return createZodFunctionTool3(
3077
- "ExecuteCommand",
3078
- "Executes a registered model-invocable Robota command through the command registry. Accepted command names and argument grammar come from registered command descriptors.",
3079
- asZodSchema3(CommandExecutionSchema),
3080
- async (params) => {
3081
- const args = CommandExecutionSchema.parse(params);
3082
- const command = normalizeCommand(args.command);
3083
- if (!deps.isModelInvocable(command)) {
3084
- return JSON.stringify({
3085
- success: false,
3086
- command,
3087
- error: `Command is not model-invocable: ${command}`
3088
- });
3089
- }
3090
- return stringifyCommandResult(command, await deps.execute(command, args.args ?? ""));
3091
- }
4010
+ "BackgroundProcess",
4011
+ "Start a shell command as a managed background task. Use this for long-running commands that should not block the current conversation. Use /background list, /background read <taskId>, /background cancel <taskId>, or /background close <taskId> to inspect or control it.",
4012
+ asZodSchema3(BackgroundProcessSchema),
4013
+ async (params) => startBackgroundProcess(params, deps)
3092
4014
  );
3093
4015
  }
3094
4016
 
@@ -3152,6 +4074,9 @@ function evaluateReversibleToolSafety(input) {
3152
4074
  };
3153
4075
  }
3154
4076
  if (FILE_MUTATION_TOOLS.has(toolName)) {
4077
+ if (input.context.isolation === "worktree" || input.context.isolation === "provider-sandbox") {
4078
+ return evaluateIsolatedSideEffect(toolName, "file-mutation", input.context);
4079
+ }
3155
4080
  if (input.context.checkpointAvailable) {
3156
4081
  return {
3157
4082
  toolName,
@@ -3334,8 +4259,8 @@ import { BackgroundTaskManager as BackgroundTaskManager2, SubagentManager as Sub
3334
4259
 
3335
4260
  // src/agents/agent-definition-loader.ts
3336
4261
  import { readdirSync as readdirSync3, readFileSync as readFileSync6, existsSync as existsSync5 } from "fs";
3337
- import { join as join5, basename as basename3 } from "path";
3338
- import { homedir as homedir2 } from "os";
4262
+ import { join as join7, basename as basename3 } from "path";
4263
+ import { homedir as homedir4 } from "os";
3339
4264
  var LIST_KEYS2 = /* @__PURE__ */ new Set(["tools", "disallowedTools"]);
3340
4265
  var NUMBER_KEYS = /* @__PURE__ */ new Set(["maxTurns"]);
3341
4266
  function parseListValue2(rawValue) {
@@ -3389,7 +4314,7 @@ function scanAgentsDir(dir) {
3389
4314
  }
3390
4315
  for (const entry of entries) {
3391
4316
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
3392
- const filePath = join5(dir, entry.name);
4317
+ const filePath = join7(dir, entry.name);
3393
4318
  const content = readFileSync6(filePath, "utf-8");
3394
4319
  const { frontmatter, body } = parseFrontmatter2(content);
3395
4320
  const fallbackName = basename3(entry.name, ".md");
@@ -3412,16 +4337,16 @@ var AgentDefinitionLoader = class {
3412
4337
  home;
3413
4338
  constructor(cwd, home) {
3414
4339
  this.cwd = cwd;
3415
- this.home = home ?? homedir2();
4340
+ this.home = home ?? homedir4();
3416
4341
  }
3417
4342
  /** Load all agent definitions, merged with built-in agents. Custom overrides built-in on name collision. */
3418
4343
  loadAll() {
3419
4344
  const sources = [
3420
- scanAgentsDir(join5(this.cwd, ".robota", "agents")),
3421
- scanAgentsDir(join5(this.cwd, ".agents", "agents")),
3422
- scanAgentsDir(join5(this.cwd, ".claude", "agents")),
3423
- scanAgentsDir(join5(this.home, ".robota", "agents")),
3424
- scanAgentsDir(join5(this.home, ".claude", "agents"))
4345
+ scanAgentsDir(join7(this.cwd, ".robota", "agents")),
4346
+ scanAgentsDir(join7(this.cwd, ".agents", "agents")),
4347
+ scanAgentsDir(join7(this.cwd, ".claude", "agents")),
4348
+ scanAgentsDir(join7(this.home, ".robota", "agents")),
4349
+ scanAgentsDir(join7(this.home, ".claude", "agents"))
3425
4350
  ];
3426
4351
  const seen = /* @__PURE__ */ new Set();
3427
4352
  const customAgents = [];
@@ -3490,6 +4415,17 @@ function fireSubagentLifecycleHook(event, cwd, hooks, hookTypeExecutors) {
3490
4415
  var ID_RADIX = 36;
3491
4416
  var ID_RANDOM_LENGTH = 9;
3492
4417
  var DEFAULT_PROVIDER_IDLE_TIMEOUT_MS = 12e4;
4418
+ function getModelInvocableCommandDescriptors(descriptors) {
4419
+ return (descriptors ?? []).filter(
4420
+ (descriptor) => descriptor.modelInvocable && descriptor.kind === "builtin-command"
4421
+ );
4422
+ }
4423
+ function normalizeCommandDescriptorName(name) {
4424
+ return name.trim().replace(/^\/+/, "").split(/\s+/)[0] ?? "";
4425
+ }
4426
+ function hasModelInvocableCommandDescriptor(descriptors, name) {
4427
+ return descriptors.some((descriptor) => normalizeCommandDescriptorName(descriptor.name) === name);
4428
+ }
3493
4429
  function createSession(options) {
3494
4430
  if (!options.provider) {
3495
4431
  throw new Error(
@@ -3499,17 +4435,34 @@ function createSession(options) {
3499
4435
  const provider = options.provider;
3500
4436
  const cwd = options.cwd ?? process.cwd();
3501
4437
  const sessionId = options.sessionId ?? createSessionId();
3502
- const defaultTools = options.editCheckpointRecorder ? wrapEditCheckpointTools(createDefaultTools(), options.editCheckpointRecorder) : createDefaultTools();
4438
+ const skillCommandSource = new SkillCommandSource(cwd);
4439
+ const modelInvocableCommandDescriptors = getModelInvocableCommandDescriptors(
4440
+ options.commandDescriptors
4441
+ );
4442
+ const modelCommandToolsEnabled = modelInvocableCommandDescriptors.length > 0 && options.modelCommandExecutor !== void 0 && options.isModelCommandInvocable !== void 0;
4443
+ const modelCommandToolProjection = modelCommandToolsEnabled ? createModelCommandToolProjection(modelInvocableCommandDescriptors) : void 0;
4444
+ const modelVisibleSkills = hasModelInvocableCommandDescriptor(
4445
+ modelInvocableCommandDescriptors,
4446
+ "skills"
4447
+ ) ? skillCommandSource.getModelInvocableSkills() : [];
4448
+ const baseDefaultTools = createDefaultTools({ sandboxClient: options.sandboxClient });
4449
+ const shouldWrapHostEditCheckpoints = options.editCheckpointRecorder !== void 0 && options.sandboxClient === void 0;
4450
+ const defaultTools = shouldWrapHostEditCheckpoints && options.editCheckpointRecorder ? wrapEditCheckpointTools(baseDefaultTools, options.editCheckpointRecorder) : baseDefaultTools;
3503
4451
  const assembledTools = [...defaultTools, ...options.additionalTools ?? []];
3504
- const tools = options.reversibleExecution ? wrapReversibleExecutionTools(assembledTools, {
4452
+ const reversibleExecution = options.reversibleExecution ? {
3505
4453
  ...options.reversibleExecution,
3506
- checkpointAvailable: options.editCheckpointRecorder !== void 0
4454
+ isolation: options.reversibleExecution.isolation ?? (options.sandboxClient ? "provider-sandbox" : void 0)
4455
+ } : void 0;
4456
+ const tools = reversibleExecution ? wrapReversibleExecutionTools(assembledTools, {
4457
+ ...reversibleExecution,
4458
+ checkpointAvailable: shouldWrapHostEditCheckpoints
3507
4459
  }) : assembledTools;
3508
- if (options.modelCommandExecutor && options.isModelCommandInvocable) {
4460
+ if (modelCommandToolsEnabled && options.modelCommandExecutor !== void 0 && options.isModelCommandInvocable !== void 0) {
3509
4461
  tools.push(
3510
- createCommandExecutionTool({
4462
+ ...createProjectedCommandExecutionTools({
3511
4463
  execute: options.modelCommandExecutor,
3512
- isModelInvocable: options.isModelCommandInvocable
4464
+ isModelInvocable: options.isModelCommandInvocable,
4465
+ commandDescriptors: modelInvocableCommandDescriptors
3513
4466
  })
3514
4467
  );
3515
4468
  }
@@ -3592,14 +4545,12 @@ function createSession(options) {
3592
4545
  };
3593
4546
  tools.push(createBackgroundProcessTool(backgroundProcessToolDeps));
3594
4547
  }
3595
- if (agentToolDeps) {
3596
- tools.push(createAgentTool(agentToolDeps));
3597
- }
3598
4548
  const buildPrompt = options.systemPromptBuilder ?? buildSystemPrompt;
3599
4549
  const defaultToolDescriptions = [
3600
4550
  ...DEFAULT_TOOL_DESCRIPTIONS,
3601
- ...agentToolDeps ? [createAgentToolPromptDescription(agentDefinitions)] : [],
3602
- ...options.modelCommandExecutor ? ["ExecuteCommand \u2014 execute model-invocable Robota commands"] : []
4551
+ ...modelCommandToolProjection ? modelCommandToolProjection.commandTools.map(
4552
+ formatProjectedModelCommandToolPromptDescription
4553
+ ) : []
3603
4554
  ];
3604
4555
  const systemMessage = buildPrompt({
3605
4556
  agentsMd: options.context.agentsMd,
@@ -3614,7 +4565,7 @@ function createSession(options) {
3614
4565
  projectInfo: options.projectInfo ?? { type: "unknown", language: "unknown" },
3615
4566
  cwd,
3616
4567
  language: options.config.language,
3617
- skills: new SkillCommandSource(cwd).getModelInvocableSkills().map((skill) => ({
4568
+ skills: modelVisibleSkills.map((skill) => ({
3618
4569
  name: skill.name,
3619
4570
  description: skill.description,
3620
4571
  disableModelInvocation: skill.disableModelInvocation
@@ -3688,50 +4639,28 @@ function logBackgroundTaskEvent(logger, sessionId, event) {
3688
4639
 
3689
4640
  // src/assembly/subagent-logger.ts
3690
4641
  import { mkdirSync as mkdirSync3 } from "fs";
3691
- import { join as join6 } from "path";
4642
+ import { join as join8 } from "path";
3692
4643
  import { FileSessionLogger } from "@robota-sdk/agent-sessions";
3693
4644
  function createSubagentLogger(parentSessionId, _agentId, baseLogsDir) {
3694
- const subagentDir = join6(baseLogsDir, parentSessionId, "subagents");
4645
+ const subagentDir = join8(baseLogsDir, parentSessionId, "subagents");
3695
4646
  mkdirSync3(subagentDir, { recursive: true });
3696
4647
  return new FileSessionLogger(subagentDir);
3697
4648
  }
3698
4649
  function resolveSubagentLogDir(parentSessionId, baseLogsDir) {
3699
- return join6(baseLogsDir, parentSessionId, "subagents");
4650
+ return join8(baseLogsDir, parentSessionId, "subagents");
3700
4651
  }
3701
4652
 
3702
4653
  // src/interactive/interactive-session-init.ts
3703
4654
  import { FileSessionLogger as FileSessionLogger2 } from "@robota-sdk/agent-sessions";
3704
4655
 
3705
- // src/paths.ts
3706
- import { join as join7 } from "path";
3707
- import { homedir as homedir3 } from "os";
3708
- function projectPaths(cwd) {
3709
- const base = join7(cwd, ".robota");
3710
- return {
3711
- settings: join7(base, "settings.json"),
3712
- settingsLocal: join7(base, "settings.local.json"),
3713
- logs: join7(base, "logs"),
3714
- sessions: join7(base, "sessions"),
3715
- memory: join7(base, "memory"),
3716
- checkpoints: join7(base, "checkpoints")
3717
- };
3718
- }
3719
- function userPaths() {
3720
- const base = join7(homedir3(), ".robota");
3721
- return {
3722
- settings: join7(base, "settings.json"),
3723
- sessions: join7(base, "sessions")
3724
- };
3725
- }
3726
-
3727
4656
  // src/context/context-loader.ts
3728
4657
  import { existsSync as existsSync7, readFileSync as readFileSync8 } from "fs";
3729
- import { join as join9, dirname as dirname3, resolve as resolve2 } from "path";
4658
+ import { join as join10, dirname as dirname3, resolve as resolve4 } from "path";
3730
4659
 
3731
4660
  // src/context/task-context.ts
3732
4661
  import { existsSync as existsSync6, readdirSync as readdirSync4, readFileSync as readFileSync7, statSync, writeFileSync as writeFileSync3 } from "fs";
3733
- import { basename as basename4, dirname as dirname2, isAbsolute, join as join8, relative, resolve } from "path";
3734
- var TASKS_DIR = join8(".agents", "tasks");
4662
+ import { basename as basename4, dirname as dirname2, isAbsolute as isAbsolute2, join as join9, relative, resolve as resolve3 } from "path";
4663
+ var TASKS_DIR = join9(".agents", "tasks");
3735
4664
  var README_FILENAME = "README.md";
3736
4665
  var MARKDOWN_EXTENSION = ".md";
3737
4666
  var DEFAULT_MAX_TASKS = Number("3");
@@ -3831,16 +4760,16 @@ function appendProgressEntry(content, now, progressMessage) {
3831
4760
  return lines.join("\n");
3832
4761
  }
3833
4762
  function resolveGitDirectory(cwd) {
3834
- let current = resolve(cwd);
4763
+ let current = resolve3(cwd);
3835
4764
  let reachedRoot = false;
3836
4765
  while (!reachedRoot) {
3837
- const gitPath = join8(current, ".git");
4766
+ const gitPath = join9(current, ".git");
3838
4767
  if (existsSync6(gitPath)) {
3839
4768
  const stats = statSync(gitPath);
3840
4769
  if (stats.isDirectory()) return gitPath;
3841
4770
  const content = readFileSync7(gitPath, "utf8").trim();
3842
4771
  const gitdir = content.match(/^gitdir:\s*(.+)$/)?.[1];
3843
- if (gitdir) return isAbsolute(gitdir) ? gitdir : resolve(current, gitdir);
4772
+ if (gitdir) return isAbsolute2(gitdir) ? gitdir : resolve3(current, gitdir);
3844
4773
  }
3845
4774
  const parent = dirname2(current);
3846
4775
  reachedRoot = parent === current;
@@ -3851,18 +4780,18 @@ function resolveGitDirectory(cwd) {
3851
4780
  function readCurrentGitBranch(cwd) {
3852
4781
  const gitDir = resolveGitDirectory(cwd);
3853
4782
  if (!gitDir) return void 0;
3854
- const headPath = join8(gitDir, "HEAD");
4783
+ const headPath = join9(gitDir, "HEAD");
3855
4784
  if (!existsSync6(headPath)) return void 0;
3856
4785
  const head = readFileSync7(headPath, "utf8").trim();
3857
4786
  const branch = head.match(/^ref:\s+refs\/heads\/(.+)$/)?.[1];
3858
4787
  return branch?.trim();
3859
4788
  }
3860
4789
  function discoverTaskFiles(cwd) {
3861
- const tasksDir = join8(cwd, TASKS_DIR);
4790
+ const tasksDir = join9(cwd, TASKS_DIR);
3862
4791
  if (!existsSync6(tasksDir)) {
3863
4792
  return [];
3864
4793
  }
3865
- return readdirSync4(tasksDir, { withFileTypes: true }).filter((entry) => entry.isFile()).map((entry) => entry.name).filter((name) => name !== README_FILENAME && name.endsWith(MARKDOWN_EXTENSION)).sort((a, b) => a.localeCompare(b)).map((name) => join8(tasksDir, name));
4794
+ return readdirSync4(tasksDir, { withFileTypes: true }).filter((entry) => entry.isFile()).map((entry) => entry.name).filter((name) => name !== README_FILENAME && name.endsWith(MARKDOWN_EXTENSION)).sort((a, b) => a.localeCompare(b)).map((name) => join9(tasksDir, name));
3866
4795
  }
3867
4796
  function parseTaskFile(taskPath, cwd) {
3868
4797
  const content = readFileSync7(taskPath, "utf8");
@@ -3902,10 +4831,10 @@ var AGENTS_FILENAME = "AGENTS.md";
3902
4831
  var CLAUDE_FILENAME = "CLAUDE.md";
3903
4832
  function collectFilesWalkingUp(startDir, filename) {
3904
4833
  const found = [];
3905
- let current = resolve2(startDir);
4834
+ let current = resolve4(startDir);
3906
4835
  let atRoot = false;
3907
4836
  while (!atRoot) {
3908
- const candidate = join9(current, filename);
4837
+ const candidate = join10(current, filename);
3909
4838
  if (existsSync7(candidate)) {
3910
4839
  found.push(candidate);
3911
4840
  }
@@ -3956,7 +4885,7 @@ async function loadContext(cwd) {
3956
4885
 
3957
4886
  // src/context/project-detector.ts
3958
4887
  import { existsSync as existsSync8, readFileSync as readFileSync9 } from "fs";
3959
- import { join as join10 } from "path";
4888
+ import { join as join11 } from "path";
3960
4889
  function tryReadJson(filePath) {
3961
4890
  if (!existsSync8(filePath)) return void 0;
3962
4891
  try {
@@ -3966,26 +4895,26 @@ function tryReadJson(filePath) {
3966
4895
  }
3967
4896
  }
3968
4897
  function detectPackageManager(cwd) {
3969
- if (existsSync8(join10(cwd, "pnpm-workspace.yaml")) || existsSync8(join10(cwd, "pnpm-lock.yaml"))) {
4898
+ if (existsSync8(join11(cwd, "pnpm-workspace.yaml")) || existsSync8(join11(cwd, "pnpm-lock.yaml"))) {
3970
4899
  return "pnpm";
3971
4900
  }
3972
- if (existsSync8(join10(cwd, "yarn.lock"))) {
4901
+ if (existsSync8(join11(cwd, "yarn.lock"))) {
3973
4902
  return "yarn";
3974
4903
  }
3975
- if (existsSync8(join10(cwd, "bun.lockb"))) {
4904
+ if (existsSync8(join11(cwd, "bun.lockb"))) {
3976
4905
  return "bun";
3977
4906
  }
3978
- if (existsSync8(join10(cwd, "package-lock.json"))) {
4907
+ if (existsSync8(join11(cwd, "package-lock.json"))) {
3979
4908
  return "npm";
3980
4909
  }
3981
4910
  return void 0;
3982
4911
  }
3983
4912
  async function detectProject(cwd) {
3984
- const pkgJsonPath = join10(cwd, "package.json");
3985
- const tsconfigPath = join10(cwd, "tsconfig.json");
3986
- const pyprojectPath = join10(cwd, "pyproject.toml");
3987
- const cargoPath = join10(cwd, "Cargo.toml");
3988
- const goModPath = join10(cwd, "go.mod");
4913
+ const pkgJsonPath = join11(cwd, "package.json");
4914
+ const tsconfigPath = join11(cwd, "tsconfig.json");
4915
+ const pyprojectPath = join11(cwd, "pyproject.toml");
4916
+ const cargoPath = join11(cwd, "Cargo.toml");
4917
+ const goModPath = join11(cwd, "go.mod");
3989
4918
  if (existsSync8(pkgJsonPath)) {
3990
4919
  const pkgJson = tryReadJson(pkgJsonPath);
3991
4920
  const language = existsSync8(tsconfigPath) ? "typescript" : "javascript";
@@ -3997,7 +4926,7 @@ async function detectProject(cwd) {
3997
4926
  language
3998
4927
  };
3999
4928
  }
4000
- if (existsSync8(pyprojectPath) || existsSync8(join10(cwd, "setup.py"))) {
4929
+ if (existsSync8(pyprojectPath) || existsSync8(join11(cwd, "setup.py"))) {
4001
4930
  return {
4002
4931
  type: "python",
4003
4932
  language: "python"
@@ -4124,7 +5053,7 @@ var PluginSettingsStore = class {
4124
5053
 
4125
5054
  // src/plugins/bundle-plugin-loader.ts
4126
5055
  import { existsSync as existsSync11, readdirSync as readdirSync6, readFileSync as readFileSync11 } from "fs";
4127
- import { join as join11 } from "path";
5056
+ import { join as join12 } from "path";
4128
5057
 
4129
5058
  // src/plugins/bundle-plugin-utils.ts
4130
5059
  import { existsSync as existsSync10, readdirSync as readdirSync5 } from "fs";
@@ -4208,22 +5137,22 @@ var BundlePluginLoader = class {
4208
5137
  * For each marketplace/plugin pair, the latest version (lexicographically last) is loaded.
4209
5138
  */
4210
5139
  discoverAndLoad() {
4211
- const cacheDir = join11(this.pluginsDir, "cache");
5140
+ const cacheDir = join12(this.pluginsDir, "cache");
4212
5141
  if (!existsSync11(cacheDir)) {
4213
5142
  return [];
4214
5143
  }
4215
5144
  const results = [];
4216
5145
  const marketplaces = getSortedSubdirs(cacheDir);
4217
5146
  for (const marketplace of marketplaces) {
4218
- const marketplaceDir = join11(cacheDir, marketplace);
5147
+ const marketplaceDir = join12(cacheDir, marketplace);
4219
5148
  const plugins = getSortedSubdirs(marketplaceDir);
4220
5149
  for (const pluginName of plugins) {
4221
- const pluginDir = join11(marketplaceDir, pluginName);
5150
+ const pluginDir = join12(marketplaceDir, pluginName);
4222
5151
  const versions = getSortedSubdirs(pluginDir);
4223
5152
  if (versions.length === 0) continue;
4224
5153
  const latestVersion = versions[versions.length - 1];
4225
- const versionDir = join11(pluginDir, latestVersion);
4226
- const manifestPath = join11(versionDir, ".claude-plugin", "plugin.json");
5154
+ const versionDir = join12(pluginDir, latestVersion);
5155
+ const manifestPath = join12(versionDir, ".claude-plugin", "plugin.json");
4227
5156
  if (!existsSync11(manifestPath)) continue;
4228
5157
  const manifest = this.readManifest(manifestPath);
4229
5158
  if (!manifest) continue;
@@ -4273,13 +5202,13 @@ var BundlePluginLoader = class {
4273
5202
  }
4274
5203
  /** Load skills from the plugin's skills/ directory. */
4275
5204
  loadSkills(pluginDir, pluginName) {
4276
- const skillsDir = join11(pluginDir, "skills");
5205
+ const skillsDir = join12(pluginDir, "skills");
4277
5206
  if (!existsSync11(skillsDir)) return [];
4278
5207
  const entries = readdirSync6(skillsDir, { withFileTypes: true });
4279
5208
  const skills = [];
4280
5209
  for (const entry of entries) {
4281
5210
  if (!entry.isDirectory()) continue;
4282
- const skillFile = join11(skillsDir, entry.name, "SKILL.md");
5211
+ const skillFile = join12(skillsDir, entry.name, "SKILL.md");
4283
5212
  if (!existsSync11(skillFile)) continue;
4284
5213
  const raw = readFileSync11(skillFile, "utf-8");
4285
5214
  const { metadata, content } = parseSkillFrontmatter(raw);
@@ -4296,13 +5225,13 @@ var BundlePluginLoader = class {
4296
5225
  }
4297
5226
  /** Load commands from the plugin's commands/ directory (flat .md files). */
4298
5227
  loadCommands(pluginDir, pluginName) {
4299
- const commandsDir = join11(pluginDir, "commands");
5228
+ const commandsDir = join12(pluginDir, "commands");
4300
5229
  if (!existsSync11(commandsDir)) return [];
4301
5230
  const entries = readdirSync6(commandsDir, { withFileTypes: true });
4302
5231
  const commands = [];
4303
5232
  for (const entry of entries) {
4304
5233
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
4305
- const raw = readFileSync11(join11(commandsDir, entry.name), "utf-8");
5234
+ const raw = readFileSync11(join12(commandsDir, entry.name), "utf-8");
4306
5235
  const { metadata, content } = parseSkillFrontmatter(raw);
4307
5236
  const name = typeof metadata.name === "string" ? metadata.name : entry.name.replace(/\.md$/, "");
4308
5237
  const description = typeof metadata.description === "string" ? metadata.description : "";
@@ -4317,7 +5246,7 @@ var BundlePluginLoader = class {
4317
5246
  }
4318
5247
  /** Load hooks from hooks/hooks.json if present. */
4319
5248
  loadHooks(pluginDir) {
4320
- const hooksPath = join11(pluginDir, "hooks", "hooks.json");
5249
+ const hooksPath = join12(pluginDir, "hooks", "hooks.json");
4321
5250
  if (!existsSync11(hooksPath)) return {};
4322
5251
  try {
4323
5252
  const raw = readFileSync11(hooksPath, "utf-8");
@@ -4332,8 +5261,8 @@ var BundlePluginLoader = class {
4332
5261
  }
4333
5262
  /** Load MCP server configuration if present. Checks `.mcp.json` at plugin root first. */
4334
5263
  loadMcpConfig(pluginDir) {
4335
- const primaryPath = join11(pluginDir, ".mcp.json");
4336
- const fallbackPath = join11(pluginDir, ".claude-plugin", "mcp.json");
5264
+ const primaryPath = join12(pluginDir, ".mcp.json");
5265
+ const fallbackPath = join12(pluginDir, ".claude-plugin", "mcp.json");
4337
5266
  const mcpPath = existsSync11(primaryPath) ? primaryPath : fallbackPath;
4338
5267
  if (!existsSync11(mcpPath)) return void 0;
4339
5268
  try {
@@ -4345,7 +5274,7 @@ var BundlePluginLoader = class {
4345
5274
  }
4346
5275
  /** Load agent definitions from agents/ directory if present. */
4347
5276
  loadAgents(pluginDir) {
4348
- const agentsDir = join11(pluginDir, "agents");
5277
+ const agentsDir = join12(pluginDir, "agents");
4349
5278
  if (!existsSync11(agentsDir)) return [];
4350
5279
  try {
4351
5280
  const entries = readdirSync6(agentsDir, { withFileTypes: true });
@@ -4359,7 +5288,7 @@ var BundlePluginLoader = class {
4359
5288
  // src/plugins/bundle-plugin-installer.ts
4360
5289
  import { execSync as execSync2 } from "child_process";
4361
5290
  import { cpSync, existsSync as existsSync12, mkdirSync as mkdirSync5, readFileSync as readFileSync12, rmSync, writeFileSync as writeFileSync5 } from "fs";
4362
- import { join as join12, dirname as dirname5 } from "path";
5291
+ import { join as join13, dirname as dirname5 } from "path";
4363
5292
  var GIT_CLONE_TIMEOUT_MS = 6e4;
4364
5293
  var BundlePluginInstaller = class {
4365
5294
  pluginsDir;
@@ -4370,8 +5299,8 @@ var BundlePluginInstaller = class {
4370
5299
  exec;
4371
5300
  constructor(options) {
4372
5301
  this.pluginsDir = options.pluginsDir;
4373
- this.cacheDir = join12(this.pluginsDir, "cache");
4374
- this.registryPath = join12(this.pluginsDir, "installed_plugins.json");
5302
+ this.cacheDir = join13(this.pluginsDir, "cache");
5303
+ this.registryPath = join13(this.pluginsDir, "installed_plugins.json");
4375
5304
  this.settingsStore = options.settingsStore;
4376
5305
  this.marketplaceClient = options.marketplaceClient;
4377
5306
  this.exec = options.exec ?? this.defaultExec;
@@ -4391,7 +5320,7 @@ var BundlePluginInstaller = class {
4391
5320
  throw new Error(`Plugin "${pluginName}" not found in marketplace "${marketplaceName}"`);
4392
5321
  }
4393
5322
  const version = this.resolveVersion(entry, marketplaceName);
4394
- const targetDir = join12(this.cacheDir, marketplaceName, pluginName, version);
5323
+ const targetDir = join13(this.cacheDir, marketplaceName, pluginName, version);
4395
5324
  if (existsSync12(targetDir)) {
4396
5325
  throw new Error(
4397
5326
  `Plugin "${pluginName}" version "${version}" is already installed from "${marketplaceName}"`
@@ -4471,7 +5400,7 @@ var BundlePluginInstaller = class {
4471
5400
  try {
4472
5401
  if (typeof source === "string") {
4473
5402
  const marketplaceDir = this.marketplaceClient.getMarketplaceDir(marketplaceName);
4474
- const sourcePath = join12(marketplaceDir, source);
5403
+ const sourcePath = join13(marketplaceDir, source);
4475
5404
  if (!existsSync12(sourcePath)) {
4476
5405
  throw new Error(
4477
5406
  `Plugin source path "${source}" not found in marketplace "${marketplaceName}"`
@@ -4539,11 +5468,11 @@ var BundlePluginInstaller = class {
4539
5468
  // src/plugins/marketplace-client.ts
4540
5469
  import { execSync as execSync3 } from "child_process";
4541
5470
  import { cpSync as cpSync2, existsSync as existsSync14, mkdirSync as mkdirSync7, readFileSync as readFileSync14, renameSync, rmSync as rmSync3 } from "fs";
4542
- import { join as join14 } from "path";
5471
+ import { join as join15 } from "path";
4543
5472
 
4544
5473
  // src/plugins/marketplace-registry.ts
4545
5474
  import { existsSync as existsSync13, mkdirSync as mkdirSync6, readFileSync as readFileSync13, rmSync as rmSync2, writeFileSync as writeFileSync6 } from "fs";
4546
- import { join as join13, dirname as dirname6 } from "path";
5475
+ import { join as join14, dirname as dirname6 } from "path";
4547
5476
  function readRegistry(registryPath) {
4548
5477
  if (!existsSync13(registryPath)) {
4549
5478
  return {};
@@ -4567,7 +5496,7 @@ function writeRegistry(registryPath, registry) {
4567
5496
  writeFileSync6(registryPath, JSON.stringify(registry, null, 2), "utf-8");
4568
5497
  }
4569
5498
  function removeInstalledPluginsForMarketplace(pluginsDir, marketplaceName) {
4570
- const installedPath = join13(pluginsDir, "installed_plugins.json");
5499
+ const installedPath = join14(pluginsDir, "installed_plugins.json");
4571
5500
  if (!existsSync13(installedPath)) return;
4572
5501
  let registry;
4573
5502
  try {
@@ -4607,8 +5536,8 @@ var MarketplaceClient = class {
4607
5536
  constructor(options) {
4608
5537
  this.pluginsDir = options.pluginsDir;
4609
5538
  this.exec = options.exec ?? this.defaultExec;
4610
- this.marketplacesDir = join14(this.pluginsDir, "marketplaces");
4611
- this.registryPath = join14(this.pluginsDir, "known_marketplaces.json");
5539
+ this.marketplacesDir = join15(this.pluginsDir, "marketplaces");
5540
+ this.registryPath = join15(this.pluginsDir, "known_marketplaces.json");
4612
5541
  }
4613
5542
  /**
4614
5543
  * Add a marketplace by cloning its repository.
@@ -4621,7 +5550,7 @@ var MarketplaceClient = class {
4621
5550
  */
4622
5551
  addMarketplace(source) {
4623
5552
  const tempName = "temp-" + Date.now().toString(36);
4624
- const tempDir = join14(this.marketplacesDir, tempName);
5553
+ const tempDir = join15(this.marketplacesDir, tempName);
4625
5554
  mkdirSync7(this.marketplacesDir, { recursive: true });
4626
5555
  if (source.type === "local") {
4627
5556
  if (!existsSync14(source.path)) {
@@ -4638,7 +5567,7 @@ var MarketplaceClient = class {
4638
5567
  throw new Error(`Failed to clone marketplace: ${message}`);
4639
5568
  }
4640
5569
  }
4641
- const manifestPath = join14(tempDir, ".claude-plugin", "marketplace.json");
5570
+ const manifestPath = join15(tempDir, ".claude-plugin", "marketplace.json");
4642
5571
  if (!existsSync14(manifestPath)) {
4643
5572
  rmSync3(tempDir, { recursive: true, force: true });
4644
5573
  throw new Error(
@@ -4656,7 +5585,7 @@ var MarketplaceClient = class {
4656
5585
  rmSync3(tempDir, { recursive: true, force: true });
4657
5586
  throw new Error(`Marketplace "${name}" already exists`);
4658
5587
  }
4659
- const finalDir = join14(this.marketplacesDir, name);
5588
+ const finalDir = join15(this.marketplacesDir, name);
4660
5589
  renameSync(tempDir, finalDir);
4661
5590
  registry[name] = {
4662
5591
  source,
@@ -4733,7 +5662,7 @@ var MarketplaceClient = class {
4733
5662
  if (!entry) {
4734
5663
  throw new Error(`Marketplace "${marketplaceName}" not found`);
4735
5664
  }
4736
- const manifestPath = join14(entry.installLocation, ".claude-plugin", "marketplace.json");
5665
+ const manifestPath = join15(entry.installLocation, ".claude-plugin", "marketplace.json");
4737
5666
  if (!existsSync14(manifestPath)) {
4738
5667
  throw new Error(
4739
5668
  `Marketplace "${marketplaceName}" does not contain .claude-plugin/marketplace.json`
@@ -4815,9 +5744,9 @@ var MarketplaceClient = class {
4815
5744
  };
4816
5745
 
4817
5746
  // src/plugins/plugin-hooks-merger.ts
4818
- import { join as join15, dirname as dirname7 } from "path";
5747
+ import { join as join16, dirname as dirname7 } from "path";
4819
5748
  function buildPluginEnv(plugin) {
4820
- const dataDir = join15(dirname7(dirname7(plugin.pluginDir)), "data", plugin.manifest.name);
5749
+ const dataDir = join16(dirname7(dirname7(plugin.pluginDir)), "data", plugin.manifest.name);
4821
5750
  return {
4822
5751
  CLAUDE_PLUGIN_ROOT: plugin.pluginDir,
4823
5752
  CLAUDE_PLUGIN_PATH: plugin.pluginDir,
@@ -4879,8 +5808,9 @@ function mergeHooksIntoConfig(configHooks, pluginHooks) {
4879
5808
  }
4880
5809
 
4881
5810
  // src/interactive/interactive-session-init.ts
4882
- import { homedir as homedir4 } from "os";
4883
- import { join as join16 } from "path";
5811
+ import { homedir as homedir5 } from "os";
5812
+ import { join as join17 } from "path";
5813
+ import { applyWorkspaceManifest } from "@robota-sdk/agent-tools";
4884
5814
  async function createInteractiveSession(options) {
4885
5815
  const cwd = options.cwd;
4886
5816
  const [config, context, projectInfo] = await Promise.all([
@@ -4888,7 +5818,7 @@ async function createInteractiveSession(options) {
4888
5818
  options.bare ? Promise.resolve({ agentsMd: "", claudeMd: "" }) : loadContext(cwd),
4889
5819
  options.bare ? Promise.resolve({ type: "unknown", language: "unknown" }) : detectProject(cwd)
4890
5820
  ]);
4891
- const pluginsDir = join16(homedir4(), ".robota", "plugins");
5821
+ const pluginsDir = join17(homedir5(), ".robota", "plugins");
4892
5822
  const pluginLoader = new BundlePluginLoader(pluginsDir);
4893
5823
  let mergedConfig = config;
4894
5824
  if (!options.bare) {
@@ -4908,6 +5838,10 @@ async function createInteractiveSession(options) {
4908
5838
  }
4909
5839
  }
4910
5840
  const paths = projectPaths(cwd);
5841
+ const sandboxRestored = await restoreInteractiveSandboxSnapshot(options);
5842
+ if (!sandboxRestored) {
5843
+ await applyInteractiveWorkspaceManifest(options, cwd);
5844
+ }
4911
5845
  const sessionId = options.resumeSessionId && !options.forkSession ? options.resumeSessionId : void 0;
4912
5846
  return createSession({
4913
5847
  config: mergedConfig,
@@ -4941,20 +5875,37 @@ async function createInteractiveSession(options) {
4941
5875
  modelCommandExecutor: options.modelCommandExecutor,
4942
5876
  isModelCommandInvocable: options.isModelCommandInvocable,
4943
5877
  editCheckpointRecorder: options.editCheckpointRecorder,
4944
- reversibleExecution: options.reversibleExecution
5878
+ reversibleExecution: options.reversibleExecution,
5879
+ sandboxClient: options.sandboxClient
5880
+ });
5881
+ }
5882
+ async function applyInteractiveWorkspaceManifest(options, cwd) {
5883
+ if (!options.workspaceManifest) return;
5884
+ if (!options.sandboxClient) {
5885
+ throw new Error("workspaceManifest requires sandboxClient.");
5886
+ }
5887
+ await applyWorkspaceManifest(options.sandboxClient, options.workspaceManifest, {
5888
+ hostRoot: cwd,
5889
+ ...options.sandboxWorkspaceRoot ? { targetRoot: options.sandboxWorkspaceRoot } : {}
4945
5890
  });
4946
5891
  }
5892
+ async function restoreInteractiveSandboxSnapshot(options) {
5893
+ if (!options.sandboxSnapshotId) return false;
5894
+ if (!options.sandboxClient?.restore) {
5895
+ throw new Error("sandboxSnapshotId requires sandboxClient with restore().");
5896
+ }
5897
+ await options.sandboxClient.restore(options.sandboxSnapshotId);
5898
+ return true;
5899
+ }
4947
5900
  function injectSavedMessage(session, msg) {
4948
- if (!msg || typeof msg !== "object") return;
4949
- const m = msg;
4950
- if (!m.role || !m.content) return;
4951
- const role = m.role;
4952
- if (role === "tool") {
4953
- const toolCallId = m.toolCallId ?? "";
4954
- const name = m.name ?? void 0;
4955
- session.injectMessage("tool", m.content, { toolCallId, name });
4956
- } else if (role === "user" || role === "assistant" || role === "system") {
4957
- session.injectMessage(role, m.content);
5901
+ if (typeof msg.content !== "string") return;
5902
+ if (msg.role === "tool") {
5903
+ session.injectMessage("tool", msg.content, {
5904
+ toolCallId: msg.toolCallId,
5905
+ ...msg.name !== void 0 ? { name: msg.name } : {}
5906
+ });
5907
+ } else {
5908
+ session.injectMessage(msg.role, msg.content);
4958
5909
  }
4959
5910
  }
4960
5911
  function loadSessionRecord(sessionStore, resumeSessionId, forkSession, existingSession) {
@@ -4968,8 +5919,11 @@ function loadSessionRecord(sessionStore, resumeSessionId, forkSession, existingS
4968
5919
  backgroundTaskEvents: [],
4969
5920
  backgroundJobGroups: [],
4970
5921
  backgroundJobGroupEvents: [],
5922
+ skillActivationEvents: [],
4971
5923
  memoryEvents: [],
4972
- usedMemoryReferences: []
5924
+ usedMemoryReferences: [],
5925
+ contextReferences: [],
5926
+ sandboxSnapshotId: void 0
4973
5927
  };
4974
5928
  }
4975
5929
  const history = record.history ?? [];
@@ -4977,8 +5931,11 @@ function loadSessionRecord(sessionStore, resumeSessionId, forkSession, existingS
4977
5931
  const restoredBackgroundTaskEvents = record.backgroundTaskEvents ?? [];
4978
5932
  const backgroundJobGroups = record.backgroundJobGroups ?? [];
4979
5933
  const backgroundJobGroupEvents = record.backgroundJobGroupEvents ?? [];
5934
+ const skillActivationEvents = record.skillActivationEvents ?? [];
4980
5935
  const memoryEvents = record.memoryEvents ?? [];
4981
5936
  const usedMemoryReferences = record.usedMemoryReferences ?? [];
5937
+ const contextReferences = record.contextReferences ?? [];
5938
+ const sandboxSnapshotId = record.sandboxSnapshotId;
4982
5939
  const { backgroundTasks, backgroundTaskEvents } = reconcileRestoredBackgroundTasks(
4983
5940
  restoredBackgroundTasks,
4984
5941
  restoredBackgroundTaskEvents
@@ -5002,8 +5959,11 @@ function loadSessionRecord(sessionStore, resumeSessionId, forkSession, existingS
5002
5959
  backgroundTaskEvents,
5003
5960
  backgroundJobGroups,
5004
5961
  backgroundJobGroupEvents,
5962
+ skillActivationEvents,
5005
5963
  memoryEvents,
5006
- usedMemoryReferences
5964
+ usedMemoryReferences,
5965
+ contextReferences,
5966
+ sandboxSnapshotId
5007
5967
  };
5008
5968
  }
5009
5969
  function reconcileRestoredBackgroundTasks(tasks, events) {
@@ -5036,14 +5996,62 @@ function isRestoredTerminalStatus(status) {
5036
5996
  return status === "completed" || status === "failed" || status === "cancelled";
5037
5997
  }
5038
5998
 
5999
+ // src/interactive/interactive-session-context-references.ts
6000
+ async function addInteractiveContextReference(references, path, cwd) {
6001
+ const result = await resolvePromptFileReferencePaths([path], {
6002
+ cwd,
6003
+ reason: "manual"
6004
+ });
6005
+ if (hasBlockingPromptFileReferenceDiagnostics(result.diagnostics)) {
6006
+ return {
6007
+ references: [...references],
6008
+ result: {
6009
+ evicted: [],
6010
+ diagnostics: [formatPromptFileReferenceDiagnostics(result.diagnostics)]
6011
+ }
6012
+ };
6013
+ }
6014
+ const reference = result.references[0];
6015
+ if (!reference) {
6016
+ return {
6017
+ references: [...references],
6018
+ result: { evicted: [], diagnostics: ["No context reference was resolved."] }
6019
+ };
6020
+ }
6021
+ const item = createContextReferenceItem(
6022
+ toPromptFileReferenceRecords([reference])[0],
6023
+ "manual",
6024
+ "active"
6025
+ );
6026
+ const upserted = upsertContextReference(references, item);
6027
+ return {
6028
+ references: upserted.references,
6029
+ result: {
6030
+ reference: item,
6031
+ evicted: upserted.evicted,
6032
+ diagnostics: []
6033
+ }
6034
+ };
6035
+ }
6036
+ function recordInteractiveContextReferences(references, records, options) {
6037
+ if (records.length === 0) return [...references];
6038
+ const now = (/* @__PURE__ */ new Date()).toISOString();
6039
+ let next = [...references];
6040
+ for (const record of records) {
6041
+ const item = createContextReferenceItem(record, options.loadType, options.status, now);
6042
+ next = upsertContextReference(next, item).references;
6043
+ }
6044
+ return next;
6045
+ }
6046
+
5039
6047
  // src/checkpoints/edit-checkpoint-store.ts
5040
6048
  import { access, copyFile, mkdir, rename, rm, writeFile } from "fs/promises";
5041
6049
  import { constants, readdirSync as readdirSync7, readFileSync as readFileSync15 } from "fs";
5042
- import { dirname as dirname8, join as join18, relative as relative3, resolve as resolve3 } from "path";
6050
+ import { dirname as dirname8, join as join19, relative as relative3, resolve as resolve5 } from "path";
5043
6051
 
5044
6052
  // src/checkpoints/edit-checkpoint-inspection.ts
5045
6053
  import { statSync as statSync2 } from "fs";
5046
- import { join as join17, relative as relative2 } from "path";
6054
+ import { join as join18, relative as relative2 } from "path";
5047
6055
  function buildEditCheckpointInspection(input) {
5048
6056
  const later = input.manifests.filter((manifest) => manifest.sequence > input.target.sequence);
5049
6057
  const rollbackRange = input.manifests.filter(
@@ -5052,7 +6060,7 @@ function buildEditCheckpointInspection(input) {
5052
6060
  return {
5053
6061
  target: toSummary(input.target),
5054
6062
  capturedFiles: input.target.files.map((file) => {
5055
- const snapshotPath = file.snapshotFile ? join17(input.checkpointDir(input.sessionId, input.target.id), file.snapshotFile) : void 0;
6063
+ const snapshotPath = file.snapshotFile ? join18(input.checkpointDir(input.sessionId, input.target.id), file.snapshotFile) : void 0;
5056
6064
  const snapshotStats = snapshotPath ? statSafe(snapshotPath) : void 0;
5057
6065
  return {
5058
6066
  originalPath: file.originalPath,
@@ -5102,7 +6110,7 @@ var EditCheckpointStore = class {
5102
6110
  now;
5103
6111
  activeTurn = null;
5104
6112
  constructor(options) {
5105
- this.cwd = resolve3(options.cwd);
6113
+ this.cwd = resolve5(options.cwd);
5106
6114
  this.rootDir = projectPaths(this.cwd).checkpoints;
5107
6115
  this.now = options.now ?? (() => /* @__PURE__ */ new Date());
5108
6116
  }
@@ -5112,8 +6120,8 @@ var EditCheckpointStore = class {
5112
6120
  }
5113
6121
  const nextSequence = this.nextSequence(input.sessionId);
5114
6122
  const id = `turn-${String(nextSequence).padStart(ID_PAD, "0")}`;
5115
- const dir = join18(this.sessionDir(input.sessionId), id);
5116
- await mkdir(join18(dir, SNAPSHOT_DIR), { recursive: true });
6123
+ const dir = join19(this.sessionDir(input.sessionId), id);
6124
+ await mkdir(join19(dir, SNAPSHOT_DIR), { recursive: true });
5117
6125
  const manifest = {
5118
6126
  version: 1,
5119
6127
  id,
@@ -5133,7 +6141,7 @@ var EditCheckpointStore = class {
5133
6141
  }
5134
6142
  async captureFile(filePath) {
5135
6143
  if (!this.activeTurn) return;
5136
- const originalPath = resolve3(this.cwd, filePath);
6144
+ const originalPath = resolve5(this.cwd, filePath);
5137
6145
  if (this.activeTurn.capturedPaths.has(originalPath)) return;
5138
6146
  if (isInside(this.rootDir, originalPath)) return;
5139
6147
  const record = await this.createFileRecord(originalPath, this.activeTurn);
@@ -5221,11 +6229,11 @@ var EditCheckpointStore = class {
5221
6229
  existed: false
5222
6230
  };
5223
6231
  }
5224
- const snapshotFile = join18(
6232
+ const snapshotFile = join19(
5225
6233
  SNAPSHOT_DIR,
5226
6234
  `${String(active.manifest.files.length + 1).padStart(SNAPSHOT_PAD, "0")}.content`
5227
6235
  );
5228
- await copyFile(originalPath, join18(active.dir, snapshotFile));
6236
+ await copyFile(originalPath, join19(active.dir, snapshotFile));
5229
6237
  return {
5230
6238
  originalPath,
5231
6239
  existed: true,
@@ -5242,13 +6250,13 @@ var EditCheckpointStore = class {
5242
6250
  }
5243
6251
  await mkdir(dirname8(record.originalPath), { recursive: true });
5244
6252
  await copyFile(
5245
- join18(this.checkpointDir(sessionId, checkpointId), record.snapshotFile),
6253
+ join19(this.checkpointDir(sessionId, checkpointId), record.snapshotFile),
5246
6254
  record.originalPath
5247
6255
  );
5248
6256
  }
5249
6257
  loadManifests(sessionId) {
5250
6258
  const dir = this.sessionDir(sessionId);
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);
6259
+ return readDirSyncSafe(dir).map((entry) => join19(dir, entry, MANIFEST_FILE)).map((manifestPath) => readJsonManifest(manifestPath)).filter((manifest) => manifest !== void 0).sort((a, b) => a.sequence - b.sequence);
5252
6260
  }
5253
6261
  nextSequence(sessionId) {
5254
6262
  const last = this.list(sessionId).at(-1);
@@ -5256,16 +6264,16 @@ var EditCheckpointStore = class {
5256
6264
  }
5257
6265
  async writeManifest(dir, manifest) {
5258
6266
  await mkdir(dir, { recursive: true });
5259
- const path = join18(dir, MANIFEST_FILE);
6267
+ const path = join19(dir, MANIFEST_FILE);
5260
6268
  const tmp = `${path}.tmp`;
5261
6269
  await writeFile(tmp, JSON.stringify(manifest, null, 2), "utf8");
5262
6270
  await rename(tmp, path);
5263
6271
  }
5264
6272
  sessionDir(sessionId) {
5265
- return join18(this.rootDir, safePathSegment(sessionId));
6273
+ return join19(this.rootDir, safePathSegment(sessionId));
5266
6274
  }
5267
6275
  checkpointDir(sessionId, checkpointId) {
5268
- return join18(this.sessionDir(sessionId), safePathSegment(checkpointId));
6276
+ return join19(this.sessionDir(sessionId), safePathSegment(checkpointId));
5269
6277
  }
5270
6278
  };
5271
6279
  function toSummary2(manifest) {
@@ -5310,6 +6318,21 @@ function readJsonManifest(path) {
5310
6318
  }
5311
6319
 
5312
6320
  // src/interactive/interactive-session.ts
6321
+ function normalizeSkillName(name) {
6322
+ return name.trim().replace(/^\/+/, "").split(/\s+/)[0] ?? "";
6323
+ }
6324
+ function normalizeCommandName(name) {
6325
+ return name.trim().replace(/^\/+/, "").split(/\s+/)[0] ?? "";
6326
+ }
6327
+ function formatSkillCommandArgs(skillName, args) {
6328
+ const trimmedArgs = args.trim();
6329
+ return trimmedArgs.length > 0 ? `${skillName} ${trimmedArgs}` : skillName;
6330
+ }
6331
+ function getQualifiedSkillName(rawInput) {
6332
+ if (!rawInput?.startsWith("/")) return void 0;
6333
+ const firstToken = rawInput.slice(1).trim().split(/\s+/)[0];
6334
+ return firstToken && firstToken.length > 0 ? firstToken : void 0;
6335
+ }
5313
6336
  var InteractiveSession = class {
5314
6337
  session = null;
5315
6338
  commandExecutor;
@@ -5334,6 +6357,7 @@ var InteractiveSession = class {
5334
6357
  backgroundJobGroupEvents = [];
5335
6358
  memoryEvents = [];
5336
6359
  usedMemoryReferences = [];
6360
+ contextReferences = [];
5337
6361
  editCheckpointStore = null;
5338
6362
  resumeSessionId;
5339
6363
  forkSession;
@@ -5342,15 +6366,16 @@ var InteractiveSession = class {
5342
6366
  backgroundJobOrchestrator = null;
5343
6367
  commandModules;
5344
6368
  commandHostAdapters;
6369
+ skillCommandSource;
6370
+ skillActivationEvents = [];
5345
6371
  autoCompactThresholdSource = "default";
5346
6372
  shuttingDown = false;
5347
6373
  shutdownPromise = null;
6374
+ sandboxClient;
6375
+ sandboxSnapshotId;
6376
+ commandInvocationSource = "user";
5348
6377
  constructor(options) {
5349
- const sdkBuiltinModule = createBuiltinCommandModule();
5350
- this.commandModules = [
5351
- sdkBuiltinModule,
5352
- ..."commandModules" in options ? options.commandModules ?? [] : []
5353
- ];
6378
+ this.commandModules = [..."commandModules" in options ? options.commandModules ?? [] : []];
5354
6379
  this.commandExecutor = new SystemCommandExecutor(
5355
6380
  this.commandModules.flatMap((module) => module.systemCommands ?? [])
5356
6381
  );
@@ -5363,34 +6388,48 @@ var InteractiveSession = class {
5363
6388
  this.resumeSessionId = options.resumeSessionId;
5364
6389
  this.forkSession = options.forkSession ?? false;
5365
6390
  this.commandHostAdapters = "commandHostAdapters" in options ? options.commandHostAdapters : void 0;
5366
- if ("session" in options && options.session) {
5367
- this.session = options.session;
5368
- this.autoCompactThresholdSource = "session";
5369
- this.initialized = true;
5370
- } else {
5371
- const stdOpts = options;
5372
- this.initPromise = this.initializeAsync(stdOpts);
5373
- }
5374
- if (options.resumeSessionId && this.sessionStore) {
5375
- const restored = loadSessionRecord(
5376
- this.sessionStore,
5377
- options.resumeSessionId,
5378
- this.forkSession,
5379
- this.session
5380
- );
5381
- if (restored.history.length > 0) this.history = restored.history;
5382
- if (restored.sessionName) this.sessionName = restored.sessionName;
5383
- this.backgroundTasks = restored.backgroundTasks;
5384
- this.backgroundTaskEvents = restored.backgroundTaskEvents;
5385
- this.backgroundJobGroups = restored.backgroundJobGroups;
5386
- this.backgroundJobGroupEvents = restored.backgroundJobGroupEvents;
5387
- this.memoryEvents = restored.memoryEvents;
5388
- this.usedMemoryReferences = restored.usedMemoryReferences;
5389
- this.pendingRestoreMessages = restored.pendingRestoreMessages;
5390
- }
6391
+ this.sandboxClient = "sandboxClient" in options ? options.sandboxClient : void 0;
6392
+ this.sandboxSnapshotId = "sandboxSnapshotId" in options ? options.sandboxSnapshotId : void 0;
6393
+ this.skillCommandSource = new SkillCommandSource(this.cwd || process.cwd());
6394
+ const hasInjectedSession = this.configureInjectedSession(options);
6395
+ this.restoreSessionRecordIfNeeded(options);
6396
+ this.startAsyncInitializationIfNeeded(options, hasInjectedSession);
5391
6397
  if (this.initialized) this.subscribeBackgroundTaskEvents();
5392
6398
  if (this.initialized) this.persistCurrentSession();
5393
6399
  }
6400
+ configureInjectedSession(options) {
6401
+ if (!("session" in options && options.session)) return false;
6402
+ this.session = options.session;
6403
+ this.autoCompactThresholdSource = "session";
6404
+ this.initialized = true;
6405
+ return true;
6406
+ }
6407
+ restoreSessionRecordIfNeeded(options) {
6408
+ if (!options.resumeSessionId || !this.sessionStore) return;
6409
+ const restored = loadSessionRecord(
6410
+ this.sessionStore,
6411
+ options.resumeSessionId,
6412
+ this.forkSession,
6413
+ this.session
6414
+ );
6415
+ if (restored.history.length > 0) this.history = restored.history;
6416
+ if (restored.sessionName) this.sessionName = restored.sessionName;
6417
+ this.backgroundTasks = restored.backgroundTasks;
6418
+ this.backgroundTaskEvents = restored.backgroundTaskEvents;
6419
+ this.backgroundJobGroups = restored.backgroundJobGroups;
6420
+ this.backgroundJobGroupEvents = restored.backgroundJobGroupEvents;
6421
+ this.skillActivationEvents = restored.skillActivationEvents;
6422
+ this.memoryEvents = restored.memoryEvents;
6423
+ this.usedMemoryReferences = restored.usedMemoryReferences;
6424
+ this.contextReferences = restored.contextReferences;
6425
+ this.pendingRestoreMessages = restored.pendingRestoreMessages;
6426
+ this.sandboxSnapshotId = this.forkSession ? void 0 : restored.sandboxSnapshotId;
6427
+ }
6428
+ startAsyncInitializationIfNeeded(options, hasInjectedSession) {
6429
+ if (hasInjectedSession) return;
6430
+ const stdOpts = options;
6431
+ this.initPromise = this.initializeAsync(stdOpts);
6432
+ }
5394
6433
  async initializeAsync(options) {
5395
6434
  const config = options.config ?? await loadConfig(options.cwd);
5396
6435
  this.autoCompactThresholdSource = config.autoCompactThreshold === void 0 ? "default" : "settings";
@@ -5416,6 +6455,10 @@ var InteractiveSession = class {
5416
6455
  ...options.commandModules ? { commandModules: options.commandModules } : {},
5417
6456
  editCheckpointRecorder: this.editCheckpointStore,
5418
6457
  ...options.reversibleExecution ? { reversibleExecution: options.reversibleExecution } : {},
6458
+ ...options.sandboxClient ? { sandboxClient: options.sandboxClient } : {},
6459
+ ...options.workspaceManifest ? { workspaceManifest: options.workspaceManifest } : {},
6460
+ ...options.sandboxWorkspaceRoot ? { sandboxWorkspaceRoot: options.sandboxWorkspaceRoot } : {},
6461
+ ...this.sandboxSnapshotId ? { sandboxSnapshotId: this.sandboxSnapshotId } : {},
5419
6462
  commandDescriptors: this.commandExecutor.listModelInvocableCommands(),
5420
6463
  ...this.commandExecutor.listModelInvocableCommands().length > 0 ? {
5421
6464
  modelCommandExecutor: (command, args) => this.executeModelCommand(command, args),
@@ -5462,36 +6505,102 @@ var InteractiveSession = class {
5462
6505
  }
5463
6506
  async executeCommand(name, args) {
5464
6507
  await this.ensureInitialized();
5465
- const command = this.commandExecutor.getCommand(name);
5466
- if (!command) return null;
6508
+ const normalizedName = normalizeCommandName(name);
6509
+ const command = this.commandExecutor.getCommand(normalizedName);
6510
+ const commandArgs = args.trim();
6511
+ if (!command) {
6512
+ const skill = this.findSkillCommand(normalizedName);
6513
+ const skillsCommand = this.commandExecutor.getCommand("skills");
6514
+ if (!skill || !skillsCommand) return null;
6515
+ return this.executeCommandWithInvocationSource(
6516
+ "user",
6517
+ skillsCommand,
6518
+ formatSkillCommandArgs(skill.name, commandArgs)
6519
+ );
6520
+ }
6521
+ return this.executeCommandWithInvocationSource("user", command, commandArgs);
6522
+ }
6523
+ async executeCommandWithInvocationSource(source, command, args) {
5467
6524
  if (this.executing) {
5468
6525
  return {
5469
6526
  success: false,
5470
6527
  message: "Another prompt or command is already running. Wait for it to finish."
5471
6528
  };
5472
6529
  }
5473
- if (command.lifecycle === "blocking") {
5474
- return this.executeForegroundCommand(command, args);
6530
+ const previousSource = this.commandInvocationSource;
6531
+ this.commandInvocationSource = source;
6532
+ try {
6533
+ if (command.lifecycle === "blocking") {
6534
+ return this.executeForegroundCommand(command, args);
6535
+ }
6536
+ return await this.commandExecutor.executeCommand(command, this, args);
6537
+ } finally {
6538
+ this.commandInvocationSource = previousSource;
5475
6539
  }
5476
- return this.commandExecutor.executeCommand(command, this, args);
5477
6540
  }
5478
6541
  async executeModelCommand(name, args) {
5479
6542
  await this.ensureInitialized();
5480
- return this.commandExecutor.executeModelInvocable(name, this, args);
6543
+ const previousSource = this.commandInvocationSource;
6544
+ this.commandInvocationSource = "model";
6545
+ try {
6546
+ return await this.commandExecutor.executeModelInvocable(name, this, args);
6547
+ } finally {
6548
+ this.commandInvocationSource = previousSource;
6549
+ }
5481
6550
  }
5482
- async executeSkillCommand(skill, args, displayInput, rawInput) {
6551
+ getCommandInvocationSource() {
6552
+ return this.commandInvocationSource;
6553
+ }
6554
+ async executeSkillCommandByName(name, args, request) {
5483
6555
  await this.ensureInitialized();
5484
- if (skill.context === "fork") {
5485
- return this.executeForkSkillCommand(skill, args, displayInput);
6556
+ const skill = this.findSkillCommand(name);
6557
+ if (!skill) return null;
6558
+ if (request.invocationSource === "model") {
6559
+ if (skill.disableModelInvocation === true) {
6560
+ return {
6561
+ success: false,
6562
+ message: `Skill is not model-invocable: ${skill.name}`
6563
+ };
6564
+ }
6565
+ const result = await this.executeSkillWithActivation(skill, args, "model-tool");
6566
+ return {
6567
+ success: true,
6568
+ message: `Skill activated: ${skill.name}`,
6569
+ data: {
6570
+ skill: skill.name,
6571
+ mode: result.mode,
6572
+ ...result.prompt !== void 0 ? { prompt: result.prompt } : {},
6573
+ ...result.result !== void 0 ? { result: result.result } : {}
6574
+ }
6575
+ };
5486
6576
  }
5487
- const result = await executeSkill(
6577
+ await this.executeUserResolvedSkillCommand(
5488
6578
  skill,
5489
6579
  args,
5490
- {
5491
- runInFork: (content, options) => this.runSkillInFork(content, options)
5492
- },
5493
- { sessionId: this.getSessionOrThrow().getSessionId() }
6580
+ request.displayInput,
6581
+ request.rawInput,
6582
+ "user-slash"
5494
6583
  );
6584
+ return {
6585
+ success: true,
6586
+ message: "",
6587
+ data: {
6588
+ skill: skill.name,
6589
+ sessionExecution: true
6590
+ },
6591
+ effects: [{ type: "session-execution-started" }]
6592
+ };
6593
+ }
6594
+ async executeUserResolvedSkillCommand(skill, args, displayInput, rawInput, invocation) {
6595
+ await this.ensureInitialized();
6596
+ if (skill.userInvocable === false) {
6597
+ throw new Error(`Skill is not user-invocable: ${skill.name}`);
6598
+ }
6599
+ const qualifiedName = getQualifiedSkillName(rawInput);
6600
+ if (skill.context === "fork") {
6601
+ return this.executeForkSkillCommand(skill, args, displayInput, qualifiedName, invocation);
6602
+ }
6603
+ const result = await this.executeSkillWithActivation(skill, args, invocation, qualifiedName);
5495
6604
  if (result.mode === "inject") {
5496
6605
  if (result.prompt) {
5497
6606
  await this.submit(result.prompt, displayInput, rawInput);
@@ -5507,12 +6616,31 @@ var InteractiveSession = class {
5507
6616
  description: cmd.description
5508
6617
  }));
5509
6618
  }
6619
+ listSkills() {
6620
+ return this.skillCommandSource.getCommands().map((skill) => ({
6621
+ name: skill.name,
6622
+ description: skill.description,
6623
+ source: skill.source,
6624
+ modelInvocable: skill.disableModelInvocation !== true,
6625
+ userInvocable: skill.userInvocable !== false,
6626
+ ...skill.argumentHint !== void 0 ? { argumentHint: skill.argumentHint } : {},
6627
+ ...skill.context !== void 0 ? { context: skill.context } : {},
6628
+ ...skill.agent !== void 0 ? { agent: skill.agent } : {}
6629
+ }));
6630
+ }
5510
6631
  listModelInvocableCommands() {
5511
6632
  return this.commandExecutor.listModelInvocableCommands().map((cmd) => ({
5512
6633
  name: cmd.name,
5513
6634
  description: cmd.description
5514
6635
  }));
5515
6636
  }
6637
+ getSkillActivationEvents() {
6638
+ return [...this.skillActivationEvents];
6639
+ }
6640
+ findSkillCommand(name) {
6641
+ const normalizedName = normalizeSkillName(name);
6642
+ return this.skillCommandSource.getCommands().find((skill) => skill.name.toLowerCase() === normalizedName.toLowerCase());
6643
+ }
5516
6644
  abort() {
5517
6645
  this.clearPendingQueue();
5518
6646
  this.session?.abort();
@@ -5532,6 +6660,7 @@ var InteractiveSession = class {
5532
6660
  this.backgroundJobUnsubscribe = null;
5533
6661
  this.backgroundJobOrchestrator?.dispose();
5534
6662
  this.backgroundJobOrchestrator = null;
6663
+ await this.captureSandboxSnapshot();
5535
6664
  this.persistCurrentSession();
5536
6665
  await session?.shutdown({ reason: options.reason ?? "other" });
5537
6666
  })();
@@ -5644,6 +6773,31 @@ var InteractiveSession = class {
5644
6773
  this.memoryEvents.push(event);
5645
6774
  this.persistCurrentSession();
5646
6775
  }
6776
+ listContextReferences() {
6777
+ return [...this.contextReferences];
6778
+ }
6779
+ async addContextReference(path) {
6780
+ const { references, result } = await addInteractiveContextReference(
6781
+ this.contextReferences,
6782
+ path,
6783
+ this.getCwd()
6784
+ );
6785
+ this.contextReferences = references;
6786
+ this.persistCurrentSession();
6787
+ return result;
6788
+ }
6789
+ removeContextReference(path) {
6790
+ const result = removeContextReference(this.contextReferences, path);
6791
+ this.contextReferences = result.references;
6792
+ this.persistCurrentSession();
6793
+ return result.result;
6794
+ }
6795
+ clearContextReferences() {
6796
+ const result = clearContextReferences(this.contextReferences);
6797
+ this.contextReferences = [];
6798
+ this.persistCurrentSession();
6799
+ return result;
6800
+ }
5647
6801
  listBackgroundTasks(filter) {
5648
6802
  return this.getBackgroundTaskManagerOrThrow().list(filter);
5649
6803
  }
@@ -5745,18 +6899,63 @@ var InteractiveSession = class {
5745
6899
  attachTransport(transport) {
5746
6900
  transport.attach(this);
5747
6901
  }
5748
- async executeForkSkillCommand(skill, args, displayInput) {
5749
- if (this.executing) {
5750
- throw new Error("Cannot execute fork skill while another prompt is running.");
5751
- }
5752
- this.startForkSkillExecution(displayInput ?? `/${skill.name}`);
6902
+ async executeSkillWithActivation(skill, args, invocation, qualifiedName) {
6903
+ this.recordSkillActivation(skill, invocation, "started", qualifiedName);
5753
6904
  try {
5754
6905
  const result = await executeSkill(
5755
6906
  skill,
5756
6907
  args,
5757
- { runInFork: (content, options) => this.runSkillInFork(content, options) },
6908
+ {
6909
+ runInFork: (content, options) => this.runSkillInFork(content, options)
6910
+ },
5758
6911
  { sessionId: this.getSessionOrThrow().getSessionId() }
5759
6912
  );
6913
+ this.recordSkillActivation(skill, invocation, "completed", qualifiedName, {
6914
+ appendHistory: false
6915
+ });
6916
+ return result;
6917
+ } catch (err) {
6918
+ const error = err instanceof Error ? err : new Error(String(err));
6919
+ this.recordSkillActivation(skill, invocation, "failed", qualifiedName, {
6920
+ error: error.message
6921
+ });
6922
+ throw error;
6923
+ }
6924
+ }
6925
+ recordSkillActivation(skill, invocation, status, qualifiedName, options = {}) {
6926
+ const event = createSkillActivationEvent({
6927
+ skill,
6928
+ invocation,
6929
+ status,
6930
+ ...qualifiedName !== void 0 ? { qualifiedName } : {},
6931
+ ...options.error !== void 0 ? { error: options.error } : {}
6932
+ });
6933
+ this.recordSkillActivationEvent(event, options.appendHistory ?? status !== "completed");
6934
+ }
6935
+ recordSkillActivationEvent(event, appendHistory) {
6936
+ this.skillActivationEvents.push(event);
6937
+ if (appendHistory) {
6938
+ this.history.push({
6939
+ id: randomUUID4(),
6940
+ timestamp: new Date(event.timestamp),
6941
+ category: "event",
6942
+ type: "skill-activation",
6943
+ data: {
6944
+ ...event,
6945
+ message: formatSkillActivationMessage(event)
6946
+ }
6947
+ });
6948
+ }
6949
+ this.emit("skill_activation", event);
6950
+ this.persistCurrentSession();
6951
+ }
6952
+ async executeForkSkillCommand(skill, args, displayInput, qualifiedName, invocation = "user-slash") {
6953
+ if (this.executing) {
6954
+ throw new Error("Cannot execute fork skill while another prompt is running.");
6955
+ }
6956
+ this.startForkSkillExecution(displayInput ?? `/${skill.name}`);
6957
+ try {
6958
+ const result = await this.executeSkillWithActivation(skill, args, invocation, qualifiedName);
5760
6959
  await this.applyForkSkillResult(result.result ?? "(empty response)");
5761
6960
  return result;
5762
6961
  } catch (err) {
@@ -5870,9 +7069,30 @@ var InteractiveSession = class {
5870
7069
  {
5871
7070
  events: this.memoryEvents,
5872
7071
  usedReferences: this.usedMemoryReferences
7072
+ },
7073
+ {
7074
+ events: this.skillActivationEvents
7075
+ },
7076
+ {
7077
+ references: this.contextReferences
7078
+ },
7079
+ {
7080
+ snapshotId: this.sandboxSnapshotId
5873
7081
  }
5874
7082
  );
5875
7083
  }
7084
+ async captureSandboxSnapshot() {
7085
+ if (!this.sandboxClient?.snapshot) return;
7086
+ try {
7087
+ this.sandboxSnapshotId = await this.sandboxClient.snapshot();
7088
+ } catch (error) {
7089
+ const err = error instanceof Error ? error : new Error(String(error));
7090
+ this.history.push(
7091
+ messageToHistoryEntry(createSystemMessage(`Sandbox snapshot error: ${err.message}`))
7092
+ );
7093
+ this.emit("error", err);
7094
+ }
7095
+ }
5876
7096
  startForkSkillExecution(displayInput) {
5877
7097
  this.executing = true;
5878
7098
  this.clearStreaming();
@@ -5888,7 +7108,7 @@ var InteractiveSession = class {
5888
7108
  const queuedDisplay = this.pendingDisplayInput;
5889
7109
  const queuedRaw = this.pendingRawInput;
5890
7110
  this.clearPendingQueue();
5891
- setTimeout(() => this.executePrompt(queued, queuedDisplay, queuedRaw), 0);
7111
+ setTimeout(() => void this.submit(queued, queuedDisplay, queuedRaw), 0);
5892
7112
  }
5893
7113
  }
5894
7114
  recordForkSkillError(err) {
@@ -5910,7 +7130,9 @@ var InteractiveSession = class {
5910
7130
  const parentSession = this.getSessionOrThrow();
5911
7131
  const deps = retrieveAgentToolDeps(parentSession);
5912
7132
  if (!deps) {
5913
- throw new Error("Fork execution is not available. Agent tool deps may not be initialized.");
7133
+ throw new Error(
7134
+ "Fork execution is not available. Agent runtime deps may not be initialized."
7135
+ );
5914
7136
  }
5915
7137
  const agentType = options.agent ?? "general-purpose";
5916
7138
  const agentDefinition = this.resolveForkAgentDefinition(agentType, options);
@@ -5968,7 +7190,7 @@ var InteractiveSession = class {
5968
7190
  const queuedDisplay = this.pendingDisplayInput;
5969
7191
  const queuedRaw = this.pendingRawInput;
5970
7192
  this.clearPendingQueue();
5971
- setTimeout(() => this.executePrompt(queued, queuedDisplay, queuedRaw), 0);
7193
+ setTimeout(() => void this.submit(queued, queuedDisplay, queuedRaw), 0);
5972
7194
  }
5973
7195
  }
5974
7196
  }
@@ -5980,8 +7202,22 @@ var InteractiveSession = class {
5980
7202
  const historyBefore = this.getSessionOrThrow().getHistory().length;
5981
7203
  this.usedMemoryReferences = [];
5982
7204
  try {
7205
+ const preparedPrompt = await preparePromptInput(
7206
+ input,
7207
+ this.getCwd(),
7208
+ rawInput,
7209
+ this.contextReferences
7210
+ );
7211
+ if (preparedPrompt.promptFileReferenceEntry) {
7212
+ this.history.push(preparedPrompt.promptFileReferenceEntry);
7213
+ }
7214
+ this.recordContextReferenceUsage(preparedPrompt.activeContextReferenceRecords);
7215
+ this.recordPromptContextReferences(preparedPrompt.promptFileReferenceRecords);
5983
7216
  await this.beginEditCheckpointTurn(displayInput ?? input);
5984
- const response = await this.getSessionOrThrow().run(input, rawInput);
7217
+ const response = await this.getSessionOrThrow().run(
7218
+ preparedPrompt.modelInput,
7219
+ preparedPrompt.hookInput
7220
+ );
5985
7221
  this.flushStreaming();
5986
7222
  pushToolSummaryToHistory({ activeTools: this.activeTools, history: this.history });
5987
7223
  this.clearStreaming();
@@ -5990,7 +7226,8 @@ var InteractiveSession = class {
5990
7226
  this.getSessionOrThrow().getHistory(),
5991
7227
  this.history,
5992
7228
  historyBefore,
5993
- this.getContextState()
7229
+ this.getContextState(),
7230
+ preparedPrompt.promptFileReferenceRecords
5994
7231
  );
5995
7232
  this.history.push(messageToHistoryEntry(createAssistantMessage(result.response)));
5996
7233
  if (result.usage) this.history.push(createUsageSummaryEntry(result.usage));
@@ -6029,10 +7266,24 @@ var InteractiveSession = class {
6029
7266
  const queuedDisplay = this.pendingDisplayInput;
6030
7267
  const queuedRaw = this.pendingRawInput;
6031
7268
  this.clearPendingQueue();
6032
- setTimeout(() => this.executePrompt(queued, queuedDisplay, queuedRaw), 0);
7269
+ setTimeout(() => void this.submit(queued, queuedDisplay, queuedRaw), 0);
6033
7270
  }
6034
7271
  }
6035
7272
  }
7273
+ recordContextReferenceUsage(records) {
7274
+ this.contextReferences = recordInteractiveContextReferences(this.contextReferences, records, {
7275
+ loadType: "manual",
7276
+ status: "active"
7277
+ });
7278
+ this.persistCurrentSession();
7279
+ }
7280
+ recordPromptContextReferences(records) {
7281
+ this.contextReferences = recordInteractiveContextReferences(this.contextReferences, records, {
7282
+ loadType: "prompt-reference",
7283
+ status: "observed"
7284
+ });
7285
+ this.persistCurrentSession();
7286
+ }
6036
7287
  getEditCheckpointStore() {
6037
7288
  if (!this.editCheckpointStore) {
6038
7289
  this.editCheckpointStore = new EditCheckpointStore({ cwd: this.getCwd() });
@@ -6108,6 +7359,163 @@ var InteractiveSession = class {
6108
7359
  }
6109
7360
  };
6110
7361
 
7362
+ // src/interactive/session-persistence.ts
7363
+ import {
7364
+ loadSessionLogEntries as loadSessionLogEntries2,
7365
+ replaySessionLogEntries,
7366
+ SessionStore
7367
+ } from "@robota-sdk/agent-sessions";
7368
+ import { existsSync as existsSync15, readdirSync as readdirSync8 } from "fs";
7369
+ import { join as join20 } from "path";
7370
+ function createProjectSessionStore(cwd) {
7371
+ const paths = projectPaths(cwd);
7372
+ return new ProjectSessionStoreFacade(paths.sessions, paths.logs);
7373
+ }
7374
+ function listResumableSessionSummaries(sessionStore, cwd) {
7375
+ return (sessionStore?.list() ?? []).filter((session) => session.cwd === cwd).sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime()).map((session) => ({
7376
+ id: session.id,
7377
+ ...session.name !== void 0 ? { name: session.name } : {},
7378
+ cwd: session.cwd,
7379
+ updatedAt: session.updatedAt,
7380
+ messageCount: session.messages.length,
7381
+ preview: getLastAssistantPreview(session.messages)
7382
+ }));
7383
+ }
7384
+ function resolveLatestSessionId(sessionStore, cwd) {
7385
+ return listResumableSessionSummaries(sessionStore, cwd)[0]?.id;
7386
+ }
7387
+ function resolveSessionIdByIdOrName(sessionStore, idOrName) {
7388
+ const match = (sessionStore?.list() ?? []).find(
7389
+ (session) => session.id === idOrName || session.name === idOrName
7390
+ );
7391
+ return match?.id;
7392
+ }
7393
+ var ProjectSessionStoreFacade = class {
7394
+ store;
7395
+ logsDir;
7396
+ constructor(baseDir, logsDir) {
7397
+ this.store = new SessionStore(baseDir);
7398
+ this.logsDir = logsDir;
7399
+ }
7400
+ save(session) {
7401
+ this.store.save(toSessionRecord(session));
7402
+ }
7403
+ load(id) {
7404
+ const session = this.store.load(id);
7405
+ if (session !== void 0) {
7406
+ return fromSessionRecord(session);
7407
+ }
7408
+ return this.loadFromReplayLog(id);
7409
+ }
7410
+ list() {
7411
+ const records = this.store.list().map(fromSessionRecord);
7412
+ const seen = new Set(records.map((record) => record.id));
7413
+ for (const replayRecord of this.listReplayLogRecords()) {
7414
+ if (!seen.has(replayRecord.id)) {
7415
+ records.push(replayRecord);
7416
+ }
7417
+ }
7418
+ return records.sort(
7419
+ (a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime()
7420
+ );
7421
+ }
7422
+ delete(id) {
7423
+ this.store.delete(id);
7424
+ }
7425
+ loadFromReplayLog(id) {
7426
+ if (!this.logsDir) return void 0;
7427
+ const replay = replaySessionLogEntries(
7428
+ loadSessionLogEntries2(join20(this.logsDir, `${id}.jsonl`))
7429
+ );
7430
+ if (!replay.sessionId || replay.messages.length === 0) {
7431
+ return void 0;
7432
+ }
7433
+ const backgroundTaskEvents = replay.backgroundTaskEvents;
7434
+ const backgroundJobGroupEvents = replay.backgroundJobGroupEvents;
7435
+ return {
7436
+ id: replay.sessionId,
7437
+ cwd: replay.cwd ?? "",
7438
+ createdAt: replay.createdAt ?? replay.updatedAt ?? (/* @__PURE__ */ new Date(0)).toISOString(),
7439
+ updatedAt: replay.updatedAt ?? replay.createdAt ?? (/* @__PURE__ */ new Date(0)).toISOString(),
7440
+ messages: replay.messages,
7441
+ history: replay.history,
7442
+ backgroundTasks: deriveBackgroundTasks(backgroundTaskEvents),
7443
+ backgroundTaskEvents,
7444
+ backgroundJobGroups: deriveBackgroundJobGroups(backgroundJobGroupEvents),
7445
+ backgroundJobGroupEvents,
7446
+ skillActivationEvents: [],
7447
+ memoryEvents: replay.memoryEvents
7448
+ };
7449
+ }
7450
+ listReplayLogRecords() {
7451
+ if (!this.logsDir || !existsSync15(this.logsDir)) {
7452
+ return [];
7453
+ }
7454
+ return readdirSync8(this.logsDir).filter((file) => file.endsWith(".jsonl")).map((file) => this.loadFromReplayLog(file.slice(0, -".jsonl".length))).filter((record) => record !== void 0);
7455
+ }
7456
+ };
7457
+ function getLastAssistantPreview(messages) {
7458
+ for (const message of [...messages].reverse()) {
7459
+ if (message.role !== "assistant") continue;
7460
+ if (typeof message.content !== "string") continue;
7461
+ return message.content.replace(/[\n\r]+/g, " ").trim();
7462
+ }
7463
+ return "";
7464
+ }
7465
+ function toSessionRecord(session) {
7466
+ return { ...session };
7467
+ }
7468
+ function fromSessionRecord(session) {
7469
+ return {
7470
+ id: session.id,
7471
+ ...session.name !== void 0 ? { name: session.name } : {},
7472
+ cwd: session.cwd,
7473
+ createdAt: session.createdAt,
7474
+ updatedAt: session.updatedAt,
7475
+ messages: session.messages,
7476
+ ...session.history !== void 0 ? { history: session.history } : {},
7477
+ ...session.systemPrompt !== void 0 ? { systemPrompt: session.systemPrompt } : {},
7478
+ ...session.toolSchemas !== void 0 ? { toolSchemas: session.toolSchemas } : {},
7479
+ ...session.backgroundTasks !== void 0 ? { backgroundTasks: session.backgroundTasks } : {},
7480
+ ...session.backgroundTaskEvents !== void 0 ? { backgroundTaskEvents: session.backgroundTaskEvents } : {},
7481
+ ...session.backgroundJobGroups !== void 0 ? { backgroundJobGroups: session.backgroundJobGroups } : {},
7482
+ ...session.backgroundJobGroupEvents !== void 0 ? { backgroundJobGroupEvents: session.backgroundJobGroupEvents } : {},
7483
+ ...session.skillActivationEvents !== void 0 ? { skillActivationEvents: session.skillActivationEvents } : {},
7484
+ ...session.memoryEvents !== void 0 ? { memoryEvents: session.memoryEvents } : {},
7485
+ ...session.usedMemoryReferences !== void 0 ? { usedMemoryReferences: session.usedMemoryReferences } : {},
7486
+ ...session.contextReferences !== void 0 ? { contextReferences: session.contextReferences } : {},
7487
+ ...session.sandboxSnapshotId !== void 0 ? { sandboxSnapshotId: session.sandboxSnapshotId } : {}
7488
+ };
7489
+ }
7490
+ function deriveBackgroundTasks(events) {
7491
+ const tasks = /* @__PURE__ */ new Map();
7492
+ for (const event of events) {
7493
+ const task = getBackgroundTaskSnapshot(event);
7494
+ if (task) tasks.set(task.id, task);
7495
+ }
7496
+ return [...tasks.values()];
7497
+ }
7498
+ function getBackgroundTaskSnapshot(event) {
7499
+ switch (event.type) {
7500
+ case "background_task_created":
7501
+ case "background_task_started":
7502
+ case "background_task_updated":
7503
+ case "background_task_completed":
7504
+ case "background_task_failed":
7505
+ case "background_task_cancelled":
7506
+ return event.task;
7507
+ default:
7508
+ return void 0;
7509
+ }
7510
+ }
7511
+ function deriveBackgroundJobGroups(events) {
7512
+ const groups = /* @__PURE__ */ new Map();
7513
+ for (const event of events) {
7514
+ groups.set(event.group.id, event.group);
7515
+ }
7516
+ return [...groups.values()];
7517
+ }
7518
+
6111
7519
  // src/query.ts
6112
7520
  function createQuery(options) {
6113
7521
  const session = new InteractiveSession({
@@ -6121,14 +7529,14 @@ function createQuery(options) {
6121
7529
  session.on("text_delta", options.onTextDelta);
6122
7530
  }
6123
7531
  return async (prompt) => {
6124
- return new Promise((resolve4, reject) => {
7532
+ return new Promise((resolve6, reject) => {
6125
7533
  const onComplete = (result) => {
6126
7534
  cleanup();
6127
- resolve4(result.response);
7535
+ resolve6(result.response);
6128
7536
  };
6129
7537
  const onInterrupted = (result) => {
6130
7538
  cleanup();
6131
- resolve4(result.response);
7539
+ resolve6(result.response);
6132
7540
  };
6133
7541
  const onError = (error) => {
6134
7542
  cleanup();
@@ -6150,17 +7558,6 @@ function createQuery(options) {
6150
7558
  };
6151
7559
  }
6152
7560
 
6153
- // src/types.ts
6154
- import { TRUST_TO_MODE } from "@robota-sdk/agent-core";
6155
-
6156
- // src/index.ts
6157
- import {
6158
- isChatEntry,
6159
- chatEntryToMessage,
6160
- messageToHistoryEntry as messageToHistoryEntry2,
6161
- getMessagesForAPI
6162
- } from "@robota-sdk/agent-core";
6163
-
6164
7561
  // src/self-hosting/self-hosting-verification.ts
6165
7562
  var DEFAULT_BASE_REF = "origin/develop";
6166
7563
  var PACKAGE_VERIFY_COMMANDS = ["test", "typecheck", "build"];
@@ -6276,13 +7673,72 @@ function transitionSelfHostingLoop(state, event) {
6276
7673
  return nextState;
6277
7674
  }
6278
7675
 
7676
+ // src/tools/command-execution-tool.ts
7677
+ import { z as z5 } from "zod";
7678
+ import { createZodFunctionTool as createZodFunctionTool4 } from "@robota-sdk/agent-tools";
7679
+ function asZodSchema4(schema) {
7680
+ return schema;
7681
+ }
7682
+ function toNonEmptyCommandNames(commandNames) {
7683
+ if (!commandNames || commandNames.length === 0) return void 0;
7684
+ const [first, ...rest] = commandNames;
7685
+ if (first === void 0) return void 0;
7686
+ return [first, ...rest];
7687
+ }
7688
+ function createCommandExecutionSchema(commandNames) {
7689
+ const validCommandNames = toNonEmptyCommandNames(commandNames);
7690
+ const commandSchema = validCommandNames !== void 0 ? z5.enum(validCommandNames).describe("Registered model-invocable command name to execute") : z5.string().describe("Registered model-invocable command name to execute");
7691
+ return z5.object({
7692
+ command: commandSchema,
7693
+ args: z5.string().optional().describe("Arguments to pass to the command")
7694
+ });
7695
+ }
7696
+ function getCommandNames(deps) {
7697
+ if (deps.commandNames !== void 0) return deps.commandNames;
7698
+ if (deps.commandDescriptors === void 0) return void 0;
7699
+ return deps.commandDescriptors.map((descriptor) => normalizeModelCommandName(descriptor.name));
7700
+ }
7701
+ function formatCommandDescriptor(descriptor) {
7702
+ const commandName = normalizeModelCommandName(descriptor.name);
7703
+ const argumentHint = descriptor.argumentHint ? ` ${descriptor.argumentHint}` : "";
7704
+ return `- ${commandName}${argumentHint}: ${descriptor.description}`;
7705
+ }
7706
+ function createToolDescription(commandDescriptors) {
7707
+ const base = "Executes a registered model-invocable Robota command through the command registry. Accepted command names and argument grammar come from registered command descriptors.";
7708
+ if (commandDescriptors === void 0 || commandDescriptors.length === 0) return base;
7709
+ return [
7710
+ base,
7711
+ "Use the registered command descriptors below as the authority for when to call this tool.",
7712
+ "",
7713
+ "Registered model-invocable commands:",
7714
+ ...commandDescriptors.map(formatCommandDescriptor)
7715
+ ].join("\n");
7716
+ }
7717
+ function createCommandExecutionTool(deps) {
7718
+ const commandExecutionSchema = createCommandExecutionSchema(getCommandNames(deps));
7719
+ return createZodFunctionTool4(
7720
+ "ExecuteCommand",
7721
+ createToolDescription(deps.commandDescriptors),
7722
+ asZodSchema4(commandExecutionSchema),
7723
+ async (params) => {
7724
+ const args = commandExecutionSchema.parse(params);
7725
+ const command = normalizeModelCommandName(args.command);
7726
+ if (!deps.isModelInvocable(command)) {
7727
+ return JSON.stringify({
7728
+ success: false,
7729
+ command,
7730
+ error: `Command is not model-invocable: ${command}`
7731
+ });
7732
+ }
7733
+ return stringifyModelCommandResult(command, await deps.execute(command, args.args ?? ""));
7734
+ }
7735
+ );
7736
+ }
7737
+
6279
7738
  // src/subagents/index.ts
6280
7739
  import { SubagentManager as SubagentManager3 } from "@robota-sdk/agent-runtime";
6281
7740
  import { WorktreeSubagentRunner, createWorktreeSubagentRunner } from "@robota-sdk/agent-runtime";
6282
7741
 
6283
- // src/index.ts
6284
- import { evaluatePermission } from "@robota-sdk/agent-core";
6285
-
6286
7742
  // src/permissions/permission-prompt.ts
6287
7743
  import chalk from "chalk";
6288
7744
  var PERMISSION_OPTIONS = ["Allow", "Deny"];
@@ -6302,9 +7758,6 @@ async function promptForApproval(terminal, toolName, toolArgs) {
6302
7758
  const selected = await terminal.select(PERMISSION_OPTIONS, ALLOW_INDEX);
6303
7759
  return selected === ALLOW_INDEX;
6304
7760
  }
6305
-
6306
- // src/index.ts
6307
- import { runHooks as runHooks2 } from "@robota-sdk/agent-core";
6308
7761
  export {
6309
7762
  AUTO_COMPACT_THRESHOLD_SETTINGS_KEY,
6310
7763
  AgentExecutor,
@@ -6321,6 +7774,7 @@ export {
6321
7774
  COST_COMMAND_DESCRIPTION,
6322
7775
  CommandRegistry,
6323
7776
  DEFAULT_AUTO_COMPACT_THRESHOLD,
7777
+ DEFAULT_BACKGROUND_TASK_LOG_PAGE_SIZE,
6324
7778
  DEFAULT_STATUS_LINE_COMMAND_SETTINGS,
6325
7779
  EXIT_COMMAND_DESCRIPTION,
6326
7780
  EditCheckpointStore,
@@ -6335,12 +7789,14 @@ export {
6335
7789
  MEMORY_INDEX_MAX_LINES,
6336
7790
  MODEL_COMMAND_ARGUMENT_HINT,
6337
7791
  MODEL_COMMAND_DESCRIPTION,
7792
+ MODEL_COMMAND_TOOL_PREFIX,
6338
7793
  MarketplaceClient,
6339
7794
  PERMISSIONS_COMMAND_DESCRIPTION,
6340
7795
  PERMISSION_MODE_ARGUMENT_HINT,
6341
7796
  PERMISSION_MODE_COMMAND_DESCRIPTION,
6342
7797
  PLUGIN_COMMAND_ARGUMENT_HINT,
6343
7798
  PLUGIN_COMMAND_DESCRIPTION,
7799
+ PROVIDER_SAFE_TOOL_NAME_PATTERN,
6344
7800
  PluginCommandSource,
6345
7801
  PluginSettingsStore,
6346
7802
  ProjectMemoryStore,
@@ -6357,9 +7813,11 @@ export {
6357
7813
  SkillCommandSource,
6358
7814
  SubagentManager3 as SubagentManager,
6359
7815
  SystemCommandExecutor,
6360
- TRUST_TO_MODE,
7816
+ VALIDATE_SESSION_COMMAND_DESCRIPTION,
6361
7817
  VALID_PERMISSION_MODES,
6362
7818
  WorktreeSubagentRunner,
7819
+ addCommandContextReference,
7820
+ appendPrefixedLogLines,
6363
7821
  assembleSubagentPrompt,
6364
7822
  buildBackgroundCommandSubcommands,
6365
7823
  buildLanguageCommandSubcommands,
@@ -6367,26 +7825,35 @@ export {
6367
7825
  buildModelCommandSubcommands,
6368
7826
  buildPermissionModeSubcommands,
6369
7827
  buildPluginCommandSubcommands,
7828
+ buildPromptWithFileReferences,
6370
7829
  buildProviderProfile,
6371
7830
  buildProviderSetupPatch,
6372
7831
  buildRewindCommandSubcommands,
6373
- buildSkillPrompt,
6374
7832
  buildStatusLineCommandSubcommands,
6375
7833
  cancelCommandBackgroundTask,
6376
- chatEntryToMessage,
7834
+ clearCommandContextReferences,
7835
+ clearContextReferences,
6377
7836
  clearConversationHistory,
6378
7837
  closeCommandBackgroundTask,
6379
7838
  compactCommandContext,
6380
7839
  createAgentTool,
6381
7840
  createBackgroundProcessTool,
7841
+ createBackgroundTaskLogPage,
6382
7842
  createBuiltinCommandModule,
6383
7843
  createCommandExecutionTool,
6384
7844
  createCommandMemoryStores,
6385
7845
  createCommandPendingMemoryStore,
6386
7846
  createCommandProjectMemoryStore,
7847
+ createContextReferenceItem,
6387
7848
  createDefaultTools,
7849
+ createLimitedOutputCapture,
7850
+ createModelCommandToolProjection,
6388
7851
  createPluginRegistryReloadRequestedEffect,
6389
7852
  createPluginTuiRequestedEffect,
7853
+ createProjectSessionStore,
7854
+ createProjectedCommandExecutionTools,
7855
+ createPromptFileReferenceHistoryEntry,
7856
+ createProviderSafeModelCommandToolName,
6390
7857
  createProviderSetupFlow,
6391
7858
  createQuery,
6392
7859
  createSessionExitRequestedEffect,
@@ -6396,48 +7863,57 @@ export {
6396
7863
  createSubagentSession,
6397
7864
  createSystemCommands,
6398
7865
  createWorktreeSubagentRunner,
7866
+ deleteProviderProfile,
6399
7867
  discoverTaskFiles,
6400
- evaluatePermission,
6401
7868
  evaluateReversibleToolSafety,
6402
7869
  executeSkill,
6403
7870
  formatCommandBackgroundTask,
6404
7871
  formatCommandBackgroundTaskList,
6405
7872
  formatCommandHelpMessage,
6406
7873
  formatCommandPermissionsMessage,
7874
+ formatCommandSessionReplayValidationReport,
6407
7875
  formatEnvReference,
6408
7876
  formatInvalidPermissionModeMessage,
6409
7877
  formatLanguageUsageMessage,
7878
+ formatModelCommandUsageMessage,
7879
+ formatModelCommandUsageMessageAsync,
7880
+ formatProjectedModelCommandToolPromptDescription,
7881
+ formatPromptFileReferenceDiagnostics,
6410
7882
  formatProviderSetupChoiceLabel,
7883
+ formatProviderSetupHelpLinks,
6411
7884
  formatProviderSetupPromptLabel,
6412
7885
  formatProviderSetupSelectionPrompt,
6413
7886
  formatTaskContext,
6414
7887
  getBackgroundTaskTransitions,
6415
7888
  getBuiltInAgent,
6416
7889
  getForkWorkerSuffix,
6417
- getMessagesForAPI,
6418
7890
  getProviderSetupStep,
6419
7891
  getSubagentSuffix,
7892
+ hasBlockingPromptFileReferenceDiagnostics,
6420
7893
  hasSensitiveCommandMemoryContent,
6421
7894
  hasUsableSecretReference,
6422
7895
  inspectCommandEditCheckpoint,
6423
- isChatEntry,
6424
7896
  isCommandMemoryType,
6425
7897
  isEnvReference,
6426
7898
  isMemoryType,
6427
7899
  isPermissionMode,
6428
7900
  isStatusLineCommandSettingsPatch,
6429
7901
  isTerminalBackgroundTaskStatus2 as isTerminalBackgroundTaskStatus,
7902
+ listActiveContextReferences,
6430
7903
  listCommandBackgroundTasks,
7904
+ listCommandContextReferences,
6431
7905
  listCommandEditCheckpoints,
6432
7906
  listCommandSessionAllowedTools,
6433
7907
  listCommandUsedMemoryReferences,
7908
+ listResumableSessionSummaries,
6434
7909
  loadTaskContext,
6435
7910
  mergeProviderPatch,
6436
- messageToHistoryEntry2 as messageToHistoryEntry,
7911
+ normalizeModelCommandName,
6437
7912
  parseCommandBackgroundLogCursor,
6438
7913
  parseFrontmatter,
6439
7914
  parseLanguageArgument,
6440
7915
  parsePermissionModeArgument,
7916
+ parsePromptFileReferences,
6441
7917
  parseSessionNameArgument,
6442
7918
  parseTaskFile,
6443
7919
  planSelfHostingVerification,
@@ -6454,30 +7930,43 @@ export {
6454
7930
  readCommandSessionInfo,
6455
7931
  readCurrentGitBranch,
6456
7932
  recordCommandMemoryEvent,
7933
+ removeCommandContextReference,
7934
+ removeContextReference,
6457
7935
  resetAutoCompactThresholdSetting,
7936
+ resolveActiveProviderModelCatalog,
7937
+ resolveActiveProviderModelCatalogState,
6458
7938
  resolveEnvReference,
7939
+ resolveLatestSessionId,
6459
7940
  resolvePermissionModeAdapter,
6460
7941
  resolvePluginCommandAdapter,
7942
+ resolvePromptFileReferencePaths,
7943
+ resolvePromptFileReferences,
6461
7944
  resolveProviderSetupSelection,
7945
+ resolveSessionIdByIdOrName,
6462
7946
  resolveSubagentLogDir,
6463
7947
  restoreCommandEditCheckpoint,
6464
7948
  retrieveAgentToolDeps,
6465
7949
  rollbackCommandEditCheckpoint,
6466
- runHooks2 as runHooks,
6467
7950
  runProviderSetupPromptFlow,
7951
+ sanitizeProviderProfileName,
6468
7952
  selectRelevantTasks,
6469
7953
  setCommandAutoCompactThreshold,
6470
7954
  setCurrentProvider,
6471
7955
  storeAgentToolDeps,
6472
7956
  submitProviderSetupValue,
6473
7957
  substituteVariables,
7958
+ suggestProviderProfileName,
6474
7959
  summarizeBackgroundJobGroup,
6475
7960
  testProviderProfileCommand,
7961
+ toContextReferenceRecords,
7962
+ toPromptFileReferenceRecords,
6476
7963
  transitionBackgroundTaskStatus,
6477
7964
  transitionSelfHostingLoop,
6478
7965
  updateTaskFileStatus,
7966
+ upsertContextReference,
6479
7967
  upsertProviderProfile,
6480
7968
  userPaths,
7969
+ validateCommandSessionReplayLog,
6481
7970
  validateProviderProfile,
6482
7971
  validateProviderSetupValue,
6483
7972
  wrapEditCheckpointTools,