@googlarz/agents-sync 1.4.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 (186) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +507 -0
  3. package/dist/cli.d.ts +3 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +267 -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 +93 -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 +134 -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 +125 -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 +6 -0
  64. package/dist/generator/agents-md.d.ts.map +1 -0
  65. package/dist/generator/agents-md.js +135 -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 +26 -0
  100. package/dist/scanner/index.d.ts.map +1 -0
  101. package/dist/scanner/index.js +95 -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 +245 -0
  130. package/dist/server.js.map +1 -0
  131. package/dist/snapshot/drift.d.ts +28 -0
  132. package/dist/snapshot/drift.d.ts.map +1 -0
  133. package/dist/snapshot/drift.js +205 -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 +51 -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/lint.d.ts +24 -0
  156. package/dist/tools/lint.d.ts.map +1 -0
  157. package/dist/tools/lint.js +213 -0
  158. package/dist/tools/lint.js.map +1 -0
  159. package/dist/tools/scan-report.d.ts +14 -0
  160. package/dist/tools/scan-report.d.ts.map +1 -0
  161. package/dist/tools/scan-report.js +136 -0
  162. package/dist/tools/scan-report.js.map +1 -0
  163. package/dist/tools/status.d.ts +18 -0
  164. package/dist/tools/status.d.ts.map +1 -0
  165. package/dist/tools/status.js +38 -0
  166. package/dist/tools/status.js.map +1 -0
  167. package/dist/tools/sync.d.ts +22 -0
  168. package/dist/tools/sync.d.ts.map +1 -0
  169. package/dist/tools/sync.js +123 -0
  170. package/dist/tools/sync.js.map +1 -0
  171. package/dist/tools/validate.d.ts +22 -0
  172. package/dist/tools/validate.d.ts.map +1 -0
  173. package/dist/tools/validate.js +97 -0
  174. package/dist/tools/validate.js.map +1 -0
  175. package/docs/agents-md-spec.md +233 -0
  176. package/docs/examples/.clinerules +29 -0
  177. package/docs/examples/.cursorrules +19 -0
  178. package/docs/examples/.windsurfrules +14 -0
  179. package/docs/examples/AGENTS.md +97 -0
  180. package/docs/examples/CLAUDE.md +88 -0
  181. package/docs/examples/GEMINI.md +61 -0
  182. package/docs/examples/copilot-instructions.md +24 -0
  183. package/docs/github-action.yml +89 -0
  184. package/package.json +63 -0
  185. package/scripts/demo.sh +138 -0
  186. package/skill/SKILL.md +158 -0
