atabey 0.0.9 → 0.0.10

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.
Files changed (125) hide show
  1. package/README.md +1 -1
  2. package/dist/src/cli/commands/init.js +49 -0
  3. package/dist/src/cli/commands/init.js.map +1 -1
  4. package/framework-mcp/README.md +48 -0
  5. package/framework-mcp/dist/resources/index.js +2 -2
  6. package/framework-mcp/package.json +1 -1
  7. package/package.json +2 -2
  8. package/framework-mcp/dist/framework-mcp/src/constants.js +0 -64
  9. package/framework-mcp/dist/framework-mcp/src/index.js +0 -144
  10. package/framework-mcp/dist/framework-mcp/src/resources/index.js +0 -58
  11. package/framework-mcp/dist/framework-mcp/src/tools/control_plane/locking.js +0 -82
  12. package/framework-mcp/dist/framework-mcp/src/tools/control_plane/registry.js +0 -35
  13. package/framework-mcp/dist/framework-mcp/src/tools/definitions.js +0 -322
  14. package/framework-mcp/dist/framework-mcp/src/tools/file_system/batch_surgical_edit.js +0 -64
  15. package/framework-mcp/dist/framework-mcp/src/tools/file_system/patch_file.js +0 -34
  16. package/framework-mcp/dist/framework-mcp/src/tools/file_system/read_file.js +0 -51
  17. package/framework-mcp/dist/framework-mcp/src/tools/file_system/replace_text.js +0 -50
  18. package/framework-mcp/dist/framework-mcp/src/tools/file_system/write_file.js +0 -43
  19. package/framework-mcp/dist/framework-mcp/src/tools/framework/audit_deps.js +0 -41
  20. package/framework-mcp/dist/framework-mcp/src/tools/framework/get_status.js +0 -5
  21. package/framework-mcp/dist/framework-mcp/src/tools/framework/orchestrate.js +0 -5
  22. package/framework-mcp/dist/framework-mcp/src/tools/framework/run_tests.js +0 -27
  23. package/framework-mcp/dist/framework-mcp/src/tools/framework/submit_plan.js +0 -13
  24. package/framework-mcp/dist/framework-mcp/src/tools/framework/update_contract_hash.js +0 -5
  25. package/framework-mcp/dist/framework-mcp/src/tools/framework/update_memory.js +0 -8
  26. package/framework-mcp/dist/framework-mcp/src/tools/index.js +0 -62
  27. package/framework-mcp/dist/framework-mcp/src/tools/memory/get_insights.js +0 -34
  28. package/framework-mcp/dist/framework-mcp/src/tools/memory/read_memory.js +0 -28
  29. package/framework-mcp/dist/framework-mcp/src/tools/messaging/log_action.js +0 -22
  30. package/framework-mcp/dist/framework-mcp/src/tools/messaging/send_message.js +0 -94
  31. package/framework-mcp/dist/framework-mcp/src/tools/observability/check_ports.js +0 -26
  32. package/framework-mcp/dist/framework-mcp/src/tools/observability/get_health.js +0 -19
  33. package/framework-mcp/dist/framework-mcp/src/tools/quality/check_lint.js +0 -30
  34. package/framework-mcp/dist/framework-mcp/src/tools/search/get_gaps.js +0 -48
  35. package/framework-mcp/dist/framework-mcp/src/tools/search/get_map.js +0 -43
  36. package/framework-mcp/dist/framework-mcp/src/tools/search/grep_search.js +0 -75
  37. package/framework-mcp/dist/framework-mcp/src/tools/search/list_dir.js +0 -28
  38. package/framework-mcp/dist/framework-mcp/src/tools/shell/run_command.js +0 -56
  39. package/framework-mcp/dist/framework-mcp/src/tools/types.js +0 -1
  40. package/framework-mcp/dist/framework-mcp/src/utils/cli.js +0 -59
  41. package/framework-mcp/dist/framework-mcp/src/utils/compliance.js +0 -231
  42. package/framework-mcp/dist/framework-mcp/src/utils/fs.js +0 -44
  43. package/framework-mcp/dist/framework-mcp/src/utils/metrics.js +0 -56
  44. package/framework-mcp/dist/framework-mcp/src/utils/permissions.js +0 -71
  45. package/framework-mcp/dist/framework-mcp/src/utils/security.js +0 -60
  46. package/framework-mcp/dist/src/cli/adapters/core.js +0 -71
  47. package/framework-mcp/dist/src/cli/adapters/index.js +0 -5
  48. package/framework-mcp/dist/src/cli/adapters/paths.js +0 -101
  49. package/framework-mcp/dist/src/cli/adapters/scaffold.js +0 -71
  50. package/framework-mcp/dist/src/cli/adapters/utils.js +0 -75
  51. package/framework-mcp/dist/src/cli/commands/approve.js +0 -63
  52. package/framework-mcp/dist/src/cli/commands/check.js +0 -181
  53. package/framework-mcp/dist/src/cli/commands/compliance.js +0 -50
  54. package/framework-mcp/dist/src/cli/commands/contract.js +0 -50
  55. package/framework-mcp/dist/src/cli/commands/dashboard.js +0 -123
  56. package/framework-mcp/dist/src/cli/commands/explorer.js +0 -42
  57. package/framework-mcp/dist/src/cli/commands/git.js +0 -40
  58. package/framework-mcp/dist/src/cli/commands/init/create-agent.js +0 -58
  59. package/framework-mcp/dist/src/cli/commands/init/scaffold-core.js +0 -112
  60. package/framework-mcp/dist/src/cli/commands/init/scaffold-docs.js +0 -34
  61. package/framework-mcp/dist/src/cli/commands/init/scaffold-ops.js +0 -80
  62. package/framework-mcp/dist/src/cli/commands/init/scaffold-standards.js +0 -67
  63. package/framework-mcp/dist/src/cli/commands/init.js +0 -167
  64. package/framework-mcp/dist/src/cli/commands/knowledge.js +0 -42
  65. package/framework-mcp/dist/src/cli/commands/lint.js +0 -22
  66. package/framework-mcp/dist/src/cli/commands/log.js +0 -10
  67. package/framework-mcp/dist/src/cli/commands/memory.js +0 -4
  68. package/framework-mcp/dist/src/cli/commands/orchestrate.js +0 -159
  69. package/framework-mcp/dist/src/cli/commands/plan.js +0 -117
  70. package/framework-mcp/dist/src/cli/commands/script.js +0 -19
  71. package/framework-mcp/dist/src/cli/commands/security.js +0 -36
  72. package/framework-mcp/dist/src/cli/commands/status.js +0 -97
  73. package/framework-mcp/dist/src/cli/commands/trace.js +0 -109
  74. package/framework-mcp/dist/src/cli/index.js +0 -338
  75. package/framework-mcp/dist/src/cli/shims.js +0 -66
  76. package/framework-mcp/dist/src/cli/utils/claude.js +0 -56
  77. package/framework-mcp/dist/src/cli/utils/compliance.js +0 -173
  78. package/framework-mcp/dist/src/cli/utils/config-schema.js +0 -42
  79. package/framework-mcp/dist/src/cli/utils/fs.js +0 -137
  80. package/framework-mcp/dist/src/cli/utils/i18n.js +0 -30
  81. package/framework-mcp/dist/src/cli/utils/memory.js +0 -276
  82. package/framework-mcp/dist/src/cli/utils/pkg.js +0 -282
  83. package/framework-mcp/dist/src/cli/utils/schemas.js +0 -19
  84. package/framework-mcp/dist/src/cli/utils/string.js +0 -49
  85. package/framework-mcp/dist/src/cli/utils/time.js +0 -27
  86. package/framework-mcp/dist/src/cli/utils/ui.js +0 -58
  87. package/framework-mcp/dist/src/contracts/index.js +0 -1
  88. package/framework-mcp/dist/src/contracts/tasks.js +0 -20
  89. package/framework-mcp/dist/src/dashboard/vite.config.js +0 -15
  90. package/framework-mcp/dist/src/modules/adapters/definitions.js +0 -140
  91. package/framework-mcp/dist/src/modules/adapters/registry.js +0 -18
  92. package/framework-mcp/dist/src/modules/adapters/shared.js +0 -104
  93. package/framework-mcp/dist/src/modules/adapters/types.js +0 -1
  94. package/framework-mcp/dist/src/modules/agents/definitions.js +0 -457
  95. package/framework-mcp/dist/src/modules/agents/registry/analyst.js +0 -39
  96. package/framework-mcp/dist/src/modules/agents/registry/architect.js +0 -42
  97. package/framework-mcp/dist/src/modules/agents/registry/backend.js +0 -49
  98. package/framework-mcp/dist/src/modules/agents/registry/database.js +0 -45
  99. package/framework-mcp/dist/src/modules/agents/registry/devops.js +0 -45
  100. package/framework-mcp/dist/src/modules/agents/registry/explorer.js +0 -36
  101. package/framework-mcp/dist/src/modules/agents/registry/frontend.js +0 -51
  102. package/framework-mcp/dist/src/modules/agents/registry/git.js +0 -36
  103. package/framework-mcp/dist/src/modules/agents/registry/manager.js +0 -53
  104. package/framework-mcp/dist/src/modules/agents/registry/mobile.js +0 -39
  105. package/framework-mcp/dist/src/modules/agents/registry/native.js +0 -39
  106. package/framework-mcp/dist/src/modules/agents/registry/quality.js +0 -41
  107. package/framework-mcp/dist/src/modules/agents/registry/security.js +0 -43
  108. package/framework-mcp/dist/src/modules/agents/types.js +0 -1
  109. package/framework-mcp/dist/src/modules/engines/evaluation-engine.js +0 -102
  110. package/framework-mcp/dist/src/modules/engines/health-engine.js +0 -49
  111. package/framework-mcp/dist/src/modules/engines/planning-engine.js +0 -78
  112. package/framework-mcp/dist/src/modules/engines/risk-engine.js +0 -105
  113. package/framework-mcp/dist/src/modules/engines/routing-engine.js +0 -73
  114. package/framework-mcp/dist/src/modules/engines/types.js +0 -1
  115. package/framework-mcp/dist/src/modules/skills/definitions.js +0 -70
  116. package/framework-mcp/dist/src/shared/constants.js +0 -187
  117. package/framework-mcp/dist/src/shared/errors.js +0 -68
  118. package/framework-mcp/dist/src/shared/fs.js +0 -51
  119. package/framework-mcp/dist/src/shared/logger.js +0 -116
  120. package/framework-mcp/dist/src/shared/storage.js +0 -207
  121. package/framework-mcp/dist/src/shared/types.js +0 -12
  122. /package/framework-mcp/dist/{framework-mcp/src/utils → utils}/errors.js +0 -0
  123. /package/framework-mcp/dist/{framework-mcp/src/utils → utils}/memory.js +0 -0
  124. /package/framework-mcp/dist/{framework-mcp/src/utils → utils}/storage.js +0 -0
  125. /package/framework-mcp/dist/{framework-mcp/src/utils → utils}/types.js +0 -0
