@horiastanxd/claude-init 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +223 -0
  3. package/dist/analyzer/code-patterns.d.ts +2 -0
  4. package/dist/analyzer/code-patterns.js +71 -0
  5. package/dist/analyzer/code-patterns.js.map +1 -0
  6. package/dist/analyzer/commands.d.ts +2 -0
  7. package/dist/analyzer/commands.js +86 -0
  8. package/dist/analyzer/commands.js.map +1 -0
  9. package/dist/analyzer/env-vars.d.ts +3 -0
  10. package/dist/analyzer/env-vars.js +42 -0
  11. package/dist/analyzer/env-vars.js.map +1 -0
  12. package/dist/analyzer/git-history.d.ts +2 -0
  13. package/dist/analyzer/git-history.js +41 -0
  14. package/dist/analyzer/git-history.js.map +1 -0
  15. package/dist/analyzer/index.d.ts +3 -0
  16. package/dist/analyzer/index.js +44 -0
  17. package/dist/analyzer/index.js.map +1 -0
  18. package/dist/analyzer/project-structure.d.ts +2 -0
  19. package/dist/analyzer/project-structure.js +95 -0
  20. package/dist/analyzer/project-structure.js.map +1 -0
  21. package/dist/analyzer/tech-stack.d.ts +2 -0
  22. package/dist/analyzer/tech-stack.js +141 -0
  23. package/dist/analyzer/tech-stack.js.map +1 -0
  24. package/dist/cli.d.ts +2 -0
  25. package/dist/cli.js +129 -0
  26. package/dist/cli.js.map +1 -0
  27. package/dist/generators/agents-md.d.ts +6 -0
  28. package/dist/generators/agents-md.js +12 -0
  29. package/dist/generators/agents-md.js.map +1 -0
  30. package/dist/generators/claude-md.d.ts +2 -0
  31. package/dist/generators/claude-md.js +5 -0
  32. package/dist/generators/claude-md.js.map +1 -0
  33. package/dist/generators/copilot-instructions.d.ts +2 -0
  34. package/dist/generators/copilot-instructions.js +5 -0
  35. package/dist/generators/copilot-instructions.js.map +1 -0
  36. package/dist/generators/cursor-rules.d.ts +2 -0
  37. package/dist/generators/cursor-rules.js +5 -0
  38. package/dist/generators/cursor-rules.js.map +1 -0
  39. package/dist/generators/gemini-md.d.ts +2 -0
  40. package/dist/generators/gemini-md.js +5 -0
  41. package/dist/generators/gemini-md.js.map +1 -0
  42. package/dist/generators/index.d.ts +11 -0
  43. package/dist/generators/index.js +43 -0
  44. package/dist/generators/index.js.map +1 -0
  45. package/dist/generators/registry.d.ts +21 -0
  46. package/dist/generators/registry.js +108 -0
  47. package/dist/generators/registry.js.map +1 -0
  48. package/dist/generators/render.d.ts +19 -0
  49. package/dist/generators/render.js +58 -0
  50. package/dist/generators/render.js.map +1 -0
  51. package/dist/generators/sections.d.ts +9 -0
  52. package/dist/generators/sections.js +96 -0
  53. package/dist/generators/sections.js.map +1 -0
  54. package/dist/index.d.ts +12 -0
  55. package/dist/index.js +11 -0
  56. package/dist/index.js.map +1 -0
  57. package/dist/mcp-server.d.ts +1 -0
  58. package/dist/mcp-server.js +98 -0
  59. package/dist/mcp-server.js.map +1 -0
  60. package/dist/types.d.ts +84 -0
  61. package/dist/types.js +2 -0
  62. package/dist/types.js.map +1 -0
  63. package/dist/utils.d.ts +5 -0
  64. package/dist/utils.js +53 -0
  65. package/dist/utils.js.map +1 -0
  66. package/dist/version.d.ts +2 -0
  67. package/dist/version.js +13 -0
  68. package/dist/version.js.map +1 -0
  69. package/package.json +79 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Horia Stan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,223 @@
