@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.
Files changed (114) hide show
  1. package/.aide/docs/.aide +128 -0
  2. package/.aide/docs/agent-readable-code.md +74 -0
  3. package/.aide/docs/aide-spec.md +201 -0
  4. package/.aide/docs/aide-template.md +110 -0
  5. package/.aide/docs/automated-qa.md +111 -0
  6. package/.aide/docs/cascading-alignment.md +107 -0
  7. package/.aide/docs/index.md +38 -0
  8. package/.aide/docs/plan-aide.md +77 -0
  9. package/.aide/docs/plan.aide +60 -0
  10. package/.aide/docs/progressive-disclosure.md +72 -0
  11. package/.aide/docs/todo-aide.md +77 -0
  12. package/.aide/intent.aide +256 -0
  13. package/.aide/plan.aide +169 -0
  14. package/.aide/todo.aide +47 -0
  15. package/.claude/.aide +246 -0
  16. package/.claude/commands/aide/align.md +15 -0
  17. package/.claude/commands/aide/build.md +17 -0
  18. package/.claude/commands/aide/fix.md +20 -0
  19. package/.claude/commands/aide/init.md +171 -0
  20. package/.claude/commands/aide/plan.md +25 -0
  21. package/.claude/commands/aide/qa.md +25 -0
  22. package/.claude/commands/aide/refactor.md +29 -0
  23. package/.claude/commands/aide/research.md +21 -0
  24. package/.claude/commands/aide/spec.md +24 -0
  25. package/.claude/commands/aide/synthesize.md +20 -0
  26. package/.claude/commands/aide/update-playbook.md +18 -0
  27. package/.claude/commands/aide/upgrade.md +91 -0
  28. package/LICENSE +21 -0
  29. package/README.md +88 -0
  30. package/dist/cli/App/index.d.ts +14 -0
  31. package/dist/cli/App/index.js +282 -0
  32. package/dist/cli/DetailPanel/index.d.ts +24 -0
  33. package/dist/cli/DetailPanel/index.js +57 -0
  34. package/dist/cli/TreePanel/index.d.ts +24 -0
  35. package/dist/cli/TreePanel/index.js +65 -0
  36. package/dist/cli/buildTreeData/index.d.ts +7 -0
  37. package/dist/cli/buildTreeData/index.js +51 -0
  38. package/dist/cli/findPrimaryIntent/index.d.ts +12 -0
  39. package/dist/cli/findPrimaryIntent/index.js +20 -0
  40. package/dist/cli/flattenTree/index.d.ts +16 -0
  41. package/dist/cli/flattenTree/index.js +20 -0
  42. package/dist/cli/index.d.ts +2 -0
  43. package/dist/cli/index.js +15 -0
  44. package/dist/cli/init/index.d.ts +2 -0
  45. package/dist/cli/init/index.js +33 -0
  46. package/dist/cli/init/writeInitCommand/index.d.ts +13 -0
  47. package/dist/cli/init/writeInitCommand/index.js +25 -0
  48. package/dist/cli/init/writeMcpEntry/index.d.ts +12 -0
  49. package/dist/cli/init/writeMcpEntry/index.js +51 -0
  50. package/dist/index.d.ts +2 -0
  51. package/dist/index.js +228 -0
  52. package/dist/tools/discover/buildAncestorChain/index.d.ts +17 -0
  53. package/dist/tools/discover/buildAncestorChain/index.js +98 -0
  54. package/dist/tools/discover/buildTree/index.d.ts +9 -0
  55. package/dist/tools/discover/buildTree/index.js +57 -0
  56. package/dist/tools/discover/index.d.ts +20 -0
  57. package/dist/tools/discover/index.js +49 -0
  58. package/dist/tools/init/applySteps/index.d.ts +30 -0
  59. package/dist/tools/init/applySteps/index.js +76 -0
  60. package/dist/tools/init/configureIde/index.d.ts +21 -0
  61. package/dist/tools/init/configureIde/index.js +135 -0
  62. package/dist/tools/init/detectFramework/index.d.ts +11 -0
  63. package/dist/tools/init/detectFramework/index.js +53 -0
  64. package/dist/tools/init/index.d.ts +46 -0
  65. package/dist/tools/init/index.js +99 -0
  66. package/dist/tools/init/initContent/index.d.ts +99 -0
  67. package/dist/tools/init/initContent/index.js +162 -0
  68. package/dist/tools/init/installAgents/index.d.ts +12 -0
  69. package/dist/tools/init/installAgents/index.js +60 -0
  70. package/dist/tools/init/installMethodologyDocs/index.d.ts +14 -0
  71. package/dist/tools/init/installMethodologyDocs/index.js +62 -0
  72. package/dist/tools/init/installSkills/index.d.ts +12 -0
  73. package/dist/tools/init/installSkills/index.js +60 -0
  74. package/dist/tools/init/provisionBrain/index.d.ts +23 -0
  75. package/dist/tools/init/provisionBrain/index.js +239 -0
  76. package/dist/tools/init/resolveBrainHints/index.d.ts +17 -0
  77. package/dist/tools/init/resolveBrainHints/index.js +44 -0
  78. package/dist/tools/init/scaffoldCommands/index.d.ts +38 -0
  79. package/dist/tools/init/scaffoldCommands/index.js +94 -0
  80. package/dist/tools/init/wireMcp/index.d.ts +16 -0
  81. package/dist/tools/init/wireMcp/index.js +72 -0
  82. package/dist/tools/init/writeMethodology/index.d.ts +20 -0
  83. package/dist/tools/init/writeMethodology/index.js +94 -0
  84. package/dist/tools/read/index.d.ts +15 -0
  85. package/dist/tools/read/index.js +79 -0
  86. package/dist/tools/scaffold/index.d.ts +22 -0
  87. package/dist/tools/scaffold/index.js +128 -0
  88. package/dist/tools/upgrade/applyFiles/index.d.ts +33 -0
  89. package/dist/tools/upgrade/applyFiles/index.js +65 -0
  90. package/dist/tools/upgrade/buildVersionsMeta/index.d.ts +20 -0
  91. package/dist/tools/upgrade/buildVersionsMeta/index.js +51 -0
  92. package/dist/tools/upgrade/checkIdeConfig/index.d.ts +24 -0
  93. package/dist/tools/upgrade/checkIdeConfig/index.js +134 -0
  94. package/dist/tools/upgrade/checkMcpConfig/index.d.ts +17 -0
  95. package/dist/tools/upgrade/checkMcpConfig/index.js +81 -0
  96. package/dist/tools/upgrade/compareFile/index.d.ts +12 -0
  97. package/dist/tools/upgrade/compareFile/index.js +24 -0
  98. package/dist/tools/upgrade/index.d.ts +24 -0
  99. package/dist/tools/upgrade/index.js +139 -0
  100. package/dist/tools/upgrade/spliceStub/index.d.ts +13 -0
  101. package/dist/tools/upgrade/spliceStub/index.js +91 -0
  102. package/dist/tools/validate/index.d.ts +18 -0
  103. package/dist/tools/validate/index.js +65 -0
  104. package/dist/types/index.d.ts +277 -0
  105. package/dist/types/index.js +10 -0
  106. package/dist/util/classify/index.d.ts +17 -0
  107. package/dist/util/classify/index.js +134 -0
  108. package/dist/util/parseBody/index.d.ts +7 -0
  109. package/dist/util/parseBody/index.js +43 -0
  110. package/dist/util/parseFrontmatter/index.d.ts +12 -0
  111. package/dist/util/parseFrontmatter/index.js +64 -0
  112. package/dist/util/scan/index.d.ts +7 -0
  113. package/dist/util/scan/index.js +82 -0
  114. 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>;