agents-reverse-engineer 0.2.11 → 0.3.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.
- package/README.md +4 -2
- package/dist/cli/index.js +0 -0
- package/dist/cli/update.d.ts.map +1 -1
- package/dist/cli/update.js +8 -10
- package/dist/cli/update.js.map +1 -1
- package/dist/config/defaults.d.ts +4 -4
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +15 -0
- package/dist/config/defaults.js.map +1 -1
- package/dist/discovery/filters/vendor.d.ts +7 -4
- package/dist/discovery/filters/vendor.d.ts.map +1 -1
- package/dist/discovery/filters/vendor.js +28 -8
- package/dist/discovery/filters/vendor.js.map +1 -1
- package/dist/generation/writers/agents-md.d.ts +7 -1
- package/dist/generation/writers/agents-md.d.ts.map +1 -1
- package/dist/generation/writers/agents-md.js +59 -4
- package/dist/generation/writers/agents-md.js.map +1 -1
- package/dist/generation/writers/claude-md.d.ts +6 -2
- package/dist/generation/writers/claude-md.d.ts.map +1 -1
- package/dist/generation/writers/claude-md.js +74 -11
- package/dist/generation/writers/claude-md.js.map +1 -1
- package/dist/generation/writers/gemini-md.d.ts +17 -0
- package/dist/generation/writers/gemini-md.d.ts.map +1 -0
- package/dist/generation/writers/gemini-md.js +96 -0
- package/dist/generation/writers/gemini-md.js.map +1 -0
- package/dist/generation/writers/index.d.ts +2 -0
- package/dist/generation/writers/index.d.ts.map +1 -1
- package/dist/generation/writers/index.js +2 -0
- package/dist/generation/writers/index.js.map +1 -1
- package/dist/generation/writers/opencode-md.d.ts +17 -0
- package/dist/generation/writers/opencode-md.d.ts.map +1 -0
- package/dist/generation/writers/opencode-md.js +96 -0
- package/dist/generation/writers/opencode-md.js.map +1 -0
- package/dist/generation/writers/sum.d.ts +3 -1
- package/dist/generation/writers/sum.d.ts.map +1 -1
- package/dist/generation/writers/sum.js +74 -14
- package/dist/generation/writers/sum.js.map +1 -1
- package/dist/generation/writers/supplementary.d.ts +8 -2
- package/dist/generation/writers/supplementary.d.ts.map +1 -1
- package/dist/generation/writers/supplementary.js +80 -7
- package/dist/generation/writers/supplementary.js.map +1 -1
- package/dist/installer/paths.d.ts +26 -0
- package/dist/installer/paths.d.ts.map +1 -1
- package/dist/installer/paths.js +55 -0
- package/dist/installer/paths.js.map +1 -1
- package/dist/integration/templates.d.ts.map +1 -1
- package/dist/integration/templates.js +25 -17
- package/dist/integration/templates.js.map +1 -1
- package/dist/update/orchestrator.d.ts +27 -32
- package/dist/update/orchestrator.d.ts.map +1 -1
- package/dist/update/orchestrator.js +97 -120
- package/dist/update/orchestrator.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Write GEMINI.md at the project root.
|
|
3
|
+
*
|
|
4
|
+
* Only writes if Gemini CLI is installed locally (`.gemini` directory exists).
|
|
5
|
+
* If a user-defined GEMINI.md exists (not generated by us), it will be
|
|
6
|
+
* preserved as GEMINI.local.md and referenced in the generated file.
|
|
7
|
+
*
|
|
8
|
+
* @param projectRoot - Project root directory
|
|
9
|
+
* @returns Path to written GEMINI.md, or null if Gemini CLI is not installed
|
|
10
|
+
*/
|
|
11
|
+
export declare function writeGeminiMd(projectRoot: string): Promise<string | null>;
|
|
12
|
+
/**
|
|
13
|
+
* Get the content that would be written to GEMINI.md.
|
|
14
|
+
* Useful for previewing without writing.
|
|
15
|
+
*/
|
|
16
|
+
export declare function getGeminiMdContent(): string;
|
|
17
|
+
//# sourceMappingURL=gemini-md.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gemini-md.d.ts","sourceRoot":"","sources":["../../../src/generation/writers/gemini-md.ts"],"names":[],"mappings":"AA4DA;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA4B/E;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { writeFile, readFile, stat, rename } from 'node:fs/promises';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import { isRuntimeInstalledLocally } from '../../installer/paths.js';
|
|
4
|
+
/** Marker comment to identify generated GEMINI.md files */
|
|
5
|
+
const GENERATED_MARKER = '<!-- Generated by agents-reverse-engineer -->';
|
|
6
|
+
/**
|
|
7
|
+
* Standard GEMINI.md content - simple pointer to AGENTS.md.
|
|
8
|
+
*
|
|
9
|
+
* For Google Gemini CLI compatibility.
|
|
10
|
+
*/
|
|
11
|
+
function buildGeminiMdContent(hasLocalFile) {
|
|
12
|
+
const sections = [];
|
|
13
|
+
// Generated marker (first line)
|
|
14
|
+
sections.push(GENERATED_MARKER);
|
|
15
|
+
sections.push('');
|
|
16
|
+
// Reference to user-defined local file if it exists
|
|
17
|
+
if (hasLocalFile) {
|
|
18
|
+
sections.push('> **Note:** This project has additional documentation in [GEMINI.local.md](./GEMINI.local.md)');
|
|
19
|
+
sections.push('');
|
|
20
|
+
}
|
|
21
|
+
sections.push('# GEMINI.md');
|
|
22
|
+
sections.push('');
|
|
23
|
+
sections.push('See [AGENTS.md](./AGENTS.md) for codebase documentation.');
|
|
24
|
+
sections.push('');
|
|
25
|
+
sections.push('This file exists for Google Gemini CLI compatibility. The actual documentation');
|
|
26
|
+
sections.push('is maintained in AGENTS.md files throughout the codebase.');
|
|
27
|
+
sections.push('');
|
|
28
|
+
return sections.join('\n');
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Check if a file was generated by us (contains marker).
|
|
32
|
+
*/
|
|
33
|
+
async function isGeneratedFile(filePath) {
|
|
34
|
+
try {
|
|
35
|
+
const content = await readFile(filePath, 'utf-8');
|
|
36
|
+
return content.includes(GENERATED_MARKER);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Check if a local file exists.
|
|
44
|
+
*/
|
|
45
|
+
async function hasLocalFile(localPath) {
|
|
46
|
+
try {
|
|
47
|
+
await stat(localPath);
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Write GEMINI.md at the project root.
|
|
56
|
+
*
|
|
57
|
+
* Only writes if Gemini CLI is installed locally (`.gemini` directory exists).
|
|
58
|
+
* If a user-defined GEMINI.md exists (not generated by us), it will be
|
|
59
|
+
* preserved as GEMINI.local.md and referenced in the generated file.
|
|
60
|
+
*
|
|
61
|
+
* @param projectRoot - Project root directory
|
|
62
|
+
* @returns Path to written GEMINI.md, or null if Gemini CLI is not installed
|
|
63
|
+
*/
|
|
64
|
+
export async function writeGeminiMd(projectRoot) {
|
|
65
|
+
// Only generate if Gemini CLI is installed locally
|
|
66
|
+
const isInstalled = await isRuntimeInstalledLocally('gemini', projectRoot);
|
|
67
|
+
if (!isInstalled) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
const geminiPath = path.join(projectRoot, 'GEMINI.md');
|
|
71
|
+
const localPath = path.join(projectRoot, 'GEMINI.local.md');
|
|
72
|
+
// Check if existing GEMINI.md is user-defined (not generated by us)
|
|
73
|
+
let hasLocal = await hasLocalFile(localPath);
|
|
74
|
+
try {
|
|
75
|
+
const existingIsGenerated = await isGeneratedFile(geminiPath);
|
|
76
|
+
if (!existingIsGenerated) {
|
|
77
|
+
// User-defined GEMINI.md exists - preserve it
|
|
78
|
+
await rename(geminiPath, localPath);
|
|
79
|
+
hasLocal = true;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
// No existing GEMINI.md - that's fine
|
|
84
|
+
}
|
|
85
|
+
const content = buildGeminiMdContent(hasLocal);
|
|
86
|
+
await writeFile(geminiPath, content, 'utf-8');
|
|
87
|
+
return geminiPath;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Get the content that would be written to GEMINI.md.
|
|
91
|
+
* Useful for previewing without writing.
|
|
92
|
+
*/
|
|
93
|
+
export function getGeminiMdContent() {
|
|
94
|
+
return buildGeminiMdContent(false);
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=gemini-md.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gemini-md.js","sourceRoot":"","sources":["../../../src/generation/writers/gemini-md.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { writeSumFile, readSumFile, getSumPath, sumFileExists, type SumFileContent, } from './sum.js';
|
|
2
2
|
export { writeAgentsMd, buildAgentsMd, buildDirectoryDoc, type DirectoryDoc, type FileGroup, type FileRef, type SubdirSummary, } from './agents-md.js';
|
|
3
3
|
export { writeClaudeMd, getClaudeMdContent, } from './claude-md.js';
|
|
4
|
+
export { writeGeminiMd, getGeminiMdContent, } from './gemini-md.js';
|
|
5
|
+
export { writeOpencodeMd, getOpencodeMdContent, } from './opencode-md.js';
|
|
4
6
|
export { writeArchitectureMd, writeStackMd, buildArchitectureMd, buildStackMd, analyzePackageJson, type SupplementaryConfig, type StackInfo, } from './supplementary.js';
|
|
5
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/generation/writers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,WAAW,EACX,UAAU,EACV,aAAa,EACb,KAAK,cAAc,GACpB,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,KAAK,OAAO,EACZ,KAAK,aAAa,GACnB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,aAAa,EACb,kBAAkB,GACnB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,mBAAmB,EACnB,YAAY,EACZ,kBAAkB,EAClB,KAAK,mBAAmB,EACxB,KAAK,SAAS,GACf,MAAM,oBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/generation/writers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,WAAW,EACX,UAAU,EACV,aAAa,EACb,KAAK,cAAc,GACpB,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,KAAK,OAAO,EACZ,KAAK,aAAa,GACnB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,aAAa,EACb,kBAAkB,GACnB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,aAAa,EACb,kBAAkB,GACnB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,eAAe,EACf,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,mBAAmB,EACnB,YAAY,EACZ,kBAAkB,EAClB,KAAK,mBAAmB,EACxB,KAAK,SAAS,GACf,MAAM,oBAAoB,CAAC"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { writeSumFile, readSumFile, getSumPath, sumFileExists, } from './sum.js';
|
|
2
2
|
export { writeAgentsMd, buildAgentsMd, buildDirectoryDoc, } from './agents-md.js';
|
|
3
3
|
export { writeClaudeMd, getClaudeMdContent, } from './claude-md.js';
|
|
4
|
+
export { writeGeminiMd, getGeminiMdContent, } from './gemini-md.js';
|
|
5
|
+
export { writeOpencodeMd, getOpencodeMdContent, } from './opencode-md.js';
|
|
4
6
|
export { writeArchitectureMd, writeStackMd, buildArchitectureMd, buildStackMd, analyzePackageJson, } from './supplementary.js';
|
|
5
7
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/generation/writers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,WAAW,EACX,UAAU,EACV,aAAa,GAEd,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,aAAa,EACb,aAAa,EACb,iBAAiB,GAKlB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,aAAa,EACb,kBAAkB,GACnB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,mBAAmB,EACnB,YAAY,EACZ,kBAAkB,GAGnB,MAAM,oBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/generation/writers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,WAAW,EACX,UAAU,EACV,aAAa,GAEd,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,aAAa,EACb,aAAa,EACb,iBAAiB,GAKlB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,aAAa,EACb,kBAAkB,GACnB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,aAAa,EACb,kBAAkB,GACnB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,eAAe,EACf,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,mBAAmB,EACnB,YAAY,EACZ,kBAAkB,GAGnB,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Write OPENCODE.md at the project root.
|
|
3
|
+
*
|
|
4
|
+
* Only writes if OpenCode is installed locally (`.opencode` directory exists).
|
|
5
|
+
* If a user-defined OPENCODE.md exists (not generated by us), it will be
|
|
6
|
+
* preserved as OPENCODE.local.md and referenced in the generated file.
|
|
7
|
+
*
|
|
8
|
+
* @param projectRoot - Project root directory
|
|
9
|
+
* @returns Path to written OPENCODE.md, or null if OpenCode is not installed
|
|
10
|
+
*/
|
|
11
|
+
export declare function writeOpencodeMd(projectRoot: string): Promise<string | null>;
|
|
12
|
+
/**
|
|
13
|
+
* Get the content that would be written to OPENCODE.md.
|
|
14
|
+
* Useful for previewing without writing.
|
|
15
|
+
*/
|
|
16
|
+
export declare function getOpencodeMdContent(): string;
|
|
17
|
+
//# sourceMappingURL=opencode-md.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opencode-md.d.ts","sourceRoot":"","sources":["../../../src/generation/writers/opencode-md.ts"],"names":[],"mappings":"AA4DA;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA4BjF;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { writeFile, readFile, stat, rename } from 'node:fs/promises';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import { isRuntimeInstalledLocally } from '../../installer/paths.js';
|
|
4
|
+
/** Marker comment to identify generated OPENCODE.md files */
|
|
5
|
+
const GENERATED_MARKER = '<!-- Generated by agents-reverse-engineer -->';
|
|
6
|
+
/**
|
|
7
|
+
* Standard OPENCODE.md content - simple pointer to AGENTS.md.
|
|
8
|
+
*
|
|
9
|
+
* For OpenCode compatibility.
|
|
10
|
+
*/
|
|
11
|
+
function buildOpencodeMdContent(hasLocalFile) {
|
|
12
|
+
const sections = [];
|
|
13
|
+
// Generated marker (first line)
|
|
14
|
+
sections.push(GENERATED_MARKER);
|
|
15
|
+
sections.push('');
|
|
16
|
+
// Reference to user-defined local file if it exists
|
|
17
|
+
if (hasLocalFile) {
|
|
18
|
+
sections.push('> **Note:** This project has additional documentation in [OPENCODE.local.md](./OPENCODE.local.md)');
|
|
19
|
+
sections.push('');
|
|
20
|
+
}
|
|
21
|
+
sections.push('# OPENCODE.md');
|
|
22
|
+
sections.push('');
|
|
23
|
+
sections.push('See [AGENTS.md](./AGENTS.md) for codebase documentation.');
|
|
24
|
+
sections.push('');
|
|
25
|
+
sections.push('This file exists for OpenCode compatibility. The actual documentation');
|
|
26
|
+
sections.push('is maintained in AGENTS.md files throughout the codebase.');
|
|
27
|
+
sections.push('');
|
|
28
|
+
return sections.join('\n');
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Check if a file was generated by us (contains marker).
|
|
32
|
+
*/
|
|
33
|
+
async function isGeneratedFile(filePath) {
|
|
34
|
+
try {
|
|
35
|
+
const content = await readFile(filePath, 'utf-8');
|
|
36
|
+
return content.includes(GENERATED_MARKER);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Check if a local file exists.
|
|
44
|
+
*/
|
|
45
|
+
async function hasLocalFile(localPath) {
|
|
46
|
+
try {
|
|
47
|
+
await stat(localPath);
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Write OPENCODE.md at the project root.
|
|
56
|
+
*
|
|
57
|
+
* Only writes if OpenCode is installed locally (`.opencode` directory exists).
|
|
58
|
+
* If a user-defined OPENCODE.md exists (not generated by us), it will be
|
|
59
|
+
* preserved as OPENCODE.local.md and referenced in the generated file.
|
|
60
|
+
*
|
|
61
|
+
* @param projectRoot - Project root directory
|
|
62
|
+
* @returns Path to written OPENCODE.md, or null if OpenCode is not installed
|
|
63
|
+
*/
|
|
64
|
+
export async function writeOpencodeMd(projectRoot) {
|
|
65
|
+
// Only generate if OpenCode is installed locally
|
|
66
|
+
const isInstalled = await isRuntimeInstalledLocally('opencode', projectRoot);
|
|
67
|
+
if (!isInstalled) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
const opencodePath = path.join(projectRoot, 'OPENCODE.md');
|
|
71
|
+
const localPath = path.join(projectRoot, 'OPENCODE.local.md');
|
|
72
|
+
// Check if existing OPENCODE.md is user-defined (not generated by us)
|
|
73
|
+
let hasLocal = await hasLocalFile(localPath);
|
|
74
|
+
try {
|
|
75
|
+
const existingIsGenerated = await isGeneratedFile(opencodePath);
|
|
76
|
+
if (!existingIsGenerated) {
|
|
77
|
+
// User-defined OPENCODE.md exists - preserve it
|
|
78
|
+
await rename(opencodePath, localPath);
|
|
79
|
+
hasLocal = true;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
// No existing OPENCODE.md - that's fine
|
|
84
|
+
}
|
|
85
|
+
const content = buildOpencodeMdContent(hasLocal);
|
|
86
|
+
await writeFile(opencodePath, content, 'utf-8');
|
|
87
|
+
return opencodePath;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Get the content that would be written to OPENCODE.md.
|
|
91
|
+
* Useful for previewing without writing.
|
|
92
|
+
*/
|
|
93
|
+
export function getOpencodeMdContent() {
|
|
94
|
+
return buildOpencodeMdContent(false);
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=opencode-md.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opencode-md.js","sourceRoot":"","sources":["../../../src/generation/writers/opencode-md.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@ import type { SummaryMetadata } from '../types.js';
|
|
|
3
3
|
* Content structure for a .sum file.
|
|
4
4
|
*/
|
|
5
5
|
export interface SumFileContent {
|
|
6
|
-
/** Main summary text */
|
|
6
|
+
/** Main summary text (detailed description) */
|
|
7
7
|
summary: string;
|
|
8
8
|
/** Extracted metadata */
|
|
9
9
|
metadata: SummaryMetadata;
|
|
@@ -11,6 +11,8 @@ export interface SumFileContent {
|
|
|
11
11
|
fileType: string;
|
|
12
12
|
/** Generation timestamp */
|
|
13
13
|
generatedAt: string;
|
|
14
|
+
/** SHA-256 hash of source file content (for change detection) */
|
|
15
|
+
contentHash: string;
|
|
14
16
|
}
|
|
15
17
|
/**
|
|
16
18
|
* Parse a .sum file back into structured content.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sum.d.ts","sourceRoot":"","sources":["../../../src/generation/writers/sum.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B
|
|
1
|
+
{"version":3,"file":"sum.d.ts","sourceRoot":"","sources":["../../../src/generation/writers/sum.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,+CAA+C;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,yBAAyB;IACzB,QAAQ,EAAE,eAAe,CAAC;IAC1B,kCAAkC;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,2BAA2B;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,iEAAiE;IACjE,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAOjF;AA8HD;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAChC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,MAAM,CAAC,CAYjB;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAErD;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAIxE"}
|
|
@@ -13,6 +13,32 @@ export async function readSumFile(sumPath) {
|
|
|
13
13
|
return null;
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* Parse a YAML-style array from frontmatter.
|
|
18
|
+
* Supports both inline [a, b, c] and multi-line formats.
|
|
19
|
+
*/
|
|
20
|
+
function parseYamlArray(frontmatter, key) {
|
|
21
|
+
// Try inline format first: key: [a, b, c]
|
|
22
|
+
const inlineMatch = frontmatter.match(new RegExp(`${key}:\\s*\\[([^\\]]*)\\]`));
|
|
23
|
+
if (inlineMatch) {
|
|
24
|
+
return inlineMatch[1]
|
|
25
|
+
.split(',')
|
|
26
|
+
.map(s => s.trim().replace(/^["']|["']$/g, ''))
|
|
27
|
+
.filter(s => s.length > 0);
|
|
28
|
+
}
|
|
29
|
+
// Try multi-line format:
|
|
30
|
+
// key:
|
|
31
|
+
// - item1
|
|
32
|
+
// - item2
|
|
33
|
+
const multiLineMatch = frontmatter.match(new RegExp(`${key}:\\s*\\n((?:\\s+-\\s+.+\\n?)+)`, 'm'));
|
|
34
|
+
if (multiLineMatch) {
|
|
35
|
+
return multiLineMatch[1]
|
|
36
|
+
.split('\n')
|
|
37
|
+
.map(line => line.replace(/^\s*-\s*/, '').trim())
|
|
38
|
+
.filter(s => s.length > 0);
|
|
39
|
+
}
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
16
42
|
/**
|
|
17
43
|
* Parse .sum file content into structured data.
|
|
18
44
|
*/
|
|
@@ -27,41 +53,75 @@ function parseSumFile(content) {
|
|
|
27
53
|
// Parse frontmatter (simple YAML-like parsing)
|
|
28
54
|
const fileType = frontmatter.match(/file_type:\s*(.+)/)?.[1]?.trim() ?? 'generic';
|
|
29
55
|
const generatedAt = frontmatter.match(/generated_at:\s*(.+)/)?.[1]?.trim() ?? '';
|
|
30
|
-
|
|
56
|
+
const contentHash = frontmatter.match(/content_hash:\s*(.+)/)?.[1]?.trim() ?? '';
|
|
57
|
+
// Parse purpose (single line value)
|
|
58
|
+
const purpose = frontmatter.match(/purpose:\s*(.+)/)?.[1]?.trim() ?? '';
|
|
59
|
+
// Parse metadata arrays
|
|
31
60
|
const metadata = {
|
|
32
|
-
purpose
|
|
33
|
-
publicInterface:
|
|
34
|
-
dependencies:
|
|
35
|
-
patterns:
|
|
61
|
+
purpose,
|
|
62
|
+
publicInterface: parseYamlArray(frontmatter, 'public_interface'),
|
|
63
|
+
dependencies: parseYamlArray(frontmatter, 'dependencies'),
|
|
64
|
+
patterns: parseYamlArray(frontmatter, 'patterns'),
|
|
36
65
|
};
|
|
37
|
-
//
|
|
38
|
-
const
|
|
39
|
-
if (
|
|
40
|
-
metadata.
|
|
66
|
+
// Parse optional fields
|
|
67
|
+
const criticalTodos = parseYamlArray(frontmatter, 'critical_todos');
|
|
68
|
+
if (criticalTodos.length > 0) {
|
|
69
|
+
metadata.criticalTodos = criticalTodos;
|
|
70
|
+
}
|
|
71
|
+
const relatedFiles = parseYamlArray(frontmatter, 'related_files');
|
|
72
|
+
if (relatedFiles.length > 0) {
|
|
73
|
+
metadata.relatedFiles = relatedFiles;
|
|
41
74
|
}
|
|
42
75
|
return {
|
|
43
76
|
summary,
|
|
44
77
|
metadata,
|
|
45
78
|
fileType,
|
|
46
79
|
generatedAt,
|
|
80
|
+
contentHash,
|
|
47
81
|
};
|
|
48
82
|
}
|
|
49
83
|
catch {
|
|
50
84
|
return null;
|
|
51
85
|
}
|
|
52
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* Format a YAML array for frontmatter.
|
|
89
|
+
* Uses inline format for short arrays, multi-line for longer ones.
|
|
90
|
+
*/
|
|
91
|
+
function formatYamlArray(key, values) {
|
|
92
|
+
if (values.length === 0) {
|
|
93
|
+
return `${key}: []`;
|
|
94
|
+
}
|
|
95
|
+
if (values.length <= 3 && values.every(v => v.length < 40)) {
|
|
96
|
+
// Inline format for short arrays
|
|
97
|
+
return `${key}: [${values.join(', ')}]`;
|
|
98
|
+
}
|
|
99
|
+
// Multi-line format for longer arrays
|
|
100
|
+
return `${key}:\n${values.map(v => ` - ${v}`).join('\n')}`;
|
|
101
|
+
}
|
|
53
102
|
/**
|
|
54
103
|
* Format .sum file content for writing.
|
|
55
104
|
*/
|
|
56
105
|
function formatSumFile(content) {
|
|
57
|
-
const
|
|
106
|
+
const lines = [
|
|
58
107
|
'---',
|
|
59
108
|
`file_type: ${content.fileType}`,
|
|
60
109
|
`generated_at: ${content.generatedAt}`,
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
110
|
+
`content_hash: ${content.contentHash}`,
|
|
111
|
+
`purpose: ${content.metadata.purpose}`,
|
|
112
|
+
formatYamlArray('public_interface', content.metadata.publicInterface),
|
|
113
|
+
formatYamlArray('dependencies', content.metadata.dependencies),
|
|
114
|
+
formatYamlArray('patterns', content.metadata.patterns),
|
|
115
|
+
];
|
|
116
|
+
// Add optional fields if present
|
|
117
|
+
if (content.metadata.criticalTodos && content.metadata.criticalTodos.length > 0) {
|
|
118
|
+
lines.push(formatYamlArray('critical_todos', content.metadata.criticalTodos));
|
|
119
|
+
}
|
|
120
|
+
if (content.metadata.relatedFiles && content.metadata.relatedFiles.length > 0) {
|
|
121
|
+
lines.push(formatYamlArray('related_files', content.metadata.relatedFiles));
|
|
122
|
+
}
|
|
123
|
+
lines.push('---', '');
|
|
124
|
+
return lines.join('\n') + content.summary;
|
|
65
125
|
}
|
|
66
126
|
/**
|
|
67
127
|
* Write a .sum file alongside a source file.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sum.js","sourceRoot":"","sources":["../../../src/generation/writers/sum.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"sum.js","sourceRoot":"","sources":["../../../src/generation/writers/sum.ts"],"names":[],"mappings":"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"}
|
|
@@ -33,21 +33,27 @@ export interface StackInfo {
|
|
|
33
33
|
* This generates a template that the host LLM will expand with actual
|
|
34
34
|
* architectural analysis.
|
|
35
35
|
*/
|
|
36
|
-
export declare function buildArchitectureMd(metrics: ComplexityMetrics, projectName: string): string;
|
|
36
|
+
export declare function buildArchitectureMd(metrics: ComplexityMetrics, projectName: string, hasLocalFile?: boolean): string;
|
|
37
37
|
/**
|
|
38
38
|
* Build STACK.md content from package.json analysis.
|
|
39
39
|
*/
|
|
40
|
-
export declare function buildStackMd(stackInfo: StackInfo, projectName: string): string;
|
|
40
|
+
export declare function buildStackMd(stackInfo: StackInfo, projectName: string, hasLocalFile?: boolean): string;
|
|
41
41
|
/**
|
|
42
42
|
* Parse package.json to extract stack information.
|
|
43
43
|
*/
|
|
44
44
|
export declare function analyzePackageJson(packageJsonPath: string): Promise<StackInfo | null>;
|
|
45
45
|
/**
|
|
46
46
|
* Write ARCHITECTURE.md to the configured location.
|
|
47
|
+
*
|
|
48
|
+
* If a user-defined ARCHITECTURE.md exists (not generated by us), it will be
|
|
49
|
+
* preserved as ARCHITECTURE.local.md and referenced in the generated file.
|
|
47
50
|
*/
|
|
48
51
|
export declare function writeArchitectureMd(projectRoot: string, metrics: ComplexityMetrics, config: SupplementaryConfig): Promise<string | null>;
|
|
49
52
|
/**
|
|
50
53
|
* Write STACK.md to the configured location.
|
|
54
|
+
*
|
|
55
|
+
* If a user-defined STACK.md exists (not generated by us), it will be
|
|
56
|
+
* preserved as STACK.local.md and referenced in the generated file.
|
|
51
57
|
*/
|
|
52
58
|
export declare function writeStackMd(projectRoot: string, config: SupplementaryConfig): Promise<string | null>;
|
|
53
59
|
//# sourceMappingURL=supplementary.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"supplementary.d.ts","sourceRoot":"","sources":["../../../src/generation/writers/supplementary.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"supplementary.d.ts","sourceRoot":"","sources":["../../../src/generation/writers/supplementary.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAK1D;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0CAA0C;IAC1C,oBAAoB,EAAE,OAAO,CAAC;IAC9B,mCAAmC;IACnC,aAAa,EAAE,OAAO,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,0BAA0B;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,wBAAwB;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IACzF,wBAAwB;IACxB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AA+CD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,iBAAiB,EAC1B,WAAW,EAAE,MAAM,EACnB,YAAY,GAAE,OAAe,GAC5B,MAAM,CAgDR;AA4BD;;GAEG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,SAAS,EACpB,WAAW,EAAE,MAAM,EACnB,YAAY,GAAE,OAAe,GAC5B,MAAM,CA8CR;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CA+D3B;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,iBAAiB,EAC1B,MAAM,EAAE,mBAAmB,GAC1B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAoBxB;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAChC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,mBAAmB,GAC1B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAyBxB"}
|
|
@@ -1,13 +1,66 @@
|
|
|
1
|
-
import { writeFile, readFile, mkdir } from 'node:fs/promises';
|
|
1
|
+
import { writeFile, readFile, mkdir, stat, rename } from 'node:fs/promises';
|
|
2
2
|
import * as path from 'node:path';
|
|
3
|
+
/** Marker comment to identify generated files */
|
|
4
|
+
const GENERATED_MARKER = '<!-- Generated by agents-reverse-engineer -->';
|
|
5
|
+
/**
|
|
6
|
+
* Check if a file was generated by us (contains marker).
|
|
7
|
+
*/
|
|
8
|
+
async function isGeneratedFile(filePath) {
|
|
9
|
+
try {
|
|
10
|
+
const content = await readFile(filePath, 'utf-8');
|
|
11
|
+
return content.includes(GENERATED_MARKER);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Check if a local file exists.
|
|
19
|
+
*/
|
|
20
|
+
async function hasLocalFile(localPath) {
|
|
21
|
+
try {
|
|
22
|
+
await stat(localPath);
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Preserve user-defined file by renaming to .local.md
|
|
31
|
+
* Returns whether a local file exists (either already existed or was just created)
|
|
32
|
+
*/
|
|
33
|
+
async function preserveUserFile(filePath, localPath) {
|
|
34
|
+
let hasLocal = await hasLocalFile(localPath);
|
|
35
|
+
try {
|
|
36
|
+
const existingIsGenerated = await isGeneratedFile(filePath);
|
|
37
|
+
if (!existingIsGenerated) {
|
|
38
|
+
// User-defined file exists - preserve it
|
|
39
|
+
await rename(filePath, localPath);
|
|
40
|
+
hasLocal = true;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// No existing file - that's fine
|
|
45
|
+
}
|
|
46
|
+
return hasLocal;
|
|
47
|
+
}
|
|
3
48
|
/**
|
|
4
49
|
* Build ARCHITECTURE.md content from complexity metrics.
|
|
5
50
|
*
|
|
6
51
|
* This generates a template that the host LLM will expand with actual
|
|
7
52
|
* architectural analysis.
|
|
8
53
|
*/
|
|
9
|
-
export function buildArchitectureMd(metrics, projectName) {
|
|
54
|
+
export function buildArchitectureMd(metrics, projectName, hasLocalFile = false) {
|
|
10
55
|
const sections = [];
|
|
56
|
+
// Generated marker (first line)
|
|
57
|
+
sections.push(GENERATED_MARKER);
|
|
58
|
+
sections.push('');
|
|
59
|
+
// Reference to user-defined local file if it exists
|
|
60
|
+
if (hasLocalFile) {
|
|
61
|
+
sections.push('> **Note:** This project has additional architecture documentation in [ARCHITECTURE.local.md](./ARCHITECTURE.local.md)');
|
|
62
|
+
sections.push('');
|
|
63
|
+
}
|
|
11
64
|
// Header
|
|
12
65
|
sections.push(`# Architecture: ${projectName}\n`);
|
|
13
66
|
sections.push(`> Auto-generated architecture overview. ${metrics.fileCount} files analyzed.\n`);
|
|
@@ -63,8 +116,16 @@ function getTopLevelDirectories(directories) {
|
|
|
63
116
|
/**
|
|
64
117
|
* Build STACK.md content from package.json analysis.
|
|
65
118
|
*/
|
|
66
|
-
export function buildStackMd(stackInfo, projectName) {
|
|
119
|
+
export function buildStackMd(stackInfo, projectName, hasLocalFile = false) {
|
|
67
120
|
const sections = [];
|
|
121
|
+
// Generated marker (first line)
|
|
122
|
+
sections.push(GENERATED_MARKER);
|
|
123
|
+
sections.push('');
|
|
124
|
+
// Reference to user-defined local file if it exists
|
|
125
|
+
if (hasLocalFile) {
|
|
126
|
+
sections.push('> **Note:** This project has additional stack documentation in [STACK.local.md](./STACK.local.md)');
|
|
127
|
+
sections.push('');
|
|
128
|
+
}
|
|
68
129
|
// Header
|
|
69
130
|
sections.push(`# Technology Stack: ${projectName}\n`);
|
|
70
131
|
// Runtime
|
|
@@ -158,6 +219,9 @@ export async function analyzePackageJson(packageJsonPath) {
|
|
|
158
219
|
}
|
|
159
220
|
/**
|
|
160
221
|
* Write ARCHITECTURE.md to the configured location.
|
|
222
|
+
*
|
|
223
|
+
* If a user-defined ARCHITECTURE.md exists (not generated by us), it will be
|
|
224
|
+
* preserved as ARCHITECTURE.local.md and referenced in the generated file.
|
|
161
225
|
*/
|
|
162
226
|
export async function writeArchitectureMd(projectRoot, metrics, config) {
|
|
163
227
|
if (!config.generateArchitecture)
|
|
@@ -166,14 +230,20 @@ export async function writeArchitectureMd(projectRoot, metrics, config) {
|
|
|
166
230
|
? path.join(projectRoot, config.outputDir)
|
|
167
231
|
: projectRoot;
|
|
168
232
|
await mkdir(outputDir, { recursive: true });
|
|
169
|
-
const projectName = path.basename(projectRoot);
|
|
170
|
-
const content = buildArchitectureMd(metrics, projectName);
|
|
171
233
|
const filePath = path.join(outputDir, 'ARCHITECTURE.md');
|
|
234
|
+
const localPath = path.join(outputDir, 'ARCHITECTURE.local.md');
|
|
235
|
+
// Preserve user-defined file if it exists
|
|
236
|
+
const hasLocal = await preserveUserFile(filePath, localPath);
|
|
237
|
+
const projectName = path.basename(projectRoot);
|
|
238
|
+
const content = buildArchitectureMd(metrics, projectName, hasLocal);
|
|
172
239
|
await writeFile(filePath, content, 'utf-8');
|
|
173
240
|
return filePath;
|
|
174
241
|
}
|
|
175
242
|
/**
|
|
176
243
|
* Write STACK.md to the configured location.
|
|
244
|
+
*
|
|
245
|
+
* If a user-defined STACK.md exists (not generated by us), it will be
|
|
246
|
+
* preserved as STACK.local.md and referenced in the generated file.
|
|
177
247
|
*/
|
|
178
248
|
export async function writeStackMd(projectRoot, config) {
|
|
179
249
|
if (!config.generateStack)
|
|
@@ -186,9 +256,12 @@ export async function writeStackMd(projectRoot, config) {
|
|
|
186
256
|
? path.join(projectRoot, config.outputDir)
|
|
187
257
|
: projectRoot;
|
|
188
258
|
await mkdir(outputDir, { recursive: true });
|
|
189
|
-
const projectName = path.basename(projectRoot);
|
|
190
|
-
const content = buildStackMd(stackInfo, projectName);
|
|
191
259
|
const filePath = path.join(outputDir, 'STACK.md');
|
|
260
|
+
const localPath = path.join(outputDir, 'STACK.local.md');
|
|
261
|
+
// Preserve user-defined file if it exists
|
|
262
|
+
const hasLocal = await preserveUserFile(filePath, localPath);
|
|
263
|
+
const projectName = path.basename(projectRoot);
|
|
264
|
+
const content = buildStackMd(stackInfo, projectName, hasLocal);
|
|
192
265
|
await writeFile(filePath, content, 'utf-8');
|
|
193
266
|
return filePath;
|
|
194
267
|
}
|