feat: Complete zCode CLI X with Telegram bot integration

- Add full Telegram bot functionality with Z.AI API integration
- Implement 4 tools: Bash, FileEdit, WebSearch, Git
- Add 3 agents: Code Reviewer, Architect, DevOps Engineer
- Add 6 skills for common coding tasks
- Add systemd service file for 24/7 operation
- Add nginx configuration for HTTPS webhook
- Add comprehensive documentation
- Implement WebSocket server for real-time updates
- Add logging system with Winston
- Add environment validation

🤖 zCode CLI X - Agentic coder with Z.AI + Telegram integration
This commit is contained in:
admin
2026-05-05 09:01:26 +00:00
Unverified
parent 4a7035dd92
commit 875c7f9b91
24688 changed files with 3224957 additions and 221 deletions

57
src/tools/BashTool.js Normal file
View File

@@ -0,0 +1,57 @@
import { logger } from '../utils/logger.js';
export class BashTool {
constructor() {
this.name = 'bash';
this.description = 'Execute shell commands';
}
async execute(command, options = {}) {
const { timeout = 300000, cwd = process.cwd() } = options;
logger.info(`🚀 Executing: ${command.substring(0, 100)}...`);
return new Promise((resolve, reject) => {
const proc = spawn(command, [], {
shell: true,
cwd,
timeout,
});
let stdout = '';
let stderr = '';
proc.stdout.on('data', (data) => {
stdout += data.toString();
});
proc.stderr.on('data', (data) => {
stderr += data.toString();
});
proc.on('close', (code) => {
if (code === 0) {
resolve({
success: true,
stdout: stdout.trim(),
stderr: stderr.trim(),
});
} else {
reject({
success: false,
stdout: stdout.trim(),
stderr: stderr.trim(),
code,
});
}
});
proc.on('error', (error) => {
reject({
success: false,
error: error.message,
});
});
});
}
}

85
src/tools/FileEditTool.js Normal file
View File

@@ -0,0 +1,85 @@
import { logger } from '../utils/logger.js';
import fs from 'fs-extra';
import path from 'path';
import { execa } from 'execa';
export class FileEditTool {
constructor() {
this.name = 'file_edit';
this.description = 'Edit files with diff-aware operations';
}
async read(filePath) {
const fullPath = path.resolve(filePath);
const content = await fs.readFile(fullPath, 'utf-8');
return {
success: true,
content,
path: fullPath,
};
}
async write(filePath, content) {
const fullPath = path.resolve(filePath);
await fs.ensureDir(path.dirname(fullPath));
await fs.writeFile(fullPath, content, 'utf-8');
return {
success: true,
path: fullPath,
};
}
async append(filePath, content) {
const fullPath = path.resolve(filePath);
await fs.appendFile(fullPath, content, 'utf-8');
return {
success: true,
path: fullPath,
};
}
async edit(filePath, oldText, newText) {
try {
const fullPath = path.resolve(filePath);
let content = await fs.readFile(fullPath, 'utf-8');
if (content.includes(oldText)) {
content = content.replace(oldText, newText);
await fs.writeFile(fullPath, content, 'utf-8');
return {
success: true,
path: fullPath,
changes: 1,
};
} else {
return {
success: false,
error: 'Text not found in file',
path: fullPath,
};
}
} catch (error) {
return {
success: false,
error: error.message,
};
}
}
async gitDiff(filePath) {
try {
const { stdout } = await execa('git', ['diff', '--no-color', filePath], {
cwd: process.cwd(),
});
return {
success: true,
diff: stdout,
};
} catch (error) {
return {
success: false,
error: error.message,
};
}
}
}

62
src/tools/GitTool.js Normal file
View File

@@ -0,0 +1,62 @@
import { logger } from '../utils/logger.js';
import { execa } from 'execa';
export class GitTool {
constructor() {
this.name = 'git';
this.description = 'Git operations';
}
async status() {
try {
const { stdout } = await execa('git', ['status', '--short'], {
cwd: process.cwd(),
});
return {
success: true,
status: stdout.trim() || 'clean',
};
} catch (error) {
return {
success: false,
error: 'Not a git repository',
};
}
}
async log(options = {}) {
const { lines = 10 } = options;
try {
const { stdout } = await execa('git', ['log', '--oneline', `-${lines}`], {
cwd: process.cwd(),
});
return {
success: true,
commits: stdout.trim().split('\n'),
};
} catch (error) {
return {
success: false,
error: 'Not a git repository',
};
}
}
async branch() {
try {
const { stdout } = await execa('git', ['branch', '--show-current'], {
cwd: process.cwd(),
});
return {
success: true,
branch: stdout.trim(),
};
} catch (error) {
return {
success: false,
error: 'Not a git repository',
};
}
}
}

View File

@@ -0,0 +1,57 @@
import { logger } from '../utils/logger.js';
import axios from 'axios';
export class WebSearchTool {
constructor() {
this.name = 'web_search';
this.description = 'Search the web for information';
}
async search(query, options = {}) {
const { numResults = 5 } = options;
logger.info(`🔍 Searching web: ${query.substring(0, 100)}...`);
try {
// Use DuckDuckGo API (free, no key required)
const response = await axios.get(
'https://api.duckduckgo.com/',
{
params: {
q: query,
format: 'json',
},
timeout: 30000,
}
);
const abstract = response.data.Abstract;
const relatedTopics = response.data.RelatedTopics || [];
const results = [
...(abstract ? [{ title: 'Abstract', snippet: abstract, url: response.data.RelatedTopics?.[0]?.FirstURL }] : []),
...relatedTopics
.filter(t => t.FirstURL)
.slice(0, numResults - 1)
.map(t => ({
title: t.Text,
snippet: t.FirstURL,
url: t.FirstURL,
})),
];
return {
success: true,
query,
results,
count: results.length,
};
} catch (error) {
logger.error('Web search error:', error.message);
return {
success: false,
error: error.message,
};
}
}
}

42
src/tools/index.js Normal file
View File

@@ -0,0 +1,42 @@
import { logger } from '../utils/logger.js';
import { BashTool } from './BashTool.js';
import { FileEditTool } from './FileEditTool.js';
import { WebSearchTool } from './WebSearchTool.js';
import { GitTool } from './GitTool.js';
export async function initTools() {
const tools = [];
// Bash tool
if (process.env.ZCODE_ENABLE_BASH !== 'false') {
const bashTool = new BashTool();
tools.push(bashTool);
logger.info(`✓ Bash tool loaded`);
}
// File edit tool
if (process.env.ZCODE_ENABLE_FILE_EDIT !== 'false') {
const fileEditTool = new FileEditTool();
tools.push(fileEditTool);
logger.info(`✓ File edit tool loaded`);
}
// Web search tool
if (process.env.ZCODE_ENABLE_WEB_SEARCH !== 'false') {
const webSearchTool = new WebSearchTool();
tools.push(webSearchTool);
logger.info(`✓ Web search tool loaded`);
}
// Git tool
if (process.env.ZCODE_ENABLE_GIT !== 'false') {
const gitTool = new GitTool();
tools.push(gitTool);
logger.info(`✓ Git tool loaded`);
}
return tools;
}
// Export tool classes
export { BashTool, FileEditTool, WebSearchTool, GitTool };