atabey 0.0.7 → 0.0.9
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/README.md +1 -1
- package/dist/framework-mcp/src/resources/index.js +2 -2
- package/dist/framework-mcp/src/resources/index.js.map +1 -1
- package/dist/framework-mcp/src/utils/errors.d.ts +46 -0
- package/dist/framework-mcp/src/utils/errors.js +69 -0
- package/dist/framework-mcp/src/utils/errors.js.map +1 -0
- package/dist/framework-mcp/src/utils/memory.d.ts +3 -0
- package/dist/framework-mcp/src/utils/memory.js +75 -0
- package/dist/framework-mcp/src/utils/memory.js.map +1 -0
- package/dist/framework-mcp/src/utils/storage.d.ts +60 -0
- package/dist/framework-mcp/src/utils/storage.js +208 -0
- package/dist/framework-mcp/src/utils/storage.js.map +1 -0
- package/dist/framework-mcp/src/utils/types.d.ts +19 -0
- package/dist/framework-mcp/src/utils/types.js +13 -0
- package/dist/framework-mcp/src/utils/types.js.map +1 -0
- package/dist/src/cli/adapters/core.js +12 -19
- package/dist/src/cli/adapters/core.js.map +1 -1
- package/dist/src/shared/constants.d.ts +1 -0
- package/dist/src/shared/constants.js +1 -0
- package/dist/src/shared/constants.js.map +1 -1
- package/dist/tests/adapter.test.js +3 -2
- package/dist/tests/adapter.test.js.map +1 -1
- package/framework-mcp/dist/constants.js +64 -0
- package/framework-mcp/dist/framework-mcp/src/constants.js +64 -0
- package/framework-mcp/dist/framework-mcp/src/index.js +144 -0
- package/framework-mcp/dist/framework-mcp/src/resources/index.js +58 -0
- package/framework-mcp/dist/framework-mcp/src/tools/control_plane/locking.js +82 -0
- package/framework-mcp/dist/framework-mcp/src/tools/control_plane/registry.js +35 -0
- package/framework-mcp/dist/framework-mcp/src/tools/definitions.js +322 -0
- package/framework-mcp/dist/framework-mcp/src/tools/file_system/batch_surgical_edit.js +64 -0
- package/framework-mcp/dist/framework-mcp/src/tools/file_system/patch_file.js +34 -0
- package/framework-mcp/dist/framework-mcp/src/tools/file_system/read_file.js +51 -0
- package/framework-mcp/dist/framework-mcp/src/tools/file_system/replace_text.js +50 -0
- package/framework-mcp/dist/framework-mcp/src/tools/file_system/write_file.js +43 -0
- package/framework-mcp/dist/framework-mcp/src/tools/framework/audit_deps.js +41 -0
- package/framework-mcp/dist/framework-mcp/src/tools/framework/get_status.js +5 -0
- package/framework-mcp/dist/framework-mcp/src/tools/framework/orchestrate.js +5 -0
- package/framework-mcp/dist/framework-mcp/src/tools/framework/run_tests.js +27 -0
- package/framework-mcp/dist/framework-mcp/src/tools/framework/submit_plan.js +13 -0
- package/framework-mcp/dist/framework-mcp/src/tools/framework/update_contract_hash.js +5 -0
- package/framework-mcp/dist/framework-mcp/src/tools/framework/update_memory.js +8 -0
- package/framework-mcp/dist/framework-mcp/src/tools/index.js +62 -0
- package/framework-mcp/dist/framework-mcp/src/tools/memory/get_insights.js +34 -0
- package/framework-mcp/dist/framework-mcp/src/tools/memory/read_memory.js +28 -0
- package/framework-mcp/dist/framework-mcp/src/tools/messaging/log_action.js +22 -0
- package/framework-mcp/dist/framework-mcp/src/tools/messaging/send_message.js +94 -0
- package/framework-mcp/dist/framework-mcp/src/tools/observability/check_ports.js +26 -0
- package/framework-mcp/dist/framework-mcp/src/tools/observability/get_health.js +19 -0
- package/framework-mcp/dist/framework-mcp/src/tools/quality/check_lint.js +30 -0
- package/framework-mcp/dist/framework-mcp/src/tools/search/get_gaps.js +48 -0
- package/framework-mcp/dist/framework-mcp/src/tools/search/get_map.js +43 -0
- package/framework-mcp/dist/framework-mcp/src/tools/search/grep_search.js +75 -0
- package/framework-mcp/dist/framework-mcp/src/tools/search/list_dir.js +28 -0
- package/framework-mcp/dist/framework-mcp/src/tools/shell/run_command.js +56 -0
- package/framework-mcp/dist/framework-mcp/src/tools/types.js +1 -0
- package/framework-mcp/dist/framework-mcp/src/utils/cli.js +59 -0
- package/framework-mcp/dist/framework-mcp/src/utils/compliance.js +231 -0
- package/framework-mcp/dist/framework-mcp/src/utils/errors.js +68 -0
- package/framework-mcp/dist/framework-mcp/src/utils/fs.js +44 -0
- package/framework-mcp/dist/framework-mcp/src/utils/memory.js +74 -0
- package/framework-mcp/dist/framework-mcp/src/utils/metrics.js +56 -0
- package/framework-mcp/dist/framework-mcp/src/utils/permissions.js +71 -0
- package/framework-mcp/dist/framework-mcp/src/utils/security.js +60 -0
- package/framework-mcp/dist/framework-mcp/src/utils/storage.js +207 -0
- package/framework-mcp/dist/framework-mcp/src/utils/types.js +12 -0
- package/framework-mcp/dist/index.js +144 -0
- package/framework-mcp/dist/resources/index.js +58 -0
- package/framework-mcp/dist/src/cli/adapters/core.js +71 -0
- package/framework-mcp/dist/src/cli/adapters/index.js +5 -0
- package/framework-mcp/dist/src/cli/adapters/paths.js +101 -0
- package/framework-mcp/dist/src/cli/adapters/scaffold.js +71 -0
- package/framework-mcp/dist/src/cli/adapters/utils.js +75 -0
- package/framework-mcp/dist/src/cli/commands/approve.js +63 -0
- package/framework-mcp/dist/src/cli/commands/check.js +181 -0
- package/framework-mcp/dist/src/cli/commands/compliance.js +50 -0
- package/framework-mcp/dist/src/cli/commands/contract.js +50 -0
- package/framework-mcp/dist/src/cli/commands/dashboard.js +123 -0
- package/framework-mcp/dist/src/cli/commands/explorer.js +42 -0
- package/framework-mcp/dist/src/cli/commands/git.js +40 -0
- package/framework-mcp/dist/src/cli/commands/init/create-agent.js +58 -0
- package/framework-mcp/dist/src/cli/commands/init/scaffold-core.js +112 -0
- package/framework-mcp/dist/src/cli/commands/init/scaffold-docs.js +34 -0
- package/framework-mcp/dist/src/cli/commands/init/scaffold-ops.js +80 -0
- package/framework-mcp/dist/src/cli/commands/init/scaffold-standards.js +67 -0
- package/framework-mcp/dist/src/cli/commands/init.js +167 -0
- package/framework-mcp/dist/src/cli/commands/knowledge.js +42 -0
- package/framework-mcp/dist/src/cli/commands/lint.js +22 -0
- package/framework-mcp/dist/src/cli/commands/log.js +10 -0
- package/framework-mcp/dist/src/cli/commands/memory.js +4 -0
- package/framework-mcp/dist/src/cli/commands/orchestrate.js +159 -0
- package/framework-mcp/dist/src/cli/commands/plan.js +117 -0
- package/framework-mcp/dist/src/cli/commands/script.js +19 -0
- package/framework-mcp/dist/src/cli/commands/security.js +36 -0
- package/framework-mcp/dist/src/cli/commands/status.js +97 -0
- package/framework-mcp/dist/src/cli/commands/trace.js +109 -0
- package/framework-mcp/dist/src/cli/index.js +338 -0
- package/framework-mcp/dist/src/cli/shims.js +66 -0
- package/framework-mcp/dist/src/cli/utils/claude.js +56 -0
- package/framework-mcp/dist/src/cli/utils/compliance.js +173 -0
- package/framework-mcp/dist/src/cli/utils/config-schema.js +42 -0
- package/framework-mcp/dist/src/cli/utils/fs.js +137 -0
- package/framework-mcp/dist/src/cli/utils/i18n.js +30 -0
- package/framework-mcp/dist/src/cli/utils/memory.js +276 -0
- package/framework-mcp/dist/src/cli/utils/pkg.js +282 -0
- package/framework-mcp/dist/src/cli/utils/schemas.js +19 -0
- package/framework-mcp/dist/src/cli/utils/string.js +49 -0
- package/framework-mcp/dist/src/cli/utils/time.js +27 -0
- package/framework-mcp/dist/src/cli/utils/ui.js +58 -0
- package/framework-mcp/dist/src/contracts/index.js +1 -0
- package/framework-mcp/dist/src/contracts/tasks.js +20 -0
- package/framework-mcp/dist/src/dashboard/vite.config.js +15 -0
- package/framework-mcp/dist/src/modules/adapters/definitions.js +140 -0
- package/framework-mcp/dist/src/modules/adapters/registry.js +18 -0
- package/framework-mcp/dist/src/modules/adapters/shared.js +104 -0
- package/framework-mcp/dist/src/modules/adapters/types.js +1 -0
- package/framework-mcp/dist/src/modules/agents/definitions.js +457 -0
- package/framework-mcp/dist/src/modules/agents/registry/analyst.js +39 -0
- package/framework-mcp/dist/src/modules/agents/registry/architect.js +42 -0
- package/framework-mcp/dist/src/modules/agents/registry/backend.js +49 -0
- package/framework-mcp/dist/src/modules/agents/registry/database.js +45 -0
- package/framework-mcp/dist/src/modules/agents/registry/devops.js +45 -0
- package/framework-mcp/dist/src/modules/agents/registry/explorer.js +36 -0
- package/framework-mcp/dist/src/modules/agents/registry/frontend.js +51 -0
- package/framework-mcp/dist/src/modules/agents/registry/git.js +36 -0
- package/framework-mcp/dist/src/modules/agents/registry/manager.js +53 -0
- package/framework-mcp/dist/src/modules/agents/registry/mobile.js +39 -0
- package/framework-mcp/dist/src/modules/agents/registry/native.js +39 -0
- package/framework-mcp/dist/src/modules/agents/registry/quality.js +41 -0
- package/framework-mcp/dist/src/modules/agents/registry/security.js +43 -0
- package/framework-mcp/dist/src/modules/agents/types.js +1 -0
- package/framework-mcp/dist/src/modules/engines/evaluation-engine.js +102 -0
- package/framework-mcp/dist/src/modules/engines/health-engine.js +49 -0
- package/framework-mcp/dist/src/modules/engines/planning-engine.js +78 -0
- package/framework-mcp/dist/src/modules/engines/risk-engine.js +105 -0
- package/framework-mcp/dist/src/modules/engines/routing-engine.js +73 -0
- package/framework-mcp/dist/src/modules/engines/types.js +1 -0
- package/framework-mcp/dist/src/modules/skills/definitions.js +70 -0
- package/framework-mcp/dist/src/shared/constants.js +187 -0
- package/framework-mcp/dist/src/shared/errors.js +68 -0
- package/framework-mcp/dist/src/shared/fs.js +51 -0
- package/framework-mcp/dist/src/shared/logger.js +116 -0
- package/framework-mcp/dist/src/shared/storage.js +207 -0
- package/framework-mcp/dist/src/shared/types.js +12 -0
- package/framework-mcp/dist/tools/control_plane/locking.js +82 -0
- package/framework-mcp/dist/tools/control_plane/registry.js +35 -0
- package/framework-mcp/dist/tools/definitions.js +322 -0
- package/framework-mcp/dist/tools/file_system/batch_surgical_edit.js +64 -0
- package/framework-mcp/dist/tools/file_system/patch_file.js +34 -0
- package/framework-mcp/dist/tools/file_system/read_file.js +51 -0
- package/framework-mcp/dist/tools/file_system/replace_text.js +50 -0
- package/framework-mcp/dist/tools/file_system/write_file.js +43 -0
- package/framework-mcp/dist/tools/framework/audit_deps.js +41 -0
- package/framework-mcp/dist/tools/framework/get_status.js +5 -0
- package/framework-mcp/dist/tools/framework/orchestrate.js +5 -0
- package/framework-mcp/dist/tools/framework/run_tests.js +27 -0
- package/framework-mcp/dist/tools/framework/submit_plan.js +13 -0
- package/framework-mcp/dist/tools/framework/update_contract_hash.js +5 -0
- package/framework-mcp/dist/tools/framework/update_memory.js +8 -0
- package/framework-mcp/dist/tools/index.js +62 -0
- package/framework-mcp/dist/tools/memory/get_insights.js +34 -0
- package/framework-mcp/dist/tools/memory/read_memory.js +28 -0
- package/framework-mcp/dist/tools/messaging/log_action.js +22 -0
- package/framework-mcp/dist/tools/messaging/send_message.js +94 -0
- package/framework-mcp/dist/tools/observability/check_ports.js +26 -0
- package/framework-mcp/dist/tools/observability/get_health.js +19 -0
- package/framework-mcp/dist/tools/quality/check_lint.js +30 -0
- package/framework-mcp/dist/tools/search/get_gaps.js +48 -0
- package/framework-mcp/dist/tools/search/get_map.js +43 -0
- package/framework-mcp/dist/tools/search/grep_search.js +75 -0
- package/framework-mcp/dist/tools/search/list_dir.js +28 -0
- package/framework-mcp/dist/tools/shell/run_command.js +56 -0
- package/framework-mcp/dist/tools/types.js +1 -0
- package/framework-mcp/dist/utils/cli.js +59 -0
- package/framework-mcp/dist/utils/compliance.js +231 -0
- package/framework-mcp/dist/utils/fs.js +44 -0
- package/framework-mcp/dist/utils/metrics.js +56 -0
- package/framework-mcp/dist/utils/permissions.js +71 -0
- package/framework-mcp/dist/utils/security.js +60 -0
- package/framework-mcp/package.json +37 -0
- package/mcp.json +1 -1
- package/package.json +10 -5
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import Database from "better-sqlite3";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import fs from "fs";
|
|
4
|
+
import { getFrameworkDir } from "./memory.js";
|
|
5
|
+
/**
|
|
6
|
+
* [DB] Atabey Storage Engine
|
|
7
|
+
* Central SQLite database for enterprise-scale agent state management.
|
|
8
|
+
*/
|
|
9
|
+
export class Storage {
|
|
10
|
+
static db = null;
|
|
11
|
+
static getDB() {
|
|
12
|
+
if (!this.db) {
|
|
13
|
+
const frameworkDir = getFrameworkDir();
|
|
14
|
+
if (!fs.existsSync(frameworkDir)) {
|
|
15
|
+
fs.mkdirSync(frameworkDir, { recursive: true });
|
|
16
|
+
}
|
|
17
|
+
const dbPath = path.join(frameworkDir, "atabey.db");
|
|
18
|
+
this.db = new Database(dbPath);
|
|
19
|
+
this.initializeSchema();
|
|
20
|
+
}
|
|
21
|
+
return this.db;
|
|
22
|
+
}
|
|
23
|
+
static initializeSchema() {
|
|
24
|
+
const db = this.db;
|
|
25
|
+
// Agents Table
|
|
26
|
+
db.exec(`
|
|
27
|
+
CREATE TABLE IF NOT EXISTS agents (
|
|
28
|
+
name TEXT PRIMARY KEY,
|
|
29
|
+
state TEXT DEFAULT 'READY',
|
|
30
|
+
task TEXT DEFAULT 'Idle',
|
|
31
|
+
last_updated DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
32
|
+
)
|
|
33
|
+
`);
|
|
34
|
+
// Messages (Hermes) Table
|
|
35
|
+
db.exec(`
|
|
36
|
+
CREATE TABLE IF NOT EXISTS messages (
|
|
37
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
38
|
+
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
39
|
+
sender TEXT,
|
|
40
|
+
receiver TEXT,
|
|
41
|
+
category TEXT,
|
|
42
|
+
content TEXT,
|
|
43
|
+
trace_id TEXT,
|
|
44
|
+
parent_id TEXT,
|
|
45
|
+
status TEXT DEFAULT 'PENDING',
|
|
46
|
+
priority TEXT DEFAULT 'NORMAL',
|
|
47
|
+
requires_approval BOOLEAN DEFAULT 0
|
|
48
|
+
)
|
|
49
|
+
`);
|
|
50
|
+
// Tasks Table
|
|
51
|
+
db.exec(`
|
|
52
|
+
CREATE TABLE IF NOT EXISTS tasks (
|
|
53
|
+
id TEXT PRIMARY KEY,
|
|
54
|
+
trace_id TEXT,
|
|
55
|
+
description TEXT,
|
|
56
|
+
agent TEXT,
|
|
57
|
+
status TEXT DEFAULT 'PENDING',
|
|
58
|
+
priority TEXT DEFAULT 'NORMAL',
|
|
59
|
+
dependencies TEXT, -- JSON Array
|
|
60
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
61
|
+
)
|
|
62
|
+
`);
|
|
63
|
+
// Logs Table
|
|
64
|
+
db.exec(`
|
|
65
|
+
CREATE TABLE IF NOT EXISTS logs (
|
|
66
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
67
|
+
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
68
|
+
agent TEXT,
|
|
69
|
+
action TEXT,
|
|
70
|
+
trace_id TEXT,
|
|
71
|
+
status TEXT,
|
|
72
|
+
summary TEXT,
|
|
73
|
+
findings TEXT
|
|
74
|
+
)
|
|
75
|
+
`);
|
|
76
|
+
// Metadata (State) Table
|
|
77
|
+
db.exec(`
|
|
78
|
+
CREATE TABLE IF NOT EXISTS metadata (
|
|
79
|
+
key TEXT PRIMARY KEY,
|
|
80
|
+
value TEXT
|
|
81
|
+
)
|
|
82
|
+
`);
|
|
83
|
+
}
|
|
84
|
+
// --- Agent Operations ---
|
|
85
|
+
static updateAgentStatus(name, state, task, lastUpdated) {
|
|
86
|
+
const db = this.getDB();
|
|
87
|
+
const cleanName = name.replace("@", "");
|
|
88
|
+
const timestamp = lastUpdated || new Date().toISOString();
|
|
89
|
+
db.prepare(`
|
|
90
|
+
INSERT INTO agents (name, state, task, last_updated)
|
|
91
|
+
VALUES (?, ?, ?, ?)
|
|
92
|
+
ON CONFLICT(name) DO UPDATE SET
|
|
93
|
+
state = excluded.state,
|
|
94
|
+
task = excluded.task,
|
|
95
|
+
last_updated = excluded.last_updated
|
|
96
|
+
`).run(cleanName, state, task, timestamp);
|
|
97
|
+
}
|
|
98
|
+
static getAllAgents() {
|
|
99
|
+
return this.getDB().prepare("SELECT * FROM agents").all();
|
|
100
|
+
}
|
|
101
|
+
// --- Message Operations ---
|
|
102
|
+
static saveMessage(msg) {
|
|
103
|
+
const db = this.getDB();
|
|
104
|
+
db.prepare(`
|
|
105
|
+
INSERT INTO messages (sender, receiver, category, content, trace_id, parent_id, status, priority, requires_approval)
|
|
106
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
107
|
+
`).run(msg.from, msg.to, msg.category, msg.content, msg.traceId, msg.parentId || null, msg.status || "PENDING", msg.priority || "NORMAL", msg.requiresApproval ? 1 : 0);
|
|
108
|
+
}
|
|
109
|
+
static getPendingMessages() {
|
|
110
|
+
const rows = this.getDB().prepare("SELECT * FROM messages WHERE status IN ('PENDING', 'APPROVED') ORDER BY priority DESC, timestamp ASC").all();
|
|
111
|
+
return rows.map(r => ({
|
|
112
|
+
id: r.id,
|
|
113
|
+
timestamp: r.timestamp,
|
|
114
|
+
from: r.sender,
|
|
115
|
+
to: r.receiver,
|
|
116
|
+
category: r.category,
|
|
117
|
+
content: r.content,
|
|
118
|
+
traceId: r.trace_id,
|
|
119
|
+
parentId: r.parent_id || undefined,
|
|
120
|
+
status: r.status,
|
|
121
|
+
priority: r.priority,
|
|
122
|
+
requiresApproval: r.requires_approval === 1
|
|
123
|
+
}));
|
|
124
|
+
}
|
|
125
|
+
static updateMessageStatus(id, status) {
|
|
126
|
+
this.getDB().prepare("UPDATE messages SET status = ? WHERE id = ?").run(status, id);
|
|
127
|
+
}
|
|
128
|
+
// --- Task Operations ---
|
|
129
|
+
static saveTask(task) {
|
|
130
|
+
const db = this.getDB();
|
|
131
|
+
db.prepare(`
|
|
132
|
+
INSERT INTO tasks (id, trace_id, description, agent, status, priority, dependencies)
|
|
133
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
134
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
135
|
+
status = excluded.status,
|
|
136
|
+
description = excluded.description
|
|
137
|
+
`).run(task.id, task.traceId, task.description, task.agent, task.status, task.priority, JSON.stringify(task.dependencies || []));
|
|
138
|
+
}
|
|
139
|
+
static getTasks(traceId) {
|
|
140
|
+
const db = this.getDB();
|
|
141
|
+
let rows;
|
|
142
|
+
if (traceId) {
|
|
143
|
+
rows = db.prepare("SELECT * FROM tasks WHERE trace_id = ?").all(traceId);
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
rows = db.prepare("SELECT * FROM tasks").all();
|
|
147
|
+
}
|
|
148
|
+
return rows.map(r => {
|
|
149
|
+
let deps = [];
|
|
150
|
+
try {
|
|
151
|
+
const parsed = JSON.parse(r.dependencies || "[]");
|
|
152
|
+
// Handle cases where dependencies might be double-stringified or are raw JSON strings
|
|
153
|
+
deps = Array.isArray(parsed) ? parsed : JSON.parse(parsed);
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
// Keep empty array
|
|
157
|
+
}
|
|
158
|
+
return {
|
|
159
|
+
id: r.id,
|
|
160
|
+
traceId: r.trace_id,
|
|
161
|
+
description: r.description,
|
|
162
|
+
agent: r.agent,
|
|
163
|
+
status: r.status,
|
|
164
|
+
priority: r.priority,
|
|
165
|
+
dependencies: deps
|
|
166
|
+
};
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
static getLogs(agentName) {
|
|
170
|
+
const db = this.getDB();
|
|
171
|
+
let rows;
|
|
172
|
+
const cleanName = agentName ? agentName.replace("@", "") : undefined;
|
|
173
|
+
if (cleanName) {
|
|
174
|
+
rows = db.prepare("SELECT * FROM logs WHERE agent = ? ORDER BY timestamp DESC").all(cleanName);
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
rows = db.prepare("SELECT * FROM logs ORDER BY timestamp DESC").all();
|
|
178
|
+
}
|
|
179
|
+
return rows.map(r => ({
|
|
180
|
+
id: r.id,
|
|
181
|
+
timestamp: r.timestamp,
|
|
182
|
+
agent: r.agent,
|
|
183
|
+
action: r.action,
|
|
184
|
+
trace_id: r.trace_id || undefined,
|
|
185
|
+
status: r.status,
|
|
186
|
+
summary: r.summary,
|
|
187
|
+
findings: r.findings || undefined
|
|
188
|
+
}));
|
|
189
|
+
}
|
|
190
|
+
// --- Metadata Operations ---
|
|
191
|
+
static setMetadata(key, value) {
|
|
192
|
+
this.getDB().prepare(`
|
|
193
|
+
INSERT INTO metadata (key, value) VALUES (?, ?)
|
|
194
|
+
ON CONFLICT(key) DO UPDATE SET value = excluded.value
|
|
195
|
+
`).run(key, value);
|
|
196
|
+
}
|
|
197
|
+
static getMetadata(key) {
|
|
198
|
+
const row = this.getDB().prepare("SELECT value FROM metadata WHERE key = ?").get(key);
|
|
199
|
+
return row ? row.value : null;
|
|
200
|
+
}
|
|
201
|
+
static reset() {
|
|
202
|
+
if (this.db) {
|
|
203
|
+
this.db.close();
|
|
204
|
+
this.db = null;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Atabey Framework — Internal Branded Types
|
|
3
|
+
* Used to enforce absolute type safety within the core orchestration logic.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Casts a raw string to a Branded Type.
|
|
7
|
+
* Use this only at the boundaries of the system.
|
|
8
|
+
*/
|
|
9
|
+
export function asTraceID(val) { return val; }
|
|
10
|
+
export function asAgentID(val) { return val; }
|
|
11
|
+
export function asPhaseID(val) { return val; }
|
|
12
|
+
export function asProjectPath(val) { return val; }
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
6
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
7
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
8
|
+
import { TOOLS, toolHandlers } from "./tools/index.js";
|
|
9
|
+
import { RESOURCES, handleReadResource } from "./resources/index.js";
|
|
10
|
+
// ─── Server Setup ─────────────────────────────────────────────────
|
|
11
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
// Robustly find package.json by walking up from __dirname
|
|
13
|
+
function findPackageJson(startDir) {
|
|
14
|
+
let currentDir = startDir;
|
|
15
|
+
while (currentDir !== path.parse(currentDir).root) {
|
|
16
|
+
const pkgPath = path.join(currentDir, "package.json");
|
|
17
|
+
if (fs.existsSync(pkgPath))
|
|
18
|
+
return pkgPath;
|
|
19
|
+
currentDir = path.dirname(currentDir);
|
|
20
|
+
}
|
|
21
|
+
throw new Error("Could not find package.json for atabey-mcp");
|
|
22
|
+
}
|
|
23
|
+
const pkgPath = findPackageJson(__dirname);
|
|
24
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
|
|
25
|
+
const serverVersion = pkg.version;
|
|
26
|
+
const server = new Server({
|
|
27
|
+
name: "atabey-mcp",
|
|
28
|
+
version: serverVersion,
|
|
29
|
+
}, {
|
|
30
|
+
capabilities: {
|
|
31
|
+
tools: {},
|
|
32
|
+
resources: {},
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
// Basic Schema Validator for Required Fields
|
|
36
|
+
function validateArgs(toolName, args) {
|
|
37
|
+
const definition = TOOLS.find(t => t.name === toolName);
|
|
38
|
+
if (!definition)
|
|
39
|
+
return `Unknown tool: ${toolName}`;
|
|
40
|
+
const required = definition.inputSchema.required || [];
|
|
41
|
+
for (const field of required) {
|
|
42
|
+
if (args[field] === undefined || args[field] === null || args[field] === "") {
|
|
43
|
+
return `Missing required argument: '${field}' for tool '${toolName}'`;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
server.setRequestHandler(ListToolsRequestSchema, async (request) => {
|
|
49
|
+
// 2026 Stateless Spec: Log client info from metadata if available
|
|
50
|
+
const meta = request._meta;
|
|
51
|
+
if (meta) {
|
|
52
|
+
process.stderr.write(`[MCP] Stateless ListTools from ${meta.client?.name || "unknown"} v${meta.client?.version || "?.?"}\n`);
|
|
53
|
+
}
|
|
54
|
+
return { tools: TOOLS };
|
|
55
|
+
});
|
|
56
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
57
|
+
return { resources: RESOURCES };
|
|
58
|
+
});
|
|
59
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
60
|
+
const uri = request.params.uri;
|
|
61
|
+
try {
|
|
62
|
+
const content = await handleReadResource(uri);
|
|
63
|
+
return {
|
|
64
|
+
contents: [
|
|
65
|
+
{
|
|
66
|
+
uri,
|
|
67
|
+
mimeType: "text/markdown",
|
|
68
|
+
text: content,
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
75
|
+
throw new Error(`Failed to read resource: ${message}`, { cause: error });
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
79
|
+
const req = request;
|
|
80
|
+
const { name, arguments: args } = req.params;
|
|
81
|
+
const meta = request._meta;
|
|
82
|
+
// 2026 Stateless Spec: Prioritize metadata-driven context
|
|
83
|
+
if (meta) {
|
|
84
|
+
process.stderr.write(`[MCP] Stateless CallTool: ${name} (Client: ${meta.client?.name || "unknown"})\n`);
|
|
85
|
+
}
|
|
86
|
+
const projectRoot = process.env.ATABEY_PROJECT_ROOT || process.cwd();
|
|
87
|
+
try {
|
|
88
|
+
const handler = toolHandlers[name];
|
|
89
|
+
if (!handler) {
|
|
90
|
+
return {
|
|
91
|
+
isError: true,
|
|
92
|
+
content: [{ type: "text", text: `[ERROR] Unknown tool: ${name}` }],
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
// [SECURITY] Runtime Validation
|
|
96
|
+
const validationError = validateArgs(name, args || {});
|
|
97
|
+
if (validationError) {
|
|
98
|
+
return {
|
|
99
|
+
isError: true,
|
|
100
|
+
content: [{ type: "text", text: `[ERROR] Validation Error: ${validationError}` }],
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
return await handler(projectRoot, args || {});
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
const message = error instanceof Error ? error.message : "Unknown error occurred";
|
|
107
|
+
return {
|
|
108
|
+
isError: true,
|
|
109
|
+
content: [{ type: "text", text: `[ERROR] Execution failed: ${message}` }],
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
// ─── Graceful Startup & Shutdown ──────────────────────────────────
|
|
114
|
+
async function run() {
|
|
115
|
+
const transport = new StdioServerTransport();
|
|
116
|
+
// Prevent unhandled errors from crashing the MCP stream
|
|
117
|
+
process.on("uncaughtException", (error) => {
|
|
118
|
+
process.stderr.write(`[atabey-mcp] Uncaught exception: ${error.message}
|
|
119
|
+
`);
|
|
120
|
+
});
|
|
121
|
+
process.on("unhandledRejection", (reason) => {
|
|
122
|
+
const message = reason instanceof Error ? reason.message : String(reason);
|
|
123
|
+
process.stderr.write(`[atabey-mcp] Unhandled rejection: ${message}
|
|
124
|
+
`);
|
|
125
|
+
});
|
|
126
|
+
// Graceful shutdown on SIGINT/SIGTERM
|
|
127
|
+
const shutdown = async () => {
|
|
128
|
+
try {
|
|
129
|
+
await server.close();
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
// Already closed or failed — safe to ignore
|
|
133
|
+
}
|
|
134
|
+
process.exit(0);
|
|
135
|
+
};
|
|
136
|
+
process.on("SIGINT", shutdown);
|
|
137
|
+
process.on("SIGTERM", shutdown);
|
|
138
|
+
await server.connect(transport);
|
|
139
|
+
}
|
|
140
|
+
run().catch((error) => {
|
|
141
|
+
process.stderr.write(`[atabey-mcp] Fatal startup error: ${error.message}
|
|
142
|
+
`);
|
|
143
|
+
process.exit(1);
|
|
144
|
+
});
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Storage } from "../../../src/shared/storage.js";
|
|
2
|
+
/**
|
|
3
|
+
* [DATA] MCP Resource Definitions
|
|
4
|
+
*/
|
|
5
|
+
export const RESOURCES = [
|
|
6
|
+
{
|
|
7
|
+
uri: "atabey://army/status",
|
|
8
|
+
name: "Agent Army Status",
|
|
9
|
+
description: "Real-time state and active tasks of all specialized agents.",
|
|
10
|
+
mimeType: "text/markdown"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
uri: "atabey://plan/active",
|
|
14
|
+
name: "Active Execution Plan",
|
|
15
|
+
description: "The current DAG of tasks and their completion status.",
|
|
16
|
+
mimeType: "text/markdown"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
uri: "atabey://memory/project",
|
|
20
|
+
name: "Project Memory",
|
|
21
|
+
description: "The central source of truth for project context (PROJECT_MEMORY.md).",
|
|
22
|
+
mimeType: "text/markdown"
|
|
23
|
+
}
|
|
24
|
+
];
|
|
25
|
+
export async function handleReadResource(uri) {
|
|
26
|
+
if (uri === "atabey://army/status") {
|
|
27
|
+
const agents = Storage.getAllAgents();
|
|
28
|
+
let md = "# [AI] Agent Army Status\n\n| Agent | State | Active Task | Last Updated |\n| :--- | :--- | :--- | :--- |\n";
|
|
29
|
+
agents.forEach((a) => {
|
|
30
|
+
md += `| @${a.name} | ${a.state} | ${a.task} | ${a.last_updated} |\n`;
|
|
31
|
+
});
|
|
32
|
+
return md;
|
|
33
|
+
}
|
|
34
|
+
if (uri === "atabey://plan/active") {
|
|
35
|
+
const tasks = Storage.getTasks();
|
|
36
|
+
let md = "# 📋 Active Execution Plan\n\n| ID | Task | Agent | Status | Dependencies |\n| :--- | :--- | :--- | :--- | :--- |\n";
|
|
37
|
+
tasks.forEach((t) => {
|
|
38
|
+
const deps = t.dependencies.join(", ") || "-";
|
|
39
|
+
md += `| ${t.id} | ${t.description} | ${t.agent} | ${t.status} | ${deps} |\n`;
|
|
40
|
+
});
|
|
41
|
+
return md;
|
|
42
|
+
}
|
|
43
|
+
if (uri === "atabey://memory/project") {
|
|
44
|
+
const fs = await import("fs");
|
|
45
|
+
const path = await import("path");
|
|
46
|
+
const { getFrameworkDir } = await import("../../../src/cli/utils/memory.js");
|
|
47
|
+
const projectRoot = process.env.ATABEY_PROJECT_ROOT || process.cwd();
|
|
48
|
+
const fwDir = getFrameworkDir();
|
|
49
|
+
const p = path.isAbsolute(fwDir)
|
|
50
|
+
? path.join(fwDir, "memory", "PROJECT_MEMORY.md")
|
|
51
|
+
: path.join(projectRoot, fwDir, "memory", "PROJECT_MEMORY.md");
|
|
52
|
+
if (fs.existsSync(p)) {
|
|
53
|
+
return fs.readFileSync(p, "utf8");
|
|
54
|
+
}
|
|
55
|
+
return "Project memory not found. Run 'atabey init' first.";
|
|
56
|
+
}
|
|
57
|
+
throw new Error(`Unknown resource URI: ${uri}`);
|
|
58
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { writeJsonFile } from "../utils/fs.js";
|
|
4
|
+
import { getPackageRoot } from "../utils/pkg.js";
|
|
5
|
+
import { MCP } from "../../shared/constants.js";
|
|
6
|
+
import { ADAPTER_CONFIGS, POST_INIT_HANDLERS } from "../../modules/adapters/definitions.js";
|
|
7
|
+
export const ADAPTERS = ADAPTER_CONFIGS;
|
|
8
|
+
export const SHIM_FILES = Object.keys(ADAPTERS).map((id) => ADAPTERS[id].shimFile);
|
|
9
|
+
export const FRAMEWORK_DIR_CANDIDATES = [
|
|
10
|
+
".atabey",
|
|
11
|
+
".cursor",
|
|
12
|
+
".claude",
|
|
13
|
+
".github",
|
|
14
|
+
".grok",
|
|
15
|
+
".antigravity",
|
|
16
|
+
".agent",
|
|
17
|
+
".gemini/antigravity-cli",
|
|
18
|
+
".gemini",
|
|
19
|
+
".agents",
|
|
20
|
+
"antigravity-cli"
|
|
21
|
+
];
|
|
22
|
+
export function buildMcpServerEntry(projectRoot) {
|
|
23
|
+
const packageRoot = getPackageRoot();
|
|
24
|
+
// Check if we are running in the framework local development repository itself
|
|
25
|
+
const isLocalFrameworkDev = path.resolve(packageRoot) === path.resolve(projectRoot);
|
|
26
|
+
let relativePath;
|
|
27
|
+
if (isLocalFrameworkDev) {
|
|
28
|
+
// In local framework dev, always use the build path directly relative to project root
|
|
29
|
+
let mcpServerPath = path.join(packageRoot, MCP.SERVER_DIST_PATH);
|
|
30
|
+
if (!fs.existsSync(mcpServerPath)) {
|
|
31
|
+
mcpServerPath = path.join(packageRoot, "../atabey-mcp/dist/index.js");
|
|
32
|
+
}
|
|
33
|
+
if (!fs.existsSync(mcpServerPath)) {
|
|
34
|
+
mcpServerPath = path.join(projectRoot, "node_modules/atabey-mcp/dist/index.js");
|
|
35
|
+
}
|
|
36
|
+
if (!fs.existsSync(mcpServerPath)) {
|
|
37
|
+
console.warn("[WARN] MCP Server not found. Did you run 'npm run build' inside atabey-mcp?");
|
|
38
|
+
}
|
|
39
|
+
relativePath = path.relative(projectRoot, mcpServerPath) || mcpServerPath;
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
// If we are initializing in a user's project:
|
|
43
|
+
// We target the atabey-mcp package which is a dependency of atabey.
|
|
44
|
+
// This ensures a stable path across different npm/pnpm/yarn setups.
|
|
45
|
+
relativePath = "node_modules/atabey-mcp/dist/index.js";
|
|
46
|
+
// Fallback check if it actually exists in a different location during init
|
|
47
|
+
const localAtabeyPath = path.join(projectRoot, "node_modules/atabey", MCP.SERVER_DIST_PATH);
|
|
48
|
+
if (!fs.existsSync(path.join(projectRoot, relativePath)) && fs.existsSync(localAtabeyPath)) {
|
|
49
|
+
relativePath = path.join("node_modules/atabey", MCP.SERVER_DIST_PATH);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
command: "node",
|
|
54
|
+
args: [relativePath],
|
|
55
|
+
env: {
|
|
56
|
+
[MCP.PROJECT_ROOT_ENV]: projectRoot,
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
export function runAdapterPostInit(adapter, projectRoot) {
|
|
61
|
+
const mcpEntry = buildMcpServerEntry(projectRoot);
|
|
62
|
+
const mcpBlock = { mcpServers: { [MCP.SERVER_NAME]: mcpEntry } };
|
|
63
|
+
const postInitFn = POST_INIT_HANDLERS[adapter.id];
|
|
64
|
+
if (postInitFn) {
|
|
65
|
+
postInitFn(projectRoot, mcpBlock);
|
|
66
|
+
}
|
|
67
|
+
const rootMcpPath = path.join(projectRoot, MCP.ROOT_CONFIG_FILE);
|
|
68
|
+
if (!fs.existsSync(rootMcpPath)) {
|
|
69
|
+
writeJsonFile(rootMcpPath, mcpBlock);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { ADAPTER_IDS } from "../../modules/adapters/types.js";
|
|
2
|
+
export { ADAPTERS, FRAMEWORK_DIR_CANDIDATES, runAdapterPostInit, buildMcpServerEntry } from "./core.js";
|
|
3
|
+
export { resolveAdapter, isAdapterShimFile, remapFrameworkContent } from "./utils.js";
|
|
4
|
+
export { scaffoldAgents } from "./scaffold.js";
|
|
5
|
+
export { resolveAgentsDir, mirrorUnifiedAgentsToNative } from "./paths.js";
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { ADAPTER_IDS } from "../../modules/adapters/types.js";
|
|
4
|
+
import { LEGACY_AGENT_LAYOUT_BASES, UNIFIED_ADAPTER_SLUG, UNIFIED_HUB_DIR, pathJoin, unifiedAdapterPath, } from "../../shared/constants.js";
|
|
5
|
+
import { ADAPTERS } from "./core.js";
|
|
6
|
+
export { CORE_FRAMEWORK_DIR, UNIFIED_HUB_DIR, UNIFIED_ADAPTER_SLUG, } from "../../shared/constants.js";
|
|
7
|
+
export function unifiedAdapterRoot(aiToolDir, adapterId) {
|
|
8
|
+
return pathJoin(aiToolDir, UNIFIED_ADAPTER_SLUG[adapterId]);
|
|
9
|
+
}
|
|
10
|
+
export function resolveAgentsDir(adapterId, isUnified, aiToolDir = UNIFIED_HUB_DIR) {
|
|
11
|
+
const adapter = ADAPTERS[adapterId];
|
|
12
|
+
if (!isUnified) {
|
|
13
|
+
return {
|
|
14
|
+
agentsDir: adapter.agentsDir ?? pathJoin(adapter.frameworkDir, "agents"),
|
|
15
|
+
agentsExt: adapter.agentsExt ?? ".md",
|
|
16
|
+
nestedAntigravity: adapterId === "antigravity-cli",
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
const base = unifiedAdapterRoot(aiToolDir, adapterId);
|
|
20
|
+
switch (adapterId) {
|
|
21
|
+
case "cursor":
|
|
22
|
+
return { agentsDir: pathJoin(base, "rules"), agentsExt: ".mdc", nestedAntigravity: false };
|
|
23
|
+
case "codex":
|
|
24
|
+
return { agentsDir: pathJoin(base, "instructions"), agentsExt: ".md", nestedAntigravity: false };
|
|
25
|
+
case "antigravity-cli":
|
|
26
|
+
// Antigravity CLI expects workspace agents at .agents/agents/{agent_name}/agent.json
|
|
27
|
+
return { agentsDir: pathJoin(aiToolDir, "agents"), agentsExt: ".json", nestedAntigravity: true };
|
|
28
|
+
default:
|
|
29
|
+
return { agentsDir: pathJoin(base, "agents"), agentsExt: ".md", nestedAntigravity: false };
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export function getUnifiedAgentLayoutBases(aiToolDir = UNIFIED_HUB_DIR) {
|
|
33
|
+
return ADAPTER_IDS.map((id) => resolveAgentsDir(id, true, aiToolDir).agentsDir);
|
|
34
|
+
}
|
|
35
|
+
const AGENT_INSTRUCTION_CANDIDATES = [
|
|
36
|
+
(n) => ADAPTER_IDS.flatMap((id) => {
|
|
37
|
+
const { agentsDir, nestedAntigravity, agentsExt } = resolveAgentsDir(id, true);
|
|
38
|
+
if (nestedAntigravity) {
|
|
39
|
+
return [pathJoin(agentsDir, n, "agent.json"), pathJoin(agentsDir, n, "agent.md")];
|
|
40
|
+
}
|
|
41
|
+
return [pathJoin(agentsDir, `${n}${agentsExt}`)];
|
|
42
|
+
}),
|
|
43
|
+
(n) => LEGACY_AGENT_LAYOUT_BASES.flatMap((base) => {
|
|
44
|
+
if (base.includes("antigravity")) {
|
|
45
|
+
return [pathJoin(base, n, "agent.json"), pathJoin(base, n, "agent.md")];
|
|
46
|
+
}
|
|
47
|
+
const ext = base.includes("rules") ? ".mdc" : ".md";
|
|
48
|
+
return [pathJoin(base, `${n}${ext}`)];
|
|
49
|
+
}),
|
|
50
|
+
];
|
|
51
|
+
export function findAgentInstruction(projectRoot, agentName) {
|
|
52
|
+
for (const buildPaths of AGENT_INSTRUCTION_CANDIDATES) {
|
|
53
|
+
for (const rel of buildPaths(agentName)) {
|
|
54
|
+
const full = path.join(projectRoot, rel);
|
|
55
|
+
if (fs.existsSync(full))
|
|
56
|
+
return rel;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
export function detectActiveAgentLayouts(projectRoot) {
|
|
62
|
+
const unified = getUnifiedAgentLayoutBases()
|
|
63
|
+
.filter((b) => fs.existsSync(path.join(projectRoot, b)));
|
|
64
|
+
const legacy = LEGACY_AGENT_LAYOUT_BASES
|
|
65
|
+
.filter((b) => fs.existsSync(path.join(projectRoot, b)));
|
|
66
|
+
return [...new Set([...unified, ...legacy])];
|
|
67
|
+
}
|
|
68
|
+
function copyDirectoryRecursive(src, dest) {
|
|
69
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
70
|
+
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
71
|
+
const srcPath = path.join(src, entry.name);
|
|
72
|
+
const destPath = path.join(dest, entry.name);
|
|
73
|
+
if (entry.isDirectory()) {
|
|
74
|
+
copyDirectoryRecursive(srcPath, destPath);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
fs.copyFileSync(srcPath, destPath);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
export function mirrorUnifiedAgentsToNative(projectRoot, adapterId) {
|
|
82
|
+
const { agentsDir: unifiedDir } = resolveAgentsDir(adapterId, true);
|
|
83
|
+
const nativeRel = ADAPTERS[adapterId].agentsDir;
|
|
84
|
+
if (!nativeRel)
|
|
85
|
+
return;
|
|
86
|
+
const src = path.join(projectRoot, unifiedDir);
|
|
87
|
+
const dest = path.join(projectRoot, nativeRel);
|
|
88
|
+
if (!fs.existsSync(src) || path.resolve(src) === path.resolve(dest))
|
|
89
|
+
return;
|
|
90
|
+
if (fs.existsSync(dest)) {
|
|
91
|
+
fs.rmSync(dest, { recursive: true, force: true });
|
|
92
|
+
}
|
|
93
|
+
copyDirectoryRecursive(src, dest);
|
|
94
|
+
}
|
|
95
|
+
/** Cursor global rule destinations (native + unified hub). */
|
|
96
|
+
export function getCursorGlobalRulePaths(projectRoot) {
|
|
97
|
+
return [
|
|
98
|
+
path.join(projectRoot, ADAPTERS.cursor.frameworkDir, "rules", "global.mdc"),
|
|
99
|
+
path.join(projectRoot, unifiedAdapterPath(UNIFIED_ADAPTER_SLUG.cursor, "rules", "global.mdc")),
|
|
100
|
+
];
|
|
101
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { writeTextFile } from "../utils/fs.js";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import fs from "fs";
|
|
4
|
+
import { getPackageRoot } from "../utils/pkg.js";
|
|
5
|
+
import { ALL_AGENTS, toClaudeCodeMd, toGeminiCliMd, toCodexMd, toAntigravityJson, toCursorMdc } from "../../modules/agents/definitions.js";
|
|
6
|
+
import { ADAPTERS } from "./core.js";
|
|
7
|
+
export function scaffoldAgents(projectRoot, adapterId, dryRun, agentsToScaffold, explicitDestDir, explicitExt, paths, backendLanguage, _language) {
|
|
8
|
+
const adapter = ADAPTERS[adapterId];
|
|
9
|
+
if (!adapter)
|
|
10
|
+
return;
|
|
11
|
+
const allowedAgents = agentsToScaffold ? new Set(agentsToScaffold) : undefined;
|
|
12
|
+
const destAgentsDir = explicitDestDir ? path.join(projectRoot, explicitDestDir) : (adapter.agentsDir ? path.join(projectRoot, adapter.agentsDir) : null);
|
|
13
|
+
const extension = explicitExt || adapter.agentsExt || ".md";
|
|
14
|
+
if (!destAgentsDir)
|
|
15
|
+
return;
|
|
16
|
+
const baseKnowledgeDir = path.join(getPackageRoot(), "templates/standards");
|
|
17
|
+
try {
|
|
18
|
+
if (!dryRun)
|
|
19
|
+
fs.mkdirSync(destAgentsDir, { recursive: true });
|
|
20
|
+
for (const agent of ALL_AGENTS) {
|
|
21
|
+
if (allowedAgents && !allowedAgents.has(agent.name))
|
|
22
|
+
continue;
|
|
23
|
+
let content = "";
|
|
24
|
+
let fileName = `${agent.name}${extension}`;
|
|
25
|
+
let secondaryContent = null;
|
|
26
|
+
let secondaryFileName = null;
|
|
27
|
+
switch (adapterId) {
|
|
28
|
+
case "gemini":
|
|
29
|
+
content = toGeminiCliMd(agent, baseKnowledgeDir, paths, backendLanguage);
|
|
30
|
+
break;
|
|
31
|
+
case "grok":
|
|
32
|
+
// Grok uses same Gemini-compatible YAML format
|
|
33
|
+
content = toGeminiCliMd(agent, baseKnowledgeDir, paths, backendLanguage);
|
|
34
|
+
break;
|
|
35
|
+
case "claude":
|
|
36
|
+
content = toClaudeCodeMd(agent, baseKnowledgeDir, paths, backendLanguage);
|
|
37
|
+
break;
|
|
38
|
+
case "cursor":
|
|
39
|
+
content = toCursorMdc(agent, baseKnowledgeDir, paths, backendLanguage);
|
|
40
|
+
break;
|
|
41
|
+
case "codex":
|
|
42
|
+
content = toCodexMd(agent, baseKnowledgeDir, paths, backendLanguage);
|
|
43
|
+
break;
|
|
44
|
+
case "antigravity-cli": {
|
|
45
|
+
// Antigravity uses nested folders: agents/{name}/agent.json and agents/{name}/agent.md
|
|
46
|
+
const agentDir = path.join(destAgentsDir, agent.name);
|
|
47
|
+
if (!dryRun)
|
|
48
|
+
fs.mkdirSync(agentDir, { recursive: true });
|
|
49
|
+
content = toAntigravityJson(agent, baseKnowledgeDir, paths, backendLanguage);
|
|
50
|
+
fileName = path.join(agent.name, "agent.json");
|
|
51
|
+
secondaryContent = `# [ATABEY] Agent Atabey — @${agent.name}\n\n${agent.instructions.identity}\n\n${agent.instructions.mission}`;
|
|
52
|
+
secondaryFileName = path.join(agent.name, "agent.md");
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
default:
|
|
56
|
+
// Fallback to Gemini format
|
|
57
|
+
content = toGeminiCliMd(agent, baseKnowledgeDir, paths, backendLanguage);
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
if (!dryRun) {
|
|
61
|
+
writeTextFile(path.join(destAgentsDir, fileName), content, dryRun);
|
|
62
|
+
if (secondaryContent && secondaryFileName) {
|
|
63
|
+
writeTextFile(path.join(destAgentsDir, secondaryFileName), secondaryContent, dryRun);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
catch (e) {
|
|
69
|
+
console.warn(`[WARN] Failed to scaffold agents for ${adapterId}: ${e}`);
|
|
70
|
+
}
|
|
71
|
+
}
|