@googlarz/agents-sync 1.0.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 (189) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +366 -0
  3. package/dist/cli.d.ts +3 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +237 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/config/loader.d.ts +9 -0
  8. package/dist/config/loader.d.ts.map +1 -0
  9. package/dist/config/loader.js +55 -0
  10. package/dist/config/loader.js.map +1 -0
  11. package/dist/config/schema.d.ts +69 -0
  12. package/dist/config/schema.d.ts.map +1 -0
  13. package/dist/config/schema.js +33 -0
  14. package/dist/config/schema.js.map +1 -0
  15. package/dist/derivers/aider.d.ts +19 -0
  16. package/dist/derivers/aider.d.ts.map +1 -0
  17. package/dist/derivers/aider.js +117 -0
  18. package/dist/derivers/aider.js.map +1 -0
  19. package/dist/derivers/claude.d.ts +19 -0
  20. package/dist/derivers/claude.d.ts.map +1 -0
  21. package/dist/derivers/claude.js +41 -0
  22. package/dist/derivers/claude.js.map +1 -0
  23. package/dist/derivers/cline.d.ts +17 -0
  24. package/dist/derivers/cline.d.ts.map +1 -0
  25. package/dist/derivers/cline.js +92 -0
  26. package/dist/derivers/cline.js.map +1 -0
  27. package/dist/derivers/copilot.d.ts +16 -0
  28. package/dist/derivers/copilot.d.ts.map +1 -0
  29. package/dist/derivers/copilot.js +162 -0
  30. package/dist/derivers/copilot.js.map +1 -0
  31. package/dist/derivers/cursor.d.ts +16 -0
  32. package/dist/derivers/cursor.d.ts.map +1 -0
  33. package/dist/derivers/cursor.js +121 -0
  34. package/dist/derivers/cursor.js.map +1 -0
  35. package/dist/derivers/gemini.d.ts +19 -0
  36. package/dist/derivers/gemini.d.ts.map +1 -0
  37. package/dist/derivers/gemini.js +33 -0
  38. package/dist/derivers/gemini.js.map +1 -0
  39. package/dist/derivers/index.d.ts +33 -0
  40. package/dist/derivers/index.d.ts.map +1 -0
  41. package/dist/derivers/index.js +124 -0
  42. package/dist/derivers/index.js.map +1 -0
  43. package/dist/derivers/merger.d.ts +36 -0
  44. package/dist/derivers/merger.d.ts.map +1 -0
  45. package/dist/derivers/merger.js +83 -0
  46. package/dist/derivers/merger.js.map +1 -0
  47. package/dist/derivers/roo.d.ts +18 -0
  48. package/dist/derivers/roo.d.ts.map +1 -0
  49. package/dist/derivers/roo.js +92 -0
  50. package/dist/derivers/roo.js.map +1 -0
  51. package/dist/derivers/windsurf.d.ts +16 -0
  52. package/dist/derivers/windsurf.d.ts.map +1 -0
  53. package/dist/derivers/windsurf.js +91 -0
  54. package/dist/derivers/windsurf.js.map +1 -0
  55. package/dist/extractor/extractor.d.ts +4 -0
  56. package/dist/extractor/extractor.d.ts.map +1 -0
  57. package/dist/extractor/extractor.js +117 -0
  58. package/dist/extractor/extractor.js.map +1 -0
  59. package/dist/extractor/schema.d.ts +187 -0
  60. package/dist/extractor/schema.d.ts.map +1 -0
  61. package/dist/extractor/schema.js +44 -0
  62. package/dist/extractor/schema.js.map +1 -0
  63. package/dist/generator/agents-md.d.ts +3 -0
  64. package/dist/generator/agents-md.d.ts.map +1 -0
  65. package/dist/generator/agents-md.js +127 -0
  66. package/dist/generator/agents-md.js.map +1 -0
  67. package/dist/generator/validator.d.ts +7 -0
  68. package/dist/generator/validator.d.ts.map +1 -0
  69. package/dist/generator/validator.js +67 -0
  70. package/dist/generator/validator.js.map +1 -0
  71. package/dist/lib/claude-client.d.ts +11 -0
  72. package/dist/lib/claude-client.d.ts.map +1 -0
  73. package/dist/lib/claude-client.js +74 -0
  74. package/dist/lib/claude-client.js.map +1 -0
  75. package/dist/lib/errors.d.ts +10 -0
  76. package/dist/lib/errors.d.ts.map +1 -0
  77. package/dist/lib/errors.js +27 -0
  78. package/dist/lib/errors.js.map +1 -0
  79. package/dist/lib/file-utils.d.ts +7 -0
  80. package/dist/lib/file-utils.d.ts.map +1 -0
  81. package/dist/lib/file-utils.js +56 -0
  82. package/dist/lib/file-utils.js.map +1 -0
  83. package/dist/lib/token-estimate.d.ts +7 -0
  84. package/dist/lib/token-estimate.d.ts.map +1 -0
  85. package/dist/lib/token-estimate.js +15 -0
  86. package/dist/lib/token-estimate.js.map +1 -0
  87. package/dist/scanner/codegraph.d.ts +13 -0
  88. package/dist/scanner/codegraph.d.ts.map +1 -0
  89. package/dist/scanner/codegraph.js +65 -0
  90. package/dist/scanner/codegraph.js.map +1 -0
  91. package/dist/scanner/docs.d.ts +13 -0
  92. package/dist/scanner/docs.d.ts.map +1 -0
  93. package/dist/scanner/docs.js +63 -0
  94. package/dist/scanner/docs.js.map +1 -0
  95. package/dist/scanner/gotchas.d.ts +8 -0
  96. package/dist/scanner/gotchas.d.ts.map +1 -0
  97. package/dist/scanner/gotchas.js +107 -0
  98. package/dist/scanner/gotchas.js.map +1 -0
  99. package/dist/scanner/index.d.ts +21 -0
  100. package/dist/scanner/index.d.ts.map +1 -0
  101. package/dist/scanner/index.js +87 -0
  102. package/dist/scanner/index.js.map +1 -0
  103. package/dist/scanner/manifest.d.ts +13 -0
  104. package/dist/scanner/manifest.d.ts.map +1 -0
  105. package/dist/scanner/manifest.js +285 -0
  106. package/dist/scanner/manifest.js.map +1 -0
  107. package/dist/scanner/mcp.d.ts +12 -0
  108. package/dist/scanner/mcp.d.ts.map +1 -0
  109. package/dist/scanner/mcp.js +96 -0
  110. package/dist/scanner/mcp.js.map +1 -0
  111. package/dist/scanner/repomix.d.ts +11 -0
  112. package/dist/scanner/repomix.d.ts.map +1 -0
  113. package/dist/scanner/repomix.js +87 -0
  114. package/dist/scanner/repomix.js.map +1 -0
  115. package/dist/scanner/skills.d.ts +18 -0
  116. package/dist/scanner/skills.d.ts.map +1 -0
  117. package/dist/scanner/skills.js +100 -0
  118. package/dist/scanner/skills.js.map +1 -0
  119. package/dist/scanner/source.d.ts +13 -0
  120. package/dist/scanner/source.d.ts.map +1 -0
  121. package/dist/scanner/source.js +157 -0
  122. package/dist/scanner/source.js.map +1 -0
  123. package/dist/scanner/structure.d.ts +10 -0
  124. package/dist/scanner/structure.d.ts.map +1 -0
  125. package/dist/scanner/structure.js +168 -0
  126. package/dist/scanner/structure.js.map +1 -0
  127. package/dist/server.d.ts +2 -0
  128. package/dist/server.d.ts.map +1 -0
  129. package/dist/server.js +212 -0
  130. package/dist/server.js.map +1 -0
  131. package/dist/snapshot/drift.d.ts +22 -0
  132. package/dist/snapshot/drift.d.ts.map +1 -0
  133. package/dist/snapshot/drift.js +105 -0
  134. package/dist/snapshot/drift.js.map +1 -0
  135. package/dist/snapshot/schema.d.ts +94 -0
  136. package/dist/snapshot/schema.d.ts.map +1 -0
  137. package/dist/snapshot/schema.js +24 -0
  138. package/dist/snapshot/schema.js.map +1 -0
  139. package/dist/snapshot/writer.d.ts +17 -0
  140. package/dist/snapshot/writer.d.ts.map +1 -0
  141. package/dist/snapshot/writer.js +44 -0
  142. package/dist/snapshot/writer.js.map +1 -0
  143. package/dist/tools/drift.d.ts +15 -0
  144. package/dist/tools/drift.d.ts.map +1 -0
  145. package/dist/tools/drift.js +31 -0
  146. package/dist/tools/drift.js.map +1 -0
  147. package/dist/tools/export.d.ts +14 -0
  148. package/dist/tools/export.d.ts.map +1 -0
  149. package/dist/tools/export.js +53 -0
  150. package/dist/tools/export.js.map +1 -0
  151. package/dist/tools/init.d.ts +28 -0
  152. package/dist/tools/init.d.ts.map +1 -0
  153. package/dist/tools/init.js +103 -0
  154. package/dist/tools/init.js.map +1 -0
  155. package/dist/tools/install-hook.d.ts +15 -0
  156. package/dist/tools/install-hook.d.ts.map +1 -0
  157. package/dist/tools/install-hook.js +169 -0
  158. package/dist/tools/install-hook.js.map +1 -0
  159. package/dist/tools/lint.d.ts +24 -0
  160. package/dist/tools/lint.d.ts.map +1 -0
  161. package/dist/tools/lint.js +213 -0
  162. package/dist/tools/lint.js.map +1 -0
  163. package/dist/tools/scan-report.d.ts +14 -0
  164. package/dist/tools/scan-report.d.ts.map +1 -0
  165. package/dist/tools/scan-report.js +136 -0
  166. package/dist/tools/scan-report.js.map +1 -0
  167. package/dist/tools/status.d.ts +18 -0
  168. package/dist/tools/status.d.ts.map +1 -0
  169. package/dist/tools/status.js +38 -0
  170. package/dist/tools/status.js.map +1 -0
  171. package/dist/tools/sync.d.ts +22 -0
  172. package/dist/tools/sync.d.ts.map +1 -0
  173. package/dist/tools/sync.js +123 -0
  174. package/dist/tools/sync.js.map +1 -0
  175. package/dist/tools/validate.d.ts +22 -0
  176. package/dist/tools/validate.d.ts.map +1 -0
  177. package/dist/tools/validate.js +97 -0
  178. package/dist/tools/validate.js.map +1 -0
  179. package/docs/examples/.clinerules +29 -0
  180. package/docs/examples/.cursorrules +19 -0
  181. package/docs/examples/.windsurfrules +14 -0
  182. package/docs/examples/AGENTS.md +97 -0
  183. package/docs/examples/CLAUDE.md +88 -0
  184. package/docs/examples/GEMINI.md +61 -0
  185. package/docs/examples/copilot-instructions.md +24 -0
  186. package/docs/github-action.yml +89 -0
  187. package/package.json +63 -0
  188. package/scripts/demo.sh +138 -0
  189. package/skill/SKILL.md +158 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/extractor/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4ChC,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE,eAAO,MAAM,gBAAgB,QAAQ,CAAC"}
