refactor: rombak arsitektur file ke modular clean-arch (vertikal per-feature)
Organisasi ulang layer-first (domain/application/infrastructure) menjadi vertikal per-feature, behavior tidak berubah: - src/shared/domain/ -> fondasi bersama (ex-domain/core): message, provider, tool_call, tool_result, store, error, usage, conversation - src/features/agent/ -> LLM turn loop: domain (TurnEvent, AgentTurnParams) + application (turn_service, ports) + infrastructure (llm LlmClient + tools) - src/features/cms/ -> settings/conversation/memory persistence: domain + application (services) + infrastructure (persistence repos) - src/features/subagent/ -> orchestration: domain (AccessTier) + infrastructure (engine runner, context, provider, delegate, spawn_tools) - src/features/workflow/ -> multi-phase + hive-mind: domain + infrastructure - src/interfaces/ -> cli + tui (outer ring) tetap Subagent-runner (engine.ts runAgent, division.ts toolsFor) dipindah ke features/subagent (bukan agent tools) utk memutus coupling agent<->subagent. Alias tsconfig: @zesdex/domain -> shared/domain, + @zesdex/agent, @zesdex/agent-infra, @zesdex/cms, @zesdex/subagent, @zesdex/workflow, @zesdex/shared. Bersihkan dead: application/ports PasswordService/TokenService/AuthService. compose.ts (composition root) & bootstrap repoint ke barrel feature. Gates: tsc --noEmit 0 error, bun test 70 pass/0 fail, bun build 147 modules, ./dist/zesdex --headless -> real turn OK.
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Background bash process output and kill tools.
|
||||
* Mirrors `tools/bash_tools.rs`.
|
||||
*/
|
||||
import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
import type { JsonValue } from "@zesdex/domain";
|
||||
import { type Tool, type ToolCtx } from "./mod.ts";
|
||||
import { argStr } from "./util.ts";
|
||||
import { bashControl } from "./bgbash/control.ts";
|
||||
|
||||
/** Get the output of a background bash job by ID. */
|
||||
export class BashOutput implements Tool {
|
||||
name = "bash_output";
|
||||
description = "Get the output of a background bash job by ID";
|
||||
|
||||
parameters = {
|
||||
type: "object",
|
||||
properties: {
|
||||
job_id: { type: "string", description: "Background job ID" },
|
||||
},
|
||||
required: ["job_id"],
|
||||
};
|
||||
|
||||
run(ctx: ToolCtx, args: JsonValue): string {
|
||||
const jobId = argStr(args, "job_id");
|
||||
|
||||
// Prevent path traversal
|
||||
if (jobId.includes("/") || jobId.includes("\\") || jobId.includes("..")) {
|
||||
throw new Error(`invalid job_id '${jobId}': must not contain path separators`);
|
||||
}
|
||||
|
||||
const outputDir = path.join(ctx.sessionDir, "bash-outputs");
|
||||
const outputFile = path.join(outputDir, jobId);
|
||||
|
||||
if (fs.existsSync(outputFile)) {
|
||||
try {
|
||||
const content = fs.readFileSync(outputFile, "utf8");
|
||||
return `Output for job '${jobId}':\n${content}`;
|
||||
} catch (e) {
|
||||
return `Error reading output: ${(e as Error).message}`;
|
||||
}
|
||||
}
|
||||
return `No output found for job '${jobId}'. The job may still be running.`;
|
||||
}
|
||||
}
|
||||
|
||||
/** Kill a background bash job by ID. */
|
||||
export class BashKill implements Tool {
|
||||
name = "bash_kill";
|
||||
description = "Kill a background bash job by ID";
|
||||
|
||||
parameters = {
|
||||
type: "object",
|
||||
properties: {
|
||||
job_id: { type: "string", description: "Background job ID to kill" },
|
||||
},
|
||||
required: ["job_id"],
|
||||
};
|
||||
|
||||
run(_ctx: ToolCtx, args: JsonValue): string {
|
||||
const jobId = argStr(args, "job_id");
|
||||
// Look up the job in the global bgbash registry.
|
||||
const cancelled = bashControl().cancel(jobId);
|
||||
if (!cancelled) {
|
||||
throw new Error(`no active background job found with ID '${jobId}'`);
|
||||
}
|
||||
return `Background job '${jobId}' killed.`;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user