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.
Files changed (53) hide show
  1. package/README.md +4 -2
  2. package/dist/cli/index.js +0 -0
  3. package/dist/cli/update.d.ts.map +1 -1
  4. package/dist/cli/update.js +8 -10
  5. package/dist/cli/update.js.map +1 -1
  6. package/dist/config/defaults.d.ts +4 -4
  7. package/dist/config/defaults.d.ts.map +1 -1
  8. package/dist/config/defaults.js +15 -0
  9. package/dist/config/defaults.js.map +1 -1
  10. package/dist/discovery/filters/vendor.d.ts +7 -4
  11. package/dist/discovery/filters/vendor.d.ts.map +1 -1
  12. package/dist/discovery/filters/vendor.js +28 -8
  13. package/dist/discovery/filters/vendor.js.map +1 -1
  14. package/dist/generation/writers/agents-md.d.ts +7 -1
  15. package/dist/generation/writers/agents-md.d.ts.map +1 -1
  16. package/dist/generation/writers/agents-md.js +59 -4
  17. package/dist/generation/writers/agents-md.js.map +1 -1
  18. package/dist/generation/writers/claude-md.d.ts +6 -2
  19. package/dist/generation/writers/claude-md.d.ts.map +1 -1
  20. package/dist/generation/writers/claude-md.js +74 -11
  21. package/dist/generation/writers/claude-md.js.map +1 -1
  22. package/dist/generation/writers/gemini-md.d.ts +17 -0
  23. package/dist/generation/writers/gemini-md.d.ts.map +1 -0
  24. package/dist/generation/writers/gemini-md.js +96 -0
  25. package/dist/generation/writers/gemini-md.js.map +1 -0
  26. package/dist/generation/writers/index.d.ts +2 -0
  27. package/dist/generation/writers/index.d.ts.map +1 -1
  28. package/dist/generation/writers/index.js +2 -0
  29. package/dist/generation/writers/index.js.map +1 -1
  30. package/dist/generation/writers/opencode-md.d.ts +17 -0
  31. package/dist/generation/writers/opencode-md.d.ts.map +1 -0
  32. package/dist/generation/writers/opencode-md.js +96 -0
  33. package/dist/generation/writers/opencode-md.js.map +1 -0
  34. package/dist/generation/writers/sum.d.ts +3 -1
  35. package/dist/generation/writers/sum.d.ts.map +1 -1
  36. package/dist/generation/writers/sum.js +74 -14
  37. package/dist/generation/writers/sum.js.map +1 -1
  38. package/dist/generation/writers/supplementary.d.ts +8 -2
  39. package/dist/generation/writers/supplementary.d.ts.map +1 -1
  40. package/dist/generation/writers/supplementary.js +80 -7
  41. package/dist/generation/writers/supplementary.js.map +1 -1
  42. package/dist/installer/paths.d.ts +26 -0
  43. package/dist/installer/paths.d.ts.map +1 -1
  44. package/dist/installer/paths.js +55 -0
  45. package/dist/installer/paths.js.map +1 -1
  46. package/dist/integration/templates.d.ts.map +1 -1
  47. package/dist/integration/templates.js +25 -17
  48. package/dist/integration/templates.js.map +1 -1
  49. package/dist/update/orchestrator.d.ts +27 -32
  50. package/dist/update/orchestrator.d.ts.map +1 -1
  51. package/dist/update/orchestrator.js +97 -120
  52. package/dist/update/orchestrator.js.map +1 -1
  53. 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,wBAAwB;IACxB,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;CACrB;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAOjF;AA0DD;;;;;;;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"}
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
- // Parse metadata sections
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
- // Extract purpose from summary (first paragraph after any heading)
38
- const purposeMatch = summary.match(/##?\s*Purpose\n([\s\S]*?)(?=\n##|\n\n##|$)/i);
39
- if (purposeMatch) {
40
- metadata.purpose = purposeMatch[1].trim();
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 frontmatter = [
106
+ const lines = [
58
107
  '---',
59
108
  `file_type: ${content.fileType}`,
60
109
  `generated_at: ${content.generatedAt}`,
61
- '---',
62
- '',
63
- ].join('\n');
64
- return frontmatter + content.summary;
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":"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"}
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;AAE1D;;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;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,iBAAiB,EAC1B,WAAW,EAAE,MAAM,GAClB,MAAM,CAsCR;AA4BD;;GAEG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,SAAS,EACpB,WAAW,EAAE,MAAM,GAClB,MAAM,CAoCR;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CA+D3B;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,iBAAiB,EAC1B,MAAM,EAAE,mBAAmB,GAC1B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAexB;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,mBAAmB,GAC1B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAoBxB"}
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
  }