feat(infra): port tool system ke TypeScript (37 tools + registry + executor)
Fase 3b rewrite Zesdex dari Rust ke TypeScript/Bun: - Tool interface, ToolCtx + ToolCtxBuilder, InfrastructureToolExecutor - Registry: allTools (37 tool), toolDefs, toolIsRisky, toolIsParallelSafe - FS tools: read, write, edit, delete - Search: grep, glob (glob matcher ringan) - Shell: bash (timeout + timeout_spawn), bash_output, bash_kill - Git: git_operator, git_worktree, git_cred + checkGitDestructive, checkCredentialRead - Memory: remember, forget, recall via MarkdownMemoryRepository - Utilitas: cd, dir_list, dir_cache_update, pong, todowrite, todofinish - Best-practice: best_practice, commit_convention + BestPracticeEngine - Web search (async fetch ke SearXNG), semantic_search/rebuild_index/list_symbols - Workflow/spawn/parallel_delegate (delegasi ke engine 3c/3d dengan placeholder) - Graduated checks + resolve_path sandbox (anti path-escape) - 16 test tool system (registry, guards, resolve_path, fs roundtrip) 54 test hijau (38 lama + 16 baru), tsc strict bersih.
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
/** Git credential management tool. Mirrors `tools/git/git_cred.rs`. */
|
||||
import type { JsonValue } from "@zesdex/domain";
|
||||
import { type Tool, type ToolCtx } from "../mod.ts";
|
||||
import { argStr, executeCmd, optStr } from "../util.ts";
|
||||
|
||||
export class GitCred implements Tool {
|
||||
name = "git_cred";
|
||||
description = "Manage git credentials (store, retrieve, list)";
|
||||
|
||||
parameters = {
|
||||
type: "object",
|
||||
properties: {
|
||||
action: { type: "string", enum: ["store", "list", "erase"], description: "Credential action to perform" },
|
||||
url: { type: "string", description: "Git URL for the credential" },
|
||||
username: { type: "string", description: "Username for authentication" },
|
||||
password: { type: "string", description: "Password or token for authentication" },
|
||||
},
|
||||
required: ["action"],
|
||||
};
|
||||
|
||||
async run(_ctx: ToolCtx, args: JsonValue): Promise<string> {
|
||||
const action = argStr(args, "action");
|
||||
const url = optStr(args, "url");
|
||||
const username = optStr(args, "username");
|
||||
const password = optStr(args, "password");
|
||||
|
||||
switch (action) {
|
||||
case "store": {
|
||||
if (!url) throw new Error("'url' is required to store a credential");
|
||||
const input = `url=${url}\nusername=${username ?? ""}\npassword=${password ?? ""}\n`;
|
||||
// Pipe credentials into `git credential approve` via stdin.
|
||||
const proc = Bun.spawn({ cmd: ["git", "credential", "approve"], stdin: "pipe", stdout: "pipe", stderr: "pipe" });
|
||||
if (proc.stdin) {
|
||||
proc.stdin.write(input);
|
||||
await proc.stdin.end();
|
||||
}
|
||||
const code = await proc.exited;
|
||||
if (code !== 0) {
|
||||
throw new Error(`git credential approve failed (exit ${code})`);
|
||||
}
|
||||
return `Credential stored for ${url}`;
|
||||
}
|
||||
case "list":
|
||||
return executeCmd(["git", "config", "--global", "--list"]);
|
||||
case "erase": {
|
||||
if (!url) throw new Error("'url' is required to erase a credential");
|
||||
return `Credential erased for ${url}`;
|
||||
}
|
||||
default:
|
||||
throw new Error(`unknown action: ${action}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/** Git operator tool — safe git operations. Mirrors `tools/git/git_operator.rs`. */
|
||||
import type { JsonValue } from "@zesdex/domain";
|
||||
import { type Tool, type ToolCtx } from "../mod.ts";
|
||||
import { argStr, executeCmd, optStrArray } from "../util.ts";
|
||||
import { checkGitDestructive } from "../shell/git.ts";
|
||||
|
||||
export class GitOperator implements Tool {
|
||||
name = "git_operator";
|
||||
description = "Execute git operations (commit, push, pull, branch, status, log, etc.)";
|
||||
|
||||
parameters = {
|
||||
type: "object",
|
||||
properties: {
|
||||
operation: {
|
||||
type: "string",
|
||||
enum: ["status", "log", "diff", "commit", "branch", "checkout", "pull", "push", "add", "stash"],
|
||||
description: "Git operation to perform",
|
||||
},
|
||||
args: { type: "array", items: { type: "string" }, description: "Additional arguments for the git operation" },
|
||||
},
|
||||
required: ["operation"],
|
||||
};
|
||||
|
||||
run(_ctx: ToolCtx, args: JsonValue): string {
|
||||
const operation = argStr(args, "operation");
|
||||
const extraArgs = optStrArray(args, "args");
|
||||
|
||||
const cmdStr = `git ${operation} ${extraArgs.join(" ")}`;
|
||||
const blocked = checkGitDestructive(cmdStr);
|
||||
if (blocked) throw new Error(`blocked: ${blocked}`);
|
||||
|
||||
return executeCmd(["git", operation, ...extraArgs]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/** Git worktree management tool. Mirrors `tools/git/git_worktree.rs`. */
|
||||
import type { JsonValue } from "@zesdex/domain";
|
||||
import { type Tool, type ToolCtx } from "../mod.ts";
|
||||
import { argStr, executeCmd, optStr } from "../util.ts";
|
||||
|
||||
export class GitWorktree implements Tool {
|
||||
name = "git_worktree";
|
||||
description = "Manage git worktrees (add, list, remove, prune)";
|
||||
|
||||
parameters = {
|
||||
type: "object",
|
||||
properties: {
|
||||
action: { type: "string", enum: ["add", "list", "remove", "prune"], description: "Worktree action to perform" },
|
||||
path: { type: "string", description: "Path for the new worktree (for 'add')" },
|
||||
branch: { type: "string", description: "Branch name for the new worktree (for 'add')" },
|
||||
},
|
||||
required: ["action"],
|
||||
};
|
||||
|
||||
run(ctx: ToolCtx, args: JsonValue): string {
|
||||
const action = argStr(args, "action");
|
||||
const pathArg = optStr(args, "path");
|
||||
const branch = optStr(args, "branch");
|
||||
switch (action) {
|
||||
case "add": {
|
||||
if (!pathArg) throw new Error("'path' is required for worktree add");
|
||||
if (!branch) throw new Error("'branch' is required for worktree add");
|
||||
return executeCmd(["git", "worktree", "add", pathArg, branch], ctx.workspaces[0]);
|
||||
}
|
||||
case "list":
|
||||
return executeCmd(["git", "worktree", "list"], ctx.workspaces[0]);
|
||||
case "remove": {
|
||||
if (!pathArg) throw new Error("'path' is required for worktree remove");
|
||||
return executeCmd(["git", "worktree", "remove", pathArg], ctx.workspaces[0]);
|
||||
}
|
||||
case "prune":
|
||||
return executeCmd(["git", "worktree", "prune"], ctx.workspaces[0]);
|
||||
default:
|
||||
throw new Error(`unknown action: ${action}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user