repo-context-center 0.1.2 → 0.1.3

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/README.md CHANGED
@@ -22,6 +22,12 @@ This project adds a generic Repository Context Center to answer those questions
22
22
 
23
23
  ## Quick Start
24
24
 
25
+ Inside a target repository:
26
+
27
+ ```sh
28
+ npx repo-context-center init
29
+ ```
30
+
25
31
  From a clone of this project:
26
32
 
27
33
  ```sh
@@ -35,6 +41,7 @@ Then, inside a target repository:
35
41
  ```sh
36
42
  repo-context-center init
37
43
  repo-context-center validate
44
+ repo-context-center suggest "fix auth bug"
38
45
  ```
39
46
 
40
47
  Preview installation without writing files:
@@ -43,6 +50,12 @@ Preview installation without writing files:
43
50
  repo-context-center init --dry-run
44
51
  ```
45
52
 
53
+ Install a PR validation workflow:
54
+
55
+ ```sh
56
+ repo-context-center init --github-action
57
+ ```
58
+
46
59
  Overwrite existing context templates:
47
60
 
48
61
  ```sh
@@ -70,13 +83,20 @@ repo-context-center init --force
70
83
 
71
84
  It also creates `.repo-context-center/config.json`.
72
85
 
86
+ With `--github-action`, it also creates:
87
+
88
+ - `.github/workflows/repo-context-check.yml`
89
+
73
90
  ## Commands
74
91
 
75
92
  ```sh
76
93
  repo-context-center --help
77
- repo-context-center init [--dry-run] [--force]
94
+ repo-context-center init [--dry-run] [--force] [--github-action]
78
95
  repo-context-center validate [--strict]
79
96
  repo-context-center archive [--keep <number>] [--dry-run]
