@xpert-ai/plugin-sdk 3.8.1 → 3.8.3
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/index.cjs.js +149 -60
- package/index.esm.js +129 -61
- package/package.json +1 -1
- package/src/index.d.ts +1 -0
- package/src/lib/core/index.d.ts +1 -0
- package/src/lib/core/plugin-config.d.ts +9 -0
- package/src/lib/file/file-storage/index.d.ts +3 -0
- package/src/lib/file/file-storage/provider.decorator.d.ts +2 -0
- package/src/lib/file/file-storage/provider.interface.d.ts +14 -0
- package/src/lib/file/file-storage/provider.registry.d.ts +6 -0
- package/src/lib/file/file-upload/index.d.ts +3 -0
- package/src/lib/file/file-upload/strategy.decorator.d.ts +2 -0
- package/src/lib/file/file-upload/strategy.interface.d.ts +25 -0
- package/src/lib/file/file-upload/strategy.registry.d.ts +6 -0
- package/src/lib/file/index.d.ts +2 -0
- package/src/lib/sandbox/execution.d.ts +27 -0
- package/src/lib/sandbox/index.d.ts +1 -0
- package/src/lib/sandbox/protocol.d.ts +6 -3
- package/src/lib/sandbox/sandbox.d.ts +4 -3
- package/src/lib/types.d.ts +3 -1
package/index.cjs.js
CHANGED
|
@@ -956,6 +956,8 @@ BuiltinToolset.provider = '';
|
|
|
956
956
|
}
|
|
957
957
|
}
|
|
958
958
|
|
|
959
|
+
const PLUGIN_CONFIG_RESOLVER_TOKEN = 'XPERT_PLUGIN_CONFIG_RESOLVER';
|
|
960
|
+
|
|
959
961
|
/**
|
|
960
962
|
* System token for resolving integration read service from plugin context.
|
|
961
963
|
*/ const INTEGRATION_PERMISSION_SERVICE_TOKEN = 'XPERT_PLUGIN_INTEGRATION_PERMISSION_SERVICE';
|
|
@@ -2635,34 +2637,100 @@ class CancelConversationCommand {
|
|
|
2635
2637
|
}
|
|
2636
2638
|
CancelConversationCommand.type = '[Chat Conversation] Cancel';
|
|
2637
2639
|
|
|
2640
|
+
const FILE_STORAGE_PROVIDER = 'FILE_STORAGE_PROVIDER';
|
|
2641
|
+
const FileStorageProvider = (provider)=>common.applyDecorators(common.SetMetadata(FILE_STORAGE_PROVIDER, provider), common.SetMetadata(STRATEGY_META_KEY, FILE_STORAGE_PROVIDER));
|
|
2642
|
+
|
|
2643
|
+
exports.FileStorageProviderRegistry = class FileStorageProviderRegistry extends BaseStrategyRegistry {
|
|
2644
|
+
constructor(discoveryService, reflector){
|
|
2645
|
+
super(FILE_STORAGE_PROVIDER, discoveryService, reflector);
|
|
2646
|
+
}
|
|
2647
|
+
};
|
|
2648
|
+
exports.FileStorageProviderRegistry = __decorate([
|
|
2649
|
+
common.Injectable(),
|
|
2650
|
+
__metadata("design:type", Function),
|
|
2651
|
+
__metadata("design:paramtypes", [
|
|
2652
|
+
typeof core.DiscoveryService === "undefined" ? Object : core.DiscoveryService,
|
|
2653
|
+
typeof core.Reflector === "undefined" ? Object : core.Reflector
|
|
2654
|
+
])
|
|
2655
|
+
], exports.FileStorageProviderRegistry);
|
|
2656
|
+
|
|
2657
|
+
const FILE_UPLOAD_TARGET_STRATEGY = 'FILE_UPLOAD_TARGET_STRATEGY';
|
|
2658
|
+
const FileUploadTargetStrategy = (type)=>common.applyDecorators(common.SetMetadata(FILE_UPLOAD_TARGET_STRATEGY, type), common.SetMetadata(STRATEGY_META_KEY, FILE_UPLOAD_TARGET_STRATEGY));
|
|
2659
|
+
|
|
2660
|
+
exports.FileUploadTargetRegistry = class FileUploadTargetRegistry extends BaseStrategyRegistry {
|
|
2661
|
+
constructor(discoveryService, reflector){
|
|
2662
|
+
super(FILE_UPLOAD_TARGET_STRATEGY, discoveryService, reflector);
|
|
2663
|
+
}
|
|
2664
|
+
};
|
|
2665
|
+
exports.FileUploadTargetRegistry = __decorate([
|
|
2666
|
+
common.Injectable(),
|
|
2667
|
+
__metadata("design:type", Function),
|
|
2668
|
+
__metadata("design:paramtypes", [
|
|
2669
|
+
typeof core.DiscoveryService === "undefined" ? Object : core.DiscoveryService,
|
|
2670
|
+
typeof core.Reflector === "undefined" ? Object : core.Reflector
|
|
2671
|
+
])
|
|
2672
|
+
], exports.FileUploadTargetRegistry);
|
|
2673
|
+
|
|
2674
|
+
const SANDBOX_SHELL_TIMEOUT_LIMITS_SEC = {
|
|
2675
|
+
min: 1,
|
|
2676
|
+
max: 3600
|
|
2677
|
+
};
|
|
2678
|
+
const DEFAULT_SANDBOX_SHELL_TIMEOUT_SEC = 600;
|
|
2679
|
+
const DEFAULT_SANDBOX_FILE_SEARCH_TIMEOUT_SEC = 120;
|
|
2680
|
+
const DEFAULT_SANDBOX_FILE_OPERATION_TIMEOUT_SEC = 120;
|
|
2681
|
+
const DEFAULT_SANDBOX_SHELL_TIMEOUT_MS = DEFAULT_SANDBOX_SHELL_TIMEOUT_SEC * 1000;
|
|
2682
|
+
const DEFAULT_SANDBOX_FILE_SEARCH_TIMEOUT_MS = DEFAULT_SANDBOX_FILE_SEARCH_TIMEOUT_SEC * 1000;
|
|
2683
|
+
const DEFAULT_SANDBOX_FILE_OPERATION_TIMEOUT_MS = DEFAULT_SANDBOX_FILE_OPERATION_TIMEOUT_SEC * 1000;
|
|
2684
|
+
const DEFAULT_SANDBOX_EXECUTION_MAX_OUTPUT_BYTES = 1024 * 1024;
|
|
2685
|
+
const DEFAULT_SANDBOX_SHELL_EXECUTION_OPTIONS = {
|
|
2686
|
+
timeoutMs: DEFAULT_SANDBOX_SHELL_TIMEOUT_MS,
|
|
2687
|
+
maxOutputBytes: DEFAULT_SANDBOX_EXECUTION_MAX_OUTPUT_BYTES
|
|
2688
|
+
};
|
|
2689
|
+
const DEFAULT_SANDBOX_FILE_SEARCH_EXECUTION_OPTIONS = {
|
|
2690
|
+
timeoutMs: DEFAULT_SANDBOX_FILE_SEARCH_TIMEOUT_MS,
|
|
2691
|
+
maxOutputBytes: DEFAULT_SANDBOX_EXECUTION_MAX_OUTPUT_BYTES
|
|
2692
|
+
};
|
|
2693
|
+
const DEFAULT_SANDBOX_FILE_OPERATION_EXECUTION_OPTIONS = {
|
|
2694
|
+
timeoutMs: DEFAULT_SANDBOX_FILE_OPERATION_TIMEOUT_MS,
|
|
2695
|
+
maxOutputBytes: DEFAULT_SANDBOX_EXECUTION_MAX_OUTPUT_BYTES
|
|
2696
|
+
};
|
|
2697
|
+
function secondsToMilliseconds(seconds) {
|
|
2698
|
+
return Math.trunc(seconds * 1000);
|
|
2699
|
+
}
|
|
2700
|
+
function formatSandboxTimeout(timeoutMs) {
|
|
2701
|
+
const timeoutSeconds = timeoutMs / 1000;
|
|
2702
|
+
const secondsLabel = Number.isInteger(timeoutSeconds) ? String(timeoutSeconds) : Number(timeoutSeconds.toFixed(3)).toString();
|
|
2703
|
+
return `${secondsLabel}s (${timeoutMs}ms)`;
|
|
2704
|
+
}
|
|
2705
|
+
function buildSandboxTimeoutMessage(subject, timeoutMs) {
|
|
2706
|
+
return `${subject} timed out after ${formatSandboxTimeout(timeoutMs)}`;
|
|
2707
|
+
}
|
|
2708
|
+
function appendSandboxMessage(output, message) {
|
|
2709
|
+
return output ? `${output}\n${message}` : message;
|
|
2710
|
+
}
|
|
2711
|
+
function resolveSandboxExecutionOptions(options, defaults = DEFAULT_SANDBOX_SHELL_EXECUTION_OPTIONS) {
|
|
2712
|
+
const timeoutMs = typeof (options == null ? void 0 : options.timeoutMs) === 'number' && Number.isFinite(options.timeoutMs) && options.timeoutMs > 0 ? Math.trunc(options.timeoutMs) : typeof defaults.timeoutMs === 'number' && Number.isFinite(defaults.timeoutMs) && defaults.timeoutMs > 0 ? Math.trunc(defaults.timeoutMs) : DEFAULT_SANDBOX_SHELL_TIMEOUT_MS;
|
|
2713
|
+
const maxOutputBytes = typeof (options == null ? void 0 : options.maxOutputBytes) === 'number' && Number.isFinite(options.maxOutputBytes) && options.maxOutputBytes > 0 ? Math.trunc(options.maxOutputBytes) : typeof defaults.maxOutputBytes === 'number' && Number.isFinite(defaults.maxOutputBytes) && defaults.maxOutputBytes > 0 ? Math.trunc(defaults.maxOutputBytes) : DEFAULT_SANDBOX_EXECUTION_MAX_OUTPUT_BYTES;
|
|
2714
|
+
return {
|
|
2715
|
+
timeoutMs,
|
|
2716
|
+
maxOutputBytes
|
|
2717
|
+
};
|
|
2718
|
+
}
|
|
2719
|
+
|
|
2638
2720
|
/**
|
|
2639
|
-
* Protocol definition for pluggable memory backends.
|
|
2640
|
-
*
|
|
2641
|
-
* This module defines the BackendProtocol that all backend implementations
|
|
2642
|
-
* must follow. Backends can store files in different locations (state, filesystem,
|
|
2643
|
-
* database, etc.) and provide a uniform interface for file operations.
|
|
2644
|
-
*/ /**
|
|
2645
2721
|
* Type guard to check if a backend supports execution.
|
|
2646
2722
|
*
|
|
2647
2723
|
* @param backend - Backend instance to check
|
|
2648
2724
|
* @returns True if the backend implements SandboxBackendProtocol
|
|
2649
2725
|
*/ function isSandboxBackend(backend) {
|
|
2650
|
-
return typeof backend.execute ===
|
|
2726
|
+
return typeof backend.execute === 'function' && typeof backend.id === 'string';
|
|
2651
2727
|
}
|
|
2652
2728
|
|
|
2653
|
-
|
|
2654
|
-
* BaseSandbox: Abstract base class for sandbox backends with command execution.
|
|
2655
|
-
*
|
|
2656
|
-
* This class provides default implementations for all SandboxBackendProtocol
|
|
2657
|
-
* methods using shell commands executed via execute(). Concrete implementations
|
|
2658
|
-
* only need to implement the execute() method.
|
|
2659
|
-
*
|
|
2660
|
-
* Requires Node.js 20+ on the sandbox host.
|
|
2661
|
-
*/ const MAX_LINE_LENGTH = 500;
|
|
2729
|
+
const MAX_LINE_LENGTH = 500;
|
|
2662
2730
|
const MAX_GREP_LINE_LENGTH = 2000;
|
|
2663
2731
|
const GREP_RESULT_LIMIT = 100;
|
|
2664
2732
|
const GLOB_RESULT_LIMIT = 100;
|
|
2665
|
-
const WRITE_EXISTS_OUTPUT =
|
|
2733
|
+
const WRITE_EXISTS_OUTPUT = 'Error: File already exists';
|
|
2666
2734
|
/**
|
|
2667
2735
|
* UTF-8 safe Base64 encoding function.
|
|
2668
2736
|
* Replaces btoa() which only supports Latin1 characters.
|
|
@@ -2676,17 +2744,17 @@ const WRITE_EXISTS_OUTPUT = "Error: File already exists";
|
|
|
2676
2744
|
const truncated = files.length > limit;
|
|
2677
2745
|
const finalFiles = truncated ? files.slice(0, limit) : files;
|
|
2678
2746
|
if (finalFiles.length === 0) {
|
|
2679
|
-
return
|
|
2747
|
+
return 'No files found';
|
|
2680
2748
|
}
|
|
2681
2749
|
const lines = [];
|
|
2682
2750
|
for (const file of finalFiles){
|
|
2683
2751
|
lines.push(file.path);
|
|
2684
2752
|
}
|
|
2685
2753
|
if (truncated) {
|
|
2686
|
-
lines.push(
|
|
2687
|
-
lines.push(
|
|
2754
|
+
lines.push('');
|
|
2755
|
+
lines.push('(Results truncated. Consider using a more specific path or pattern.)');
|
|
2688
2756
|
}
|
|
2689
|
-
return lines.join(
|
|
2757
|
+
return lines.join('\n');
|
|
2690
2758
|
}
|
|
2691
2759
|
/**
|
|
2692
2760
|
* Format grep matches into human-readable output grouped by file.
|
|
@@ -2695,28 +2763,28 @@ const WRITE_EXISTS_OUTPUT = "Error: File already exists";
|
|
|
2695
2763
|
const truncated = matches.length > limit;
|
|
2696
2764
|
const finalMatches = truncated ? matches.slice(0, limit) : matches;
|
|
2697
2765
|
if (finalMatches.length === 0) {
|
|
2698
|
-
return
|
|
2766
|
+
return 'No matches found';
|
|
2699
2767
|
}
|
|
2700
2768
|
const lines = [
|
|
2701
2769
|
`Found ${finalMatches.length} matches`
|
|
2702
2770
|
];
|
|
2703
|
-
let currentFile =
|
|
2771
|
+
let currentFile = '';
|
|
2704
2772
|
for (const match of finalMatches){
|
|
2705
2773
|
if (currentFile !== match.path) {
|
|
2706
|
-
if (currentFile !==
|
|
2707
|
-
lines.push(
|
|
2774
|
+
if (currentFile !== '') {
|
|
2775
|
+
lines.push('');
|
|
2708
2776
|
}
|
|
2709
2777
|
currentFile = match.path;
|
|
2710
2778
|
lines.push(`${match.path}:`);
|
|
2711
2779
|
}
|
|
2712
|
-
const text = match.text.length > MAX_GREP_LINE_LENGTH ? match.text.substring(0, MAX_GREP_LINE_LENGTH) +
|
|
2780
|
+
const text = match.text.length > MAX_GREP_LINE_LENGTH ? match.text.substring(0, MAX_GREP_LINE_LENGTH) + '...' : match.text;
|
|
2713
2781
|
lines.push(` Line ${match.line}: ${text}`);
|
|
2714
2782
|
}
|
|
2715
2783
|
if (truncated) {
|
|
2716
|
-
lines.push(
|
|
2717
|
-
lines.push(
|
|
2784
|
+
lines.push('');
|
|
2785
|
+
lines.push('(Results truncated. Consider using a more specific path or pattern.)');
|
|
2718
2786
|
}
|
|
2719
|
-
return lines.join(
|
|
2787
|
+
return lines.join('\n');
|
|
2720
2788
|
}
|
|
2721
2789
|
/**
|
|
2722
2790
|
* Node.js command template for glob operations.
|
|
@@ -3197,14 +3265,14 @@ console.log(count);
|
|
|
3197
3265
|
*/ function buildGrepCommand(pattern, searchPath, globPattern) {
|
|
3198
3266
|
const patternB64 = utf8ToBase64(pattern);
|
|
3199
3267
|
const pathB64 = utf8ToBase64(searchPath);
|
|
3200
|
-
const globB64 = globPattern ? utf8ToBase64(globPattern) :
|
|
3268
|
+
const globB64 = globPattern ? utf8ToBase64(globPattern) : '';
|
|
3201
3269
|
return `node -e "
|
|
3202
3270
|
const fs = require('fs');
|
|
3203
3271
|
const path = require('path');
|
|
3204
3272
|
|
|
3205
3273
|
const pattern = Buffer.from('${patternB64}', 'base64').toString('utf-8');
|
|
3206
3274
|
const searchPath = Buffer.from('${pathB64}', 'base64').toString('utf-8');
|
|
3207
|
-
const globPattern = ${globPattern ? `Buffer.from('${globB64}', 'base64').toString('utf-8')` :
|
|
3275
|
+
const globPattern = ${globPattern ? `Buffer.from('${globB64}', 'base64').toString('utf-8')` : 'null'};
|
|
3208
3276
|
|
|
3209
3277
|
let regex;
|
|
3210
3278
|
try {
|
|
@@ -3273,8 +3341,8 @@ try {
|
|
|
3273
3341
|
*
|
|
3274
3342
|
* Requires Node.js 20+ on the sandbox host.
|
|
3275
3343
|
*/ class BaseSandbox {
|
|
3276
|
-
async streamExecute(command, onLine) {
|
|
3277
|
-
const result = await this.execute(command);
|
|
3344
|
+
async streamExecute(command, onLine, options) {
|
|
3345
|
+
const result = await this.execute(command, options);
|
|
3278
3346
|
if (result.output) {
|
|
3279
3347
|
onLine(result.output);
|
|
3280
3348
|
}
|
|
@@ -3287,12 +3355,12 @@ try {
|
|
|
3287
3355
|
* @returns List of FileInfo objects for files and directories directly in the directory.
|
|
3288
3356
|
*/ async lsInfo(path) {
|
|
3289
3357
|
const command = buildLsCommand(path);
|
|
3290
|
-
const result = await this.execute(command);
|
|
3358
|
+
const result = await this.execute(command, DEFAULT_SANDBOX_FILE_OPERATION_EXECUTION_OPTIONS);
|
|
3291
3359
|
if (result.exitCode !== 0) {
|
|
3292
3360
|
return [];
|
|
3293
3361
|
}
|
|
3294
3362
|
const infos = [];
|
|
3295
|
-
const lines = result.output.trim().split(
|
|
3363
|
+
const lines = result.output.trim().split('\n').filter(Boolean);
|
|
3296
3364
|
for (const line of lines){
|
|
3297
3365
|
try {
|
|
3298
3366
|
const parsed = JSON.parse(line);
|
|
@@ -3318,16 +3386,16 @@ try {
|
|
|
3318
3386
|
* @returns Human-readable directory tree with indentation
|
|
3319
3387
|
*/ async listDir(dirPath, offset = 1, limit = 25, depth = 2) {
|
|
3320
3388
|
if (offset < 1) {
|
|
3321
|
-
return
|
|
3389
|
+
return 'Error: offset must be a 1-indexed entry number';
|
|
3322
3390
|
}
|
|
3323
3391
|
if (limit < 1) {
|
|
3324
|
-
return
|
|
3392
|
+
return 'Error: limit must be greater than zero';
|
|
3325
3393
|
}
|
|
3326
3394
|
if (depth < 1) {
|
|
3327
|
-
return
|
|
3395
|
+
return 'Error: depth must be greater than zero';
|
|
3328
3396
|
}
|
|
3329
3397
|
const command = buildListDirCommand(dirPath, offset, limit, depth);
|
|
3330
|
-
const result = await this.execute(command);
|
|
3398
|
+
const result = await this.execute(command, DEFAULT_SANDBOX_FILE_OPERATION_EXECUTION_OPTIONS);
|
|
3331
3399
|
if (result.exitCode !== 0) {
|
|
3332
3400
|
return result.output || `Error: Failed to list directory '${dirPath}'`;
|
|
3333
3401
|
}
|
|
@@ -3344,7 +3412,7 @@ try {
|
|
|
3344
3412
|
* @returns Formatted file content with line numbers, or error message
|
|
3345
3413
|
*/ async read(filePath, offset = 1, limit = 2000, mode = 'slice', indentation) {
|
|
3346
3414
|
const command = mode === 'indentation' ? buildIndentationReadCommand(filePath, offset, limit, indentation != null ? indentation : {}) : buildSliceReadCommand(filePath, offset, limit);
|
|
3347
|
-
const result = await this.execute(command);
|
|
3415
|
+
const result = await this.execute(command, DEFAULT_SANDBOX_FILE_OPERATION_EXECUTION_OPTIONS);
|
|
3348
3416
|
if (result.exitCode !== 0) {
|
|
3349
3417
|
return result.output || `Error: File '${filePath}' not found`;
|
|
3350
3418
|
}
|
|
@@ -3352,17 +3420,17 @@ try {
|
|
|
3352
3420
|
}
|
|
3353
3421
|
/**
|
|
3354
3422
|
* Structured search results or error string for invalid input.
|
|
3355
|
-
*/ async grepRaw(pattern, path =
|
|
3423
|
+
*/ async grepRaw(pattern, path = '/', include = null) {
|
|
3356
3424
|
const command = buildGrepCommand(pattern, path, include);
|
|
3357
|
-
const result = await this.execute(command);
|
|
3425
|
+
const result = await this.execute(command, DEFAULT_SANDBOX_FILE_SEARCH_EXECUTION_OPTIONS);
|
|
3358
3426
|
if (result.exitCode === 1) {
|
|
3359
3427
|
// Check if it's a regex error
|
|
3360
|
-
if (result.output.includes(
|
|
3428
|
+
if (result.output.includes('Invalid regex:')) {
|
|
3361
3429
|
return result.output.trim();
|
|
3362
3430
|
}
|
|
3363
3431
|
}
|
|
3364
3432
|
const matches = [];
|
|
3365
|
-
const lines = result.output.trim().split(
|
|
3433
|
+
const lines = result.output.trim().split('\n').filter(Boolean);
|
|
3366
3434
|
for (const line of lines){
|
|
3367
3435
|
try {
|
|
3368
3436
|
const parsed = JSON.parse(line);
|
|
@@ -3379,23 +3447,23 @@ try {
|
|
|
3379
3447
|
}
|
|
3380
3448
|
/**
|
|
3381
3449
|
* Search file contents for a regex pattern, returning human-readable output.
|
|
3382
|
-
*/ async grep(pattern, path =
|
|
3450
|
+
*/ async grep(pattern, path = '/', include = null) {
|
|
3383
3451
|
const result = await this.grepRaw(pattern, path, include);
|
|
3384
|
-
if (typeof result ===
|
|
3452
|
+
if (typeof result === 'string') {
|
|
3385
3453
|
return result;
|
|
3386
3454
|
}
|
|
3387
3455
|
if (result.length === 0) {
|
|
3388
|
-
return
|
|
3456
|
+
return 'No matches found';
|
|
3389
3457
|
}
|
|
3390
3458
|
return formatGrepOutput(result);
|
|
3391
3459
|
}
|
|
3392
3460
|
/**
|
|
3393
3461
|
* Structured glob matching returning FileInfo objects.
|
|
3394
|
-
*/ async globInfo(pattern, path =
|
|
3462
|
+
*/ async globInfo(pattern, path = '/') {
|
|
3395
3463
|
const command = buildGlobCommand(path, pattern);
|
|
3396
|
-
const result = await this.execute(command);
|
|
3464
|
+
const result = await this.execute(command, DEFAULT_SANDBOX_FILE_SEARCH_EXECUTION_OPTIONS);
|
|
3397
3465
|
const infos = [];
|
|
3398
|
-
const lines = result.output.trim().split(
|
|
3466
|
+
const lines = result.output.trim().split('\n').filter(Boolean);
|
|
3399
3467
|
for (const line of lines){
|
|
3400
3468
|
try {
|
|
3401
3469
|
const parsed = JSON.parse(line);
|
|
@@ -3413,10 +3481,10 @@ try {
|
|
|
3413
3481
|
}
|
|
3414
3482
|
/**
|
|
3415
3483
|
* Find files matching a glob pattern, returning human-readable output.
|
|
3416
|
-
*/ async glob(pattern, path =
|
|
3484
|
+
*/ async glob(pattern, path = '/') {
|
|
3417
3485
|
const files = await this.globInfo(pattern, path);
|
|
3418
3486
|
if (files.length === 0) {
|
|
3419
|
-
return
|
|
3487
|
+
return 'No files found';
|
|
3420
3488
|
}
|
|
3421
3489
|
return formatGlobOutput(files);
|
|
3422
3490
|
}
|
|
@@ -3424,9 +3492,9 @@ try {
|
|
|
3424
3492
|
* Create a new file with content.
|
|
3425
3493
|
*/ async write(filePath, content) {
|
|
3426
3494
|
const command = buildWriteCommand(filePath, content);
|
|
3427
|
-
const result = await this.execute(command);
|
|
3495
|
+
const result = await this.execute(command, DEFAULT_SANDBOX_FILE_OPERATION_EXECUTION_OPTIONS);
|
|
3428
3496
|
if (result.exitCode !== 0) {
|
|
3429
|
-
const output = (result.output ||
|
|
3497
|
+
const output = (result.output || '').trim();
|
|
3430
3498
|
if (output.includes(WRITE_EXISTS_OUTPUT)) {
|
|
3431
3499
|
return {
|
|
3432
3500
|
error: `Cannot write to ${filePath} because it already exists. Read and then make an edit, or write to a new path.`
|
|
@@ -3446,7 +3514,7 @@ try {
|
|
|
3446
3514
|
};
|
|
3447
3515
|
}
|
|
3448
3516
|
async writeViaUpload(filePath, content) {
|
|
3449
|
-
const existsCheck = await this.execute(buildExistsCommand(filePath));
|
|
3517
|
+
const existsCheck = await this.execute(buildExistsCommand(filePath), DEFAULT_SANDBOX_FILE_OPERATION_EXECUTION_OPTIONS);
|
|
3450
3518
|
if (existsCheck.exitCode === 0) {
|
|
3451
3519
|
return {
|
|
3452
3520
|
error: `Cannot write to ${filePath} because it already exists. Read and then make an edit, or write to a new path.`
|
|
@@ -3455,7 +3523,7 @@ try {
|
|
|
3455
3523
|
const uploads = await this.uploadFiles([
|
|
3456
3524
|
[
|
|
3457
3525
|
filePath,
|
|
3458
|
-
Buffer.from(content,
|
|
3526
|
+
Buffer.from(content, 'utf-8')
|
|
3459
3527
|
]
|
|
3460
3528
|
]);
|
|
3461
3529
|
const first = uploads[0];
|
|
@@ -3478,9 +3546,9 @@ try {
|
|
|
3478
3546
|
* Append content to a file. Creates the file if it doesn't exist.
|
|
3479
3547
|
*/ async append(filePath, content) {
|
|
3480
3548
|
const command = buildAppendCommand(filePath, content);
|
|
3481
|
-
const result = await this.execute(command);
|
|
3549
|
+
const result = await this.execute(command, DEFAULT_SANDBOX_FILE_OPERATION_EXECUTION_OPTIONS);
|
|
3482
3550
|
if (result.exitCode !== 0) {
|
|
3483
|
-
const output = (result.output ||
|
|
3551
|
+
const output = (result.output || '').trim();
|
|
3484
3552
|
return {
|
|
3485
3553
|
error: output ? `Failed to append to file '${filePath}': ${output}` : `Failed to append to file '${filePath}'.`
|
|
3486
3554
|
};
|
|
@@ -3494,7 +3562,7 @@ try {
|
|
|
3494
3562
|
* Edit a file by replacing string occurrences.
|
|
3495
3563
|
*/ async edit(filePath, oldString, newString, replaceAll = false) {
|
|
3496
3564
|
const command = buildEditCommand(filePath, oldString, newString, replaceAll);
|
|
3497
|
-
const result = await this.execute(command);
|
|
3565
|
+
const result = await this.execute(command, DEFAULT_SANDBOX_FILE_OPERATION_EXECUTION_OPTIONS);
|
|
3498
3566
|
switch(result.exitCode){
|
|
3499
3567
|
case 0:
|
|
3500
3568
|
{
|
|
@@ -3530,7 +3598,7 @@ try {
|
|
|
3530
3598
|
*/ async multiEdit(filePath, edits) {
|
|
3531
3599
|
if (!edits || edits.length === 0) {
|
|
3532
3600
|
return {
|
|
3533
|
-
error:
|
|
3601
|
+
error: 'No edits provided'
|
|
3534
3602
|
};
|
|
3535
3603
|
}
|
|
3536
3604
|
const results = [];
|
|
@@ -3617,11 +3685,25 @@ exports.CreateModelClientCommand = CreateModelClientCommand;
|
|
|
3617
3685
|
exports.CredentialsValidateFailedError = CredentialsValidateFailedError;
|
|
3618
3686
|
exports.DATASOURCE_STRATEGY = DATASOURCE_STRATEGY;
|
|
3619
3687
|
exports.DEFAULT_EXECUTION_CONFIG = DEFAULT_EXECUTION_CONFIG;
|
|
3688
|
+
exports.DEFAULT_SANDBOX_EXECUTION_MAX_OUTPUT_BYTES = DEFAULT_SANDBOX_EXECUTION_MAX_OUTPUT_BYTES;
|
|
3689
|
+
exports.DEFAULT_SANDBOX_FILE_OPERATION_EXECUTION_OPTIONS = DEFAULT_SANDBOX_FILE_OPERATION_EXECUTION_OPTIONS;
|
|
3690
|
+
exports.DEFAULT_SANDBOX_FILE_OPERATION_TIMEOUT_MS = DEFAULT_SANDBOX_FILE_OPERATION_TIMEOUT_MS;
|
|
3691
|
+
exports.DEFAULT_SANDBOX_FILE_OPERATION_TIMEOUT_SEC = DEFAULT_SANDBOX_FILE_OPERATION_TIMEOUT_SEC;
|
|
3692
|
+
exports.DEFAULT_SANDBOX_FILE_SEARCH_EXECUTION_OPTIONS = DEFAULT_SANDBOX_FILE_SEARCH_EXECUTION_OPTIONS;
|
|
3693
|
+
exports.DEFAULT_SANDBOX_FILE_SEARCH_TIMEOUT_MS = DEFAULT_SANDBOX_FILE_SEARCH_TIMEOUT_MS;
|
|
3694
|
+
exports.DEFAULT_SANDBOX_FILE_SEARCH_TIMEOUT_SEC = DEFAULT_SANDBOX_FILE_SEARCH_TIMEOUT_SEC;
|
|
3695
|
+
exports.DEFAULT_SANDBOX_SHELL_EXECUTION_OPTIONS = DEFAULT_SANDBOX_SHELL_EXECUTION_OPTIONS;
|
|
3696
|
+
exports.DEFAULT_SANDBOX_SHELL_TIMEOUT_MS = DEFAULT_SANDBOX_SHELL_TIMEOUT_MS;
|
|
3697
|
+
exports.DEFAULT_SANDBOX_SHELL_TIMEOUT_SEC = DEFAULT_SANDBOX_SHELL_TIMEOUT_SEC;
|
|
3620
3698
|
exports.DOCUMENT_SOURCE_STRATEGY = DOCUMENT_SOURCE_STRATEGY;
|
|
3621
3699
|
exports.DOCUMENT_TRANSFORMER_STRATEGY = DOCUMENT_TRANSFORMER_STRATEGY;
|
|
3622
3700
|
exports.DataSourceStrategy = DataSourceStrategy;
|
|
3623
3701
|
exports.DocumentSourceStrategy = DocumentSourceStrategy;
|
|
3624
3702
|
exports.DocumentTransformerStrategy = DocumentTransformerStrategy;
|
|
3703
|
+
exports.FILE_STORAGE_PROVIDER = FILE_STORAGE_PROVIDER;
|
|
3704
|
+
exports.FILE_UPLOAD_TARGET_STRATEGY = FILE_UPLOAD_TARGET_STRATEGY;
|
|
3705
|
+
exports.FileStorageProvider = FileStorageProvider;
|
|
3706
|
+
exports.FileUploadTargetStrategy = FileUploadTargetStrategy;
|
|
3625
3707
|
exports.GLOBAL_ORGANIZATION_SCOPE = GLOBAL_ORGANIZATION_SCOPE;
|
|
3626
3708
|
exports.HANDOFF_PERMISSION_SERVICE_TOKEN = HANDOFF_PERMISSION_SERVICE_TOKEN;
|
|
3627
3709
|
exports.HANDOFF_PROCESSOR_STRATEGY = HANDOFF_PROCESSOR_STRATEGY;
|
|
@@ -3641,6 +3723,7 @@ exports.LargeLanguageModel = LargeLanguageModel;
|
|
|
3641
3723
|
exports.ORGANIZATION_METADATA_KEY = ORGANIZATION_METADATA_KEY;
|
|
3642
3724
|
exports.OpenAICompatibleReranker = OpenAICompatibleReranker;
|
|
3643
3725
|
exports.PERMISSION_OPERATION_METADATA_KEY = PERMISSION_OPERATION_METADATA_KEY;
|
|
3726
|
+
exports.PLUGIN_CONFIG_RESOLVER_TOKEN = PLUGIN_CONFIG_RESOLVER_TOKEN;
|
|
3644
3727
|
exports.PLUGIN_METADATA = PLUGIN_METADATA;
|
|
3645
3728
|
exports.PLUGIN_METADATA_KEY = PLUGIN_METADATA_KEY;
|
|
3646
3729
|
exports.PROVIDE_AI_MODEL_LLM = PROVIDE_AI_MODEL_LLM;
|
|
@@ -3655,6 +3738,7 @@ exports.RequirePermissionOperation = RequirePermissionOperation;
|
|
|
3655
3738
|
exports.RerankModel = RerankModel;
|
|
3656
3739
|
exports.RetrieverStrategy = RetrieverStrategy;
|
|
3657
3740
|
exports.SANDBOX_PROVIDER = SANDBOX_PROVIDER;
|
|
3741
|
+
exports.SANDBOX_SHELL_TIMEOUT_LIMITS_SEC = SANDBOX_SHELL_TIMEOUT_LIMITS_SEC;
|
|
3658
3742
|
exports.STRATEGY_META_KEY = STRATEGY_META_KEY;
|
|
3659
3743
|
exports.SandboxProviderStrategy = SandboxProviderStrategy;
|
|
3660
3744
|
exports.Speech2TextChatModel = Speech2TextChatModel;
|
|
@@ -3676,6 +3760,8 @@ exports.WrapWorkflowNodeExecutionCommand = WrapWorkflowNodeExecutionCommand;
|
|
|
3676
3760
|
exports.XpFileSystem = XpFileSystem;
|
|
3677
3761
|
exports.XpertServerPlugin = XpertServerPlugin;
|
|
3678
3762
|
exports.als = als;
|
|
3763
|
+
exports.appendSandboxMessage = appendSandboxMessage;
|
|
3764
|
+
exports.buildSandboxTimeoutMessage = buildSandboxTimeoutMessage;
|
|
3679
3765
|
exports.calcTokenUsage = calcTokenUsage;
|
|
3680
3766
|
exports.chunkText = chunkText;
|
|
3681
3767
|
exports.countTokensSafe = countTokensSafe;
|
|
@@ -3684,6 +3770,7 @@ exports.createPluginLogger = createPluginLogger;
|
|
|
3684
3770
|
exports.defineAgentMessageType = defineAgentMessageType;
|
|
3685
3771
|
exports.defineChannelMessageType = defineChannelMessageType;
|
|
3686
3772
|
exports.downloadRemoteFile = downloadRemoteFile;
|
|
3773
|
+
exports.formatSandboxTimeout = formatSandboxTimeout;
|
|
3687
3774
|
exports.getErrorMessage = getErrorMessage;
|
|
3688
3775
|
exports.getModelContextSize = getModelContextSize;
|
|
3689
3776
|
exports.getPermissionOperationMetadata = getPermissionOperationMetadata;
|
|
@@ -3698,5 +3785,7 @@ exports.loadYamlFile = loadYamlFile;
|
|
|
3698
3785
|
exports.mergeCredentials = mergeCredentials;
|
|
3699
3786
|
exports.mergeParentChildChunks = mergeParentChildChunks;
|
|
3700
3787
|
exports.normalizeContextSize = normalizeContextSize;
|
|
3788
|
+
exports.resolveSandboxExecutionOptions = resolveSandboxExecutionOptions;
|
|
3701
3789
|
exports.runWithRequestContext = runWithRequestContext;
|
|
3790
|
+
exports.secondsToMilliseconds = secondsToMilliseconds;
|
|
3702
3791
|
exports.sumTokenUsage = sumTokenUsage;
|
package/index.esm.js
CHANGED
|
@@ -936,6 +936,8 @@ BuiltinToolset.provider = '';
|
|
|
936
936
|
}
|
|
937
937
|
}
|
|
938
938
|
|
|
939
|
+
const PLUGIN_CONFIG_RESOLVER_TOKEN = 'XPERT_PLUGIN_CONFIG_RESOLVER';
|
|
940
|
+
|
|
939
941
|
/**
|
|
940
942
|
* System token for resolving integration read service from plugin context.
|
|
941
943
|
*/ const INTEGRATION_PERMISSION_SERVICE_TOKEN = 'XPERT_PLUGIN_INTEGRATION_PERMISSION_SERVICE';
|
|
@@ -2615,34 +2617,100 @@ class CancelConversationCommand {
|
|
|
2615
2617
|
}
|
|
2616
2618
|
CancelConversationCommand.type = '[Chat Conversation] Cancel';
|
|
2617
2619
|
|
|
2620
|
+
const FILE_STORAGE_PROVIDER = 'FILE_STORAGE_PROVIDER';
|
|
2621
|
+
const FileStorageProvider = (provider)=>applyDecorators(SetMetadata(FILE_STORAGE_PROVIDER, provider), SetMetadata(STRATEGY_META_KEY, FILE_STORAGE_PROVIDER));
|
|
2622
|
+
|
|
2623
|
+
let FileStorageProviderRegistry = class FileStorageProviderRegistry extends BaseStrategyRegistry {
|
|
2624
|
+
constructor(discoveryService, reflector){
|
|
2625
|
+
super(FILE_STORAGE_PROVIDER, discoveryService, reflector);
|
|
2626
|
+
}
|
|
2627
|
+
};
|
|
2628
|
+
FileStorageProviderRegistry = __decorate([
|
|
2629
|
+
Injectable(),
|
|
2630
|
+
__metadata("design:type", Function),
|
|
2631
|
+
__metadata("design:paramtypes", [
|
|
2632
|
+
typeof DiscoveryService === "undefined" ? Object : DiscoveryService,
|
|
2633
|
+
typeof Reflector === "undefined" ? Object : Reflector
|
|
2634
|
+
])
|
|
2635
|
+
], FileStorageProviderRegistry);
|
|
2636
|
+
|
|
2637
|
+
const FILE_UPLOAD_TARGET_STRATEGY = 'FILE_UPLOAD_TARGET_STRATEGY';
|
|
2638
|
+
const FileUploadTargetStrategy = (type)=>applyDecorators(SetMetadata(FILE_UPLOAD_TARGET_STRATEGY, type), SetMetadata(STRATEGY_META_KEY, FILE_UPLOAD_TARGET_STRATEGY));
|
|
2639
|
+
|
|
2640
|
+
let FileUploadTargetRegistry = class FileUploadTargetRegistry extends BaseStrategyRegistry {
|
|
2641
|
+
constructor(discoveryService, reflector){
|
|
2642
|
+
super(FILE_UPLOAD_TARGET_STRATEGY, discoveryService, reflector);
|
|
2643
|
+
}
|
|
2644
|
+
};
|
|
2645
|
+
FileUploadTargetRegistry = __decorate([
|
|
2646
|
+
Injectable(),
|
|
2647
|
+
__metadata("design:type", Function),
|
|
2648
|
+
__metadata("design:paramtypes", [
|
|
2649
|
+
typeof DiscoveryService === "undefined" ? Object : DiscoveryService,
|
|
2650
|
+
typeof Reflector === "undefined" ? Object : Reflector
|
|
2651
|
+
])
|
|
2652
|
+
], FileUploadTargetRegistry);
|
|
2653
|
+
|
|
2654
|
+
const SANDBOX_SHELL_TIMEOUT_LIMITS_SEC = {
|
|
2655
|
+
min: 1,
|
|
2656
|
+
max: 3600
|
|
2657
|
+
};
|
|
2658
|
+
const DEFAULT_SANDBOX_SHELL_TIMEOUT_SEC = 600;
|
|
2659
|
+
const DEFAULT_SANDBOX_FILE_SEARCH_TIMEOUT_SEC = 120;
|
|
2660
|
+
const DEFAULT_SANDBOX_FILE_OPERATION_TIMEOUT_SEC = 120;
|
|
2661
|
+
const DEFAULT_SANDBOX_SHELL_TIMEOUT_MS = DEFAULT_SANDBOX_SHELL_TIMEOUT_SEC * 1000;
|
|
2662
|
+
const DEFAULT_SANDBOX_FILE_SEARCH_TIMEOUT_MS = DEFAULT_SANDBOX_FILE_SEARCH_TIMEOUT_SEC * 1000;
|
|
2663
|
+
const DEFAULT_SANDBOX_FILE_OPERATION_TIMEOUT_MS = DEFAULT_SANDBOX_FILE_OPERATION_TIMEOUT_SEC * 1000;
|
|
2664
|
+
const DEFAULT_SANDBOX_EXECUTION_MAX_OUTPUT_BYTES = 1024 * 1024;
|
|
2665
|
+
const DEFAULT_SANDBOX_SHELL_EXECUTION_OPTIONS = {
|
|
2666
|
+
timeoutMs: DEFAULT_SANDBOX_SHELL_TIMEOUT_MS,
|
|
2667
|
+
maxOutputBytes: DEFAULT_SANDBOX_EXECUTION_MAX_OUTPUT_BYTES
|
|
2668
|
+
};
|
|
2669
|
+
const DEFAULT_SANDBOX_FILE_SEARCH_EXECUTION_OPTIONS = {
|
|
2670
|
+
timeoutMs: DEFAULT_SANDBOX_FILE_SEARCH_TIMEOUT_MS,
|
|
2671
|
+
maxOutputBytes: DEFAULT_SANDBOX_EXECUTION_MAX_OUTPUT_BYTES
|
|
2672
|
+
};
|
|
2673
|
+
const DEFAULT_SANDBOX_FILE_OPERATION_EXECUTION_OPTIONS = {
|
|
2674
|
+
timeoutMs: DEFAULT_SANDBOX_FILE_OPERATION_TIMEOUT_MS,
|
|
2675
|
+
maxOutputBytes: DEFAULT_SANDBOX_EXECUTION_MAX_OUTPUT_BYTES
|
|
2676
|
+
};
|
|
2677
|
+
function secondsToMilliseconds(seconds) {
|
|
2678
|
+
return Math.trunc(seconds * 1000);
|
|
2679
|
+
}
|
|
2680
|
+
function formatSandboxTimeout(timeoutMs) {
|
|
2681
|
+
const timeoutSeconds = timeoutMs / 1000;
|
|
2682
|
+
const secondsLabel = Number.isInteger(timeoutSeconds) ? String(timeoutSeconds) : Number(timeoutSeconds.toFixed(3)).toString();
|
|
2683
|
+
return `${secondsLabel}s (${timeoutMs}ms)`;
|
|
2684
|
+
}
|
|
2685
|
+
function buildSandboxTimeoutMessage(subject, timeoutMs) {
|
|
2686
|
+
return `${subject} timed out after ${formatSandboxTimeout(timeoutMs)}`;
|
|
2687
|
+
}
|
|
2688
|
+
function appendSandboxMessage(output, message) {
|
|
2689
|
+
return output ? `${output}\n${message}` : message;
|
|
2690
|
+
}
|
|
2691
|
+
function resolveSandboxExecutionOptions(options, defaults = DEFAULT_SANDBOX_SHELL_EXECUTION_OPTIONS) {
|
|
2692
|
+
const timeoutMs = typeof (options == null ? void 0 : options.timeoutMs) === 'number' && Number.isFinite(options.timeoutMs) && options.timeoutMs > 0 ? Math.trunc(options.timeoutMs) : typeof defaults.timeoutMs === 'number' && Number.isFinite(defaults.timeoutMs) && defaults.timeoutMs > 0 ? Math.trunc(defaults.timeoutMs) : DEFAULT_SANDBOX_SHELL_TIMEOUT_MS;
|
|
2693
|
+
const maxOutputBytes = typeof (options == null ? void 0 : options.maxOutputBytes) === 'number' && Number.isFinite(options.maxOutputBytes) && options.maxOutputBytes > 0 ? Math.trunc(options.maxOutputBytes) : typeof defaults.maxOutputBytes === 'number' && Number.isFinite(defaults.maxOutputBytes) && defaults.maxOutputBytes > 0 ? Math.trunc(defaults.maxOutputBytes) : DEFAULT_SANDBOX_EXECUTION_MAX_OUTPUT_BYTES;
|
|
2694
|
+
return {
|
|
2695
|
+
timeoutMs,
|
|
2696
|
+
maxOutputBytes
|
|
2697
|
+
};
|
|
2698
|
+
}
|
|
2699
|
+
|
|
2618
2700
|
/**
|
|
2619
|
-
* Protocol definition for pluggable memory backends.
|
|
2620
|
-
*
|
|
2621
|
-
* This module defines the BackendProtocol that all backend implementations
|
|
2622
|
-
* must follow. Backends can store files in different locations (state, filesystem,
|
|
2623
|
-
* database, etc.) and provide a uniform interface for file operations.
|
|
2624
|
-
*/ /**
|
|
2625
2701
|
* Type guard to check if a backend supports execution.
|
|
2626
2702
|
*
|
|
2627
2703
|
* @param backend - Backend instance to check
|
|
2628
2704
|
* @returns True if the backend implements SandboxBackendProtocol
|
|
2629
2705
|
*/ function isSandboxBackend(backend) {
|
|
2630
|
-
return typeof backend.execute ===
|
|
2706
|
+
return typeof backend.execute === 'function' && typeof backend.id === 'string';
|
|
2631
2707
|
}
|
|
2632
2708
|
|
|
2633
|
-
|
|
2634
|
-
* BaseSandbox: Abstract base class for sandbox backends with command execution.
|
|
2635
|
-
*
|
|
2636
|
-
* This class provides default implementations for all SandboxBackendProtocol
|
|
2637
|
-
* methods using shell commands executed via execute(). Concrete implementations
|
|
2638
|
-
* only need to implement the execute() method.
|
|
2639
|
-
*
|
|
2640
|
-
* Requires Node.js 20+ on the sandbox host.
|
|
2641
|
-
*/ const MAX_LINE_LENGTH = 500;
|
|
2709
|
+
const MAX_LINE_LENGTH = 500;
|
|
2642
2710
|
const MAX_GREP_LINE_LENGTH = 2000;
|
|
2643
2711
|
const GREP_RESULT_LIMIT = 100;
|
|
2644
2712
|
const GLOB_RESULT_LIMIT = 100;
|
|
2645
|
-
const WRITE_EXISTS_OUTPUT =
|
|
2713
|
+
const WRITE_EXISTS_OUTPUT = 'Error: File already exists';
|
|
2646
2714
|
/**
|
|
2647
2715
|
* UTF-8 safe Base64 encoding function.
|
|
2648
2716
|
* Replaces btoa() which only supports Latin1 characters.
|
|
@@ -2656,17 +2724,17 @@ const WRITE_EXISTS_OUTPUT = "Error: File already exists";
|
|
|
2656
2724
|
const truncated = files.length > limit;
|
|
2657
2725
|
const finalFiles = truncated ? files.slice(0, limit) : files;
|
|
2658
2726
|
if (finalFiles.length === 0) {
|
|
2659
|
-
return
|
|
2727
|
+
return 'No files found';
|
|
2660
2728
|
}
|
|
2661
2729
|
const lines = [];
|
|
2662
2730
|
for (const file of finalFiles){
|
|
2663
2731
|
lines.push(file.path);
|
|
2664
2732
|
}
|
|
2665
2733
|
if (truncated) {
|
|
2666
|
-
lines.push(
|
|
2667
|
-
lines.push(
|
|
2734
|
+
lines.push('');
|
|
2735
|
+
lines.push('(Results truncated. Consider using a more specific path or pattern.)');
|
|
2668
2736
|
}
|
|
2669
|
-
return lines.join(
|
|
2737
|
+
return lines.join('\n');
|
|
2670
2738
|
}
|
|
2671
2739
|
/**
|
|
2672
2740
|
* Format grep matches into human-readable output grouped by file.
|
|
@@ -2675,28 +2743,28 @@ const WRITE_EXISTS_OUTPUT = "Error: File already exists";
|
|
|
2675
2743
|
const truncated = matches.length > limit;
|
|
2676
2744
|
const finalMatches = truncated ? matches.slice(0, limit) : matches;
|
|
2677
2745
|
if (finalMatches.length === 0) {
|
|
2678
|
-
return
|
|
2746
|
+
return 'No matches found';
|
|
2679
2747
|
}
|
|
2680
2748
|
const lines = [
|
|
2681
2749
|
`Found ${finalMatches.length} matches`
|
|
2682
2750
|
];
|
|
2683
|
-
let currentFile =
|
|
2751
|
+
let currentFile = '';
|
|
2684
2752
|
for (const match of finalMatches){
|
|
2685
2753
|
if (currentFile !== match.path) {
|
|
2686
|
-
if (currentFile !==
|
|
2687
|
-
lines.push(
|
|
2754
|
+
if (currentFile !== '') {
|
|
2755
|
+
lines.push('');
|
|
2688
2756
|
}
|
|
2689
2757
|
currentFile = match.path;
|
|
2690
2758
|
lines.push(`${match.path}:`);
|
|
2691
2759
|
}
|
|
2692
|
-
const text = match.text.length > MAX_GREP_LINE_LENGTH ? match.text.substring(0, MAX_GREP_LINE_LENGTH) +
|
|
2760
|
+
const text = match.text.length > MAX_GREP_LINE_LENGTH ? match.text.substring(0, MAX_GREP_LINE_LENGTH) + '...' : match.text;
|
|
2693
2761
|
lines.push(` Line ${match.line}: ${text}`);
|
|
2694
2762
|
}
|
|
2695
2763
|
if (truncated) {
|
|
2696
|
-
lines.push(
|
|
2697
|
-
lines.push(
|
|
2764
|
+
lines.push('');
|
|
2765
|
+
lines.push('(Results truncated. Consider using a more specific path or pattern.)');
|
|
2698
2766
|
}
|
|
2699
|
-
return lines.join(
|
|
2767
|
+
return lines.join('\n');
|
|
2700
2768
|
}
|
|
2701
2769
|
/**
|
|
2702
2770
|
* Node.js command template for glob operations.
|
|
@@ -3177,14 +3245,14 @@ console.log(count);
|
|
|
3177
3245
|
*/ function buildGrepCommand(pattern, searchPath, globPattern) {
|
|
3178
3246
|
const patternB64 = utf8ToBase64(pattern);
|
|
3179
3247
|
const pathB64 = utf8ToBase64(searchPath);
|
|
3180
|
-
const globB64 = globPattern ? utf8ToBase64(globPattern) :
|
|
3248
|
+
const globB64 = globPattern ? utf8ToBase64(globPattern) : '';
|
|
3181
3249
|
return `node -e "
|
|
3182
3250
|
const fs = require('fs');
|
|
3183
3251
|
const path = require('path');
|
|
3184
3252
|
|
|
3185
3253
|
const pattern = Buffer.from('${patternB64}', 'base64').toString('utf-8');
|
|
3186
3254
|
const searchPath = Buffer.from('${pathB64}', 'base64').toString('utf-8');
|
|
3187
|
-
const globPattern = ${globPattern ? `Buffer.from('${globB64}', 'base64').toString('utf-8')` :
|
|
3255
|
+
const globPattern = ${globPattern ? `Buffer.from('${globB64}', 'base64').toString('utf-8')` : 'null'};
|
|
3188
3256
|
|
|
3189
3257
|
let regex;
|
|
3190
3258
|
try {
|
|
@@ -3253,8 +3321,8 @@ try {
|
|
|
3253
3321
|
*
|
|
3254
3322
|
* Requires Node.js 20+ on the sandbox host.
|
|
3255
3323
|
*/ class BaseSandbox {
|
|
3256
|
-
async streamExecute(command, onLine) {
|
|
3257
|
-
const result = await this.execute(command);
|
|
3324
|
+
async streamExecute(command, onLine, options) {
|
|
3325
|
+
const result = await this.execute(command, options);
|
|
3258
3326
|
if (result.output) {
|
|
3259
3327
|
onLine(result.output);
|
|
3260
3328
|
}
|
|
@@ -3267,12 +3335,12 @@ try {
|
|
|
3267
3335
|
* @returns List of FileInfo objects for files and directories directly in the directory.
|
|
3268
3336
|
*/ async lsInfo(path) {
|
|
3269
3337
|
const command = buildLsCommand(path);
|
|
3270
|
-
const result = await this.execute(command);
|
|
3338
|
+
const result = await this.execute(command, DEFAULT_SANDBOX_FILE_OPERATION_EXECUTION_OPTIONS);
|
|
3271
3339
|
if (result.exitCode !== 0) {
|
|
3272
3340
|
return [];
|
|
3273
3341
|
}
|
|
3274
3342
|
const infos = [];
|
|
3275
|
-
const lines = result.output.trim().split(
|
|
3343
|
+
const lines = result.output.trim().split('\n').filter(Boolean);
|
|
3276
3344
|
for (const line of lines){
|
|
3277
3345
|
try {
|
|
3278
3346
|
const parsed = JSON.parse(line);
|
|
@@ -3298,16 +3366,16 @@ try {
|
|
|
3298
3366
|
* @returns Human-readable directory tree with indentation
|
|
3299
3367
|
*/ async listDir(dirPath, offset = 1, limit = 25, depth = 2) {
|
|
3300
3368
|
if (offset < 1) {
|
|
3301
|
-
return
|
|
3369
|
+
return 'Error: offset must be a 1-indexed entry number';
|
|
3302
3370
|
}
|
|
3303
3371
|
if (limit < 1) {
|
|
3304
|
-
return
|
|
3372
|
+
return 'Error: limit must be greater than zero';
|
|
3305
3373
|
}
|
|
3306
3374
|
if (depth < 1) {
|
|
3307
|
-
return
|
|
3375
|
+
return 'Error: depth must be greater than zero';
|
|
3308
3376
|
}
|
|
3309
3377
|
const command = buildListDirCommand(dirPath, offset, limit, depth);
|
|
3310
|
-
const result = await this.execute(command);
|
|
3378
|
+
const result = await this.execute(command, DEFAULT_SANDBOX_FILE_OPERATION_EXECUTION_OPTIONS);
|
|
3311
3379
|
if (result.exitCode !== 0) {
|
|
3312
3380
|
return result.output || `Error: Failed to list directory '${dirPath}'`;
|
|
3313
3381
|
}
|
|
@@ -3324,7 +3392,7 @@ try {
|
|
|
3324
3392
|
* @returns Formatted file content with line numbers, or error message
|
|
3325
3393
|
*/ async read(filePath, offset = 1, limit = 2000, mode = 'slice', indentation) {
|
|
3326
3394
|
const command = mode === 'indentation' ? buildIndentationReadCommand(filePath, offset, limit, indentation != null ? indentation : {}) : buildSliceReadCommand(filePath, offset, limit);
|
|
3327
|
-
const result = await this.execute(command);
|
|
3395
|
+
const result = await this.execute(command, DEFAULT_SANDBOX_FILE_OPERATION_EXECUTION_OPTIONS);
|
|
3328
3396
|
if (result.exitCode !== 0) {
|
|
3329
3397
|
return result.output || `Error: File '${filePath}' not found`;
|
|
3330
3398
|
}
|
|
@@ -3332,17 +3400,17 @@ try {
|
|
|
3332
3400
|
}
|
|
3333
3401
|
/**
|
|
3334
3402
|
* Structured search results or error string for invalid input.
|
|
3335
|
-
*/ async grepRaw(pattern, path =
|
|
3403
|
+
*/ async grepRaw(pattern, path = '/', include = null) {
|
|
3336
3404
|
const command = buildGrepCommand(pattern, path, include);
|
|
3337
|
-
const result = await this.execute(command);
|
|
3405
|
+
const result = await this.execute(command, DEFAULT_SANDBOX_FILE_SEARCH_EXECUTION_OPTIONS);
|
|
3338
3406
|
if (result.exitCode === 1) {
|
|
3339
3407
|
// Check if it's a regex error
|
|
3340
|
-
if (result.output.includes(
|
|
3408
|
+
if (result.output.includes('Invalid regex:')) {
|
|
3341
3409
|
return result.output.trim();
|
|
3342
3410
|
}
|
|
3343
3411
|
}
|
|
3344
3412
|
const matches = [];
|
|
3345
|
-
const lines = result.output.trim().split(
|
|
3413
|
+
const lines = result.output.trim().split('\n').filter(Boolean);
|
|
3346
3414
|
for (const line of lines){
|
|
3347
3415
|
try {
|
|
3348
3416
|
const parsed = JSON.parse(line);
|
|
@@ -3359,23 +3427,23 @@ try {
|
|
|
3359
3427
|
}
|
|
3360
3428
|
/**
|
|
3361
3429
|
* Search file contents for a regex pattern, returning human-readable output.
|
|
3362
|
-
*/ async grep(pattern, path =
|
|
3430
|
+
*/ async grep(pattern, path = '/', include = null) {
|
|
3363
3431
|
const result = await this.grepRaw(pattern, path, include);
|
|
3364
|
-
if (typeof result ===
|
|
3432
|
+
if (typeof result === 'string') {
|
|
3365
3433
|
return result;
|
|
3366
3434
|
}
|
|
3367
3435
|
if (result.length === 0) {
|
|
3368
|
-
return
|
|
3436
|
+
return 'No matches found';
|
|
3369
3437
|
}
|
|
3370
3438
|
return formatGrepOutput(result);
|
|
3371
3439
|
}
|
|
3372
3440
|
/**
|
|
3373
3441
|
* Structured glob matching returning FileInfo objects.
|
|
3374
|
-
*/ async globInfo(pattern, path =
|
|
3442
|
+
*/ async globInfo(pattern, path = '/') {
|
|
3375
3443
|
const command = buildGlobCommand(path, pattern);
|
|
3376
|
-
const result = await this.execute(command);
|
|
3444
|
+
const result = await this.execute(command, DEFAULT_SANDBOX_FILE_SEARCH_EXECUTION_OPTIONS);
|
|
3377
3445
|
const infos = [];
|
|
3378
|
-
const lines = result.output.trim().split(
|
|
3446
|
+
const lines = result.output.trim().split('\n').filter(Boolean);
|
|
3379
3447
|
for (const line of lines){
|
|
3380
3448
|
try {
|
|
3381
3449
|
const parsed = JSON.parse(line);
|
|
@@ -3393,10 +3461,10 @@ try {
|
|
|
3393
3461
|
}
|
|
3394
3462
|
/**
|
|
3395
3463
|
* Find files matching a glob pattern, returning human-readable output.
|
|
3396
|
-
*/ async glob(pattern, path =
|
|
3464
|
+
*/ async glob(pattern, path = '/') {
|
|
3397
3465
|
const files = await this.globInfo(pattern, path);
|
|
3398
3466
|
if (files.length === 0) {
|
|
3399
|
-
return
|
|
3467
|
+
return 'No files found';
|
|
3400
3468
|
}
|
|
3401
3469
|
return formatGlobOutput(files);
|
|
3402
3470
|
}
|
|
@@ -3404,9 +3472,9 @@ try {
|
|
|
3404
3472
|
* Create a new file with content.
|
|
3405
3473
|
*/ async write(filePath, content) {
|
|
3406
3474
|
const command = buildWriteCommand(filePath, content);
|
|
3407
|
-
const result = await this.execute(command);
|
|
3475
|
+
const result = await this.execute(command, DEFAULT_SANDBOX_FILE_OPERATION_EXECUTION_OPTIONS);
|
|
3408
3476
|
if (result.exitCode !== 0) {
|
|
3409
|
-
const output = (result.output ||
|
|
3477
|
+
const output = (result.output || '').trim();
|
|
3410
3478
|
if (output.includes(WRITE_EXISTS_OUTPUT)) {
|
|
3411
3479
|
return {
|
|
3412
3480
|
error: `Cannot write to ${filePath} because it already exists. Read and then make an edit, or write to a new path.`
|
|
@@ -3426,7 +3494,7 @@ try {
|
|
|
3426
3494
|
};
|
|
3427
3495
|
}
|
|
3428
3496
|
async writeViaUpload(filePath, content) {
|
|
3429
|
-
const existsCheck = await this.execute(buildExistsCommand(filePath));
|
|
3497
|
+
const existsCheck = await this.execute(buildExistsCommand(filePath), DEFAULT_SANDBOX_FILE_OPERATION_EXECUTION_OPTIONS);
|
|
3430
3498
|
if (existsCheck.exitCode === 0) {
|
|
3431
3499
|
return {
|
|
3432
3500
|
error: `Cannot write to ${filePath} because it already exists. Read and then make an edit, or write to a new path.`
|
|
@@ -3435,7 +3503,7 @@ try {
|
|
|
3435
3503
|
const uploads = await this.uploadFiles([
|
|
3436
3504
|
[
|
|
3437
3505
|
filePath,
|
|
3438
|
-
Buffer.from(content,
|
|
3506
|
+
Buffer.from(content, 'utf-8')
|
|
3439
3507
|
]
|
|
3440
3508
|
]);
|
|
3441
3509
|
const first = uploads[0];
|
|
@@ -3458,9 +3526,9 @@ try {
|
|
|
3458
3526
|
* Append content to a file. Creates the file if it doesn't exist.
|
|
3459
3527
|
*/ async append(filePath, content) {
|
|
3460
3528
|
const command = buildAppendCommand(filePath, content);
|
|
3461
|
-
const result = await this.execute(command);
|
|
3529
|
+
const result = await this.execute(command, DEFAULT_SANDBOX_FILE_OPERATION_EXECUTION_OPTIONS);
|
|
3462
3530
|
if (result.exitCode !== 0) {
|
|
3463
|
-
const output = (result.output ||
|
|
3531
|
+
const output = (result.output || '').trim();
|
|
3464
3532
|
return {
|
|
3465
3533
|
error: output ? `Failed to append to file '${filePath}': ${output}` : `Failed to append to file '${filePath}'.`
|
|
3466
3534
|
};
|
|
@@ -3474,7 +3542,7 @@ try {
|
|
|
3474
3542
|
* Edit a file by replacing string occurrences.
|
|
3475
3543
|
*/ async edit(filePath, oldString, newString, replaceAll = false) {
|
|
3476
3544
|
const command = buildEditCommand(filePath, oldString, newString, replaceAll);
|
|
3477
|
-
const result = await this.execute(command);
|
|
3545
|
+
const result = await this.execute(command, DEFAULT_SANDBOX_FILE_OPERATION_EXECUTION_OPTIONS);
|
|
3478
3546
|
switch(result.exitCode){
|
|
3479
3547
|
case 0:
|
|
3480
3548
|
{
|
|
@@ -3510,7 +3578,7 @@ try {
|
|
|
3510
3578
|
*/ async multiEdit(filePath, edits) {
|
|
3511
3579
|
if (!edits || edits.length === 0) {
|
|
3512
3580
|
return {
|
|
3513
|
-
error:
|
|
3581
|
+
error: 'No edits provided'
|
|
3514
3582
|
};
|
|
3515
3583
|
}
|
|
3516
3584
|
const results = [];
|
|
@@ -3554,4 +3622,4 @@ SandboxProviderRegistry = __decorate([
|
|
|
3554
3622
|
])
|
|
3555
3623
|
], SandboxProviderRegistry);
|
|
3556
3624
|
|
|
3557
|
-
export { AGENT_CHAT_DISPATCH_MESSAGE_TYPE, AGENT_MIDDLEWARE_STRATEGY, AIModelProviderNotFoundException, AIModelProviderRegistry, AIModelProviderStrategy, AI_MODEL_PROVIDER, ANALYTICS_PERMISSION_SERVICE_TOKEN, AdapterDataSourceStrategy, AgentMiddlewareRegistry, AgentMiddlewareStrategy, AiModelNotFoundException, BaseHTTPQueryRunner, BaseQueryRunner, BaseSQLQueryRunner, BaseSandbox, BaseStrategyRegistry, BaseTool, BaseToolset, BuiltinToolset, CHAT_CHANNEL, CHAT_CHANNEL_TEXT_LIMITS, CancelConversationCommand, ChatChannel, ChatChannelRegistry, ChatOAICompatReasoningModel, CommonParameterRules, CreateModelClientCommand, CredentialsValidateFailedError, DATASOURCE_STRATEGY, DBCreateTableMode, DBProtocolEnum, DBSyntaxEnum, DBTableAction, DBTableDataAction, DEFAULT_EXECUTION_CONFIG, DOCUMENT_SOURCE_STRATEGY, DOCUMENT_TRANSFORMER_STRATEGY, DataSourceStrategy, DataSourceStrategyRegistry, DocumentSourceRegistry, DocumentSourceStrategy, DocumentTransformerRegistry, DocumentTransformerStrategy, GLOBAL_ORGANIZATION_SCOPE, HANDOFF_PERMISSION_SERVICE_TOKEN, HANDOFF_PROCESSOR_STRATEGY, HANDOFF_QUEUE_SERVICE_TOKEN, HandoffProcessorRegistry, HandoffProcessorStrategy, IMAGE_UNDERSTANDING_STRATEGY, INTEGRATION_PERMISSION_SERVICE_TOKEN, INTEGRATION_STRATEGY, ImageUnderstandingRegistry, ImageUnderstandingStrategy, IntegrationStrategyKey, IntegrationStrategyRegistry, JUMP_TO_TARGETS, JsonSchemaValidator, KNOWLEDGE_STRATEGY, KnowledgeStrategyKey, KnowledgeStrategyRegistry, LLMUsage, LargeLanguageModel, ModelProvider, ORGANIZATION_METADATA_KEY, OpenAICompatibleReranker, PERMISSION_OPERATION_METADATA_KEY, PLUGIN_METADATA, PLUGIN_METADATA_KEY, PROVIDE_AI_MODEL_LLM, PROVIDE_AI_MODEL_MODERATION, PROVIDE_AI_MODEL_RERANK, PROVIDE_AI_MODEL_SPEECH2TEXT, PROVIDE_AI_MODEL_TEXT_EMBEDDING, PROVIDE_AI_MODEL_TTS, RETRIEVER_STRATEGY, RequestContext, RequestContextMiddleware, RequirePermissionOperation, RerankModel, RetrieverRegistry, RetrieverStrategy, SANDBOX_PROVIDER, STRATEGY_META_KEY, SandboxProviderRegistry, SandboxProviderStrategy, Speech2TextChatModel, SpeechToTextModel, StrategyBus, TEXT_SPLITTER_STRATEGY, TOOLSET_STRATEGY, TextEmbeddingModelManager, TextSplitterRegistry, TextSplitterStrategy, TextToSpeechModel, ToolsetRegistry, ToolsetStrategy, USER_PERMISSION_SERVICE_TOKEN, VECTOR_STORE_STRATEGY, VectorStoreRegistry, VectorStoreStrategy, WORKFLOW_NODE_STRATEGY, WORKFLOW_TRIGGER_STRATEGY, WorkflowNodeRegistry, WorkflowNodeStrategy, WorkflowTriggerRegistry, WorkflowTriggerStrategy, WrapWorkflowNodeExecutionCommand, XpFileSystem, XpertServerPlugin, als, calcTokenUsage, chunkText, countTokensSafe, createI18nInstance, createPluginLogger, defineAgentMessageType, defineChannelMessageType, downloadRemoteFile, getErrorMessage, getModelContextSize, getPermissionOperationMetadata, getPositionList, getPositionMap, getRequestContext, getRequiredPermissionOperation, isRemoteFile, isSandboxBackend, isStructuredMessageType, loadYamlFile, mergeCredentials, mergeParentChildChunks, normalizeContextSize, runWithRequestContext, sumTokenUsage };
|
|
3625
|
+
export { AGENT_CHAT_DISPATCH_MESSAGE_TYPE, AGENT_MIDDLEWARE_STRATEGY, AIModelProviderNotFoundException, AIModelProviderRegistry, AIModelProviderStrategy, AI_MODEL_PROVIDER, ANALYTICS_PERMISSION_SERVICE_TOKEN, AdapterDataSourceStrategy, AgentMiddlewareRegistry, AgentMiddlewareStrategy, AiModelNotFoundException, BaseHTTPQueryRunner, BaseQueryRunner, BaseSQLQueryRunner, BaseSandbox, BaseStrategyRegistry, BaseTool, BaseToolset, BuiltinToolset, CHAT_CHANNEL, CHAT_CHANNEL_TEXT_LIMITS, CancelConversationCommand, ChatChannel, ChatChannelRegistry, ChatOAICompatReasoningModel, CommonParameterRules, CreateModelClientCommand, CredentialsValidateFailedError, DATASOURCE_STRATEGY, DBCreateTableMode, DBProtocolEnum, DBSyntaxEnum, DBTableAction, DBTableDataAction, DEFAULT_EXECUTION_CONFIG, DEFAULT_SANDBOX_EXECUTION_MAX_OUTPUT_BYTES, DEFAULT_SANDBOX_FILE_OPERATION_EXECUTION_OPTIONS, DEFAULT_SANDBOX_FILE_OPERATION_TIMEOUT_MS, DEFAULT_SANDBOX_FILE_OPERATION_TIMEOUT_SEC, DEFAULT_SANDBOX_FILE_SEARCH_EXECUTION_OPTIONS, DEFAULT_SANDBOX_FILE_SEARCH_TIMEOUT_MS, DEFAULT_SANDBOX_FILE_SEARCH_TIMEOUT_SEC, DEFAULT_SANDBOX_SHELL_EXECUTION_OPTIONS, DEFAULT_SANDBOX_SHELL_TIMEOUT_MS, DEFAULT_SANDBOX_SHELL_TIMEOUT_SEC, DOCUMENT_SOURCE_STRATEGY, DOCUMENT_TRANSFORMER_STRATEGY, DataSourceStrategy, DataSourceStrategyRegistry, DocumentSourceRegistry, DocumentSourceStrategy, DocumentTransformerRegistry, DocumentTransformerStrategy, FILE_STORAGE_PROVIDER, FILE_UPLOAD_TARGET_STRATEGY, FileStorageProvider, FileStorageProviderRegistry, FileUploadTargetRegistry, FileUploadTargetStrategy, GLOBAL_ORGANIZATION_SCOPE, HANDOFF_PERMISSION_SERVICE_TOKEN, HANDOFF_PROCESSOR_STRATEGY, HANDOFF_QUEUE_SERVICE_TOKEN, HandoffProcessorRegistry, HandoffProcessorStrategy, IMAGE_UNDERSTANDING_STRATEGY, INTEGRATION_PERMISSION_SERVICE_TOKEN, INTEGRATION_STRATEGY, ImageUnderstandingRegistry, ImageUnderstandingStrategy, IntegrationStrategyKey, IntegrationStrategyRegistry, JUMP_TO_TARGETS, JsonSchemaValidator, KNOWLEDGE_STRATEGY, KnowledgeStrategyKey, KnowledgeStrategyRegistry, LLMUsage, LargeLanguageModel, ModelProvider, ORGANIZATION_METADATA_KEY, OpenAICompatibleReranker, PERMISSION_OPERATION_METADATA_KEY, PLUGIN_CONFIG_RESOLVER_TOKEN, PLUGIN_METADATA, PLUGIN_METADATA_KEY, PROVIDE_AI_MODEL_LLM, PROVIDE_AI_MODEL_MODERATION, PROVIDE_AI_MODEL_RERANK, PROVIDE_AI_MODEL_SPEECH2TEXT, PROVIDE_AI_MODEL_TEXT_EMBEDDING, PROVIDE_AI_MODEL_TTS, RETRIEVER_STRATEGY, RequestContext, RequestContextMiddleware, RequirePermissionOperation, RerankModel, RetrieverRegistry, RetrieverStrategy, SANDBOX_PROVIDER, SANDBOX_SHELL_TIMEOUT_LIMITS_SEC, STRATEGY_META_KEY, SandboxProviderRegistry, SandboxProviderStrategy, Speech2TextChatModel, SpeechToTextModel, StrategyBus, TEXT_SPLITTER_STRATEGY, TOOLSET_STRATEGY, TextEmbeddingModelManager, TextSplitterRegistry, TextSplitterStrategy, TextToSpeechModel, ToolsetRegistry, ToolsetStrategy, USER_PERMISSION_SERVICE_TOKEN, VECTOR_STORE_STRATEGY, VectorStoreRegistry, VectorStoreStrategy, WORKFLOW_NODE_STRATEGY, WORKFLOW_TRIGGER_STRATEGY, WorkflowNodeRegistry, WorkflowNodeStrategy, WorkflowTriggerRegistry, WorkflowTriggerStrategy, WrapWorkflowNodeExecutionCommand, XpFileSystem, XpertServerPlugin, als, appendSandboxMessage, buildSandboxTimeoutMessage, calcTokenUsage, chunkText, countTokensSafe, createI18nInstance, createPluginLogger, defineAgentMessageType, defineChannelMessageType, downloadRemoteFile, formatSandboxTimeout, getErrorMessage, getModelContextSize, getPermissionOperationMetadata, getPositionList, getPositionMap, getRequestContext, getRequiredPermissionOperation, isRemoteFile, isSandboxBackend, isStructuredMessageType, loadYamlFile, mergeCredentials, mergeParentChildChunks, normalizeContextSize, resolveSandboxExecutionOptions, runWithRequestContext, secondsToMilliseconds, sumTokenUsage };
|
package/package.json
CHANGED
package/src/index.d.ts
CHANGED
package/src/lib/core/index.d.ts
CHANGED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface PluginConfigResolveOptions<TConfig extends object = Record<string, any>> {
|
|
2
|
+
organizationId?: string;
|
|
3
|
+
fallbackToGlobal?: boolean;
|
|
4
|
+
defaults?: Partial<TConfig>;
|
|
5
|
+
}
|
|
6
|
+
export interface IPluginConfigResolver {
|
|
7
|
+
resolve<TConfig extends object = Record<string, any>>(pluginName: string, options?: PluginConfigResolveOptions<TConfig>): TConfig;
|
|
8
|
+
}
|
|
9
|
+
export declare const PLUGIN_CONFIG_RESOLVER_TOKEN = "XPERT_PLUGIN_CONFIG_RESOLVER";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/// <reference types="node" />
|
|
3
|
+
import { FileStorageOption, FileSystem, UploadedFile } from '@metad/contracts';
|
|
4
|
+
export interface IFileStorageProvider {
|
|
5
|
+
readonly name: string;
|
|
6
|
+
readonly config?: FileSystem & Record<string, any>;
|
|
7
|
+
url(path: string): string;
|
|
8
|
+
path(path: string): string;
|
|
9
|
+
handler(options: FileStorageOption): any;
|
|
10
|
+
getFile(file: string): Promise<Buffer>;
|
|
11
|
+
putFile(fileContent: string | Buffer | URL, path?: string): Promise<UploadedFile>;
|
|
12
|
+
deleteFile(path: string): Promise<void>;
|
|
13
|
+
mapUploadedFile?(file: any): UploadedFile;
|
|
14
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { DiscoveryService, Reflector } from '@nestjs/core';
|
|
2
|
+
import { BaseStrategyRegistry } from '../../strategy';
|
|
3
|
+
import { IFileStorageProvider } from './provider.interface';
|
|
4
|
+
export declare class FileStorageProviderRegistry extends BaseStrategyRegistry<IFileStorageProvider> {
|
|
5
|
+
constructor(discoveryService: DiscoveryService, reflector: Reflector);
|
|
6
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const FILE_UPLOAD_TARGET_STRATEGY = "FILE_UPLOAD_TARGET_STRATEGY";
|
|
2
|
+
export declare const FileUploadTargetStrategy: (type: string) => <TFunction extends Function, Y>(target: object | TFunction, propertyKey?: string | symbol, descriptor?: TypedPropertyDescriptor<Y>) => void;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/// <reference types="node" />
|
|
3
|
+
import { IFileAssetDestination, IFileAssetSource, IStorageFile, IUploadFileTarget } from '@metad/contracts';
|
|
4
|
+
export type TFileUploadRequestContext = {
|
|
5
|
+
tenantId?: string;
|
|
6
|
+
organizationId?: string;
|
|
7
|
+
userId?: string;
|
|
8
|
+
};
|
|
9
|
+
export type TResolvedFileUploadSource = {
|
|
10
|
+
name: string;
|
|
11
|
+
originalName: string;
|
|
12
|
+
mimeType?: string;
|
|
13
|
+
size?: number;
|
|
14
|
+
buffer: Buffer;
|
|
15
|
+
source: IFileAssetSource;
|
|
16
|
+
storageFile?: IStorageFile;
|
|
17
|
+
};
|
|
18
|
+
export type TFileUploadContext = {
|
|
19
|
+
request: TFileUploadRequestContext;
|
|
20
|
+
metadata?: Record<string, any>;
|
|
21
|
+
};
|
|
22
|
+
export type TStorageProviderType = string;
|
|
23
|
+
export interface IFileUploadTargetStrategy<TTarget extends IUploadFileTarget = IUploadFileTarget> {
|
|
24
|
+
upload(source: TResolvedFileUploadSource, target: TTarget, context: TFileUploadContext): Promise<IFileAssetDestination>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { DiscoveryService, Reflector } from '@nestjs/core';
|
|
2
|
+
import { BaseStrategyRegistry } from '../../strategy';
|
|
3
|
+
import { IFileUploadTargetStrategy } from './strategy.interface';
|
|
4
|
+
export declare class FileUploadTargetRegistry extends BaseStrategyRegistry<IFileUploadTargetStrategy> {
|
|
5
|
+
constructor(discoveryService: DiscoveryService, reflector: Reflector);
|
|
6
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface SandboxExecutionOptions {
|
|
2
|
+
timeoutMs?: number;
|
|
3
|
+
maxOutputBytes?: number;
|
|
4
|
+
}
|
|
5
|
+
export interface ResolvedSandboxExecutionOptions {
|
|
6
|
+
timeoutMs: number;
|
|
7
|
+
maxOutputBytes: number;
|
|
8
|
+
}
|
|
9
|
+
export declare const SANDBOX_SHELL_TIMEOUT_LIMITS_SEC: {
|
|
10
|
+
readonly min: 1;
|
|
11
|
+
readonly max: 3600;
|
|
12
|
+
};
|
|
13
|
+
export declare const DEFAULT_SANDBOX_SHELL_TIMEOUT_SEC = 600;
|
|
14
|
+
export declare const DEFAULT_SANDBOX_FILE_SEARCH_TIMEOUT_SEC = 120;
|
|
15
|
+
export declare const DEFAULT_SANDBOX_FILE_OPERATION_TIMEOUT_SEC = 120;
|
|
16
|
+
export declare const DEFAULT_SANDBOX_SHELL_TIMEOUT_MS: number;
|
|
17
|
+
export declare const DEFAULT_SANDBOX_FILE_SEARCH_TIMEOUT_MS: number;
|
|
18
|
+
export declare const DEFAULT_SANDBOX_FILE_OPERATION_TIMEOUT_MS: number;
|
|
19
|
+
export declare const DEFAULT_SANDBOX_EXECUTION_MAX_OUTPUT_BYTES: number;
|
|
20
|
+
export declare const DEFAULT_SANDBOX_SHELL_EXECUTION_OPTIONS: Readonly<SandboxExecutionOptions>;
|
|
21
|
+
export declare const DEFAULT_SANDBOX_FILE_SEARCH_EXECUTION_OPTIONS: Readonly<SandboxExecutionOptions>;
|
|
22
|
+
export declare const DEFAULT_SANDBOX_FILE_OPERATION_EXECUTION_OPTIONS: Readonly<SandboxExecutionOptions>;
|
|
23
|
+
export declare function secondsToMilliseconds(seconds: number): number;
|
|
24
|
+
export declare function formatSandboxTimeout(timeoutMs: number): string;
|
|
25
|
+
export declare function buildSandboxTimeoutMessage(subject: string, timeoutMs: number): string;
|
|
26
|
+
export declare function appendSandboxMessage(output: string, message: string): string;
|
|
27
|
+
export declare function resolveSandboxExecutionOptions(options?: SandboxExecutionOptions, defaults?: SandboxExecutionOptions): ResolvedSandboxExecutionOptions;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { SandboxExecutionOptions } from './execution';
|
|
1
2
|
/**
|
|
2
3
|
* Protocol definition for pluggable memory backends.
|
|
3
4
|
*
|
|
@@ -151,11 +152,13 @@ export interface ExecuteResponse {
|
|
|
151
152
|
exitCode: number | null;
|
|
152
153
|
/** Whether the output was truncated due to backend limitations */
|
|
153
154
|
truncated: boolean;
|
|
155
|
+
/** Whether the command exceeded its timeout and was terminated */
|
|
156
|
+
timedOut?: boolean;
|
|
154
157
|
}
|
|
155
158
|
/**
|
|
156
159
|
* Standardized error codes for file upload/download operations.
|
|
157
160
|
*/
|
|
158
|
-
export type FileOperationError =
|
|
161
|
+
export type FileOperationError = 'file_not_found' | 'permission_denied' | 'is_directory' | 'invalid_path';
|
|
159
162
|
/**
|
|
160
163
|
* Result of a single file download operation.
|
|
161
164
|
*/
|
|
@@ -318,7 +321,7 @@ export interface SandboxBackendProtocol extends BackendProtocol {
|
|
|
318
321
|
* @param command - Full shell command string to execute
|
|
319
322
|
* @returns ExecuteResponse with combined output, exit code, and truncation flag
|
|
320
323
|
*/
|
|
321
|
-
execute(command: string): MaybePromise<ExecuteResponse>;
|
|
324
|
+
execute(command: string, options?: SandboxExecutionOptions): MaybePromise<ExecuteResponse>;
|
|
322
325
|
/**
|
|
323
326
|
* Execute a command with line-by-line streaming output.
|
|
324
327
|
*
|
|
@@ -337,7 +340,7 @@ export interface SandboxBackendProtocol extends BackendProtocol {
|
|
|
337
340
|
* @param onLine - Callback invoked once per complete output line
|
|
338
341
|
* @returns ExecuteResponse with combined output, exit code, and truncation flag
|
|
339
342
|
*/
|
|
340
|
-
streamExecute?(command: string, onLine: (line: string) => void): MaybePromise<ExecuteResponse>;
|
|
343
|
+
streamExecute?(command: string, onLine: (line: string) => void, options?: SandboxExecutionOptions): MaybePromise<ExecuteResponse>;
|
|
341
344
|
/** Unique identifier for the sandbox backend instance */
|
|
342
345
|
readonly id: string;
|
|
343
346
|
}
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Requires Node.js 20+ on the sandbox host.
|
|
9
9
|
*/
|
|
10
|
-
import type { EditOperation, EditResult, ExecuteResponse, FileDownloadResponse, FileInfo, FileUploadResponse, GrepMatch, IndentationOptions, MaybePromise, MultiEditResult, ReadMode, SandboxBackendProtocol, WriteResult } from
|
|
10
|
+
import type { EditOperation, EditResult, ExecuteResponse, FileDownloadResponse, FileInfo, FileUploadResponse, GrepMatch, IndentationOptions, MaybePromise, MultiEditResult, ReadMode, SandboxBackendProtocol, WriteResult } from './protocol';
|
|
11
|
+
import { SandboxExecutionOptions } from './execution';
|
|
11
12
|
/**
|
|
12
13
|
* Base sandbox implementation with execute() as the only abstract method.
|
|
13
14
|
*
|
|
@@ -25,8 +26,8 @@ export declare abstract class BaseSandbox implements SandboxBackendProtocol {
|
|
|
25
26
|
* Execute a command in the sandbox.
|
|
26
27
|
* This is the only method concrete implementations must provide.
|
|
27
28
|
*/
|
|
28
|
-
abstract execute(command: string): MaybePromise<ExecuteResponse>;
|
|
29
|
-
streamExecute(command: string, onLine: (line: string) => void): Promise<ExecuteResponse>;
|
|
29
|
+
abstract execute(command: string, options?: SandboxExecutionOptions): MaybePromise<ExecuteResponse>;
|
|
30
|
+
streamExecute(command: string, onLine: (line: string) => void, options?: SandboxExecutionOptions): Promise<ExecuteResponse>;
|
|
30
31
|
/**
|
|
31
32
|
* Upload multiple files to the sandbox.
|
|
32
33
|
* Implementations must support partial success.
|
package/src/lib/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PluginMeta } from '@metad/contracts';
|
|
1
|
+
import { JsonSchemaObjectType, PluginMeta } from '@metad/contracts';
|
|
2
2
|
import type { DynamicModule, INestApplicationContext } from '@nestjs/common';
|
|
3
3
|
import { ModuleRef } from '@nestjs/core';
|
|
4
4
|
import type { ZodSchema } from 'zod';
|
|
@@ -30,6 +30,8 @@ export interface PluginConfigSpec<T extends object = any> {
|
|
|
30
30
|
schema?: ZodSchema<T>;
|
|
31
31
|
/** Default configuration */
|
|
32
32
|
defaults?: Partial<T>;
|
|
33
|
+
/** Optional JSON schema used by frontend configuration forms. */
|
|
34
|
+
formSchema?: JsonSchemaObjectType;
|
|
33
35
|
}
|
|
34
36
|
export interface XpertPlugin<TConfig extends object = any> extends PluginLifecycle, PluginHealth {
|
|
35
37
|
meta: PluginMeta;
|