@stainless-code/codemap 0.1.1 → 0.1.2
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/CHANGELOG.md +8 -0
- package/README.md +3 -2
- package/dist/agents-init-COkjrzc5.mjs +303 -0
- package/dist/agents-init-interactive-HLqgP8gL.mjs +122 -0
- package/dist/cmd-agents-Dph66vnf.mjs +17 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +27 -10
- package/dist/parse-worker.d.mts +1 -1
- package/package.json +2 -1
- package/templates/agents/README.md +3 -1
- package/dist/cmd-agents-BJPx1vGG.mjs +0 -38
- /package/dist/{cmd-index-oyoHr0c4.mjs → cmd-index-UeGdciH7.mjs} +0 -0
- /package/dist/{cmd-query-D3zXZu7K.mjs → cmd-query-lSSRXMX8.mjs} +0 -0
- /package/dist/{parsed-types-udxNyD9e.d.mts → parsed-types-CtqqGr-K.d.mts} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# @stainless-code/codemap
|
|
2
2
|
|
|
3
|
+
## 0.1.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#4](https://github.com/stainless-code/codemap/pull/4) [`0a9d829`](https://github.com/stainless-code/codemap/commit/0a9d82935e775edfb942029c03b8a427f18f9e71) Thanks [@SutuSebastian](https://github.com/SutuSebastian)! - **`codemap agents init`:** For Git repos, ensure **`.codemap.*`** is in **`.gitignore`** (create the file or append the line once). **`--force`** removes only template file paths (same relpaths under **`.agents/rules/`** and **`.agents/skills/`** as **`templates/agents`**) before merging; other files under **`.agents/`**, **`rules/`**, or **`skills/`** are kept. **`--interactive` / `-i`** — pick IDE integrations (Cursor, GitHub Copilot, Windsurf, Continue, Cline, Amazon Q, **`CLAUDE.md`**, **`AGENTS.md`**, **`GEMINI.md`**) and symlink vs copy for rule mirrors; requires a TTY. Unknown positional arguments (e.g. `interactive` without `--interactive`) are rejected. Depends on **`@clack/prompts`**.
|
|
8
|
+
|
|
9
|
+
**Docs:** **[`docs/agents.md`](https://github.com/stainless-code/codemap/blob/main/docs/agents.md)**; **[`docs/README.md`](https://github.com/stainless-code/codemap/blob/main/docs/README.md)** index updated. Root **[`.gitignore`](https://github.com/stainless-code/codemap/blob/main/.gitignore)** uses a single **`.codemap.*`** line.
|
|
10
|
+
|
|
3
11
|
## 0.1.1
|
|
4
12
|
|
|
5
13
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
- **Not** full-text search or grep on arbitrary strings — use those when you need raw file-body search.
|
|
6
6
|
- **Is** a fast, token-efficient way to navigate **structure**: definitions, imports, dependency direction, components, and other extracted facts.
|
|
7
7
|
|
|
8
|
-
**Documentation:** [docs/README.md](docs/README.md) is the index
|
|
8
|
+
**Documentation:** [docs/README.md](docs/README.md) is the hub (topic index + single-source rules). Topics: [architecture](docs/architecture.md), [agents](docs/agents.md) (`codemap agents init`), [benchmark](docs/benchmark.md), [packaging](docs/packaging.md), [roadmap](docs/roadmap.md), [why Codemap](docs/why-codemap.md). **Bundled rules/skills:** [`.agents/rules/`](.agents/rules/), [`.agents/skills/codemap/SKILL.md`](.agents/skills/codemap/SKILL.md). **Consumers:** [.github/CONTRIBUTING.md](.github/CONTRIBUTING.md).
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -47,9 +47,10 @@ codemap --config /path/to/codemap.config.json --full
|
|
|
47
47
|
# Re-index only given paths (relative to project root)
|
|
48
48
|
codemap --files src/a.ts src/b.tsx
|
|
49
49
|
|
|
50
|
-
# Scaffold .agents/
|
|
50
|
+
# Scaffold .agents/ from bundled templates — full matrix: docs/agents.md
|
|
51
51
|
codemap agents init
|
|
52
52
|
codemap agents init --force
|
|
53
|
+
codemap agents init --interactive # -i; IDE wiring + symlink vs copy
|
|
53
54
|
```
|
|
54
55
|
|
|
55
56
|
**Environment / flags:** `--root` overrides **`CODEMAP_ROOT`** / **`CODEMAP_TEST_BENCH`**, then **`process.cwd()`**. Indexing a project outside this clone: [docs/benchmark.md § Indexing another project](docs/benchmark.md#indexing-another-project).
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { dirname, join, relative } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { appendFileSync, copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, symlinkSync, writeFileSync } from "node:fs";
|
|
6
|
+
//#region src/agents-init.ts
|
|
7
|
+
/**
|
|
8
|
+
* Directory containing `rules/` and `skills/` (next to `dist/` in published packages).
|
|
9
|
+
*/
|
|
10
|
+
function resolveAgentsTemplateDir() {
|
|
11
|
+
return join(dirname(fileURLToPath(import.meta.url)), "..", "templates", "agents");
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Every regular file path under `dir` relative to `dir` (POSIX-style `/`).
|
|
15
|
+
* Used for template paths (`--force` removal), template writes, and copy-mode IDE sync.
|
|
16
|
+
*/
|
|
17
|
+
function listRegularFilesRecursive(dir, relPrefix = "") {
|
|
18
|
+
const out = [];
|
|
19
|
+
if (!existsSync(dir)) return out;
|
|
20
|
+
for (const ent of readdirSync(dir, { withFileTypes: true })) {
|
|
21
|
+
const name = ent.name;
|
|
22
|
+
const rel = relPrefix ? `${relPrefix}/${name}` : name;
|
|
23
|
+
const full = join(dir, name);
|
|
24
|
+
if (ent.isDirectory()) out.push(...listRegularFilesRecursive(full, rel));
|
|
25
|
+
else if (ent.isFile()) out.push(rel);
|
|
26
|
+
}
|
|
27
|
+
return out;
|
|
28
|
+
}
|
|
29
|
+
function relPathToAbsSegments(rel) {
|
|
30
|
+
return rel.split("/").filter(Boolean);
|
|
31
|
+
}
|
|
32
|
+
/** Copy only listed relative paths from `srcRoot` into `destRoot` (mkdir parents per file). */
|
|
33
|
+
function copyFilesGranular(srcRoot, destRoot, relPaths) {
|
|
34
|
+
for (const rel of relPaths) {
|
|
35
|
+
const from = join(srcRoot, ...relPathToAbsSegments(rel));
|
|
36
|
+
const to = join(destRoot, ...relPathToAbsSegments(rel));
|
|
37
|
+
mkdirSync(dirname(to), { recursive: true });
|
|
38
|
+
copyFileSync(from, to);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/** Symlink each file: `destRoot/<rel>` → relative path to `srcRoot/<rel>` (mkdir parents per file). */
|
|
42
|
+
function symlinkFilesGranular(srcRoot, destRoot, relPaths, labelForErrors) {
|
|
43
|
+
mkdirSync(destRoot, { recursive: true });
|
|
44
|
+
for (const rel of relPaths) {
|
|
45
|
+
const srcFile = join(srcRoot, ...relPathToAbsSegments(rel));
|
|
46
|
+
const destFile = join(destRoot, ...relPathToAbsSegments(rel));
|
|
47
|
+
mkdirSync(dirname(destFile), { recursive: true });
|
|
48
|
+
const target = relative(dirname(destFile), srcFile);
|
|
49
|
+
try {
|
|
50
|
+
symlinkSync(target, destFile, "file");
|
|
51
|
+
} catch (err) {
|
|
52
|
+
throw new Error(`Codemap: symlink failed for ${labelForErrors} (${destFile}): ${String(err)}. Try copy mode or check permissions on Windows.`, { cause: err });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function removeBundledPathsIfExist(destBase, relPaths) {
|
|
57
|
+
for (const rel of relPaths) {
|
|
58
|
+
const abs = join(destBase, ...relPathToAbsSegments(rel));
|
|
59
|
+
if (!existsSync(abs)) continue;
|
|
60
|
+
rmSync(abs, {
|
|
61
|
+
recursive: true,
|
|
62
|
+
force: true
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/** Default DB basename `.codemap` plus SQLite sidecars (`.db`, `-wal`, `-shm`, …). */
|
|
67
|
+
const GITIGNORE_CODEMAP_PATTERN = ".codemap.*";
|
|
68
|
+
/** Targets that mirror `.agents/rules` (and Cursor also `.agents/skills`) via per-file symlink or copy. */
|
|
69
|
+
const AGENTS_INIT_SYMLINK_TARGETS = [
|
|
70
|
+
"cursor",
|
|
71
|
+
"windsurf",
|
|
72
|
+
"continue",
|
|
73
|
+
"cline",
|
|
74
|
+
"amazon-q"
|
|
75
|
+
];
|
|
76
|
+
function targetsNeedLinkMode(targets) {
|
|
77
|
+
return targets.some((t) => AGENTS_INIT_SYMLINK_TARGETS.includes(t));
|
|
78
|
+
}
|
|
79
|
+
const POINTER_BODY = `This project uses [Codemap](https://github.com/stainless-code/codemap) — a structural SQLite index for AI agents.
|
|
80
|
+
|
|
81
|
+
- **Skill:** \`.agents/skills/codemap/SKILL.md\`
|
|
82
|
+
- **CLI:** \`codemap\` to index, \`codemap query "SELECT …"\` for SQL
|
|
83
|
+
- **Rules:** \`.agents/rules/\`
|
|
84
|
+
|
|
85
|
+
`;
|
|
86
|
+
const CLAUDE_MD_TEMPLATE = `# Codemap\n\n${POINTER_BODY}`;
|
|
87
|
+
const AGENTS_MD_TEMPLATE = `# Agent instructions (Codemap)
|
|
88
|
+
|
|
89
|
+
${POINTER_BODY}
|
|
90
|
+
Also referenced by **Zed**, **JetBrains AI**-style tools, **Aider**, and other agents that read \`AGENTS.md\` at the repo root.
|
|
91
|
+
|
|
92
|
+
`;
|
|
93
|
+
const GEMINI_MD_TEMPLATE = `# Codemap (Gemini)
|
|
94
|
+
|
|
95
|
+
${POINTER_BODY}
|
|
96
|
+
Use this file if your **Gemini** CLI or IDE loads \`GEMINI.md\` at the repo root.
|
|
97
|
+
|
|
98
|
+
`;
|
|
99
|
+
const COPILOT_TEMPLATE = `# Codemap — GitHub Copilot custom instructions
|
|
100
|
+
|
|
101
|
+
${POINTER_BODY}
|
|
102
|
+
See [GitHub Docs: custom instructions for Copilot](https://docs.github.com/copilot/customizing-copilot/adding-custom-instructions-for-github-copilot).
|
|
103
|
+
|
|
104
|
+
`;
|
|
105
|
+
/** HTML comments — invisible in most Markdown renderers; used to upsert without duplicating on re-run. */
|
|
106
|
+
const CODMAP_POINTER_BEGIN = "<!-- codemap-pointer:begin -->";
|
|
107
|
+
const CODMAP_POINTER_END = "<!-- codemap-pointer:end -->";
|
|
108
|
+
function wrapCodemapPointerBlock(inner) {
|
|
109
|
+
return `${CODMAP_POINTER_BEGIN}\n${inner.trim()}\n${CODMAP_POINTER_END}\n`;
|
|
110
|
+
}
|
|
111
|
+
function escapeRegexChars(s) {
|
|
112
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
113
|
+
}
|
|
114
|
+
function codemapPointerBlockRegex() {
|
|
115
|
+
return new RegExp(`${escapeRegexChars(CODMAP_POINTER_BEGIN)}\\s*[\\s\\S]*?${escapeRegexChars(CODMAP_POINTER_END)}`, "m");
|
|
116
|
+
}
|
|
117
|
+
/** Heuristic: file looks like a prior Codemap pointer file before we added markers (upgrade → single managed block). */
|
|
118
|
+
function looksLikeLegacyCodemapPointer(content) {
|
|
119
|
+
const t = content.trim();
|
|
120
|
+
if (t.length < 80) return false;
|
|
121
|
+
return t.includes("stainless-code/codemap") && t.includes(".agents/skills/codemap") && t.includes("codemap query");
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Create or merge a Codemap pointer file. Idempotent: managed section is between
|
|
125
|
+
* {@link CODMAP_POINTER_BEGIN} / {@link CODMAP_POINTER_END}; re-runs replace that section only.
|
|
126
|
+
* - **No file:** write managed block.
|
|
127
|
+
* - **Existing + markers:** replace inner section (updates stale template text).
|
|
128
|
+
* - **Existing, no markers, legacy Codemap content:** replace whole file with managed block.
|
|
129
|
+
* - **Existing, other content:** append managed block once.
|
|
130
|
+
* - **`force`:** replace entire file with the latest managed block (same as a fresh write).
|
|
131
|
+
*/
|
|
132
|
+
function upsertCodemapPointerFile(path, innerTemplate, label, force) {
|
|
133
|
+
const wrapped = wrapCodemapPointerBlock(innerTemplate);
|
|
134
|
+
if (!existsSync(path)) {
|
|
135
|
+
writeFileSync(path, wrapped, "utf-8");
|
|
136
|
+
console.log(` Wrote ${label} with Codemap pointers`);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
if (force) {
|
|
140
|
+
writeFileSync(path, wrapped, "utf-8");
|
|
141
|
+
console.log(` Replaced ${label} (--force)`);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const content = readFileSync(path, "utf-8");
|
|
145
|
+
const re = codemapPointerBlockRegex();
|
|
146
|
+
if (content.match(re)) {
|
|
147
|
+
const next = content.replace(re, wrapped);
|
|
148
|
+
if (next === content) {
|
|
149
|
+
console.log(` Codemap section in ${label} already up to date`);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
writeFileSync(path, next, "utf-8");
|
|
153
|
+
console.log(` Updated Codemap section in ${label}`);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (looksLikeLegacyCodemapPointer(content)) {
|
|
157
|
+
writeFileSync(path, wrapped, "utf-8");
|
|
158
|
+
console.log(` Migrated ${label} to managed Codemap section`);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
writeFileSync(path, content + (content.endsWith("\n") ? "\n" : "\n\n") + wrapped, "utf-8");
|
|
162
|
+
console.log(` Appended Codemap section to ${label}`);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Ensure `.codemap.*` is listed in `.gitignore` when the project uses Git:
|
|
166
|
+
* - If `<projectRoot>/.git` exists and there is no `.gitignore`, create one with `.codemap.*`.
|
|
167
|
+
* - If `.gitignore` exists, append `.codemap.*` once when missing.
|
|
168
|
+
* - If there is no `.git`, do nothing (not a Git working tree).
|
|
169
|
+
*/
|
|
170
|
+
function ensureGitignoreCodemapPattern(projectRoot) {
|
|
171
|
+
const gitDir = join(projectRoot, ".git");
|
|
172
|
+
const gitignorePath = join(projectRoot, ".gitignore");
|
|
173
|
+
if (!existsSync(gitDir)) return;
|
|
174
|
+
if (!existsSync(gitignorePath)) {
|
|
175
|
+
writeFileSync(gitignorePath, `${GITIGNORE_CODEMAP_PATTERN}\n`, "utf-8");
|
|
176
|
+
console.log(` Created .gitignore with ${GITIGNORE_CODEMAP_PATTERN} (Git repo, no .gitignore yet)`);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
const content = readFileSync(gitignorePath, "utf-8");
|
|
180
|
+
if (content.split(/\r?\n/).some((line) => line.trim() === GITIGNORE_CODEMAP_PATTERN)) return;
|
|
181
|
+
appendFileSync(gitignorePath, `${content.length > 0 && !content.endsWith("\n") ? "\n" : ""}${GITIGNORE_CODEMAP_PATTERN}\n`, "utf-8");
|
|
182
|
+
console.log(` Appended ${GITIGNORE_CODEMAP_PATTERN} to .gitignore`);
|
|
183
|
+
}
|
|
184
|
+
function removePathForRewrite(path, force, label) {
|
|
185
|
+
if (!existsSync(path)) return;
|
|
186
|
+
if (!force) throw new Error(`Codemap: ${label} already exists — use --force to replace, or remove it manually.`);
|
|
187
|
+
rmSync(path, {
|
|
188
|
+
recursive: true,
|
|
189
|
+
force: true
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Map `.agents/rules` into a destination directory (symlink or copy).
|
|
194
|
+
*/
|
|
195
|
+
function wireAgentsRulesTo(projectRoot, destPath, label, linkMode, force) {
|
|
196
|
+
const agentsRules = join(projectRoot, ".agents", "rules");
|
|
197
|
+
mkdirSync(dirname(destPath), { recursive: true });
|
|
198
|
+
removePathForRewrite(destPath, force, label);
|
|
199
|
+
if (linkMode === "symlink") {
|
|
200
|
+
const ruleFiles = listRegularFilesRecursive(agentsRules);
|
|
201
|
+
symlinkFilesGranular(agentsRules, destPath, ruleFiles, label);
|
|
202
|
+
console.log(` Linked each file under ${label} → .agents/rules (${ruleFiles.length} files)`);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
copyFilesGranular(agentsRules, destPath, listRegularFilesRecursive(agentsRules));
|
|
206
|
+
console.log(` Copied .agents/rules → ${label}`);
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Wire Cursor or other tools after `.agents/` exists.
|
|
210
|
+
*/
|
|
211
|
+
function applyAgentsInitTargets(projectRoot, targets, linkMode, force) {
|
|
212
|
+
const agentsRules = join(projectRoot, ".agents", "rules");
|
|
213
|
+
const agentsSkills = join(projectRoot, ".agents", "skills");
|
|
214
|
+
if (!existsSync(agentsRules) || !existsSync(agentsSkills)) throw new Error("Codemap: .agents/rules and .agents/skills must exist before wiring integrations");
|
|
215
|
+
for (const t of targets) switch (t) {
|
|
216
|
+
case "cursor":
|
|
217
|
+
applyCursorIntegration(projectRoot, linkMode, force);
|
|
218
|
+
break;
|
|
219
|
+
case "windsurf":
|
|
220
|
+
wireAgentsRulesTo(projectRoot, join(projectRoot, ".windsurf", "rules"), ".windsurf/rules", linkMode, force);
|
|
221
|
+
break;
|
|
222
|
+
case "continue":
|
|
223
|
+
wireAgentsRulesTo(projectRoot, join(projectRoot, ".continue", "rules"), ".continue/rules", linkMode, force);
|
|
224
|
+
break;
|
|
225
|
+
case "cline":
|
|
226
|
+
wireAgentsRulesTo(projectRoot, join(projectRoot, ".clinerules"), ".clinerules", linkMode, force);
|
|
227
|
+
break;
|
|
228
|
+
case "amazon-q":
|
|
229
|
+
wireAgentsRulesTo(projectRoot, join(projectRoot, ".amazonq", "rules"), ".amazonq/rules", linkMode, force);
|
|
230
|
+
break;
|
|
231
|
+
case "claude-md":
|
|
232
|
+
upsertCodemapPointerFile(join(projectRoot, "CLAUDE.md"), CLAUDE_MD_TEMPLATE, "CLAUDE.md", force);
|
|
233
|
+
break;
|
|
234
|
+
case "copilot":
|
|
235
|
+
mkdirSync(join(projectRoot, ".github"), { recursive: true });
|
|
236
|
+
upsertCodemapPointerFile(join(projectRoot, ".github", "copilot-instructions.md"), COPILOT_TEMPLATE, ".github/copilot-instructions.md", force);
|
|
237
|
+
break;
|
|
238
|
+
case "agents-md":
|
|
239
|
+
upsertCodemapPointerFile(join(projectRoot, "AGENTS.md"), AGENTS_MD_TEMPLATE, "AGENTS.md", force);
|
|
240
|
+
break;
|
|
241
|
+
case "gemini-md":
|
|
242
|
+
upsertCodemapPointerFile(join(projectRoot, "GEMINI.md"), GEMINI_MD_TEMPLATE, "GEMINI.md", force);
|
|
243
|
+
break;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
function applyCursorIntegration(projectRoot, linkMode, force) {
|
|
247
|
+
const agentsRules = join(projectRoot, ".agents", "rules");
|
|
248
|
+
const agentsSkills = join(projectRoot, ".agents", "skills");
|
|
249
|
+
const cursorRules = join(projectRoot, ".cursor", "rules");
|
|
250
|
+
const cursorSkills = join(projectRoot, ".cursor", "skills");
|
|
251
|
+
mkdirSync(join(projectRoot, ".cursor"), { recursive: true });
|
|
252
|
+
if (linkMode === "symlink") {
|
|
253
|
+
removePathForRewrite(cursorRules, force, ".cursor/rules");
|
|
254
|
+
removePathForRewrite(cursorSkills, force, ".cursor/skills");
|
|
255
|
+
const ruleFiles = listRegularFilesRecursive(agentsRules);
|
|
256
|
+
const skillFiles = listRegularFilesRecursive(agentsSkills);
|
|
257
|
+
symlinkFilesGranular(agentsRules, cursorRules, ruleFiles, ".cursor/rules");
|
|
258
|
+
symlinkFilesGranular(agentsSkills, cursorSkills, skillFiles, ".cursor/skills");
|
|
259
|
+
console.log(` Linked ${ruleFiles.length} rule file(s) and ${skillFiles.length} skill file(s) under .cursor/ → .agents/`);
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
removePathForRewrite(cursorRules, force, ".cursor/rules");
|
|
263
|
+
removePathForRewrite(cursorSkills, force, ".cursor/skills");
|
|
264
|
+
copyFilesGranular(agentsRules, cursorRules, listRegularFilesRecursive(agentsRules));
|
|
265
|
+
copyFilesGranular(agentsSkills, cursorSkills, listRegularFilesRecursive(agentsSkills));
|
|
266
|
+
console.log(" Copied rules and skills into .cursor/rules and .cursor/skills");
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Copy bundled `rules/` and `skills/` into `<projectRoot>/.agents/`, optional integrations, `.gitignore` hint.
|
|
270
|
+
* **`--force`** deletes only template-backed files, then writes those files again with per-file copies — your other files under **`.agents/`**, **`rules/`**, or **`skills/`** stay.
|
|
271
|
+
* @returns `false` when `.agents/` exists and `--force` was not used.
|
|
272
|
+
*/
|
|
273
|
+
function runAgentsInit(options) {
|
|
274
|
+
const templateRoot = resolveAgentsTemplateDir();
|
|
275
|
+
if (!existsSync(templateRoot)) throw new Error(`Codemap: agent templates not found at ${templateRoot} (expected npm package layout: templates/agents next to dist/)`);
|
|
276
|
+
const templateRules = join(templateRoot, "rules");
|
|
277
|
+
const templateSkills = join(templateRoot, "skills");
|
|
278
|
+
const bundledRuleFiles = listRegularFilesRecursive(templateRules);
|
|
279
|
+
const bundledSkillFiles = listRegularFilesRecursive(templateSkills);
|
|
280
|
+
const destRoot = join(options.projectRoot, ".agents");
|
|
281
|
+
const destRules = join(destRoot, "rules");
|
|
282
|
+
const destSkills = join(destRoot, "skills");
|
|
283
|
+
if (existsSync(destRoot)) {
|
|
284
|
+
if (!statSync(destRoot).isDirectory()) throw new Error(`Codemap: ${destRoot} exists but is not a directory — remove or rename it, then retry.`);
|
|
285
|
+
if (!options.force) {
|
|
286
|
+
console.error(` .agents/ already exists at ${destRoot}. Re-run with --force to refresh bundled template files under rules/ and skills/, or remove the directory.`);
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
removeBundledPathsIfExist(destRules, bundledRuleFiles);
|
|
290
|
+
removeBundledPathsIfExist(destSkills, bundledSkillFiles);
|
|
291
|
+
} else mkdirSync(destRoot, { recursive: true });
|
|
292
|
+
copyFilesGranular(templateRules, destRules, bundledRuleFiles);
|
|
293
|
+
copyFilesGranular(templateSkills, destSkills, bundledSkillFiles);
|
|
294
|
+
console.log(` Wrote agent templates to ${destRoot}`);
|
|
295
|
+
const targets = options.targets ?? [];
|
|
296
|
+
const linkMode = options.linkMode ?? "symlink";
|
|
297
|
+
if (targets.length > 0) applyAgentsInitTargets(options.projectRoot, targets, linkMode, !!options.force);
|
|
298
|
+
else console.log(" Tip: run `codemap agents init --interactive` to wire editors (Cursor, Copilot, …) or add CLAUDE.md / AGENTS.md");
|
|
299
|
+
ensureGitignoreCodemapPattern(options.projectRoot);
|
|
300
|
+
return true;
|
|
301
|
+
}
|
|
302
|
+
//#endregion
|
|
303
|
+
export { targetsNeedLinkMode as n, runAgentsInit as t };
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { n as targetsNeedLinkMode, t as runAgentsInit } from "./agents-init-COkjrzc5.mjs";
|
|
4
|
+
import { cancel, confirm, intro, isCancel, multiselect, note, outro, select } from "@clack/prompts";
|
|
5
|
+
//#region src/agents-init-interactive.ts
|
|
6
|
+
const INTEGRATION_OPTIONS = [
|
|
7
|
+
{
|
|
8
|
+
value: "cursor",
|
|
9
|
+
label: "Cursor",
|
|
10
|
+
hint: ".cursor/rules + skills → .agents/"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
value: "claude-md",
|
|
14
|
+
label: "Claude Code",
|
|
15
|
+
hint: "CLAUDE.md"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
value: "copilot",
|
|
19
|
+
label: "GitHub Copilot",
|
|
20
|
+
hint: ".github/copilot-instructions.md"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
value: "windsurf",
|
|
24
|
+
label: "Windsurf (Cascade)",
|
|
25
|
+
hint: ".windsurf/rules → .agents/rules"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
value: "continue",
|
|
29
|
+
label: "Continue",
|
|
30
|
+
hint: ".continue/rules → .agents/rules"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
value: "cline",
|
|
34
|
+
label: "Cline",
|
|
35
|
+
hint: ".clinerules → .agents/rules"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
value: "amazon-q",
|
|
39
|
+
label: "Amazon Q Developer",
|
|
40
|
+
hint: ".amazonq/rules → .agents/rules"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
value: "agents-md",
|
|
44
|
+
label: "AGENTS.md (Zed, JetBrains, Aider, …)",
|
|
45
|
+
hint: "Root AGENTS.md"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
value: "gemini-md",
|
|
49
|
+
label: "Gemini",
|
|
50
|
+
hint: "GEMINI.md"
|
|
51
|
+
}
|
|
52
|
+
];
|
|
53
|
+
function summarizeTargets(targets) {
|
|
54
|
+
const lines = [];
|
|
55
|
+
for (const t of targets) {
|
|
56
|
+
const opt = INTEGRATION_OPTIONS.find((o) => o.value === t);
|
|
57
|
+
lines.push(opt ? `${opt.label}: ${opt.hint}` : t);
|
|
58
|
+
}
|
|
59
|
+
return lines;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Interactive `codemap agents init`: choose integrations and symlink vs copy for rule mirrors.
|
|
63
|
+
*/
|
|
64
|
+
async function runAgentsInitInteractive(opts) {
|
|
65
|
+
intro("codemap agents init");
|
|
66
|
+
note("Canonical templates always install to .agents/ (rules + skills).\nOptional steps wire other tools to the same content.", "Codemap");
|
|
67
|
+
const targetsRaw = await multiselect({
|
|
68
|
+
message: "Integrations (space to toggle, enter to confirm)",
|
|
69
|
+
options: INTEGRATION_OPTIONS,
|
|
70
|
+
required: false,
|
|
71
|
+
initialValues: []
|
|
72
|
+
});
|
|
73
|
+
if (isCancel(targetsRaw)) {
|
|
74
|
+
cancel("Cancelled.");
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
const targets = targetsRaw;
|
|
78
|
+
let linkMode = "symlink";
|
|
79
|
+
if (targetsNeedLinkMode(targets)) {
|
|
80
|
+
const mode = await select({
|
|
81
|
+
message: "How should tools that mirror .agents/rules (and Cursor skills) link?",
|
|
82
|
+
options: [{
|
|
83
|
+
value: "symlink",
|
|
84
|
+
label: "Symlink",
|
|
85
|
+
hint: "One source of truth; best on macOS / Linux"
|
|
86
|
+
}, {
|
|
87
|
+
value: "copy",
|
|
88
|
+
label: "Copy",
|
|
89
|
+
hint: "Duplicate files; safest on Windows / sandboxes"
|
|
90
|
+
}],
|
|
91
|
+
initialValue: "symlink"
|
|
92
|
+
});
|
|
93
|
+
if (isCancel(mode)) {
|
|
94
|
+
cancel("Cancelled.");
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
linkMode = mode;
|
|
98
|
+
}
|
|
99
|
+
note([
|
|
100
|
+
`Project: ${opts.projectRoot}`,
|
|
101
|
+
"Will write: .agents/rules, .agents/skills",
|
|
102
|
+
...summarizeTargets(targets).map((l) => `• ${l}`)
|
|
103
|
+
].join("\n"), "Summary");
|
|
104
|
+
const ok = await confirm({
|
|
105
|
+
message: "Proceed?",
|
|
106
|
+
initialValue: true
|
|
107
|
+
});
|
|
108
|
+
if (isCancel(ok) || !ok) {
|
|
109
|
+
cancel("Cancelled.");
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
const success = runAgentsInit({
|
|
113
|
+
projectRoot: opts.projectRoot,
|
|
114
|
+
force: opts.force,
|
|
115
|
+
targets,
|
|
116
|
+
linkMode
|
|
117
|
+
});
|
|
118
|
+
if (success) outro("Done. Edit .agents/ for your team; restart IDEs if rules did not reload.");
|
|
119
|
+
return success;
|
|
120
|
+
}
|
|
121
|
+
//#endregion
|
|
122
|
+
export { runAgentsInitInteractive };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { t as runAgentsInit } from "./agents-init-COkjrzc5.mjs";
|
|
4
|
+
//#region src/cli/cmd-agents.ts
|
|
5
|
+
async function runAgentsInitCmd(opts) {
|
|
6
|
+
if (opts.interactive) {
|
|
7
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
8
|
+
console.error("codemap: --interactive requires an interactive terminal (TTY).");
|
|
9
|
+
process.exit(1);
|
|
10
|
+
}
|
|
11
|
+
const { runAgentsInitInteractive } = await import("./agents-init-interactive-HLqgP8gL.mjs");
|
|
12
|
+
return runAgentsInitInteractive(opts);
|
|
13
|
+
}
|
|
14
|
+
return runAgentsInit(opts);
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
export { runAgentsInitCmd };
|
package/dist/index.d.mts
CHANGED
package/dist/index.mjs
CHANGED
|
@@ -8,7 +8,7 @@ import { fileURLToPath } from "node:url";
|
|
|
8
8
|
//#endregion
|
|
9
9
|
//#region src/version.ts
|
|
10
10
|
/** Package version from `package.json` (inlined at build time). */
|
|
11
|
-
const CODEMAP_VERSION = "0.1.
|
|
11
|
+
const CODEMAP_VERSION = "0.1.2";
|
|
12
12
|
//#endregion
|
|
13
13
|
//#region src/cli/bootstrap.ts
|
|
14
14
|
/** Printed for `codemap --help` / `-h` (must run before config or DB access). */
|
|
@@ -23,7 +23,7 @@ Query:
|
|
|
23
23
|
codemap query "<SQL>"
|
|
24
24
|
|
|
25
25
|
Agents:
|
|
26
|
-
codemap agents init [--force]
|
|
26
|
+
codemap agents init [--force] [--interactive|-i]
|
|
27
27
|
|
|
28
28
|
Other:
|
|
29
29
|
codemap version
|
|
@@ -48,7 +48,7 @@ function validateIndexModeArgs(rest) {
|
|
|
48
48
|
if (rest[0] === "query") return;
|
|
49
49
|
if (rest[0] === "agents") {
|
|
50
50
|
if (rest[1] === "init") return;
|
|
51
|
-
console.error(`codemap: unknown agents command "${rest[1] ?? "(missing)"}". Expected: codemap agents init [--force]`);
|
|
51
|
+
console.error(`codemap: unknown agents command "${rest[1] ?? "(missing)"}". Expected: codemap agents init [--force] [--interactive|-i]`);
|
|
52
52
|
process.exit(1);
|
|
53
53
|
}
|
|
54
54
|
let i = 0;
|
|
@@ -116,17 +116,34 @@ async function main() {
|
|
|
116
116
|
}
|
|
117
117
|
if (rest[0] === "agents" && rest[1] === "init") {
|
|
118
118
|
if (rest.includes("--help") || rest.includes("-h")) {
|
|
119
|
-
console.log(`Usage: codemap agents init [--force]
|
|
119
|
+
console.log(`Usage: codemap agents init [--force] [--interactive|-i]
|
|
120
120
|
|
|
121
121
|
Copies bundled agent templates into .agents/ under the project root.
|
|
122
|
-
|
|
122
|
+
--force Refresh only files that ship in templates/agents (merge into rules/ & skills/)
|
|
123
|
+
--interactive Pick IDEs (Cursor, Copilot, Windsurf, …) and symlink vs copy
|
|
123
124
|
`);
|
|
124
125
|
return;
|
|
125
126
|
}
|
|
126
|
-
const
|
|
127
|
-
|
|
127
|
+
const initRest = rest.slice(2);
|
|
128
|
+
const knownInit = new Set([
|
|
129
|
+
"--force",
|
|
130
|
+
"--interactive",
|
|
131
|
+
"-i",
|
|
132
|
+
"--help",
|
|
133
|
+
"-h"
|
|
134
|
+
]);
|
|
135
|
+
for (const a of initRest) {
|
|
136
|
+
if (knownInit.has(a)) continue;
|
|
137
|
+
if (a.startsWith("-")) console.error(`codemap: unknown option "${a}"`);
|
|
138
|
+
else console.error(`codemap: unexpected argument "${a}"`);
|
|
139
|
+
console.error("Run codemap agents init --help for usage.");
|
|
140
|
+
process.exit(1);
|
|
141
|
+
}
|
|
142
|
+
const { runAgentsInitCmd } = await import("./cmd-agents-Dph66vnf.mjs");
|
|
143
|
+
if (!await runAgentsInitCmd({
|
|
128
144
|
projectRoot: root,
|
|
129
|
-
force: rest.includes("--force")
|
|
145
|
+
force: rest.includes("--force"),
|
|
146
|
+
interactive: rest.includes("--interactive") || rest.includes("-i")
|
|
130
147
|
})) process.exit(1);
|
|
131
148
|
return;
|
|
132
149
|
}
|
|
@@ -140,7 +157,7 @@ Example: codemap query "SELECT name, file_path FROM symbols LIMIT 10"
|
|
|
140
157
|
`);
|
|
141
158
|
return;
|
|
142
159
|
}
|
|
143
|
-
const { runQueryCmd } = await import("./cmd-query-
|
|
160
|
+
const { runQueryCmd } = await import("./cmd-query-lSSRXMX8.mjs");
|
|
144
161
|
await runQueryCmd({
|
|
145
162
|
root,
|
|
146
163
|
configFile,
|
|
@@ -148,7 +165,7 @@ Example: codemap query "SELECT name, file_path FROM symbols LIMIT 10"
|
|
|
148
165
|
});
|
|
149
166
|
return;
|
|
150
167
|
}
|
|
151
|
-
const { runIndexCmd } = await import("./cmd-index-
|
|
168
|
+
const { runIndexCmd } = await import("./cmd-index-UeGdciH7.mjs");
|
|
152
169
|
await runIndexCmd({
|
|
153
170
|
root,
|
|
154
171
|
configFile,
|
package/dist/parse-worker.d.mts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stainless-code/codemap",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Query your codebase — structural SQLite index for AI agents",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agents",
|
|
@@ -66,6 +66,7 @@
|
|
|
66
66
|
"typecheck": "tsgo --noEmit"
|
|
67
67
|
},
|
|
68
68
|
"dependencies": {
|
|
69
|
+
"@clack/prompts": "^1.2.0",
|
|
69
70
|
"better-sqlite3": "^12.8.0",
|
|
70
71
|
"fast-glob": "^3.3.3",
|
|
71
72
|
"lightningcss": "^1.32.0",
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Bundled agent templates
|
|
2
2
|
|
|
3
|
-
These files are **copies** of the upstream [`.agents/`](../../.agents/) rules and skills shipped with
|
|
3
|
+
These files are **copies** of the upstream [`.agents/`](../../.agents/) rules and skills shipped with **`@stainless-code/codemap`** for **`codemap agents init`**.
|
|
4
|
+
|
|
5
|
+
**Documentation:** [docs/agents.md](../../docs/agents.md) — interactive setup, **`.gitignore`**, and optional IDE wiring (Cursor, Copilot, …).
|
|
4
6
|
|
|
5
7
|
After running the command, **edit** `.agents/` in your project (paths, SQL, team conventions). Treat updates here as a reference when refreshing your copy.
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { dirname, join } from "node:path";
|
|
4
|
-
import { fileURLToPath } from "node:url";
|
|
5
|
-
import { cpSync, existsSync, mkdirSync } from "node:fs";
|
|
6
|
-
//#region src/agents-init.ts
|
|
7
|
-
/**
|
|
8
|
-
* Directory containing `rules/` and `skills/` (next to `dist/` in published packages).
|
|
9
|
-
*/
|
|
10
|
-
function resolveAgentsTemplateDir() {
|
|
11
|
-
return join(dirname(fileURLToPath(import.meta.url)), "..", "templates", "agents");
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Copy bundled rules and skills into `<projectRoot>/.agents/`.
|
|
15
|
-
* @returns `false` when `.agents/` exists and `--force` was not used.
|
|
16
|
-
*/
|
|
17
|
-
function runAgentsInit(options) {
|
|
18
|
-
const templateRoot = resolveAgentsTemplateDir();
|
|
19
|
-
if (!existsSync(templateRoot)) throw new Error(`Codemap: agent templates not found at ${templateRoot} (expected npm package layout: templates/agents next to dist/)`);
|
|
20
|
-
const destRoot = join(options.projectRoot, ".agents");
|
|
21
|
-
if (existsSync(destRoot) && !options.force) {
|
|
22
|
-
console.error(` .agents/ already exists at ${destRoot}. Re-run with --force to overwrite, or remove the directory.`);
|
|
23
|
-
return false;
|
|
24
|
-
}
|
|
25
|
-
mkdirSync(destRoot, { recursive: true });
|
|
26
|
-
cpSync(join(templateRoot, "rules"), join(destRoot, "rules"), { recursive: true });
|
|
27
|
-
cpSync(join(templateRoot, "skills"), join(destRoot, "skills"), { recursive: true });
|
|
28
|
-
console.log(` Wrote agent templates to ${destRoot}`);
|
|
29
|
-
console.log(` Symlink into .cursor/ if needed — see https://github.com/stainless-code/codemap/blob/main/.github/CONTRIBUTING.md`);
|
|
30
|
-
return true;
|
|
31
|
-
}
|
|
32
|
-
//#endregion
|
|
33
|
-
//#region src/cli/cmd-agents.ts
|
|
34
|
-
function runAgentsInitCmd(opts) {
|
|
35
|
-
return runAgentsInit(opts);
|
|
36
|
-
}
|
|
37
|
-
//#endregion
|
|
38
|
-
export { runAgentsInitCmd };
|
|
File without changes
|
|
File without changes
|
|
File without changes
|