97
+ repo-context-center estimate [--mode compact|investigation|detailed] [--compare-naive] [--json]
98
+ repo-context-center scan [--json]
99
+ repo-context-center suggest "<task>" [--json]
80
100
  ```
81
101
 
82
102
  - `init`: install the generic context templates.
@@ -84,6 +104,29 @@ repo-context-center archive [--keep <number>] [--dry-run]
84
104
  Missing `.repo-context-center/config.json` is a warning by default and a
85
105
  failure with `--strict`.
86
106
  - `archive`: archive older entries from long-running context files; defaults to keeping 50 entries.
107
+ - `estimate`: estimate context token overhead and compare it with a naive repo scan.
108
+ - `scan`: inspect only the repository layout and suggest lightweight entries for context maps.
109
+ - `suggest`: recommend low-token context files, likely modules, likely tests, mode, and risk level for a task.
110
+
111
+ See [docs/github-action.md](docs/github-action.md) for PR validation setup.
112
+
113
+ Example:
114
+
115
+ ```sh
116
+ repo-context-center suggest "fix payment consent bug" --json
117
+ ```
118
+
119
+ Estimate context overhead:
120
+
121
+ ```sh
122
+ repo-context-center estimate --compare-naive
123
+ repo-context-center estimate --mode investigation --task "fix auth bug" --json
124
+ ```
125
+
126
+ Token estimates use `ceil(characters / 4)`. They are rough planning numbers,
127
+ not exact tokenizer output and not model billing estimates. The command is meant
128
+ to help evaluate whether the context center is reducing broad repo reads enough
129
+ to justify its own startup cost.
87
130
 
88
131
  ## Recommended AI Agent Workflow
89
132
 
@@ -91,9 +134,10 @@ Ask the agent to:
91
134
 
92
135
  1. Read `AGENTS.md`.
93
136
  2. Follow `docs/ai-context/TASK_ROUTING.md`.
94
- 3. Read only the context files relevant to the task.
95
- 4. Check `DO_NOT_READ.md` before broad search.
96
- 5. Update `LESSONS_LEARNED.md` and `CHANGE_LOG.md` when durable context changes.
137
+ 3. Check `docs/ai-context/TOKEN_BUDGET.md` and `docs/ai-context/DO_NOT_READ.md`.
138
+ 4. Read only the on-demand context files relevant to the task.
139
+ 5. Verify source code before changing behavior.
140
+ 6. Update context files only when durable repo knowledge changes.
97
141
 
98
142
  See [docs/agent-usage.md](docs/agent-usage.md).
99
143
 
@@ -126,17 +170,20 @@ More examples are in [docs/examples.md](docs/examples.md).
126
170
  - [Agent usage](docs/agent-usage.md)
127
171
  - [Token strategy](docs/token-strategy.md)
128
172
  - [Examples](docs/examples.md)
173
+ - [GitHub Action](docs/github-action.md)
129
174
 
130
175
  ## Supported Project Types
131
176
 
132
177
  The generic templates are language-agnostic. They can be installed in JavaScript, TypeScript, Python, Go, Rust, Ruby, Java, monorepos, docs repos, and mixed stacks.
133
178
 
134
- Project-specific templates and repo scanning are not implemented yet.
179
+ Project-specific templates are not implemented yet. The current scanner is intentionally lightweight and does not read full source files.
135
180
 
136
181
  ## Roadmap
137
182
 
138
183
  - Generic template installation and validation.
139
184
  - Context file archiving.
185
+ - Lightweight repo layout scanning.
186
+ - Task-specific context suggestions.
140
187
  - Project-specific template packs.
141
188
  - Optional repository scanning to prefill maps.
142
189
  - Safer update workflows for existing context centers.
@@ -0,0 +1,2 @@
1
+ import type { CliIO } from "../index";
2
+ export declare function estimateCommand(io: CliIO, args?: string[]): Promise<number>;
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.estimateCommand = estimateCommand;
4
+ const tokenEstimator_1 = require("../../core/tokenEstimator");
5
+ function parseEstimateOptions(args) {
6
+ let json = false;
7
+ let mode = "compact";
8
+ let task;
9
+ let compareNaive = false;
10
+ let maxFiles = 500;
11
+ for (let index = 0; index < args.length; index += 1) {
12
+ const arg = args[index];
13
+ if (arg === "--json") {
14
+ json = true;
15
+ }
16
+ else if (arg === "--compare-naive") {
17
+ compareNaive = true;
18
+ }
19
+ else if (arg === "--mode") {
20
+ const value = args[index + 1];
21
+ if (value !== "compact" && value !== "investigation" && value !== "detailed") {
22
+ return undefined;
23
+ }
24
+ mode = value;
25
+ index += 1;
26
+ }
27
+ else if (arg === "--task") {
28
+ const value = args[index + 1];
29
+ if (!value) {
30
+ return undefined;
31
+ }
32
+ task = value;
33
+ index += 1;
34
+ }
35
+ else if (arg === "--max-files") {
36
+ const value = Number.parseInt(args[index + 1] ?? "", 10);
37
+ if (!Number.isInteger(value) || value < 1) {
38
+ return undefined;
39
+ }
40
+ maxFiles = value;
41
+ index += 1;
42
+ }
43
+ else {
44
+ return undefined;
45
+ }
46
+ }
47
+ return { json, mode, task, compareNaive, maxFiles };
48
+ }
49
+ function formatNumber(value) {
50
+ return value === undefined ? "not run" : value.toLocaleString("en-US");
51
+ }
52
+ function formatReport(report) {
53
+ const lines = [
54
+ "repo-context-center token estimate",
55
+ "",
56
+ "Method:",
57
+ `- Approximation: ${report.method}`,
58
+ "",
59
+ "Mode:",
60
+ `- ${report.mode}`,
61
+ "",
62
+ "Context cost:",
63
+ `- Startup context: ${formatNumber(report.startupTokens)} tokens`,
64
+ `- On-demand context available: ${formatNumber(report.onDemandTokens)} tokens`,
65
+ `- History/archive excluded: ${formatNumber(report.historyTokens)} tokens`,
66
+ `- Included for mode: ${formatNumber(report.includedContextTokens)} tokens`
67
+ ];
68
+ if (report.naiveScanTokens !== undefined) {
69
+ lines.push("", "Naive comparison:", `- Estimated naive scan: ${formatNumber(report.naiveScanTokens)} tokens`, `- Estimated compact startup: ${formatNumber(report.startupTokens)} tokens`, `- Estimated saving: ${formatNumber(report.estimatedSavedTokens)} tokens`, `- Estimated saving: ${formatNumber(report.estimatedSavingPercent)}%`);
70
+ if (report.naiveScanCapped) {
71
+ lines.push(`- Naive scan capped at ${report.maxFiles} files`);
72
+ }
73
+ }
74
+ if (report.taskEstimate) {
75
+ lines.push("", "Task recommendation:", `- Task: ${report.taskEstimate.task}`, `- Recommended context: ${formatNumber(report.taskEstimate.recommendedContextTokens)} tokens`, `- Likely source: ${formatNumber(report.taskEstimate.likelySourceTokens)} tokens`, `- Likely tests: ${formatNumber(report.taskEstimate.likelyTestTokens)} tokens`);
76
+ }
77
+ lines.push("", "Warnings:", ...report.warnings.map((warning) => `- ${warning}`));
78
+ return `${lines.join("\n")}\n`;
79
+ }
80
+ async function estimateCommand(io, args = []) {
81
+ const options = parseEstimateOptions(args);
82
+ if (!options) {
83
+ io.stderr('Usage: repo-context-center estimate [--json] [--mode compact|investigation|detailed] [--task "<task>"] [--compare-naive] [--max-files <number>]\n');
84
+ return 1;
85
+ }
86
+ const report = await (0, tokenEstimator_1.estimateTokenCost)({
87
+ cwd: io.cwd,
88
+ mode: options.mode,
89
+ task: options.task,
90
+ compareNaive: options.compareNaive,
91
+ maxFiles: options.maxFiles
92
+ });
93
+ if (options.json) {
94
+ io.stdout(`${JSON.stringify(report, null, 2)}\n`);
95
+ return 0;
96
+ }
97
+ io.stdout(formatReport(report));
98
+ return 0;
99
+ }
@@ -6,7 +6,8 @@ const templateInstaller_1 = require("../../core/templateInstaller");
6
6
  function parseInitOptions(args) {
7
7
  return {
8
8
  force: args.includes("--force"),
9
- dryRun: args.includes("--dry-run")
9
+ dryRun: args.includes("--dry-run"),
10
+ githubAction: args.includes("--github-action")
10
11
  };
11
12
  }
12
13
  function formatInstallMessage(result, dryRun) {
@@ -24,7 +25,8 @@ function formatInstallMessage(result, dryRun) {
24
25
  }
25
26
  async function initCommand(io, args = []) {
26
27
  const options = parseInitOptions(args);
27
- const unknownFlag = args.find((arg) => arg.startsWith("--") && arg !== "--force" && arg !== "--dry-run");
28
+ const knownFlags = new Set(["--force", "--dry-run", "--github-action"]);
29
+ const unknownFlag = args.find((arg) => arg.startsWith("--") && !knownFlags.has(arg));
28
30
  if (unknownFlag) {
29
31
  io.stderr(`Unknown init option: ${unknownFlag}\n`);
30
32
  return 1;
@@ -32,7 +34,8 @@ async function initCommand(io, args = []) {
32
34
  const results = await (0, templateInstaller_1.installGenericTemplates)({
33
35
  cwd: io.cwd,
34
36
  force: options.force,
35
- dryRun: options.dryRun
37
+ dryRun: options.dryRun,
38
+ githubAction: options.githubAction
36
39
  });
37
40
  for (const result of results) {
38
41
  io.stdout(formatInstallMessage(result, options.dryRun));
@@ -0,0 +1,2 @@
1
+ import type { CliIO } from "../index";
2
+ export declare function scanCommand(io: CliIO, args?: string[]): Promise<number>;
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.scanCommand = scanCommand;
4
+ const scanner_1 = require("../../core/scanner");
5
+ function parseScanOptions(args) {
6
+ const unknownFlag = args.find((arg) => arg !== "--json");
7
+ if (unknownFlag) {
8
+ return undefined;
9
+ }
10
+ return {
11
+ json: args.includes("--json")
12
+ };
13
+ }
14
+ function formatList(values) {
15
+ return values.length > 0 ? values.join(", ") : "none";
16
+ }
17
+ function formatScanReport(report) {
18
+ const lines = [
19
+ "repo-context-center scan report",
20
+ "",
21
+ `Source folders: ${formatList(report.detected.sourceFolders)}`,
22
+ `Test folders: ${formatList(report.detected.testFolders)}`,
23
+ `Generated folders: ${formatList(report.detected.generatedFolders)}`,
24
+ ""
25
+ ];
26
+ if (report.detected.modules.length > 0) {
27
+ lines.push("Detected modules:");
28
+ for (const module of report.detected.modules) {
29
+ lines.push(` - ${module.path}`);
30
+ }
31
+ }
32
+ else {
33
+ lines.push("Detected modules: none");
34
+ }
35
+ lines.push("");
36
+ for (const [file, suggestions] of Object.entries(report.suggestions)) {
37
+ lines.push(file);
38
+ lines.push(...suggestions.map((line) => (line ? ` ${line}` : "")));
39
+ lines.push("");
40
+ }
41
+ return `${lines.join("\n").trimEnd()}\n`;
42
+ }
43
+ async function scanCommand(io, args = []) {
44
+ const options = parseScanOptions(args);
45
+ if (!options) {
46
+ io.stderr("Unknown scan option. Supported options: --json\n");
47
+ return 1;
48
+ }
49
+ const report = await (0, scanner_1.scanRepository)(io.cwd);
50
+ if (options.json) {
51
+ io.stdout(`${JSON.stringify(report, null, 2)}\n`);
52
+ return 0;
53
+ }
54
+ io.stdout(formatScanReport(report));
55
+ return 0;
56
+ }
@@ -0,0 +1,2 @@
1
+ import type { CliIO } from "../index";
2
+ export declare function suggestCommand(io: CliIO, args?: string[]): Promise<number>;
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.suggestCommand = suggestCommand;
4
+ const suggester_1 = require("../../core/suggester");
5
+ function parseSuggestOptions(args) {
6
+ const json = args.includes("--json");
7
+ const symbols = args.includes("--symbols");
8
+ const taskParts = args.filter((arg) => arg !== "--json" && arg !== "--symbols");
9
+ if (taskParts.some((arg) => arg.startsWith("--"))) {
10
+ return undefined;
11
+ }
12
+ const task = taskParts.join(" ").trim();
13
+ if (!task) {
14
+ return undefined;
15
+ }
16
+ return { json, symbols, task };
17
+ }
18
+ function formatList(values) {
19
+ return values.length > 0 ? values.map((value) => ` - ${value}`).join("\n") : " - none";
20
+ }
21
+ function formatSymbols(suggestion) {
22
+ if (suggestion.relevantSymbols.length === 0) {
23
+ return " - none";
24
+ }
25
+ return suggestion.relevantSymbols
26
+ .map((entry) => [
27
+ ` - ${entry.file}`,
28
+ ...entry.symbols.map((symbol) => ` - ${symbol}`)
29
+ ].join("\n"))
30
+ .join("\n");
31
+ }
32
+ function formatSuggestion(suggestion, includeSymbols) {
33
+ const lines = [
34
+ "repo-context-center suggestion",
35
+ "",
36
+ `Task: ${suggestion.task}`,
37
+ `Mode: ${suggestion.mode}`,
38
+ `Risk: ${suggestion.riskLevel}`,
39
+ "",
40
+ "Context files:",
41
+ formatList(suggestion.contextFiles),
42
+ "",
43
+ "Likely source files:",
44
+ formatList(suggestion.likelySourceFiles),
45
+ ];
46
+ if (includeSymbols) {
47
+ lines.push("", "Relevant symbols:", formatSymbols(suggestion));
48
+ }
49
+ lines.push("", "Likely tests:", formatList(suggestion.likelyTests), "", "Reasons:", formatList(suggestion.reasons));
50
+ return `${lines.join("\n")}\n`;
51
+ }
52
+ async function suggestCommand(io, args = []) {
53
+ const options = parseSuggestOptions(args);
54
+ if (!options) {
55
+ io.stderr('Usage: repo-context-center suggest "<task>" [--json] [--symbols]\n');
56
+ return 1;
57
+ }
58
+ const suggestion = await (0, suggester_1.suggestContext)(io.cwd, options.task);
59
+ if (options.json) {
60
+ io.stdout(`${JSON.stringify(suggestion, null, 2)}\n`);
61
+ return 0;
62
+ }
63
+ io.stdout(formatSuggestion(suggestion, options.symbols));
64
+ return 0;
65
+ }
package/dist/cli/index.js CHANGED
@@ -4,12 +4,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.getHelpText = getHelpText;
5
5
  exports.run = run;
6
6
  const archive_1 = require("./commands/archive");
7
+ const estimate_1 = require("./commands/estimate");
7
8
  const init_1 = require("./commands/init");
9
+ const scan_1 = require("./commands/scan");
10
+ const suggest_1 = require("./commands/suggest");
8
11
  const validate_1 = require("./commands/validate");
9
12
  const commands = {
10
13
  init: init_1.initCommand,
11
14
  validate: validate_1.validateCommand,
12
- archive: archive_1.archiveCommand
15
+ archive: archive_1.archiveCommand,
16
+ estimate: estimate_1.estimateCommand,
17
+ scan: scan_1.scanCommand,
18
+ suggest: suggest_1.suggestCommand
13
19
  };
14
20
  const helpText = `repo-context-center