@@ -0,0 +1,33 @@
1
+ import type { ProjectMetadata } from "../extractor/schema.js";
2
+ export type ToolName = "claude" | "cursor" | "copilot" | "gemini" | "windsurf" | "cline" | "roo" | "aider";
3
+ export interface DerivationResult {
4
+ tool: ToolName | "agents-md";
5
+ /** Absolute path to the file. */
6
+ path: string;
7
+ written: boolean;
8
+ customBlocksPreserved: number;
9
+ /** true when dryRun is enabled — file was not written. */
10
+ skipped?: boolean;
11
+ error?: string;
12
+ }
13
+ export interface DeriveAllOptions {
14
+ projectPath: string;
15
+ agentsMdContent: string;
16
+ metadata: ProjectMetadata;
17
+ /** Tools to derive. Defaults to all six. */
18
+ tools?: ToolName[];
19
+ dryRun?: boolean;
20
+ /** @default true */
21
+ preserveCustom?: boolean;
22
+ }
23
+ export declare const ALL_TOOLS: ToolName[];
24
+ export declare function toolPath(projectPath: string, tool: ToolName): string;
25
+ /**
26
+ * Runs all (or selected) derivers and writes the results.
27
+ *
28
+ * AGENTS.md is always written first as the canonical source file.
29
+ * Per-tool errors are caught and returned as `{ error }` entries — one
30
+ * failing tool does not abort the others.
31
+ */
32
+ export declare function deriveAll(options: DeriveAllOptions): Promise<DerivationResult[]>;
33
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/derivers/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAa9D,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,UAAU,GAAG,OAAO,GAAG,KAAK,GAAG,OAAO,CAAC;AAE3G,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,QAAQ,GAAG,WAAW,CAAC;IAC7B,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,0DAA0D;IAC1D,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,eAAe,CAAC;IAC1B,4CAA4C;IAC5C,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,oBAAoB;IACpB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,eAAO,MAAM,SAAS,EAAE,QAAQ,EAAmF,CAAC;AAMpH,wBAAgB,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,MAAM,CAmBpE;AAqCD;;;;;;GAMG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAwEtF"}
@@ -0,0 +1,134 @@
1
+ import path from "node:path";
2
+ import { writeFileAtomic } from "../lib/file-utils.js";
3
+ import { toMcpError } from "../lib/errors.js";
4
+ import { extractCustomBlocks } from "./merger.js";
5
+ import { deriveClaudeMd } from "./claude.js";
6
+ import { deriveCursorRules } from "./cursor.js";
7
+ import { deriveCopilotInstructions } from "./copilot.js";
8
+ import { deriveGeminiMd } from "./gemini.js";
9
+ import { deriveWindsurfRules } from "./windsurf.js";
10
+ import { deriveClineRules } from "./cline.js";
11
+ import { deriveRooModes } from "./roo.js";
12
+ import { deriveAiderConventions } from "./aider.js";
13
+ export const ALL_TOOLS = ["claude", "cursor", "copilot", "gemini", "windsurf", "cline", "roo", "aider"];
14
+ // ---------------------------------------------------------------------------
15
+ // Tool → file-path mapping
16
+ // ---------------------------------------------------------------------------
17
+ export function toolPath(projectPath, tool) {
18
+ switch (tool) {
19
+ case "claude":
20
+ return path.join(projectPath, "CLAUDE.md");
21
+ case "cursor":
22
+ return path.join(projectPath, ".cursorrules");
23
+ case "copilot":
24
+ return path.join(projectPath, ".github", "copilot-instructions.md");
25
+ case "gemini":
26
+ return path.join(projectPath, "GEMINI.md");
27
+ case "windsurf":
28
+ return path.join(projectPath, ".windsurfrules");
29
+ case "cline":
30
+ return path.join(projectPath, ".clinerules");
31
+ case "roo":
32
+ return path.join(projectPath, ".roomodes");
33
+ case "aider":
34
+ return path.join(projectPath, "CONVENTIONS.md");
35
+ }
36
+ }
37
+ // ---------------------------------------------------------------------------
38
+ // Per-tool content generation
39
+ // ---------------------------------------------------------------------------
40
+ async function deriveContent(tool, options) {
41
+ const { projectPath, agentsMdContent, metadata, preserveCustom = true } = options;
42
+ const shared = { projectPath, agentsMdContent, metadata, preserveCustom };
43
+ switch (tool) {
44
+ case "claude":
45
+ return deriveClaudeMd(shared);
46
+ case "cursor":
47
+ return deriveCursorRules(shared);
48
+ case "copilot":
49
+ return deriveCopilotInstructions(shared);
50
+ case "gemini":
51
+ return deriveGeminiMd(shared);
52
+ case "windsurf":
53
+ return deriveWindsurfRules(shared);
54
+ case "cline":
55
+ return deriveClineRules(shared);
56
+ case "roo":
57
+ return deriveRooModes(shared);
58
+ case "aider":
59
+ return deriveAiderConventions(shared);
60
+ }
61
+ }
62
+ // ---------------------------------------------------------------------------
63
+ // Main entry point
64
+ // ---------------------------------------------------------------------------
65
+ /**
66
+ * Runs all (or selected) derivers and writes the results.
67
+ *
68
+ * AGENTS.md is always written first as the canonical source file.
69
+ * Per-tool errors are caught and returned as `{ error }` entries — one
70
+ * failing tool does not abort the others.
71
+ */
72
+ export async function deriveAll(options) {
73
+ const { projectPath, agentsMdContent, tools = ALL_TOOLS, dryRun = false, } = options;
74
+ const results = [];
75
+ // --- Always write AGENTS.md (canonical) --------------------------------
76
+ const agentsMdPath = path.join(projectPath, "AGENTS.md");
77
+ try {
78
+ if (!dryRun) {
79
+ await writeFileAtomic(agentsMdPath, agentsMdContent);
80
+ }
81
+ results.push({
82
+ tool: "agents-md",
83
+ path: agentsMdPath,
84
+ written: !dryRun,
85
+ customBlocksPreserved: 0,
86
+ skipped: dryRun || undefined,
87
+ });
88
+ }
89
+ catch (e) {
90
+ results.push({
91
+ tool: "agents-md",
92
+ path: agentsMdPath,
93
+ written: false,
94
+ customBlocksPreserved: 0,
95
+ error: toMcpError(e),
96
+ });
97
+ }
98
+ // --- Derive and write each tool file ------------------------------------
99
+ for (const tool of tools) {
100
+ const filePath = toolPath(projectPath, tool);
101
+ try {
102
+ const content = await deriveContent(tool, options);
103
+ const customBlocksPreserved = extractCustomBlocks(content).length;
104
+ if (dryRun) {
105
+ results.push({
106
+ tool,
107
+ path: filePath,
108
+ written: false,
109
+ customBlocksPreserved,
110
+ skipped: true,
111
+ });
112
+ continue;
113
+ }
114
+ await writeFileAtomic(filePath, content);
115
+ results.push({
116
+ tool,
117
+ path: filePath,
118
+ written: true,
119
+ customBlocksPreserved,
120
+ });
121
+ }
122
+ catch (e) {
123
+ results.push({
124
+ tool,
125
+ path: filePath,
126
+ written: false,
127
+ customBlocksPreserved: 0,
128
+ error: toMcpError(e),
129
+ });
130
+ }
131
+ }
132
+ return results;
133
+ }
134
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/derivers/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Returns all text between CUSTOM_START and CUSTOM_END markers.
3
+ * Multiple blocks are supported; each returned string is the inner content
4
+ * (exclusive of the marker lines themselves).
5
+ */
6
+ export declare function extractCustomBlocks(content: string): string[];
7
+ /**
8
+ * Appends custom blocks at the end of the generated content, each wrapped in
9
+ * markers and preceded by a divider on the first block.
10
+ */
11
+ export declare function injectCustomBlocks(generated: string, blocks: string[]): string;
12
+ /**
13
+ * Reads the file at filePath (if it exists) and extracts its custom blocks.
14
+ * Returns [] when the file is missing or contains no custom blocks.
15
+ */
16
+ export declare function loadExistingCustomBlocks(filePath: string): Promise<string[]>;
17
+ /**
18
+ * Wraps user-provided content in the CUSTOM markers so it can be embedded in a
19
+ * managed file.
20
+ */
21
+ export declare function buildCustomSection(userContent: string): string;
22
+ /**
23
+ * Returns true when the file content was written by agents-sync (has the
24
+ * generated-by comment at the top).
25
+ */
26
+ export declare function isManagedByAgentsSync(content: string): boolean;
27
+ /**
28
+ * If the file at filePath exists and was NOT previously managed by agents-sync,
29
+ * returns the entire file content wrapped as a single custom block so it
30
+ * survives the next write. Returns [] when:
31
+ * - the file does not exist
32
+ * - the file is already managed (has the generated-by marker)
33
+ * - the file is empty
34
+ */
35
+ export declare function loadUnmanagedFileAsCustomBlock(filePath: string): Promise<string[]>;
36
+ //# sourceMappingURL=merger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merger.d.ts","sourceRoot":"","sources":["../../src/derivers/merger.ts"],"names":[],"mappings":"AAQA;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAqB7D;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAQ9E;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAIlF;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE9D;AAID;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE9D;AAED;;;;;;;GAOG;AACH,wBAAsB,8BAA8B,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAMxF"}
@@ -0,0 +1,83 @@
1
+ import { readFileSafe } from "../lib/file-utils.js";
2
+ const CUSTOM_START = "<!-- AGENTS-SYNC:CUSTOM:START -->";
3
+ const CUSTOM_END = "<!-- AGENTS-SYNC:CUSTOM:END -->";
4
+ const CUSTOM_DIVIDER = "\n---\n<!-- Custom additions — preserved on re-sync. Edit freely. -->\n";
5
+ /**
6
+ * Returns all text between CUSTOM_START and CUSTOM_END markers.
7
+ * Multiple blocks are supported; each returned string is the inner content
8
+ * (exclusive of the marker lines themselves).
9
+ */
10
+ export function extractCustomBlocks(content) {
11
+ const blocks = [];
12
+ let searchFrom = 0;
13
+ while (true) {
14
+ const startIdx = content.indexOf(CUSTOM_START, searchFrom);
15
+ if (startIdx === -1)
16
+ break;
17
+ const endIdx = content.indexOf(CUSTOM_END, startIdx + CUSTOM_START.length);
18
+ if (endIdx === -1)
19
+ break;
20
+ const inner = content.slice(startIdx + CUSTOM_START.length, endIdx);
21
+ // Only include non-empty blocks (after trimming surrounding newlines).
22
+ if (inner.trim().length > 0) {
23
+ blocks.push(inner);
24
+ }
25
+ searchFrom = endIdx + CUSTOM_END.length;
26
+ }
27
+ return blocks;
28
+ }
29
+ /**
30
+ * Appends custom blocks at the end of the generated content, each wrapped in
31
+ * markers and preceded by a divider on the first block.
32
+ */
33
+ export function injectCustomBlocks(generated, blocks) {
34
+ if (blocks.length === 0)
35
+ return generated;
36
+ const wrapped = blocks
37
+ .map((block) => `${CUSTOM_START}${block}${CUSTOM_END}`)
38
+ .join("\n");
39
+ return `${generated}${CUSTOM_DIVIDER}${wrapped}\n`;
40
+ }
41
+ /**
42
+ * Reads the file at filePath (if it exists) and extracts its custom blocks.
43
+ * Returns [] when the file is missing or contains no custom blocks.
44
+ */
45
+ export async function loadExistingCustomBlocks(filePath) {
46
+ const content = await readFileSafe(filePath);
47
+ if (content === null)
48
+ return [];
49
+ return extractCustomBlocks(content);
50
+ }
51
+ /**
52
+ * Wraps user-provided content in the CUSTOM markers so it can be embedded in a
53
+ * managed file.
54
+ */
55
+ export function buildCustomSection(userContent) {
56
+ return `${CUSTOM_START}\n${userContent}\n${CUSTOM_END}`;
57
+ }
58
+ const MANAGED_MARKER = "<!-- Generated by agents-sync";
59
+ /**
60
+ * Returns true when the file content was written by agents-sync (has the
61
+ * generated-by comment at the top).
62
+ */
63
+ export function isManagedByAgentsSync(content) {
64
+ return content.includes(MANAGED_MARKER);
65
+ }
66
+ /**
67
+ * If the file at filePath exists and was NOT previously managed by agents-sync,
68
+ * returns the entire file content wrapped as a single custom block so it
69
+ * survives the next write. Returns [] when:
70
+ * - the file does not exist
71
+ * - the file is already managed (has the generated-by marker)
72
+ * - the file is empty
73
+ */
74
+ export async function loadUnmanagedFileAsCustomBlock(filePath) {
75
+ const content = await readFileSafe(filePath);
76
+ if (!content || content.trim().length === 0)
77
+ return [];
78
+ if (isManagedByAgentsSync(content))
79
+ return [];
80
+ // Wrap the entire existing file as one preserved block
81
+ return [`\n<!-- Pre-existing file content preserved by agents-sync -->\n${content}\n`];
82
+ }
83
+ //# sourceMappingURL=merger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merger.js","sourceRoot":"","sources":["../../src/derivers/merger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEpD,MAAM,YAAY,GAAG,mCAAmC,CAAC;AACzD,MAAM,UAAU,GAAG,iCAAiC,CAAC;AAErD,MAAM,cAAc,GAClB,yEAAyE,CAAC;AAE5E;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAe;IACjD,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,UAAU,GAAG,CAAC,CAAC;IAEnB,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;QAC3D,IAAI,QAAQ,KAAK,CAAC,CAAC;YAAE,MAAM;QAE3B,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,UAAU,EAAE,QAAQ,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;QAC3E,IAAI,MAAM,KAAK,CAAC,CAAC;YAAE,MAAM;QAEzB,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,QAAQ,GAAG,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACpE,uEAAuE;QACvE,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;QAED,UAAU,GAAG,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC;IAC1C,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,SAAiB,EAAE,MAAgB;IACpE,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAE1C,MAAM,OAAO,GAAG,MAAM;SACnB,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,YAAY,GAAG,KAAK,GAAG,UAAU,EAAE,CAAC;SACtD,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,OAAO,GAAG,SAAS,GAAG,cAAc,GAAG,OAAO,IAAI,CAAC;AACrD,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,QAAgB;IAC7D,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,CAAC;IAC7C,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,EAAE,CAAC;IAChC,OAAO,mBAAmB,CAAC,OAAO,CAAC,CAAC;AACtC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,WAAmB;IACpD,OAAO,GAAG,YAAY,KAAK,WAAW,KAAK,UAAU,EAAE,CAAC;AAC1D,CAAC;AAED,MAAM,cAAc,GAAG,+BAA+B,CAAC;AAEvD;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAAe;IACnD,OAAO,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;AAC1C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,8BAA8B,CAAC,QAAgB;IACnE,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,CAAC;IAC7C,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACvD,IAAI,qBAAqB,CAAC,OAAO,CAAC;QAAE,OAAO,EAAE,CAAC;IAC9C,uDAAuD;IACvD,OAAO,CAAC,kEAAkE,OAAO,IAAI,CAAC,CAAC;AACzF,CAAC"}
@@ -0,0 +1,18 @@
1
+ import type { ProjectMetadata } from "../extractor/schema.js";
2
+ export interface RooDerivationOptions {
3
+ projectPath: string;
4
+ agentsMdContent: string;
5
+ metadata: ProjectMetadata;
6
+ /** @default true */
7
+ preserveCustom?: boolean;
8
+ }
9
+ /**
10
+ * Derives `.roomodes` content for Roo Code.
11
+ *
12
+ * Generates a single custom mode that packages project context — conventions,
13
+ * never rules, and stack information — into Roo Code's JSON format.
14
+ *
15
+ * Does NOT write the file — the caller is responsible.
16
+ */
17
+ export declare function deriveRooModes(options: RooDerivationOptions): Promise<string>;
18
+ //# sourceMappingURL=roo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roo.d.ts","sourceRoot":"","sources":["../../src/derivers/roo.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAG9D,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,eAAe,CAAC;IAC1B,oBAAoB;IACpB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAyDD;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,MAAM,CAAC,CA2DnF"}
@@ -0,0 +1,92 @@
1
+ import path from "node:path";
2
+ import { injectCustomBlocks, loadExistingCustomBlocks } from "./merger.js";
3
+ function escapeRegExp(s) {
4
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
5
+ }
6
+ function extractSection(content, heading) {
7
+ const re = new RegExp(`^##\\s+${escapeRegExp(heading)}\\s*$([\\s\\S]*?)(?=^##\\s|$)`, "mi");
8
+ const match = re.exec(content);
9
+ return match ? match[1].trim() : "";
10
+ }
11
+ function extractSubSection(content, heading) {
12
+ const re = new RegExp(`^###\\s+${escapeRegExp(heading)}\\s*$([\\s\\S]*?)(?=^###\\s|^##\\s|$)`, "mi");
13
+ const match = re.exec(content);
14
+ return match ? match[1].trim() : "";
15
+ }
16
+ function sectionToLines(text) {
17
+ return text
18
+ .split("\n")
19
+ .map((l) => l.replace(/^[\s\-*>]+/, "").trim())
20
+ .filter((l) => l.length > 0);
21
+ }
22
+ function deduplicateLines(items) {
23
+ const seen = new Set();
24
+ return items.filter((item) => {
25
+ const key = item.toLowerCase().trim();
26
+ if (seen.has(key))
27
+ return false;
28
+ seen.add(key);
29
+ return true;
30
+ });
31
+ }
32
+ function toSlug(name) {
33
+ return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "project";
34
+ }
35
+ /**
36
+ * Derives `.roomodes` content for Roo Code.
37
+ *
38
+ * Generates a single custom mode that packages project context — conventions,
39
+ * never rules, and stack information — into Roo Code's JSON format.
40
+ *
41
+ * Does NOT write the file — the caller is responsible.
42
+ */
43
+ export async function deriveRooModes(options) {
44
+ const { projectPath, agentsMdContent, metadata, preserveCustom = true } = options;
45
+ const { project, conventions: metaConventions, boundaries, testing } = metadata;
46
+ const conventionsSection = sectionToLines(extractSection(agentsMdContent, "Conventions"));
47
+ const neverSection = sectionToLines(extractSubSection(agentsMdContent, "Never"));
48
+ const alwaysSection = sectionToLines(extractSubSection(agentsMdContent, "Always"));
49
+ const allConventions = deduplicateLines([...metaConventions, ...conventionsSection]);
50
+ const allNever = deduplicateLines([...boundaries.never, ...neverSection]);
51
+ const allAlways = deduplicateLines([...boundaries.alwaysDo, ...alwaysSection]);
52
+ const fwPart = project.framework ? ` using ${project.framework}` : "";
53
+ const roleDefinition = [
54
+ `You are an expert ${project.language}${fwPart} developer working on ${project.name ?? "this project"}.`,
55
+ project.description ? `\n${project.description}` : "",
56
+ ].filter(Boolean).join(" ");
57
+ const instructionParts = [];
58
+ if (allConventions.length > 0) {
59
+ instructionParts.push("## Conventions\n" + allConventions.map((r) => `- ${r}`).join("\n"));
60
+ }
61
+ if (allNever.length > 0) {
62
+ instructionParts.push("## Never\n" + allNever.map((r) => `- ${r}`).join("\n"));
63
+ }
64
+ if (allAlways.length > 0) {
65
+ instructionParts.push("## Always\n" + allAlways.map((r) => `- ${r}`).join("\n"));
66
+ }
67
+ if (testing.command) {
68
+ instructionParts.push(`## Testing\nRun tests with: \`${testing.command}\``);
69
+ }
70
+ const customInstructions = instructionParts.join("\n\n");
71
+ const mode = {
72
+ slug: toSlug(project.name ?? "project"),
73
+ name: project.name ?? "Project",
74
+ roleDefinition,
75
+ customInstructions,
76
+ groups: ["read", "edit", "browser", "command", "mcp"],
77
+ };
78
+ const roomodes = { customModes: [mode] };
79
+ const generated = JSON.stringify(roomodes, null, 2) + "\n";
80
+ // .roomodes is JSON — custom block injection would corrupt it.
81
+ // If there's an existing file, we merge the customModes arrays instead.
82
+ if (!preserveCustom)
83
+ return generated;
84
+ const existingPath = path.join(projectPath, ".roomodes");
85
+ const existingBlocks = await loadExistingCustomBlocks(existingPath);
86
+ // For JSON files, custom block markers don't apply.
87
+ // Return generated as-is (existing user modes can be manually added).
88
+ return existingBlocks.length > 0
89
+ ? injectCustomBlocks(generated, existingBlocks)
90
+ : generated;
91
+ }
92
+ //# sourceMappingURL=roo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roo.js","sourceRoot":"","sources":["../../src/derivers/roo.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { ProjectMetadata } from "../extractor/schema.js";
2
+ export interface WindsurfDerivationOptions {
3
+ projectPath: string;
4
+ agentsMdContent: string;
5
+ metadata: ProjectMetadata;
6
+ /** @default true */
7
+ preserveCustom?: boolean;
8
+ }
9
+ /**
10
+ * Derives `.windsurfrules` content from AGENTS.md + metadata.
11
+ * Same directive style as .cursorrules — target < 400 words.
12
+ *
13
+ * Does NOT write the file — the caller is responsible for writing.
14
+ */
15
+ export declare function deriveWindsurfRules(options: WindsurfDerivationOptions): Promise<string>;
16
+ //# sourceMappingURL=windsurf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windsurf.d.ts","sourceRoot":"","sources":["../../src/derivers/windsurf.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAG9D,MAAM,WAAW,yBAAyB;IACxC,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,eAAe,CAAC;IAC1B,oBAAoB;IACpB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAyCD;;;;;GAKG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,MAAM,CAAC,CAiE7F"}
@@ -0,0 +1,91 @@
1
+ import path from "node:path";
2
+ import { injectCustomBlocks, loadExistingCustomBlocks } from "./merger.js";
3
+ function escapeRegExp(s) {
4
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
5
+ }
6
+ function extractSection(content, heading) {
7
+ const re = new RegExp(`^##\\s+${escapeRegExp(heading)}\\s*$([\\s\\S]*?)(?=^##\\s|$)`, "mi");
8
+ const match = re.exec(content);
9
+ return match ? match[1].trim() : "";
10
+ }
11
+ function extractSubSection(content, heading) {
12
+ const re = new RegExp(`^###\\s+${escapeRegExp(heading)}\\s*$([\\s\\S]*?)(?=^###\\s|^##\\s|$)`, "mi");
13
+ const match = re.exec(content);
14
+ return match ? match[1].trim() : "";
15
+ }
16
+ function sectionToLines(text) {
17
+ return text
18
+ .split("\n")
19
+ .map((l) => l.replace(/^[\s\-*>]+/, "").trim())
20
+ .filter((l) => l.length > 0);
21
+ }
22
+ function deduplicateLines(items) {
23
+ const seen = new Set();
24
+ return items.filter((item) => {
25
+ const key = item.toLowerCase().trim();
26
+ if (seen.has(key))
27
+ return false;
28
+ seen.add(key);
29
+ return true;
30
+ });
31
+ }
32
+ /**
33
+ * Derives `.windsurfrules` content from AGENTS.md + metadata.
34
+ * Same directive style as .cursorrules — target < 400 words.
35
+ *
36
+ * Does NOT write the file — the caller is responsible for writing.
37
+ */
38
+ export async function deriveWindsurfRules(options) {
39
+ const { projectPath, agentsMdContent, metadata, preserveCustom = true } = options;
40
+ const { project, conventions: metaConventions, gotchas: metaGotchas, boundaries, testing } = metadata;
41
+ const conventionsSection = sectionToLines(extractSection(agentsMdContent, "Conventions"));
42
+ const gotchasSection = sectionToLines(extractSection(agentsMdContent, "Gotchas"));
43
+ const neverSection = sectionToLines(extractSubSection(agentsMdContent, "Never"));
44
+ const allConventions = deduplicateLines([...metaConventions, ...conventionsSection]);
45
+ const allGotchas = deduplicateLines([...metaGotchas, ...gotchasSection]);
46
+ const allNever = deduplicateLines([...boundaries.never, ...neverSection]);
47
+ const lines = [];
48
+ const fwPart = project.framework ? ` / ${project.framework}` : "";
49
+ lines.push(`# .windsurfrules — managed by agents-sync`);
50
+ lines.push(`# Language: ${project.language}${fwPart}`);
51
+ lines.push("");
52
+ if (allConventions.length > 0) {
53
+ lines.push("## Conventions");
54
+ for (const rule of allConventions) {
55
+ lines.push(`- Always: ${rule}`);
56
+ }
57
+ lines.push("");
58
+ }
59
+ if (allGotchas.length > 0) {
60
+ lines.push("## Gotchas");
61
+ for (const gotcha of allGotchas) {
62
+ lines.push(`- Never: ${gotcha}`);
63
+ }
64
+ lines.push("");
65
+ }
66
+ if (allNever.length > 0) {
67
+ lines.push("## Hard boundaries");
68
+ for (const rule of allNever) {
69
+ lines.push(`- Never: ${rule}`);
70
+ }
71
+ lines.push("");
72
+ }
73
+ if (boundaries.alwaysDo.length > 0) {
74
+ lines.push("## Always do");
75
+ for (const rule of boundaries.alwaysDo) {
76
+ lines.push(`- ${rule}`);
77
+ }
78
+ lines.push("");
79
+ }
80
+ if (testing.command) {
81
+ lines.push(`Tests: \`${testing.command}\``);
82
+ lines.push("");
83
+ }
84
+ const generated = lines.join("\n").trimEnd() + "\n";
85
+ if (!preserveCustom)
86
+ return generated;
87
+ const windsurfPath = path.join(projectPath, ".windsurfrules");
88
+ const existingBlocks = await loadExistingCustomBlocks(windsurfPath);
89
+ return injectCustomBlocks(generated, existingBlocks);
90
+ }
91
+ //# sourceMappingURL=windsurf.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windsurf.js","sourceRoot":"","sources":["../../src/derivers/windsurf.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { type ProjectMetadata } from "./schema.js";
2
+ import type { RawCorpus } from "../scanner/index.js";
3
+ export declare function extractMetadata(corpus: RawCorpus): Promise<ProjectMetadata>;
4
+ //# sourceMappingURL=extractor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extractor.d.ts","sourceRoot":"","sources":["../../src/extractor/extractor.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,eAAe,EAAyB,MAAM,aAAa,CAAC;AAC1E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAyBrD,wBAAsB,eAAe,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,eAAe,CAAC,CAmCjF"}