@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,313 @@
|
|
|
1
|
+
import { spawn } from "child_process";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
const OUTPUT_LIMIT_BYTES = 64 * 1024;
|
|
4
|
+
const TERMINATION_GRACE_MS = 1500;
|
|
5
|
+
const TERMINAL_TASK_TTL_MS = 60 * 60 * 1000;
|
|
6
|
+
const MAX_TERMINAL_TASKS_RETAINED = 200;
|
|
7
|
+
const tasks = new Map();
|
|
8
|
+
let evictedTasksTotal = 0;
|
|
9
|
+
const getRetentionStats = () => ({
|
|
10
|
+
maxTerminalTasksRetained: MAX_TERMINAL_TASKS_RETAINED,
|
|
11
|
+
terminalTaskTtlMs: TERMINAL_TASK_TTL_MS,
|
|
12
|
+
evictedTasksTotal,
|
|
13
|
+
});
|
|
14
|
+
const sweepTerminalTasks = () => {
|
|
15
|
+
const now = Date.now();
|
|
16
|
+
const terminalEntries = Array.from(tasks.entries()).filter(([, task]) => ["completed", "failed", "stopped"].includes(task.status));
|
|
17
|
+
for (const [id, task] of terminalEntries) {
|
|
18
|
+
const terminalAt = task.endedAt || task.startedAt;
|
|
19
|
+
if (now - terminalAt > TERMINAL_TASK_TTL_MS) {
|
|
20
|
+
tasks.delete(id);
|
|
21
|
+
evictedTasksTotal += 1;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const remainingTerminal = Array.from(tasks.entries())
|
|
25
|
+
.filter(([, task]) => ["completed", "failed", "stopped"].includes(task.status))
|
|
26
|
+
.sort((a, b) => {
|
|
27
|
+
const aTime = a[1].endedAt || a[1].startedAt;
|
|
28
|
+
const bTime = b[1].endedAt || b[1].startedAt;
|
|
29
|
+
return bTime - aTime;
|
|
30
|
+
});
|
|
31
|
+
if (remainingTerminal.length > MAX_TERMINAL_TASKS_RETAINED) {
|
|
32
|
+
const overflow = remainingTerminal.slice(MAX_TERMINAL_TASKS_RETAINED);
|
|
33
|
+
for (const [id] of overflow) {
|
|
34
|
+
tasks.delete(id);
|
|
35
|
+
evictedTasksTotal += 1;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
const waitForProcessExit = async (child, timeoutMs) => {
|
|
40
|
+
if (child.exitCode !== null || child.signalCode !== null) {
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
return await new Promise((resolve) => {
|
|
44
|
+
let settled = false;
|
|
45
|
+
const finish = () => {
|
|
46
|
+
if (settled)
|
|
47
|
+
return;
|
|
48
|
+
settled = true;
|
|
49
|
+
clearTimeout(timer);
|
|
50
|
+
child.off("close", finish);
|
|
51
|
+
child.off("exit", finish);
|
|
52
|
+
resolve(true);
|
|
53
|
+
};
|
|
54
|
+
const timer = setTimeout(() => {
|
|
55
|
+
if (settled)
|
|
56
|
+
return;
|
|
57
|
+
settled = true;
|
|
58
|
+
child.off("close", finish);
|
|
59
|
+
child.off("exit", finish);
|
|
60
|
+
resolve(false);
|
|
61
|
+
}, timeoutMs);
|
|
62
|
+
child.once("close", finish);
|
|
63
|
+
child.once("exit", finish);
|
|
64
|
+
});
|
|
65
|
+
};
|
|
66
|
+
const taskKillOnWindows = async (pid, force) => {
|
|
67
|
+
return await new Promise((resolve) => {
|
|
68
|
+
const args = ["/PID", String(pid), "/T", ...(force ? ["/F"] : [])];
|
|
69
|
+
const killer = spawn("taskkill", args, {
|
|
70
|
+
windowsHide: true,
|
|
71
|
+
stdio: "ignore",
|
|
72
|
+
});
|
|
73
|
+
killer.on("error", () => resolve(false));
|
|
74
|
+
killer.on("close", (code) => resolve(code === 0));
|
|
75
|
+
});
|
|
76
|
+
};
|
|
77
|
+
const sendTerminationSignal = async (task, force) => {
|
|
78
|
+
const pid = task.pid;
|
|
79
|
+
if (!pid)
|
|
80
|
+
return false;
|
|
81
|
+
if (process.platform === "win32") {
|
|
82
|
+
return taskKillOnWindows(pid, force);
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
const signal = force ? "SIGKILL" : "SIGTERM";
|
|
86
|
+
if (task.usesProcessGroup) {
|
|
87
|
+
process.kill(-pid, signal);
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
process.kill(pid, signal);
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
const terminateTaskProcess = async (task) => {
|
|
98
|
+
const child = task.process;
|
|
99
|
+
if (!child)
|
|
100
|
+
return true;
|
|
101
|
+
await sendTerminationSignal(task, false);
|
|
102
|
+
let exited = await waitForProcessExit(child, TERMINATION_GRACE_MS);
|
|
103
|
+
if (exited)
|
|
104
|
+
return true;
|
|
105
|
+
await sendTerminationSignal(task, true);
|
|
106
|
+
exited = await waitForProcessExit(child, TERMINATION_GRACE_MS);
|
|
107
|
+
return exited;
|
|
108
|
+
};
|
|
109
|
+
export const __resetBackgroundTasksForTests = async () => {
|
|
110
|
+
const runningTasks = Array.from(tasks.values()).filter((task) => task.status === "running");
|
|
111
|
+
await Promise.all(runningTasks.map(async (task) => {
|
|
112
|
+
task.status = "stopped";
|
|
113
|
+
task.endedAt = Date.now();
|
|
114
|
+
task.stopReason = "Stopped by test reset";
|
|
115
|
+
appendTaskOutput(task, "\n[background-task-stop] Stopped by test reset\n");
|
|
116
|
+
await terminateTaskProcess(task);
|
|
117
|
+
}));
|
|
118
|
+
tasks.clear();
|
|
119
|
+
evictedTasksTotal = 0;
|
|
120
|
+
};
|
|
121
|
+
const trimUtf8TailToByteLimit = (input, maxBytes) => {
|
|
122
|
+
if (maxBytes <= 0)
|
|
123
|
+
return "";
|
|
124
|
+
const buffer = Buffer.from(input, "utf8");
|
|
125
|
+
if (buffer.length <= maxBytes) {
|
|
126
|
+
return input;
|
|
127
|
+
}
|
|
128
|
+
let start = buffer.length - maxBytes;
|
|
129
|
+
// Avoid starting in the middle of a UTF-8 continuation sequence.
|
|
130
|
+
while (start < buffer.length && (buffer[start] & 0b11000000) === 0b10000000) {
|
|
131
|
+
start += 1;
|
|
132
|
+
}
|
|
133
|
+
return buffer.subarray(start).toString("utf8");
|
|
134
|
+
};
|
|
135
|
+
const appendTaskOutput = (task, chunk) => {
|
|
136
|
+
if (!chunk)
|
|
137
|
+
return;
|
|
138
|
+
const nextOutput = task.output + chunk;
|
|
139
|
+
if (Buffer.byteLength(nextOutput, "utf8") <= OUTPUT_LIMIT_BYTES) {
|
|
140
|
+
task.output = nextOutput;
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
task.outputTruncated = true;
|
|
144
|
+
task.output = trimUtf8TailToByteLimit(nextOutput, OUTPUT_LIMIT_BYTES);
|
|
145
|
+
};
|
|
146
|
+
const makeTaskId = () => `task_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
147
|
+
export const startBackgroundTask = ({ command, cwd, env = {}, description, }) => {
|
|
148
|
+
sweepTerminalTasks();
|
|
149
|
+
const id = makeTaskId();
|
|
150
|
+
const usesProcessGroup = process.platform !== "win32";
|
|
151
|
+
const child = spawn(command, {
|
|
152
|
+
cwd,
|
|
153
|
+
env: { ...process.env, ...env },
|
|
154
|
+
shell: true,
|
|
155
|
+
detached: usesProcessGroup,
|
|
156
|
+
});
|
|
157
|
+
const task = {
|
|
158
|
+
id,
|
|
159
|
+
command,
|
|
160
|
+
cwd,
|
|
161
|
+
description: description || command,
|
|
162
|
+
status: "running",
|
|
163
|
+
startedAt: Date.now(),
|
|
164
|
+
output: "",
|
|
165
|
+
outputTruncated: false,
|
|
166
|
+
pid: child.pid,
|
|
167
|
+
process: child,
|
|
168
|
+
usesProcessGroup,
|
|
169
|
+
};
|
|
170
|
+
tasks.set(id, task);
|
|
171
|
+
child.stdout?.on("data", (data) => {
|
|
172
|
+
appendTaskOutput(task, data.toString());
|
|
173
|
+
});
|
|
174
|
+
child.stderr?.on("data", (data) => {
|
|
175
|
+
appendTaskOutput(task, data.toString());
|
|
176
|
+
});
|
|
177
|
+
child.on("error", (error) => {
|
|
178
|
+
appendTaskOutput(task, `\n[background-task-error] ${error.message}\n`);
|
|
179
|
+
task.status = "failed";
|
|
180
|
+
task.endedAt = Date.now();
|
|
181
|
+
task.exitCode = 1;
|
|
182
|
+
});
|
|
183
|
+
child.on("close", (code, signal) => {
|
|
184
|
+
if (task.status === "stopped") {
|
|
185
|
+
task.endedAt = task.endedAt || Date.now();
|
|
186
|
+
task.exitCode = code;
|
|
187
|
+
task.signal = signal;
|
|
188
|
+
task.process = undefined;
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
task.status = code === 0 ? "completed" : "failed";
|
|
192
|
+
task.endedAt = Date.now();
|
|
193
|
+
task.exitCode = code;
|
|
194
|
+
task.signal = signal;
|
|
195
|
+
task.process = undefined;
|
|
196
|
+
});
|
|
197
|
+
return {
|
|
198
|
+
success: true,
|
|
199
|
+
status: "in_progress",
|
|
200
|
+
taskId: id,
|
|
201
|
+
pid: child.pid,
|
|
202
|
+
command,
|
|
203
|
+
cwd,
|
|
204
|
+
description: task.description,
|
|
205
|
+
startedAt: task.startedAt,
|
|
206
|
+
message: `Started background task ${id}`,
|
|
207
|
+
};
|
|
208
|
+
};
|
|
209
|
+
export const listBackgroundTasks = ({ activeOnly = true, limit = 20, }) => {
|
|
210
|
+
sweepTerminalTasks();
|
|
211
|
+
const ordered = Array.from(tasks.values())
|
|
212
|
+
.filter((task) => (activeOnly ? task.status === "running" : true))
|
|
213
|
+
.sort((a, b) => b.startedAt - a.startedAt)
|
|
214
|
+
.slice(0, Math.max(1, Math.min(limit, 100)));
|
|
215
|
+
return ordered.map((task) => ({
|
|
216
|
+
taskId: task.id,
|
|
217
|
+
command: task.command,
|
|
218
|
+
description: task.description,
|
|
219
|
+
cwd: task.cwd,
|
|
220
|
+
status: task.status,
|
|
221
|
+
startedAt: task.startedAt,
|
|
222
|
+
endedAt: task.endedAt,
|
|
223
|
+
pid: task.pid,
|
|
224
|
+
exitCode: task.exitCode,
|
|
225
|
+
signal: task.signal,
|
|
226
|
+
retention: getRetentionStats(),
|
|
227
|
+
}));
|
|
228
|
+
};
|
|
229
|
+
export const getBackgroundTaskOutput = ({ taskId, tailChars = 3000, }) => {
|
|
230
|
+
sweepTerminalTasks();
|
|
231
|
+
const task = tasks.get(taskId);
|
|
232
|
+
if (!task) {
|
|
233
|
+
return {
|
|
234
|
+
success: false,
|
|
235
|
+
error: `Background task '${taskId}' not found`,
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
const normalizedTailChars = Math.max(256, Math.min(tailChars, 20000));
|
|
239
|
+
return {
|
|
240
|
+
success: true,
|
|
241
|
+
taskId,
|
|
242
|
+
status: task.status,
|
|
243
|
+
command: task.command,
|
|
244
|
+
description: task.description,
|
|
245
|
+
startedAt: task.startedAt,
|
|
246
|
+
endedAt: task.endedAt,
|
|
247
|
+
exitCode: task.exitCode,
|
|
248
|
+
signal: task.signal,
|
|
249
|
+
output: task.output.slice(-normalizedTailChars),
|
|
250
|
+
outputTruncated: task.outputTruncated || task.output.length > normalizedTailChars,
|
|
251
|
+
totalOutputChars: task.output.length,
|
|
252
|
+
retention: getRetentionStats(),
|
|
253
|
+
};
|
|
254
|
+
};
|
|
255
|
+
export const stopBackgroundTask = ({ taskId, reason = "Stopped by TaskStop", }) => {
|
|
256
|
+
sweepTerminalTasks();
|
|
257
|
+
const task = tasks.get(taskId);
|
|
258
|
+
if (!task) {
|
|
259
|
+
return {
|
|
260
|
+
success: false,
|
|
261
|
+
error: `Background task '${taskId}' not found`,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
if (task.status !== "running") {
|
|
265
|
+
return {
|
|
266
|
+
success: true,
|
|
267
|
+
taskId,
|
|
268
|
+
status: task.status,
|
|
269
|
+
message: `Task ${taskId} is already in terminal status '${task.status}'`,
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
task.status = "stopped";
|
|
273
|
+
task.endedAt = Date.now();
|
|
274
|
+
task.stopReason = reason;
|
|
275
|
+
appendTaskOutput(task, `\n[background-task-stop] ${reason}\n`);
|
|
276
|
+
return terminateTaskProcess(task).then((killed) => ({
|
|
277
|
+
success: true,
|
|
278
|
+
taskId,
|
|
279
|
+
status: task.status,
|
|
280
|
+
killed,
|
|
281
|
+
reason,
|
|
282
|
+
retention: getRetentionStats(),
|
|
283
|
+
message: `Stop signal sent to task ${taskId}`,
|
|
284
|
+
}));
|
|
285
|
+
};
|
|
286
|
+
export const taskListTool = {
|
|
287
|
+
description: "List background tasks started with runInBackground. Use activeOnly=true by default.",
|
|
288
|
+
parameters: z.object({
|
|
289
|
+
activeOnly: z.boolean().default(true),
|
|
290
|
+
limit: z.number().min(1).max(100).default(20),
|
|
291
|
+
}),
|
|
292
|
+
execute: async ({ activeOnly = true, limit = 20 }) => ({
|
|
293
|
+
success: true,
|
|
294
|
+
tasks: listBackgroundTasks({ activeOnly, limit }),
|
|
295
|
+
retention: getRetentionStats(),
|
|
296
|
+
}),
|
|
297
|
+
};
|
|
298
|
+
export const taskOutputTool = {
|
|
299
|
+
description: "Get non-blocking status and output snapshot for a background task.",
|
|
300
|
+
parameters: z.object({
|
|
301
|
+
taskId: z.string().describe("Background task ID"),
|
|
302
|
+
tailChars: z.number().min(256).max(20000).default(3000),
|
|
303
|
+
}),
|
|
304
|
+
execute: async ({ taskId, tailChars = 3000 }) => getBackgroundTaskOutput({ taskId, tailChars }),
|
|
305
|
+
};
|
|
306
|
+
export const taskStopTool = {
|
|
307
|
+
description: "Stop a running background task by task ID.",
|
|
308
|
+
parameters: z.object({
|
|
309
|
+
taskId: z.string().describe("Background task ID"),
|
|
310
|
+
reason: z.string().default("Stopped by TaskStop"),
|
|
311
|
+
}),
|
|
312
|
+
execute: async ({ taskId, reason = "Stopped by TaskStop" }) => await stopBackgroundTask({ taskId, reason }),
|
|
313
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
type CreateDirectoryParams = {
|
|
3
|
+
dirPath: string;
|
|
4
|
+
recursive?: boolean;
|
|
5
|
+
};
|
|
6
|
+
type CreateDirectorySuccessResult = {
|
|
7
|
+
success: true;
|
|
8
|
+
dirPath: string;
|
|
9
|
+
created?: Date;
|
|
10
|
+
alreadyExists: boolean;
|
|
11
|
+
message: string;
|
|
12
|
+
};
|
|
13
|
+
type CreateDirectoryErrorResult = {
|
|
14
|
+
success: false;
|
|
15
|
+
error: string;
|
|
16
|
+
};
|
|
17
|
+
type CreateDirectoryResult = CreateDirectorySuccessResult | CreateDirectoryErrorResult;
|
|
18
|
+
/**
|
|
19
|
+
* Tool for creating directories
|
|
20
|
+
* @param {Object} params - The parameters for creating a directory
|
|
21
|
+
* @param {string} params.dirPath - The path to the directory to create
|
|
22
|
+
* @param {boolean} [params.recursive=true] - Whether to create parent directories
|
|
23
|
+
* @returns {Promise<Object>} Object containing success status and directory info or error
|
|
24
|
+
*/
|
|
25
|
+
export declare function createDirectory({ dirPath, recursive, }: CreateDirectoryParams): Promise<CreateDirectoryResult>;
|
|
26
|
+
/**
|
|
27
|
+
* Tool metadata for agent system
|
|
28
|
+
*/
|
|
29
|
+
export declare const createDirectoryTool: {
|
|
30
|
+
description: string;
|
|
31
|
+
parameters: z.ZodObject<{
|
|
32
|
+
dirPath: z.ZodString;
|
|
33
|
+
recursive: z.ZodDefault<z.ZodBoolean>;
|
|
34
|
+
}, "strip", z.ZodTypeAny, {
|
|
35
|
+
recursive?: boolean;
|
|
36
|
+
dirPath?: string;
|
|
37
|
+
}, {
|
|
38
|
+
recursive?: boolean;
|
|
39
|
+
dirPath?: string;
|
|
40
|
+
}>;
|
|
41
|
+
execute: typeof createDirectory;
|
|
42
|
+
};
|
|
43
|
+
export default createDirectoryTool;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import fs from "fs/promises";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
/**
|
|
5
|
+
* Tool for creating directories
|
|
6
|
+
* @param {Object} params - The parameters for creating a directory
|
|
7
|
+
* @param {string} params.dirPath - The path to the directory to create
|
|
8
|
+
* @param {boolean} [params.recursive=true] - Whether to create parent directories
|
|
9
|
+
* @returns {Promise<Object>} Object containing success status and directory info or error
|
|
10
|
+
*/
|
|
11
|
+
export async function createDirectory({ dirPath, recursive = true, }) {
|
|
12
|
+
try {
|
|
13
|
+
// Validate input
|
|
14
|
+
if (!dirPath) {
|
|
15
|
+
return {
|
|
16
|
+
success: false,
|
|
17
|
+
error: "Directory path is required",
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
// Resolve to absolute path
|
|
21
|
+
const absolutePath = path.resolve(dirPath);
|
|
22
|
+
// Check if directory already exists
|
|
23
|
+
try {
|
|
24
|
+
const stats = await fs.stat(absolutePath);
|
|
25
|
+
if (stats.isDirectory()) {
|
|
26
|
+
return {
|
|
27
|
+
success: true,
|
|
28
|
+
dirPath: absolutePath,
|
|
29
|
+
alreadyExists: true,
|
|
30
|
+
message: "Directory already exists",
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
return {
|
|
35
|
+
success: false,
|
|
36
|
+
error: "Path exists but is not a directory",
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
// Directory doesn't exist, continue with creation
|
|
42
|
+
}
|
|
43
|
+
// Create the directory
|
|
44
|
+
await fs.mkdir(absolutePath, { recursive });
|
|
45
|
+
// Get directory stats
|
|
46
|
+
const stats = await fs.stat(absolutePath);
|
|
47
|
+
return {
|
|
48
|
+
success: true,
|
|
49
|
+
dirPath: absolutePath,
|
|
50
|
+
created: stats.birthtime,
|
|
51
|
+
alreadyExists: false,
|
|
52
|
+
message: "Directory created successfully",
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
const err = error;
|
|
57
|
+
return {
|
|
58
|
+
success: false,
|
|
59
|
+
error: err.message,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Tool metadata for agent system
|
|
65
|
+
*/
|
|
66
|
+
export const createDirectoryTool = {
|
|
67
|
+
description: "Create a new directory, optionally creating parent directories",
|
|
68
|
+
parameters: z.object({
|
|
69
|
+
dirPath: z.string().describe("The path to the directory to create"),
|
|
70
|
+
recursive: z
|
|
71
|
+
.boolean()
|
|
72
|
+
.default(true)
|
|
73
|
+
.describe("Whether to create parent directories if they don't exist"),
|
|
74
|
+
}),
|
|
75
|
+
execute: createDirectory,
|
|
76
|
+
};
|
|
77
|
+
export default createDirectoryTool;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
type DeleteFileParams = {
|
|
3
|
+
filePath: string;
|
|
4
|
+
};
|
|
5
|
+
type DeleteFileSuccessResult = {
|
|
6
|
+
success: true;
|
|
7
|
+
filePath: string;
|
|
8
|
+
deletedSize: number;
|
|
9
|
+
message: string;
|
|
10
|
+
};
|
|
11
|
+
type DeleteFileErrorResult = {
|
|
12
|
+
success: false;
|
|
13
|
+
error: string;
|
|
14
|
+
};
|
|
15
|
+
type DeleteFileResult = DeleteFileSuccessResult | DeleteFileErrorResult;
|
|
16
|
+
/**
|
|
17
|
+
* Tool for deleting files
|
|
18
|
+
* @param {Object} params - The parameters for deleting a file
|
|
19
|
+
* @param {string} params.filePath - The path to the file to delete
|
|
20
|
+
* @returns {Promise<Object>} Object containing success status and deletion info or error
|
|
21
|
+
*/
|
|
22
|
+
export declare function deleteFile({ filePath, }: DeleteFileParams): Promise<DeleteFileResult>;
|
|
23
|
+
/**
|
|
24
|
+
* Tool metadata for agent system
|
|
25
|
+
*/
|
|
26
|
+
export declare const deleteFileTool: {
|
|
27
|
+
description: string;
|
|
28
|
+
parameters: z.ZodObject<{
|
|
29
|
+
filePath: z.ZodString;
|
|
30
|
+
}, "strip", z.ZodTypeAny, {
|
|
31
|
+
filePath?: string;
|
|
32
|
+
}, {
|
|
33
|
+
filePath?: string;
|
|
34
|
+
}>;
|
|
35
|
+
execute: typeof deleteFile;
|
|
36
|
+
};
|
|
37
|
+
export default deleteFileTool;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import fs from "fs/promises";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
/**
|
|
5
|
+
* Tool for deleting files
|
|
6
|
+
* @param {Object} params - The parameters for deleting a file
|
|
7
|
+
* @param {string} params.filePath - The path to the file to delete
|
|
8
|
+
* @returns {Promise<Object>} Object containing success status and deletion info or error
|
|
9
|
+
*/
|
|
10
|
+
export async function deleteFile({ filePath, }) {
|
|
11
|
+
try {
|
|
12
|
+
// Validate input
|
|
13
|
+
if (!filePath) {
|
|
14
|
+
return {
|
|
15
|
+
success: false,
|
|
16
|
+
error: "File path is required",
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
// Resolve to absolute path
|
|
20
|
+
const absolutePath = path.resolve(filePath);
|
|
21
|
+
// Check if file exists
|
|
22
|
+
try {
|
|
23
|
+
await fs.access(absolutePath, fs.constants.F_OK);
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
return {
|
|
27
|
+
success: false,
|
|
28
|
+
error: `File not found: ${filePath}`,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
// Get file stats before deletion
|
|
32
|
+
const stats = await fs.stat(absolutePath);
|
|
33
|
+
if (!stats.isFile()) {
|
|
34
|
+
return {
|
|
35
|
+
success: false,
|
|
36
|
+
error: `Path is not a file: ${filePath}`,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
// Delete the file
|
|
40
|
+
await fs.unlink(absolutePath);
|
|
41
|
+
return {
|
|
42
|
+
success: true,
|
|
43
|
+
filePath: absolutePath,
|
|
44
|
+
deletedSize: stats.size,
|
|
45
|
+
message: "File deleted successfully",
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
const err = error;
|
|
50
|
+
return {
|
|
51
|
+
success: false,
|
|
52
|
+
error: err.message,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Tool metadata for agent system
|
|
58
|
+
*/
|
|
59
|
+
export const deleteFileTool = {
|
|
60
|
+
description: "Delete a file from the file system",
|
|
61
|
+
parameters: z.object({
|
|
62
|
+
filePath: z.string().describe("The path to the file to delete"),
|
|
63
|
+
}),
|
|
64
|
+
execute: deleteFile,
|
|
65
|
+
};
|
|
66
|
+
export default deleteFileTool;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
type EditFileParams = {
|
|
3
|
+
filePath: string;
|
|
4
|
+
oldContent?: string;
|
|
5
|
+
newContent?: string;
|
|
6
|
+
startLine?: number;
|
|
7
|
+
endLine?: number;
|
|
8
|
+
lineContent?: string;
|
|
9
|
+
encoding?: BufferEncoding;
|
|
10
|
+
};
|
|
11
|
+
type EditFileSuccessResult = {
|
|
12
|
+
success: true;
|
|
13
|
+
filePath: string;
|
|
14
|
+
fileExisted: true;
|
|
15
|
+
size: number;
|
|
16
|
+
modified: Date;
|
|
17
|
+
linesAdded: number;
|
|
18
|
+
linesRemoved: number;
|
|
19
|
+
diff: string;
|
|
20
|
+
oldContent: string;
|
|
21
|
+
newContent: string;
|
|
22
|
+
};
|
|
23
|
+
type EditFileErrorResult = {
|
|
24
|
+
success: false;
|
|
25
|
+
error: string;
|
|
26
|
+
};
|
|
27
|
+
type EditFileResult = EditFileSuccessResult | EditFileErrorResult;
|
|
28
|
+
/**
|
|
29
|
+
* Tool for editing files by replacing content or specific lines
|
|
30
|
+
* @param {Object} params - The parameters for editing a file
|
|
31
|
+
* @param {string} params.filePath - The path to the file to edit
|
|
32
|
+
* @param {string} [params.oldContent] - The old content to replace (must match exactly)
|
|
33
|
+
* @param {string} [params.newContent] - The new content to replace with
|
|
34
|
+
* @param {number} [params.startLine] - Starting line number to replace (1-indexed)
|
|
35
|
+
* @param {number} [params.endLine] - Ending line number to replace (1-indexed)
|
|
36
|
+
* @param {string} [params.lineContent] - New content for the line range
|
|
37
|
+
* @param {string} [params.encoding='utf8'] - The encoding to use
|
|
38
|
+
* @returns {Promise<Object>} Object containing success status and edit info or error
|
|
39
|
+
*/
|
|
40
|
+
export declare function editFile({ filePath, oldContent, newContent, startLine, endLine, lineContent, encoding, }: EditFileParams): Promise<EditFileResult>;
|
|
41
|
+
/**
|
|
42
|
+
* Tool metadata for agent system
|
|
43
|
+
*/
|
|
44
|
+
export declare const editFileTool: {
|
|
45
|
+
description: string;
|
|
46
|
+
parameters: z.ZodObject<{
|
|
47
|
+
filePath: z.ZodString;
|
|
48
|
+
oldContent: z.ZodOptional<z.ZodString>;
|
|
49
|
+
newContent: z.ZodOptional<z.ZodString>;
|
|
50
|
+
startLine: z.ZodOptional<z.ZodNumber>;
|
|
51
|
+
endLine: z.ZodOptional<z.ZodNumber>;
|
|
52
|
+
lineContent: z.ZodOptional<z.ZodString>;
|
|
53
|
+
encoding: z.ZodDefault<z.ZodEnum<["utf8", "ascii", "base64", "binary", "hex"]>>;
|
|
54
|
+
}, "strip", z.ZodTypeAny, {
|
|
55
|
+
encoding?: "ascii" | "utf8" | "base64" | "binary" | "hex";
|
|
56
|
+
filePath?: string;
|
|
57
|
+
startLine?: number;
|
|
58
|
+
endLine?: number;
|
|
59
|
+
oldContent?: string;
|
|
60
|
+
newContent?: string;
|
|
61
|
+
lineContent?: string;
|
|
62
|
+
}, {
|
|
63
|
+
encoding?: "ascii" | "utf8" | "base64" | "binary" | "hex";
|
|
64
|
+
filePath?: string;
|
|
65
|
+
startLine?: number;
|
|
66
|
+
endLine?: number;
|
|
67
|
+
oldContent?: string;
|
|
68
|
+
newContent?: string;
|
|
69
|
+
lineContent?: string;
|
|
70
|
+
}>;
|
|
71
|
+
execute: typeof editFile;
|
|
72
|
+
};
|
|
73
|
+
export default editFileTool;
|