-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathextension.js
More file actions
135 lines (122 loc) · 4.87 KB
/
Copy pathextension.js
File metadata and controls
135 lines (122 loc) · 4.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
const vscode = require("vscode");
// Heavy / noisy paths an AI agent almost never needs to read. We only write the ones that exist.
const CANDIDATES = [
"node_modules", "dist", "build", ".next", "out", "coverage", ".turbo", ".cache",
".venv", "venv", "__pycache__", ".pytest_cache", ".mypy_cache",
"target", "vendor", ".gradle", "bin", "obj",
".git", ".idea", ".vscode", ".DS_Store"
];
// Glob patterns that are noise regardless of folder presence.
const GLOBS = [
"*.lock", "package-lock.json", "pnpm-lock.yaml", "yarn.lock", "bun.lockb",
"*.min.js", "*.map", "*.log",
"*.png", "*.jpg", "*.jpeg", "*.gif", "*.webp", "*.ico", "*.pdf",
"*.zip", "*.tar", "*.gz", "*.mp4", "*.mov", "*.woff", "*.woff2", "*.ttf"
];
function uriOf(rootUri, rel) {
let u = rootUri;
for (const p of rel.split("/")) u = vscode.Uri.joinPath(u, p);
return u;
}
async function exists(rootUri, rel) {
try { await vscode.workspace.fs.stat(uriOf(rootUri, rel)); return true; } catch { return false; }
}
async function listTopLevel(rootUri) {
try {
const entries = await vscode.workspace.fs.readDirectory(rootUri);
return entries
.filter(([name]) => !name.startsWith(".") && name !== "node_modules")
.map(([name, type]) => ({ name, dir: type === vscode.FileType.Directory }))
.sort((a, b) => (a.dir === b.dir ? a.name.localeCompare(b.name) : a.dir ? -1 : 1));
} catch { return []; }
}
async function detectEntryPoints(rootUri) {
const candidates = [
"src/index.ts", "src/index.js", "src/main.ts", "src/main.tsx", "src/app.tsx",
"app/page.tsx", "pages/index.tsx", "index.js", "index.ts", "main.py", "app.py",
"src/main.rs", "main.go", "cmd/main.go"
];
const found = [];
for (const c of candidates) if (await exists(rootUri, c)) found.push(c);
return found;
}
function buildIgnore(presentDirs) {
const lines = [
"# Generated by Context Saver — files your AI agent should skip to save tokens.",
"# Works with Cursor (.cursorignore). Tune to taste.",
""
];
if (presentDirs.length) {
lines.push("# Heavy folders");
for (const d of presentDirs) lines.push(`${d}/`);
lines.push("");
}
lines.push("# Noise files");
lines.push(...GLOBS);
lines.push("");
return lines.join("\n");
}
async function buildRepoMap(rootUri) {
const top = await listTopLevel(rootUri);
const entries = await detectEntryPoints(rootUri);
const lines = [
"# Repo map",
"",
"A compact orientation for AI agents — read this instead of crawling the whole tree.",
"",
"## Top-level layout"
];
for (const e of top.slice(0, 40)) lines.push(`- ${e.dir ? "📁 " : "📄 "}${e.name}${e.dir ? "/" : ""}`);
if (entries.length) {
lines.push("", "## Likely entry points");
for (const e of entries) lines.push(`- \`${e}\``);
}
lines.push(
"",
"## How to navigate",
"- Start from the entry points above; follow imports rather than reading every file.",
"- Folders listed in the ignore file are build output / deps — don't read them.",
""
);
return lines.join("\n");
}
async function writeFile(rootUri, rel, content) {
const target = uriOf(rootUri, rel);
try {
await vscode.workspace.fs.stat(target);
const choice = await vscode.window.showWarningMessage(`${rel} already exists. Overwrite it?`, "Overwrite", "Skip");
if (choice !== "Overwrite") return false;
} catch { /* not present */ }
await vscode.workspace.fs.writeFile(target, Buffer.from(content, "utf8"));
return true;
}
async function generate() {
const folders = vscode.workspace.workspaceFolders;
if (!folders || folders.length === 0) {
vscode.window.showErrorMessage("Open a folder/workspace first.");
return;
}
const rootUri = folders[0].uri;
const presentDirs = [];
for (const d of CANDIDATES) if (await exists(rootUri, d)) presentDirs.push(d);
const written = [];
if (await writeFile(rootUri, ".cursorignore", buildIgnore(presentDirs))) written.push(".cursorignore");
if (await writeFile(rootUri, ".agent/repo-map.md", await buildRepoMap(rootUri))) written.push(".agent/repo-map.md");
if (!written.length) { vscode.window.showInformationMessage("Context Saver: nothing written."); return; }
const action = await vscode.window.showInformationMessage(
`Context Saver: wrote ${written.join(", ")}. Your agent will skip ${presentDirs.length} heavy folder(s).`,
"Open repo map",
"Get the Pro config pack"
);
if (action === "Open repo map") {
const doc = await vscode.workspace.openTextDocument(uriOf(rootUri, ".agent/repo-map.md"));
vscode.window.showTextDocument(doc);
} else if (action === "Get the Pro config pack") {
vscode.env.openExternal(vscode.Uri.parse("https://alphaletgo.gumroad.com/l/agentic-coding-kit"));
}
}
function activate(context) {
context.subscriptions.push(vscode.commands.registerCommand("contextSaver.generate", generate));
}
function deactivate() {}
module.exports = { activate, deactivate };