15
21
 
@@ -18,11 +24,17 @@ Usage:
18
24
 
19
25
  Commands:
20
26
  init Install generic context templates and config
21
- Options: --dry-run, --force
27
+ Options: --dry-run, --force, --github-action
22
28
  validate Validate required context files and warnings
23
29
  Options: --strict
24
30
  archive Archive older CHANGE_LOG and LESSONS_LEARNED entries
25
31
  Options: --keep <number>, --dry-run
32
+ estimate Estimate context token costs and rough savings
33
+ Options: --json, --mode <mode>, --task <text>, --compare-naive, --max-files <number>
34
+ scan Suggest lightweight context entries from repo layout
35
+ Options: --json
36
+ suggest Recommend context files for a task
37
+ Usage: suggest "<task>" [--json] [--symbols]
26
38
 
27
39
  Options:
28
40
  -h, --help Show this help
@@ -1,4 +1,9 @@
1
1
  export declare const requiredContextFiles: readonly ["AGENTS.md", "docs/ai-context/COMMUNICATION_MODE.md", "docs/ai-context/TASK_ROUTING.md", "docs/ai-context/MODULE_INDEX.md", "docs/ai-context/PROJECT_MAP.md", "docs/ai-context/RISK_REGISTER.md", "docs/ai-context/DEPENDENCY_MAP.md", "docs/ai-context/SYMBOL_MAP.md", "docs/ai-context/TOKEN_BUDGET.md", "docs/ai-context/DO_NOT_READ.md", "docs/ai-context/HOTSPOTS.md", "docs/ai-context/LESSONS_LEARNED.md", "docs/ai-context/CHANGE_LOG.md"];
