@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.
- package/README.md +133 -46
- package/dist/node/index.cjs +2037 -519
- package/dist/node/index.d.cts +339 -26
- package/dist/node/index.d.ts +339 -26
- package/dist/node/index.js +2011 -522
- package/package.json +7 -6
package/dist/node/index.js
CHANGED
|
@@ -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:
|
|
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:
|
|
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
|
-
|
|
229
|
-
|
|
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
|
|
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:
|
|
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(
|
|
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
|
-
|
|
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
|
|
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
|
|
781
|
+
profile,
|
|
645
782
|
type: state.type,
|
|
646
783
|
model: state.values.model,
|
|
647
|
-
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 {
|
|
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(
|
|
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
|
|
1329
|
+
import { dirname, join as join4 } from "path";
|
|
972
1330
|
var PENDING_FILENAME = "pending.json";
|
|
973
1331
|
function memoryRoot(cwd) {
|
|
974
|
-
return
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
1458
|
+
return join5(memoryRoot2(this.cwd), INDEX_FILENAME);
|
|
1101
1459
|
}
|
|
1102
1460
|
getTopicsPath() {
|
|
1103
|
-
return
|
|
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:
|
|
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 =
|
|
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 =
|
|
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(
|
|
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(
|
|
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
|
|
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 =
|
|
1706
|
-
prompt:
|
|
1707
|
-
subagent_type:
|
|
1708
|
-
model:
|
|
1709
|
-
isolation:
|
|
1710
|
-
jobs:
|
|
1711
|
-
|
|
1712
|
-
label:
|
|
1713
|
-
prompt:
|
|
1714
|
-
subagent_type:
|
|
1715
|
-
model:
|
|
1716
|
-
isolation:
|
|
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
|
|
2337
|
+
return createZodFunctionTool2(
|
|
1842
2338
|
"Agent",
|
|
1843
2339
|
AGENT_TOOL_DESCRIPTION,
|
|
1844
|
-
|
|
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((
|
|
1949
|
-
resolveGroup =
|
|
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("&", "&").replaceAll('"', """).replaceAll("<", "<").replaceAll(">", ">");
|
|
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_${
|
|
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
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
|
3329
|
+
import { join as join6 } from "path";
|
|
2376
3330
|
|
|
2377
3331
|
// src/config/config-types.ts
|
|
2378
|
-
import { z as
|
|
2379
|
-
var UniversalValueSchema =
|
|
2380
|
-
() =>
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
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 =
|
|
2392
|
-
name:
|
|
2393
|
-
model:
|
|
2394
|
-
apiKey:
|
|
2395
|
-
baseURL:
|
|
2396
|
-
timeout:
|
|
2397
|
-
options:
|
|
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 =
|
|
2400
|
-
type:
|
|
2401
|
-
model:
|
|
2402
|
-
apiKey:
|
|
2403
|
-
baseURL:
|
|
2404
|
-
timeout:
|
|
2405
|
-
options:
|
|
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 =
|
|
3361
|
+
var PermissionsSchema = z3.object({
|
|
2408
3362
|
/** Patterns that are always approved without prompting */
|
|
2409
|
-
allow:
|
|
3363
|
+
allow: z3.array(z3.string()).optional(),
|
|
2410
3364
|
/** Patterns that are always denied */
|
|
2411
|
-
deny:
|
|
3365
|
+
deny: z3.array(z3.string()).optional()
|
|
2412
3366
|
});
|
|
2413
|
-
var EnvSchema =
|
|
2414
|
-
var CommandHookDefinitionSchema =
|
|
2415
|
-
type:
|
|
2416
|
-
command:
|
|
2417
|
-
timeout:
|
|
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 =
|
|
2420
|
-
type:
|
|
2421
|
-
url:
|
|
2422
|
-
headers:
|
|
2423
|
-
timeout:
|
|
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 =
|
|
2426
|
-
type:
|
|
2427
|
-
prompt:
|
|
2428
|
-
model:
|
|
3379
|
+
var PromptHookDefinitionSchema = z3.object({
|
|
3380
|
+
type: z3.literal("prompt"),
|
|
3381
|
+
prompt: z3.string(),
|
|
3382
|
+
model: z3.string().optional()
|
|
2429
3383
|
});
|
|
2430
|
-
var AgentHookDefinitionSchema =
|
|
2431
|
-
type:
|
|
2432
|
-
agent:
|
|
2433
|
-
maxTurns:
|
|
2434
|
-
timeout:
|
|
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 =
|
|
3390
|
+
var HookDefinitionSchema = z3.discriminatedUnion("type", [
|
|
2437
3391
|
CommandHookDefinitionSchema,
|
|
2438
3392
|
HttpHookDefinitionSchema,
|
|
2439
3393
|
PromptHookDefinitionSchema,
|
|
2440
3394
|
AgentHookDefinitionSchema
|
|
2441
3395
|
]);
|
|
2442
|
-
var HookGroupSchema =
|
|
2443
|
-
matcher:
|
|
2444
|
-
hooks:
|
|
3396
|
+
var HookGroupSchema = z3.object({
|
|
3397
|
+
matcher: z3.string(),
|
|
3398
|
+
hooks: z3.array(HookDefinitionSchema)
|
|
2445
3399
|
});
|
|
2446
|
-
var HooksSchema =
|
|
2447
|
-
PreToolUse:
|
|
2448
|
-
PostToolUse:
|
|
2449
|
-
SessionStart:
|
|
2450
|
-
SessionEnd:
|
|
2451
|
-
Stop:
|
|
2452
|
-
StopFailure:
|
|
2453
|
-
PreCompact:
|
|
2454
|
-
PostCompact:
|
|
2455
|
-
UserPromptSubmit:
|
|
2456
|
-
SubagentStart:
|
|
2457
|
-
SubagentStop:
|
|
2458
|
-
WorktreeCreate:
|
|
2459
|
-
WorktreeRemove:
|
|
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 =
|
|
2462
|
-
var MarketplaceSourceSchema =
|
|
2463
|
-
source:
|
|
2464
|
-
type:
|
|
2465
|
-
repo:
|
|
2466
|
-
url:
|
|
2467
|
-
path:
|
|
2468
|
-
ref:
|
|
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 =
|
|
2472
|
-
var AutoCompactThresholdSchema =
|
|
2473
|
-
var SettingsSchema =
|
|
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:
|
|
3429
|
+
defaultTrustLevel: z3.enum(["safe", "moderate", "full"]).optional(),
|
|
2476
3430
|
/** Response language (e.g., "ko", "en", "ja"). Injected into system prompt. */
|
|
2477
|
-
language:
|
|
3431
|
+
language: z3.string().optional(),
|
|
2478
3432
|
/** Active provider profile key from providers. */
|
|
2479
|
-
currentProvider:
|
|
3433
|
+
currentProvider: z3.string().optional(),
|
|
2480
3434
|
/** Provider profiles keyed by user-facing profile name. */
|
|
2481
|
-
providers:
|
|
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
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
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
|
-
|
|
3602
|
+
join6(home, ".robota", "settings.json"),
|
|
2639
3603
|
// 1. user (lowest)
|
|
2640
|
-
|
|
3604
|
+
join6(home, ".claude", "settings.json"),
|
|
2641
3605
|
// 1b. user (Claude Code compat)
|
|
2642
|
-
|
|
3606
|
+
join6(cwd, ".robota", "settings.json"),
|
|
2643
3607
|
// 2. project
|
|
2644
|
-
|
|
3608
|
+
join6(cwd, ".robota", "settings.local.json"),
|
|
2645
3609
|
// 3. project-local
|
|
2646
|
-
|
|
3610
|
+
join6(cwd, ".claude", "settings.json"),
|
|
2647
3611
|
// 4. project, Claude Code compat
|
|
2648
|
-
|
|
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
|
|
2886
|
-
if (
|
|
2887
|
-
return createSection(
|
|
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
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
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
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
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
|
|
2989
|
-
import { createZodFunctionTool as
|
|
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
|
|
3961
|
+
function asZodSchema3(schema) {
|
|
2992
3962
|
return schema;
|
|
2993
3963
|
}
|
|
2994
|
-
var BackgroundProcessSchema =
|
|
2995
|
-
command:
|
|
2996
|
-
timeout:
|
|
2997
|
-
workingDirectory:
|
|
2998
|
-
stdin:
|
|
2999
|
-
outputLimitBytes:
|
|
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
|
|
4008
|
+
function createBackgroundProcessTool(deps) {
|
|
3076
4009
|
return createZodFunctionTool3(
|
|
3077
|
-
"
|
|
3078
|
-
"
|
|
3079
|
-
asZodSchema3(
|
|
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
|
|
3338
|
-
import { homedir as
|
|
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 =
|
|
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 ??
|
|
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(
|
|
3421
|
-
scanAgentsDir(
|
|
3422
|
-
scanAgentsDir(
|
|
3423
|
-
scanAgentsDir(
|
|
3424
|
-
scanAgentsDir(
|
|
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
|
|
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
|
|
4452
|
+
const reversibleExecution = options.reversibleExecution ? {
|
|
3505
4453
|
...options.reversibleExecution,
|
|
3506
|
-
|
|
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
|
-
|
|
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
|
-
...
|
|
3602
|
-
|
|
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:
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
3734
|
-
var TASKS_DIR =
|
|
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 =
|
|
4763
|
+
let current = resolve3(cwd);
|
|
3835
4764
|
let reachedRoot = false;
|
|
3836
4765
|
while (!reachedRoot) {
|
|
3837
|
-
const gitPath =
|
|
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
|
|
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 =
|
|
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 =
|
|
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) =>
|
|
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 =
|
|
4834
|
+
let current = resolve4(startDir);
|
|
3906
4835
|
let atRoot = false;
|
|
3907
4836
|
while (!atRoot) {
|
|
3908
|
-
const candidate =
|
|
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
|
|
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(
|
|
4898
|
+
if (existsSync8(join11(cwd, "pnpm-workspace.yaml")) || existsSync8(join11(cwd, "pnpm-lock.yaml"))) {
|
|
3970
4899
|
return "pnpm";
|
|
3971
4900
|
}
|
|
3972
|
-
if (existsSync8(
|
|
4901
|
+
if (existsSync8(join11(cwd, "yarn.lock"))) {
|
|
3973
4902
|
return "yarn";
|
|
3974
4903
|
}
|
|
3975
|
-
if (existsSync8(
|
|
4904
|
+
if (existsSync8(join11(cwd, "bun.lockb"))) {
|
|
3976
4905
|
return "bun";
|
|
3977
4906
|
}
|
|
3978
|
-
if (existsSync8(
|
|
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 =
|
|
3985
|
-
const tsconfigPath =
|
|
3986
|
-
const pyprojectPath =
|
|
3987
|
-
const cargoPath =
|
|
3988
|
-
const goModPath =
|
|
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(
|
|
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
|
|
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 =
|
|
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 =
|
|
5147
|
+
const marketplaceDir = join12(cacheDir, marketplace);
|
|
4219
5148
|
const plugins = getSortedSubdirs(marketplaceDir);
|
|
4220
5149
|
for (const pluginName of plugins) {
|
|
4221
|
-
const pluginDir =
|
|
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 =
|
|
4226
|
-
const manifestPath =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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(
|
|
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 =
|
|
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 =
|
|
4336
|
-
const fallbackPath =
|
|
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 =
|
|
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
|
|
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 =
|
|
4374
|
-
this.registryPath =
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
4611
|
-
this.registryPath =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
5747
|
+
import { join as join16, dirname as dirname7 } from "path";
|
|
4819
5748
|
function buildPluginEnv(plugin) {
|
|
4820
|
-
const dataDir =
|
|
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
|
|
4883
|
-
import { join as
|
|
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 =
|
|
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 (
|
|
4949
|
-
|
|
4950
|
-
|
|
4951
|
-
|
|
4952
|
-
|
|
4953
|
-
|
|
4954
|
-
|
|
4955
|
-
session.injectMessage(
|
|
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
|
|
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
|
|
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 ?
|
|
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 =
|
|
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 =
|
|
5116
|
-
await mkdir(
|
|
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 =
|
|
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 =
|
|
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,
|
|
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
|
-
|
|
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) =>
|
|
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 =
|
|
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
|
|
6273
|
+
return join19(this.rootDir, safePathSegment(sessionId));
|
|
5266
6274
|
}
|
|
5267
6275
|
checkpointDir(sessionId, checkpointId) {
|
|
5268
|
-
return
|
|
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
|
-
|
|
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
|
-
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
|
|
5370
|
-
|
|
5371
|
-
|
|
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
|
|
5466
|
-
|
|
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
|
-
|
|
5474
|
-
|
|
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
|
-
|
|
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
|
-
|
|
6551
|
+
getCommandInvocationSource() {
|
|
6552
|
+
return this.commandInvocationSource;
|
|
6553
|
+
}
|
|
6554
|
+
async executeSkillCommandByName(name, args, request) {
|
|
5483
6555
|
await this.ensureInitialized();
|
|
5484
|
-
|
|
5485
|
-
|
|
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
|
-
|
|
6577
|
+
await this.executeUserResolvedSkillCommand(
|
|
5488
6578
|
skill,
|
|
5489
6579
|
args,
|
|
5490
|
-
|
|
5491
|
-
|
|
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
|
|
5749
|
-
|
|
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
|
-
{
|
|
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.
|
|
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(
|
|
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.
|
|
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(
|
|
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.
|
|
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((
|
|
7532
|
+
return new Promise((resolve6, reject) => {
|
|
6125
7533
|
const onComplete = (result) => {
|
|
6126
7534
|
cleanup();
|
|
6127
|
-
|
|
7535
|
+
resolve6(result.response);
|
|
6128
7536
|
};
|
|
6129
7537
|
const onInterrupted = (result) => {
|
|
6130
7538
|
cleanup();
|
|
6131
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|