nogrep 1.2.0 → 1.2.1
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/package.json +1 -1
- package/plugins/nogrep/scripts/chunk-7D4SUZUM.js +38 -0
- package/plugins/nogrep/scripts/chunk-7D4SUZUM.js.map +1 -0
- package/plugins/nogrep/scripts/query.js +1 -0
- package/plugins/nogrep/scripts/query.js.map +1 -1
- package/plugins/nogrep/scripts/settings.js +2 -0
- package/plugins/nogrep/scripts/settings.js.map +1 -1
- package/plugins/nogrep/scripts/signals.js +2 -0
- package/plugins/nogrep/scripts/signals.js.map +1 -1
- package/plugins/nogrep/scripts/trim.js +2 -0
- package/plugins/nogrep/scripts/trim.js.map +1 -1
- package/plugins/nogrep/scripts/types.js +1 -0
- package/plugins/nogrep/scripts/validate.js +9552 -7
- package/plugins/nogrep/scripts/validate.js.map +1 -1
- package/plugins/nogrep/scripts/write.js +2638 -6
- package/plugins/nogrep/scripts/write.js.map +1 -1
package/package.json
CHANGED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
8
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
9
|
+
}) : x)(function(x) {
|
|
10
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
11
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
12
|
+
});
|
|
13
|
+
var __commonJS = (cb, mod) => function __require2() {
|
|
14
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
15
|
+
};
|
|
16
|
+
var __copyProps = (to, from, except, desc) => {
|
|
17
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
18
|
+
for (let key of __getOwnPropNames(from))
|
|
19
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
20
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
21
|
+
}
|
|
22
|
+
return to;
|
|
23
|
+
};
|
|
24
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
25
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
26
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
27
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
28
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
29
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
30
|
+
mod
|
|
31
|
+
));
|
|
32
|
+
|
|
33
|
+
export {
|
|
34
|
+
__require,
|
|
35
|
+
__commonJS,
|
|
36
|
+
__toESM
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=chunk-7D4SUZUM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../scripts/query.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises'\nimport { join, resolve as resolvePath } from 'node:path'\nimport { parseArgs } from 'node:util'\nimport type { IndexJson, RankedResult, Taxonomy } from './types.js'\nimport { NogrepError } from './types.js'\n\n// --- Term extraction ---\n\nexport function extractTerms(\n question: string,\n taxonomy: Taxonomy,\n): { tags: string[]; keywords: string[] } {\n const words = question\n .toLowerCase()\n .replace(/[^\\w\\s-]/g, ' ')\n .split(/\\s+/)\n .filter(w => w.length > 1)\n\n const tags: string[] = []\n const keywords: string[] = []\n\n // Collect all taxonomy values for matching\n const tagLookup = new Map<string, string>()\n\n for (const val of taxonomy.static.layer) {\n tagLookup.set(val.toLowerCase(), `layer:${val}`)\n }\n for (const val of taxonomy.static.concern) {\n tagLookup.set(val.toLowerCase(), `concern:${val}`)\n }\n for (const val of taxonomy.static.type) {\n tagLookup.set(val.toLowerCase(), `type:${val}`)\n }\n for (const val of taxonomy.dynamic.domain) {\n tagLookup.set(val.toLowerCase(), `domain:${val}`)\n }\n for (const val of taxonomy.dynamic.tech) {\n tagLookup.set(val.toLowerCase(), `tech:${val}`)\n }\n for (const [cat, values] of Object.entries(taxonomy.custom)) {\n for (const val of values) {\n tagLookup.set(val.toLowerCase(), `${cat}:${val}`)\n }\n }\n\n // Stop words to skip as keywords\n const stopWords = new Set([\n 'the', 'is', 'at', 'in', 'of', 'on', 'to', 'a', 'an', 'and', 'or',\n 'for', 'it', 'do', 'does', 'how', 'what', 'where', 'which', 'when',\n 'who', 'why', 'this', 'that', 'with', 'from', 'by', 'be', 'as',\n 'are', 'was', 'were', 'been', 'has', 'have', 'had', 'not', 'but',\n 'if', 'my', 'our', 'its', 'can', 'will', 'should', 'would', 'could',\n 'about', 'after', 'work', 'works', 'use', 'uses', 'used',\n ])\n\n for (const word of words) {\n const tag = tagLookup.get(word)\n if (tag && !tags.includes(tag)) {\n tags.push(tag)\n }\n\n // Also check hyphenated compound matches (e.g. \"error-handling\")\n if (!tag && !stopWords.has(word)) {\n keywords.push(word)\n }\n }\n\n // Check for multi-word tag matches (e.g. \"error handling\" → \"error-handling\")\n const questionLower = question.toLowerCase()\n for (const [val, tag] of tagLookup.entries()) {\n if (val.includes('-')) {\n const spacedVersion = val.replace(/-/g, ' ')\n if (questionLower.includes(spacedVersion) && !tags.includes(tag)) {\n tags.push(tag)\n }\n if (questionLower.includes(val) && !tags.includes(tag)) {\n tags.push(tag)\n }\n }\n }\n\n return { tags, keywords }\n}\n\n// --- Resolution ---\n\nexport function resolveQuery(\n terms: { tags: string[]; keywords: string[] },\n index: IndexJson,\n limit = 5,\n): RankedResult[] {\n const scoreMap = new Map<string, { score: number; matchedOn: string[] }>()\n\n function addMatch(contextFile: string, score: number, matchLabel: string): void {\n const existing = scoreMap.get(contextFile)\n if (existing) {\n existing.score += score\n existing.matchedOn.push(matchLabel)\n } else {\n scoreMap.set(contextFile, { score, matchedOn: [matchLabel] })\n }\n }\n\n // Tag matching: +2 per match\n for (const tag of terms.tags) {\n const files = index.tags[tag]\n if (files) {\n for (const file of files) {\n addMatch(file, 2, `tag:${tag}`)\n }\n }\n }\n\n // Keyword matching: +1 per match\n for (const kw of terms.keywords) {\n const kwLower = kw.toLowerCase()\n\n // Direct keyword lookup\n const files = index.keywords[kwLower]\n if (files) {\n for (const file of files) {\n addMatch(file, 1, `keyword:${kwLower}`)\n }\n }\n\n // Also search all index keywords for partial matches\n for (const [indexKw, kwFiles] of Object.entries(index.keywords)) {\n if (indexKw === kwLower) continue // Already handled\n if (indexKw.includes(kwLower) || kwLower.includes(indexKw)) {\n for (const file of kwFiles) {\n addMatch(file, 1, `keyword:${indexKw}`)\n }\n }\n }\n }\n\n // Sort by score descending, then alphabetically for ties\n const results: RankedResult[] = [...scoreMap.entries()]\n .sort((a, b) => b[1].score - a[1].score || a[0].localeCompare(b[0]))\n .slice(0, limit)\n .map(([contextFile, { score, matchedOn }]) => ({\n contextFile,\n score,\n matchedOn: [...new Set(matchedOn)],\n summary: `Matched: ${[...new Set(matchedOn)].join(', ')}`,\n }))\n\n return results\n}\n\n// --- Index + taxonomy loading ---\n\nasync function loadIndex(projectRoot: string): Promise<IndexJson> {\n const indexPath = join(projectRoot, '.nogrep', '_index.json')\n try {\n const content = await readFile(indexPath, 'utf-8')\n return JSON.parse(content) as IndexJson\n } catch {\n throw new NogrepError(\n 'No .nogrep/_index.json found. Run /nogrep:init first.',\n 'NO_INDEX',\n )\n }\n}\n\nasync function loadTaxonomy(projectRoot: string): Promise<Taxonomy> {\n const taxonomyPath = join(projectRoot, '.nogrep', '_taxonomy.json')\n try {\n const content = await readFile(taxonomyPath, 'utf-8')\n return JSON.parse(content) as Taxonomy\n } catch {\n // Return default taxonomy if file doesn't exist\n return {\n static: {\n layer: ['presentation', 'business', 'data', 'infrastructure', 'cross-cutting'],\n concern: ['security', 'performance', 'caching', 'validation', 'error-handling', 'idempotency', 'observability'],\n type: ['module', 'flow', 'entity', 'integration', 'config', 'ui', 'test'],\n },\n dynamic: { domain: [], tech: [] },\n custom: {},\n }\n }\n}\n\nfunction buildTaxonomyFromIndex(index: IndexJson, baseTaxonomy: Taxonomy): Taxonomy {\n // Extract dynamic domain and tech values from the index tags\n const domains = new Set<string>(baseTaxonomy.dynamic.domain)\n const techs = new Set<string>(baseTaxonomy.dynamic.tech)\n\n for (const tagKey of Object.keys(index.tags)) {\n const [category, value] = tagKey.split(':')\n if (!category || !value) continue\n if (category === 'domain') domains.add(value)\n if (category === 'tech') techs.add(value)\n }\n\n return {\n ...baseTaxonomy,\n dynamic: {\n domain: [...domains],\n tech: [...techs],\n },\n }\n}\n\n// --- Formatting ---\n\nfunction formatPaths(results: RankedResult[]): string {\n return results.map(r => r.contextFile).join('\\n')\n}\n\nfunction formatJson(results: RankedResult[]): string {\n return JSON.stringify(results, null, 2)\n}\n\nfunction formatSummary(results: RankedResult[]): string {\n if (results.length === 0) return 'No matching context files found.'\n return results\n .map(r => `- ${r.contextFile} (score: ${r.score}) — ${r.summary}`)\n .join('\\n')\n}\n\n// --- CLI ---\n\nasync function main(): Promise<void> {\n const { values } = parseArgs({\n options: {\n tags: { type: 'string' },\n keywords: { type: 'string' },\n question: { type: 'string' },\n format: { type: 'string', default: 'json' },\n limit: { type: 'string', default: '5' },\n root: { type: 'string', default: process.cwd() },\n },\n strict: true,\n })\n\n const root = resolvePath(values.root ?? process.cwd())\n const limit = parseInt(values.limit ?? '5', 10)\n const format = values.format ?? 'json'\n\n const index = await loadIndex(root)\n const baseTaxonomy = await loadTaxonomy(root)\n const taxonomy = buildTaxonomyFromIndex(index, baseTaxonomy)\n\n let terms: { tags: string[]; keywords: string[] }\n\n if (values.question) {\n terms = extractTerms(values.question, taxonomy)\n } else if (values.tags || values.keywords) {\n const tags = values.tags\n ? values.tags.split(',').map(t => t.trim()).filter(Boolean)\n : []\n const keywords = values.keywords\n ? values.keywords.split(',').map(k => k.trim()).filter(Boolean)\n : []\n terms = { tags, keywords }\n } else {\n process.stderr.write(\n JSON.stringify({ error: 'Usage: node query.js --tags <tags> | --keywords <words> | --question <text> [--format paths|json|summary] [--limit N]' }) + '\\n',\n )\n process.exitCode = 1\n return\n }\n\n const results = resolveQuery(terms, index, limit)\n\n switch (format) {\n case 'paths':\n process.stdout.write(formatPaths(results) + '\\n')\n break\n case 'summary':\n process.stdout.write(formatSummary(results) + '\\n')\n break\n case 'json':\n default:\n process.stdout.write(formatJson(results) + '\\n')\n break\n }\n}\n\nif (import.meta.url === `file://${process.argv[1]}`) {\n main().catch((err: unknown) => {\n if (err instanceof NogrepError) {\n process.stderr.write(JSON.stringify({ error: err.message, code: err.code }) + '\\n')\n } else {\n const message = err instanceof Error ? err.message : String(err)\n process.stderr.write(JSON.stringify({ error: message }) + '\\n')\n }\n process.exitCode = 1\n })\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../scripts/query.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises'\nimport { join, resolve as resolvePath } from 'node:path'\nimport { parseArgs } from 'node:util'\nimport type { IndexJson, RankedResult, Taxonomy } from './types.js'\nimport { NogrepError } from './types.js'\n\n// --- Term extraction ---\n\nexport function extractTerms(\n question: string,\n taxonomy: Taxonomy,\n): { tags: string[]; keywords: string[] } {\n const words = question\n .toLowerCase()\n .replace(/[^\\w\\s-]/g, ' ')\n .split(/\\s+/)\n .filter(w => w.length > 1)\n\n const tags: string[] = []\n const keywords: string[] = []\n\n // Collect all taxonomy values for matching\n const tagLookup = new Map<string, string>()\n\n for (const val of taxonomy.static.layer) {\n tagLookup.set(val.toLowerCase(), `layer:${val}`)\n }\n for (const val of taxonomy.static.concern) {\n tagLookup.set(val.toLowerCase(), `concern:${val}`)\n }\n for (const val of taxonomy.static.type) {\n tagLookup.set(val.toLowerCase(), `type:${val}`)\n }\n for (const val of taxonomy.dynamic.domain) {\n tagLookup.set(val.toLowerCase(), `domain:${val}`)\n }\n for (const val of taxonomy.dynamic.tech) {\n tagLookup.set(val.toLowerCase(), `tech:${val}`)\n }\n for (const [cat, values] of Object.entries(taxonomy.custom)) {\n for (const val of values) {\n tagLookup.set(val.toLowerCase(), `${cat}:${val}`)\n }\n }\n\n // Stop words to skip as keywords\n const stopWords = new Set([\n 'the', 'is', 'at', 'in', 'of', 'on', 'to', 'a', 'an', 'and', 'or',\n 'for', 'it', 'do', 'does', 'how', 'what', 'where', 'which', 'when',\n 'who', 'why', 'this', 'that', 'with', 'from', 'by', 'be', 'as',\n 'are', 'was', 'were', 'been', 'has', 'have', 'had', 'not', 'but',\n 'if', 'my', 'our', 'its', 'can', 'will', 'should', 'would', 'could',\n 'about', 'after', 'work', 'works', 'use', 'uses', 'used',\n ])\n\n for (const word of words) {\n const tag = tagLookup.get(word)\n if (tag && !tags.includes(tag)) {\n tags.push(tag)\n }\n\n // Also check hyphenated compound matches (e.g. \"error-handling\")\n if (!tag && !stopWords.has(word)) {\n keywords.push(word)\n }\n }\n\n // Check for multi-word tag matches (e.g. \"error handling\" → \"error-handling\")\n const questionLower = question.toLowerCase()\n for (const [val, tag] of tagLookup.entries()) {\n if (val.includes('-')) {\n const spacedVersion = val.replace(/-/g, ' ')\n if (questionLower.includes(spacedVersion) && !tags.includes(tag)) {\n tags.push(tag)\n }\n if (questionLower.includes(val) && !tags.includes(tag)) {\n tags.push(tag)\n }\n }\n }\n\n return { tags, keywords }\n}\n\n// --- Resolution ---\n\nexport function resolveQuery(\n terms: { tags: string[]; keywords: string[] },\n index: IndexJson,\n limit = 5,\n): RankedResult[] {\n const scoreMap = new Map<string, { score: number; matchedOn: string[] }>()\n\n function addMatch(contextFile: string, score: number, matchLabel: string): void {\n const existing = scoreMap.get(contextFile)\n if (existing) {\n existing.score += score\n existing.matchedOn.push(matchLabel)\n } else {\n scoreMap.set(contextFile, { score, matchedOn: [matchLabel] })\n }\n }\n\n // Tag matching: +2 per match\n for (const tag of terms.tags) {\n const files = index.tags[tag]\n if (files) {\n for (const file of files) {\n addMatch(file, 2, `tag:${tag}`)\n }\n }\n }\n\n // Keyword matching: +1 per match\n for (const kw of terms.keywords) {\n const kwLower = kw.toLowerCase()\n\n // Direct keyword lookup\n const files = index.keywords[kwLower]\n if (files) {\n for (const file of files) {\n addMatch(file, 1, `keyword:${kwLower}`)\n }\n }\n\n // Also search all index keywords for partial matches\n for (const [indexKw, kwFiles] of Object.entries(index.keywords)) {\n if (indexKw === kwLower) continue // Already handled\n if (indexKw.includes(kwLower) || kwLower.includes(indexKw)) {\n for (const file of kwFiles) {\n addMatch(file, 1, `keyword:${indexKw}`)\n }\n }\n }\n }\n\n // Sort by score descending, then alphabetically for ties\n const results: RankedResult[] = [...scoreMap.entries()]\n .sort((a, b) => b[1].score - a[1].score || a[0].localeCompare(b[0]))\n .slice(0, limit)\n .map(([contextFile, { score, matchedOn }]) => ({\n contextFile,\n score,\n matchedOn: [...new Set(matchedOn)],\n summary: `Matched: ${[...new Set(matchedOn)].join(', ')}`,\n }))\n\n return results\n}\n\n// --- Index + taxonomy loading ---\n\nasync function loadIndex(projectRoot: string): Promise<IndexJson> {\n const indexPath = join(projectRoot, '.nogrep', '_index.json')\n try {\n const content = await readFile(indexPath, 'utf-8')\n return JSON.parse(content) as IndexJson\n } catch {\n throw new NogrepError(\n 'No .nogrep/_index.json found. Run /nogrep:init first.',\n 'NO_INDEX',\n )\n }\n}\n\nasync function loadTaxonomy(projectRoot: string): Promise<Taxonomy> {\n const taxonomyPath = join(projectRoot, '.nogrep', '_taxonomy.json')\n try {\n const content = await readFile(taxonomyPath, 'utf-8')\n return JSON.parse(content) as Taxonomy\n } catch {\n // Return default taxonomy if file doesn't exist\n return {\n static: {\n layer: ['presentation', 'business', 'data', 'infrastructure', 'cross-cutting'],\n concern: ['security', 'performance', 'caching', 'validation', 'error-handling', 'idempotency', 'observability'],\n type: ['module', 'flow', 'entity', 'integration', 'config', 'ui', 'test'],\n },\n dynamic: { domain: [], tech: [] },\n custom: {},\n }\n }\n}\n\nfunction buildTaxonomyFromIndex(index: IndexJson, baseTaxonomy: Taxonomy): Taxonomy {\n // Extract dynamic domain and tech values from the index tags\n const domains = new Set<string>(baseTaxonomy.dynamic.domain)\n const techs = new Set<string>(baseTaxonomy.dynamic.tech)\n\n for (const tagKey of Object.keys(index.tags)) {\n const [category, value] = tagKey.split(':')\n if (!category || !value) continue\n if (category === 'domain') domains.add(value)\n if (category === 'tech') techs.add(value)\n }\n\n return {\n ...baseTaxonomy,\n dynamic: {\n domain: [...domains],\n tech: [...techs],\n },\n }\n}\n\n// --- Formatting ---\n\nfunction formatPaths(results: RankedResult[]): string {\n return results.map(r => r.contextFile).join('\\n')\n}\n\nfunction formatJson(results: RankedResult[]): string {\n return JSON.stringify(results, null, 2)\n}\n\nfunction formatSummary(results: RankedResult[]): string {\n if (results.length === 0) return 'No matching context files found.'\n return results\n .map(r => `- ${r.contextFile} (score: ${r.score}) — ${r.summary}`)\n .join('\\n')\n}\n\n// --- CLI ---\n\nasync function main(): Promise<void> {\n const { values } = parseArgs({\n options: {\n tags: { type: 'string' },\n keywords: { type: 'string' },\n question: { type: 'string' },\n format: { type: 'string', default: 'json' },\n limit: { type: 'string', default: '5' },\n root: { type: 'string', default: process.cwd() },\n },\n strict: true,\n })\n\n const root = resolvePath(values.root ?? process.cwd())\n const limit = parseInt(values.limit ?? '5', 10)\n const format = values.format ?? 'json'\n\n const index = await loadIndex(root)\n const baseTaxonomy = await loadTaxonomy(root)\n const taxonomy = buildTaxonomyFromIndex(index, baseTaxonomy)\n\n let terms: { tags: string[]; keywords: string[] }\n\n if (values.question) {\n terms = extractTerms(values.question, taxonomy)\n } else if (values.tags || values.keywords) {\n const tags = values.tags\n ? values.tags.split(',').map(t => t.trim()).filter(Boolean)\n : []\n const keywords = values.keywords\n ? values.keywords.split(',').map(k => k.trim()).filter(Boolean)\n : []\n terms = { tags, keywords }\n } else {\n process.stderr.write(\n JSON.stringify({ error: 'Usage: node query.js --tags <tags> | --keywords <words> | --question <text> [--format paths|json|summary] [--limit N]' }) + '\\n',\n )\n process.exitCode = 1\n return\n }\n\n const results = resolveQuery(terms, index, limit)\n\n switch (format) {\n case 'paths':\n process.stdout.write(formatPaths(results) + '\\n')\n break\n case 'summary':\n process.stdout.write(formatSummary(results) + '\\n')\n break\n case 'json':\n default:\n process.stdout.write(formatJson(results) + '\\n')\n break\n }\n}\n\nif (import.meta.url === `file://${process.argv[1]}`) {\n main().catch((err: unknown) => {\n if (err instanceof NogrepError) {\n process.stderr.write(JSON.stringify({ error: err.message, code: err.code }) + '\\n')\n } else {\n const message = err instanceof Error ? err.message : String(err)\n process.stderr.write(JSON.stringify({ error: message }) + '\\n')\n }\n process.exitCode = 1\n })\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../scripts/settings.ts"],"sourcesContent":["import { readFile, writeFile, mkdir } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport { parseArgs } from 'node:util'\nimport type { NogrepSettings } from './types.js'\n\nconst SETTINGS_FILE = '.claude/settings.json'\nconst SETTINGS_LOCAL_FILE = '.claude/settings.local.json'\n\ninterface SettingsJson {\n nogrep?: Partial<NogrepSettings>\n [key: string]: unknown\n}\n\nasync function readJsonFile(path: string): Promise<SettingsJson> {\n try {\n const content = await readFile(path, 'utf-8')\n return JSON.parse(content) as SettingsJson\n } catch {\n return {}\n }\n}\n\nasync function ensureDir(dir: string): Promise<void> {\n await mkdir(dir, { recursive: true })\n}\n\nexport async function readSettings(projectRoot: string): Promise<NogrepSettings> {\n const sharedPath = join(projectRoot, SETTINGS_FILE)\n const localPath = join(projectRoot, SETTINGS_LOCAL_FILE)\n\n const shared = await readJsonFile(sharedPath)\n const local = await readJsonFile(localPath)\n\n const enabled =\n local.nogrep?.enabled ?? shared.nogrep?.enabled ?? false\n\n return { enabled }\n}\n\nexport async function writeSettings(\n projectRoot: string,\n settings: Partial<NogrepSettings>,\n local?: boolean,\n): Promise<void> {\n const filePath = join(\n projectRoot,\n local ? SETTINGS_LOCAL_FILE : SETTINGS_FILE,\n )\n\n await ensureDir(join(projectRoot, '.claude'))\n\n const existing = await readJsonFile(filePath)\n existing.nogrep = { ...existing.nogrep, ...settings }\n\n await writeFile(filePath, JSON.stringify(existing, null, 2) + '\\n', 'utf-8')\n}\n\n// CLI interface\nasync function main(): Promise<void> {\n const { values } = parseArgs({\n options: {\n set: { type: 'string' },\n get: { type: 'boolean', default: false },\n local: { type: 'boolean', default: false },\n root: { type: 'string', default: process.cwd() },\n },\n strict: true,\n })\n\n const root = values.root ?? process.cwd()\n\n if (values.get) {\n const settings = await readSettings(root)\n process.stdout.write(JSON.stringify(settings, null, 2) + '\\n')\n return\n }\n\n if (values.set) {\n const [key, value] = values.set.split('=')\n if (key === 'enabled') {\n const enabled = value === 'true'\n await writeSettings(root, { enabled }, values.local)\n } else {\n process.stderr.write(JSON.stringify({ error: `Unknown setting: ${key}` }) + '\\n')\n process.exitCode = 1\n }\n return\n }\n\n process.stderr.write(JSON.stringify({ error: 'Usage: node settings.js --set enabled=true [--local] | --get' }) + '\\n')\n process.exitCode = 1\n}\n\nif (import.meta.url === `file://${process.argv[1]}`) {\n main().catch((err: unknown) => {\n const message = err instanceof Error ? err.message : String(err)\n process.stderr.write(JSON.stringify({ error: message }) + '\\n')\n process.exitCode = 1\n })\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../../scripts/settings.ts"],"sourcesContent":["import { readFile, writeFile, mkdir } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport { parseArgs } from 'node:util'\nimport type { NogrepSettings } from './types.js'\n\nconst SETTINGS_FILE = '.claude/settings.json'\nconst SETTINGS_LOCAL_FILE = '.claude/settings.local.json'\n\ninterface SettingsJson {\n nogrep?: Partial<NogrepSettings>\n [key: string]: unknown\n}\n\nasync function readJsonFile(path: string): Promise<SettingsJson> {\n try {\n const content = await readFile(path, 'utf-8')\n return JSON.parse(content) as SettingsJson\n } catch {\n return {}\n }\n}\n\nasync function ensureDir(dir: string): Promise<void> {\n await mkdir(dir, { recursive: true })\n}\n\nexport async function readSettings(projectRoot: string): Promise<NogrepSettings> {\n const sharedPath = join(projectRoot, SETTINGS_FILE)\n const localPath = join(projectRoot, SETTINGS_LOCAL_FILE)\n\n const shared = await readJsonFile(sharedPath)\n const local = await readJsonFile(localPath)\n\n const enabled =\n local.nogrep?.enabled ?? shared.nogrep?.enabled ?? false\n\n return { enabled }\n}\n\nexport async function writeSettings(\n projectRoot: string,\n settings: Partial<NogrepSettings>,\n local?: boolean,\n): Promise<void> {\n const filePath = join(\n projectRoot,\n local ? SETTINGS_LOCAL_FILE : SETTINGS_FILE,\n )\n\n await ensureDir(join(projectRoot, '.claude'))\n\n const existing = await readJsonFile(filePath)\n existing.nogrep = { ...existing.nogrep, ...settings }\n\n await writeFile(filePath, JSON.stringify(existing, null, 2) + '\\n', 'utf-8')\n}\n\n// CLI interface\nasync function main(): Promise<void> {\n const { values } = parseArgs({\n options: {\n set: { type: 'string' },\n get: { type: 'boolean', default: false },\n local: { type: 'boolean', default: false },\n root: { type: 'string', default: process.cwd() },\n },\n strict: true,\n })\n\n const root = values.root ?? process.cwd()\n\n if (values.get) {\n const settings = await readSettings(root)\n process.stdout.write(JSON.stringify(settings, null, 2) + '\\n')\n return\n }\n\n if (values.set) {\n const [key, value] = values.set.split('=')\n if (key === 'enabled') {\n const enabled = value === 'true'\n await writeSettings(root, { enabled }, values.local)\n } else {\n process.stderr.write(JSON.stringify({ error: `Unknown setting: ${key}` }) + '\\n')\n process.exitCode = 1\n }\n return\n }\n\n process.stderr.write(JSON.stringify({ error: 'Usage: node settings.js --set enabled=true [--local] | --get' }) + '\\n')\n process.exitCode = 1\n}\n\nif (import.meta.url === `file://${process.argv[1]}`) {\n main().catch((err: unknown) => {\n const message = err instanceof Error ? err.message : String(err)\n process.stderr.write(JSON.stringify({ error: message }) + '\\n')\n process.exitCode = 1\n })\n}\n"],"mappings":";;;AAAA,SAAS,UAAU,WAAW,aAAa;AAC3C,SAAS,YAAY;AACrB,SAAS,iBAAiB;AAG1B,IAAM,gBAAgB;AACtB,IAAM,sBAAsB;AAO5B,eAAe,aAAa,MAAqC;AAC/D,MAAI;AACF,UAAM,UAAU,MAAM,SAAS,MAAM,OAAO;AAC5C,WAAO,KAAK,MAAM,OAAO;AAAA,EAC3B,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,eAAe,UAAU,KAA4B;AACnD,QAAM,MAAM,KAAK,EAAE,WAAW,KAAK,CAAC;AACtC;AAEA,eAAsB,aAAa,aAA8C;AAC/E,QAAM,aAAa,KAAK,aAAa,aAAa;AAClD,QAAM,YAAY,KAAK,aAAa,mBAAmB;AAEvD,QAAM,SAAS,MAAM,aAAa,UAAU;AAC5C,QAAM,QAAQ,MAAM,aAAa,SAAS;AAE1C,QAAM,UACJ,MAAM,QAAQ,WAAW,OAAO,QAAQ,WAAW;AAErD,SAAO,EAAE,QAAQ;AACnB;AAEA,eAAsB,cACpB,aACA,UACA,OACe;AACf,QAAM,WAAW;AAAA,IACf;AAAA,IACA,QAAQ,sBAAsB;AAAA,EAChC;AAEA,QAAM,UAAU,KAAK,aAAa,SAAS,CAAC;AAE5C,QAAM,WAAW,MAAM,aAAa,QAAQ;AAC5C,WAAS,SAAS,EAAE,GAAG,SAAS,QAAQ,GAAG,SAAS;AAEpD,QAAM,UAAU,UAAU,KAAK,UAAU,UAAU,MAAM,CAAC,IAAI,MAAM,OAAO;AAC7E;AAGA,eAAe,OAAsB;AACnC,QAAM,EAAE,OAAO,IAAI,UAAU;AAAA,IAC3B,SAAS;AAAA,MACP,KAAK,EAAE,MAAM,SAAS;AAAA,MACtB,KAAK,EAAE,MAAM,WAAW,SAAS,MAAM;AAAA,MACvC,OAAO,EAAE,MAAM,WAAW,SAAS,MAAM;AAAA,MACzC,MAAM,EAAE,MAAM,UAAU,SAAS,QAAQ,IAAI,EAAE;AAAA,IACjD;AAAA,IACA,QAAQ;AAAA,EACV,CAAC;AAED,QAAM,OAAO,OAAO,QAAQ,QAAQ,IAAI;AAExC,MAAI,OAAO,KAAK;AACd,UAAM,WAAW,MAAM,aAAa,IAAI;AACxC,YAAQ,OAAO,MAAM,KAAK,UAAU,UAAU,MAAM,CAAC,IAAI,IAAI;AAC7D;AAAA,EACF;AAEA,MAAI,OAAO,KAAK;AACd,UAAM,CAAC,KAAK,KAAK,IAAI,OAAO,IAAI,MAAM,GAAG;AACzC,QAAI,QAAQ,WAAW;AACrB,YAAM,UAAU,UAAU;AAC1B,YAAM,cAAc,MAAM,EAAE,QAAQ,GAAG,OAAO,KAAK;AAAA,IACrD,OAAO;AACL,cAAQ,OAAO,MAAM,KAAK,UAAU,EAAE,OAAO,oBAAoB,GAAG,GAAG,CAAC,IAAI,IAAI;AAChF,cAAQ,WAAW;AAAA,IACrB;AACA;AAAA,EACF;AAEA,UAAQ,OAAO,MAAM,KAAK,UAAU,EAAE,OAAO,+DAA+D,CAAC,IAAI,IAAI;AACrH,UAAQ,WAAW;AACrB;AAEA,IAAI,YAAY,QAAQ,UAAU,QAAQ,KAAK,CAAC,CAAC,IAAI;AACnD,OAAK,EAAE,MAAM,CAAC,QAAiB;AAC7B,UAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,YAAQ,OAAO,MAAM,KAAK,UAAU,EAAE,OAAO,QAAQ,CAAC,IAAI,IAAI;AAC9D,YAAQ,WAAW;AAAA,EACrB,CAAC;AACH;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../scripts/signals.ts"],"sourcesContent":["import { readdir, stat, readFile } from 'fs/promises'\nimport { join, extname, relative, resolve } from 'path'\nimport { execFile } from 'child_process'\nimport { promisify } from 'util'\nimport type { SignalResult, DirectoryNode, ManifestFile, ChurnEntry, FileSize } from './types.js'\n\nconst execFileAsync = promisify(execFile)\n\nconst SKIP_DIRS = new Set([\n 'node_modules', 'dist', 'build', '.git', 'coverage',\n '.next', '.nuxt', '__pycache__', '.venv', 'venv',\n '.idea', '.vscode', '.nogrep',\n])\n\nconst MANIFEST_NAMES: Record<string, string> = {\n 'package.json': 'npm',\n 'requirements.txt': 'pip',\n 'pom.xml': 'maven',\n 'go.mod': 'go',\n 'Podfile': 'cocoapods',\n 'Cargo.toml': 'cargo',\n 'pubspec.yaml': 'flutter',\n 'composer.json': 'composer',\n}\n\nconst ENTRY_NAMES = new Set(['main', 'index', 'app', 'server'])\n\nconst TEST_PATTERNS = [\n /\\.test\\.\\w+$/,\n /\\.spec\\.\\w+$/,\n /_test\\.\\w+$/,\n /^test_.*\\.py$/,\n]\n\ninterface CollectOptions {\n exclude?: string[]\n maxDepth?: number\n}\n\nexport async function collectSignals(\n root: string,\n options: CollectOptions = {},\n): Promise<SignalResult> {\n const absRoot = resolve(root)\n const maxDepth = options.maxDepth ?? 4\n const extraSkip = new Set(options.exclude ?? [])\n\n const allFiles: { path: string; bytes: number }[] = []\n const extensionMap: Record<string, number> = {}\n const manifests: ManifestFile[] = []\n const entryPoints: string[] = []\n const envFiles: string[] = []\n const testFiles: string[] = []\n\n const directoryTree = await walkDirectory(absRoot, absRoot, 0, maxDepth, extraSkip, {\n allFiles,\n extensionMap,\n manifests,\n entryPoints,\n envFiles,\n testFiles,\n })\n\n const gitChurn = await collectGitChurn(absRoot)\n\n const largeFiles = allFiles\n .sort((a, b) => b.bytes - a.bytes)\n .slice(0, 20)\n .map(f => ({ path: f.path, bytes: f.bytes }))\n\n return {\n directoryTree,\n extensionMap,\n manifests,\n entryPoints,\n gitChurn,\n largeFiles,\n envFiles,\n testFiles,\n }\n}\n\ninterface Collectors {\n allFiles: { path: string; bytes: number }[]\n extensionMap: Record<string, number>\n manifests: ManifestFile[]\n entryPoints: string[]\n envFiles: string[]\n testFiles: string[]\n}\n\nasync function walkDirectory(\n dir: string,\n root: string,\n depth: number,\n maxDepth: number,\n extraSkip: Set<string>,\n collectors: Collectors,\n): Promise<DirectoryNode[]> {\n if (depth > maxDepth) return []\n\n let entries\n try {\n entries = await readdir(dir, { withFileTypes: true })\n } catch {\n return []\n }\n\n const nodes: DirectoryNode[] = []\n\n for (const entry of entries) {\n const fullPath = join(dir, entry.name)\n const relPath = relative(root, fullPath)\n\n if (entry.isDirectory()) {\n if (SKIP_DIRS.has(entry.name) || extraSkip.has(entry.name)) continue\n\n const children = await walkDirectory(fullPath, root, depth + 1, maxDepth, extraSkip, collectors)\n nodes.push({ name: entry.name, path: relPath, type: 'directory', children })\n } else if (entry.isFile()) {\n nodes.push({ name: entry.name, path: relPath, type: 'file' })\n\n let fileBytes = 0\n try {\n const s = await stat(fullPath)\n fileBytes = s.size\n } catch {\n // skip\n }\n\n collectors.allFiles.push({ path: relPath, bytes: fileBytes })\n\n const ext = extname(entry.name)\n if (ext) {\n collectors.extensionMap[ext] = (collectors.extensionMap[ext] ?? 0) + 1\n }\n\n // Manifest check\n if (entry.name in MANIFEST_NAMES) {\n collectors.manifests.push({\n path: relPath,\n type: MANIFEST_NAMES[entry.name]!,\n depth,\n })\n }\n\n // Entry point check — root or src/ level\n if (depth <= 1 || (depth === 2 && dir.endsWith('/src'))) {\n const nameWithoutExt = entry.name.replace(/\\.\\w+$/, '')\n if (ENTRY_NAMES.has(nameWithoutExt)) {\n collectors.entryPoints.push(relPath)\n }\n }\n\n // Env files\n if (entry.name.startsWith('.env')) {\n collectors.envFiles.push(relPath)\n }\n\n // Config directories are handled at directory level\n // But we also detect config files at root\n if (depth === 0 && entry.name.match(/^config\\./)) {\n collectors.envFiles.push(relPath)\n }\n\n // Test files\n const fileName = entry.name\n if (TEST_PATTERNS.some(p => p.test(fileName))) {\n collectors.testFiles.push(relPath)\n }\n }\n }\n\n // Check if this directory is a config directory\n const dirName = dir.split('/').pop()\n if (dirName === 'config' && depth <= 2) {\n collectors.envFiles.push(relative(root, dir))\n }\n\n return nodes\n}\n\nasync function collectGitChurn(root: string): Promise<ChurnEntry[]> {\n try {\n const { stdout } = await execFileAsync(\n 'git',\n ['log', '--stat', '--oneline', '-50', '--pretty=format:'],\n { cwd: root, maxBuffer: 1024 * 1024 },\n )\n\n const changeCounts: Record<string, number> = {}\n\n for (const line of stdout.split('\\n')) {\n // Match lines like: src/billing/service.ts | 42 +++---\n const match = line.match(/^\\s+(.+?)\\s+\\|\\s+(\\d+)/)\n if (match) {\n const filePath = match[1]!.trim()\n const changes = parseInt(match[2]!, 10)\n changeCounts[filePath] = (changeCounts[filePath] ?? 0) + changes\n }\n }\n\n return Object.entries(changeCounts)\n .sort(([, a], [, b]) => b - a)\n .slice(0, 20)\n .map(([path, changes]) => ({ path, changes }))\n } catch {\n // No git or git log fails — return empty\n return []\n }\n}\n\n// --- CLI interface ---\n\nasync function main(): Promise<void> {\n const args = process.argv.slice(2)\n let root = '.'\n const exclude: string[] = []\n\n for (let i = 0; i < args.length; i++) {\n if (args[i] === '--root' && args[i + 1]) {\n root = args[i + 1]!\n i++\n } else if (args[i] === '--exclude' && args[i + 1]) {\n exclude.push(...args[i + 1]!.split(','))\n i++\n }\n }\n\n const result = await collectSignals(root, { exclude })\n process.stdout.write(JSON.stringify(result, null, 2))\n}\n\nif (import.meta.url === `file://${process.argv[1]}`) {\n main().catch(err => {\n process.stderr.write(JSON.stringify({ error: String(err) }))\n process.exit(1)\n })\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../scripts/signals.ts"],"sourcesContent":["import { readdir, stat, readFile } from 'fs/promises'\nimport { join, extname, relative, resolve } from 'path'\nimport { execFile } from 'child_process'\nimport { promisify } from 'util'\nimport type { SignalResult, DirectoryNode, ManifestFile, ChurnEntry, FileSize } from './types.js'\n\nconst execFileAsync = promisify(execFile)\n\nconst SKIP_DIRS = new Set([\n 'node_modules', 'dist', 'build', '.git', 'coverage',\n '.next', '.nuxt', '__pycache__', '.venv', 'venv',\n '.idea', '.vscode', '.nogrep',\n])\n\nconst MANIFEST_NAMES: Record<string, string> = {\n 'package.json': 'npm',\n 'requirements.txt': 'pip',\n 'pom.xml': 'maven',\n 'go.mod': 'go',\n 'Podfile': 'cocoapods',\n 'Cargo.toml': 'cargo',\n 'pubspec.yaml': 'flutter',\n 'composer.json': 'composer',\n}\n\nconst ENTRY_NAMES = new Set(['main', 'index', 'app', 'server'])\n\nconst TEST_PATTERNS = [\n /\\.test\\.\\w+$/,\n /\\.spec\\.\\w+$/,\n /_test\\.\\w+$/,\n /^test_.*\\.py$/,\n]\n\ninterface CollectOptions {\n exclude?: string[]\n maxDepth?: number\n}\n\nexport async function collectSignals(\n root: string,\n options: CollectOptions = {},\n): Promise<SignalResult> {\n const absRoot = resolve(root)\n const maxDepth = options.maxDepth ?? 4\n const extraSkip = new Set(options.exclude ?? [])\n\n const allFiles: { path: string; bytes: number }[] = []\n const extensionMap: Record<string, number> = {}\n const manifests: ManifestFile[] = []\n const entryPoints: string[] = []\n const envFiles: string[] = []\n const testFiles: string[] = []\n\n const directoryTree = await walkDirectory(absRoot, absRoot, 0, maxDepth, extraSkip, {\n allFiles,\n extensionMap,\n manifests,\n entryPoints,\n envFiles,\n testFiles,\n })\n\n const gitChurn = await collectGitChurn(absRoot)\n\n const largeFiles = allFiles\n .sort((a, b) => b.bytes - a.bytes)\n .slice(0, 20)\n .map(f => ({ path: f.path, bytes: f.bytes }))\n\n return {\n directoryTree,\n extensionMap,\n manifests,\n entryPoints,\n gitChurn,\n largeFiles,\n envFiles,\n testFiles,\n }\n}\n\ninterface Collectors {\n allFiles: { path: string; bytes: number }[]\n extensionMap: Record<string, number>\n manifests: ManifestFile[]\n entryPoints: string[]\n envFiles: string[]\n testFiles: string[]\n}\n\nasync function walkDirectory(\n dir: string,\n root: string,\n depth: number,\n maxDepth: number,\n extraSkip: Set<string>,\n collectors: Collectors,\n): Promise<DirectoryNode[]> {\n if (depth > maxDepth) return []\n\n let entries\n try {\n entries = await readdir(dir, { withFileTypes: true })\n } catch {\n return []\n }\n\n const nodes: DirectoryNode[] = []\n\n for (const entry of entries) {\n const fullPath = join(dir, entry.name)\n const relPath = relative(root, fullPath)\n\n if (entry.isDirectory()) {\n if (SKIP_DIRS.has(entry.name) || extraSkip.has(entry.name)) continue\n\n const children = await walkDirectory(fullPath, root, depth + 1, maxDepth, extraSkip, collectors)\n nodes.push({ name: entry.name, path: relPath, type: 'directory', children })\n } else if (entry.isFile()) {\n nodes.push({ name: entry.name, path: relPath, type: 'file' })\n\n let fileBytes = 0\n try {\n const s = await stat(fullPath)\n fileBytes = s.size\n } catch {\n // skip\n }\n\n collectors.allFiles.push({ path: relPath, bytes: fileBytes })\n\n const ext = extname(entry.name)\n if (ext) {\n collectors.extensionMap[ext] = (collectors.extensionMap[ext] ?? 0) + 1\n }\n\n // Manifest check\n if (entry.name in MANIFEST_NAMES) {\n collectors.manifests.push({\n path: relPath,\n type: MANIFEST_NAMES[entry.name]!,\n depth,\n })\n }\n\n // Entry point check — root or src/ level\n if (depth <= 1 || (depth === 2 && dir.endsWith('/src'))) {\n const nameWithoutExt = entry.name.replace(/\\.\\w+$/, '')\n if (ENTRY_NAMES.has(nameWithoutExt)) {\n collectors.entryPoints.push(relPath)\n }\n }\n\n // Env files\n if (entry.name.startsWith('.env')) {\n collectors.envFiles.push(relPath)\n }\n\n // Config directories are handled at directory level\n // But we also detect config files at root\n if (depth === 0 && entry.name.match(/^config\\./)) {\n collectors.envFiles.push(relPath)\n }\n\n // Test files\n const fileName = entry.name\n if (TEST_PATTERNS.some(p => p.test(fileName))) {\n collectors.testFiles.push(relPath)\n }\n }\n }\n\n // Check if this directory is a config directory\n const dirName = dir.split('/').pop()\n if (dirName === 'config' && depth <= 2) {\n collectors.envFiles.push(relative(root, dir))\n }\n\n return nodes\n}\n\nasync function collectGitChurn(root: string): Promise<ChurnEntry[]> {\n try {\n const { stdout } = await execFileAsync(\n 'git',\n ['log', '--stat', '--oneline', '-50', '--pretty=format:'],\n { cwd: root, maxBuffer: 1024 * 1024 },\n )\n\n const changeCounts: Record<string, number> = {}\n\n for (const line of stdout.split('\\n')) {\n // Match lines like: src/billing/service.ts | 42 +++---\n const match = line.match(/^\\s+(.+?)\\s+\\|\\s+(\\d+)/)\n if (match) {\n const filePath = match[1]!.trim()\n const changes = parseInt(match[2]!, 10)\n changeCounts[filePath] = (changeCounts[filePath] ?? 0) + changes\n }\n }\n\n return Object.entries(changeCounts)\n .sort(([, a], [, b]) => b - a)\n .slice(0, 20)\n .map(([path, changes]) => ({ path, changes }))\n } catch {\n // No git or git log fails — return empty\n return []\n }\n}\n\n// --- CLI interface ---\n\nasync function main(): Promise<void> {\n const args = process.argv.slice(2)\n let root = '.'\n const exclude: string[] = []\n\n for (let i = 0; i < args.length; i++) {\n if (args[i] === '--root' && args[i + 1]) {\n root = args[i + 1]!\n i++\n } else if (args[i] === '--exclude' && args[i + 1]) {\n exclude.push(...args[i + 1]!.split(','))\n i++\n }\n }\n\n const result = await collectSignals(root, { exclude })\n process.stdout.write(JSON.stringify(result, null, 2))\n}\n\nif (import.meta.url === `file://${process.argv[1]}`) {\n main().catch(err => {\n process.stderr.write(JSON.stringify({ error: String(err) }))\n process.exit(1)\n })\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../scripts/trim.ts"],"sourcesContent":["import { readFile } from 'fs/promises'\nimport { resolve, extname, basename } from 'path'\n\nconst MAX_CLUSTER_LINES = 300\n\ninterface TrimOptions {\n maxLines?: number\n}\n\n// Language-agnostic regex patterns for stripping function/method bodies\n// Strategy: find opening braces after signatures, track depth, remove body content\n\nfunction trimTypeScript(content: string): string {\n const lines = content.split('\\n')\n const result: string[] = []\n let braceDepth = 0\n let inBody = false\n let bodyStartDepth = 0\n\n for (const line of lines) {\n const trimmed = line.trim()\n\n // Always keep: empty lines at top level, imports, type/interface, decorators, exports of types\n if (braceDepth === 0 || !inBody) {\n if (\n trimmed === '' ||\n trimmed.startsWith('import ') ||\n trimmed.startsWith('export type ') ||\n trimmed.startsWith('export interface ') ||\n trimmed.startsWith('export enum ') ||\n trimmed.startsWith('export const ') ||\n trimmed.startsWith('type ') ||\n trimmed.startsWith('interface ') ||\n trimmed.startsWith('enum ') ||\n trimmed.startsWith('@') ||\n trimmed.startsWith('//') ||\n trimmed.startsWith('/*') ||\n trimmed.startsWith('*') ||\n trimmed.startsWith('declare ')\n ) {\n result.push(line)\n // Count braces even in kept lines\n braceDepth += countChar(trimmed, '{') - countChar(trimmed, '}')\n continue\n }\n }\n\n const openBraces = countChar(trimmed, '{')\n const closeBraces = countChar(trimmed, '}')\n\n if (!inBody) {\n // Detect function/method signature — line with opening brace\n if (isSignatureLine(trimmed) && openBraces > closeBraces) {\n result.push(line)\n braceDepth += openBraces - closeBraces\n inBody = true\n bodyStartDepth = braceDepth\n continue\n }\n\n // Class/interface declaration — keep but don't treat as body\n if (isClassOrInterfaceLine(trimmed)) {\n result.push(line)\n braceDepth += openBraces - closeBraces\n continue\n }\n\n // Keep the line (top-level statement, property declaration, etc.)\n result.push(line)\n braceDepth += openBraces - closeBraces\n } else {\n // Inside a function body — skip lines\n braceDepth += openBraces - closeBraces\n\n // Check if we've closed back to where the body started\n if (braceDepth < bodyStartDepth) {\n // Add closing brace\n result.push(line)\n inBody = false\n }\n }\n }\n\n return result.join('\\n')\n}\n\nfunction trimPython(content: string): string {\n const lines = content.split('\\n')\n const result: string[] = []\n let skipIndent = -1\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!\n const trimmed = line.trim()\n const indent = line.length - line.trimStart().length\n\n // If we're skipping a body and this line is still indented deeper, skip it\n if (skipIndent >= 0) {\n if (trimmed === '' || indent > skipIndent) {\n continue\n }\n // We've exited the body\n skipIndent = -1\n }\n\n // Always keep: comments, imports, class defs, decorators, type hints, module-level assignments\n if (\n trimmed === '' ||\n trimmed.startsWith('#') ||\n trimmed.startsWith('import ') ||\n trimmed.startsWith('from ') ||\n trimmed.startsWith('@') ||\n trimmed.startsWith('class ') ||\n /^[A-Z_][A-Z_0-9]*\\s*=/.test(trimmed)\n ) {\n result.push(line)\n continue\n }\n\n // Function/method definition — keep signature, skip body\n if (trimmed.startsWith('def ') || trimmed.startsWith('async def ')) {\n result.push(line)\n // If the next non-empty line has docstring, keep it\n const docIdx = findDocstring(lines, i + 1, indent)\n if (docIdx > i) {\n for (let j = i + 1; j <= docIdx; j++) {\n result.push(lines[j]!)\n }\n }\n skipIndent = indent\n continue\n }\n\n // Keep everything else at module/class level\n result.push(line)\n }\n\n return result.join('\\n')\n}\n\nfunction trimJava(content: string): string {\n // Java/Kotlin — very similar to TypeScript brace-matching\n const lines = content.split('\\n')\n const result: string[] = []\n let braceDepth = 0\n let inBody = false\n let bodyStartDepth = 0\n\n for (const line of lines) {\n const trimmed = line.trim()\n\n if (braceDepth === 0 || !inBody) {\n if (\n trimmed === '' ||\n trimmed.startsWith('import ') ||\n trimmed.startsWith('package ') ||\n trimmed.startsWith('@') ||\n trimmed.startsWith('//') ||\n trimmed.startsWith('/*') ||\n trimmed.startsWith('*') ||\n trimmed.startsWith('public interface ') ||\n trimmed.startsWith('interface ') ||\n trimmed.startsWith('public enum ') ||\n trimmed.startsWith('enum ')\n ) {\n result.push(line)\n braceDepth += countChar(trimmed, '{') - countChar(trimmed, '}')\n continue\n }\n }\n\n const openBraces = countChar(trimmed, '{')\n const closeBraces = countChar(trimmed, '}')\n\n if (!inBody) {\n if (isJavaMethodSignature(trimmed) && openBraces > closeBraces) {\n result.push(line)\n braceDepth += openBraces - closeBraces\n inBody = true\n bodyStartDepth = braceDepth\n continue\n }\n\n if (isJavaClassLine(trimmed)) {\n result.push(line)\n braceDepth += openBraces - closeBraces\n continue\n }\n\n result.push(line)\n braceDepth += openBraces - closeBraces\n } else {\n braceDepth += openBraces - closeBraces\n if (braceDepth < bodyStartDepth) {\n result.push(line)\n inBody = false\n }\n }\n }\n\n return result.join('\\n')\n}\n\nfunction trimGeneric(content: string): string {\n // For unknown languages, just return as-is (truncation handles size)\n return content\n}\n\n// --- Helpers ---\n\nfunction countChar(s: string, ch: string): number {\n let count = 0\n let inString = false\n let stringChar = ''\n for (let i = 0; i < s.length; i++) {\n const c = s[i]!\n if (inString) {\n if (c === stringChar && s[i - 1] !== '\\\\') inString = false\n } else if (c === '\"' || c === \"'\" || c === '`') {\n inString = true\n stringChar = c\n } else if (c === ch) {\n count++\n }\n }\n return count\n}\n\nfunction isSignatureLine(trimmed: string): boolean {\n return /^(export\\s+)?(async\\s+)?function\\s/.test(trimmed) ||\n /^(public|private|protected|static|async|get|set|\\*)\\s/.test(trimmed) ||\n /^(readonly\\s+)?[a-zA-Z_$][a-zA-Z0-9_$]*\\s*\\(/.test(trimmed) ||\n /^(export\\s+)?(const|let|var)\\s+\\w+\\s*=\\s*(async\\s+)?\\(/.test(trimmed) ||\n /^(export\\s+)?(const|let|var)\\s+\\w+\\s*=\\s*(async\\s+)?function/.test(trimmed) ||\n // Arrow function assigned at class level\n /^[a-zA-Z_$][a-zA-Z0-9_$]*\\s*=\\s*(async\\s+)?\\(/.test(trimmed)\n}\n\nfunction isClassOrInterfaceLine(trimmed: string): boolean {\n return /^(export\\s+)?(abstract\\s+)?(class|interface|enum)\\s/.test(trimmed) ||\n /^(export\\s+)?namespace\\s/.test(trimmed)\n}\n\nfunction isJavaMethodSignature(trimmed: string): boolean {\n return /^(public|private|protected|static|final|abstract|synchronized|native)\\s/.test(trimmed) &&\n /\\(/.test(trimmed)\n}\n\nfunction isJavaClassLine(trimmed: string): boolean {\n return /^(public|private|protected)?\\s*(abstract\\s+)?(class|interface|enum)\\s/.test(trimmed)\n}\n\nfunction findDocstring(lines: string[], startIdx: number, defIndent: number): number {\n // Find Python docstring (triple-quoted) after a def\n for (let i = startIdx; i < lines.length; i++) {\n const trimmed = lines[i]!.trim()\n if (trimmed === '') continue\n if (trimmed.startsWith('\"\"\"') || trimmed.startsWith(\"'''\")) {\n const quote = trimmed.slice(0, 3)\n // Single-line docstring\n if (trimmed.length > 3 && trimmed.endsWith(quote)) return i\n // Multi-line docstring — find closing\n for (let j = i + 1; j < lines.length; j++) {\n if (lines[j]!.trim().endsWith(quote)) return j\n }\n return i\n }\n // First non-empty line after def is not a docstring\n return startIdx - 1\n }\n return startIdx - 1\n}\n\nfunction getTrimmer(filePath: string): (content: string) => string {\n const ext = extname(filePath).toLowerCase()\n switch (ext) {\n case '.ts':\n case '.tsx':\n case '.js':\n case '.jsx':\n case '.mjs':\n case '.cjs':\n return trimTypeScript\n case '.py':\n return trimPython\n case '.java':\n case '.kt':\n case '.kts':\n case '.scala':\n case '.groovy':\n return trimJava\n case '.go':\n case '.rs':\n case '.c':\n case '.cpp':\n case '.h':\n case '.hpp':\n case '.cs':\n case '.swift':\n case '.dart':\n return trimJava // brace-based languages use same strategy\n default:\n return trimGeneric\n }\n}\n\nexport async function trimCluster(paths: string[], projectRoot: string): Promise<string> {\n const results: Array<{ path: string; content: string; lines: number }> = []\n\n for (const filePath of paths) {\n const absPath = resolve(projectRoot, filePath)\n try {\n const raw = await readFile(absPath, 'utf-8')\n const trimmer = getTrimmer(filePath)\n const trimmed = trimmer(raw)\n results.push({\n path: filePath,\n content: trimmed,\n lines: trimmed.split('\\n').length,\n })\n } catch {\n // Skip files that can't be read\n if (process.env['NOGREP_DEBUG'] === '1') {\n process.stderr.write(`[nogrep] Could not read: ${absPath}\\n`)\n }\n }\n }\n\n // Sort by line count descending — truncate least important (largest) files first\n results.sort((a, b) => a.lines - b.lines)\n\n const output: string[] = []\n let totalLines = 0\n const maxLines = MAX_CLUSTER_LINES\n\n for (const file of results) {\n const header = `// === ${file.path} ===`\n const fileLines = file.content.split('\\n')\n const available = maxLines - totalLines - 2 // header + separator\n\n if (available <= 0) break\n\n output.push(header)\n if (fileLines.length <= available) {\n output.push(file.content)\n } else {\n output.push(fileLines.slice(0, available).join('\\n'))\n output.push(`// ... truncated (${fileLines.length - available} more lines)`)\n }\n output.push('')\n\n totalLines += Math.min(fileLines.length, available) + 2\n }\n\n return output.join('\\n')\n}\n\n// --- CLI ---\n\nasync function main(): Promise<void> {\n const args = process.argv.slice(2)\n\n if (args.length === 0) {\n process.stderr.write('Usage: node trim.js <path1> <path2> ...\\n')\n process.exit(1)\n }\n\n const projectRoot = process.cwd()\n const result = await trimCluster(args, projectRoot)\n process.stdout.write(result)\n}\n\nconst isDirectRun = process.argv[1]?.endsWith('trim.js') || process.argv[1]?.endsWith('trim.ts')\nif (isDirectRun) {\n main().catch((err: unknown) => {\n process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}\\n`)\n process.exit(1)\n })\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../scripts/trim.ts"],"sourcesContent":["import { readFile } from 'fs/promises'\nimport { resolve, extname, basename } from 'path'\n\nconst MAX_CLUSTER_LINES = 300\n\ninterface TrimOptions {\n maxLines?: number\n}\n\n// Language-agnostic regex patterns for stripping function/method bodies\n// Strategy: find opening braces after signatures, track depth, remove body content\n\nfunction trimTypeScript(content: string): string {\n const lines = content.split('\\n')\n const result: string[] = []\n let braceDepth = 0\n let inBody = false\n let bodyStartDepth = 0\n\n for (const line of lines) {\n const trimmed = line.trim()\n\n // Always keep: empty lines at top level, imports, type/interface, decorators, exports of types\n if (braceDepth === 0 || !inBody) {\n if (\n trimmed === '' ||\n trimmed.startsWith('import ') ||\n trimmed.startsWith('export type ') ||\n trimmed.startsWith('export interface ') ||\n trimmed.startsWith('export enum ') ||\n trimmed.startsWith('export const ') ||\n trimmed.startsWith('type ') ||\n trimmed.startsWith('interface ') ||\n trimmed.startsWith('enum ') ||\n trimmed.startsWith('@') ||\n trimmed.startsWith('//') ||\n trimmed.startsWith('/*') ||\n trimmed.startsWith('*') ||\n trimmed.startsWith('declare ')\n ) {\n result.push(line)\n // Count braces even in kept lines\n braceDepth += countChar(trimmed, '{') - countChar(trimmed, '}')\n continue\n }\n }\n\n const openBraces = countChar(trimmed, '{')\n const closeBraces = countChar(trimmed, '}')\n\n if (!inBody) {\n // Detect function/method signature — line with opening brace\n if (isSignatureLine(trimmed) && openBraces > closeBraces) {\n result.push(line)\n braceDepth += openBraces - closeBraces\n inBody = true\n bodyStartDepth = braceDepth\n continue\n }\n\n // Class/interface declaration — keep but don't treat as body\n if (isClassOrInterfaceLine(trimmed)) {\n result.push(line)\n braceDepth += openBraces - closeBraces\n continue\n }\n\n // Keep the line (top-level statement, property declaration, etc.)\n result.push(line)\n braceDepth += openBraces - closeBraces\n } else {\n // Inside a function body — skip lines\n braceDepth += openBraces - closeBraces\n\n // Check if we've closed back to where the body started\n if (braceDepth < bodyStartDepth) {\n // Add closing brace\n result.push(line)\n inBody = false\n }\n }\n }\n\n return result.join('\\n')\n}\n\nfunction trimPython(content: string): string {\n const lines = content.split('\\n')\n const result: string[] = []\n let skipIndent = -1\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!\n const trimmed = line.trim()\n const indent = line.length - line.trimStart().length\n\n // If we're skipping a body and this line is still indented deeper, skip it\n if (skipIndent >= 0) {\n if (trimmed === '' || indent > skipIndent) {\n continue\n }\n // We've exited the body\n skipIndent = -1\n }\n\n // Always keep: comments, imports, class defs, decorators, type hints, module-level assignments\n if (\n trimmed === '' ||\n trimmed.startsWith('#') ||\n trimmed.startsWith('import ') ||\n trimmed.startsWith('from ') ||\n trimmed.startsWith('@') ||\n trimmed.startsWith('class ') ||\n /^[A-Z_][A-Z_0-9]*\\s*=/.test(trimmed)\n ) {\n result.push(line)\n continue\n }\n\n // Function/method definition — keep signature, skip body\n if (trimmed.startsWith('def ') || trimmed.startsWith('async def ')) {\n result.push(line)\n // If the next non-empty line has docstring, keep it\n const docIdx = findDocstring(lines, i + 1, indent)\n if (docIdx > i) {\n for (let j = i + 1; j <= docIdx; j++) {\n result.push(lines[j]!)\n }\n }\n skipIndent = indent\n continue\n }\n\n // Keep everything else at module/class level\n result.push(line)\n }\n\n return result.join('\\n')\n}\n\nfunction trimJava(content: string): string {\n // Java/Kotlin — very similar to TypeScript brace-matching\n const lines = content.split('\\n')\n const result: string[] = []\n let braceDepth = 0\n let inBody = false\n let bodyStartDepth = 0\n\n for (const line of lines) {\n const trimmed = line.trim()\n\n if (braceDepth === 0 || !inBody) {\n if (\n trimmed === '' ||\n trimmed.startsWith('import ') ||\n trimmed.startsWith('package ') ||\n trimmed.startsWith('@') ||\n trimmed.startsWith('//') ||\n trimmed.startsWith('/*') ||\n trimmed.startsWith('*') ||\n trimmed.startsWith('public interface ') ||\n trimmed.startsWith('interface ') ||\n trimmed.startsWith('public enum ') ||\n trimmed.startsWith('enum ')\n ) {\n result.push(line)\n braceDepth += countChar(trimmed, '{') - countChar(trimmed, '}')\n continue\n }\n }\n\n const openBraces = countChar(trimmed, '{')\n const closeBraces = countChar(trimmed, '}')\n\n if (!inBody) {\n if (isJavaMethodSignature(trimmed) && openBraces > closeBraces) {\n result.push(line)\n braceDepth += openBraces - closeBraces\n inBody = true\n bodyStartDepth = braceDepth\n continue\n }\n\n if (isJavaClassLine(trimmed)) {\n result.push(line)\n braceDepth += openBraces - closeBraces\n continue\n }\n\n result.push(line)\n braceDepth += openBraces - closeBraces\n } else {\n braceDepth += openBraces - closeBraces\n if (braceDepth < bodyStartDepth) {\n result.push(line)\n inBody = false\n }\n }\n }\n\n return result.join('\\n')\n}\n\nfunction trimGeneric(content: string): string {\n // For unknown languages, just return as-is (truncation handles size)\n return content\n}\n\n// --- Helpers ---\n\nfunction countChar(s: string, ch: string): number {\n let count = 0\n let inString = false\n let stringChar = ''\n for (let i = 0; i < s.length; i++) {\n const c = s[i]!\n if (inString) {\n if (c === stringChar && s[i - 1] !== '\\\\') inString = false\n } else if (c === '\"' || c === \"'\" || c === '`') {\n inString = true\n stringChar = c\n } else if (c === ch) {\n count++\n }\n }\n return count\n}\n\nfunction isSignatureLine(trimmed: string): boolean {\n return /^(export\\s+)?(async\\s+)?function\\s/.test(trimmed) ||\n /^(public|private|protected|static|async|get|set|\\*)\\s/.test(trimmed) ||\n /^(readonly\\s+)?[a-zA-Z_$][a-zA-Z0-9_$]*\\s*\\(/.test(trimmed) ||\n /^(export\\s+)?(const|let|var)\\s+\\w+\\s*=\\s*(async\\s+)?\\(/.test(trimmed) ||\n /^(export\\s+)?(const|let|var)\\s+\\w+\\s*=\\s*(async\\s+)?function/.test(trimmed) ||\n // Arrow function assigned at class level\n /^[a-zA-Z_$][a-zA-Z0-9_$]*\\s*=\\s*(async\\s+)?\\(/.test(trimmed)\n}\n\nfunction isClassOrInterfaceLine(trimmed: string): boolean {\n return /^(export\\s+)?(abstract\\s+)?(class|interface|enum)\\s/.test(trimmed) ||\n /^(export\\s+)?namespace\\s/.test(trimmed)\n}\n\nfunction isJavaMethodSignature(trimmed: string): boolean {\n return /^(public|private|protected|static|final|abstract|synchronized|native)\\s/.test(trimmed) &&\n /\\(/.test(trimmed)\n}\n\nfunction isJavaClassLine(trimmed: string): boolean {\n return /^(public|private|protected)?\\s*(abstract\\s+)?(class|interface|enum)\\s/.test(trimmed)\n}\n\nfunction findDocstring(lines: string[], startIdx: number, defIndent: number): number {\n // Find Python docstring (triple-quoted) after a def\n for (let i = startIdx; i < lines.length; i++) {\n const trimmed = lines[i]!.trim()\n if (trimmed === '') continue\n if (trimmed.startsWith('\"\"\"') || trimmed.startsWith(\"'''\")) {\n const quote = trimmed.slice(0, 3)\n // Single-line docstring\n if (trimmed.length > 3 && trimmed.endsWith(quote)) return i\n // Multi-line docstring — find closing\n for (let j = i + 1; j < lines.length; j++) {\n if (lines[j]!.trim().endsWith(quote)) return j\n }\n return i\n }\n // First non-empty line after def is not a docstring\n return startIdx - 1\n }\n return startIdx - 1\n}\n\nfunction getTrimmer(filePath: string): (content: string) => string {\n const ext = extname(filePath).toLowerCase()\n switch (ext) {\n case '.ts':\n case '.tsx':\n case '.js':\n case '.jsx':\n case '.mjs':\n case '.cjs':\n return trimTypeScript\n case '.py':\n return trimPython\n case '.java':\n case '.kt':\n case '.kts':\n case '.scala':\n case '.groovy':\n return trimJava\n case '.go':\n case '.rs':\n case '.c':\n case '.cpp':\n case '.h':\n case '.hpp':\n case '.cs':\n case '.swift':\n case '.dart':\n return trimJava // brace-based languages use same strategy\n default:\n return trimGeneric\n }\n}\n\nexport async function trimCluster(paths: string[], projectRoot: string): Promise<string> {\n const results: Array<{ path: string; content: string; lines: number }> = []\n\n for (const filePath of paths) {\n const absPath = resolve(projectRoot, filePath)\n try {\n const raw = await readFile(absPath, 'utf-8')\n const trimmer = getTrimmer(filePath)\n const trimmed = trimmer(raw)\n results.push({\n path: filePath,\n content: trimmed,\n lines: trimmed.split('\\n').length,\n })\n } catch {\n // Skip files that can't be read\n if (process.env['NOGREP_DEBUG'] === '1') {\n process.stderr.write(`[nogrep] Could not read: ${absPath}\\n`)\n }\n }\n }\n\n // Sort by line count descending — truncate least important (largest) files first\n results.sort((a, b) => a.lines - b.lines)\n\n const output: string[] = []\n let totalLines = 0\n const maxLines = MAX_CLUSTER_LINES\n\n for (const file of results) {\n const header = `// === ${file.path} ===`\n const fileLines = file.content.split('\\n')\n const available = maxLines - totalLines - 2 // header + separator\n\n if (available <= 0) break\n\n output.push(header)\n if (fileLines.length <= available) {\n output.push(file.content)\n } else {\n output.push(fileLines.slice(0, available).join('\\n'))\n output.push(`// ... truncated (${fileLines.length - available} more lines)`)\n }\n output.push('')\n\n totalLines += Math.min(fileLines.length, available) + 2\n }\n\n return output.join('\\n')\n}\n\n// --- CLI ---\n\nasync function main(): Promise<void> {\n const args = process.argv.slice(2)\n\n if (args.length === 0) {\n process.stderr.write('Usage: node trim.js <path1> <path2> ...\\n')\n process.exit(1)\n }\n\n const projectRoot = process.cwd()\n const result = await trimCluster(args, projectRoot)\n process.stdout.write(result)\n}\n\nconst isDirectRun = process.argv[1]?.endsWith('trim.js') || process.argv[1]?.endsWith('trim.ts')\nif (isDirectRun) {\n main().catch((err: unknown) => {\n process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}\\n`)\n process.exit(1)\n })\n}\n"],"mappings":"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","names":[]}
|