glitool 1.0.0 ā 2.0.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 +115 -45
- package/dist/agent.js +234 -37
- package/dist/agents/coder.js +46 -34
- package/dist/agents/debugger.js +111 -0
- package/dist/agents/explainer.js +2 -5
- package/dist/agents/git-agent.js +90 -0
- package/dist/agents/graph.js +214 -23
- package/dist/agents/judge.js +61 -0
- package/dist/agents/planner.js +31 -10
- package/dist/agents/planningAgent.js +41 -0
- package/dist/agents/refactorer.js +97 -0
- package/dist/agents/reviewer-agent.js +87 -0
- package/dist/agents/reviewer.js +6 -9
- package/dist/agents/types.js +1 -0
- package/dist/agents/validator.js +93 -0
- package/dist/agents/workflow.js +45 -0
- package/dist/auth.js +87 -0
- package/dist/commands/version.js +1 -0
- package/dist/config.js +4 -1
- package/dist/confirmHandler.js +4 -2
- package/dist/index.js +12 -25
- package/dist/llm/classifier.js +61 -0
- package/dist/llm/factory.js +50 -0
- package/dist/llm/router.js +235 -14
- package/dist/llm/telemetry.js +18 -0
- package/dist/logger.js +25 -0
- package/dist/processEvents.js +1 -0
- package/dist/tools/bashTool.js +90 -0
- package/dist/tools/editFileTool.js +14 -3
- package/dist/tools/index.js +3 -1
- package/dist/tools/listFilesTool.js +19 -21
- package/dist/tools/processRegistry.js +36 -0
- package/dist/tools/readBackgroundOutput.js +29 -0
- package/dist/tools/readFileTool.js +64 -9
- package/dist/tools/searchCodeTool.js +14 -4
- package/dist/tools/webFetchTool.js +45 -0
- package/dist/tools/writeFileTool.js +9 -6
- package/dist/trust/riskScorer.js +29 -2
- package/dist/ui/App.js +384 -47
- package/dist/ui/AuthFlow.js +76 -0
- package/dist/ui/ConfirmCard.js +53 -0
- package/dist/ui/EscalationCard.js +22 -0
- package/dist/ui/ExplainCard.js +5 -0
- package/dist/ui/Pipeline.js +37 -0
- package/dist/ui/ProcessTrace.js +79 -0
- package/dist/ui/RoleRow.js +16 -0
- package/dist/ui/RoleRow.test.js +8 -0
- package/dist/ui/SlashPalette.js +32 -0
- package/dist/ui/StatusBar.js +44 -0
- package/dist/ui/ToolLog.js +62 -0
- package/dist/ui/Welcome.js +11 -0
- package/dist/ui/renderMarkdown.js +41 -0
- package/dist/ui/symbols.js +19 -0
- package/dist/ui/tokens.js +13 -0
- package/dist/version.js +1 -0
- package/package.json +27 -20
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
import { tool } from "@langchain/core/tools";
|
|
2
|
-
import {
|
|
2
|
+
import { execFileSync } from "child_process";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
export const searchCodeTool = tool(async ({ keyword }) => {
|
|
5
5
|
try {
|
|
6
|
-
const result =
|
|
7
|
-
|
|
6
|
+
const result = execFileSync('grep', [
|
|
7
|
+
'-rn',
|
|
8
|
+
keyword,
|
|
9
|
+
'--include=*.ts',
|
|
10
|
+
'--include=*.js',
|
|
11
|
+
'--include=*.json',
|
|
12
|
+
'--exclude-dir=node_modules',
|
|
13
|
+
'--exclude-dir=dist',
|
|
14
|
+
'--exclude-dir=.git',
|
|
15
|
+
'.'
|
|
16
|
+
], { cwd: process.cwd(), timeout: 10000, stdio: 'pipe' }).toString();
|
|
17
|
+
return result || 'No matches found.';
|
|
8
18
|
}
|
|
9
19
|
catch {
|
|
10
20
|
return 'No matches found.';
|
|
@@ -13,6 +23,6 @@ export const searchCodeTool = tool(async ({ keyword }) => {
|
|
|
13
23
|
name: 'searchCode',
|
|
14
24
|
description: 'Search for a keyword or function name across all project files. Returns file paths and line numbers where the keyword is found. Use this tool to quickly locate where a specific function or variable is used in the codebase.',
|
|
15
25
|
schema: z.object({
|
|
16
|
-
keyword: z.string().describe('The
|
|
26
|
+
keyword: z.string().describe('The keyword, function name, or pattern to search for in the codebase')
|
|
17
27
|
})
|
|
18
28
|
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { tool } from "@langchain/core/tools";
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import TurndownService from 'turndown';
|
|
4
|
+
const turndown = new TurndownService({ headingStyle: 'atx', codeBlockStyle: 'fenced' });
|
|
5
|
+
const MAX_CHARS = 20_000;
|
|
6
|
+
export const webFetchTool = tool(async ({ url }) => {
|
|
7
|
+
let parsed;
|
|
8
|
+
try {
|
|
9
|
+
parsed = new URL(url);
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return `Invalid URL: ${url}`;
|
|
13
|
+
}
|
|
14
|
+
if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {
|
|
15
|
+
return `BLOCKED: Only http/https URLs are allowed. Got: ${parsed.protocol}`;
|
|
16
|
+
}
|
|
17
|
+
let response;
|
|
18
|
+
try {
|
|
19
|
+
response = await fetch(url, {
|
|
20
|
+
headers: { 'User-Agent': 'glitool/1.0' },
|
|
21
|
+
signal: AbortSignal.timeout(15_000)
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
catch (err) {
|
|
25
|
+
return `Fetch failed: ${err.message}`;
|
|
26
|
+
}
|
|
27
|
+
if (!response.ok) {
|
|
28
|
+
return `HTTP ${response.status}: ${response.statusText}`;
|
|
29
|
+
}
|
|
30
|
+
const contentType = response.headers.get('content-type') ?? '';
|
|
31
|
+
if (contentType.includes('text/html')) {
|
|
32
|
+
const html = await response.text();
|
|
33
|
+
const markdown = turndown.turndown(html);
|
|
34
|
+
const trimmed = markdown.slice(0, MAX_CHARS);
|
|
35
|
+
return trimmed.length < markdown.length ? trimmed + '\n\n(content truncated at 20 00 chars)' : trimmed;
|
|
36
|
+
}
|
|
37
|
+
const text = await response.text();
|
|
38
|
+
return text.slice(0, MAX_CHARS);
|
|
39
|
+
}, {
|
|
40
|
+
name: 'webFetch',
|
|
41
|
+
description: 'Fetch a public URL and return its content as readable text. HTML pages are converted to markdown. Use for reading docs, changelogs, npm package pages, GitHub READMEs, or any public web resource. Only http/https allowed ā file:// and other schemes are blocked.',
|
|
42
|
+
schema: z.object({
|
|
43
|
+
url: z.string().describe('The full URL to fetch (must start with http:// or https://)')
|
|
44
|
+
})
|
|
45
|
+
});
|
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
import { tool } from "@langchain/core/tools";
|
|
2
|
-
import { confirm } from "@inquirer/prompts";
|
|
3
2
|
import fs from 'fs';
|
|
4
3
|
import path from 'path';
|
|
5
4
|
import { z } from 'zod';
|
|
6
5
|
import { requestConfirm } from "../confirmHandler.js";
|
|
6
|
+
import { log } from "../logger.js";
|
|
7
7
|
export const writeFileTool = tool(async ({ filePath, content }) => {
|
|
8
8
|
const projectRoot = process.cwd();
|
|
9
9
|
const fullPath = path.resolve(projectRoot, filePath);
|
|
10
10
|
if (!fullPath.startsWith(projectRoot + path.sep) && fullPath !== projectRoot) {
|
|
11
11
|
throw new Error('Access denied: cannot write outside project root');
|
|
12
12
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
log('write:before-confirm', { filePath });
|
|
14
|
+
const ok = await requestConfirm({
|
|
15
|
+
type: 'write',
|
|
16
|
+
filePath,
|
|
17
|
+
content,
|
|
18
|
+
risk: 'medium',
|
|
19
|
+
});
|
|
20
|
+
log('write:after-confirm', { filePath, ok });
|
|
18
21
|
if (!ok) {
|
|
19
22
|
return 'USER_CANCELLED: The user explicitly rejected this file write. Do NOT retry. Inform the user the write was cancelled.';
|
|
20
23
|
}
|
package/dist/trust/riskScorer.js
CHANGED
|
@@ -1,11 +1,30 @@
|
|
|
1
1
|
const HIGH_RISK_PATTERNS = [
|
|
2
2
|
/\.env/,
|
|
3
3
|
/\.env\.\w+/,
|
|
4
|
-
/package\.json$/,
|
|
5
|
-
/tsconfig\.json$/,
|
|
6
4
|
/docker-compose/,
|
|
7
5
|
/\.git\//,
|
|
8
6
|
];
|
|
7
|
+
const BLOCKED_SHELL_PATTERNS = [
|
|
8
|
+
/\brm\s+-rf?\s+\/(?!\w)/, // rm -rf / (not /something)
|
|
9
|
+
/\brm\s+-rf?\s+~(?!\w)/, // rm -rf ~
|
|
10
|
+
/\bsudo\b/,
|
|
11
|
+
/\|\s*(sh|bash|zsh)\b/, // piped to a shell ā curl | sh etc.
|
|
12
|
+
/:\s*\(\s*\)\s*\{.*\|.*&\s*\}\s*;\s*:/, // fork bomb
|
|
13
|
+
/\bdd\s+if=/, // dd block-level copy
|
|
14
|
+
/>\s*\/dev\/(sd[a-z]|hd[a-z]|nvme)/, // writing to disk devices
|
|
15
|
+
/\bmkfs\b/, // formatting disks
|
|
16
|
+
/\bchmod\s+-R\s+777\s+\//, // chmod 777 root
|
|
17
|
+
];
|
|
18
|
+
const CONFIRM_SHELL_PATTERNS = [
|
|
19
|
+
/\bgit\s+push\b/,
|
|
20
|
+
/\bgit\s+reset\s+--hard\b/,
|
|
21
|
+
/\bgit\s+rebase\b/,
|
|
22
|
+
/\bgit\s+(force-?push|push\s+-f)\b/,
|
|
23
|
+
/\bnpm\s+(publish|install|i|uninstall|un|rm|remove)\b/,
|
|
24
|
+
/\byarn\s+(add|remove|publish)\b/,
|
|
25
|
+
/\bpnpm\s+(add|remove|publish)\b/,
|
|
26
|
+
/\bdocker\s+(rm|rmi|kill|exec)\b/,
|
|
27
|
+
];
|
|
9
28
|
const LOW_RISK_TOOLS = ['listFiles', 'readFile', 'searchCode'];
|
|
10
29
|
export function scoreRisk(toolName, args) {
|
|
11
30
|
if (LOW_RISK_TOOLS.includes(toolName))
|
|
@@ -23,3 +42,11 @@ export function getRiskMessage(toolName, riskLevel, args) {
|
|
|
23
42
|
return `${toolName}${filePath ? ` -> ${filePath}` : ''}`;
|
|
24
43
|
return '';
|
|
25
44
|
}
|
|
45
|
+
export function scoreShellRisk(command) {
|
|
46
|
+
const trimmed = command.trim();
|
|
47
|
+
if (BLOCKED_SHELL_PATTERNS.some(p => p.test(trimmed)))
|
|
48
|
+
return 'block';
|
|
49
|
+
if (CONFIRM_SHELL_PATTERNS.some(p => p.test(trimmed)))
|
|
50
|
+
return 'confirm';
|
|
51
|
+
return 'allow';
|
|
52
|
+
}
|