2
2
  export type RequiredContextFile = (typeof requiredContextFiles)[number];
3
3
  export declare const contextArchiveDir = "docs/ai-context/archive";
4
+ export declare const agentsFile = "AGENTS.md";
5
+ export declare const tokenBudgetFile = "docs/ai-context/TOKEN_BUDGET.md";
6
+ export declare const doNotReadFile = "docs/ai-context/DO_NOT_READ.md";
7
+ export declare const requiredTokenBudgetModes: readonly ["Compact Mode", "Investigation Mode"];
8
+ export declare const generatedFolderExclusions: readonly ["node_modules", "dist", "build", "coverage", "archive"];
4
9
  export declare const contextSizeLimits: Partial<Record<RequiredContextFile, number>>;
@@ -1,9 +1,20 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.contextSizeLimits = exports.contextArchiveDir = exports.requiredContextFiles = void 0;
3
+ exports.contextSizeLimits = exports.generatedFolderExclusions = exports.requiredTokenBudgetModes = exports.doNotReadFile = exports.tokenBudgetFile = exports.agentsFile = exports.contextArchiveDir = exports.requiredContextFiles = void 0;
4
4
  const generic_1 = require("../templates/generic");
5
5
  exports.requiredContextFiles = generic_1.genericTemplateFiles;