@@ -0,0 +1,44 @@
1
+ import { z } from "zod";
2
+ export const ProjectMetadataSchema = z.object({
3
+ project: z.object({
4
+ name: z.string().describe("Project name from manifest"),
5
+ description: z.string().describe("What this project does, 1-2 sentences"),
6
+ language: z.string().describe("Primary language: typescript, javascript, python, rust, go, etc"),
7
+ framework: z.string().optional().describe("Primary framework: nextjs, django, express, axum, etc"),
8
+ version: z.string().optional().describe("Project version from manifest"),
9
+ }),
10
+ stack: z.object({
11
+ runtime: z.string().optional().describe("Runtime and version: node 20, python 3.11, etc"),
12
+ database: z.string().optional().describe("Database + ORM: postgres via prisma, sqlite via drizzle, etc"),
13
+ auth: z.string().optional().describe("Auth solution: next-auth, jwt, supabase auth, etc"),
14
+ testing: z.string().optional().describe("Test framework and runner: vitest, pytest, cargo test, etc"),
15
+ deploy: z.string().optional().describe("Deployment target: vercel, railway, fly.io, docker, etc"),
16
+ other: z.array(z.string()).describe("Other notable stack items: redis, stripe, openai, etc"),
17
+ }),
18
+ architecture: z.object({
19
+ style: z.string().optional().describe("feature-first, layered, monorepo, flat, etc"),
20
+ keyDirs: z.record(z.string()).describe("Map of important dirs to their purpose: { 'src/features': 'domain modules' }"),
21
+ entryPoints: z.array(z.string()).describe("Main entry point files relative to project root"),
22
+ }),
23
+ conventions: z.array(z.string()).describe("Specific coding conventions Claude must follow. Be concrete: 'kebab-case filenames', 'named exports only', 'zod for all external input'. No generic advice."),
24
+ gotchas: z.array(z.string()).describe("Things that will break if ignored. Include consequence: 'Do not import PrismaClient directly — causes connection pool exhaustion. Use lib/db.ts singleton instead.'"),
25
+ boundaries: z.object({
26
+ alwaysDo: z.array(z.string()).describe("Things AI must always do"),
27
+ askFirst: z.array(z.string()).describe("Things requiring human approval before doing"),
28
+ never: z.array(z.string()).describe("Hard constraints — never violate these"),
29
+ }),
30
+ testing: z.object({
31
+ framework: z.string().optional().describe("Test framework name"),
32
+ command: z.string().optional().describe("Exact command to run tests: npm test, pytest, cargo test"),
33
+ location: z.string().optional().describe("Where tests live: colocated, tests/, __tests__/"),
34
+ coverageCommand: z.string().optional().describe("Command to run with coverage"),
35
+ }),
36
+ deployment: z.object({
37
+ target: z.string().optional().describe("Where it deploys: vercel, fly.io, etc"),
38
+ command: z.string().optional().describe("Deploy command if any"),
39
+ envFile: z.string().optional().describe(".env file name if non-standard"),
40
+ notes: z.array(z.string()).describe("Important deployment notes"),
41
+ }),
42
+ });
43
+ export const METADATA_VERSION = "1.0";
44
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/extractor/schema.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ProjectMetadata } from "../extractor/schema.js";
2
+ export declare function generateAgentsMd(metadata: ProjectMetadata): Promise<string>;
3
+ //# sourceMappingURL=agents-md.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agents-md.d.ts","sourceRoot":"","sources":["../../src/generator/agents-md.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAuD9D,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAsBjF"}
@@ -0,0 +1,127 @@
1
+ import { callClaude } from "../lib/claude-client.js";
2
+ import { AgentsSyncError } from "../lib/errors.js";
3
+ const SYSTEM_PROMPT = `You are writing an AGENTS.md file — the canonical AI context file for a software project.
4
+
5
+ This file will be read by AI coding assistants (Claude, Cursor, Copilot, Codex) to understand the project.
6
+ A session starting with ONLY this file must be able to:
7
+ 1. Identify the correct directory for a new feature
8
+ 2. Know the naming convention for new files
9
+ 3. Know the exact test command to run
10
+ 4. Avoid the project's top gotchas
11
+
12
+ Quality rules:
13
+ - Every convention must be SPECIFIC: "kebab-case filenames" not "follow conventions"
14
+ - Every gotcha must include CONSEQUENCE: "Do not import PrismaClient directly — causes pool exhaustion"
15
+ - Architecture section must name REAL directories (from the data provided)
16
+ - No section may be generic advice that applies to any project
17
+ - No empty sections — omit a section entirely if you have no real data for it
18
+ - Length: 400–900 words
19
+
20
+ Format the output as valid markdown starting with "# AGENTS.md".`;
21
+ const TEMPLATE = `# AGENTS.md
22
+
23
+ <!-- Generated by agents-sync v1.0.0 on {DATE} -->
24
+ <!-- Edit this file, then run /agents-sync sync to propagate changes to all tool files -->
25
+
26
+ ## Project Overview
27
+ {OVERVIEW}
28
+
29
+ ## Tech Stack
30
+ {STACK}
31
+
32
+ ## Architecture
33
+ {ARCHITECTURE}
34
+
35
+ ## Conventions
36
+ {CONVENTIONS}
37
+
38
+ ## Gotchas
39
+ {GOTCHAS}
40
+
41
+ ## Testing
42
+ {TESTING}
43
+
44
+ ## Boundaries
45
+
46
+ ### Always
47
+ {ALWAYS}
48
+
49
+ ### Ask First
50
+ {ASK_FIRST}
51
+
52
+ ### Never
53
+ {NEVER}`;
54
+ export async function generateAgentsMd(metadata) {
55
+ const userPrompt = buildPrompt(metadata);
56
+ const { content } = await callClaude(SYSTEM_PROMPT, userPrompt, 2048);
57
+ // Ensure it starts with the header
58
+ if (!content.trim().startsWith("# AGENTS.md") && !content.trim().startsWith("# agents-sync")) {
59
+ throw new AgentsSyncError("GENERATION_FAILED", "Generated output did not produce a valid AGENTS.md header.", "Run with AGENTS_SYNC_DEBUG=1 to inspect output.");
60
+ }
61
+ // Inject generated timestamp if Claude didn't include a comment
62
+ const dated = content.includes("Generated by agents-sync")
63
+ ? content
64
+ : content.replace("# AGENTS.md", `# AGENTS.md\n\n<!-- Generated by agents-sync v1.0.0 on ${new Date().toISOString().slice(0, 10)} -->\n<!-- Edit this file, then run /agents-sync sync to propagate changes to all tool files -->`);
65
+ return dated.trim();
66
+ }
67
+ function buildPrompt(m) {
68
+ const lines = ["Here is the extracted project metadata. Generate the AGENTS.md:\n"];
69
+ lines.push(`PROJECT: ${m.project.name} — ${m.project.description}`);
70
+ lines.push(`Language: ${m.project.language}${m.project.framework ? `, Framework: ${m.project.framework}` : ""}${m.project.version ? `, v${m.project.version}` : ""}`);
71
+ lines.push("\nSTACK:");
72
+ if (m.stack.runtime)
73
+ lines.push(` Runtime: ${m.stack.runtime}`);
74
+ if (m.stack.database)
75
+ lines.push(` Database: ${m.stack.database}`);
76
+ if (m.stack.auth)
77
+ lines.push(` Auth: ${m.stack.auth}`);
78
+ if (m.stack.testing)
79
+ lines.push(` Testing: ${m.stack.testing}`);
80
+ if (m.stack.deploy)
81
+ lines.push(` Deploy: ${m.stack.deploy}`);
82
+ if (m.stack.other.length > 0)
83
+ lines.push(` Other: ${m.stack.other.join(", ")}`);
84
+ lines.push("\nARCHITECTURE:");
85
+ if (m.architecture.style)
86
+ lines.push(` Style: ${m.architecture.style}`);
87
+ lines.push(` Entry points: ${m.architecture.entryPoints.join(", ") || "unknown"}`);
88
+ for (const [dir, desc] of Object.entries(m.architecture.keyDirs)) {
89
+ lines.push(` ${dir}: ${desc}`);
90
+ }
91
+ if (m.conventions.length > 0) {
92
+ lines.push("\nCONVENTIONS:");
93
+ m.conventions.forEach((c, i) => lines.push(` ${i + 1}. ${c}`));
94
+ }
95
+ if (m.gotchas.length > 0) {
96
+ lines.push("\nGOTCHAS:");
97
+ m.gotchas.forEach((g, i) => lines.push(` ${i + 1}. ${g}`));
98
+ }
99
+ lines.push("\nBOUNDARIES:");
100
+ if (m.boundaries.alwaysDo.length > 0)
101
+ lines.push(` Always: ${m.boundaries.alwaysDo.join("; ")}`);
102
+ if (m.boundaries.askFirst.length > 0)
103
+ lines.push(` Ask first: ${m.boundaries.askFirst.join("; ")}`);
104
+ if (m.boundaries.never.length > 0)
105
+ lines.push(` Never: ${m.boundaries.never.join("; ")}`);
106
+ lines.push("\nTESTING:");
107
+ if (m.testing.framework)
108
+ lines.push(` Framework: ${m.testing.framework}`);
109
+ if (m.testing.command)
110
+ lines.push(` Command: ${m.testing.command}`);
111
+ if (m.testing.location)
112
+ lines.push(` Location: ${m.testing.location}`);
113
+ if (m.testing.coverageCommand)
114
+ lines.push(` Coverage: ${m.testing.coverageCommand}`);
115
+ if (m.deployment.target || m.deployment.notes.length > 0) {
116
+ lines.push("\nDEPLOYMENT:");
117
+ if (m.deployment.target)
118
+ lines.push(` Target: ${m.deployment.target}`);
119
+ if (m.deployment.command)
120
+ lines.push(` Command: ${m.deployment.command}`);
121
+ m.deployment.notes.forEach((n) => lines.push(` Note: ${n}`));
122
+ }
123
+ lines.push(`\nUse this template structure:\n${TEMPLATE.replace("{DATE}", new Date().toISOString().slice(0, 10))}`);
124
+ lines.push("\nGenerate the complete AGENTS.md now:");
125
+ return lines.join("\n");
126
+ }
127
+ //# sourceMappingURL=agents-md.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agents-md.js","sourceRoot":"","sources":["../../src/generator/agents-md.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export interface ValidationResult {
2
+ passed: boolean;
3
+ failures: string[];
4
+ warnings: string[];
5
+ }
6
+ export declare function validateAgentsMd(content: string, knownDirs?: string[]): ValidationResult;
7
+ //# sourceMappingURL=validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/generator/validator.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAMD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,GAAE,MAAM,EAAO,GAAG,gBAAgB,CAsE5F"}
@@ -0,0 +1,67 @@
1
+ const MIN_CONVENTIONS = 2;
2
+ const MIN_WORDS = 300;
3
+ const MAX_WORDS = 1200;
4
+ export function validateAgentsMd(content, knownDirs = []) {
5
+ const failures = [];
6
+ const warnings = [];
7
+ // Must have the header
8
+ if (!content.includes("# AGENTS.md")) {
9
+ failures.push("Missing '# AGENTS.md' header");
10
+ }
11
+ // Word count
12
+ const words = content.split(/\s+/).filter(Boolean).length;
13
+ if (words < MIN_WORDS) {
14
+ failures.push(`Too short: ${words} words (minimum ${MIN_WORDS}). Output is too generic.`);
15
+ }
16
+ if (words > MAX_WORDS) {
17
+ warnings.push(`Long: ${words} words. Consider trimming for readability.`);
18
+ }
19
+ // Must have conventions section with specific rules
20
+ const conventionsMatch = content.match(/## Conventions\n([\s\S]*?)(?=\n## |\n# |$)/);
21
+ if (!conventionsMatch) {
22
+ failures.push("Missing '## Conventions' section");
23
+ }
24
+ else {
25
+ const convText = conventionsMatch[1];
26
+ const bulletCount = (convText.match(/^[-*\d]/gm) ?? []).length;
27
+ if (bulletCount < MIN_CONVENTIONS) {
28
+ failures.push(`Conventions section has ${bulletCount} items (minimum ${MIN_CONVENTIONS})`);
29
+ }
30
+ // Detect generic advice
31
+ const genericPhrases = ["best practices", "follow conventions", "write clean code", "use good names"];
32
+ for (const phrase of genericPhrases) {
33
+ if (convText.toLowerCase().includes(phrase)) {
34
+ warnings.push(`Generic phrase detected in Conventions: "${phrase}" — should be specific`);
35
+ }
36
+ }
37
+ }
38
+ // Must have boundaries section
39
+ if (!content.includes("### Never")) {
40
+ failures.push("Missing '### Never' section under Boundaries");
41
+ }
42
+ // Architecture dirs should reference real directories
43
+ if (knownDirs.length > 0) {
44
+ const archMatch = content.match(/## Architecture\n([\s\S]*?)(?=\n## |\n# |$)/);
45
+ if (archMatch) {
46
+ const archText = archMatch[1];
47
+ const referencedDirs = archText.match(/`([^`]+)`|`([^`]+)`|\b(src\/\w+|tests?\/|\w+\/)/g) ?? [];
48
+ const hasRealDir = referencedDirs.some((d) => knownDirs.some((kd) => d.includes(kd.split("/")[0])));
49
+ if (!hasRealDir && knownDirs.length > 2) {
50
+ warnings.push("Architecture section may not reference actual project directories");
51
+ }
52
+ }
53
+ }
54
+ // Testing section should have a command
55
+ if (content.includes("## Testing")) {
56
+ const testMatch = content.match(/## Testing\n([\s\S]*?)(?=\n## |\n# |$)/);
57
+ if (testMatch && !testMatch[1].match(/`[^`]+`/)) {
58
+ warnings.push("Testing section has no code-formatted command (e.g. `npm test`)");
59
+ }
60
+ }
61
+ return {
62
+ passed: failures.length === 0,
63
+ failures,
64
+ warnings,
65
+ };
66
+ }
67
+ //# sourceMappingURL=validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validator.js","sourceRoot":"","sources":["../../src/generator/validator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ export interface ClaudeResponse {
2
+ content: string;
3
+ usage: {
4
+ inputTokens: number;
5
+ outputTokens: number;
6
+ cacheReadTokens: number;
7
+ cacheWriteTokens: number;
8
+ };
9
+ }
10
+ export declare function callClaude(systemPrompt: string, userPrompt: string, maxTokens?: number): Promise<ClaudeResponse>;
11
+ //# sourceMappingURL=claude-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-client.d.ts","sourceRoot":"","sources":["../../src/lib/claude-client.ts"],"names":[],"mappings":"AA8BA,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAA;KAAE,CAAC;CACzG;AAED,wBAAsB,UAAU,CAC9B,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,SAAS,SAAO,GACf,OAAO,CAAC,cAAc,CAAC,CA+DzB"}
@@ -0,0 +1,74 @@
1
+ import Anthropic from "@anthropic-ai/sdk";
2
+ import { AgentsSyncError } from "./errors.js";
3
+ const MODEL = "claude-sonnet-4-6";
4
+ const MAX_RETRIES = 3;
5
+ const RETRY_DELAY_MS = 2000;
6
+ let _client = null;
7
+ function getClient() {
8
+ if (!_client) {
9
+ const apiKey = process.env.ANTHROPIC_API_KEY;
10
+ if (!apiKey) {
11
+ throw new AgentsSyncError("MISSING_API_KEY", "ANTHROPIC_API_KEY environment variable is not set.", "Export it: export ANTHROPIC_API_KEY=sk-ant-...");
12
+ }
13
+ _client = new Anthropic({ apiKey });
14
+ }
15
+ return _client;
16
+ }
17
+ function debug(msg) {
18
+ if (process.env.AGENTS_SYNC_DEBUG === "1") {
19
+ process.stderr.write(`[agents-sync:debug] ${msg}\n`);
20
+ }
21
+ }
22
+ export async function callClaude(systemPrompt, userPrompt, maxTokens = 4096) {
23
+ const client = getClient();
24
+ for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
25
+ try {
26
+ debug(`Claude call attempt ${attempt}, maxTokens=${maxTokens}`);
27
+ const response = await client.messages.create({
28
+ model: MODEL,
29
+ max_tokens: maxTokens,
30
+ system: [
31
+ {
32
+ type: "text",
33
+ text: systemPrompt,
34
+ cache_control: { type: "ephemeral" },
35
+ },
36
+ ],
37
+ messages: [{ role: "user", content: userPrompt }],
38
+ });
39
+ const content = response.content
40
+ .filter((b) => b.type === "text")
41
+ .map((b) => b.text)
42
+ .join("");
43
+ const usage = {
44
+ inputTokens: response.usage.input_tokens,
45
+ outputTokens: response.usage.output_tokens,
46
+ cacheReadTokens: response.usage.cache_read_input_tokens ?? 0,
47
+ cacheWriteTokens: response.usage.cache_creation_input_tokens ?? 0,
48
+ };
49
+ debug(`Response: ${usage.outputTokens} out, ${usage.cacheReadTokens} cache_read, ${usage.cacheWriteTokens} cache_write`);
50
+ return { content, usage };
51
+ }
52
+ catch (e) {
53
+ const err = e;
54
+ if (err.status === 429 && attempt < MAX_RETRIES) {
55
+ debug(`Rate limited, retrying in ${RETRY_DELAY_MS * attempt}ms...`);
56
+ await sleep(RETRY_DELAY_MS * attempt);
57
+ continue;
58
+ }
59
+ if (err.status === 529 && attempt < MAX_RETRIES) {
60
+ debug(`Overloaded, retrying in ${RETRY_DELAY_MS}ms...`);
61
+ await sleep(RETRY_DELAY_MS);
62
+ continue;
63
+ }
64
+ throw new AgentsSyncError(err.status === 429 ? "RATE_LIMIT" : "API_ERROR", `Claude API error: ${err.message ?? String(e)}`, err.status === 429
65
+ ? "Rate limited. Try again in ~60 seconds. Use --fast flag to skip re-extraction."
66
+ : "Run with AGENTS_SYNC_DEBUG=1 to see full error.");
67
+ }
68
+ }
69
+ throw new AgentsSyncError("RATE_LIMIT", "Rate limited after 3 retries.", "Wait ~60 seconds and try again.");
70
+ }
71
+ function sleep(ms) {
72
+ return new Promise((r) => setTimeout(r, ms));
73
+ }
74
+ //# sourceMappingURL=claude-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-client.js","sourceRoot":"","sources":["../../src/lib/claude-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export type ErrorCode = "MISSING_API_KEY" | "INVALID_PROJECT_PATH" | "NO_SNAPSHOT" | "RATE_LIMIT" | "API_ERROR" | "EXTRACTION_FAILED" | "GENERATION_FAILED" | "WRITE_ERROR" | "PARSE_ERROR" | "TIMEOUT";
2
+ export declare class AgentsSyncError extends Error {
3
+ readonly code: ErrorCode;
4
+ readonly hint?: string | undefined;
5
+ constructor(code: ErrorCode, message: string, hint?: string | undefined);
6
+ format(): string;
7
+ }
8
+ export declare function isAgentsSyncError(e: unknown): e is AgentsSyncError;
9
+ export declare function toMcpError(e: unknown): string;
10
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GACjB,iBAAiB,GACjB,sBAAsB,GACtB,aAAa,GACb,YAAY,GACZ,WAAW,GACX,mBAAmB,GACnB,mBAAmB,GACnB,aAAa,GACb,aAAa,GACb,SAAS,CAAC;AAEd,qBAAa,eAAgB,SAAQ,KAAK;aAEtB,IAAI,EAAE,SAAS;aAEf,IAAI,CAAC,EAAE,MAAM;gBAFb,IAAI,EAAE,SAAS,EAC/B,OAAO,EAAE,MAAM,EACC,IAAI,CAAC,EAAE,MAAM,YAAA;IAM/B,MAAM,IAAI,MAAM;CAKjB;AAED,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,eAAe,CAElE;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAI7C"}
@@ -0,0 +1,27 @@
1
+ export class AgentsSyncError extends Error {
2
+ code;
3
+ hint;
4
+ constructor(code, message, hint) {
5
+ super(message);
6
+ this.code = code;
7
+ this.hint = hint;
8
+ this.name = "AgentsSyncError";
9
+ }
10
+ format() {
11
+ const lines = [`[${this.code}] ${this.message}`];
12
+ if (this.hint)
13
+ lines.push(` → ${this.hint}`);
14
+ return lines.join("\n");
15
+ }
16
+ }
17
+ export function isAgentsSyncError(e) {
18
+ return e instanceof AgentsSyncError;
19
+ }
20
+ export function toMcpError(e) {
21
+ if (e instanceof AgentsSyncError)
22
+ return e.format();
23
+ if (e instanceof Error)
24
+ return e.message;
25
+ return String(e);
26
+ }
27
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"AAYA,MAAM,OAAO,eAAgB,SAAQ,KAAK;IAEtB;IAEA;IAHlB,YACkB,IAAe,EAC/B,OAAe,EACC,IAAa;QAE7B,KAAK,CAAC,OAAO,CAAC,CAAC;QAJC,SAAI,GAAJ,IAAI,CAAW;QAEf,SAAI,GAAJ,IAAI,CAAS;QAG7B,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAChC,CAAC;IAED,MAAM;QACJ,MAAM,KAAK,GAAG,CAAC,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;QACjD,IAAI,IAAI,CAAC,IAAI;YAAE,KAAK,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAC9C,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;CACF;AAED,MAAM,UAAU,iBAAiB,CAAC,CAAU;IAC1C,OAAO,CAAC,YAAY,eAAe,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,CAAU;IACnC,IAAI,CAAC,YAAY,eAAe;QAAE,OAAO,CAAC,CAAC,MAAM,EAAE,CAAC;IACpD,IAAI,CAAC,YAAY,KAAK;QAAE,OAAO,CAAC,CAAC,OAAO,CAAC;IACzC,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;AACnB,CAAC"}
@@ -0,0 +1,7 @@
1
+ export declare function readFileSafe(filePath: string): Promise<string | null>;
2
+ export declare function writeFileAtomic(filePath: string, content: string): Promise<void>;
3
+ export declare function dirExists(p: string): Promise<boolean>;
4
+ export declare function fileExists(p: string): Promise<boolean>;
5
+ export declare function assertAbsolutePath(p: string): void;
6
+ export declare function assertProjectDir(p: string): Promise<void>;
7
+ //# sourceMappingURL=file-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-utils.d.ts","sourceRoot":"","sources":["../../src/lib/file-utils.ts"],"names":[],"mappings":"AAIA,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAM3E;AAED,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CActF;AAED,wBAAsB,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO3D;AAED,wBAAsB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO5D;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAQlD;AAED,wBAAsB,gBAAgB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAS/D"}
@@ -0,0 +1,56 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { AgentsSyncError } from "./errors.js";
4
+ export async function readFileSafe(filePath) {
5
+ try {
6
+ return await fs.readFile(filePath, "utf-8");
7
+ }
8
+ catch {
9
+ return null;
10
+ }
11
+ }
12
+ export async function writeFileAtomic(filePath, content) {
13
+ const tmp = filePath + ".agents-sync.tmp";
14
+ try {
15
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
16
+ await fs.writeFile(tmp, content, "utf-8");
17
+ await fs.rename(tmp, filePath);
18
+ }
19
+ catch (e) {
20
+ try {
21
+ await fs.unlink(tmp);
22
+ }
23
+ catch { /* ignore */ }
24
+ throw new AgentsSyncError("WRITE_ERROR", `Cannot write to ${filePath}: ${e.message}`, "Check file permissions and disk space.");
25
+ }
26
+ }
27
+ export async function dirExists(p) {
28
+ try {
29
+ const stat = await fs.stat(p);
30
+ return stat.isDirectory();
31
+ }
32
+ catch {
33
+ return false;
34
+ }
35
+ }
36
+ export async function fileExists(p) {
37
+ try {
38
+ await fs.stat(p);
39
+ return true;
40
+ }
41
+ catch {
42
+ return false;
43
+ }
44
+ }
45
+ export function assertAbsolutePath(p) {
46
+ if (!path.isAbsolute(p)) {
47
+ throw new AgentsSyncError("INVALID_PROJECT_PATH", `Path must be absolute: ${p}`, "Pass the full path, e.g. /Users/you/my-project");
48
+ }
49
+ }
50
+ export async function assertProjectDir(p) {
51
+ assertAbsolutePath(p);
52
+ if (!(await dirExists(p))) {
53
+ throw new AgentsSyncError("INVALID_PROJECT_PATH", `Project path not found: ${p}`, "Make sure the directory exists and the path is correct.");
54
+ }
55
+ }
56
+ //# sourceMappingURL=file-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-utils.js","sourceRoot":"","sources":["../../src/lib/file-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAgB;IACjD,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,QAAgB,EAAE,OAAe;IACrE,MAAM,GAAG,GAAG,QAAQ,GAAG,kBAAkB,CAAC;IAC1C,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5D,MAAM,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QAC1C,MAAM,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IACjC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC;YAAC,MAAM,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;QACpD,MAAM,IAAI,eAAe,CACvB,aAAa,EACb,mBAAmB,QAAQ,KAAM,CAAW,CAAC,OAAO,EAAE,EACtD,wCAAwC,CACzC,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,CAAS;IACvC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC9B,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,CAAS;IACxC,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,CAAS;IAC1C,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,eAAe,CACvB,sBAAsB,EACtB,0BAA0B,CAAC,EAAE,EAC7B,gDAAgD,CACjD,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,CAAS;IAC9C,kBAAkB,CAAC,CAAC,CAAC,CAAC;IACtB,IAAI,CAAC,CAAC,MAAM,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,eAAe,CACvB,sBAAsB,EACtB,2BAA2B,CAAC,EAAE,EAC9B,yDAAyD,CAC1D,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,7 @@
1
+ /** Rough token estimate: ~4 chars per token for code */
2
+ export declare function estimateTokens(text: string): number;
3
+ export declare function truncateToTokenBudget(text: string, maxTokens: number): {
4
+ text: string;
5
+ truncated: boolean;
6
+ };
7
+ //# sourceMappingURL=token-estimate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-estimate.d.ts","sourceRoot":"","sources":["../../src/lib/token-estimate.ts"],"names":[],"mappings":"AAAA,wDAAwD;AACxD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,GAChB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAStC"}
@@ -0,0 +1,15 @@
1
+ /** Rough token estimate: ~4 chars per token for code */
2
+ export function estimateTokens(text) {
3
+ return Math.ceil(text.length / 4);
4
+ }
5
+ export function truncateToTokenBudget(text, maxTokens) {
6
+ const estimated = estimateTokens(text);
7
+ if (estimated <= maxTokens)
8
+ return { text, truncated: false };
9
+ const maxChars = maxTokens * 4;
10
+ return {
11
+ text: text.slice(0, maxChars) + `\n\n[... truncated at ~${maxTokens} tokens]`,
12
+ truncated: true,
13
+ };
14
+ }
15
+ //# sourceMappingURL=token-estimate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-estimate.js","sourceRoot":"","sources":["../../src/lib/token-estimate.ts"],"names":[],"mappings":"AAAA,wDAAwD;AACxD,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,IAAY,EACZ,SAAiB;IAEjB,MAAM,SAAS,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,SAAS,IAAI,SAAS;QAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IAE9D,MAAM,QAAQ,GAAG,SAAS,GAAG,CAAC,CAAC;IAC/B,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,0BAA0B,SAAS,UAAU;QAC7E,SAAS,EAAE,IAAI;KAChB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,13 @@
1
+ export interface CodegraphSummary {
2
+ available: boolean;
3
+ communities: CodegraphCommunity[];
4
+ hubNodes: string[];
5
+ entryPoints: string[];
6
+ }
7
+ export interface CodegraphCommunity {
8
+ name: string;
9
+ files: string[];
10
+ }
11
+ export declare function readCodegraphIndex(projectPath: string): Promise<CodegraphSummary>;
12
+ export declare function formatCodegraphContext(summary: CodegraphSummary): string;
13
+ //# sourceMappingURL=codegraph.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codegraph.d.ts","sourceRoot":"","sources":["../../src/scanner/codegraph.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,kBAAkB,EAAE,CAAC;IAClC,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAcD,wBAAsB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAqCvF;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,CAuBxE"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * codegraph scanner
3
+ *
4
+ * Reads .codegraph/index.json (if present) and returns a lightweight summary
5
+ * of community clusters + hub nodes that can be injected into the corpus.
6
+ * This enriches AGENTS.md with evidence-backed architecture notes.
7
+ *
8
+ * Gracefully no-ops when .codegraph/ is absent — works without codegraph.
9
+ */
10
+ import path from "node:path";
11
+ import fs from "node:fs/promises";
12
+ export async function readCodegraphIndex(projectPath) {
13
+ const candidates = [
14
+ path.join(projectPath, ".codegraph", "index.json"),
15
+ path.join(projectPath, ".codegraph", "graph.json"),
16
+ path.join(projectPath, "codegraph.json"),
17
+ ];
18
+ for (const candidate of candidates) {
19
+ const raw = await fs.readFile(candidate, "utf-8").catch(() => null);
20
+ if (!raw)
21
+ continue;
22
+ let parsed;
23
+ try {
24
+ parsed = JSON.parse(raw);
25
+ }
26
+ catch {
27
+ continue;
28
+ }
29
+ const communities = (parsed.communities ?? []).slice(0, 8).map((c) => ({
30
+ name: c.label ?? c.name ?? "unnamed",
31
+ files: (c.files ?? c.nodes?.map((n) => n.file ?? n.path ?? "").filter(Boolean) ?? []).slice(0, 5),
32
+ }));
33
+ const hubNodes = (parsed.hubNodes ?? parsed.nodes?.filter((n) => (n.hubScore ?? 0) > 0.5) ?? [])
34
+ .slice(0, 10)
35
+ .map((n) => n.file ?? n.path ?? n.name ?? "")
36
+ .filter(Boolean);
37
+ const entryPoints = (parsed.entryPoints ?? parsed.nodes?.filter((n) => n.isEntry) ?? [])
38
+ .slice(0, 8)
39
+ .map((n) => n.file ?? n.path ?? "")
40
+ .filter(Boolean);
41
+ return { available: true, communities, hubNodes, entryPoints };
42
+ }
43
+ return { available: false, communities: [], hubNodes: [], entryPoints: [] };
44
+ }
45
+ export function formatCodegraphContext(summary) {
46
+ if (!summary.available)
47
+ return "";
48
+ const lines = ["## Code Graph (from .codegraph/)"];
49
+ if (summary.communities.length > 0) {
50
+ lines.push("\n### Architecture clusters");
51
+ for (const c of summary.communities) {
52
+ lines.push(`- **${c.name}**: ${c.files.join(", ")}`);
53
+ }
54
+ }
55
+ if (summary.hubNodes.length > 0) {
56
+ lines.push("\n### High-connectivity files (call hubs)");
57
+ lines.push(summary.hubNodes.map((n) => `- ${n}`).join("\n"));
58
+ }
59
+ if (summary.entryPoints.length > 0) {
60
+ lines.push("\n### Entry points");
61
+ lines.push(summary.entryPoints.map((n) => `- ${n}`).join("\n"));
62
+ }
63
+ return lines.join("\n");
64
+ }
65
+ //# sourceMappingURL=codegraph.js.map