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:
asepharyana
2026-09-03 02:30:12 +07:00
parent 7e6ed34f0d
commit b5ebd07fa8
126 changed files with 157 additions and 166 deletions
-8
View File
@@ -1,8 +0,0 @@
/**
* Zesdex Application Layer — port traits, use cases, turn service.
* Depends only on @zesdex/domain. Higher-level ports implemented by
* infrastructure adapters.
*/
export * from "./ports/index.ts";
export * from "./agent/index.ts";
export * from "./cms/index.ts";
-7
View File
@@ -1,7 +0,0 @@
/**
* Re-export of conversation types from core (matches Rust `cms/conversation.rs`).
*/
export type { Conversation } from "../core/conversation.ts";
export type { ChatMessage, Role } from "../core/message.ts";
export { newConversation, pushMessage, rebuildSystem, toApiMessages } from "../core/conversation.ts";
export { Roles } from "../core/message.ts";
-9
View File
@@ -1,9 +0,0 @@
/**
* Zesdex Domain Layer — pure types, value objects, and port interfaces.
* Zero framework dependencies, zero I/O. Mirrors the Rust `zesdex-domain` crate.
*/
export * from "./core/index.ts";
export * from "./cms/index.ts";
export * from "./agent/index.ts";
export * from "./subagent/mod.ts";
export * from "./workflow/mod.ts";
@@ -14,7 +14,7 @@ export interface ToolExecutor {
/** Service for running agent turns asynchronously. */
export interface AgentTurnService {
runTurn(params: import("@zesdex/domain").AgentTurnParams): Promise<void>;
runTurn(params: import("@zesdex/agent").AgentTurnParams): Promise<void>;
}
export * from "./turn_service.ts";
@@ -1,6 +1,7 @@
/**
* Port traits (interfaces) to external services. Mirrors `apps/application/src/ports/`.
* Concrete implementations live in the infrastructure layer.
* Port traits (interfaces) that the Agent application layer exposes to
* its infrastructure. Concrete implementations live in
* `features/agent/infrastructure/`.
*/
import type { ChatMessage, StreamEvent, ToolDef } from "@zesdex/domain";
@@ -31,23 +32,3 @@ export interface ProviderService {
signal?: AbortSignal,
): Promise<{ message: ChatMessage; usage: [number, number] | null }>;
}
/** Abstraction for password hashing and verification. */
export interface PasswordService {
hash(password: string): Promise<string>;
verify(password: string, hash: string): Promise<boolean>;
}
/** Abstraction for JWT-based token generation and verification. */
export interface TokenService {
/** Generate an `[access, refresh]` token pair for the given subject. */
generateTokens(sub: string): [string, string];
verifyAccessToken(token: string): string;
verifyRefreshToken(token: string): string;
}
/** High-level authentication service combining password + token issuance. */
export interface AuthService {
authenticate(password: string, hash: string): Promise<boolean>;
issueTokens(sub: string): [string, string];
}
@@ -3,23 +3,25 @@
* `apps/application/src/agent/turn_service.rs`.
*/
import {
type AgentTurnParams,
type ChatMessage,
type StreamEvent,
type ToolCall,
type ToolDef,
type TurnEventSink,
type JsonValue,
systemMessage,
userMessage,
assistantMessage,
toolResultMessage,
sanitizeToolArguments,
} from "@zesdex/domain";
import {
type AgentTurnParams,
type TurnEventSink,
mainAgentPromptWithProjectContext,
compactionPrompt,
errorRecoveryNote,
sanitizeToolArguments,
} from "@zesdex/domain";
import type { ProviderService } from "../ports/index.ts";
} from "@zesdex/agent";
import type { ProviderService } from "./ports.ts";
import type { ToolExecutor } from "./index.ts";
/* -------------------------------------------------------------------------- */
@@ -2,7 +2,7 @@
* Domain types for agent lifecycle: turn events, session runtime, progress.
* Mirrors `apps/domain/src/agent/mod.rs`.
*/
import type { ChatMessage, JsonValue, ToolCallResult, UsageStats } from "../core/index.ts";
import type { ChatMessage, JsonValue, ToolCallResult, UsageStats } from "@zesdex/domain";
import type { AgentProgress } from "./progress.ts";
/** Which kind of caller (main agent vs subagent vs reviewer) is invoking a tool. */
+5
View File
@@ -0,0 +1,5 @@
/** Agent feature — LLM turn loop, tool-execution runtime, subagent-spawning tools.
* Vertical slice: domain (turn events/runtime) → application (turn service + ports)
* → infrastructure (LLM client + tool registry/executor). */
export * from "./domain/index.ts";
export * from "./application/index.ts";
@@ -0,0 +1,6 @@
/** Agent infrastructure — concrete LLM client + tool-execution runtime.
* Consumed by the composition root. */
export { LlmClient, resolveApiKey } from "./llm/provider.ts";
export { InfrastructureToolExecutor } from "./tools/executor.ts";
export { allTools, toolDefs } from "./tools/registry.ts";
export { type ToolCtx } from "./tools/context.ts";
@@ -8,14 +8,12 @@ import {
type StreamEvent,
type ToolCall,
type ToolDef,
type Settings,
type AppConfig,
SseParser,
Roles,
DEFAULT_API_BASE,
DEFAULT_MODEL,
} from "@zesdex/domain";
import type { ProviderService } from "@zesdex/application";
import type { Settings, AppConfig } from "@zesdex/cms";
import { DEFAULT_API_BASE, DEFAULT_MODEL } from "@zesdex/agent";
import type { ProviderService } from "../../application/ports.ts";
const DEFAULT_BASE_URL = DEFAULT_API_BASE;
const REQUEST_TIMEOUT_MS = 600_000;
@@ -7,7 +7,7 @@ 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";
import { bashControl } from "./bgbash/control.ts";
/** Get the output of a background bash job by ID. */
export class BashOutput implements Tool {
@@ -2,8 +2,8 @@
* Built-in best-practice tools. Mirrors `tools/best_practice.rs`.
*/
import type { JsonValue } from "@zesdex/domain";
import { type Tool, type ToolCtx } from "../tools/mod.ts";
import { argStr, optStr } from "../tools/util.ts";
import { type Tool, type ToolCtx } from "../mod.ts";
import { argStr, optStr } from "../util.ts";
import { BestPracticeEngine } from "./engine.ts";
const engine = new BestPracticeEngine();
@@ -2,7 +2,7 @@
* Tool execution context — shared state passed to every `Tool.run` call.
* Mirrors `apps/infrastructure/src/tools/context.rs`.
*/
import type { Origin, TurnEvent } from "@zesdex/domain";
import type { Origin, TurnEvent } from "@zesdex/agent";
/** Graduated check rule from project config. */
export interface GraduatedCheck {
@@ -2,7 +2,7 @@
* Simple sink adapter that wraps a TurnEvent[] (array-based) into the
* TurnEventSink interface, providing a `push` method and a no-op `drain`.
*/
import type { TurnEvent, TurnEventSink } from "@zesdex/domain";
import type { TurnEvent, TurnEventSink } from "@zesdex/agent";
/**
* Create a TurnEventSink backed by a plain array.
@@ -2,7 +2,7 @@
* Delete a memory by name. Mirrors `tools/memory/forget.rs`.
*/
import type { JsonValue } from "@zesdex/domain";
import { MarkdownMemoryRepository } from "../../persistence/cms/memory_repo.ts";
import { MarkdownMemoryRepository } from "@zesdex/cms";
import { type Tool, type ToolCtx } from "../mod.ts";
import { argStr } from "../util.ts";
import { resolveMemoryDir } from "./mod.ts";
@@ -2,7 +2,7 @@
* Recall previously saved memories. Mirrors `tools/memory/recall.rs`.
*/
import type { JsonValue } from "@zesdex/domain";
import { MarkdownMemoryRepository } from "../../persistence/cms/memory_repo.ts";
import { MarkdownMemoryRepository } from "@zesdex/cms";
import { type Tool, type ToolCtx } from "../mod.ts";
import { optStr } from "../util.ts";
import { resolveMemoryDir } from "./mod.ts";
@@ -2,7 +2,7 @@
* Remember a lesson or fact as persistent memory. Mirrors `tools/memory/remember.rs`.
*/
import type { JsonValue } from "@zesdex/domain";
import { MarkdownMemoryRepository } from "../../persistence/cms/memory_repo.ts";
import { MarkdownMemoryRepository } from "@zesdex/cms";
import { type Tool, type ToolCtx } from "../mod.ts";
import { argStr, optStr } from "../util.ts";
import { resolveMemoryDir } from "./mod.ts";
@@ -59,7 +59,7 @@ export class ParallelDelegate implements Tool {
// Delegate to subagent engine if available, else report the breakdown.
try {
const { runParallelDelegation } = await import("../subagent/delegate.ts");
const { runParallelDelegation } = await import("../../../subagent/infrastructure/delegate.ts");
return await runParallelDelegation(task, directives, synthesize, ctx);
} catch (e) {
const msg = (e as Error).message;
@@ -1,7 +1,8 @@
/** Plan management tools — enter and mark ready. Mirrors `tools/plan.rs`. */
import * as fs from "node:fs";
import * as path from "node:path";
import type { JsonValue, TurnEvent } from "@zesdex/domain";
import type { JsonValue } from "@zesdex/domain";
import type { TurnEvent } from "@zesdex/agent";
import { type Tool, type ToolCtx } from "./mod.ts";
import { argStr } from "./util.ts";
@@ -25,7 +25,7 @@ import { Cd, DirList, DirCacheUpdate, Pong, Todowrite, Todofinish } from "./util
import { WebSearch } from "./web_search.ts";
import { SemanticSearch, RebuildIndex, ListSymbols } from "./semantic/index.ts";
import { ParallelDelegate } from "./parallel_delegate.ts";
import { BestPractice, CommitConvention } from "../best_practice/tools.ts";
import { BestPractice, CommitConvention } from "./best_practice/tools.ts";
/** Construct one instance of every built-in tool. */
export function allTools(): Tool[] {
@@ -39,8 +39,8 @@ export class Bash implements Tool {
if (runInBackground) {
// Background jobs handled via bgbash registry
const { spawnBashJob } = await import("../../bgbash/job.ts");
const { bashControl } = await import("../../bgbash/control.ts");
const { spawnBashJob } = await import("../bgbash/job.ts");
const { bashControl } = await import("../bgbash/control.ts");
const job = spawnBashJob(cmd);
bashControl().register(job);
return `Background job: ${job.id}`;
@@ -33,7 +33,7 @@ export class SpawnAgents implements Tool {
async run(ctx: ToolCtx, args: JsonValue): Promise<string> {
const agents = reqArray(args, "agents");
try {
const { spawnAgents } = await import("../subagent/spawn_tools.ts");
const { spawnAgents } = await import("../../../subagent/infrastructure/spawn_tools.ts");
return await spawnAgents(agents as Array<{ directive: string; access: string }>, ctx);
} catch (e) {
const msg = (e as Error).message;
@@ -71,7 +71,7 @@ export class SpawnPipeline implements Tool {
async run(ctx: ToolCtx, args: JsonValue): Promise<string> {
const stages = reqArray(args, "stages");
try {
const { spawnPipeline } = await import("../subagent/spawn_tools.ts");
const { spawnPipeline } = await import("../../../subagent/infrastructure/spawn_tools.ts");
return await spawnPipeline(stages as Array<{ directive: string; access: string }>, ctx);
} catch (e) {
const msg = (e as Error).message;

Some files were not shown because too many files have changed in this diff Show More