vigthoria-cli 1.1.0 → 1.4.0
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 +85 -2
- package/SECURITY_HARDENING.md +253 -0
- package/dist/commands/chat.d.ts +2 -2
- package/dist/commands/chat.js +4 -4
- package/dist/commands/chat.js.map +1 -1
- package/dist/commands/deploy.d.ts +80 -0
- package/dist/commands/deploy.d.ts.map +1 -0
- package/dist/commands/deploy.js +514 -0
- package/dist/commands/deploy.js.map +1 -0
- package/dist/commands/generate.d.ts +3 -0
- package/dist/commands/generate.d.ts.map +1 -1
- package/dist/commands/generate.js +45 -4
- package/dist/commands/generate.js.map +1 -1
- package/dist/commands/hub.d.ts +40 -0
- package/dist/commands/hub.d.ts.map +1 -0
- package/dist/commands/hub.js +289 -0
- package/dist/commands/hub.js.map +1 -0
- package/dist/commands/repo.d.ts +80 -0
- package/dist/commands/repo.d.ts.map +1 -0
- package/dist/commands/repo.js +607 -0
- package/dist/commands/repo.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +267 -10
- package/dist/index.js.map +1 -1
- package/dist/utils/api.d.ts +15 -0
- package/dist/utils/api.d.ts.map +1 -1
- package/dist/utils/api.js +62 -33
- package/dist/utils/api.js.map +1 -1
- package/dist/utils/config.js +1 -1
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/session.d.ts +1 -1
- package/dist/utils/session.js +1 -1
- package/dist/utils/tools.d.ts +18 -3
- package/dist/utils/tools.d.ts.map +1 -1
- package/dist/utils/tools.js +326 -20
- package/dist/utils/tools.js.map +1 -1
- package/install.sh +1 -1
- package/package.json +6 -3
- package/src/commands/chat.ts +4 -4
- package/src/commands/deploy.ts +609 -0
- package/src/commands/generate.ts +49 -4
- package/src/commands/hub.ts +382 -0
- package/src/commands/repo.ts +729 -0
- package/src/index.ts +297 -10
- package/src/utils/api.ts +78 -34
- package/src/utils/config.ts +1 -1
- package/src/utils/session.ts +1 -1
- package/src/utils/tools.ts +348 -21
package/src/utils/tools.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Vigthoria CLI Tools - Agentic Tool System
|
|
3
3
|
*
|
|
4
|
-
* This module provides
|
|
4
|
+
* This module provides Vigthoria Autonomous autonomous tool execution.
|
|
5
5
|
* Tools can be called by the AI to perform actions.
|
|
6
6
|
*
|
|
7
7
|
* Enhanced with:
|
|
@@ -159,7 +159,7 @@ export class AgenticTools {
|
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
/**
|
|
162
|
-
* List of available tools -
|
|
162
|
+
* List of available tools - Vigthoria's advanced
|
|
163
163
|
* Enhanced with risk levels and categories
|
|
164
164
|
*/
|
|
165
165
|
static getToolDefinitions(): ToolDefinition[] {
|
|
@@ -262,6 +262,22 @@ export class AgenticTools {
|
|
|
262
262
|
riskLevel: 'medium',
|
|
263
263
|
category: 'execute',
|
|
264
264
|
},
|
|
265
|
+
{
|
|
266
|
+
name: 'repo',
|
|
267
|
+
description: 'Manage projects in Vigthoria Repository - push, pull, list, share, delete, or clone projects',
|
|
268
|
+
parameters: [
|
|
269
|
+
{ name: 'action', description: 'Action: push, pull, list, status, share, delete, clone', required: true },
|
|
270
|
+
{ name: 'project', description: 'Project name (for push/pull/status/share/delete)', required: false },
|
|
271
|
+
{ name: 'visibility', description: 'Visibility: public or private (for push)', required: false },
|
|
272
|
+
{ name: 'path', description: 'Directory path (for push) or target path (for clone)', required: false },
|
|
273
|
+
{ name: 'username', description: 'Username to share with (for share action)', required: false },
|
|
274
|
+
{ name: 'permission', description: 'Permission level: read, write, admin (for share action)', required: false },
|
|
275
|
+
],
|
|
276
|
+
requiresPermission: true,
|
|
277
|
+
dangerous: false,
|
|
278
|
+
riskLevel: 'medium',
|
|
279
|
+
category: 'execute',
|
|
280
|
+
},
|
|
265
281
|
];
|
|
266
282
|
}
|
|
267
283
|
|
|
@@ -376,6 +392,8 @@ export class AgenticTools {
|
|
|
376
392
|
return this.glob(call.args);
|
|
377
393
|
case 'git':
|
|
378
394
|
return this.git(call.args);
|
|
395
|
+
case 'repo':
|
|
396
|
+
return this.repo(call.args);
|
|
379
397
|
default:
|
|
380
398
|
return this.createErrorResult(
|
|
381
399
|
ToolErrorType.INVALID_ARGS,
|
|
@@ -708,11 +726,40 @@ export class AgenticTools {
|
|
|
708
726
|
|
|
709
727
|
/**
|
|
710
728
|
* Execute bash command with enhanced error handling
|
|
729
|
+
* SECURITY: Commands are sandboxed to workspace directory
|
|
711
730
|
*/
|
|
712
731
|
private bash(args: Record<string, string>): ToolResult {
|
|
713
732
|
const cwd = args.cwd ? this.resolvePath(args.cwd) : this.cwd;
|
|
714
733
|
const timeout = args.timeout ? parseInt(args.timeout) * 1000 : 30000;
|
|
715
734
|
|
|
735
|
+
// SECURITY: Block dangerous commands that could access outside workspace
|
|
736
|
+
const blockedPatterns = [
|
|
737
|
+
/\bcat\s+\/etc\//i, // Reading system files
|
|
738
|
+
/\bcat\s+\/var\/(?!log)/i, // Reading /var/ except logs
|
|
739
|
+
/\bcat\s+\/root\//i, // Reading root home
|
|
740
|
+
/\bcat\s+\/home\/[^\/]+\/\.[^\/]/i, // Reading hidden files in home dirs
|
|
741
|
+
/\bcat\s+~\/\./i, // Reading hidden files via ~
|
|
742
|
+
/\bcd\s+(\/etc|\/var\/www|\/root|\/home)/i, // CD to sensitive dirs
|
|
743
|
+
/\brm\s+-rf?\s+\//i, // Dangerous rm commands
|
|
744
|
+
/\b(curl|wget).*\|\s*(bash|sh)\b/i, // Downloading and executing scripts
|
|
745
|
+
/\bsudo\b/i, // Sudo commands
|
|
746
|
+
/\bsu\s+-/i, // Su to root
|
|
747
|
+
/\bchmod\s+[0-7]*777/i, // World-writable permissions
|
|
748
|
+
/\/(var\/www|opt)\/[a-z]+-?(database|models|coder|mcp|operator|voice|music)/i, // Vigthoria ecosystem
|
|
749
|
+
/vigthoria-(models|database|mcp|operator|voice|music)/i, // Vigthoria project names
|
|
750
|
+
];
|
|
751
|
+
|
|
752
|
+
for (const pattern of blockedPatterns) {
|
|
753
|
+
if (pattern.test(args.command)) {
|
|
754
|
+
this.logger.warn(`Security: Blocked potentially dangerous command: ${args.command.substring(0, 50)}...`);
|
|
755
|
+
return this.createErrorResult(
|
|
756
|
+
ToolErrorType.PERMISSION_DENIED,
|
|
757
|
+
'This command is blocked for security reasons',
|
|
758
|
+
'Commands must operate within your current project workspace.'
|
|
759
|
+
);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
|
|
716
763
|
// Validate working directory
|
|
717
764
|
if (!fs.existsSync(cwd)) {
|
|
718
765
|
return this.createErrorResult(
|
|
@@ -850,27 +897,218 @@ export class AgenticTools {
|
|
|
850
897
|
}
|
|
851
898
|
}
|
|
852
899
|
|
|
900
|
+
/**
|
|
901
|
+
* Vigthoria Repository management tool
|
|
902
|
+
* Allows AI to push, pull, list, share, and manage projects in the Vigthoria Repository
|
|
903
|
+
*/
|
|
904
|
+
private async repo(args: Record<string, string>): Promise<ToolResult> {
|
|
905
|
+
const action = args.action?.toLowerCase();
|
|
906
|
+
const project = args.project;
|
|
907
|
+
const visibility = args.visibility || 'private';
|
|
908
|
+
const targetPath = args.path || this.cwd;
|
|
909
|
+
|
|
910
|
+
try {
|
|
911
|
+
// Use vigthoria CLI for repo operations
|
|
912
|
+
let command: string;
|
|
913
|
+
|
|
914
|
+
switch (action) {
|
|
915
|
+
case 'push':
|
|
916
|
+
if (!project) {
|
|
917
|
+
return {
|
|
918
|
+
success: false,
|
|
919
|
+
error: 'Project name is required for push',
|
|
920
|
+
suggestion: 'Provide a project name, e.g., repo action=push project=my-project'
|
|
921
|
+
};
|
|
922
|
+
}
|
|
923
|
+
command = `vigthoria repo push "${project}" "${targetPath}" --visibility ${visibility}`;
|
|
924
|
+
break;
|
|
925
|
+
|
|
926
|
+
case 'pull':
|
|
927
|
+
if (!project) {
|
|
928
|
+
return {
|
|
929
|
+
success: false,
|
|
930
|
+
error: 'Project name is required for pull',
|
|
931
|
+
suggestion: 'Provide a project name, e.g., repo action=pull project=my-project'
|
|
932
|
+
};
|
|
933
|
+
}
|
|
934
|
+
command = `vigthoria repo pull "${project}"`;
|
|
935
|
+
break;
|
|
936
|
+
|
|
937
|
+
case 'list':
|
|
938
|
+
command = 'vigthoria repo list';
|
|
939
|
+
break;
|
|
940
|
+
|
|
941
|
+
case 'status':
|
|
942
|
+
if (!project) {
|
|
943
|
+
return {
|
|
944
|
+
success: false,
|
|
945
|
+
error: 'Project name is required for status',
|
|
946
|
+
suggestion: 'Provide a project name, e.g., repo action=status project=my-project'
|
|
947
|
+
};
|
|
948
|
+
}
|
|
949
|
+
command = `vigthoria repo status "${project}"`;
|
|
950
|
+
break;
|
|
951
|
+
|
|
952
|
+
case 'share':
|
|
953
|
+
if (!project || !args.username) {
|
|
954
|
+
return {
|
|
955
|
+
success: false,
|
|
956
|
+
error: 'Project name and username are required for share',
|
|
957
|
+
suggestion: 'Provide both, e.g., repo action=share project=my-project username=collaborator permission=read'
|
|
958
|
+
};
|
|
959
|
+
}
|
|
960
|
+
const permission = args.permission || 'read';
|
|
961
|
+
command = `vigthoria repo share "${project}" "${args.username}" --permission ${permission}`;
|
|
962
|
+
break;
|
|
963
|
+
|
|
964
|
+
case 'delete':
|
|
965
|
+
if (!project) {
|
|
966
|
+
return {
|
|
967
|
+
success: false,
|
|
968
|
+
error: 'Project name is required for delete',
|
|
969
|
+
suggestion: 'Provide a project name, e.g., repo action=delete project=my-project'
|
|
970
|
+
};
|
|
971
|
+
}
|
|
972
|
+
command = `vigthoria repo delete "${project}" --force`;
|
|
973
|
+
break;
|
|
974
|
+
|
|
975
|
+
case 'clone':
|
|
976
|
+
if (!project) {
|
|
977
|
+
return {
|
|
978
|
+
success: false,
|
|
979
|
+
error: 'Project name is required for clone',
|
|
980
|
+
suggestion: 'Provide a project name, e.g., repo action=clone project=my-project path=/path/to/target'
|
|
981
|
+
};
|
|
982
|
+
}
|
|
983
|
+
command = `vigthoria repo clone "${project}" "${targetPath}"`;
|
|
984
|
+
break;
|
|
985
|
+
|
|
986
|
+
default:
|
|
987
|
+
return {
|
|
988
|
+
success: false,
|
|
989
|
+
error: `Unknown repo action: ${action}`,
|
|
990
|
+
suggestion: 'Available actions: push, pull, list, status, share, delete, clone'
|
|
991
|
+
};
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
const output = execSync(command, {
|
|
995
|
+
cwd: this.cwd,
|
|
996
|
+
encoding: 'utf-8',
|
|
997
|
+
timeout: 120000, // 2 minute timeout for repo operations
|
|
998
|
+
env: { ...process.env, FORCE_COLOR: '0' } // Disable colors for clean output
|
|
999
|
+
});
|
|
1000
|
+
|
|
1001
|
+
return {
|
|
1002
|
+
success: true,
|
|
1003
|
+
output: output.trim(),
|
|
1004
|
+
metadata: { action, project }
|
|
1005
|
+
};
|
|
1006
|
+
} catch (error: any) {
|
|
1007
|
+
return {
|
|
1008
|
+
success: false,
|
|
1009
|
+
error: error.stderr || error.message,
|
|
1010
|
+
suggestion: 'Make sure you are logged in with vigthoria login and have the required permissions.'
|
|
1011
|
+
};
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
/**
|
|
1016
|
+
* Resolve and SANITIZE path - prevent path traversal outside workspace
|
|
1017
|
+
* SECURITY: All paths MUST stay within the workspace (cwd)
|
|
1018
|
+
*/
|
|
853
1019
|
private resolvePath(p: string): string {
|
|
1020
|
+
// Resolve the full path (handles both relative and absolute)
|
|
1021
|
+
let resolvedPath: string;
|
|
854
1022
|
if (path.isAbsolute(p)) {
|
|
855
|
-
|
|
1023
|
+
resolvedPath = path.normalize(p);
|
|
1024
|
+
} else {
|
|
1025
|
+
resolvedPath = path.normalize(path.join(this.cwd, p));
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
// SECURITY CHECK: Ensure path is within workspace
|
|
1029
|
+
const workspaceRoot = path.normalize(this.cwd);
|
|
1030
|
+
if (!resolvedPath.startsWith(workspaceRoot + path.sep) && resolvedPath !== workspaceRoot) {
|
|
1031
|
+
// Path is outside workspace - force it back to workspace
|
|
1032
|
+
this.logger.warn(`Security: Blocked access to path outside workspace: ${p}`);
|
|
1033
|
+
// Return the sanitized relative path within workspace
|
|
1034
|
+
const basename = path.basename(p);
|
|
1035
|
+
return path.join(this.cwd, basename);
|
|
856
1036
|
}
|
|
857
|
-
|
|
1037
|
+
|
|
1038
|
+
return resolvedPath;
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
/**
|
|
1042
|
+
* Check if a path is within the allowed workspace
|
|
1043
|
+
*/
|
|
1044
|
+
private isPathWithinWorkspace(p: string): boolean {
|
|
1045
|
+
const resolvedPath = path.normalize(path.isAbsolute(p) ? p : path.join(this.cwd, p));
|
|
1046
|
+
const workspaceRoot = path.normalize(this.cwd);
|
|
1047
|
+
return resolvedPath.startsWith(workspaceRoot + path.sep) || resolvedPath === workspaceRoot;
|
|
858
1048
|
}
|
|
859
1049
|
|
|
860
1050
|
/**
|
|
861
|
-
* Parse tool calls from AI response (
|
|
1051
|
+
* Parse tool calls from AI response (Vigthoria Agent format)
|
|
1052
|
+
* Enhanced to handle various AI output formats including malformed JSON
|
|
862
1053
|
*/
|
|
863
1054
|
static parseToolCalls(text: string): ToolCall[] {
|
|
864
1055
|
const calls: ToolCall[] = [];
|
|
865
|
-
|
|
866
|
-
// Match <tool_call>...</tool_call> blocks
|
|
867
|
-
const toolCallRegex = /<tool_call>\s*(\{[\s\S]*?\})\s*<\/tool_call>/g;
|
|
868
1056
|
let match;
|
|
869
1057
|
|
|
1058
|
+
// Helper to fix common JSON issues from AI outputs
|
|
1059
|
+
const fixJson = (jsonStr: string): string => {
|
|
1060
|
+
return jsonStr
|
|
1061
|
+
.replace(/'/g, '"') // Replace single quotes with double
|
|
1062
|
+
.replace(/([{,]\s*)(\w+):/g, '$1"$2":') // Quote unquoted keys
|
|
1063
|
+
.replace(/:\s*'([^']*)'\s*([,}])/g, ': "$1"$2') // Quote values with single quotes
|
|
1064
|
+
.replace(/\n/g, '\\n') // Escape newlines
|
|
1065
|
+
.replace(/\r/g, '') // Remove carriage returns
|
|
1066
|
+
.replace(/\t/g, '\\t') // Escape tabs
|
|
1067
|
+
.replace(/,\s*}/g, '}') // Remove trailing commas in objects
|
|
1068
|
+
.replace(/,\s*]/g, ']'); // Remove trailing commas in arrays
|
|
1069
|
+
};
|
|
1070
|
+
|
|
1071
|
+
// Normalize tool name from various formats
|
|
1072
|
+
const normalizeToolName = (name: string): string => {
|
|
1073
|
+
const normalized = name
|
|
1074
|
+
.replace(/^__/, '') // Remove leading underscores
|
|
1075
|
+
.replace(/__$/, '') // Remove trailing underscores
|
|
1076
|
+
.replace(/^execute_/i, '') // Remove execute_ prefix
|
|
1077
|
+
.replace(/_execute$/i, '') // Remove _execute suffix
|
|
1078
|
+
.toLowerCase();
|
|
1079
|
+
|
|
1080
|
+
// Map common variations
|
|
1081
|
+
const toolMap: Record<string, string> = {
|
|
1082
|
+
'bash': 'bash',
|
|
1083
|
+
'shell': 'bash',
|
|
1084
|
+
'run': 'bash',
|
|
1085
|
+
'command': 'bash',
|
|
1086
|
+
'list_dir': 'list_dir',
|
|
1087
|
+
'list_directory': 'list_dir',
|
|
1088
|
+
'ls': 'list_dir',
|
|
1089
|
+
'dir': 'list_dir',
|
|
1090
|
+
'read_file': 'read_file',
|
|
1091
|
+
'readfile': 'read_file',
|
|
1092
|
+
'read': 'read_file',
|
|
1093
|
+
'write_file': 'write_file',
|
|
1094
|
+
'writefile': 'write_file',
|
|
1095
|
+
'write': 'write_file',
|
|
1096
|
+
'edit_file': 'edit_file',
|
|
1097
|
+
'editfile': 'edit_file',
|
|
1098
|
+
'edit': 'edit_file',
|
|
1099
|
+
};
|
|
1100
|
+
|
|
1101
|
+
return toolMap[normalized] || normalized;
|
|
1102
|
+
};
|
|
1103
|
+
|
|
1104
|
+
// Match <tool_call>...</tool_call> blocks
|
|
1105
|
+
const toolCallRegex = /<tool_call>\s*([\s\S]*?)\s*<\/tool_call>/g;
|
|
870
1106
|
while ((match = toolCallRegex.exec(text)) !== null) {
|
|
871
1107
|
try {
|
|
872
|
-
const
|
|
1108
|
+
const fixed = fixJson(match[1]);
|
|
1109
|
+
const parsed = JSON.parse(fixed);
|
|
873
1110
|
if (parsed.tool && parsed.args) {
|
|
1111
|
+
parsed.tool = normalizeToolName(parsed.tool);
|
|
874
1112
|
calls.push(parsed);
|
|
875
1113
|
}
|
|
876
1114
|
} catch (e) {
|
|
@@ -878,12 +1116,14 @@ export class AgenticTools {
|
|
|
878
1116
|
}
|
|
879
1117
|
}
|
|
880
1118
|
|
|
881
|
-
//
|
|
882
|
-
const codeBlockRegex = /```tool\s*\n(
|
|
1119
|
+
// Match ```tool format
|
|
1120
|
+
const codeBlockRegex = /```tool\s*\n([\s\S]*?)\n```/g;
|
|
883
1121
|
while ((match = codeBlockRegex.exec(text)) !== null) {
|
|
884
1122
|
try {
|
|
885
|
-
const
|
|
1123
|
+
const fixed = fixJson(match[1]);
|
|
1124
|
+
const parsed = JSON.parse(fixed);
|
|
886
1125
|
if (parsed.tool && parsed.args) {
|
|
1126
|
+
parsed.tool = normalizeToolName(parsed.tool);
|
|
887
1127
|
calls.push(parsed);
|
|
888
1128
|
}
|
|
889
1129
|
} catch (e) {
|
|
@@ -891,6 +1131,67 @@ export class AgenticTools {
|
|
|
891
1131
|
}
|
|
892
1132
|
}
|
|
893
1133
|
|
|
1134
|
+
// Match ```json blocks with tool definitions
|
|
1135
|
+
const jsonBlockRegex = /```(?:json)?\s*\n?([\s\S]*?"tool"[\s\S]*?)\n?```/g;
|
|
1136
|
+
while ((match = jsonBlockRegex.exec(text)) !== null) {
|
|
1137
|
+
try {
|
|
1138
|
+
const fixed = fixJson(match[1]);
|
|
1139
|
+
const parsed = JSON.parse(fixed);
|
|
1140
|
+
if (parsed.tool && parsed.args) {
|
|
1141
|
+
parsed.tool = normalizeToolName(parsed.tool);
|
|
1142
|
+
// Prevent duplicates
|
|
1143
|
+
if (!calls.some(c => c.tool === parsed.tool && JSON.stringify(c.args) === JSON.stringify(parsed.args))) {
|
|
1144
|
+
calls.push(parsed);
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
} catch (e) {
|
|
1148
|
+
// Invalid JSON, skip
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
// Match inline JSON with "tool" key (various formats)
|
|
1153
|
+
const inlineToolRegex = /\{[^{}]*"?tool"?\s*:\s*["']?([^"',}]+)["']?[^{}]*"?args"?\s*:\s*\{([^{}]*)\}[^{}]*\}/gi;
|
|
1154
|
+
while ((match = inlineToolRegex.exec(text)) !== null) {
|
|
1155
|
+
try {
|
|
1156
|
+
const fixed = fixJson(match[0]);
|
|
1157
|
+
const parsed = JSON.parse(fixed);
|
|
1158
|
+
if (parsed.tool && parsed.args) {
|
|
1159
|
+
parsed.tool = normalizeToolName(parsed.tool);
|
|
1160
|
+
if (!calls.some(c => c.tool === parsed.tool && JSON.stringify(c.args) === JSON.stringify(parsed.args))) {
|
|
1161
|
+
calls.push(parsed);
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
} catch (e) {
|
|
1165
|
+
// Invalid JSON, skip
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
// Parse Vigthoria V2 format: {"tool": "__BASH__", ...}
|
|
1170
|
+
const vigV2Regex = /"?tool"?\s*:\s*["']__?([A-Za-z_]+)__?["']/gi;
|
|
1171
|
+
while ((match = vigV2Regex.exec(text)) !== null) {
|
|
1172
|
+
try {
|
|
1173
|
+
const toolName = normalizeToolName(match[1]);
|
|
1174
|
+
// Extract args from nearby context
|
|
1175
|
+
const pathMatch = text.match(/"?(?:arg_)?path"?\s*:\s*["']([^"']+)["']/i);
|
|
1176
|
+
const cmdMatch = text.match(/"?command"?\s*:\s*(?:["']([^"']+)["']|\[\s*["']([^"']+)["']\s*\])/i);
|
|
1177
|
+
const contentMatch = text.match(/"?content"?\s*:\s*["']([^"']+)["']/i);
|
|
1178
|
+
|
|
1179
|
+
const args: Record<string, string> = {};
|
|
1180
|
+
if (pathMatch) args.path = pathMatch[1];
|
|
1181
|
+
if (cmdMatch) args.command = cmdMatch[1] || cmdMatch[2];
|
|
1182
|
+
if (contentMatch) args.content = contentMatch[1];
|
|
1183
|
+
|
|
1184
|
+
if (Object.keys(args).length > 0) {
|
|
1185
|
+
// Prevent duplicates
|
|
1186
|
+
if (!calls.some(c => c.tool === toolName && JSON.stringify(c.args) === JSON.stringify(args))) {
|
|
1187
|
+
calls.push({ tool: toolName, args });
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
} catch (e) {
|
|
1191
|
+
// Skip
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
|
|
894
1195
|
return calls;
|
|
895
1196
|
}
|
|
896
1197
|
|
|
@@ -914,18 +1215,44 @@ ${tool.parameters.map(p => ` - ${p.name}${p.required ? ' (required)' : ''}: ${p
|
|
|
914
1215
|
}
|
|
915
1216
|
|
|
916
1217
|
prompt += `
|
|
917
|
-
|
|
1218
|
+
## How to Use Tools
|
|
1219
|
+
|
|
1220
|
+
To use a tool, output a JSON block in a code fence with "tool" language:
|
|
1221
|
+
|
|
918
1222
|
\`\`\`tool
|
|
919
|
-
{
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
1223
|
+
{"tool": "tool_name", "args": {"param1": "value1"}}
|
|
1224
|
+
\`\`\`
|
|
1225
|
+
|
|
1226
|
+
### Examples:
|
|
1227
|
+
|
|
1228
|
+
1. List directory contents:
|
|
1229
|
+
\`\`\`tool
|
|
1230
|
+
{"tool": "list_dir", "args": {"path": "."}}
|
|
1231
|
+
\`\`\`
|
|
1232
|
+
|
|
1233
|
+
2. Read a file:
|
|
1234
|
+
\`\`\`tool
|
|
1235
|
+
{"tool": "read_file", "args": {"path": "src/index.js"}}
|
|
1236
|
+
\`\`\`
|
|
1237
|
+
|
|
1238
|
+
3. Run a shell command:
|
|
1239
|
+
\`\`\`tool
|
|
1240
|
+
{"tool": "bash", "args": {"command": "ls -la"}}
|
|
1241
|
+
\`\`\`
|
|
1242
|
+
|
|
1243
|
+
4. Write a file:
|
|
1244
|
+
\`\`\`tool
|
|
1245
|
+
{"tool": "write_file", "args": {"path": "hello.py", "content": "print('Hello World')"}}
|
|
925
1246
|
\`\`\`
|
|
926
1247
|
|
|
927
|
-
|
|
928
|
-
|
|
1248
|
+
IMPORTANT:
|
|
1249
|
+
- You can ONLY access files within the current project workspace
|
|
1250
|
+
- Use relative paths (e.g., "src/file.js", "app.py", "./config.json")
|
|
1251
|
+
- Never try to access system files or directories outside the workspace
|
|
1252
|
+
- Use ONLY the exact tool names: list_dir, read_file, write_file, edit_file, bash, grep, glob, git
|
|
1253
|
+
- The JSON must be valid with double quotes for all keys and string values
|
|
1254
|
+
- After tool execution, you will receive results and can continue with the next step
|
|
1255
|
+
- Explain what you're doing before using tools
|
|
929
1256
|
`;
|
|
930
1257
|
|
|
931
1258
|
return prompt;
|