@aidemd-mcp/server 0.2.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/.aide/docs/.aide +128 -0
- package/.aide/docs/agent-readable-code.md +74 -0
- package/.aide/docs/aide-spec.md +201 -0
- package/.aide/docs/aide-template.md +110 -0
- package/.aide/docs/automated-qa.md +111 -0
- package/.aide/docs/cascading-alignment.md +107 -0
- package/.aide/docs/index.md +38 -0
- package/.aide/docs/plan-aide.md +77 -0
- package/.aide/docs/plan.aide +60 -0
- package/.aide/docs/progressive-disclosure.md +72 -0
- package/.aide/docs/todo-aide.md +77 -0
- package/.aide/intent.aide +256 -0
- package/.aide/plan.aide +169 -0
- package/.aide/todo.aide +47 -0
- package/.claude/.aide +246 -0
- package/.claude/commands/aide/align.md +15 -0
- package/.claude/commands/aide/build.md +17 -0
- package/.claude/commands/aide/fix.md +20 -0
- package/.claude/commands/aide/init.md +171 -0
- package/.claude/commands/aide/plan.md +25 -0
- package/.claude/commands/aide/qa.md +25 -0
- package/.claude/commands/aide/refactor.md +29 -0
- package/.claude/commands/aide/research.md +21 -0
- package/.claude/commands/aide/spec.md +24 -0
- package/.claude/commands/aide/synthesize.md +20 -0
- package/.claude/commands/aide/update-playbook.md +18 -0
- package/.claude/commands/aide/upgrade.md +91 -0
- package/LICENSE +21 -0
- package/README.md +88 -0
- package/dist/cli/App/index.d.ts +14 -0
- package/dist/cli/App/index.js +282 -0
- package/dist/cli/DetailPanel/index.d.ts +24 -0
- package/dist/cli/DetailPanel/index.js +57 -0
- package/dist/cli/TreePanel/index.d.ts +24 -0
- package/dist/cli/TreePanel/index.js +65 -0
- package/dist/cli/buildTreeData/index.d.ts +7 -0
- package/dist/cli/buildTreeData/index.js +51 -0
- package/dist/cli/findPrimaryIntent/index.d.ts +12 -0
- package/dist/cli/findPrimaryIntent/index.js +20 -0
- package/dist/cli/flattenTree/index.d.ts +16 -0
- package/dist/cli/flattenTree/index.js +20 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +15 -0
- package/dist/cli/init/index.d.ts +2 -0
- package/dist/cli/init/index.js +33 -0
- package/dist/cli/init/writeInitCommand/index.d.ts +13 -0
- package/dist/cli/init/writeInitCommand/index.js +25 -0
- package/dist/cli/init/writeMcpEntry/index.d.ts +12 -0
- package/dist/cli/init/writeMcpEntry/index.js +51 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +228 -0
- package/dist/tools/discover/buildAncestorChain/index.d.ts +17 -0
- package/dist/tools/discover/buildAncestorChain/index.js +98 -0
- package/dist/tools/discover/buildTree/index.d.ts +9 -0
- package/dist/tools/discover/buildTree/index.js +57 -0
- package/dist/tools/discover/index.d.ts +20 -0
- package/dist/tools/discover/index.js +49 -0
- package/dist/tools/init/applySteps/index.d.ts +30 -0
- package/dist/tools/init/applySteps/index.js +76 -0
- package/dist/tools/init/configureIde/index.d.ts +21 -0
- package/dist/tools/init/configureIde/index.js +135 -0
- package/dist/tools/init/detectFramework/index.d.ts +11 -0
- package/dist/tools/init/detectFramework/index.js +53 -0
- package/dist/tools/init/index.d.ts +46 -0
- package/dist/tools/init/index.js +99 -0
- package/dist/tools/init/initContent/index.d.ts +99 -0
- package/dist/tools/init/initContent/index.js +162 -0
- package/dist/tools/init/installAgents/index.d.ts +12 -0
- package/dist/tools/init/installAgents/index.js +60 -0
- package/dist/tools/init/installMethodologyDocs/index.d.ts +14 -0
- package/dist/tools/init/installMethodologyDocs/index.js +62 -0
- package/dist/tools/init/installSkills/index.d.ts +12 -0
- package/dist/tools/init/installSkills/index.js +60 -0
- package/dist/tools/init/provisionBrain/index.d.ts +23 -0
- package/dist/tools/init/provisionBrain/index.js +239 -0
- package/dist/tools/init/resolveBrainHints/index.d.ts +17 -0
- package/dist/tools/init/resolveBrainHints/index.js +44 -0
- package/dist/tools/init/scaffoldCommands/index.d.ts +38 -0
- package/dist/tools/init/scaffoldCommands/index.js +94 -0
- package/dist/tools/init/wireMcp/index.d.ts +16 -0
- package/dist/tools/init/wireMcp/index.js +72 -0
- package/dist/tools/init/writeMethodology/index.d.ts +20 -0
- package/dist/tools/init/writeMethodology/index.js +94 -0
- package/dist/tools/read/index.d.ts +15 -0
- package/dist/tools/read/index.js +79 -0
- package/dist/tools/scaffold/index.d.ts +22 -0
- package/dist/tools/scaffold/index.js +128 -0
- package/dist/tools/upgrade/applyFiles/index.d.ts +33 -0
- package/dist/tools/upgrade/applyFiles/index.js +65 -0
- package/dist/tools/upgrade/buildVersionsMeta/index.d.ts +20 -0
- package/dist/tools/upgrade/buildVersionsMeta/index.js +51 -0
- package/dist/tools/upgrade/checkIdeConfig/index.d.ts +24 -0
- package/dist/tools/upgrade/checkIdeConfig/index.js +134 -0
- package/dist/tools/upgrade/checkMcpConfig/index.d.ts +17 -0
- package/dist/tools/upgrade/checkMcpConfig/index.js +81 -0
- package/dist/tools/upgrade/compareFile/index.d.ts +12 -0
- package/dist/tools/upgrade/compareFile/index.js +24 -0
- package/dist/tools/upgrade/index.d.ts +24 -0
- package/dist/tools/upgrade/index.js +139 -0
- package/dist/tools/upgrade/spliceStub/index.d.ts +13 -0
- package/dist/tools/upgrade/spliceStub/index.js +91 -0
- package/dist/tools/validate/index.d.ts +18 -0
- package/dist/tools/validate/index.js +65 -0
- package/dist/types/index.d.ts +277 -0
- package/dist/types/index.js +10 -0
- package/dist/util/classify/index.d.ts +17 -0
- package/dist/util/classify/index.js +134 -0
- package/dist/util/parseBody/index.d.ts +7 -0
- package/dist/util/parseBody/index.js +43 -0
- package/dist/util/parseFrontmatter/index.d.ts +12 -0
- package/dist/util/parseFrontmatter/index.js +64 -0
- package/dist/util/scan/index.d.ts +7 -0
- package/dist/util/scan/index.js +82 -0
- package/package.json +59 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { AideFile, AideFileType, ValidationWarning } from "../../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Classify a filename into an AideFileType based on naming conventions:
|
|
4
|
+
* - `.aide` or `intent.aide` → "intent"
|
|
5
|
+
* - `research.aide` → "research"
|
|
6
|
+
* - `todo.aide` → "todo"
|
|
7
|
+
* - `plan.aide` → "plan"
|
|
8
|
+
*/
|
|
9
|
+
export declare function classifyFile(filename: string): AideFileType;
|
|
10
|
+
/**
|
|
11
|
+
* Detect anomalies across a set of .aide files:
|
|
12
|
+
* - .aide + intent.aide in the same folder (naming conflict)
|
|
13
|
+
* - research.aide without a corresponding intent spec (orphaned research)
|
|
14
|
+
* - .aide in a folder with no orchestrator index.ts (orphaned spec)
|
|
15
|
+
* - Orchestrators with 3+ helper imports but no .aide (missing spec)
|
|
16
|
+
*/
|
|
17
|
+
export declare function detectAnomalies(files: AideFile[], root: string): Promise<ValidationWarning[]>;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
2
|
+
import { join, dirname, basename, relative } from "node:path";
|
|
3
|
+
import { SKIP_DIRS } from "../../types/index.js";
|
|
4
|
+
/**
|
|
5
|
+
* Classify a filename into an AideFileType based on naming conventions:
|
|
6
|
+
* - `.aide` or `intent.aide` → "intent"
|
|
7
|
+
* - `research.aide` → "research"
|
|
8
|
+
* - `todo.aide` → "todo"
|
|
9
|
+
* - `plan.aide` → "plan"
|
|
10
|
+
*/
|
|
11
|
+
export function classifyFile(filename) {
|
|
12
|
+
const base = basename(filename);
|
|
13
|
+
if (base === "research.aide")
|
|
14
|
+
return "research";
|
|
15
|
+
if (base === "todo.aide")
|
|
16
|
+
return "todo";
|
|
17
|
+
if (base === "plan.aide")
|
|
18
|
+
return "plan";
|
|
19
|
+
return "intent";
|
|
20
|
+
}
|
|
21
|
+
/** Check if a file has 2+ relative `./` imports (orchestrator heuristic). */
|
|
22
|
+
async function countRelativeImports(filePath) {
|
|
23
|
+
try {
|
|
24
|
+
const content = await readFile(filePath, "utf-8");
|
|
25
|
+
const matches = content.match(/(?:import|from)\s+["']\.\/[^"']+["']/g);
|
|
26
|
+
return matches ? matches.length : 0;
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return 0;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/** Check if a directory contains an orchestrator file (index.ts or index.js). */
|
|
33
|
+
async function findOrchestrator(dir) {
|
|
34
|
+
try {
|
|
35
|
+
const entries = await readdir(dir);
|
|
36
|
+
for (const name of entries) {
|
|
37
|
+
if (name === "index.ts" || name === "index.js")
|
|
38
|
+
return join(dir, name);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// skip unreadable dirs
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Detect anomalies across a set of .aide files:
|
|
48
|
+
* - .aide + intent.aide in the same folder (naming conflict)
|
|
49
|
+
* - research.aide without a corresponding intent spec (orphaned research)
|
|
50
|
+
* - .aide in a folder with no orchestrator index.ts (orphaned spec)
|
|
51
|
+
* - Orchestrators with 3+ helper imports but no .aide (missing spec)
|
|
52
|
+
*/
|
|
53
|
+
export async function detectAnomalies(files, root) {
|
|
54
|
+
const warnings = [];
|
|
55
|
+
// Group files by directory (using absolute path dirname)
|
|
56
|
+
const byDir = new Map();
|
|
57
|
+
for (const file of files) {
|
|
58
|
+
const dir = dirname(file.path);
|
|
59
|
+
const group = byDir.get(dir) ?? [];
|
|
60
|
+
group.push(file);
|
|
61
|
+
byDir.set(dir, group);
|
|
62
|
+
}
|
|
63
|
+
// Collect all directories that have .aide files (for missing-spec scan)
|
|
64
|
+
const dirsWithSpecs = new Set(byDir.keys());
|
|
65
|
+
for (const [dir, dirFiles] of byDir) {
|
|
66
|
+
const names = dirFiles.map((f) => basename(f.path));
|
|
67
|
+
const relDir = dirFiles[0].relativePath.split("/").slice(0, -1).join("/") || ".";
|
|
68
|
+
// naming-conflict: .aide + intent.aide in same folder
|
|
69
|
+
if (names.includes(".aide") && names.includes("intent.aide")) {
|
|
70
|
+
warnings.push({
|
|
71
|
+
kind: "naming-conflict",
|
|
72
|
+
path: relDir,
|
|
73
|
+
message: "Both .aide and intent.aide exist. Remove .aide or rename to intent.aide.",
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
// orphaned-research: research.aide without intent spec
|
|
77
|
+
const hasResearch = names.includes("research.aide");
|
|
78
|
+
const hasIntent = names.includes(".aide") || names.includes("intent.aide");
|
|
79
|
+
if (hasResearch && !hasIntent) {
|
|
80
|
+
warnings.push({
|
|
81
|
+
kind: "orphaned-research",
|
|
82
|
+
path: relDir,
|
|
83
|
+
message: "research.aide exists without a corresponding intent spec.",
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
// orphaned-spec: .aide in folder with no orchestrator
|
|
87
|
+
const orchestrator = await findOrchestrator(dir);
|
|
88
|
+
if (!orchestrator) {
|
|
89
|
+
warnings.push({
|
|
90
|
+
kind: "orphaned-spec",
|
|
91
|
+
path: relDir,
|
|
92
|
+
message: "Spec file(s) in folder with no orchestrator (index.ts/index.js).",
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// missing-spec: find orchestrators with 3+ relative imports but no .aide
|
|
97
|
+
// Scan directories that DON'T already have specs
|
|
98
|
+
await scanForMissingSpecs(root, root, dirsWithSpecs, warnings);
|
|
99
|
+
return warnings;
|
|
100
|
+
}
|
|
101
|
+
/** Walk the project looking for orchestrators without specs. */
|
|
102
|
+
async function scanForMissingSpecs(dir, root, dirsWithSpecs, warnings) {
|
|
103
|
+
let entries;
|
|
104
|
+
try {
|
|
105
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
const skipSet = new Set(SKIP_DIRS);
|
|
111
|
+
for (const entry of entries) {
|
|
112
|
+
if (!entry.isDirectory())
|
|
113
|
+
continue;
|
|
114
|
+
if (skipSet.has(entry.name))
|
|
115
|
+
continue;
|
|
116
|
+
const subdir = join(dir, entry.name);
|
|
117
|
+
// Only check dirs that don't already have specs
|
|
118
|
+
if (!dirsWithSpecs.has(subdir)) {
|
|
119
|
+
const orchestrator = await findOrchestrator(subdir);
|
|
120
|
+
if (orchestrator) {
|
|
121
|
+
const importCount = await countRelativeImports(orchestrator);
|
|
122
|
+
if (importCount >= 3) {
|
|
123
|
+
const relPath = relative(root, subdir).split("\\").join("/");
|
|
124
|
+
warnings.push({
|
|
125
|
+
kind: "missing-spec",
|
|
126
|
+
path: relPath,
|
|
127
|
+
message: `Orchestrator has ${importCount} helper imports but no .aide file.`,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
await scanForMissingSpecs(subdir, root, dirsWithSpecs, warnings);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { BodySection } from "../../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Split a .aide body string into sections by `##` headings.
|
|
4
|
+
* Content before the first heading is collected as an unnamed section (heading: "").
|
|
5
|
+
* Each section's summary is the first sentence or a paragraph count.
|
|
6
|
+
*/
|
|
7
|
+
export default function parseBody(body: string): BodySection[];
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/** Extract a summary from section content: first sentence, or "N paragraphs" count. */
|
|
2
|
+
function summarize(content) {
|
|
3
|
+
const trimmed = content.trim();
|
|
4
|
+
if (!trimmed)
|
|
5
|
+
return "";
|
|
6
|
+
const firstSentenceMatch = trimmed.match(/^[^.!?]+[.!?]/);
|
|
7
|
+
if (firstSentenceMatch)
|
|
8
|
+
return firstSentenceMatch[0].trim();
|
|
9
|
+
const paragraphs = trimmed.split(/\n\s*\n/).filter((p) => p.trim().length > 0);
|
|
10
|
+
if (paragraphs.length === 1)
|
|
11
|
+
return paragraphs[0].trim().slice(0, 80);
|
|
12
|
+
return `${paragraphs.length} paragraphs`;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Split a .aide body string into sections by `##` headings.
|
|
16
|
+
* Content before the first heading is collected as an unnamed section (heading: "").
|
|
17
|
+
* Each section's summary is the first sentence or a paragraph count.
|
|
18
|
+
*/
|
|
19
|
+
export default function parseBody(body) {
|
|
20
|
+
const lines = body.split("\n");
|
|
21
|
+
const sections = [];
|
|
22
|
+
let currentHeading = "";
|
|
23
|
+
let currentLines = [];
|
|
24
|
+
for (const line of lines) {
|
|
25
|
+
if (line.startsWith("## ")) {
|
|
26
|
+
if (currentHeading !== "" || currentLines.some((l) => l.trim())) {
|
|
27
|
+
const content = currentLines.join("\n").trim();
|
|
28
|
+
sections.push({ heading: currentHeading, content, summary: summarize(content) });
|
|
29
|
+
}
|
|
30
|
+
currentHeading = line.slice(3).trim();
|
|
31
|
+
currentLines = [];
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
currentLines.push(line);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// Flush the final section.
|
|
38
|
+
if (currentHeading !== "" || currentLines.some((l) => l.trim())) {
|
|
39
|
+
const content = currentLines.join("\n").trim();
|
|
40
|
+
sections.push({ heading: currentHeading, content, summary: summarize(content) });
|
|
41
|
+
}
|
|
42
|
+
return sections;
|
|
43
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AideFrontmatter } from "../../types/index.js";
|
|
2
|
+
/** Parsed result of a raw .aide file string. */
|
|
3
|
+
export interface ParseFrontmatterResult {
|
|
4
|
+
frontmatter: AideFrontmatter | null;
|
|
5
|
+
body: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Parse YAML frontmatter and body from a raw .aide file string.
|
|
9
|
+
* Returns `{ frontmatter: null, body: raw }` when no `---` block is present.
|
|
10
|
+
* Missing `outcomes` fields default to empty arrays rather than throwing.
|
|
11
|
+
*/
|
|
12
|
+
export default function parseFrontmatter(raw: string): ParseFrontmatterResult;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { parse } from "yaml";
|
|
2
|
+
/** Extract the YAML block between the first pair of `---` delimiters. Returns null when no block is found. */
|
|
3
|
+
function extractYamlBlock(raw) {
|
|
4
|
+
const trimmed = raw.trimStart();
|
|
5
|
+
if (!trimmed.startsWith("---"))
|
|
6
|
+
return null;
|
|
7
|
+
const afterOpen = trimmed.slice(3);
|
|
8
|
+
const closeIndex = afterOpen.indexOf("\n---");
|
|
9
|
+
if (closeIndex === -1)
|
|
10
|
+
return null;
|
|
11
|
+
const yaml = afterOpen.slice(0, closeIndex).trim();
|
|
12
|
+
const rest = afterOpen.slice(closeIndex + 4).replace(/^\n/, "");
|
|
13
|
+
return { yaml, rest };
|
|
14
|
+
}
|
|
15
|
+
/** Coerce a parsed YAML value into a string array, returning an empty array on failure. */
|
|
16
|
+
function toStringArray(value) {
|
|
17
|
+
if (!Array.isArray(value))
|
|
18
|
+
return [];
|
|
19
|
+
return value.filter((v) => typeof v === "string");
|
|
20
|
+
}
|
|
21
|
+
/** Coerce raw parsed YAML into a well-typed AideFrontmatter, tolerating missing fields. */
|
|
22
|
+
function coerceFrontmatter(raw) {
|
|
23
|
+
if (!raw || typeof raw !== "object")
|
|
24
|
+
return {};
|
|
25
|
+
const obj = raw;
|
|
26
|
+
const fm = {};
|
|
27
|
+
if (typeof obj.scope === "string")
|
|
28
|
+
fm.scope = obj.scope;
|
|
29
|
+
if (typeof obj.description === "string")
|
|
30
|
+
fm.description = obj.description;
|
|
31
|
+
if (typeof obj.intent === "string")
|
|
32
|
+
fm.intent = obj.intent;
|
|
33
|
+
if (obj.status === "aligned" || obj.status === "misaligned")
|
|
34
|
+
fm.status = obj.status;
|
|
35
|
+
if (obj.outcomes && typeof obj.outcomes === "object") {
|
|
36
|
+
const outcomes = obj.outcomes;
|
|
37
|
+
fm.outcomes = {
|
|
38
|
+
desired: toStringArray(outcomes.desired),
|
|
39
|
+
undesired: toStringArray(outcomes.undesired),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
return fm;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Parse YAML frontmatter and body from a raw .aide file string.
|
|
46
|
+
* Returns `{ frontmatter: null, body: raw }` when no `---` block is present.
|
|
47
|
+
* Missing `outcomes` fields default to empty arrays rather than throwing.
|
|
48
|
+
*/
|
|
49
|
+
export default function parseFrontmatter(raw) {
|
|
50
|
+
const block = extractYamlBlock(raw);
|
|
51
|
+
if (!block)
|
|
52
|
+
return { frontmatter: null, body: raw };
|
|
53
|
+
let parsed;
|
|
54
|
+
try {
|
|
55
|
+
parsed = parse(block.yaml);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return { frontmatter: null, body: raw };
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
frontmatter: coerceFrontmatter(parsed),
|
|
62
|
+
body: block.rest,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ScanResult } from "../../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Recursively walk the filesystem from `root` and collect all .aide files.
|
|
4
|
+
* Skips node_modules, .git, dist, build, .next, coverage, __pycache__.
|
|
5
|
+
* Reads the first ~1000 bytes of each file to extract the first meaningful body line as summary.
|
|
6
|
+
*/
|
|
7
|
+
export default function scan(root: string, path?: string, shallow?: boolean): Promise<ScanResult>;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
2
|
+
import { join, relative } from "node:path";
|
|
3
|
+
import { classifyFile } from "../../util/classify/index.js";
|
|
4
|
+
import { SKIP_DIRS } from "../../types/index.js";
|
|
5
|
+
/** Extract the first meaningful body line as the summary, truncated to ~80 chars. */
|
|
6
|
+
function extractSummary(content) {
|
|
7
|
+
const lines = content.split("\n");
|
|
8
|
+
let bodyStart = 0;
|
|
9
|
+
// Skip YAML frontmatter if present
|
|
10
|
+
if (lines[0] && lines[0].trim() === "---") {
|
|
11
|
+
let closingIdx = -1;
|
|
12
|
+
for (let i = 1; i < lines.length; i++) {
|
|
13
|
+
if (lines[i].trim() === "---") {
|
|
14
|
+
closingIdx = i;
|
|
15
|
+
break;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
bodyStart = closingIdx !== -1 ? closingIdx + 1 : lines.length;
|
|
19
|
+
}
|
|
20
|
+
// Find the first non-empty, non-heading line after frontmatter
|
|
21
|
+
for (let i = bodyStart; i < lines.length; i++) {
|
|
22
|
+
const line = lines[i].trim();
|
|
23
|
+
if (!line || line.startsWith("#"))
|
|
24
|
+
continue;
|
|
25
|
+
if (line.length <= 80)
|
|
26
|
+
return line;
|
|
27
|
+
return line.slice(0, 77) + "...";
|
|
28
|
+
}
|
|
29
|
+
return "";
|
|
30
|
+
}
|
|
31
|
+
/** Normalize a Windows or mixed path to POSIX forward slashes. */
|
|
32
|
+
function toPosix(p) {
|
|
33
|
+
return p.split("\\").join("/");
|
|
34
|
+
}
|
|
35
|
+
/** Recursively walk a directory and collect all .aide files. */
|
|
36
|
+
async function walk(dir, root, files, shallow) {
|
|
37
|
+
let entries;
|
|
38
|
+
try {
|
|
39
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
for (const entry of entries) {
|
|
45
|
+
const fullPath = join(dir, entry.name);
|
|
46
|
+
if (entry.isDirectory()) {
|
|
47
|
+
if (SKIP_DIRS.includes(entry.name))
|
|
48
|
+
continue;
|
|
49
|
+
await walk(fullPath, root, files, shallow);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (!entry.name.endsWith(".aide"))
|
|
53
|
+
continue;
|
|
54
|
+
let summary = "";
|
|
55
|
+
if (!shallow) {
|
|
56
|
+
try {
|
|
57
|
+
const buf = await readFile(fullPath, { encoding: "utf-8" });
|
|
58
|
+
summary = extractSummary(buf.slice(0, 1000));
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// skip unreadable files
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
files.push({
|
|
65
|
+
path: fullPath,
|
|
66
|
+
relativePath: toPosix(relative(root, fullPath)),
|
|
67
|
+
type: classifyFile(entry.name),
|
|
68
|
+
summary,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Recursively walk the filesystem from `root` and collect all .aide files.
|
|
74
|
+
* Skips node_modules, .git, dist, build, .next, coverage, __pycache__.
|
|
75
|
+
* Reads the first ~1000 bytes of each file to extract the first meaningful body line as summary.
|
|
76
|
+
*/
|
|
77
|
+
export default async function scan(root, path, shallow) {
|
|
78
|
+
const scanRoot = path ? join(root, path) : root;
|
|
79
|
+
const files = [];
|
|
80
|
+
await walk(scanRoot, root, files, !!shallow);
|
|
81
|
+
return { root, files };
|
|
82
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@aidemd-mcp/server",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "MCP server that teaches any agent the AIDE methodology through tool descriptions and progressive disclosure tooling",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"aidemd-mcp": "dist/index.js",
|
|
8
|
+
"aide-tree": "dist/cli/index.js",
|
|
9
|
+
"server": "dist/cli/init/index.js"
|
|
10
|
+
},
|
|
11
|
+
"main": "dist/index.js",
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
|
|
14
|
+
"prepublishOnly": "rm -rf dist && npm run build",
|
|
15
|
+
"dev": "tsc --watch",
|
|
16
|
+
"test": "vitest run",
|
|
17
|
+
"aide-tree": "node dist/cli/index.js",
|
|
18
|
+
"export-pdf": "tsx scripts/export-pdf.ts"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"mcp",
|
|
22
|
+
"aide",
|
|
23
|
+
"progressive-disclosure",
|
|
24
|
+
"ai-agents",
|
|
25
|
+
"spec-documents"
|
|
26
|
+
],
|
|
27
|
+
"author": "TetsuKod.ai",
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://github.com/aidemd-mcp/server.git"
|
|
31
|
+
},
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"files": [
|
|
34
|
+
"dist",
|
|
35
|
+
"README.md",
|
|
36
|
+
".aide",
|
|
37
|
+
".claude/commands/aide"
|
|
38
|
+
],
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
41
|
+
"ink": "^7.0.0",
|
|
42
|
+
"react": "^19.2.5",
|
|
43
|
+
"yaml": "^2.8.3",
|
|
44
|
+
"zod": "^3.24.4"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/marked": "^6.0.0",
|
|
48
|
+
"@types/node": "^22.15.2",
|
|
49
|
+
"@types/react": "^19.2.14",
|
|
50
|
+
"ink-testing-library": "^4.0.0",
|
|
51
|
+
"marked": "^18.0.0",
|
|
52
|
+
"pdf-lib": "^1.17.1",
|
|
53
|
+
"puppeteer": "^24.40.0",
|
|
54
|
+
"tsc-alias": "^1.8.16",
|
|
55
|
+
"tsx": "^4.21.0",
|
|
56
|
+
"typescript": "^5.8.3",
|
|
57
|
+
"vitest": "^3.1.2"
|
|
58
|
+
}
|
|
59
|
+
}
|