1
+ <div align="center">
2
+
3
+ # claude-init
4
+
5
+ **One command generates the AI context files for every coding assistant - from one repo scan.**
6
+
7
+ `CLAUDE.md` · `AGENTS.md` · Cursor · Windsurf · Cline · Copilot · `GEMINI.md` · Aider · Junie · Warp
8
+
9
+ ```bash
10
+ npx @horiastanxd/claude-init
11
+ ```
12
+
13
+ [![npm version](https://img.shields.io/npm/v/@horiastanxd/claude-init.svg?color=cb3837&logo=npm)](https://www.npmjs.com/package/@horiastanxd/claude-init)
14
+ [![CI](https://github.com/horiastanxd/claude-init/actions/workflows/ci.yml/badge.svg)](https://github.com/horiastanxd/claude-init/actions/workflows/ci.yml)
15
+ [![license](https://img.shields.io/npm/l/@horiastanxd/claude-init.svg?color=blue)](./LICENSE)
16
+ [![node](https://img.shields.io/node/v/@horiastanxd/claude-init.svg?color=339933&logo=node.js)](https://nodejs.org)
17
+
18
+ </div>
19
+
20
+ <div align="center">
21
+
22
+ ![claude-init demo](./assets/demo.gif)
23
+
24
+ </div>
25
+
26
+ ---
27
+
28
+ ## Why
29
+
30
+ Every AI coding tool wants a file describing your project - and they all use a
31
+ different name and format. Keeping ten of them in sync by hand is busywork, and the
32
+ moment your stack changes they go stale.
33
+
34
+ `claude-init` scans your repo once - stack, scripts, structure, env vars, conventions,
35
+ git - and writes all of them in seconds. **No API key, no network, 100% local.**
36
+
37
+ ```bash
38
+ $ npx @horiastanxd/claude-init
39
+ ✔ Analyzed my-app (TypeScript, Next.js)
40
+ + CLAUDE.md
41
+ + AGENTS.md
42
+ + .cursor/rules/project.mdc
43
+ + .windsurf/rules/project.md
44
+ + .clinerules/project.md
45
+ + .github/copilot-instructions.md
46
+ + GEMINI.md
47
+ + CONVENTIONS.md
48
+ + .junie/guidelines.md
49
+ + WARP.md
50
+
51
+ Done. 10 file(s) generated.
52
+ ```
53
+
54
+ ## Supported tools
55
+
56
+ | Target (`-t`) | File written | Read by |
57
+ | --- | --- | --- |
58
+ | `claude` | `CLAUDE.md` | Claude Code |
59
+ | `agents` | `AGENTS.md` | OpenAI Codex, Jules, Amp, Zed, Devin, RooCode, Factory, +20 agents |
60
+ | `cursor` | `.cursor/rules/project.mdc` | Cursor (modern `.mdc` rules) |
61
+ | `windsurf` | `.windsurf/rules/project.md` | Windsurf / Codeium |
62
+ | `cline` | `.clinerules/project.md` | Cline, Roo Code |
63
+ | `copilot` | `.github/copilot-instructions.md` | GitHub Copilot |
64
+ | `gemini` | `GEMINI.md` | Gemini CLI |
65
+ | `aider` | `CONVENTIONS.md` | Aider |
66
+ | `junie` | `.junie/guidelines.md` | JetBrains Junie |
67
+ | `warp` | `WARP.md` | Warp terminal |
68
+
69
+ > [`AGENTS.md`](https://agents.md) is becoming the shared standard - one file read by
70
+ > a growing list of agents. `claude-init` generates it alongside each tool's native
71
+ > format, so you are covered both ways.
72
+
73
+ ## Usage
74
+
75
+ ```bash
76
+ npx @horiastanxd/claude-init # generate everything in the current repo
77
+ npx @horiastanxd/claude-init ./path/to/repo # analyze a different directory
78
+ npx @horiastanxd/claude-init -t claude,cursor # only specific tools
79
+ npx @horiastanxd/claude-init --overwrite # refresh files that already exist
80
+ npx @horiastanxd/claude-init --dry-run # print the analysis as JSON, write nothing
81
+ npx @horiastanxd/claude-init list # show all targets and their paths
82
+ ```
83
+
84
+ By default existing files are left untouched - re-run with `--overwrite` to refresh
85
+ them after your stack changes.
86
+
87
+ ```
88
+ claude-init [generate] [dir] analyze a repo and write context files (default)
89
+ claude-init check [dir] verify files are up to date (exit 1 on drift)
90
+ claude-init list list supported targets
91
+ claude-init mcp run as an MCP server over stdio
92
+
93
+ Options:
94
+ -t, --targets <list> comma-separated target ids, or "all" (default: all)
95
+ -o, --output <dir> output directory (default: .)
96
+ --overwrite overwrite existing files
97
+ --dry-run print the analysis as JSON, write nothing
98
+ ```
99
+
100
+ ## Keep context files fresh
101
+
102
+ `claude-init check` regenerates in memory and compares against disk, exiting non-zero
103
+ on drift. Wire it into CI or a pre-commit hook so your context never rots.
104
+
105
+ **pre-commit** (`.git/hooks/pre-commit` or [pre-commit](https://pre-commit.com)):
106
+
107
+ ```bash
108
+ npx @horiastanxd/claude-init check || {
109
+ echo "AI context files are stale - run: npx @horiastanxd/claude-init --overwrite"
110
+ exit 1
111
+ }
112
+ ```
113
+
114
+ **GitHub Actions:**
115
+
116
+ ```yaml
117
+ - run: npx @horiastanxd/claude-init check
118
+ ```
119
+
120
+ ## Example output
121
+
122
+ <details>
123
+ <summary><code>CLAUDE.md</code> generated for a Next.js + Prisma app</summary>
124
+
125
+ ```markdown
126
+ # my-app
127
+
128
+ A demo application.
129
+
130
+ ## Stack
131
+ - Language: TypeScript
132
+ - Framework: Next.js
133
+ - Runtime: Node.js
134
+ - Package manager: pnpm
135
+ - Database: Prisma ORM
136
+ - Testing: Vitest
137
+
138
+ ## Commands
139
+ ```bash
140
+ pnpm install # install
141
+ pnpm run dev # dev
142
+ pnpm run test # test
143
+ ```
144
+
145
+ ## Code conventions
146
+ - TypeScript strict mode is enabled - keep full type safety, avoid `any`.
147
+ - Linter: ESLint. Run it before committing.
148
+ - Formatter: Prettier. Do not hand-format against it.
149
+
150
+ ## Environment variables
151
+ Copy `.env.example` to `.env` and set:
152
+ - `DATABASE_URL` (**required**) - Postgres connection string
153
+ ```
154
+
155
+ </details>
156
+
157
+ ## MCP server
158
+
159
+ `claude-init` also runs as a [Model Context Protocol](https://modelcontextprotocol.io)
160
+ server, so an agent can analyze a repo and write the context files itself.
161
+
162
+ ```bash
163
+ # Claude Code
164
+ claude mcp add claude-init -- npx @horiastanxd/claude-init --mcp
165
+ ```
166
+
167
+ Tools exposed: `analyze_project`, `generate_context_files`, `check_context_files`.
168
+
169
+ ## What gets detected
170
+
171
+ - **Stack** - language, framework, runtime, package manager, database, test runner, build tool
172
+ - **Commands** - install / dev / build / test / lint / format, plus other scripts
173
+ - **Structure** - a trimmed file tree, entry points, config files
174
+ - **Conventions** - strict mode, linter, formatter, import style, commit convention
175
+ - **Env vars** - parsed from `.env.example`, with inline comments as descriptions
176
+ - **Git** - default branch, remote, top authors, frequently changed files
177
+
178
+ Languages: JS/TS (npm, pnpm, yarn, bun), Python (pip, uv, poetry), Rust (cargo),
179
+ Go (modules), plus partial detection for Java, Ruby, and PHP.
180
+
181
+ ## Use as a library
182
+
183
+ ```ts
184
+ import { analyzeProject, generateClaudeMd, buildFiles } from 'claude-init';
185
+
186
+ const analysis = await analyzeProject(process.cwd());
187
+ const md = generateClaudeMd(analysis);
188
+
189
+ // or render every target in memory
190
+ for (const file of buildFiles(analysis)) {
191
+ console.log(file.relPath, file.content.length);
192
+ }
193
+ ```
194
+
195
+ ## Development
196
+
197
+ ```bash
198
+ npm install
199
+ npm run dev -- --dry-run # run from source
200
+ npm test
201
+ npm run build
202
+ ```
203
+
204
+ Contributions welcome - adding a new tool is usually a single entry in
205
+ [`src/generators/registry.ts`](./src/generators/registry.ts). See
206
+ [CONTRIBUTING.md](./CONTRIBUTING.md).
207
+
208
+ ## Roadmap
209
+
210
+ - More tools (Zed dedicated rules, Continue, Kilo Code, Trae)
211
+ - Monorepo-aware generation (per-package context files)
212
+ - Optional LLM pass to enrich descriptions (opt-in, off by default)
213
+
214
+ Ideas and PRs welcome.
215
+
216
+ ## Star History
217
+
218
+ [![Star History Chart](https://api.star-history.com/svg?repos=horiastanxd/claude-init&type=Date)](https://star-history.com/#horiastanxd/claude-init&Date)
219
+
220
+ ## License
221
+
222
+ [MIT](./LICENSE)
223
+
@@ -0,0 +1,2 @@
1
+ import type { CodePatterns } from '../types.js';
2
+ export declare function detectCodePatterns(projectDir: string): Promise<CodePatterns>;
@@ -0,0 +1,71 @@
1
+ import { join } from 'node:path';
2
+ import { pathExists, readText, readJson } from '../utils.js';
3
+ export async function detectCodePatterns(projectDir) {
4
+ const [tsconfig, linter, formatter, commitConvention] = await Promise.all([
5
+ detectStrict(projectDir),
6
+ detectLinter(projectDir),
7
+ detectFormatter(projectDir),
8
+ detectCommitConvention(projectDir),
9
+ ]);
10
+ return {
11
+ strict: tsconfig.strict,
12
+ linter,
13
+ formatter,
14
+ commitConvention,
15
+ importStyle: tsconfig.importStyle,
16
+ };
17
+ }
18
+ async function detectStrict(dir) {
19
+ const raw = await readText(join(dir, 'tsconfig.json'));
20
+ if (raw === null)
21
+ return { strict: false, importStyle: null };
22
+ return {
23
+ strict: /"strict"\s*:\s*true/.test(raw),
24
+ importStyle: /"(baseUrl|paths)"\s*:/.test(raw) ? 'absolute (path aliases)' : 'relative',
25
+ };
26
+ }
27
+ async function detectLinter(dir) {
28
+ const eslint = [
29
+ '.eslintrc',
30
+ '.eslintrc.json',
31
+ '.eslintrc.js',
32
+ '.eslintrc.cjs',
33
+ 'eslint.config.js',
34
+ 'eslint.config.mjs',
35
+ ];
36
+ for (const f of eslint) {
37
+ if (await pathExists(join(dir, f)))
38
+ return 'ESLint';
39
+ }
40
+ if (await pathExists(join(dir, 'biome.json')))
41
+ return 'Biome';
42
+ if (await pathExists(join(dir, 'ruff.toml')))
43
+ return 'Ruff';
44
+ if (await pathExists(join(dir, '.golangci.yml')))
45
+ return 'golangci-lint';
46
+ return null;
47
+ }
48
+ async function detectFormatter(dir) {
49
+ const prettier = ['.prettierrc', '.prettierrc.json', '.prettierrc.js', 'prettier.config.js'];
50
+ for (const f of prettier) {
51
+ if (await pathExists(join(dir, f)))
52
+ return 'Prettier';
53
+ }
54
+ if (await pathExists(join(dir, 'biome.json')))
55
+ return 'Biome';
56
+ const pkg = await readJson(join(dir, 'package.json'));
57
+ if (pkg?.prettier)
58
+ return 'Prettier';
59
+ if (pkg?.devDependencies?.['prettier'])
60
+ return 'Prettier';
61
+ return null;
62
+ }
63
+ async function detectCommitConvention(dir) {
64
+ const markers = ['commitlint.config.js', '.commitlintrc', '.commitlintrc.json', '.czrc'];
65
+ for (const f of markers) {
66
+ if (await pathExists(join(dir, f)))
67
+ return 'Conventional Commits';
68
+ }
69
+ return null;
70
+ }
71
+ //# sourceMappingURL=code-patterns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-patterns.js","sourceRoot":"","sources":["../../src/analyzer/code-patterns.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { ProjectCommands } from '../types.js';
2
+ export declare function detectCommands(projectDir: string): Promise<ProjectCommands>;
@@ -0,0 +1,86 @@
1
+ import { join } from 'node:path';
2
+ import { pathExists, readJson, detectPackageManager } from '../utils.js';
3
+ const EMPTY = {
4
+ install: null,
5
+ dev: null,
6
+ build: null,
7
+ test: null,
8
+ lint: null,
9
+ format: null,
10
+ extra: {},
11
+ };
12
+ const KNOWN_SCRIPTS = new Set([
13
+ 'dev',
14
+ 'start',
15
+ 'build',
16
+ 'test',
17
+ 'lint',
18
+ 'format',
19
+ 'fmt',
20
+ 'prepare',
21
+ 'postinstall',
22
+ 'prepublishonly',
23
+ ]);
24
+ export async function detectCommands(projectDir) {
25
+ if (await pathExists(join(projectDir, 'package.json'))) {
26
+ return fromPackageJson(projectDir);
27
+ }
28
+ if (await pathExists(join(projectDir, 'Cargo.toml'))) {
29
+ return {
30
+ install: null,
31
+ dev: 'cargo run',
32
+ build: 'cargo build --release',
33
+ test: 'cargo test',
34
+ lint: 'cargo clippy',
35
+ format: 'cargo fmt',
36
+ extra: {},
37
+ };
38
+ }
39
+ if (await pathExists(join(projectDir, 'pyproject.toml'))) {
40
+ const hasUv = await pathExists(join(projectDir, 'uv.lock'));
41
+ return {
42
+ install: hasUv ? 'uv sync' : 'pip install -e ".[dev]"',
43
+ dev: null,
44
+ build: null,
45
+ test: 'pytest',
46
+ lint: 'ruff check .',
47
+ format: 'ruff format .',
48
+ extra: {},
49
+ };
50
+ }
51
+ if (await pathExists(join(projectDir, 'go.mod'))) {
52
+ return {
53
+ install: 'go mod download',
54
+ dev: 'go run .',
55
+ build: 'go build ./...',
56
+ test: 'go test ./...',
57
+ lint: 'golangci-lint run',
58
+ format: 'go fmt ./...',
59
+ extra: {},
60
+ };
61
+ }
62
+ return { ...EMPTY };
63
+ }
64
+ async function fromPackageJson(dir) {
65
+ const pkg = await readJson(join(dir, 'package.json'));
66
+ const scripts = pkg?.scripts ?? {};
67
+ const pm = await detectPackageManager(dir);
68
+ const run = (script) => `${pm} run ${script}`;
69
+ const has = (script) => typeof scripts[script] === 'string';
70
+ const formatScript = has('format') ? 'format' : has('fmt') ? 'fmt' : null;
71
+ const extra = {};
72
+ for (const key of Object.keys(scripts)) {
73
+ if (!KNOWN_SCRIPTS.has(key.toLowerCase()))
74
+ extra[key] = run(key);
75
+ }
76
+ return {
77
+ install: pm === 'npm' ? 'npm install' : `${pm} install`,
78
+ dev: has('dev') ? run('dev') : has('start') ? run('start') : null,
79
+ build: has('build') ? run('build') : null,
80
+ test: has('test') ? run('test') : null,
81
+ lint: has('lint') ? run('lint') : null,
82
+ format: formatScript ? run(formatScript) : null,
83
+ extra,
84
+ };
85
+ }
86
+ //# sourceMappingURL=commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.js","sourceRoot":"","sources":["../../src/analyzer/commands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { EnvVar } from '../types.js';
2
+ export declare function detectEnvVars(projectDir: string): Promise<EnvVar[]>;
3
+ export declare function parseEnvFile(content: string): EnvVar[];
@@ -0,0 +1,42 @@
1
+ import { join } from 'node:path';
2
+ import { readText } from '../utils.js';
3
+ const CANDIDATES = ['.env.example', '.env.sample', '.env.template', '.env.local.example'];
4
+ export async function detectEnvVars(projectDir) {
5
+ for (const candidate of CANDIDATES) {
6
+ const content = await readText(join(projectDir, candidate));
7
+ if (content !== null)
8
+ return parseEnvFile(content);
9
+ }
10
+ return [];
11
+ }
12
+ export function parseEnvFile(content) {
13
+ const vars = [];
14
+ let pendingComment = '';
15
+ for (const rawLine of content.split('\n')) {
16
+ const line = rawLine.trim();
17
+ if (!line) {
18
+ pendingComment = '';
19
+ continue;
20
+ }
21
+ if (line.startsWith('#')) {
22
+ pendingComment = line.replace(/^#+\s*/, '');
23
+ continue;
24
+ }
25
+ const eqIdx = line.indexOf('=');
26
+ if (eqIdx === -1)
27
+ continue;
28
+ const name = line.slice(0, eqIdx).trim().replace(/^export\s+/, '');
29
+ if (!name)
30
+ continue;
31
+ const value = line.slice(eqIdx + 1).trim().replace(/^["']|["']$/g, '');
32
+ vars.push({
33
+ name,
34
+ example: value || null,
35
+ required: value === '',
36
+ description: pendingComment,
37
+ });
38
+ pendingComment = '';
39
+ }
40
+ return vars;
41
+ }
42
+ //# sourceMappingURL=env-vars.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-vars.js","sourceRoot":"","sources":["../../src/analyzer/env-vars.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGvC,MAAM,UAAU,GAAG,CAAC,cAAc,EAAE,aAAa,EAAE,eAAe,EAAE,oBAAoB,CAAC,CAAC;AAE1F,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,UAAkB;IACpD,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC;QAC5D,IAAI,OAAO,KAAK,IAAI;YAAE,OAAO,YAAY,CAAC,OAAO,CAAC,CAAC;IACrD,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,IAAI,cAAc,GAAG,EAAE,CAAC;IAExB,KAAK,MAAM,OAAO,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;QAE5B,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,cAAc,GAAG,EAAE,CAAC;YACpB,SAAS;QACX,CAAC;QACD,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACzB,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;YAC5C,SAAS;QACX,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAChC,IAAI,KAAK,KAAK,CAAC,CAAC;YAAE,SAAS;QAE3B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;QACnE,IAAI,CAAC,IAAI;YAAE,SAAS;QACpB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;QAEvE,IAAI,CAAC,IAAI,CAAC;YACR,IAAI;YACJ,OAAO,EAAE,KAAK,IAAI,IAAI;YACtB,QAAQ,EAAE,KAAK,KAAK,EAAE;YACtB,WAAW,EAAE,cAAc;SAC5B,CAAC,CAAC;QACH,cAAc,GAAG,EAAE,CAAC;IACtB,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { GitInfo } from '../types.js';
2
+ export declare function analyzeGit(projectDir: string): Promise<GitInfo>;
@@ -0,0 +1,41 @@
1
+ import { simpleGit } from 'simple-git';
2
+ const NONE = {
3
+ hasGit: false,
4
+ remoteName: null,
5
+ defaultBranch: null,
6
+ topAuthors: [],
7
+ hotFiles: [],
8
+ };
9
+ export async function analyzeGit(projectDir) {
10
+ const git = simpleGit(projectDir);
11
+ const isRepo = await git.checkIsRepo().catch(() => false);
12
+ if (!isRepo)
13
+ return { ...NONE };
14
+ const [remotes, branch, authorLog, fileLog] = await Promise.all([
15
+ git.getRemotes(true).catch(() => []),
16
+ git.revparse(['--abbrev-ref', 'HEAD']).catch(() => 'main'),
17
+ git.raw(['log', '--format=%an', '--no-merges', '-200']).catch(() => ''),
18
+ git.raw(['log', '--name-only', '--format=', '--no-merges', '-500']).catch(() => ''),
19
+ ]);
20
+ return {
21
+ hasGit: true,
22
+ remoteName: remotes[0]?.refs?.fetch ?? remotes[0]?.name ?? null,
23
+ defaultBranch: branch.trim() || 'main',
24
+ topAuthors: topCounts(authorLog, 3),
25
+ hotFiles: topCounts(fileLog, 5),
26
+ };
27
+ }
28
+ function topCounts(log, limit) {
29
+ const counts = {};
30
+ for (const line of log.split('\n')) {
31
+ const key = line.trim();
32
+ if (!key)
33
+ continue;
34
+ counts[key] = (counts[key] ?? 0) + 1;
35
+ }
36
+ return Object.entries(counts)
37
+ .sort(([, a], [, b]) => b - a)
38
+ .slice(0, limit)
39
+ .map(([k]) => k);
40
+ }
41
+ //# sourceMappingURL=git-history.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-history.js","sourceRoot":"","sources":["../../src/analyzer/git-history.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGvC,MAAM,IAAI,GAAY;IACpB,MAAM,EAAE,KAAK;IACb,UAAU,EAAE,IAAI;IAChB,aAAa,EAAE,IAAI;IACnB,UAAU,EAAE,EAAE;IACd,QAAQ,EAAE,EAAE;CACb,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,UAAkB;IACjD,MAAM,GAAG,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC;IAElC,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC;IAC1D,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,GAAG,IAAI,EAAE,CAAC;IAEhC,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC9D,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC;QACpC,GAAG,CAAC,QAAQ,CAAC,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC;QAC1D,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC;QACvE,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC;KACpF,CAAC,CAAC;IAEH,OAAO;QACL,MAAM,EAAE,IAAI;QACZ,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,IAAI;QAC/D,aAAa,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI,MAAM;QACtC,UAAU,EAAE,SAAS,CAAC,SAAS,EAAE,CAAC,CAAC;QACnC,QAAQ,EAAE,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC;KAChC,CAAC;AACJ,CAAC;AAED,SAAS,SAAS,CAAC,GAAW,EAAE,KAAa;IAC3C,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QACxB,IAAI,CAAC,GAAG;YAAE,SAAS;QACnB,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;IACvC,CAAC;IACD,OAAO,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;SAC1B,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;SAC7B,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC;SACf,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;AACrB,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { ProjectAnalysis } from '../types.js';
2
+ export declare function analyzeProject(projectDir: string): Promise<ProjectAnalysis>;
3
+ export type { ProjectAnalysis } from '../types.js';
@@ -0,0 +1,44 @@
1
+ import { basename, join } from 'node:path';
2
+ import { readJson } from '../utils.js';
3
+ import { detectTechStack } from './tech-stack.js';
4
+ import { analyzeGit } from './git-history.js';
5
+ import { analyzeStructure } from './project-structure.js';
6
+ import { detectCommands } from './commands.js';
7
+ import { detectEnvVars } from './env-vars.js';
8
+ import { detectCodePatterns } from './code-patterns.js';
9
+ import { TARGETS } from '../generators/registry.js';
10
+ /**
11
+ * Top-level path segments of every file we generate. Excluded from the structure
12
+ * tree so that running `generate` does not make a later `check` report drift.
13
+ */
14
+ const GENERATED_SEGMENTS = [
15
+ ...new Set(TARGETS.flatMap((t) => t.files.map((f) => f.path.split(/[\\/]/)[0]))),
16
+ ];
17
+ export async function analyzeProject(projectDir) {
18
+ const [techStack, gitInfo, structure, commands, envVars, codePatterns, pkg] = await Promise.all([
19
+ detectTechStack(projectDir),
20
+ analyzeGit(projectDir),
21
+ analyzeStructure(projectDir, GENERATED_SEGMENTS),
22
+ detectCommands(projectDir),
23
+ detectEnvVars(projectDir),
24
+ detectCodePatterns(projectDir),
25
+ readJson(join(projectDir, 'package.json')),
26
+ ]);
27
+ return {
28
+ name: pkg?.name || basename(projectDir) || 'project',
29
+ description: pkg?.description ?? '',
30
+ techStack,
31
+ structure,
32
+ commands,
33
+ tests: {
34
+ framework: techStack.testing,
35
+ command: commands.test,
36
+ coverage: Boolean(pkg?.scripts && ('coverage' in pkg.scripts || 'test:coverage' in pkg.scripts)),
37
+ testDir: structure.testDir,
38
+ },
39
+ envVars,
40
+ codePatterns,
41
+ gitInfo,
42
+ };
43
+ }
44
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/analyzer/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAGpD;;;GAGG;AACH,MAAM,kBAAkB,GAAa;IACnC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC;CAClF,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,UAAkB;IACrD,MAAM,CAAC,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC9F,eAAe,CAAC,UAAU,CAAC;QAC3B,UAAU,CAAC,UAAU,CAAC;QACtB,gBAAgB,CAAC,UAAU,EAAE,kBAAkB,CAAC;QAChD,cAAc,CAAC,UAAU,CAAC;QAC1B,aAAa,CAAC,UAAU,CAAC;QACzB,kBAAkB,CAAC,UAAU,CAAC;QAC9B,QAAQ,CACN,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,CACjC;KACF,CAAC,CAAC;IAEH,OAAO;QACL,IAAI,EAAE,GAAG,EAAE,IAAI,IAAI,QAAQ,CAAC,UAAU,CAAC,IAAI,SAAS;QACpD,WAAW,EAAE,GAAG,EAAE,WAAW,IAAI,EAAE;QACnC,SAAS;QACT,SAAS;QACT,QAAQ;QACR,KAAK,EAAE;YACL,SAAS,EAAE,SAAS,CAAC,OAAO;YAC5B,OAAO,EAAE,QAAQ,CAAC,IAAI;YACtB,QAAQ,EAAE,OAAO,CAAC,GAAG,EAAE,OAAO,IAAI,CAAC,UAAU,IAAI,GAAG,CAAC,OAAO,IAAI,eAAe,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;YAChG,OAAO,EAAE,SAAS,CAAC,OAAO;SAC3B;QACD,OAAO;QACP,YAAY;QACZ,OAAO;KACR,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { ProjectStructure } from '../types.js';
2
+ export declare function analyzeStructure(projectDir: string, extraIgnore?: Iterable<string>): Promise<ProjectStructure>;