6
6
  exports.contextArchiveDir = "docs/ai-context/archive";
7
+ exports.agentsFile = "AGENTS.md";
8
+ exports.tokenBudgetFile = "docs/ai-context/TOKEN_BUDGET.md";
9
+ exports.doNotReadFile = "docs/ai-context/DO_NOT_READ.md";
10
+ exports.requiredTokenBudgetModes = ["Compact Mode", "Investigation Mode"];
11
+ exports.generatedFolderExclusions = [
12
+ "node_modules",
13
+ "dist",
14
+ "build",
15
+ "coverage",
16
+ "archive"
17
+ ];
7
18
  exports.contextSizeLimits = {
8
19
  "docs/ai-context/CHANGE_LOG.md": 32 * 1024,
9
20
  "docs/ai-context/TASK_ROUTING.md": 16 * 1024
@@ -0,0 +1,7 @@
1
+ export declare const suggestContextFiles: readonly ["docs/ai-context/TASK_ROUTING.md", "docs/ai-context/MODULE_INDEX.md", "docs/ai-context/DEPENDENCY_MAP.md", "docs/ai-context/SYMBOL_MAP.md", "docs/ai-context/RISK_REGISTER.md", "docs/ai-context/HOTSPOTS.md"];
2
+ export type SuggestContextFile = (typeof suggestContextFiles)[number];
3
+ export interface ContextDocument {
4
+ path: SuggestContextFile;
5
+ content: string;
6
+ }
7
+ export declare function readSuggestContext(cwd: string): Promise<ContextDocument[]>;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.suggestContextFiles = void 0;
7
+ exports.readSuggestContext = readSuggestContext;
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const fileSystem_1 = require("./fileSystem");
10
+ exports.suggestContextFiles = [
11
+ "docs/ai-context/TASK_ROUTING.md",
12
+ "docs/ai-context/MODULE_INDEX.md",
13
+ "docs/ai-context/DEPENDENCY_MAP.md",
14
+ "docs/ai-context/SYMBOL_MAP.md",
15
+ "docs/ai-context/RISK_REGISTER.md",
16
+ "docs/ai-context/HOTSPOTS.md"
17
+ ];
18
+ async function readSuggestContext(cwd) {
19
+ const documents = [];
20
+ for (const file of exports.suggestContextFiles) {
21
+ const fullPath = node_path_1.default.join(cwd, file);
22
+ if (await (0, fileSystem_1.pathExists)(fullPath)) {
23
+ documents.push({
24
+ path: file,
25
+ content: await (0, fileSystem_1.readTextFile)(fullPath)
26
+ });
27
+ }
28
+ }
29
+ return documents;
30
+ }
@@ -2,4 +2,7 @@ export declare function pathExists(filePath: string): Promise<boolean>;
2
2
  export declare function ensureDir(dirPath: string): Promise<void>;
3
3
  export declare function writeJsonFile(filePath: string, value: unknown): Promise<void>;
4
4
  export declare function writeTextFile(filePath: string, content: string): Promise<void>;
5
+ export declare function readTextFile(filePath: string): Promise<string>;
5
6
  export declare function readJsonFile<T>(filePath: string): Promise<T>;
7
+ export declare function listDirectoryNames(dirPath: string): Promise<string[]>;
8
+ export declare function listFilesRecursive(dirPath: string, rootPath?: string): Promise<string[]>;
@@ -7,7 +7,10 @@ exports.pathExists = pathExists;
7
7
  exports.ensureDir = ensureDir;
8
8
  exports.writeJsonFile = writeJsonFile;
9
9
  exports.writeTextFile = writeTextFile;
10
+ exports.readTextFile = readTextFile;
10
11
  exports.readJsonFile = readJsonFile;
12
+ exports.listDirectoryNames = listDirectoryNames;
13
+ exports.listFilesRecursive = listFilesRecursive;
11
14
  const promises_1 = require("node:fs/promises");
12
15
  const node_path_1 = __importDefault(require("node:path"));
13
16
  async function pathExists(filePath) {
@@ -30,6 +33,40 @@ async function writeTextFile(filePath, content) {
30
33
  await ensureDir(node_path_1.default.dirname(filePath));
31
34
  await (0, promises_1.writeFile)(filePath, content, "utf8");
32
35
  }
36
+ async function readTextFile(filePath) {
37
+ return (0, promises_1.readFile)(filePath, "utf8");
38
+ }
33
39
  async function readJsonFile(filePath) {
34
40
  return JSON.parse(await (0, promises_1.readFile)(filePath, "utf8"));
35
41
  }
42
+ async function listDirectoryNames(dirPath) {
43
+ try {
44
+ const entries = await (0, promises_1.readdir)(dirPath, { withFileTypes: true });
45
+ return entries
46
+ .filter((entry) => entry.isDirectory())
47
+ .map((entry) => entry.name)
48
+ .sort((left, right) => left.localeCompare(right));
49
+ }
50
+ catch {
51
+ return [];
52
+ }
53
+ }
54
+ async function listFilesRecursive(dirPath, rootPath = dirPath) {
55
+ try {
56
+ const entries = await (0, promises_1.readdir)(dirPath, { withFileTypes: true });
57
+ const files = [];
58
+ for (const entry of entries) {
59
+ const fullPath = node_path_1.default.join(dirPath, entry.name);
60
+ if (entry.isDirectory()) {
61
+ files.push(...await listFilesRecursive(fullPath, rootPath));
62
+ }
63
+ else if (entry.isFile()) {
64
+ files.push(node_path_1.default.relative(rootPath, fullPath).split(node_path_1.default.sep).join("/"));
65
+ }
66
+ }
67
+ return files.sort((left, right) => left.localeCompare(right));
68
+ }
69
+ catch {
70
+ return [];
71
+ }
72
+ }
@@ -0,0 +1,34 @@
1
+ export interface ScannedModule {
2
+ name: string;
3
+ path: string;
4
+ sourceRoot: string;
5
+ }
6
+ export type ScannedSymbolKind = "function" | "class" | "interface" | "type" | "const" | "export";
7
+ export interface ScannedSymbol {
8
+ name: string;
9
+ kind: ScannedSymbolKind;
10
+ path: string;
11
+ }
12
+ export interface ScannedSourceFile {
13
+ path: string;
14
+ symbols: ScannedSymbol[];
15
+ tests: string[];
16
+ }
17
+ export interface ScanReport {
18
+ root: string;
19
+ detected: {
20
+ sourceFolders: string[];
21
+ testFolders: string[];
22
+ generatedFolders: string[];
23
+ modules: ScannedModule[];
24
+ sourceFiles: ScannedSourceFile[];
25
+ };
26
+ suggestions: {
27
+ "MODULE_INDEX.md": string[];
28
+ "DO_NOT_READ.md": string[];
29
+ "TASK_ROUTING.md": string[];
30
+ "SYMBOL_MAP.md": string[];
31
+ };
32
+ }
33
+ export declare function extractExportedSymbols(sourcePath: string, content: string): ScannedSymbol[];
34
+ export declare function scanRepository(cwd: string): Promise<ScanReport>;