@4onstudios/iris-agent 0.1.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/LICENSE +21 -0
- package/README.md +690 -0
- package/dist/api/acp/acpServer.d.ts +23 -0
- package/dist/api/acp/acpServer.js +814 -0
- package/dist/api/acp/index.d.ts +2 -0
- package/dist/api/acp/index.js +2 -0
- package/dist/api/acp/irisClient.d.ts +58 -0
- package/dist/api/acp/irisClient.js +214 -0
- package/dist/api/agent.d.ts +14 -0
- package/dist/api/agent.js +4171 -0
- package/dist/api/backendService.d.ts +4 -0
- package/dist/api/backendService.js +14 -0
- package/dist/api/core/agent/host/AgentContract.d.ts +82 -0
- package/dist/api/core/agent/host/AgentContract.js +1 -0
- package/dist/api/core/agent/host/AgentRegistry.d.ts +24 -0
- package/dist/api/core/agent/host/AgentRegistry.js +125 -0
- package/dist/api/core/agent/host/defaultRegistry.d.ts +15 -0
- package/dist/api/core/agent/host/defaultRegistry.js +46 -0
- package/dist/api/core/agent/host/externalAgentLifecycle.d.ts +65 -0
- package/dist/api/core/agent/host/externalAgentLifecycle.js +117 -0
- package/dist/api/core/agent/host/hostSessionManager.d.ts +111 -0
- package/dist/api/core/agent/host/hostSessionManager.js +352 -0
- package/dist/api/core/agent/host/index.d.ts +5 -0
- package/dist/api/core/agent/host/index.js +5 -0
- package/dist/api/core/agent/index.d.ts +87 -0
- package/dist/api/core/agent/index.js +1024 -0
- package/dist/api/core/agent/publicContracts.d.ts +35 -0
- package/dist/api/core/agent/publicContracts.js +103 -0
- package/dist/api/core/agent/tools/applyDiff.d.ts +51 -0
- package/dist/api/core/agent/tools/applyDiff.js +131 -0
- package/dist/api/core/agent/tools/backgroundTasks.d.ts +240 -0
- package/dist/api/core/agent/tools/backgroundTasks.js +313 -0
- package/dist/api/core/agent/tools/createDirectory.d.ts +43 -0
- package/dist/api/core/agent/tools/createDirectory.js +77 -0
- package/dist/api/core/agent/tools/deleteFile.d.ts +37 -0
- package/dist/api/core/agent/tools/deleteFile.js +66 -0
- package/dist/api/core/agent/tools/editFile.d.ts +73 -0
- package/dist/api/core/agent/tools/editFile.js +173 -0
- package/dist/api/core/agent/tools/executeCommand.d.ts +59 -0
- package/dist/api/core/agent/tools/executeCommand.js +250 -0
- package/dist/api/core/agent/tools/fileContent.d.ts +54 -0
- package/dist/api/core/agent/tools/fileContent.js +227 -0
- package/dist/api/core/agent/tools/findDefinition.d.ts +72 -0
- package/dist/api/core/agent/tools/findDefinition.js +109 -0
- package/dist/api/core/agent/tools/findReferences.d.ts +86 -0
- package/dist/api/core/agent/tools/findReferences.js +135 -0
- package/dist/api/core/agent/tools/formatDocument.d.ts +67 -0
- package/dist/api/core/agent/tools/formatDocument.js +90 -0
- package/dist/api/core/agent/tools/getCodeActions.d.ts +77 -0
- package/dist/api/core/agent/tools/getCodeActions.js +97 -0
- package/dist/api/core/agent/tools/getCodeCompletion.d.ts +77 -0
- package/dist/api/core/agent/tools/getCodeCompletion.js +174 -0
- package/dist/api/core/agent/tools/getCodeContext.d.ts +14 -0
- package/dist/api/core/agent/tools/getCodeContext.js +282 -0
- package/dist/api/core/agent/tools/getSignatureHelp.d.ts +61 -0
- package/dist/api/core/agent/tools/getSignatureHelp.js +85 -0
- package/dist/api/core/agent/tools/getSymbols.d.ts +50 -0
- package/dist/api/core/agent/tools/getSymbols.js +164 -0
- package/dist/api/core/agent/tools/getSymbolsLSP.d.ts +58 -0
- package/dist/api/core/agent/tools/getSymbolsLSP.js +147 -0
- package/dist/api/core/agent/tools/getTypeInfo.d.ts +70 -0
- package/dist/api/core/agent/tools/getTypeInfo.js +84 -0
- package/dist/api/core/agent/tools/getWorkspaceInfo.d.ts +80 -0
- package/dist/api/core/agent/tools/getWorkspaceInfo.js +281 -0
- package/dist/api/core/agent/tools/getWorkspaceSymbols.d.ts +53 -0
- package/dist/api/core/agent/tools/getWorkspaceSymbols.js +97 -0
- package/dist/api/core/agent/tools/grepSearch.d.ts +100 -0
- package/dist/api/core/agent/tools/grepSearch.js +211 -0
- package/dist/api/core/agent/tools/languageModelToolsIntegration.d.ts +13 -0
- package/dist/api/core/agent/tools/languageModelToolsIntegration.js +22 -0
- package/dist/api/core/agent/tools/listDirectory.d.ts +66 -0
- package/dist/api/core/agent/tools/listDirectory.js +161 -0
- package/dist/api/core/agent/tools/mcpTools.d.ts +48 -0
- package/dist/api/core/agent/tools/mcpTools.js +442 -0
- package/dist/api/core/agent/tools/queryKnowledgeGraph.d.ts +120 -0
- package/dist/api/core/agent/tools/queryKnowledgeGraph.js +306 -0
- package/dist/api/core/agent/tools/readFile.d.ts +92 -0
- package/dist/api/core/agent/tools/readFile.js +337 -0
- package/dist/api/core/agent/tools/renameFile.d.ts +49 -0
- package/dist/api/core/agent/tools/renameFile.js +86 -0
- package/dist/api/core/agent/tools/renameSymbol.d.ts +70 -0
- package/dist/api/core/agent/tools/renameSymbol.js +106 -0
- package/dist/api/core/agent/tools/runTerminalCommand.d.ts +72 -0
- package/dist/api/core/agent/tools/runTerminalCommand.js +69 -0
- package/dist/api/core/agent/tools/searchFiles.d.ts +82 -0
- package/dist/api/core/agent/tools/searchFiles.js +280 -0
- package/dist/api/core/agent/tools/terminalAutoApprove.d.ts +3 -0
- package/dist/api/core/agent/tools/terminalAutoApprove.js +676 -0
- package/dist/api/core/agent/tools/treeTraversal.d.ts +60 -0
- package/dist/api/core/agent/tools/treeTraversal.js +217 -0
- package/dist/api/core/agent/tools/webSearch.d.ts +37 -0
- package/dist/api/core/agent/tools/webSearch.js +80 -0
- package/dist/api/core/agent/tools/writeFile.d.ts +59 -0
- package/dist/api/core/agent/tools/writeFile.js +97 -0
- package/dist/api/core/agent/utils/capturedWorkspaceMutationBridge.d.ts +12 -0
- package/dist/api/core/agent/utils/capturedWorkspaceMutationBridge.js +67 -0
- package/dist/api/core/agent/utils/diffUtils.d.ts +14 -0
- package/dist/api/core/agent/utils/diffUtils.js +39 -0
- package/dist/api/core/agent/utils/environmentSnapshot.d.ts +42 -0
- package/dist/api/core/agent/utils/environmentSnapshot.js +213 -0
- package/dist/api/core/agent/utils/errorRecovery.d.ts +49 -0
- package/dist/api/core/agent/utils/errorRecovery.js +229 -0
- package/dist/api/core/agent/utils/multimodalTokenLimiter.d.ts +8 -0
- package/dist/api/core/agent/utils/multimodalTokenLimiter.js +238 -0
- package/dist/api/core/agent/utils/openRouterModelSettings.d.ts +12 -0
- package/dist/api/core/agent/utils/openRouterModelSettings.js +34 -0
- package/dist/api/core/agent/utils/pathRecovery.d.ts +1 -0
- package/dist/api/core/agent/utils/pathRecovery.js +29 -0
- package/dist/api/core/agent/utils/repoMapIndex.d.ts +3 -0
- package/dist/api/core/agent/utils/repoMapIndex.js +197 -0
- package/dist/api/core/agent/utils/skillsDiscovery.d.ts +10 -0
- package/dist/api/core/agent/utils/skillsDiscovery.js +50 -0
- package/dist/api/core/agent/utils/toolCallBudget.d.ts +9 -0
- package/dist/api/core/agent/utils/toolCallBudget.js +55 -0
- package/dist/api/core/agent/utils/toolLifecycle.d.ts +30 -0
- package/dist/api/core/agent/utils/toolLifecycle.js +361 -0
- package/dist/api/core/agent/utils/toolResultSafetyProcessor.d.ts +12 -0
- package/dist/api/core/agent/utils/toolResultSafetyProcessor.js +57 -0
- package/dist/api/core/agent/utils/workspaceMutationBridge.d.ts +13 -0
- package/dist/api/core/agent/utils/workspaceMutationBridge.js +149 -0
- package/dist/api/core/agent/utils/workspacePathGuard.d.ts +7 -0
- package/dist/api/core/agent/utils/workspacePathGuard.js +79 -0
- package/dist/api/core/containers/chat/toolResultSerialization.d.ts +8 -0
- package/dist/api/core/containers/chat/toolResultSerialization.js +71 -0
- package/dist/api/core/library/BrowserManager.d.ts +11 -0
- package/dist/api/core/library/BrowserManager.js +66 -0
- package/dist/api/core/library/desktopWorkspace.d.ts +1 -0
- package/dist/api/core/library/desktopWorkspace.js +3 -0
- package/dist/api/core/library/extensionManager.d.ts +10 -0
- package/dist/api/core/library/extensionManager.js +27 -0
- package/dist/api/core/library/knowledgeGraph.d.ts +268 -0
- package/dist/api/core/library/knowledgeGraph.js +989 -0
- package/dist/api/core/library/languageModelTools.d.ts +141 -0
- package/dist/api/core/library/languageModelTools.js +207 -0
- package/dist/api/core/library/localRuntime.d.ts +23 -0
- package/dist/api/core/library/localRuntime.js +144 -0
- package/dist/api/core/library/lsp/coreLsp.d.ts +367 -0
- package/dist/api/core/library/lsp/coreLsp.js +2076 -0
- package/dist/api/core/library/lsp/protocol.d.ts +25 -0
- package/dist/api/core/library/lsp/protocol.js +1 -0
- package/dist/api/core/library/lsp/serverManager.d.ts +37 -0
- package/dist/api/core/library/lsp/serverManager.js +427 -0
- package/dist/api/core/library/mcpServerProvider.d.ts +69 -0
- package/dist/api/core/library/mcpServerProvider.js +152 -0
- package/dist/api/core/library/mcpSettings.d.ts +20 -0
- package/dist/api/core/library/mcpSettings.js +131 -0
- package/dist/api/core/library/patternMatcher.d.ts +66 -0
- package/dist/api/core/library/patternMatcher.js +284 -0
- package/dist/api/core/library/regexEscape.d.ts +4 -0
- package/dist/api/core/library/regexEscape.js +4 -0
- package/dist/api/core/library/runtimeEventBus.d.ts +27 -0
- package/dist/api/core/library/runtimeEventBus.js +78 -0
- package/dist/api/core/library/safetyMiddleware.d.ts +98 -0
- package/dist/api/core/library/safetyMiddleware.js +215 -0
- package/dist/api/core/library/tauri.d.ts +71 -0
- package/dist/api/core/library/tauri.js +222 -0
- package/dist/api/core/library/tauriImport.d.ts +5 -0
- package/dist/api/core/library/tauriImport.js +7 -0
- package/dist/api/core/library/terminalAutoApproveSettings.d.ts +32 -0
- package/dist/api/core/library/terminalAutoApproveSettings.js +529 -0
- package/dist/api/core/library/workspaceIdentity.d.ts +10 -0
- package/dist/api/core/library/workspaceIdentity.js +49 -0
- package/dist/api/core/library/workspaceSummary.d.ts +19 -0
- package/dist/api/core/library/workspaceSummary.js +35 -0
- package/dist/api/core/skills/agent-customization/SKILL.md +27 -0
- package/dist/api/core/skills/bug-fix/SKILL.md +21 -0
- package/dist/api/core/skills/create-pr/SKILL.md +32 -0
- package/dist/api/core/skills/dev-server/SKILL.md +20 -0
- package/dist/api/core/skills/fix-suggestions/SKILL.md +21 -0
- package/dist/api/core/skills/github-search/SKILL.md +21 -0
- package/dist/api/core/skills/github-summary/SKILL.md +25 -0
- package/dist/api/core/skills/integration-tests/SKILL.md +29 -0
- package/dist/api/core/skills/pr-comments/SKILL.md +23 -0
- package/dist/api/core/skills/project-setup/SKILL.md +20 -0
- package/dist/api/core/skills/search-integration/SKILL.md +19 -0
- package/dist/api/core/skills/search-results/SKILL.md +19 -0
- package/dist/api/core/skills/typescript-upgrade/SKILL.md +21 -0
- package/dist/api/data/runStore.d.ts +46 -0
- package/dist/api/data/runStore.js +244 -0
- package/dist/api/helpers/agentUtils.d.ts +11 -0
- package/dist/api/helpers/agentUtils.js +23 -0
- package/dist/api/helpers/modelTokenLimits.d.ts +2 -0
- package/dist/api/helpers/modelTokenLimits.js +158 -0
- package/dist/api/helpers/observationalMemory.d.ts +10 -0
- package/dist/api/helpers/observationalMemory.js +36 -0
- package/dist/api/helpers/promptBudget.d.ts +30 -0
- package/dist/api/helpers/promptBudget.js +216 -0
- package/dist/api/helpers/resolveImageMessageParts.d.ts +9 -0
- package/dist/api/helpers/resolveImageMessageParts.js +140 -0
- package/dist/api/helpers/slashCommands.d.ts +31 -0
- package/dist/api/helpers/slashCommands.js +129 -0
- package/dist/api/helpers/tokenUsage.d.ts +19 -0
- package/dist/api/helpers/tokenUsage.js +81 -0
- package/dist/api/routes/fileRoutes.d.ts +2 -0
- package/dist/api/routes/fileRoutes.js +108 -0
- package/dist/api/routes/lspDocumentRoutes.d.ts +4 -0
- package/dist/api/routes/lspDocumentRoutes.js +84 -0
- package/dist/api/routes/lspHierarchyRoutes.d.ts +4 -0
- package/dist/api/routes/lspHierarchyRoutes.js +122 -0
- package/dist/api/routes/lspPositionRoutes.d.ts +4 -0
- package/dist/api/routes/lspPositionRoutes.js +263 -0
- package/dist/api/routes/lspQueryRoutes.d.ts +4 -0
- package/dist/api/routes/lspQueryRoutes.js +679 -0
- package/dist/api/routes/lspResolveRoutes.d.ts +4 -0
- package/dist/api/routes/lspResolveRoutes.js +143 -0
- package/dist/api/routes/lspSemanticDocumentRoutes.d.ts +4 -0
- package/dist/api/routes/lspSemanticDocumentRoutes.js +98 -0
- package/dist/api/routes/semanticRoutes.d.ts +2 -0
- package/dist/api/routes/semanticRoutes.js +126 -0
- package/dist/cli.d.ts +8 -0
- package/dist/cli.js +160 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +38 -0
- package/package.json +100 -0
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
import fs from "fs/promises";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { execFile } from "child_process";
|
|
4
|
+
import { promisify } from "util";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { knowledgeGraph } from "../../library/knowledgeGraph.js";
|
|
7
|
+
import { findFilesViaRepoMap, rankFileCandidates, } from "../utils/repoMapIndex.js";
|
|
8
|
+
import { buildRecoveryQueries } from "../utils/pathRecovery.js";
|
|
9
|
+
const execFileAsync = promisify(execFile);
|
|
10
|
+
const MAX_READ_LINES = 500;
|
|
11
|
+
const normalizeRelativeInputPath = (value) => value.replace(/\\/g, "/").replace(/^\.\//, "").replace(/^\//, "");
|
|
12
|
+
const isPathInsideBase = (basePath, targetPath) => {
|
|
13
|
+
const relative = path.relative(basePath, targetPath);
|
|
14
|
+
return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative));
|
|
15
|
+
};
|
|
16
|
+
const findFileViaTerminal = async (cwd, query) => {
|
|
17
|
+
const normalizedQuery = normalizeRelativeInputPath(query);
|
|
18
|
+
const baseName = path.basename(normalizedQuery);
|
|
19
|
+
const attempts = [];
|
|
20
|
+
if (normalizedQuery && normalizedQuery !== baseName) {
|
|
21
|
+
attempts.push([
|
|
22
|
+
".",
|
|
23
|
+
"-type",
|
|
24
|
+
"f",
|
|
25
|
+
"-path",
|
|
26
|
+
`./${normalizedQuery}`,
|
|
27
|
+
]);
|
|
28
|
+
}
|
|
29
|
+
if (baseName) {
|
|
30
|
+
attempts.push([".", "-type", "f", "-name", baseName]);
|
|
31
|
+
}
|
|
32
|
+
for (const args of attempts) {
|
|
33
|
+
try {
|
|
34
|
+
const { stdout } = await execFileAsync("find", args, {
|
|
35
|
+
cwd,
|
|
36
|
+
maxBuffer: 1024 * 1024 * 4,
|
|
37
|
+
});
|
|
38
|
+
const firstMatch = stdout
|
|
39
|
+
.split(/\r?\n/)
|
|
40
|
+
.map((line) => line.trim())
|
|
41
|
+
.filter(Boolean);
|
|
42
|
+
const rankedMatches = await rankFileCandidates(cwd, query, firstMatch.map((match) => path.resolve(cwd, match)));
|
|
43
|
+
const bestMatch = rankedMatches[0];
|
|
44
|
+
if (bestMatch) {
|
|
45
|
+
return bestMatch;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
// Ignore and continue to next fallback strategy.
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return null;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Detect language from file extension
|
|
56
|
+
*/
|
|
57
|
+
function detectLanguage(filePath) {
|
|
58
|
+
const ext = path.extname(filePath).toLowerCase().replace(/^\./, "");
|
|
59
|
+
if (!ext) {
|
|
60
|
+
return "text";
|
|
61
|
+
}
|
|
62
|
+
switch (ext) {
|
|
63
|
+
case "js":
|
|
64
|
+
return "javascript";
|
|
65
|
+
case "jsx":
|
|
66
|
+
return "jsx";
|
|
67
|
+
case "ts":
|
|
68
|
+
return "typescript";
|
|
69
|
+
case "tsx":
|
|
70
|
+
return "tsx";
|
|
71
|
+
case "py":
|
|
72
|
+
return "python";
|
|
73
|
+
case "java":
|
|
74
|
+
return "java";
|
|
75
|
+
case "go":
|
|
76
|
+
return "go";
|
|
77
|
+
case "cpp":
|
|
78
|
+
return "cpp";
|
|
79
|
+
case "c":
|
|
80
|
+
return "c";
|
|
81
|
+
case "cs":
|
|
82
|
+
return "csharp";
|
|
83
|
+
case "rb":
|
|
84
|
+
return "ruby";
|
|
85
|
+
case "php":
|
|
86
|
+
return "php";
|
|
87
|
+
default:
|
|
88
|
+
return "text";
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Tool for reading file contents
|
|
93
|
+
* @param {Object} params - The parameters for reading a file
|
|
94
|
+
* @param {string} params.filePath - The path to the file to read
|
|
95
|
+
* @param {string} [params.encoding='utf8'] - The encoding to use when reading the file
|
|
96
|
+
* @param {boolean} [params.parseWithKnowledgeGraph=true] - Whether to parse file with knowledge graph
|
|
97
|
+
* @returns {Promise<Object>} Object containing success status and file content or error
|
|
98
|
+
*/
|
|
99
|
+
export async function readFile({ filePath, workspaceRoot, encoding = "utf8", parseWithKnowledgeGraph = true, startLine, endLine, withLineNumbers, }) {
|
|
100
|
+
try {
|
|
101
|
+
// Validate input
|
|
102
|
+
if (!filePath) {
|
|
103
|
+
return {
|
|
104
|
+
success: false,
|
|
105
|
+
error: "File path is required",
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
if ((startLine === undefined) !== (endLine === undefined)) {
|
|
109
|
+
return {
|
|
110
|
+
success: false,
|
|
111
|
+
error: "Both startLine and endLine must be provided together",
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
if (startLine !== undefined && endLine !== undefined) {
|
|
115
|
+
const validatedEndLine = endLine;
|
|
116
|
+
if (!Number.isInteger(startLine)
|
|
117
|
+
|| !Number.isInteger(validatedEndLine)
|
|
118
|
+
|| startLine < 1
|
|
119
|
+
|| validatedEndLine < 1) {
|
|
120
|
+
return {
|
|
121
|
+
success: false,
|
|
122
|
+
error: "startLine and endLine must be positive integers",
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (startLine !== undefined
|
|
127
|
+
&& endLine !== undefined
|
|
128
|
+
&& startLine > endLine) {
|
|
129
|
+
return {
|
|
130
|
+
success: false,
|
|
131
|
+
error: "startLine cannot be greater than endLine",
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
// Prefer the active workspace root when provided so reads keep working
|
|
135
|
+
// after the UI switches folders without changing the server cwd.
|
|
136
|
+
const effectiveWorkspaceRoot = workspaceRoot || process.cwd();
|
|
137
|
+
const absoluteWorkspaceRoot = path.resolve(effectiveWorkspaceRoot);
|
|
138
|
+
// If path is already absolute, use it; otherwise resolve from workspace root.
|
|
139
|
+
// Reads are allowed outside the workspace root when the resolved path is
|
|
140
|
+
// directly readable, so callers can inspect sibling repos and shared files.
|
|
141
|
+
const absolutePath = path.isAbsolute(filePath)
|
|
142
|
+
? path.resolve(filePath)
|
|
143
|
+
: path.join(effectiveWorkspaceRoot, filePath);
|
|
144
|
+
let readablePath = absolutePath;
|
|
145
|
+
let resolvedBy = "direct";
|
|
146
|
+
// Check if file exists
|
|
147
|
+
try {
|
|
148
|
+
await fs.access(readablePath, fs.constants.R_OK);
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
const recoveryQueries = buildRecoveryQueries(filePath, absoluteWorkspaceRoot);
|
|
152
|
+
let recoveredPath = null;
|
|
153
|
+
let recoveredByRepoMap = false;
|
|
154
|
+
for (const query of recoveryQueries) {
|
|
155
|
+
const fromRepoMap = await findFilesViaRepoMap(effectiveWorkspaceRoot, query, 1);
|
|
156
|
+
const recoveredPathCandidate = fromRepoMap[0] || (await findFileViaTerminal(effectiveWorkspaceRoot, query));
|
|
157
|
+
const safeRecoveredPath = recoveredPathCandidate
|
|
158
|
+
&& isPathInsideBase(absoluteWorkspaceRoot, path.resolve(recoveredPathCandidate))
|
|
159
|
+
? recoveredPathCandidate
|
|
160
|
+
: null;
|
|
161
|
+
if (safeRecoveredPath) {
|
|
162
|
+
recoveredPath = safeRecoveredPath;
|
|
163
|
+
recoveredByRepoMap = Boolean(fromRepoMap[0]);
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (!recoveredPath) {
|
|
168
|
+
return {
|
|
169
|
+
success: false,
|
|
170
|
+
error: `File not found or not readable: ${filePath}`,
|
|
171
|
+
attemptedPath: absolutePath,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
readablePath = recoveredPath;
|
|
175
|
+
resolvedBy = recoveredByRepoMap ? "repo_map" : "terminal_find";
|
|
176
|
+
}
|
|
177
|
+
// Get file stats
|
|
178
|
+
const stats = await fs.stat(readablePath);
|
|
179
|
+
if (!stats.isFile()) {
|
|
180
|
+
return {
|
|
181
|
+
success: false,
|
|
182
|
+
error: `Path is not a file: ${filePath}`,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
// Read file content
|
|
186
|
+
const fullContent = await fs.readFile(readablePath, encoding);
|
|
187
|
+
let content = fullContent;
|
|
188
|
+
let selectedStartLine;
|
|
189
|
+
let selectedEndLine;
|
|
190
|
+
let totalLines;
|
|
191
|
+
const shouldChunkText = encoding === "utf8" || encoding === "ascii";
|
|
192
|
+
if (shouldChunkText) {
|
|
193
|
+
const lines = fullContent.split("\n");
|
|
194
|
+
totalLines = lines.length;
|
|
195
|
+
const requestedStartLine = startLine ?? 1;
|
|
196
|
+
const requestedEndLine = endLine ?? totalLines;
|
|
197
|
+
if (requestedStartLine > totalLines) {
|
|
198
|
+
return {
|
|
199
|
+
success: false,
|
|
200
|
+
error: `Start line ${requestedStartLine} exceeds file length (${totalLines} lines)`,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
selectedStartLine = requestedStartLine;
|
|
204
|
+
selectedEndLine = Math.min(requestedEndLine, selectedStartLine + MAX_READ_LINES - 1, totalLines);
|
|
205
|
+
const selectedLines = lines.slice(selectedStartLine - 1, selectedEndLine);
|
|
206
|
+
const shouldAddLineNumbers = withLineNumbers ?? startLine !== undefined;
|
|
207
|
+
content = shouldAddLineNumbers
|
|
208
|
+
? selectedLines
|
|
209
|
+
.map((line, index) => `${selectedStartLine + index}:${line}`)
|
|
210
|
+
.join("\n")
|
|
211
|
+
: selectedLines.join("\n");
|
|
212
|
+
}
|
|
213
|
+
// Parse with knowledge graph if enabled and file is code
|
|
214
|
+
let parseResult = null;
|
|
215
|
+
const language = detectLanguage(readablePath);
|
|
216
|
+
const codeLanguages = [
|
|
217
|
+
"javascript",
|
|
218
|
+
"jsx",
|
|
219
|
+
"typescript",
|
|
220
|
+
"tsx",
|
|
221
|
+
"python",
|
|
222
|
+
"java",
|
|
223
|
+
"go",
|
|
224
|
+
];
|
|
225
|
+
if (parseWithKnowledgeGraph && codeLanguages.includes(language)) {
|
|
226
|
+
try {
|
|
227
|
+
knowledgeGraph.indexFile({
|
|
228
|
+
path: readablePath,
|
|
229
|
+
name: path.basename(readablePath),
|
|
230
|
+
content: fullContent,
|
|
231
|
+
language,
|
|
232
|
+
});
|
|
233
|
+
// Get code summary from knowledge graph
|
|
234
|
+
const node = knowledgeGraph.nodes.get(readablePath);
|
|
235
|
+
if (node) {
|
|
236
|
+
const parsedComponents = Array.from(knowledgeGraph.nodes.values())
|
|
237
|
+
.filter((n) => n.metadata.filePath === readablePath && n.id !== readablePath)
|
|
238
|
+
.map((n) => ({
|
|
239
|
+
type: n.type,
|
|
240
|
+
name: String(n.metadata.name || n.id.split(":").pop() || ""),
|
|
241
|
+
line: n.metadata.startLine,
|
|
242
|
+
}));
|
|
243
|
+
parseResult = {
|
|
244
|
+
parsed: true,
|
|
245
|
+
language,
|
|
246
|
+
components: parsedComponents,
|
|
247
|
+
tokenCount: node.tokenCount,
|
|
248
|
+
relationships: Array.from(node.relationships).map((rel) => ({
|
|
249
|
+
type: rel.type,
|
|
250
|
+
target: rel.nodeId,
|
|
251
|
+
})),
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
catch (parseError) {
|
|
256
|
+
const error = parseError;
|
|
257
|
+
console.error("Knowledge graph parsing error:", parseError);
|
|
258
|
+
parseResult = {
|
|
259
|
+
parsed: false,
|
|
260
|
+
error: error.message,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
return {
|
|
265
|
+
success: true,
|
|
266
|
+
filePath: readablePath,
|
|
267
|
+
resolvedBy,
|
|
268
|
+
content,
|
|
269
|
+
...(selectedStartLine !== undefined
|
|
270
|
+
? {
|
|
271
|
+
startLine: selectedStartLine,
|
|
272
|
+
endLine: selectedEndLine,
|
|
273
|
+
totalLines,
|
|
274
|
+
hasMore: selectedEndLine < totalLines,
|
|
275
|
+
...(selectedEndLine < totalLines
|
|
276
|
+
? {
|
|
277
|
+
nextStartLine: selectedEndLine + 1,
|
|
278
|
+
nextEndLine: Math.min(selectedEndLine + MAX_READ_LINES, totalLines),
|
|
279
|
+
}
|
|
280
|
+
: {}),
|
|
281
|
+
}
|
|
282
|
+
: {}),
|
|
283
|
+
size: stats.size,
|
|
284
|
+
lastModified: stats.mtime,
|
|
285
|
+
knowledgeGraph: parseResult,
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
catch (error) {
|
|
289
|
+
const err = error;
|
|
290
|
+
return {
|
|
291
|
+
success: false,
|
|
292
|
+
error: err.message,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Tool metadata for agent system
|
|
298
|
+
*/
|
|
299
|
+
export const readFileTool = {
|
|
300
|
+
name: "read_file",
|
|
301
|
+
description: "Read up to 500 lines of a file. Use startLine and endLine with the returned next range to continue reading large files",
|
|
302
|
+
parameters: z.object({
|
|
303
|
+
filePath: z
|
|
304
|
+
.string()
|
|
305
|
+
.describe("The path to the file to read (can be relative or absolute)"),
|
|
306
|
+
workspaceRoot: z
|
|
307
|
+
.string()
|
|
308
|
+
.optional()
|
|
309
|
+
.describe("Workspace root used for path validation and recovery"),
|
|
310
|
+
encoding: z
|
|
311
|
+
.enum(["utf8", "ascii", "base64", "binary", "hex"])
|
|
312
|
+
.default("utf8")
|
|
313
|
+
.describe("The encoding to use when reading the file"),
|
|
314
|
+
startLine: z
|
|
315
|
+
.number()
|
|
316
|
+
.int()
|
|
317
|
+
.positive()
|
|
318
|
+
.optional()
|
|
319
|
+
.describe("First line to return (1-based, inclusive). Must be provided together with endLine"),
|
|
320
|
+
endLine: z
|
|
321
|
+
.number()
|
|
322
|
+
.int()
|
|
323
|
+
.positive()
|
|
324
|
+
.optional()
|
|
325
|
+
.describe("Last line to return (1-based, inclusive). Must be provided together with startLine"),
|
|
326
|
+
withLineNumbers: z
|
|
327
|
+
.boolean()
|
|
328
|
+
.optional()
|
|
329
|
+
.describe("Prefix each returned line with its line number. Defaults to true when a range is requested"),
|
|
330
|
+
parseWithKnowledgeGraph: z
|
|
331
|
+
.boolean()
|
|
332
|
+
.default(true)
|
|
333
|
+
.describe("Whether to automatically parse code files with the knowledge graph for enhanced analysis"),
|
|
334
|
+
}),
|
|
335
|
+
execute: readFile,
|
|
336
|
+
};
|
|
337
|
+
export default readFileTool;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
type RenameFileParams = {
|
|
3
|
+
oldPath: string;
|
|
4
|
+
newPath: string;
|
|
5
|
+
overwrite?: boolean;
|
|
6
|
+
};
|
|
7
|
+
type RenameFileSuccessResult = {
|
|
8
|
+
success: true;
|
|
9
|
+
oldPath: string;
|
|
10
|
+
newPath: string;
|
|
11
|
+
size: number;
|
|
12
|
+
isMove: boolean;
|
|
13
|
+
message: string;
|
|
14
|
+
};
|
|
15
|
+
type RenameFileErrorResult = {
|
|
16
|
+
success: false;
|
|
17
|
+
error: string;
|
|
18
|
+
};
|
|
19
|
+
type RenameFileResult = RenameFileSuccessResult | RenameFileErrorResult;
|
|
20
|
+
/**
|
|
21
|
+
* Tool for renaming or moving files
|
|
22
|
+
* @param {Object} params - The parameters for renaming a file
|
|
23
|
+
* @param {string} params.oldPath - The current path of the file
|
|
24
|
+
* @param {string} params.newPath - The new path for the file
|
|
25
|
+
* @param {boolean} [params.overwrite=false] - Whether to overwrite if destination exists
|
|
26
|
+
* @returns {Promise<Object>} Object containing success status and rename info or error
|
|
27
|
+
*/
|
|
28
|
+
export declare function renameFile({ oldPath, newPath, overwrite, }: RenameFileParams): Promise<RenameFileResult>;
|
|
29
|
+
/**
|
|
30
|
+
* Tool metadata for agent system
|
|
31
|
+
*/
|
|
32
|
+
export declare const renameFileTool: {
|
|
33
|
+
description: string;
|
|
34
|
+
parameters: z.ZodObject<{
|
|
35
|
+
oldPath: z.ZodString;
|
|
36
|
+
newPath: z.ZodString;
|
|
37
|
+
overwrite: z.ZodDefault<z.ZodBoolean>;
|
|
38
|
+
}, "strip", z.ZodTypeAny, {
|
|
39
|
+
oldPath?: string;
|
|
40
|
+
newPath?: string;
|
|
41
|
+
overwrite?: boolean;
|
|
42
|
+
}, {
|
|
43
|
+
oldPath?: string;
|
|
44
|
+
newPath?: string;
|
|
45
|
+
overwrite?: boolean;
|
|
46
|
+
}>;
|
|
47
|
+
execute: typeof renameFile;
|
|
48
|
+
};
|
|
49
|
+
export default renameFileTool;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import fs from "fs/promises";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
/**
|
|
5
|
+
* Tool for renaming or moving files
|
|
6
|
+
* @param {Object} params - The parameters for renaming a file
|
|
7
|
+
* @param {string} params.oldPath - The current path of the file
|
|
8
|
+
* @param {string} params.newPath - The new path for the file
|
|
9
|
+
* @param {boolean} [params.overwrite=false] - Whether to overwrite if destination exists
|
|
10
|
+
* @returns {Promise<Object>} Object containing success status and rename info or error
|
|
11
|
+
*/
|
|
12
|
+
export async function renameFile({ oldPath, newPath, overwrite = false, }) {
|
|
13
|
+
try {
|
|
14
|
+
// Validate input
|
|
15
|
+
if (!oldPath || !newPath) {
|
|
16
|
+
return {
|
|
17
|
+
success: false,
|
|
18
|
+
error: "Both oldPath and newPath are required",
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
// Resolve to absolute paths
|
|
22
|
+
const absoluteOldPath = path.resolve(oldPath);
|
|
23
|
+
const absoluteNewPath = path.resolve(newPath);
|
|
24
|
+
// Check if source file exists
|
|
25
|
+
try {
|
|
26
|
+
await fs.access(absoluteOldPath, fs.constants.F_OK);
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
return {
|
|
30
|
+
success: false,
|
|
31
|
+
error: `Source file not found: ${oldPath}`,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
// Check if destination exists
|
|
35
|
+
try {
|
|
36
|
+
await fs.access(absoluteNewPath, fs.constants.F_OK);
|
|
37
|
+
if (!overwrite) {
|
|
38
|
+
return {
|
|
39
|
+
success: false,
|
|
40
|
+
error: `Destination already exists: ${newPath}. Set overwrite=true to replace.`,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
// Destination doesn't exist, which is fine
|
|
46
|
+
}
|
|
47
|
+
// Create destination directory if it doesn't exist
|
|
48
|
+
const destDir = path.dirname(absoluteNewPath);
|
|
49
|
+
await fs.mkdir(destDir, { recursive: true });
|
|
50
|
+
// Get file stats before moving
|
|
51
|
+
const stats = await fs.stat(absoluteOldPath);
|
|
52
|
+
// Rename/move the file
|
|
53
|
+
await fs.rename(absoluteOldPath, absoluteNewPath);
|
|
54
|
+
return {
|
|
55
|
+
success: true,
|
|
56
|
+
oldPath: absoluteOldPath,
|
|
57
|
+
newPath: absoluteNewPath,
|
|
58
|
+
size: stats.size,
|
|
59
|
+
isMove: path.dirname(absoluteOldPath) !== path.dirname(absoluteNewPath),
|
|
60
|
+
message: "File renamed/moved successfully",
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
const err = error;
|
|
65
|
+
return {
|
|
66
|
+
success: false,
|
|
67
|
+
error: err.message,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Tool metadata for agent system
|
|
73
|
+
*/
|
|
74
|
+
export const renameFileTool = {
|
|
75
|
+
description: "Rename or move a file to a new location",
|
|
76
|
+
parameters: z.object({
|
|
77
|
+
oldPath: z.string().describe("The current path of the file"),
|
|
78
|
+
newPath: z.string().describe("The new path for the file"),
|
|
79
|
+
overwrite: z
|
|
80
|
+
.boolean()
|
|
81
|
+
.default(false)
|
|
82
|
+
.describe("Whether to overwrite if destination exists"),
|
|
83
|
+
}),
|
|
84
|
+
execute: renameFile,
|
|
85
|
+
};
|
|
86
|
+
export default renameFileTool;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rename Symbol Tool
|
|
3
|
+
* Uses LSP to rename a symbol across the whole workspace.
|
|
4
|
+
*/
|
|
5
|
+
type RenameSymbolParams = {
|
|
6
|
+
filePath: string;
|
|
7
|
+
line: number;
|
|
8
|
+
character: number;
|
|
9
|
+
newName: string;
|
|
10
|
+
};
|
|
11
|
+
type FileChange = {
|
|
12
|
+
filePath: string;
|
|
13
|
+
editCount: number;
|
|
14
|
+
edits: Array<{
|
|
15
|
+
startLine: number;
|
|
16
|
+
startCharacter: number;
|
|
17
|
+
endLine: number;
|
|
18
|
+
endCharacter: number;
|
|
19
|
+
newText: string;
|
|
20
|
+
}>;
|
|
21
|
+
};
|
|
22
|
+
type RenameSymbolResult = {
|
|
23
|
+
success: true;
|
|
24
|
+
filePath: string;
|
|
25
|
+
position: {
|
|
26
|
+
line: number;
|
|
27
|
+
character: number;
|
|
28
|
+
};
|
|
29
|
+
newName: string;
|
|
30
|
+
totalFiles: number;
|
|
31
|
+
totalEdits: number;
|
|
32
|
+
files: FileChange[];
|
|
33
|
+
} | {
|
|
34
|
+
success: false;
|
|
35
|
+
message?: string;
|
|
36
|
+
error?: string;
|
|
37
|
+
filePath: string;
|
|
38
|
+
position: {
|
|
39
|
+
line: number;
|
|
40
|
+
character: number;
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
declare const renameSymbolTool: {
|
|
44
|
+
name: string;
|
|
45
|
+
description: string;
|
|
46
|
+
parameters: {
|
|
47
|
+
type: string;
|
|
48
|
+
properties: {
|
|
49
|
+
filePath: {
|
|
50
|
+
type: string;
|
|
51
|
+
description: string;
|
|
52
|
+
};
|
|
53
|
+
line: {
|
|
54
|
+
type: string;
|
|
55
|
+
description: string;
|
|
56
|
+
};
|
|
57
|
+
character: {
|
|
58
|
+
type: string;
|
|
59
|
+
description: string;
|
|
60
|
+
};
|
|
61
|
+
newName: {
|
|
62
|
+
type: string;
|
|
63
|
+
description: string;
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
required: string[];
|
|
67
|
+
};
|
|
68
|
+
execute({ filePath, line, character, newName }: RenameSymbolParams): Promise<RenameSymbolResult>;
|
|
69
|
+
};
|
|
70
|
+
export default renameSymbolTool;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rename Symbol Tool
|
|
3
|
+
* Uses LSP to rename a symbol across the whole workspace.
|
|
4
|
+
*/
|
|
5
|
+
import { coreLsp } from "../../library/lsp/coreLsp.js";
|
|
6
|
+
import fs from "fs/promises";
|
|
7
|
+
import { fileURLToPath } from "url";
|
|
8
|
+
const renameSymbolTool = {
|
|
9
|
+
name: "renameSymbol",
|
|
10
|
+
description: `Rename a symbol (variable, function, class, etc.) across the entire workspace using LSP.
|
|
11
|
+
Safely renames all references to the symbol at the given position.
|
|
12
|
+
|
|
13
|
+
Use this when you need to:
|
|
14
|
+
- Rename a function, class, or variable consistently everywhere it is used
|
|
15
|
+
- Refactor code with confidence that all call sites are updated
|
|
16
|
+
- Understand the full scope of a rename before applying it`,
|
|
17
|
+
parameters: {
|
|
18
|
+
type: "object",
|
|
19
|
+
properties: {
|
|
20
|
+
filePath: {
|
|
21
|
+
type: "string",
|
|
22
|
+
description: "Absolute path to the file containing the symbol",
|
|
23
|
+
},
|
|
24
|
+
line: {
|
|
25
|
+
type: "number",
|
|
26
|
+
description: "Line number (1-based) of the symbol to rename",
|
|
27
|
+
},
|
|
28
|
+
character: {
|
|
29
|
+
type: "number",
|
|
30
|
+
description: "Character position (1-based) on the line",
|
|
31
|
+
},
|
|
32
|
+
newName: {
|
|
33
|
+
type: "string",
|
|
34
|
+
description: "The new name for the symbol",
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
required: ["filePath", "line", "character", "newName"],
|
|
38
|
+
},
|
|
39
|
+
async execute({ filePath, line, character, newName }) {
|
|
40
|
+
try {
|
|
41
|
+
await fs.access(filePath);
|
|
42
|
+
const result = (await coreLsp.renameSymbol(filePath, line, character, newName));
|
|
43
|
+
if (!result) {
|
|
44
|
+
return {
|
|
45
|
+
success: false,
|
|
46
|
+
message: `No rename result for symbol at ${filePath}:${line}:${character}`,
|
|
47
|
+
filePath,
|
|
48
|
+
position: { line, character },
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
const files = [];
|
|
52
|
+
const processEdits = (uri, edits) => {
|
|
53
|
+
let filePath;
|
|
54
|
+
try {
|
|
55
|
+
filePath = uri.startsWith("file://") ? fileURLToPath(uri) : uri;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
filePath = uri.replace("file://", "");
|
|
59
|
+
}
|
|
60
|
+
files.push({
|
|
61
|
+
filePath,
|
|
62
|
+
editCount: edits.length,
|
|
63
|
+
edits: edits.map((edit) => ({
|
|
64
|
+
startLine: (edit.range?.start?.line ?? 0) + 1,
|
|
65
|
+
startCharacter: (edit.range?.start?.character ?? 0) + 1,
|
|
66
|
+
endLine: (edit.range?.end?.line ?? 0) + 1,
|
|
67
|
+
endCharacter: (edit.range?.end?.character ?? 0) + 1,
|
|
68
|
+
newText: edit.newText ?? newName,
|
|
69
|
+
})),
|
|
70
|
+
});
|
|
71
|
+
};
|
|
72
|
+
if (result.changes) {
|
|
73
|
+
for (const [uri, edits] of Object.entries(result.changes)) {
|
|
74
|
+
processEdits(uri, edits);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
else if (result.documentChanges) {
|
|
78
|
+
for (const change of result.documentChanges) {
|
|
79
|
+
if (change.textDocument?.uri) {
|
|
80
|
+
processEdits(change.textDocument.uri, change.edits ?? []);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const totalEdits = files.reduce((sum, f) => sum + f.editCount, 0);
|
|
85
|
+
return {
|
|
86
|
+
success: true,
|
|
87
|
+
filePath,
|
|
88
|
+
position: { line, character },
|
|
89
|
+
newName,
|
|
90
|
+
totalFiles: files.length,
|
|
91
|
+
totalEdits,
|
|
92
|
+
files,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
const err = error;
|
|
97
|
+
return {
|
|
98
|
+
success: false,
|
|
99
|
+
error: err.message,
|
|
100
|
+
filePath,
|
|
101
|
+
position: { line, character },
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
export default renameSymbolTool;
|