@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,239 @@
|
|
|
1
|
+
import { readFile, access, readdir } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { platform } from "node:os";
|
|
4
|
+
/** Check if a path exists. */
|
|
5
|
+
async function exists(path) {
|
|
6
|
+
try {
|
|
7
|
+
await access(path);
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
/** Check if a vault already exists at brainPath (.obsidian/ dir present, or directory is non-empty). */
|
|
15
|
+
async function vaultExists(brainPath) {
|
|
16
|
+
if (await exists(join(brainPath, ".obsidian")))
|
|
17
|
+
return true;
|
|
18
|
+
try {
|
|
19
|
+
const entries = await readdir(brainPath);
|
|
20
|
+
return entries.length > 0;
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/** Read a file, returning empty string if it doesn't exist. */
|
|
27
|
+
async function safeReadFile(path) {
|
|
28
|
+
try {
|
|
29
|
+
return await readFile(path, "utf-8");
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return "";
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/** Build the Obsidian MCP server entry, wrapping with cmd /c on Windows. */
|
|
36
|
+
function obsidianMcpEntry(brainPath) {
|
|
37
|
+
if (platform() === "win32") {
|
|
38
|
+
return { command: "cmd", args: ["/c", "npx", "@bitbonsai/mcpvault", brainPath] };
|
|
39
|
+
}
|
|
40
|
+
return { command: "npx", args: ["@bitbonsai/mcpvault", brainPath] };
|
|
41
|
+
}
|
|
42
|
+
/** The vault directories that init scaffolds into a fresh vault. */
|
|
43
|
+
const VAULT_DIRS = ["research", "process/retro", "coding-playbook"];
|
|
44
|
+
/** Markdown template for the vault-root CLAUDE.md. Covers vault navigation only:
|
|
45
|
+
* wikilink crawling protocol, decision protocol, where-to-find-things table, and
|
|
46
|
+
* the brain's role in AIDE. Contains no project-specific instructions or user config. */
|
|
47
|
+
const VAULT_CLAUDE_MD_TEMPLATE = `# Brain Vault Navigation
|
|
48
|
+
|
|
49
|
+
## Brain's Role in AIDE
|
|
50
|
+
|
|
51
|
+
The vault is the pipeline's durable memory. Research agents write domain findings into it, QA agents promote retros, and the coding playbook captures engineering conventions that survive across projects. Without the vault, agents cannot persist or retrieve knowledge across runs — each session starts from scratch.
|
|
52
|
+
|
|
53
|
+
## Wikilink Crawling Protocol
|
|
54
|
+
|
|
55
|
+
When reading any vault note, follow \`[[wikilinks]]\` that are relevant to your current task. The rules:
|
|
56
|
+
|
|
57
|
+
- **Hub notes** (tagged \`hub\` or acting as section indexes) are navigation, not content. Read all wikilinks in their \`## Subnotes\` section to get the full context of that domain. Hubs do not count toward depth.
|
|
58
|
+
- **Content notes** are where depth starts (depth 0). When reading a content note, look for \`[[wikilinks]]\` in the body. If a linked note looks relevant to the task, read it (depth 1). Check *that* note's links too — go at least 1–2 levels deep from the first content note in any direction where the information could apply.
|
|
59
|
+
- **Never re-read.** If a note is already in your conversation context from a prior read, skip it. This applies across skill invocations and manual reads within the same session.
|
|
60
|
+
- **Stay in scope.** Wikilinks that point outside the current domain of interest can be skipped. Follow links that deepen understanding of the task, not links that branch into unrelated topics.
|
|
61
|
+
|
|
62
|
+
## Decision Protocol
|
|
63
|
+
|
|
64
|
+
There are two lookup paths — use the right one:
|
|
65
|
+
|
|
66
|
+
- **Coding conventions and patterns** → use the \`study-playbook\` skill. It navigates the coding playbook hub top-down (hub → section hub → content notes → wikilinks). Do NOT flat-search for playbook content with \`search_notes\` — the hub structure gives you the full picture; search gives you fragments.
|
|
67
|
+
- **Everything else** (project context, journal logs, research, domain knowledge, tasks) → use \`mcp__obsidian__search_notes\` with query terms matching the domain.
|
|
68
|
+
|
|
69
|
+
## Where to Find Things
|
|
70
|
+
|
|
71
|
+
| What you need | Where to look |
|
|
72
|
+
|---------------|---------------|
|
|
73
|
+
| Coding conventions, patterns | \`study-playbook\` skill (not search) |
|
|
74
|
+
| Domain research, reference material | \`research/\` (search by domain) |
|
|
75
|
+
| QA retros, process learnings | \`process/retro/\` |
|
|
76
|
+
`;
|
|
77
|
+
/** Markdown template for the coding-playbook hub note. Contains the five-section
|
|
78
|
+
* structure the study-playbook skill's crawling protocol expects — headings and
|
|
79
|
+
* table skeleton are present, all content rows and entries are left empty. */
|
|
80
|
+
const PLAYBOOK_HUB_TEMPLATE = `# Coding Playbook
|
|
81
|
+
|
|
82
|
+
## Task Routing
|
|
83
|
+
|
|
84
|
+
| Task domain | Section |
|
|
85
|
+
|-------------|---------|
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## How to Use This Index
|
|
90
|
+
|
|
91
|
+
Read this note first. Each section links to a **section hub** that lists its notes with keywords. Navigate to the section relevant to your task, then drill into the specific notes you need. Do not read all sections — only the ones whose keywords match the work.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Always Read First
|
|
96
|
+
|
|
97
|
+
These notes are **required reading** for every task, regardless of which section you're working in:
|
|
98
|
+
|
|
99
|
+
1. **[[your-conventions-note]]** — Add your naming, function ordering, and code hygiene conventions here.
|
|
100
|
+
2. **[[your-folder-structure-note]]** — Add your folder layout and progressive disclosure conventions here.
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Sections
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Contents
|
|
109
|
+
`;
|
|
110
|
+
/**
|
|
111
|
+
* Return planning steps for brain vault scaffolding and Obsidian MCP wiring.
|
|
112
|
+
*
|
|
113
|
+
* The function signature requires a resolved `brainPath` — the caller (agent)
|
|
114
|
+
* guarantees a path is provided before calling. Returns four `InitStep` items:
|
|
115
|
+
*
|
|
116
|
+
* 1. Vault scaffolding (category `"brain"`): `exists` if vault is already
|
|
117
|
+
* populated, `would-create` with the directories list as JSON content.
|
|
118
|
+
* 2. Playbook hub (category `"brain"`): `exists` if `coding-playbook/coding-playbook.md`
|
|
119
|
+
* is present, `would-create` with the five-section Markdown template when absent.
|
|
120
|
+
* Idempotency is per-file — checked independently of the vault-level step.
|
|
121
|
+
* 3. Vault CLAUDE.md (category `"brain"`): `exists` if `CLAUDE.md` is present at the
|
|
122
|
+
* vault root, `would-create` with the navigation guide template when absent.
|
|
123
|
+
* Idempotency is per-file — checked independently of the vault-level step.
|
|
124
|
+
* 4. Obsidian MCP entry (category `"mcp"`): `exists` if the obsidian key is
|
|
125
|
+
* already in the config, `would-create` with a `McpPrescription`.
|
|
126
|
+
* If the config file is malformed JSON, returns `would-create` with
|
|
127
|
+
* `configMalformed: true`.
|
|
128
|
+
*
|
|
129
|
+
* No step writes to disk — this helper is a planner only.
|
|
130
|
+
*/
|
|
131
|
+
export default async function provisionBrain(brainPath, mcpConfigPath) {
|
|
132
|
+
const vaultStep = await buildVaultStep(brainPath);
|
|
133
|
+
const playbookHubStep = await buildPlaybookHubStep(brainPath);
|
|
134
|
+
const vaultClaudeMdStep = await buildVaultClaudeMdStep(brainPath);
|
|
135
|
+
const mcpStep = await buildObsidianMcpStep(brainPath, mcpConfigPath);
|
|
136
|
+
return [vaultStep, playbookHubStep, vaultClaudeMdStep, mcpStep];
|
|
137
|
+
}
|
|
138
|
+
/** Build the vault scaffolding planning step. */
|
|
139
|
+
async function buildVaultStep(brainPath) {
|
|
140
|
+
if (await vaultExists(brainPath)) {
|
|
141
|
+
return {
|
|
142
|
+
name: "Brain vault",
|
|
143
|
+
status: "exists",
|
|
144
|
+
category: "brain",
|
|
145
|
+
filePath: brainPath,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
name: "Brain vault",
|
|
150
|
+
status: "would-create",
|
|
151
|
+
category: "brain",
|
|
152
|
+
filePath: brainPath,
|
|
153
|
+
content: JSON.stringify(VAULT_DIRS),
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
/** Build the playbook hub template planning step, with per-file idempotency. */
|
|
157
|
+
async function buildPlaybookHubStep(brainPath) {
|
|
158
|
+
const filePath = join(brainPath, "coding-playbook", "coding-playbook.md");
|
|
159
|
+
if (await exists(filePath)) {
|
|
160
|
+
return {
|
|
161
|
+
name: "Playbook hub",
|
|
162
|
+
status: "exists",
|
|
163
|
+
category: "brain",
|
|
164
|
+
filePath,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
return {
|
|
168
|
+
name: "Playbook hub",
|
|
169
|
+
status: "would-create",
|
|
170
|
+
category: "brain",
|
|
171
|
+
filePath,
|
|
172
|
+
content: PLAYBOOK_HUB_TEMPLATE,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
/** Build the vault-root CLAUDE.md planning step, with per-file idempotency. */
|
|
176
|
+
async function buildVaultClaudeMdStep(brainPath) {
|
|
177
|
+
const filePath = join(brainPath, "CLAUDE.md");
|
|
178
|
+
if (await exists(filePath)) {
|
|
179
|
+
return {
|
|
180
|
+
name: "Vault CLAUDE.md",
|
|
181
|
+
status: "exists",
|
|
182
|
+
category: "brain",
|
|
183
|
+
filePath,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
name: "Vault CLAUDE.md",
|
|
188
|
+
status: "would-create",
|
|
189
|
+
category: "brain",
|
|
190
|
+
filePath,
|
|
191
|
+
content: VAULT_CLAUDE_MD_TEMPLATE,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
/** Build the Obsidian MCP wiring planning step. */
|
|
195
|
+
async function buildObsidianMcpStep(brainPath, mcpConfigPath) {
|
|
196
|
+
const prescription = {
|
|
197
|
+
key: "obsidian",
|
|
198
|
+
entry: obsidianMcpEntry(brainPath),
|
|
199
|
+
};
|
|
200
|
+
const existing = await safeReadFile(mcpConfigPath);
|
|
201
|
+
if (existing) {
|
|
202
|
+
try {
|
|
203
|
+
const config = JSON.parse(existing);
|
|
204
|
+
const servers = config.mcpServers || {};
|
|
205
|
+
if ("obsidian" in servers) {
|
|
206
|
+
return {
|
|
207
|
+
name: "MCP config (obsidian)",
|
|
208
|
+
status: "exists",
|
|
209
|
+
category: "mcp",
|
|
210
|
+
filePath: mcpConfigPath,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
return {
|
|
214
|
+
name: "MCP config (obsidian)",
|
|
215
|
+
status: "would-create",
|
|
216
|
+
category: "mcp",
|
|
217
|
+
filePath: mcpConfigPath,
|
|
218
|
+
prescription,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
return {
|
|
223
|
+
name: "MCP config (obsidian)",
|
|
224
|
+
status: "would-create",
|
|
225
|
+
category: "mcp",
|
|
226
|
+
filePath: mcpConfigPath,
|
|
227
|
+
prescription,
|
|
228
|
+
configMalformed: true,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return {
|
|
233
|
+
name: "MCP config (obsidian)",
|
|
234
|
+
status: "would-create",
|
|
235
|
+
category: "mcp",
|
|
236
|
+
filePath: mcpConfigPath,
|
|
237
|
+
prescription,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { BrainHint } from "../../../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Discover all candidate brain vault locations and return them as hints.
|
|
4
|
+
*
|
|
5
|
+
* Checks three sources in order:
|
|
6
|
+
* 1. AIDE_BRAIN_PATH environment variable
|
|
7
|
+
* 2. Sibling my-brain/ directory next to projectRoot
|
|
8
|
+
* 3. Platform-conventional location: ~/my-brain
|
|
9
|
+
*
|
|
10
|
+
* Returns every candidate that exists on disk. Returns an empty array when
|
|
11
|
+
* none are found — the agent must then ask the user directly.
|
|
12
|
+
*
|
|
13
|
+
* The caller (agent) presents these hints as suggestions and asks the user
|
|
14
|
+
* to confirm or provide a different path. The hints are never silently
|
|
15
|
+
* adopted — this function reports candidates, not a winner.
|
|
16
|
+
*/
|
|
17
|
+
export default function resolveBrainHints(projectRoot: string): Promise<BrainHint[]>;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { access } from "node:fs/promises";
|
|
2
|
+
import { join, dirname } from "node:path";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
/** Check if a path exists on disk. */
|
|
5
|
+
async function exists(path) {
|
|
6
|
+
try {
|
|
7
|
+
await access(path);
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Discover all candidate brain vault locations and return them as hints.
|
|
16
|
+
*
|
|
17
|
+
* Checks three sources in order:
|
|
18
|
+
* 1. AIDE_BRAIN_PATH environment variable
|
|
19
|
+
* 2. Sibling my-brain/ directory next to projectRoot
|
|
20
|
+
* 3. Platform-conventional location: ~/my-brain
|
|
21
|
+
*
|
|
22
|
+
* Returns every candidate that exists on disk. Returns an empty array when
|
|
23
|
+
* none are found — the agent must then ask the user directly.
|
|
24
|
+
*
|
|
25
|
+
* The caller (agent) presents these hints as suggestions and asks the user
|
|
26
|
+
* to confirm or provide a different path. The hints are never silently
|
|
27
|
+
* adopted — this function reports candidates, not a winner.
|
|
28
|
+
*/
|
|
29
|
+
export default async function resolveBrainHints(projectRoot) {
|
|
30
|
+
const hints = [];
|
|
31
|
+
const envPath = process.env.AIDE_BRAIN_PATH;
|
|
32
|
+
if (envPath && await exists(envPath)) {
|
|
33
|
+
hints.push({ source: "env", path: envPath });
|
|
34
|
+
}
|
|
35
|
+
const siblingPath = join(dirname(projectRoot), "my-brain");
|
|
36
|
+
if (await exists(siblingPath)) {
|
|
37
|
+
hints.push({ source: "sibling", path: siblingPath });
|
|
38
|
+
}
|
|
39
|
+
const conventionalPath = join(homedir(), "my-brain");
|
|
40
|
+
if (await exists(conventionalPath)) {
|
|
41
|
+
hints.push({ source: "conventional", path: conventionalPath });
|
|
42
|
+
}
|
|
43
|
+
return hints;
|
|
44
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { InitStep } from "../../../types/index.js";
|
|
2
|
+
import { type CanonicalDocName } from "../../../tools/init/initContent/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Fixed registry of the /aide orchestrator entry point plus the AIDE pipeline
|
|
5
|
+
* phase commands. Owning this list here — rather than discovering it
|
|
6
|
+
* from .claude/commands/ at runtime — is the mechanical guarantee that a stray
|
|
7
|
+
* Markdown file committed under .claude/commands/aide/ cannot silently expand
|
|
8
|
+
* the pipeline.
|
|
9
|
+
*
|
|
10
|
+
* Layout: the orchestrator is installed at <commandDir>/aide.md — a peer of
|
|
11
|
+
* the `aide/` subfolder, not inside it. Phase commands are installed at
|
|
12
|
+
* <commandDir>/aide/<phase>.md. The `aide/` subfolder is the namespace, not a
|
|
13
|
+
* filename prefix — host frameworks derive slash-command namespaces from folder
|
|
14
|
+
* nesting, so a file at aide/research.md becomes `/aide:research` on the host.
|
|
15
|
+
* This is the layout .claude/commands/aide/.aide mandates: "filenames must be
|
|
16
|
+
* bare phase names ... the enclosing aide/ folder already carries the
|
|
17
|
+
* namespace". Reintroducing an `aide-` filename prefix here would produce
|
|
18
|
+
* `/aide:aide-research` on the host — the exact double-namespace failure the
|
|
19
|
+
* canonical spec names as undesired. The orchestrator lives one level up
|
|
20
|
+
* (aide.md) so it registers as the plain `/aide` command with no colon suffix.
|
|
21
|
+
*/
|
|
22
|
+
export declare const COMMANDS: readonly {
|
|
23
|
+
canonical: CanonicalDocName;
|
|
24
|
+
hostPath: string;
|
|
25
|
+
displayName: string;
|
|
26
|
+
}[];
|
|
27
|
+
/**
|
|
28
|
+
* Return planning steps for the /aide orchestrator and pipeline phase commands.
|
|
29
|
+
*
|
|
30
|
+
* For each command in COMMANDS, checks whether the host file already exists.
|
|
31
|
+
* Returns `exists` for present files, `would-create` with the canonical content
|
|
32
|
+
* for absent files. A failed canonical read returns `would-skip` for that
|
|
33
|
+
* command only.
|
|
34
|
+
*
|
|
35
|
+
* The COMMANDS export stays unchanged — upgrade's logic still uses it.
|
|
36
|
+
* This helper never writes to disk — it is a planner only.
|
|
37
|
+
*/
|
|
38
|
+
export default function scaffoldCommands(commandDir: string): Promise<InitStep[]>;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { access } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { readCanonicalDoc, } from "../../../tools/init/initContent/index.js";
|
|
4
|
+
/**
|
|
5
|
+
* Fixed registry of the /aide orchestrator entry point plus the AIDE pipeline
|
|
6
|
+
* phase commands. Owning this list here — rather than discovering it
|
|
7
|
+
* from .claude/commands/ at runtime — is the mechanical guarantee that a stray
|
|
8
|
+
* Markdown file committed under .claude/commands/aide/ cannot silently expand
|
|
9
|
+
* the pipeline.
|
|
10
|
+
*
|
|
11
|
+
* Layout: the orchestrator is installed at <commandDir>/aide.md — a peer of
|
|
12
|
+
* the `aide/` subfolder, not inside it. Phase commands are installed at
|
|
13
|
+
* <commandDir>/aide/<phase>.md. The `aide/` subfolder is the namespace, not a
|
|
14
|
+
* filename prefix — host frameworks derive slash-command namespaces from folder
|
|
15
|
+
* nesting, so a file at aide/research.md becomes `/aide:research` on the host.
|
|
16
|
+
* This is the layout .claude/commands/aide/.aide mandates: "filenames must be
|
|
17
|
+
* bare phase names ... the enclosing aide/ folder already carries the
|
|
18
|
+
* namespace". Reintroducing an `aide-` filename prefix here would produce
|
|
19
|
+
* `/aide:aide-research` on the host — the exact double-namespace failure the
|
|
20
|
+
* canonical spec names as undesired. The orchestrator lives one level up
|
|
21
|
+
* (aide.md) so it registers as the plain `/aide` command with no colon suffix.
|
|
22
|
+
*/
|
|
23
|
+
export const COMMANDS = [
|
|
24
|
+
{ canonical: "commands/aide/aide", hostPath: "aide.md", displayName: "aide" },
|
|
25
|
+
{ canonical: "commands/aide/research", hostPath: "aide/research.md", displayName: "aide:research" },
|
|
26
|
+
{ canonical: "commands/aide/spec", hostPath: "aide/spec.md", displayName: "aide:spec" },
|
|
27
|
+
{ canonical: "commands/aide/synthesize", hostPath: "aide/synthesize.md", displayName: "aide:synthesize" },
|
|
28
|
+
{ canonical: "commands/aide/plan", hostPath: "aide/plan.md", displayName: "aide:plan" },
|
|
29
|
+
{ canonical: "commands/aide/build", hostPath: "aide/build.md", displayName: "aide:build" },
|
|
30
|
+
{ canonical: "commands/aide/qa", hostPath: "aide/qa.md", displayName: "aide:qa" },
|
|
31
|
+
{ canonical: "commands/aide/fix", hostPath: "aide/fix.md", displayName: "aide:fix" },
|
|
32
|
+
{ canonical: "commands/aide/upgrade", hostPath: "aide/upgrade.md", displayName: "aide:upgrade" },
|
|
33
|
+
{ canonical: "commands/aide/init", hostPath: "aide/init.md", displayName: "aide:init" },
|
|
34
|
+
{ canonical: "commands/aide/update-playbook", hostPath: "aide/update-playbook.md", displayName: "aide:update-playbook" },
|
|
35
|
+
{ canonical: "commands/aide/refactor", hostPath: "aide/refactor.md", displayName: "aide:refactor" },
|
|
36
|
+
{ canonical: "commands/aide/align", hostPath: "aide/align.md", displayName: "aide:align" },
|
|
37
|
+
];
|
|
38
|
+
/** Check if a file exists. */
|
|
39
|
+
async function fileExists(path) {
|
|
40
|
+
try {
|
|
41
|
+
await access(path);
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Return planning steps for the /aide orchestrator and pipeline phase commands.
|
|
50
|
+
*
|
|
51
|
+
* For each command in COMMANDS, checks whether the host file already exists.
|
|
52
|
+
* Returns `exists` for present files, `would-create` with the canonical content
|
|
53
|
+
* for absent files. A failed canonical read returns `would-skip` for that
|
|
54
|
+
* command only.
|
|
55
|
+
*
|
|
56
|
+
* The COMMANDS export stays unchanged — upgrade's logic still uses it.
|
|
57
|
+
* This helper never writes to disk — it is a planner only.
|
|
58
|
+
*/
|
|
59
|
+
export default async function scaffoldCommands(commandDir) {
|
|
60
|
+
const steps = [];
|
|
61
|
+
for (const cmd of COMMANDS) {
|
|
62
|
+
const filePath = join(commandDir, cmd.hostPath);
|
|
63
|
+
if (await fileExists(filePath)) {
|
|
64
|
+
steps.push({
|
|
65
|
+
name: cmd.displayName,
|
|
66
|
+
status: "exists",
|
|
67
|
+
category: "commands",
|
|
68
|
+
filePath,
|
|
69
|
+
});
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
let content;
|
|
73
|
+
try {
|
|
74
|
+
content = readCanonicalDoc(cmd.canonical);
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
steps.push({
|
|
78
|
+
name: cmd.displayName,
|
|
79
|
+
status: "would-skip",
|
|
80
|
+
category: "commands",
|
|
81
|
+
filePath,
|
|
82
|
+
});
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
steps.push({
|
|
86
|
+
name: cmd.displayName,
|
|
87
|
+
status: "would-create",
|
|
88
|
+
category: "commands",
|
|
89
|
+
filePath,
|
|
90
|
+
content,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
return steps;
|
|
94
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { InitStep, McpPrescription } from "../../../types/index.js";
|
|
2
|
+
/** Build the MCP server entry, wrapping with cmd /c on Windows. */
|
|
3
|
+
export declare function mcpEntry(): McpPrescription["entry"];
|
|
4
|
+
/**
|
|
5
|
+
* Inspect the project's MCP config and return a planning step for the aide
|
|
6
|
+
* server entry.
|
|
7
|
+
*
|
|
8
|
+
* Returns `exists` when an aide entry is already present. Returns
|
|
9
|
+
* `would-create` with a McpPrescription when the entry is absent.
|
|
10
|
+
* If the config file exists but contains malformed JSON, returns
|
|
11
|
+
* `would-create` with `configMalformed: true` so the agent can surface
|
|
12
|
+
* the issue to the user.
|
|
13
|
+
*
|
|
14
|
+
* This helper never writes to disk — it is a planner only.
|
|
15
|
+
*/
|
|
16
|
+
export default function wireMcp(mcpConfigPath: string): Promise<InitStep>;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { platform } from "node:os";
|
|
3
|
+
/** Read a file, returning empty string if it doesn't exist. */
|
|
4
|
+
async function safeReadFile(path) {
|
|
5
|
+
try {
|
|
6
|
+
return await readFile(path, "utf-8");
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
return "";
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
/** Build the MCP server entry, wrapping with cmd /c on Windows. */
|
|
13
|
+
export function mcpEntry() {
|
|
14
|
+
if (platform() === "win32") {
|
|
15
|
+
return { command: "cmd", args: ["/c", "npx", "@aidemd-mcp/server"] };
|
|
16
|
+
}
|
|
17
|
+
return { command: "npx", args: ["@aidemd-mcp/server"] };
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Inspect the project's MCP config and return a planning step for the aide
|
|
21
|
+
* server entry.
|
|
22
|
+
*
|
|
23
|
+
* Returns `exists` when an aide entry is already present. Returns
|
|
24
|
+
* `would-create` with a McpPrescription when the entry is absent.
|
|
25
|
+
* If the config file exists but contains malformed JSON, returns
|
|
26
|
+
* `would-create` with `configMalformed: true` so the agent can surface
|
|
27
|
+
* the issue to the user.
|
|
28
|
+
*
|
|
29
|
+
* This helper never writes to disk — it is a planner only.
|
|
30
|
+
*/
|
|
31
|
+
export default async function wireMcp(mcpConfigPath) {
|
|
32
|
+
const prescription = { key: "aide", entry: mcpEntry() };
|
|
33
|
+
const existing = await safeReadFile(mcpConfigPath);
|
|
34
|
+
if (existing) {
|
|
35
|
+
try {
|
|
36
|
+
const config = JSON.parse(existing);
|
|
37
|
+
const servers = config.mcpServers || {};
|
|
38
|
+
if ("aide" in servers || "aidemd-mcp" in servers) {
|
|
39
|
+
return {
|
|
40
|
+
name: "MCP config (aide)",
|
|
41
|
+
status: "exists",
|
|
42
|
+
category: "mcp",
|
|
43
|
+
filePath: mcpConfigPath,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
name: "MCP config (aide)",
|
|
48
|
+
status: "would-create",
|
|
49
|
+
category: "mcp",
|
|
50
|
+
filePath: mcpConfigPath,
|
|
51
|
+
prescription,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return {
|
|
56
|
+
name: "MCP config (aide)",
|
|
57
|
+
status: "would-create",
|
|
58
|
+
category: "mcp",
|
|
59
|
+
filePath: mcpConfigPath,
|
|
60
|
+
prescription,
|
|
61
|
+
configMalformed: true,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
name: "MCP config (aide)",
|
|
67
|
+
status: "would-create",
|
|
68
|
+
category: "mcp",
|
|
69
|
+
filePath: mcpConfigPath,
|
|
70
|
+
prescription,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { InitStep } from "../../../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Compose the marker-bounded pointer stub. The body is the inlined
|
|
4
|
+
* STUB_TEMPLATE with the host-side hub path substituted in; marker
|
|
5
|
+
* comments wrap it for idempotency detection.
|
|
6
|
+
*/
|
|
7
|
+
export declare function composeStub(docHubDir: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* Inspect the host's agent config file and return a planning step for the
|
|
10
|
+
* AIDE methodology pointer stub.
|
|
11
|
+
*
|
|
12
|
+
* Returns `exists` if the marker is already present. Returns `would-create`
|
|
13
|
+
* with the composed stub as `content` — the caller writes the stub
|
|
14
|
+
* appended to the existing content (or as the full content when the file is
|
|
15
|
+
* absent).
|
|
16
|
+
*
|
|
17
|
+
* This helper never writes to disk — it is a planner only. `composeStub`
|
|
18
|
+
* remains a named export so upgrade's `spliceStub` can continue to use it.
|
|
19
|
+
*/
|
|
20
|
+
export default function writeMethodology(configPath: string, docHubDir: string): Promise<InitStep>;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { getMethodologyMarker } from "../../../tools/init/initContent/index.js";
|
|
3
|
+
/** Placeholder token inside the stub template that names the host-side
|
|
4
|
+
* doc hub path. writeMethodology substitutes this at install time with
|
|
5
|
+
* the caller-supplied relative path, so the stub's pointer and the
|
|
6
|
+
* installer's write target derive from a single shared source. */
|
|
7
|
+
const HUB_PATH_PLACEHOLDER = "{{HUB_PATH}}";
|
|
8
|
+
/**
|
|
9
|
+
* The pointer stub written into the host's agent config file. This is
|
|
10
|
+
* framework plumbing — not AIDE doctrine — because its only job is to
|
|
11
|
+
* tell the agent where the canonical docs live and that they must be
|
|
12
|
+
* crawled before acting on any `.aide` file. The doctrine itself lives
|
|
13
|
+
* in the canonical docs the stub points at; this template just routes
|
|
14
|
+
* the agent there.
|
|
15
|
+
*/
|
|
16
|
+
const STUB_TEMPLATE = `## AIDE — Autonomous Intent-Driven Engineering
|
|
17
|
+
|
|
18
|
+
This project uses the AIDE methodology. AIDE treats a short \`.aide\` intent
|
|
19
|
+
spec living next to orchestrator code as the contract every downstream
|
|
20
|
+
agent (architect, implementor, QA) works from — when the intent changes,
|
|
21
|
+
the code changes.
|
|
22
|
+
|
|
23
|
+
The full canonical methodology is installed in this project at
|
|
24
|
+
\`${HUB_PATH_PLACEHOLDER}/\`. Start at \`${HUB_PATH_PLACEHOLDER}/index.md\` for the doc list, then
|
|
25
|
+
crawl into the specific canonical doc your current task requires. Read
|
|
26
|
+
only what the task actually needs — the hub is organized for
|
|
27
|
+
progressive disclosure, not for front-loading.
|
|
28
|
+
|
|
29
|
+
**Before writing, editing, or acting on any \`.aide\` file, crawl the hub
|
|
30
|
+
and read the canonical doc that governs the work you are about to do.**
|
|
31
|
+
Never guess AIDE rules from memory: the files under \`${HUB_PATH_PLACEHOLDER}/\` are
|
|
32
|
+
the authoritative source, and any decision that disagrees with them is
|
|
33
|
+
wrong by definition.
|
|
34
|
+
|
|
35
|
+
**AIDE tools quick-reference:**
|
|
36
|
+
- \`aide_discover\` — map where \`.aide\` specs live in the project
|
|
37
|
+
- \`aide_read\` — read a specific \`.aide\` file with context
|
|
38
|
+
- \`aide_scaffold\` — create a new \`.aide\` file
|
|
39
|
+
- \`aide_validate\` — check spec layout for drift or issues
|
|
40
|
+
- \`aide_init\` — bootstrap AIDE into a new project (first-time setup)
|
|
41
|
+
- \`aide_upgrade\` — update/sync/refresh AIDE docs, commands, agents, and skills to the latest canonical versions (use this when asked to "update AIDE", "update the docs", or "sync the methodology")
|
|
42
|
+
`;
|
|
43
|
+
/** Read a file, returning empty string if it doesn't exist. */
|
|
44
|
+
async function safeReadFile(path) {
|
|
45
|
+
try {
|
|
46
|
+
return await readFile(path, "utf-8");
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return "";
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Compose the marker-bounded pointer stub. The body is the inlined
|
|
54
|
+
* STUB_TEMPLATE with the host-side hub path substituted in; marker
|
|
55
|
+
* comments wrap it for idempotency detection.
|
|
56
|
+
*/
|
|
57
|
+
export function composeStub(docHubDir) {
|
|
58
|
+
const marker = getMethodologyMarker();
|
|
59
|
+
const body = STUB_TEMPLATE.replaceAll(HUB_PATH_PLACEHOLDER, docHubDir);
|
|
60
|
+
return `${marker}\n${body}\n${marker}`;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Inspect the host's agent config file and return a planning step for the
|
|
64
|
+
* AIDE methodology pointer stub.
|
|
65
|
+
*
|
|
66
|
+
* Returns `exists` if the marker is already present. Returns `would-create`
|
|
67
|
+
* with the composed stub as `content` — the caller writes the stub
|
|
68
|
+
* appended to the existing content (or as the full content when the file is
|
|
69
|
+
* absent).
|
|
70
|
+
*
|
|
71
|
+
* This helper never writes to disk — it is a planner only. `composeStub`
|
|
72
|
+
* remains a named export so upgrade's `spliceStub` can continue to use it.
|
|
73
|
+
*/
|
|
74
|
+
export default async function writeMethodology(configPath, docHubDir) {
|
|
75
|
+
const existing = await safeReadFile(configPath);
|
|
76
|
+
const marker = getMethodologyMarker();
|
|
77
|
+
if (existing.includes(marker)) {
|
|
78
|
+
return {
|
|
79
|
+
name: "Methodology pointer",
|
|
80
|
+
status: "exists",
|
|
81
|
+
category: "methodology",
|
|
82
|
+
filePath: configPath,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
const stub = composeStub(docHubDir);
|
|
86
|
+
const content = existing ? `${existing}\n\n${stub}\n` : `${stub}\n`;
|
|
87
|
+
return {
|
|
88
|
+
name: "Methodology pointer",
|
|
89
|
+
status: "would-create",
|
|
90
|
+
category: "methodology",
|
|
91
|
+
filePath: configPath,
|
|
92
|
+
content,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { ReadResult } from "../../types/index.js";
|
|
3
|
+
export declare const ReadInput: z.ZodObject<{
|
|
4
|
+
path: z.ZodString;
|
|
5
|
+
}, "strip", z.ZodTypeAny, {
|
|
6
|
+
path: string;
|
|
7
|
+
}, {
|
|
8
|
+
path: string;
|
|
9
|
+
}>;
|
|
10
|
+
/**
|
|
11
|
+
* Read an .aide file with context awareness.
|
|
12
|
+
* Returns the file content, classified type, sibling specs in the same
|
|
13
|
+
* directory, and links found in the content.
|
|
14
|
+
*/
|
|
15
|
+
export default function read(root: string, filePath: string): Promise<ReadResult>;
|