@@ -1,59 +0,0 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import { execFileSync } from "child_process";
4
- /**
5
- * Executes a command safely and returns the output.
6
- */
7
- export function safeExec(cmd, args, cwd, timeout = 30000) {
8
- try {
9
- return execFileSync(cmd, args, { cwd, timeout, encoding: "utf8", stdio: "pipe" });
10
- }
11
- catch (err) {
12
- const error = err;
13
- return error.stdout?.toString() || error.stderr?.toString() || error.message || String(err);
14
- }
15
- }
16
- /**
17
- * Detects the backend language from the framework configuration.
18
- */
19
- export function getBackendLanguage(projectRoot) {
20
- try {
21
- const configPath = path.join(projectRoot, ".atabey", "config.json");
22
- if (fs.existsSync(configPath)) {
23
- const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
24
- return config.backendLanguage || "Node.js (TypeScript)";
25
- }
26
- }
27
- catch {
28
- // Fallback to default
29
- }
30
- return "Node.js (TypeScript)";
31
- }
32
- /**
33
- * Returns the default lint command for the given language.
34
- */
35
- export function getDefaultLintCommand(language) {
36
- if (language.includes("Go"))
37
- return "go fmt ./...";
38
- if (language.includes("Java"))
39
- return "./gradlew check"; // or mvn check
40
- if (language.includes("Python"))
41
- return "ruff check .";
42
- if (language.includes(".NET"))
43
- return "dotnet format";
44
- return "npm run lint";
45
- }
46
- /**
47
- * Returns the default test command for the given language.
48
- */
49
- export function getDefaultTestCommand(language) {
50
- if (language.includes("Go"))
51
- return "go test ./...";
52
- if (language.includes("Java"))
53
- return "./gradlew test"; // or mvn test
54
- if (language.includes("Python"))
55
- return "pytest";
56
- if (language.includes(".NET"))
57
- return "dotnet test";
58
- return "npm test";
59
- }
@@ -1,231 +0,0 @@
1
- import ts from "typescript";
2
- import fs from "fs";
3
- import path from "path";
4
- import { resolveFrameworkDir } from "./security.js";
5
- /**
6
- * Enterprise Compliance Guardrail
7
- * Checks content against corporate standards using AST analysis before allowing file mutations.
8
- */
9
- export function verifyCorporateCompliance(content, filePath) {
10
- // Skip compliance checks for non-source files or specific ignored files
11
- if (filePath.endsWith(".json") || filePath.endsWith(".md") || filePath.endsWith(".env.example")) {
12
- return;
13
- }
14
- const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
15
- const errors = [];
16
- /**
17
- * Recursive AST Visitor
18
- */
19
- function visit(node) {
20
- // 1. Zero Console Policy
21
- if (ts.isPropertyAccessExpression(node)) {
22
- const expression = node.expression;
23
- const name = node.name.text;
24
- if (ts.isIdentifier(expression) && expression.text === "console") {
25
- if (["log", "warn", "error"].includes(name)) {
26
- // Check if file is exempt
27
- if (!filePath.includes("logger.ts") && !filePath.includes("check.ts") && !filePath.includes("cli.ts")) {
28
- errors.push(`[ERROR] Corporate Compliance Breach: 'console.${name}' usage is forbidden at line ${sourceFile.getLineAndCharacterOfPosition(node.getStart()).line + 1}.`);
29
- }
30
- }
31
- }
32
- }
33
- // 2. No Explicit Any Policy
34
- if (ts.isTypeReferenceNode(node)) {
35
- if (ts.isIdentifier(node.typeName) && node.typeName.text === "any") {
36
- if (!filePath.includes("definitions.ts") && !filePath.includes("types.ts")) {
37
- errors.push(`[ERROR] Corporate Compliance Breach: 'any' type is forbidden at line ${sourceFile.getLineAndCharacterOfPosition(node.getStart()).line + 1}.`);
38
- }
39
- }
40
- }
41
- // 3. Zero UI Library Policy (No @chakra-ui, mui, @shadcn)
42
- if (ts.isImportDeclaration(node)) {
43
- const moduleSpecifier = node.moduleSpecifier;
44
- if (ts.isStringLiteral(moduleSpecifier)) {
45
- const forbiddenLibs = ["@chakra-ui", "mui", "@shadcn", "antd", "bootstrap"];
46
- const lib = forbiddenLibs.find(l => moduleSpecifier.text.includes(l));
47
- if (lib) {
48
- errors.push(`[ERROR] Corporate Compliance Breach: External UI library '${lib}' usage is FORBIDDEN at line ${sourceFile.getLineAndCharacterOfPosition(node.getStart()).line + 1}. Build atomic components manually instead.`);
49
- }
50
- }
51
- }
52
- // Handle 'any' as a keyword type (e.g., parameter: any)
53
- if (node.kind === ts.SyntaxKind.AnyKeyword) {
54
- if (!filePath.includes("definitions.ts") && !filePath.includes("types.ts")) {
55
- errors.push(`[ERROR] Corporate Compliance Breach: 'any' keyword is forbidden at line ${sourceFile.getLineAndCharacterOfPosition(node.getStart()).line + 1}.`);
56
- }
57
- }
58
- ts.forEachChild(node, visit);
59
- }
60
- visit(sourceFile);
61
- // 3. Hardcoded Secrets & PII Guard
62
- const piiKeywords = [
63
- { regex: /API_KEY\s*=\s*['"][^'"]+['"]/i, msg: "Hardcoded API Key" },
64
- { regex: /SECRET\s*=\s*['"][^'"]+['"]/i, msg: "Hardcoded Secret" },
65
- { regex: /PASSWORD\s*=\s*['"][^'"]+['"]/i, msg: "Hardcoded Password" },
66
- { regex: /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/, msg: "PII Detected: Email Address" },
67
- { regex: /\b\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}\b/, msg: "PII Detected: Credit Card Pattern" }
68
- ];
69
- for (const { regex, msg } of piiKeywords) {
70
- if (regex.test(content)) {
71
- // Allow emails in specific files like README or package.json
72
- if (msg.includes("Email") && (filePath.endsWith("README.md") || filePath.endsWith("package.json") || filePath.includes("CONTRIBUTING"))) {
73
- continue;
74
- }
75
- errors.push(`[ERROR] Corporate Compliance Breach: ${msg} detected.`);
76
- }
77
- }
78
- if (errors.length > 0) {
79
- throw new Error(errors.join("\n"));
80
- }
81
- }
82
- export function isHighRiskOperation(content, filePath) {
83
- const fileName = filePath.toLowerCase();
84
- // 1. Database Deletions / Table Drops
85
- if (fileName.endsWith(".sql") || fileName.endsWith(".ts") || fileName.endsWith(".js") || fileName.endsWith(".go")) {
86
- const dropRegex = /\b(DROP\s+(DATABASE|TABLE|SCHEMA|VIEW|INDEX)|TRUNCATE\s+TABLE)\b/i;
87
- if (dropRegex.test(content)) {
88
- return { isRisk: true, reason: "Database structural deletion detected (DROP/TRUNCATE)" };
89
- }
90
- }
91
- // 2. Package Updates
92
- if (fileName.endsWith("package.json")) {
93
- return { isRisk: true, reason: "Dependency/package update operation detected" };
94
- }
95
- // 3. Deployment / Infrastructure Scripts
96
- if (fileName.includes("deploy") ||
97
- fileName.includes("dockerfile") ||
98
- fileName.includes("docker-compose") ||
99
- fileName.includes("k8s") ||
100
- fileName.includes("kubernetes") ||
101
- fileName.includes("github/workflows")) {
102
- return { isRisk: true, reason: "Infrastructure or deployment script mutation detected" };
103
- }
104
- return { isRisk: false };
105
- }
106
- export async function verifyRiskAndAwaitApproval(projectRoot, content, filePath) {
107
- const assessment = isHighRiskOperation(content, filePath);
108
- if (!assessment.isRisk) {
109
- return;
110
- }
111
- const frameworkDir = resolveFrameworkDir(projectRoot);
112
- const absoluteFrameworkPath = path.isAbsolute(frameworkDir)
113
- ? frameworkDir
114
- : path.resolve(projectRoot, frameworkDir);
115
- const statusPath = path.join(absoluteFrameworkPath, "memory", "status.json");
116
- const statePath = path.join(absoluteFrameworkPath, "memory", "state.json");
117
- const messagesDir = path.join(absoluteFrameworkPath, "messages");
118
- const managerMsgPath = path.join(messagesDir, "manager.json");
119
- let activeAgent = null;
120
- let traceId = "UNKNOWN";
121
- // 1. Resolve traceId from state.json
122
- if (fs.existsSync(statePath)) {
123
- try {
124
- const state = JSON.parse(fs.readFileSync(statePath, "utf8"));
125
- if (state && state.traceId) {
126
- traceId = state.traceId;
127
- }
128
- }
129
- catch { /* ignore */ }
130
- }
131
- // 2. Resolve active agent from status.json
132
- let statusData = {};
133
- if (fs.existsSync(statusPath)) {
134
- try {
135
- statusData = JSON.parse(fs.readFileSync(statusPath, "utf8"));
136
- for (const [agentName, info] of Object.entries(statusData)) {
137
- if (info.state === "EXECUTING") {
138
- activeAgent = agentName.startsWith("@") ? agentName : `@${agentName}`;
139
- break;
140
- }
141
- }
142
- }
143
- catch { /* ignore */ }
144
- }
145
- if (!activeAgent) {
146
- throw new Error(`Security Exception: High-risk operation blocked. ${assessment.reason}. (No active executing agent found)`);
147
- }
148
- // 3. Update active agent status to WAITING_FOR_APPROVAL
149
- const originalTask = statusData[activeAgent.replace("@", "")]?.task || statusData[activeAgent]?.task || "Executing task";
150
- const statusKey = activeAgent.replace("@", "");
151
- statusData[statusKey] = {
152
- state: "WAITING_FOR_APPROVAL",
153
- task: `[PAUSED] Waiting for approval: ${assessment.reason} on ${filePath}`
154
- };
155
- try {
156
- fs.writeFileSync(statusPath, JSON.stringify(statusData, null, 2));
157
- }
158
- catch { /* ignore */ }
159
- // 4. Create and append ALERT message to messages/manager.json
160
- if (!fs.existsSync(messagesDir)) {
161
- fs.mkdirSync(messagesDir, { recursive: true });
162
- }
163
- const alertMsg = {
164
- timestamp: new Date().toISOString(),
165
- from: activeAgent,
166
- to: "@manager",
167
- category: "ALERT",
168
- content: `High-risk operation: ${assessment.reason} on ${filePath}`,
169
- traceId: traceId,
170
- status: "PENDING",
171
- priority: "HIGH",
172
- requiresApproval: true,
173
- action: `MUTATION:${filePath}`
174
- };
175
- try {
176
- fs.appendFileSync(managerMsgPath, JSON.stringify(alertMsg) + "\n");
177
- }
178
- catch (err) {
179
- statusData[statusKey] = { state: "EXECUTING", task: originalTask };
180
- fs.writeFileSync(statusPath, JSON.stringify(statusData, null, 2));
181
- throw new Error(`Security Exception: Failed to queue approval request. ${String(err)}`, { cause: err });
182
- }
183
- // 5. Polling Loop: Wait for approval (up to 60 seconds)
184
- const pollIntervalMs = 500;
185
- const timeoutMs = 60000;
186
- const start = Date.now();
187
- while (Date.now() - start < timeoutMs) {
188
- // Non-blocking wait
189
- await new Promise(resolve => setTimeout(resolve, pollIntervalMs));
190
- if (fs.existsSync(managerMsgPath)) {
191
- try {
192
- const contentStr = fs.readFileSync(managerMsgPath, "utf8").trim();
193
- const lines = contentStr.split("\n");
194
- let isApproved = false;
195
- let isDenied = false;
196
- for (const line of lines) {
197
- if (!line.trim())
198
- continue;
199
- const parsed = JSON.parse(line);
200
- if (parsed.traceId === traceId && parsed.category === "ALERT" && parsed.action === `MUTATION:${filePath}`) {
201
- if (parsed.status === "APPROVED") {
202
- isApproved = true;
203
- }
204
- else if (parsed.status === "PROCESSED" || parsed.status === "DENIED") {
205
- isDenied = true;
206
- }
207
- }
208
- }
209
- if (isApproved) {
210
- statusData[statusKey] = { state: "EXECUTING", task: originalTask };
211
- fs.writeFileSync(statusPath, JSON.stringify(statusData, null, 2));
212
- return;
213
- }
214
- if (isDenied) {
215
- throw new Error("Security Exception: High-risk operation was explicitly DENIED by user.");
216
- }
217
- }
218
- catch (err) {
219
- if (err.message.includes("explicitly DENIED")) {
220
- throw err;
221
- }
222
- }
223
- }
224
- }
225
- statusData[statusKey] = { state: "EXECUTING", task: originalTask };
226
- try {
227
- fs.writeFileSync(statusPath, JSON.stringify(statusData, null, 2));
228
- }
229
- catch { /* ignore */ }
230
- throw new Error(`Security Exception: High-risk operation timed out waiting for approval. (${assessment.reason})`);
231
- }
@@ -1,44 +0,0 @@
1
- import fs from "fs";
2
- import path from "path";
3
- /**
4
- * Ensures directory existence.
5
- */
6
- export function ensureDir(dirPath) {
7
- if (!fs.existsSync(dirPath)) {
8
- fs.mkdirSync(dirPath, { recursive: true });
9
- }
10
- }
11
- /**
12
- * Atomically writes a text file.
13
- */
14
- export function writeTextFileAtomic(filePath, content) {
15
- const dir = path.dirname(filePath);
16
- ensureDir(dir);
17
- const tempPath = `${filePath}.${Math.random().toString(36).slice(2, 9)}.tmp`;
18
- const finalContent = content.endsWith("\n") ? content : `${content}\n`;
19
- try {
20
- fs.writeFileSync(tempPath, finalContent, "utf8");
21
- fs.renameSync(tempPath, filePath);
22
- }
23
- catch (err) {
24
- if (fs.existsSync(tempPath)) {
25
- try {
26
- fs.unlinkSync(tempPath);
27
- }
28
- catch { /* ignore */ }
29
- }
30
- throw err;
31
- }
32
- }
33
- /**
34
- * Atomically appends to a file (if supported by OS) or simulates it.
35
- * Note: Real atomic append on POSIX is a single write() call with O_APPEND.
36
- * For simplicity and robustness across platforms, we use a simple append here
37
- * as the risk of corruption is lower than a full rewrite, but for logs
38
- * it's acceptable.
39
- */
40
- export function appendFileSafe(filePath, content) {
41
- const dir = path.dirname(filePath);
42
- ensureDir(dir);
43
- fs.appendFileSync(filePath, content, "utf8");
44
- }
@@ -1,56 +0,0 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import { resolveFrameworkDir } from "./security.js";
4
- export const Metrics = {
5
- /**
6
- * Estimates tokens based on character count (rough heuristic: 1 token ~= 4 chars).
7
- */
8
- estimateTokens: (text) => {
9
- return Math.ceil(text.length / 4);
10
- },
11
- /**
12
- * Logs the token usage and action to the observability metrics file.
13
- */
14
- logUsage: (projectRoot, agent, action, tokens) => {
15
- Metrics.saveMetric(projectRoot, {
16
- timestamp: new Date().toISOString(),
17
- agent,
18
- action,
19
- estimatedTokens: tokens
20
- });
21
- },
22
- /**
23
- * Logs an error occurrence to the observability metrics file.
24
- */
25
- logError: (projectRoot, agent, action, error) => {
26
- Metrics.saveMetric(projectRoot, {
27
- timestamp: new Date().toISOString(),
28
- agent,
29
- action: `ERROR: ${action}`,
30
- estimatedTokens: 0,
31
- error
32
- });
33
- },
34
- /**
35
- * Internal helper to save metric entries.
36
- */
37
- saveMetric: (projectRoot, entry) => {
38
- const frameworkDir = resolveFrameworkDir(projectRoot);
39
- const metricsPath = path.join(projectRoot, frameworkDir, "observability/metrics.json");
40
- try {
41
- const metricsDir = path.dirname(metricsPath);
42
- if (!fs.existsSync(metricsDir))
43
- fs.mkdirSync(metricsDir, { recursive: true });
44
- let currentMetrics = [];
45
- if (fs.existsSync(metricsPath)) {
46
- currentMetrics = JSON.parse(fs.readFileSync(metricsPath, "utf8"));
47
- }
48
- currentMetrics.push(entry);
49
- // Keep only last 100 entries to save space
50
- if (currentMetrics.length > 100)
51
- currentMetrics.shift();
52
- fs.writeFileSync(metricsPath, JSON.stringify(currentMetrics, null, 2));
53
- }
54
- catch { /* ignore: metrics should not block the main process */ }
55
- }
56
- };
@@ -1,71 +0,0 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import { resolveFrameworkDir } from "./security.js";
4
- function globToRegex(glob) {
5
- const escaped = glob.replace(/[.+^${}()|[\]\\]/g, "\\$&");
6
- const step1 = escaped.replace(/\*\*/g, "__DBL_STR__");
7
- const step2 = step1.replace(/\*/g, "[^/]*");
8
- const regexStr = "^" + step2.replace(/__DBL_STR__/g, ".*") + "$";
9
- return new RegExp(regexStr);
10
- }
11
- /**
12
- * Validates if the active agent has write permission for the target file.
13
- * Automatically identifies the active agent by checking the status.json store
14
- * for the agent in the "EXECUTING" state.
15
- */
16
- export function verifyWritePermission(projectRoot, targetFilePath) {
17
- const frameworkDir = resolveFrameworkDir(projectRoot);
18
- const absoluteFrameworkPath = path.isAbsolute(frameworkDir)
19
- ? frameworkDir
20
- : path.resolve(projectRoot, frameworkDir);
21
- const matrixPath = path.join(absoluteFrameworkPath, "permission-matrix.json");
22
- // If no permission matrix exists, skip enforcement (default allow)
23
- if (!fs.existsSync(matrixPath)) {
24
- return;
25
- }
26
- let matrix;
27
- try {
28
- matrix = JSON.parse(fs.readFileSync(matrixPath, "utf8"));
29
- }
30
- catch (e) {
31
- throw new Error(`Failed to parse permission-matrix.json: ${String(e)}`, { cause: e });
32
- }
33
- // Determine the active agent from status.json
34
- const statusPath = path.join(absoluteFrameworkPath, "memory", "status.json");
35
- let activeAgent = null;
36
- if (fs.existsSync(statusPath)) {
37
- try {
38
- const status = JSON.parse(fs.readFileSync(statusPath, "utf8"));
39
- // Find an agent that is currently in the EXECUTING state
40
- for (const [agentName, info] of Object.entries(status)) {
41
- const data = info;
42
- if (data.state === "EXECUTING") {
43
- activeAgent = agentName.startsWith("@") ? agentName : `@${agentName}`;
44
- break;
45
- }
46
- }
47
- }
48
- catch (e) {
49
- // Log warning but don't crash, default to allowing if status can't be parsed
50
- process.stderr.write(`[Permissions] Warning: Failed to read status.json: ${String(e)}\n`);
51
- }
52
- }
53
- // If no active executing agent is found, default to allowing
54
- if (!activeAgent) {
55
- return;
56
- }
57
- const agentRules = matrix[activeAgent];
58
- // If no rules defined for the agent, default to allowing
59
- if (!agentRules || !agentRules.write) {
60
- return;
61
- }
62
- // Resolve target path relative to project root for glob matching
63
- const relativeTargetPath = path.relative(projectRoot, path.resolve(projectRoot, targetFilePath));
64
- const allowed = agentRules.write.some(glob => {
65
- const regex = globToRegex(glob);
66
- return regex.test(relativeTargetPath);
67
- });
68
- if (!allowed) {
69
- throw new Error(`Permission Denied: Agent ${activeAgent} is not authorized to write to "${relativeTargetPath}". Matrix rules restrict writes to: [${agentRules.write.join(", ")}].`);
70
- }
71
- }
@@ -1,60 +0,0 @@
1
- import path from "path";
2
- import fs from "fs";
3
- import { FRAMEWORK, MCP, UNIFIED_HUB_DIR } from "../constants.js"; // New import
4
- import os from "os"; // Need os.homedir()
5
- /**
6
- * Validates and resolves a user-provided path to prevent path traversal attacks.
7
- * Ensures the resolved path stays within the project root boundary.
8
- */
9
- export function safePath(projectRoot, userPath) {
10
- const resolved = path.resolve(projectRoot, userPath);
11
- const normalizedRoot = path.resolve(projectRoot);
12
- if (!resolved.startsWith(normalizedRoot + path.sep) && resolved !== normalizedRoot) {
13
- throw new Error(`Access denied: path "${userPath}" escapes project root.`);
14
- }
15
- return resolved;
16
- }
17
- /**
18
- * Resolves the active framework directory.
19
- * Priority: ATABEY_TEST_DIR (env) -> package.json `atabey.frameworkDir` -> `.atabey` -> other adapter dirs -> global HOME.
20
- */
21
- export function resolveFrameworkDir(projectRoot) {
22
- // For test environments, use the explicitly set test directory.
23
- const testDir = process.env[MCP.TEST_DIR_ENV];
24
- if (testDir)
25
- return testDir;
26
- // 1. Authoritative source: read from package.json if present
27
- try {
28
- const pkgPath = path.join(projectRoot, "package.json");
29
- if (fs.existsSync(pkgPath)) {
30
- const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
31
- const atabeyConfig = pkg["atabey"];
32
- if (atabeyConfig && typeof atabeyConfig["frameworkDir"] === "string") {
33
- // Ensure the path is relative if it's within the project, otherwise use as-is.
34
- const resolvedDir = path.resolve(projectRoot, atabeyConfig["frameworkDir"]);
35
- if (resolvedDir.startsWith(path.resolve(projectRoot))) {
36
- return path.relative(projectRoot, resolvedDir);
37
- }
38
- return atabeyConfig["frameworkDir"];
39
- }
40
- }
41
- }
42
- catch {
43
- // ignore — fall through to filesystem scan
44
- }
45
- // 2. Filesystem scan in projectRoot for common framework directories
46
- const localCandidates = [
47
- FRAMEWORK.CORE_DIR, // .atabey
48
- UNIFIED_HUB_DIR, // .agents
49
- // Add other adapter specific directories if needed, or remove if unified is strictly enforced
50
- ];
51
- for (const candidate of localCandidates) {
52
- const candidatePath = path.join(projectRoot, candidate);
53
- if (fs.existsSync(candidatePath)) {
54
- return candidate;
55
- }
56
- }
57
- // 3. Fallback to global home directory.
58
- const homeDir = os.homedir();
59
- return path.join(homeDir, FRAMEWORK.CORE_DIR);
60
- }
@@ -1,71 +0,0 @@
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
- }
@@ -1,5 +0,0 @@
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";