@takimcizgisi/ajan 0.5.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/LICENSE +227 -0
- package/README.md +324 -0
- package/config/models.json +50 -0
- package/out/ajan-engine.js +8306 -0
- package/package.json +84 -0
- package/src/client/client.ts +289 -0
- package/src/config/configManager.ts +300 -0
- package/src/config/types.ts +139 -0
- package/src/core/agent.ts +379 -0
- package/src/daemon/gpu.ts +54 -0
- package/src/daemon/main.ts +87 -0
- package/src/daemon/runner.ts +261 -0
- package/src/daemon/server.ts +231 -0
- package/src/engine/llama.ts +329 -0
- package/src/engine/modelManager.ts +84 -0
- package/src/index.ts +63 -0
- package/src/protocol/channel.ts +151 -0
- package/src/protocol/messages.ts +138 -0
- package/src/service.ts +410 -0
- package/src/tools/data.ts +101 -0
- package/src/tools/edit.ts +54 -0
- package/src/tools/file.ts +261 -0
- package/src/tools/filesys.ts +70 -0
- package/src/tools/memory.ts +76 -0
- package/src/tools/patch.ts +138 -0
- package/src/tools/playground.ts +130 -0
- package/src/tools/registry.ts +79 -0
- package/src/tools/taskComplete.ts +34 -0
- package/src/tools/terminal.ts +138 -0
- package/src/tools/utils.ts +63 -0
- package/src/tools/web.ts +204 -0
- package/src/utils/paths.ts +80 -0
- package/src/utils/projectContext.ts +23 -0
- package/src/utils/sessions.ts +91 -0
- package/src/version.ts +4 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { mkdirSync, appendFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
|
|
5
|
+
export type LogLevel = "silent" | "error" | "warn" | "info" | "debug";
|
|
6
|
+
|
|
7
|
+
let currentLevel: LogLevel = "info";
|
|
8
|
+
|
|
9
|
+
export function setLogLevel(level: LogLevel): void {
|
|
10
|
+
currentLevel = level;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const levelOrder: Record<LogLevel, number> = {
|
|
14
|
+
silent: 0,
|
|
15
|
+
error: 1,
|
|
16
|
+
warn: 2,
|
|
17
|
+
info: 3,
|
|
18
|
+
debug: 4
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/** Her seviyedeki logu (debug dahil) diskteki günlüğe de yazar. */
|
|
22
|
+
function writeLogFile(level: string, prefix: string, ...args: unknown[]): void {
|
|
23
|
+
try {
|
|
24
|
+
const line = `[${new Date().toISOString()}] [${level}] ${prefix} ${args
|
|
25
|
+
.map((a) => (typeof a === "string" ? a : JSON.stringify(a)))
|
|
26
|
+
.join(" ")}\n`;
|
|
27
|
+
appendFileSync(join(getLogDir(), "ajan.log"), line);
|
|
28
|
+
} catch {
|
|
29
|
+
/* log dosyasına yazılamazsa sessizce geç */
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function log(level: LogLevel, tag: string, ...args: unknown[]): void {
|
|
34
|
+
const prefix = `[${tag}]`;
|
|
35
|
+
if (levelOrder[level] <= levelOrder[currentLevel]) {
|
|
36
|
+
if (level === "error") {
|
|
37
|
+
console.error(prefix, ...args);
|
|
38
|
+
} else if (level === "warn") {
|
|
39
|
+
console.warn(prefix, ...args);
|
|
40
|
+
} else {
|
|
41
|
+
console.log(prefix, ...args);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
writeLogFile(level, prefix, ...args);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export const logger = {
|
|
48
|
+
error: (...args: unknown[]) => log("error", "hata", ...args),
|
|
49
|
+
warn: (...args: unknown[]) => log("warn", "uyari", ...args),
|
|
50
|
+
info: (...args: unknown[]) => log("info", "bilgi", ...args),
|
|
51
|
+
debug: (...args: unknown[]) => log("debug", "debug", ...args)
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export function getDataDir(): string {
|
|
55
|
+
const base = process.env.AJAN_HOME ?? join(os.homedir(), ".ajan");
|
|
56
|
+
mkdirSync(base, { recursive: true });
|
|
57
|
+
return base;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function getModelsDir(): string {
|
|
61
|
+
const dir = join(getDataDir(), "models");
|
|
62
|
+
mkdirSync(dir, { recursive: true });
|
|
63
|
+
return dir;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function getConfigPath(): string {
|
|
67
|
+
return join(getDataDir(), "config.json");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function getCacheDir(): string {
|
|
71
|
+
const dir = join(getDataDir(), "cache");
|
|
72
|
+
mkdirSync(dir, { recursive: true });
|
|
73
|
+
return dir;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function getLogDir(): string {
|
|
77
|
+
const dir = join(getDataDir(), "logs");
|
|
78
|
+
mkdirSync(dir, { recursive: true });
|
|
79
|
+
return dir;
|
|
80
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
const MAX_CONTEXT_CHARS = 20_000;
|
|
5
|
+
|
|
6
|
+
const CANDIDATES = ["AGENTS.md", "AJAN.md"] as const;
|
|
7
|
+
|
|
8
|
+
/** cwd içinde AGENTS.md veya AJAN.md varsa içeriğini sistem promptuna eklenebilir metin olarak döndürür */
|
|
9
|
+
export function loadProjectContext(cwd: string): string {
|
|
10
|
+
for (const name of CANDIDATES) {
|
|
11
|
+
const file = join(cwd, name);
|
|
12
|
+
if (!existsSync(file)) continue;
|
|
13
|
+
try {
|
|
14
|
+
const content = readFileSync(file, "utf8").trim();
|
|
15
|
+
if (!content) return "";
|
|
16
|
+
const limited = content.length > MAX_CONTEXT_CHARS ? `${content.slice(0, MAX_CONTEXT_CHARS)}\n... [proje notları kesildi]` : content;
|
|
17
|
+
return `\n\n--- PROJE NOTLARI (${name}) ---\n${limited}\n--- PROJE NOTLARI SONU ---`;
|
|
18
|
+
} catch {
|
|
19
|
+
/* okunamayan not dosyasını yut */
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return "";
|
|
23
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { promises as fs } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import type { ChatHistoryItem } from "node-llama-cpp";
|
|
4
|
+
import { getDataDir } from "./paths.js";
|
|
5
|
+
|
|
6
|
+
export type StoredMessage = {
|
|
7
|
+
kind: "user" | "assistant" | "thought" | "info" | "tool";
|
|
8
|
+
text?: string;
|
|
9
|
+
name?: string;
|
|
10
|
+
state?: "running" | "done" | "error";
|
|
11
|
+
startedAt?: number;
|
|
12
|
+
elapsed?: number;
|
|
13
|
+
output?: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export type TodoItem = {
|
|
17
|
+
text: string;
|
|
18
|
+
done: boolean;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export type StoredSession = {
|
|
22
|
+
id: string;
|
|
23
|
+
title: string;
|
|
24
|
+
mode: string;
|
|
25
|
+
createdAt: string;
|
|
26
|
+
updatedAt: string;
|
|
27
|
+
history: ChatHistoryItem[];
|
|
28
|
+
messages: StoredMessage[];
|
|
29
|
+
todos?: TodoItem[];
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const ID_RE = /^[A-Za-z0-9._-]+$/;
|
|
33
|
+
|
|
34
|
+
function sessionsDir(): string {
|
|
35
|
+
return path.join(getDataDir(), "sessions");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function sessionPath(id: string): string {
|
|
39
|
+
return path.join(sessionsDir(), `${id}.json`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function isValidId(id: string): boolean {
|
|
43
|
+
return ID_RE.test(id) && !id.includes("..");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function generateSessionId(date = new Date()): string {
|
|
47
|
+
const p = (n: number): string => String(n).padStart(2, "0");
|
|
48
|
+
return `${date.getFullYear()}${p(date.getMonth() + 1)}${p(date.getDate())}-${p(date.getHours())}${p(date.getMinutes())}${p(date.getSeconds())}`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export async function saveSession(session: StoredSession): Promise<void> {
|
|
52
|
+
await fs.mkdir(sessionsDir(), { recursive: true });
|
|
53
|
+
await fs.writeFile(sessionPath(session.id), JSON.stringify(session, null, 2), "utf8");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export async function loadSession(id: string): Promise<StoredSession | null> {
|
|
57
|
+
if (!isValidId(id)) return null;
|
|
58
|
+
try {
|
|
59
|
+
const raw = await fs.readFile(sessionPath(id), "utf8");
|
|
60
|
+
const data = JSON.parse(raw) as StoredSession;
|
|
61
|
+
if (!data || typeof data !== "object" || typeof data.id !== "string") return null;
|
|
62
|
+
return data;
|
|
63
|
+
} catch {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export async function deleteSession(id: string): Promise<void> {
|
|
69
|
+
if (!isValidId(id)) return;
|
|
70
|
+
try {
|
|
71
|
+
await fs.rm(sessionPath(id), { force: true });
|
|
72
|
+
} catch {
|
|
73
|
+
/* yok say */
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export async function listSessions(): Promise<StoredSession[]> {
|
|
78
|
+
try {
|
|
79
|
+
const entries = await fs.readdir(sessionsDir());
|
|
80
|
+
const sessions: StoredSession[] = [];
|
|
81
|
+
for (const entry of entries) {
|
|
82
|
+
if (!entry.endsWith(".json")) continue;
|
|
83
|
+
const data = await loadSession(entry.slice(0, -5));
|
|
84
|
+
if (data) sessions.push(data);
|
|
85
|
+
}
|
|
86
|
+
sessions.sort((a, b) => (a.updatedAt < b.updatedAt ? 1 : -1));
|
|
87
|
+
return sessions;
|
|
88
|
+
} catch {
|
|
89
|
+
return [];
|
|
90
|
+
}
|
|
91
|
+
}
|
package/src/version.ts
ADDED