open-agreements 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (243) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +161 -0
  3. package/bin/open-agreements.js +2 -0
  4. package/dist/cli/index.d.ts +2 -0
  5. package/dist/cli/index.d.ts.map +1 -0
  6. package/dist/cli/index.js +102 -0
  7. package/dist/cli/index.js.map +1 -0
  8. package/dist/commands/fill.d.ts +7 -0
  9. package/dist/commands/fill.d.ts.map +1 -0
  10. package/dist/commands/fill.js +84 -0
  11. package/dist/commands/fill.js.map +1 -0
  12. package/dist/commands/list.d.ts +6 -0
  13. package/dist/commands/list.d.ts.map +1 -0
  14. package/dist/commands/list.js +202 -0
  15. package/dist/commands/list.js.map +1 -0
  16. package/dist/commands/recipe.d.ts +21 -0
  17. package/dist/commands/recipe.d.ts.map +1 -0
  18. package/dist/commands/recipe.js +71 -0
  19. package/dist/commands/recipe.js.map +1 -0
  20. package/dist/commands/scan.d.ts +12 -0
  21. package/dist/commands/scan.d.ts.map +1 -0
  22. package/dist/commands/scan.js +122 -0
  23. package/dist/commands/scan.js.map +1 -0
  24. package/dist/commands/validate.d.ts +6 -0
  25. package/dist/commands/validate.d.ts.map +1 -0
  26. package/dist/commands/validate.js +139 -0
  27. package/dist/commands/validate.js.map +1 -0
  28. package/dist/core/command-generation/adapters/claude.d.ts +11 -0
  29. package/dist/core/command-generation/adapters/claude.d.ts.map +1 -0
  30. package/dist/core/command-generation/adapters/claude.js +85 -0
  31. package/dist/core/command-generation/adapters/claude.js.map +1 -0
  32. package/dist/core/command-generation/types.d.ts +14 -0
  33. package/dist/core/command-generation/types.d.ts.map +1 -0
  34. package/dist/core/command-generation/types.js +2 -0
  35. package/dist/core/command-generation/types.js.map +1 -0
  36. package/dist/core/engine.d.ts +13 -0
  37. package/dist/core/engine.d.ts.map +1 -0
  38. package/dist/core/engine.js +149 -0
  39. package/dist/core/engine.js.map +1 -0
  40. package/dist/core/external/index.d.ts +8 -0
  41. package/dist/core/external/index.d.ts.map +1 -0
  42. package/dist/core/external/index.js +92 -0
  43. package/dist/core/external/index.js.map +1 -0
  44. package/dist/core/external/types.d.ts +18 -0
  45. package/dist/core/external/types.d.ts.map +1 -0
  46. package/dist/core/external/types.js +2 -0
  47. package/dist/core/external/types.js.map +1 -0
  48. package/dist/core/fill-pipeline.d.ts +61 -0
  49. package/dist/core/fill-pipeline.d.ts.map +1 -0
  50. package/dist/core/fill-pipeline.js +279 -0
  51. package/dist/core/fill-pipeline.js.map +1 -0
  52. package/dist/core/fill-utils.d.ts +39 -0
  53. package/dist/core/fill-utils.d.ts.map +1 -0
  54. package/dist/core/fill-utils.js +127 -0
  55. package/dist/core/fill-utils.js.map +1 -0
  56. package/dist/core/metadata.d.ts +396 -0
  57. package/dist/core/metadata.d.ts.map +1 -0
  58. package/dist/core/metadata.js +126 -0
  59. package/dist/core/metadata.js.map +1 -0
  60. package/dist/core/recipe/cleaner.d.ts +13 -0
  61. package/dist/core/recipe/cleaner.d.ts.map +1 -0
  62. package/dist/core/recipe/cleaner.js +106 -0
  63. package/dist/core/recipe/cleaner.js.map +1 -0
  64. package/dist/core/recipe/downloader.d.ts +8 -0
  65. package/dist/core/recipe/downloader.d.ts.map +1 -0
  66. package/dist/core/recipe/downloader.js +58 -0
  67. package/dist/core/recipe/downloader.js.map +1 -0
  68. package/dist/core/recipe/index.d.ts +14 -0
  69. package/dist/core/recipe/index.d.ts.map +1 -0
  70. package/dist/core/recipe/index.js +91 -0
  71. package/dist/core/recipe/index.js.map +1 -0
  72. package/dist/core/recipe/ooxml-parts.d.ts +21 -0
  73. package/dist/core/recipe/ooxml-parts.d.ts.map +1 -0
  74. package/dist/core/recipe/ooxml-parts.js +33 -0
  75. package/dist/core/recipe/ooxml-parts.js.map +1 -0
  76. package/dist/core/recipe/patcher.d.ts +17 -0
  77. package/dist/core/recipe/patcher.d.ts.map +1 -0
  78. package/dist/core/recipe/patcher.js +240 -0
  79. package/dist/core/recipe/patcher.js.map +1 -0
  80. package/dist/core/recipe/types.d.ts +28 -0
  81. package/dist/core/recipe/types.d.ts.map +1 -0
  82. package/dist/core/recipe/types.js +2 -0
  83. package/dist/core/recipe/types.js.map +1 -0
  84. package/dist/core/recipe/verifier.d.ts +24 -0
  85. package/dist/core/recipe/verifier.d.ts.map +1 -0
  86. package/dist/core/recipe/verifier.js +143 -0
  87. package/dist/core/recipe/verifier.js.map +1 -0
  88. package/dist/core/validation/external.d.ts +16 -0
  89. package/dist/core/validation/external.d.ts.map +1 -0
  90. package/dist/core/validation/external.js +106 -0
  91. package/dist/core/validation/external.js.map +1 -0
  92. package/dist/core/validation/license.d.ts +15 -0
  93. package/dist/core/validation/license.d.ts.map +1 -0
  94. package/dist/core/validation/license.js +30 -0
  95. package/dist/core/validation/license.js.map +1 -0
  96. package/dist/core/validation/output.d.ts +12 -0
  97. package/dist/core/validation/output.d.ts.map +1 -0
  98. package/dist/core/validation/output.js +47 -0
  99. package/dist/core/validation/output.js.map +1 -0
  100. package/dist/core/validation/recipe.d.ts +19 -0
  101. package/dist/core/validation/recipe.d.ts.map +1 -0
  102. package/dist/core/validation/recipe.js +148 -0
  103. package/dist/core/validation/recipe.js.map +1 -0
  104. package/dist/core/validation/template.d.ts +11 -0
  105. package/dist/core/validation/template.d.ts.map +1 -0
  106. package/dist/core/validation/template.js +159 -0
  107. package/dist/core/validation/template.js.map +1 -0
  108. package/dist/index.d.ts +13 -0
  109. package/dist/index.d.ts.map +1 -0
  110. package/dist/index.js +19 -0
  111. package/dist/index.js.map +1 -0
  112. package/dist/utils/paths.d.ts +15 -0
  113. package/dist/utils/paths.d.ts.map +1 -0
  114. package/dist/utils/paths.js +43 -0
  115. package/dist/utils/paths.js.map +1 -0
  116. package/external/LICENSE +27 -0
  117. package/external/README.md +38 -0
  118. package/external/yc-safe-discount/README.md +16 -0
  119. package/external/yc-safe-discount/clean.json +4 -0
  120. package/external/yc-safe-discount/metadata.yaml +71 -0
  121. package/external/yc-safe-discount/replacements.json +13 -0
  122. package/external/yc-safe-discount/template.docx +0 -0
  123. package/external/yc-safe-mfn/README.md +16 -0
  124. package/external/yc-safe-mfn/clean.json +4 -0
  125. package/external/yc-safe-mfn/metadata.yaml +64 -0
  126. package/external/yc-safe-mfn/replacements.json +12 -0
  127. package/external/yc-safe-mfn/template.docx +0 -0
  128. package/external/yc-safe-pro-rata-side-letter/README.md +16 -0
  129. package/external/yc-safe-pro-rata-side-letter/clean.json +4 -0
  130. package/external/yc-safe-pro-rata-side-letter/metadata.yaml +49 -0
  131. package/external/yc-safe-pro-rata-side-letter/replacements.json +9 -0
  132. package/external/yc-safe-pro-rata-side-letter/template.docx +0 -0
  133. package/external/yc-safe-valuation-cap/README.md +16 -0
  134. package/external/yc-safe-valuation-cap/clean.json +4 -0
  135. package/external/yc-safe-valuation-cap/metadata.yaml +64 -0
  136. package/external/yc-safe-valuation-cap/replacements.json +12 -0
  137. package/external/yc-safe-valuation-cap/template.docx +0 -0
  138. package/package.json +77 -0
  139. package/recipes/nvca-certificate-of-incorporation/clean.json +8 -0
  140. package/recipes/nvca-certificate-of-incorporation/metadata.yaml +43 -0
  141. package/recipes/nvca-certificate-of-incorporation/replacements.json +9 -0
  142. package/recipes/nvca-certificate-of-incorporation/schema.json +11 -0
  143. package/recipes/nvca-indemnification-agreement/clean.json +7 -0
  144. package/recipes/nvca-indemnification-agreement/metadata.yaml +83 -0
  145. package/recipes/nvca-indemnification-agreement/replacements.json +17 -0
  146. package/recipes/nvca-indemnification-agreement/schema.json +19 -0
  147. package/recipes/nvca-investors-rights-agreement/clean.json +12 -0
  148. package/recipes/nvca-investors-rights-agreement/metadata.yaml +75 -0
  149. package/recipes/nvca-investors-rights-agreement/replacements.json +18 -0
  150. package/recipes/nvca-investors-rights-agreement/schema.json +18 -0
  151. package/recipes/nvca-management-rights-letter/clean.json +7 -0
  152. package/recipes/nvca-management-rights-letter/metadata.yaml +50 -0
  153. package/recipes/nvca-management-rights-letter/replacements.json +11 -0
  154. package/recipes/nvca-management-rights-letter/schema.json +13 -0
  155. package/recipes/nvca-rofr-co-sale-agreement/clean.json +7 -0
  156. package/recipes/nvca-rofr-co-sale-agreement/metadata.yaml +80 -0
  157. package/recipes/nvca-rofr-co-sale-agreement/replacements.json +17 -0
  158. package/recipes/nvca-rofr-co-sale-agreement/schema.json +19 -0
  159. package/recipes/nvca-stock-purchase-agreement/clean.json +10 -0
  160. package/recipes/nvca-stock-purchase-agreement/metadata.yaml +74 -0
  161. package/recipes/nvca-stock-purchase-agreement/replacements.json +20 -0
  162. package/recipes/nvca-stock-purchase-agreement/schema.json +19 -0
  163. package/recipes/nvca-voting-agreement/README.md +53 -0
  164. package/recipes/nvca-voting-agreement/clean.json +7 -0
  165. package/recipes/nvca-voting-agreement/metadata.yaml +70 -0
  166. package/recipes/nvca-voting-agreement/replacements.json +18 -0
  167. package/recipes/nvca-voting-agreement/schema.json +28 -0
  168. package/skills/open-agreements/SKILL.md +166 -0
  169. package/templates/bonterms-mutual-nda/README.md +27 -0
  170. package/templates/bonterms-mutual-nda/metadata.yaml +58 -0
  171. package/templates/bonterms-mutual-nda/template.docx +0 -0
  172. package/templates/bonterms-professional-services-agreement/README.md +24 -0
  173. package/templates/bonterms-professional-services-agreement/metadata.yaml +40 -0
  174. package/templates/bonterms-professional-services-agreement/template.docx +0 -0
  175. package/templates/common-paper-ai-addendum/README.md +23 -0
  176. package/templates/common-paper-ai-addendum/metadata.yaml +33 -0
  177. package/templates/common-paper-ai-addendum/template.docx +0 -0
  178. package/templates/common-paper-ai-addendum-in-app/README.md +21 -0
  179. package/templates/common-paper-ai-addendum-in-app/metadata.yaml +23 -0
  180. package/templates/common-paper-ai-addendum-in-app/template.docx +0 -0
  181. package/templates/common-paper-amendment/README.md +27 -0
  182. package/templates/common-paper-amendment/metadata.yaml +53 -0
  183. package/templates/common-paper-amendment/template.docx +0 -0
  184. package/templates/common-paper-business-associate-agreement/README.md +29 -0
  185. package/templates/common-paper-business-associate-agreement/metadata.yaml +63 -0
  186. package/templates/common-paper-business-associate-agreement/template.docx +0 -0
  187. package/templates/common-paper-cloud-service-agreement/README.md +32 -0
  188. package/templates/common-paper-cloud-service-agreement/metadata.yaml +488 -0
  189. package/templates/common-paper-cloud-service-agreement/template.docx +0 -0
  190. package/templates/common-paper-csa-click-through/README.md +33 -0
  191. package/templates/common-paper-csa-click-through/metadata.yaml +83 -0
  192. package/templates/common-paper-csa-click-through/template.docx +0 -0
  193. package/templates/common-paper-csa-with-ai/README.md +49 -0
  194. package/templates/common-paper-csa-with-ai/metadata.yaml +166 -0
  195. package/templates/common-paper-csa-with-ai/template.docx +0 -0
  196. package/templates/common-paper-csa-with-sla/README.md +53 -0
  197. package/templates/common-paper-csa-with-sla/metadata.yaml +185 -0
  198. package/templates/common-paper-csa-with-sla/template.docx +0 -0
  199. package/templates/common-paper-csa-without-sla/README.md +47 -0
  200. package/templates/common-paper-csa-without-sla/metadata.yaml +155 -0
  201. package/templates/common-paper-csa-without-sla/template.docx +0 -0
  202. package/templates/common-paper-data-processing-agreement/README.md +46 -0
  203. package/templates/common-paper-data-processing-agreement/metadata.yaml +149 -0
  204. package/templates/common-paper-data-processing-agreement/template.docx +0 -0
  205. package/templates/common-paper-design-partner-agreement/README.md +29 -0
  206. package/templates/common-paper-design-partner-agreement/metadata.yaml +65 -0
  207. package/templates/common-paper-design-partner-agreement/template.docx +0 -0
  208. package/templates/common-paper-independent-contractor-agreement/README.md +27 -0
  209. package/templates/common-paper-independent-contractor-agreement/metadata.yaml +55 -0
  210. package/templates/common-paper-independent-contractor-agreement/template.docx +0 -0
  211. package/templates/common-paper-letter-of-intent/README.md +25 -0
  212. package/templates/common-paper-letter-of-intent/metadata.yaml +43 -0
  213. package/templates/common-paper-letter-of-intent/template.docx +0 -0
  214. package/templates/common-paper-mutual-nda/README.md +29 -0
  215. package/templates/common-paper-mutual-nda/metadata.yaml +59 -0
  216. package/templates/common-paper-mutual-nda/template.docx +0 -0
  217. package/templates/common-paper-one-way-nda/README.md +27 -0
  218. package/templates/common-paper-one-way-nda/metadata.yaml +60 -0
  219. package/templates/common-paper-one-way-nda/template.docx +0 -0
  220. package/templates/common-paper-order-form/README.md +36 -0
  221. package/templates/common-paper-order-form/metadata.yaml +98 -0
  222. package/templates/common-paper-order-form/template.docx +0 -0
  223. package/templates/common-paper-order-form-with-sla/README.md +42 -0
  224. package/templates/common-paper-order-form-with-sla/metadata.yaml +129 -0
  225. package/templates/common-paper-order-form-with-sla/template.docx +0 -0
  226. package/templates/common-paper-partnership-agreement/README.md +34 -0
  227. package/templates/common-paper-partnership-agreement/metadata.yaml +90 -0
  228. package/templates/common-paper-partnership-agreement/template.docx +0 -0
  229. package/templates/common-paper-pilot-agreement/README.md +34 -0
  230. package/templates/common-paper-pilot-agreement/metadata.yaml +90 -0
  231. package/templates/common-paper-pilot-agreement/template.docx +0 -0
  232. package/templates/common-paper-professional-services-agreement/README.md +44 -0
  233. package/templates/common-paper-professional-services-agreement/metadata.yaml +141 -0
  234. package/templates/common-paper-professional-services-agreement/template.docx +0 -0
  235. package/templates/common-paper-software-license-agreement/README.md +18 -0
  236. package/templates/common-paper-software-license-agreement/metadata.yaml +13 -0
  237. package/templates/common-paper-software-license-agreement/template.docx +0 -0
  238. package/templates/common-paper-statement-of-work/README.md +32 -0
  239. package/templates/common-paper-statement-of-work/metadata.yaml +78 -0
  240. package/templates/common-paper-statement-of-work/template.docx +0 -0
  241. package/templates/common-paper-term-sheet/README.md +22 -0
  242. package/templates/common-paper-term-sheet/metadata.yaml +28 -0
  243. package/templates/common-paper-term-sheet/template.docx +0 -0
@@ -0,0 +1,30 @@
1
+ import { loadMetadata } from '../metadata.js';
2
+ /**
3
+ * Validate a template's license metadata.
4
+ *
5
+ * The allow_derivatives field means "the committed source DOCX must not be
6
+ * modified" when false. It does NOT prevent the tool from rendering filled
7
+ * output — that decision is made by the fill command based on directory
8
+ * context (templates/ vs external/).
9
+ */
10
+ export function validateLicense(templateDir, templateId) {
11
+ const errors = [];
12
+ let metadata;
13
+ try {
14
+ metadata = loadMetadata(templateDir);
15
+ }
16
+ catch (err) {
17
+ return {
18
+ templateId,
19
+ valid: false,
20
+ errors: [`Failed to load metadata: ${err.message}`],
21
+ };
22
+ }
23
+ // CC-BY-4.0 and CC-BY-ND-4.0 require attribution text
24
+ if ((metadata.license === 'CC-BY-4.0' || metadata.license === 'CC-BY-ND-4.0') &&
25
+ !metadata.attribution_text.trim()) {
26
+ errors.push(`${metadata.license} license requires attribution_text to be non-empty.`);
27
+ }
28
+ return { templateId, valid: errors.length === 0, errors };
29
+ }
30
+ //# sourceMappingURL=license.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"license.js","sourceRoot":"","sources":["../../../src/core/validation/license.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAQ9C;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,WAAmB,EAAE,UAAkB;IACrE,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,IAAI,QAAQ,CAAC;IACb,IAAI,CAAC;QACH,QAAQ,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC;IACvC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,UAAU;YACV,KAAK,EAAE,KAAK;YACZ,MAAM,EAAE,CAAC,4BAA6B,GAAa,CAAC,OAAO,EAAE,CAAC;SAC/D,CAAC;IACJ,CAAC;IAED,sDAAsD;IACtD,IACE,CAAC,QAAQ,CAAC,OAAO,KAAK,WAAW,IAAI,QAAQ,CAAC,OAAO,KAAK,cAAc,CAAC;QACzE,CAAC,QAAQ,CAAC,gBAAgB,CAAC,IAAI,EAAE,EACjC,CAAC;QACD,MAAM,CAAC,IAAI,CACT,GAAG,QAAQ,CAAC,OAAO,qDAAqD,CACzE,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;AAC5D,CAAC"}
@@ -0,0 +1,12 @@
1
+ export interface OutputValidationResult {
2
+ valid: boolean;
3
+ errors: string[];
4
+ sourceHeadingCount: number;
5
+ outputHeadingCount: number;
6
+ }
7
+ /**
8
+ * Validate that a rendered DOCX preserves the heading structure of the source template.
9
+ * Extracts word/document.xml via AdmZip before scanning for heading styles.
10
+ */
11
+ export declare function validateOutput(sourceDocxPath: string, outputDocxPath: string): OutputValidationResult;
12
+ //# sourceMappingURL=output.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../../src/core/validation/output.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,cAAc,EAAE,MAAM,EACtB,cAAc,EAAE,MAAM,GACrB,sBAAsB,CAiCxB"}
@@ -0,0 +1,47 @@
1
+ import AdmZip from 'adm-zip';
2
+ /**
3
+ * Validate that a rendered DOCX preserves the heading structure of the source template.
4
+ * Extracts word/document.xml via AdmZip before scanning for heading styles.
5
+ */
6
+ export function validateOutput(sourceDocxPath, outputDocxPath) {
7
+ const errors = [];
8
+ let sourceXml;
9
+ let outputXml;
10
+ try {
11
+ sourceXml = extractDocumentXml(sourceDocxPath);
12
+ outputXml = extractDocumentXml(outputDocxPath);
13
+ }
14
+ catch (err) {
15
+ return {
16
+ valid: false,
17
+ errors: [`Failed to read files: ${err.message}`],
18
+ sourceHeadingCount: 0,
19
+ outputHeadingCount: 0,
20
+ };
21
+ }
22
+ const sourceHeadings = countHeadings(sourceXml);
23
+ const outputHeadings = countHeadings(outputXml);
24
+ if (sourceHeadings !== outputHeadings) {
25
+ errors.push(`Heading count mismatch: source has ${sourceHeadings} headings, output has ${outputHeadings}. ` +
26
+ 'Template rendering may have dropped or duplicated content.');
27
+ }
28
+ return {
29
+ valid: errors.length === 0,
30
+ errors,
31
+ sourceHeadingCount: sourceHeadings,
32
+ outputHeadingCount: outputHeadings,
33
+ };
34
+ }
35
+ function extractDocumentXml(docxPath) {
36
+ const zip = new AdmZip(docxPath);
37
+ const entry = zip.getEntry('word/document.xml');
38
+ if (!entry)
39
+ return '';
40
+ return entry.getData().toString('utf-8');
41
+ }
42
+ function countHeadings(xml) {
43
+ const headingPattern = /w:val="Heading\d"/g;
44
+ const matches = xml.match(headingPattern);
45
+ return matches ? matches.length : 0;
46
+ }
47
+ //# sourceMappingURL=output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../../../src/core/validation/output.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,SAAS,CAAC;AAS7B;;;GAGG;AACH,MAAM,UAAU,cAAc,CAC5B,cAAsB,EACtB,cAAsB;IAEtB,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,IAAI,SAAiB,CAAC;IACtB,IAAI,SAAiB,CAAC;IACtB,IAAI,CAAC;QACH,SAAS,GAAG,kBAAkB,CAAC,cAAc,CAAC,CAAC;QAC/C,SAAS,GAAG,kBAAkB,CAAC,cAAc,CAAC,CAAC;IACjD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,KAAK,EAAE,KAAK;YACZ,MAAM,EAAE,CAAC,yBAA0B,GAAa,CAAC,OAAO,EAAE,CAAC;YAC3D,kBAAkB,EAAE,CAAC;YACrB,kBAAkB,EAAE,CAAC;SACtB,CAAC;IACJ,CAAC;IAED,MAAM,cAAc,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC;IAChD,MAAM,cAAc,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC;IAEhD,IAAI,cAAc,KAAK,cAAc,EAAE,CAAC;QACtC,MAAM,CAAC,IAAI,CACT,sCAAsC,cAAc,yBAAyB,cAAc,IAAI;YAC/F,4DAA4D,CAC7D,CAAC;IACJ,CAAC;IAED,OAAO;QACL,KAAK,EAAE,MAAM,CAAC,MAAM,KAAK,CAAC;QAC1B,MAAM;QACN,kBAAkB,EAAE,cAAc;QAClC,kBAAkB,EAAE,cAAc;KACnC,CAAC;AACJ,CAAC;AAED,SAAS,kBAAkB,CAAC,QAAgB;IAC1C,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC;IACjC,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC;IAChD,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IACtB,OAAO,KAAK,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AAC3C,CAAC;AAED,SAAS,aAAa,CAAC,GAAW;IAChC,MAAM,cAAc,GAAG,oBAAoB,CAAC;IAC5C,MAAM,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IAC1C,OAAO,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AACtC,CAAC"}
@@ -0,0 +1,19 @@
1
+ export interface RecipeValidationResult {
2
+ recipeId: string;
3
+ valid: boolean;
4
+ scaffold: boolean;
5
+ errors: string[];
6
+ warnings: string[];
7
+ }
8
+ /**
9
+ * Validate a recipe directory:
10
+ * - No .docx files (copyrighted content must not be committed)
11
+ * - metadata.yaml validates against schema
12
+ * - For non-scaffold recipes: replacements.json, schema.json present and valid
13
+ * - Replacement values must be valid {identifier} tags
14
+ * - In strict mode: scaffolds are errors, all files required
15
+ */
16
+ export declare function validateRecipe(recipeDir: string, recipeId: string, options?: {
17
+ strict?: boolean;
18
+ }): RecipeValidationResult;
19
+ //# sourceMappingURL=recipe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recipe.d.ts","sourceRoot":"","sources":["../../../src/core/validation/recipe.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AASD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAC7B,sBAAsB,CA8IxB"}
@@ -0,0 +1,148 @@
1
+ import { readdirSync, existsSync, readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { validateRecipeMetadata, loadRecipeMetadata } from '../metadata.js';
4
+ import { CleanConfigSchema } from '../metadata.js';
5
+ /** Pattern for valid template tags within replacement values */
6
+ const TAG_RE = /\{[a-z_][a-z0-9_]*\}/g;
7
+ /** Pattern for any curly-brace token (to detect control tags) */
8
+ const ANY_BRACE_RE = /\{[^}]+\}/g;
9
+ /** Only simple identifiers inside braces are allowed */
10
+ const SAFE_TAG_RE = /^\{[a-z_][a-z0-9_]*\}$/;
11
+ /**
12
+ * Validate a recipe directory:
13
+ * - No .docx files (copyrighted content must not be committed)
14
+ * - metadata.yaml validates against schema
15
+ * - For non-scaffold recipes: replacements.json, schema.json present and valid
16
+ * - Replacement values must be valid {identifier} tags
17
+ * - In strict mode: scaffolds are errors, all files required
18
+ */
19
+ export function validateRecipe(recipeDir, recipeId, options) {
20
+ const errors = [];
21
+ const warnings = [];
22
+ const strict = options?.strict ?? false;
23
+ // Check for .docx files (forbidden in recipe dirs)
24
+ const files = readdirSync(recipeDir);
25
+ const docxFiles = files.filter((f) => f.toLowerCase().endsWith('.docx'));
26
+ if (docxFiles.length > 0) {
27
+ errors.push(`Copyrighted .docx file(s) found: ${docxFiles.join(', ')}. Recipes must not contain source documents.`);
28
+ }
29
+ // Validate metadata
30
+ const metaResult = validateRecipeMetadata(recipeDir);
31
+ if (!metaResult.valid) {
32
+ errors.push(...metaResult.errors.map((e) => `metadata: ${e}`));
33
+ return { recipeId, valid: false, scaffold: false, errors, warnings };
34
+ }
35
+ // Scaffold detection: if only metadata.yaml exists, this is a scaffold
36
+ const hasReplacements = existsSync(join(recipeDir, 'replacements.json'));
37
+ const hasSchema = existsSync(join(recipeDir, 'schema.json'));
38
+ const isScaffold = !hasReplacements && !hasSchema;
39
+ if (isScaffold) {
40
+ if (strict) {
41
+ errors.push('Scaffold recipe (metadata-only): not runnable. Use non-strict mode to allow scaffolds.');
42
+ }
43
+ else {
44
+ warnings.push('Scaffold recipe (metadata-only): not runnable');
45
+ }
46
+ return { recipeId, valid: errors.length === 0, scaffold: true, errors, warnings };
47
+ }
48
+ // Validate replacements.json
49
+ if (hasReplacements) {
50
+ try {
51
+ const raw = readFileSync(join(recipeDir, 'replacements.json'), 'utf-8');
52
+ const replacements = JSON.parse(raw);
53
+ if (typeof replacements !== 'object' || replacements === null) {
54
+ errors.push('replacements.json must be a JSON object');
55
+ }
56
+ else {
57
+ for (const [key, value] of Object.entries(replacements)) {
58
+ if (typeof value !== 'string') {
59
+ errors.push(`replacements.json: value for "${key}" must be a string`);
60
+ continue;
61
+ }
62
+ // Value must contain at least one {identifier} tag
63
+ const tags = value.match(TAG_RE);
64
+ if (!tags || tags.length === 0) {
65
+ errors.push(`replacements.json: value for "${key}" must contain at least one {identifier} tag, got "${value}"`);
66
+ }
67
+ // All curly-brace tokens in value must be safe identifiers (no control tags)
68
+ const allBraces = value.match(ANY_BRACE_RE);
69
+ if (allBraces) {
70
+ for (const token of allBraces) {
71
+ if (!SAFE_TAG_RE.test(token)) {
72
+ errors.push(`replacements.json: unsafe tag "${token}" in value for "${key}". Only {identifier} tags allowed.`);
73
+ }
74
+ }
75
+ }
76
+ // Value must not contain the source key (infinite loop prevention)
77
+ if (value.includes(key)) {
78
+ errors.push(`replacements.json: value for "${key}" contains the key itself (would cause infinite loop)`);
79
+ }
80
+ }
81
+ }
82
+ }
83
+ catch (err) {
84
+ errors.push(`replacements.json: ${err.message}`);
85
+ }
86
+ }
87
+ else {
88
+ if (strict) {
89
+ errors.push('replacements.json not found (required for runnable recipes)');
90
+ }
91
+ else {
92
+ warnings.push('replacements.json not found (required for runnable recipes)');
93
+ }
94
+ }
95
+ // schema.json is required for non-scaffold recipes
96
+ if (!hasSchema) {
97
+ if (strict) {
98
+ errors.push('schema.json not found (required for runnable recipes)');
99
+ }
100
+ else {
101
+ warnings.push('schema.json not found (required for runnable recipes)');
102
+ }
103
+ }
104
+ // Validate schema.json field coverage
105
+ if (hasSchema && hasReplacements) {
106
+ try {
107
+ const schema = JSON.parse(readFileSync(join(recipeDir, 'schema.json'), 'utf-8'));
108
+ const replacements = JSON.parse(readFileSync(join(recipeDir, 'replacements.json'), 'utf-8'));
109
+ const schemaFields = new Set((schema.fields ?? schema).map?.((f) => f.name) ?? Object.keys(schema));
110
+ // Check that replacement targets reference schema fields
111
+ for (const value of Object.values(replacements)) {
112
+ const tagMatch = value.match(/^\{(\w+)\}$/);
113
+ if (tagMatch) {
114
+ const fieldName = tagMatch[1];
115
+ if (!schemaFields.has(fieldName)) {
116
+ warnings.push(`Replacement target {${fieldName}} not found in schema.json`);
117
+ }
118
+ }
119
+ }
120
+ }
121
+ catch {
122
+ // Already validated above
123
+ }
124
+ }
125
+ // Validate clean.json if present
126
+ const cleanPath = join(recipeDir, 'clean.json');
127
+ if (existsSync(cleanPath)) {
128
+ try {
129
+ const raw = readFileSync(cleanPath, 'utf-8');
130
+ CleanConfigSchema.parse(JSON.parse(raw));
131
+ }
132
+ catch {
133
+ errors.push(`clean.json: invalid format`);
134
+ }
135
+ }
136
+ // Warn if source_sha256 is missing (fill will skip integrity verification)
137
+ try {
138
+ const meta = loadRecipeMetadata(recipeDir);
139
+ if (!meta.source_sha256) {
140
+ warnings.push('No source_sha256 in metadata — fill will skip integrity verification');
141
+ }
142
+ }
143
+ catch {
144
+ // metadata validation already handled above
145
+ }
146
+ return { recipeId, valid: errors.length === 0, scaffold: false, errors, warnings };
147
+ }
148
+ //# sourceMappingURL=recipe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recipe.js","sourceRoot":"","sources":["../../../src/core/validation/recipe.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ export interface TemplateValidationResult {
2
+ templateId: string;
3
+ valid: boolean;
4
+ errors: string[];
5
+ warnings: string[];
6
+ }
7
+ /**
8
+ * Validate that a template's metadata fields match the placeholders in its DOCX file.
9
+ */
10
+ export declare function validateTemplate(templateDir: string, templateId: string): TemplateValidationResult;
11
+ //# sourceMappingURL=template.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../../../src/core/validation/template.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,wBAAwB;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AA+BD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,wBAAwB,CAmFlG"}
@@ -0,0 +1,159 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import AdmZip from 'adm-zip';
4
+ import { loadMetadata } from '../metadata.js';
5
+ /**
6
+ * Extract text content from a DOCX file by unzipping and reading word/document.xml.
7
+ * Concatenates <w:t> text within each <w:p> paragraph, then joins paragraphs with
8
+ * newlines to prevent false {tag} matches across element boundaries.
9
+ */
10
+ function extractDocxText(docxPath) {
11
+ const zip = new AdmZip(docxPath);
12
+ const documentXml = zip.getEntry('word/document.xml');
13
+ if (!documentXml)
14
+ return '';
15
+ const xml = documentXml.getData().toString('utf-8');
16
+ const paragraphs = [];
17
+ const paraRegex = /<w:p[\s>][\s\S]*?<\/w:p>/g;
18
+ let paraMatch;
19
+ while ((paraMatch = paraRegex.exec(xml)) !== null) {
20
+ const paraXml = paraMatch[0];
21
+ const textParts = [];
22
+ const tRegex = /<w:t[^>]*>([^<]*)<\/w:t>/g;
23
+ let tMatch;
24
+ while ((tMatch = tRegex.exec(paraXml)) !== null) {
25
+ textParts.push(tMatch[1]);
26
+ }
27
+ if (textParts.length > 0) {
28
+ paragraphs.push(textParts.join(''));
29
+ }
30
+ }
31
+ return paragraphs.join('\n');
32
+ }
33
+ /**
34
+ * Validate that a template's metadata fields match the placeholders in its DOCX file.
35
+ */
36
+ export function validateTemplate(templateDir, templateId) {
37
+ const errors = [];
38
+ const warnings = [];
39
+ let metadata;
40
+ try {
41
+ metadata = loadMetadata(templateDir);
42
+ }
43
+ catch (err) {
44
+ return {
45
+ templateId,
46
+ valid: false,
47
+ errors: [`Failed to load metadata: ${err.message}`],
48
+ warnings: [],
49
+ };
50
+ }
51
+ const templatePath = join(templateDir, 'template.docx');
52
+ if (!existsSync(templatePath)) {
53
+ return {
54
+ templateId,
55
+ valid: false,
56
+ errors: ['template.docx not found in template directory'],
57
+ warnings: [],
58
+ };
59
+ }
60
+ // Extract text from DOCX and find {tag} placeholders and {IF field} conditionals
61
+ const text = extractDocxText(templatePath);
62
+ const placeholderRegex = /\{(\w+)\}/g;
63
+ const foundTags = new Set();
64
+ let match;
65
+ while ((match = placeholderRegex.exec(text)) !== null) {
66
+ foundTags.add(match[1]);
67
+ }
68
+ // Also find fields used in IF conditions (boolean fields appear here, not as {field})
69
+ const conditionalRegex = /\{IF !?(\w+)\}/g;
70
+ const foundConditionalFields = new Set();
71
+ let condMatch;
72
+ while ((condMatch = conditionalRegex.exec(text)) !== null) {
73
+ foundConditionalFields.add(condMatch[1]);
74
+ }
75
+ const metadataFieldNames = new Set(metadata.fields.map((f) => f.name));
76
+ // Security: scan for docx-templates control/code tags that should not exist
77
+ // in open-source templates. Only simple {identifier} tags are allowed.
78
+ const rawXml = extractRawDocumentXml(templatePath);
79
+ if (rawXml) {
80
+ scanForUnsafeTemplateTags(rawXml, errors);
81
+ }
82
+ // Check for fields in metadata but not in DOCX
83
+ for (const fieldName of metadataFieldNames) {
84
+ // A field can appear as {field} (simple tag) or in {IF field}/{IF !field} (conditional)
85
+ const inDocx = foundTags.has(fieldName) || foundConditionalFields.has(fieldName);
86
+ if (!inDocx) {
87
+ const field = metadata.fields.find((f) => f.name === fieldName);
88
+ if (field?.required) {
89
+ errors.push(`Required field "${fieldName}" defined in metadata but not found as {${fieldName}} in template.docx`);
90
+ }
91
+ else {
92
+ warnings.push(`Optional field "${fieldName}" defined in metadata but not found as {${fieldName}} in template.docx`);
93
+ }
94
+ }
95
+ }
96
+ // Check for placeholders in DOCX but not in metadata
97
+ // Skip control tokens (IF, END) that aren't field names
98
+ const controlTokens = new Set(['IF', 'END']);
99
+ for (const tag of foundTags) {
100
+ if (controlTokens.has(tag))
101
+ continue;
102
+ if (!metadataFieldNames.has(tag)) {
103
+ warnings.push(`Placeholder {${tag}} found in template.docx but not defined in metadata fields`);
104
+ }
105
+ }
106
+ return { templateId, valid: errors.length === 0, errors, warnings };
107
+ }
108
+ /**
109
+ * Extract raw word/document.xml string from a DOCX file.
110
+ */
111
+ function extractRawDocumentXml(docxPath) {
112
+ const zip = new AdmZip(docxPath);
113
+ const entry = zip.getEntry('word/document.xml');
114
+ if (!entry)
115
+ return null;
116
+ return entry.getData().toString('utf-8');
117
+ }
118
+ /** Allowed tag pattern: simple {identifier}, {IF [!]identifier}, or {END-IF}. */
119
+ const SAFE_TAG_RE = /^\{(?:[a-zA-Z_][a-zA-Z0-9_]*|IF !?[a-zA-Z_][a-zA-Z0-9_]*|END-IF)\}$/;
120
+ /**
121
+ * Scan the raw OOXML text content for any {…} tokens and reject ones that
122
+ * are not simple identifiers. This blocks docx-templates control tags
123
+ * ({#if}, {/if}, {>partial}, {= expression}, etc.) that could execute
124
+ * arbitrary code in the Node VM sandbox.
125
+ *
126
+ * We extract text from <w:t> elements and scan for curly-brace tokens,
127
+ * then also check across run boundaries within paragraphs.
128
+ */
129
+ function scanForUnsafeTemplateTags(xml, errors) {
130
+ // Extract all text content from <w:t> elements and reassemble per-paragraph
131
+ const paragraphs = [];
132
+ const paraRegex = /<w:p[\s>][\s\S]*?<\/w:p>/g;
133
+ let paraMatch;
134
+ while ((paraMatch = paraRegex.exec(xml)) !== null) {
135
+ const paraXml = paraMatch[0];
136
+ const textParts = [];
137
+ const tRegex = /<w:t[^>]*>([^<]*)<\/w:t>/g;
138
+ let tMatch;
139
+ while ((tMatch = tRegex.exec(paraXml)) !== null) {
140
+ textParts.push(tMatch[1]);
141
+ }
142
+ if (textParts.length > 0) {
143
+ paragraphs.push(textParts.join(''));
144
+ }
145
+ }
146
+ const fullText = paragraphs.join('\n');
147
+ // Find all {…} tokens in the reassembled text
148
+ const tokenRegex = /\{[^}]+\}/g;
149
+ let tokenMatch;
150
+ while ((tokenMatch = tokenRegex.exec(fullText)) !== null) {
151
+ const token = tokenMatch[0];
152
+ if (!SAFE_TAG_RE.test(token)) {
153
+ errors.push(`Unsafe template tag "${token}" found in template.docx. ` +
154
+ `Only simple {identifier}, {IF [!]identifier}, and {END-IF} tags are allowed. ` +
155
+ `Control tags ({#...}, {/...}, {>...}, {=...}) are not permitted in open-source templates.`);
156
+ }
157
+ }
158
+ }
159
+ //# sourceMappingURL=template.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template.js","sourceRoot":"","sources":["../../../src/core/validation/template.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export { fillTemplate, type FillOptions, type FillResult } from './core/engine.js';
2
+ export { loadMetadata, validateMetadata, loadRecipeMetadata, validateRecipeMetadata, loadCleanConfig, TemplateMetadataSchema, RecipeMetadataSchema, CleanConfigSchema, LicenseEnum, FieldDefinitionSchema, type TemplateMetadata, type RecipeMetadata, type CleanConfig, type FieldDefinition, type License, } from './core/metadata.js';
3
+ export { runExternalFill, type ExternalFillOptions, type ExternalFillResult, } from './core/external/index.js';
4
+ export { loadExternalMetadata, validateExternalMetadata, ExternalMetadataSchema, type ExternalMetadata, } from './core/metadata.js';
5
+ export { validateTemplate, type TemplateValidationResult } from './core/validation/template.js';
6
+ export { validateLicense, type LicenseValidationResult } from './core/validation/license.js';
7
+ export { validateOutput, type OutputValidationResult } from './core/validation/output.js';
8
+ export { validateRecipe, type RecipeValidationResult } from './core/validation/recipe.js';
9
+ export { validateExternal, type ExternalValidationResult } from './core/validation/external.js';
10
+ export { runRecipe, cleanDocument, patchDocument, verifyOutput, ensureSourceDocx, type RecipeRunOptions, type RecipeRunResult, type VerifyResult, type VerifyCheck, } from './core/recipe/index.js';
11
+ export type { ToolCommandAdapter } from './core/command-generation/types.js';
12
+ export { ClaudeCodeAdapter } from './core/command-generation/adapters/claude.js';
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,KAAK,WAAW,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAGnF,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,kBAAkB,EAClB,sBAAsB,EACtB,eAAe,EACf,sBAAsB,EACtB,oBAAoB,EACpB,iBAAiB,EACjB,WAAW,EACX,qBAAqB,EACrB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,OAAO,GACb,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,eAAe,EACf,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,GACxB,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EACL,oBAAoB,EACpB,wBAAwB,EACxB,sBAAsB,EACtB,KAAK,gBAAgB,GACtB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,gBAAgB,EAAE,KAAK,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AAChG,OAAO,EAAE,eAAe,EAAE,KAAK,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAC7F,OAAO,EAAE,cAAc,EAAE,KAAK,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAC1F,OAAO,EAAE,cAAc,EAAE,KAAK,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAC1F,OAAO,EAAE,gBAAgB,EAAE,KAAK,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AAGhG,OAAO,EACL,SAAS,EACT,aAAa,EACb,aAAa,EACb,YAAY,EACZ,gBAAgB,EAChB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,WAAW,GACjB,MAAM,wBAAwB,CAAC;AAGhC,YAAY,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,EAAE,iBAAiB,EAAE,MAAM,8CAA8C,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,19 @@
1
+ // Public API exports
2
+ // Template engine
3
+ export { fillTemplate } from './core/engine.js';
4
+ // Metadata schemas and loaders
5
+ export { loadMetadata, validateMetadata, loadRecipeMetadata, validateRecipeMetadata, loadCleanConfig, TemplateMetadataSchema, RecipeMetadataSchema, CleanConfigSchema, LicenseEnum, FieldDefinitionSchema, } from './core/metadata.js';
6
+ // External template engine
7
+ export { runExternalFill, } from './core/external/index.js';
8
+ // Metadata schemas and loaders (external)
9
+ export { loadExternalMetadata, validateExternalMetadata, ExternalMetadataSchema, } from './core/metadata.js';
10
+ // Template validation
11
+ export { validateTemplate } from './core/validation/template.js';
12
+ export { validateLicense } from './core/validation/license.js';
13
+ export { validateOutput } from './core/validation/output.js';
14
+ export { validateRecipe } from './core/validation/recipe.js';
15
+ export { validateExternal } from './core/validation/external.js';
16
+ // Recipe engine
17
+ export { runRecipe, cleanDocument, patchDocument, verifyOutput, ensureSourceDocx, } from './core/recipe/index.js';
18
+ export { ClaudeCodeAdapter } from './core/command-generation/adapters/claude.js';
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qBAAqB;AAErB,kBAAkB;AAClB,OAAO,EAAE,YAAY,EAAqC,MAAM,kBAAkB,CAAC;AAEnF,+BAA+B;AAC/B,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,kBAAkB,EAClB,sBAAsB,EACtB,eAAe,EACf,sBAAsB,EACtB,oBAAoB,EACpB,iBAAiB,EACjB,WAAW,EACX,qBAAqB,GAMtB,MAAM,oBAAoB,CAAC;AAE5B,2BAA2B;AAC3B,OAAO,EACL,eAAe,GAGhB,MAAM,0BAA0B,CAAC;AAElC,0CAA0C;AAC1C,OAAO,EACL,oBAAoB,EACpB,wBAAwB,EACxB,sBAAsB,GAEvB,MAAM,oBAAoB,CAAC;AAE5B,sBAAsB;AACtB,OAAO,EAAE,gBAAgB,EAAiC,MAAM,+BAA+B,CAAC;AAChG,OAAO,EAAE,eAAe,EAAgC,MAAM,8BAA8B,CAAC;AAC7F,OAAO,EAAE,cAAc,EAA+B,MAAM,6BAA6B,CAAC;AAC1F,OAAO,EAAE,cAAc,EAA+B,MAAM,6BAA6B,CAAC;AAC1F,OAAO,EAAE,gBAAgB,EAAiC,MAAM,+BAA+B,CAAC;AAEhG,gBAAgB;AAChB,OAAO,EACL,SAAS,EACT,aAAa,EACb,aAAa,EACb,YAAY,EACZ,gBAAgB,GAKjB,MAAM,wBAAwB,CAAC;AAIhC,OAAO,EAAE,iBAAiB,EAAE,MAAM,8CAA8C,CAAC"}
@@ -0,0 +1,15 @@
1
+ /** Root of the open-agreements package */
2
+ export declare function getPackageRoot(): string;
3
+ /** Templates directory */
4
+ export declare function getTemplatesDir(): string;
5
+ /** Resolve a specific template directory by ID */
6
+ export declare function resolveTemplateDir(templateId: string): string;
7
+ /** External templates directory */
8
+ export declare function getExternalDir(): string;
9
+ /** Resolve a specific external template directory by ID */
10
+ export declare function resolveExternalDir(externalId: string): string;
11
+ /** Recipes directory */
12
+ export declare function getRecipesDir(): string;
13
+ /** Resolve a specific recipe directory by ID */
14
+ export declare function resolveRecipeDir(recipeId: string): string;
15
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/utils/paths.ts"],"names":[],"mappings":"AAMA,0CAA0C;AAC1C,wBAAgB,cAAc,IAAI,MAAM,CAGvC;AAYD,0BAA0B;AAC1B,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED,kDAAkD;AAClD,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED,mCAAmC;AACnC,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,2DAA2D;AAC3D,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED,wBAAwB;AACxB,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,gDAAgD;AAChD,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEzD"}
@@ -0,0 +1,43 @@
1
+ import { join, dirname, resolve, relative, sep } from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
3
+ const __filename = fileURLToPath(import.meta.url);
4
+ const __dirname = dirname(__filename);
5
+ /** Root of the open-agreements package */
6
+ export function getPackageRoot() {
7
+ // From dist/utils/paths.js → go up to package root
8
+ return join(__dirname, '..', '..');
9
+ }
10
+ /** Resolve a child directory, rejecting path traversal (e.g. "../../etc") */
11
+ function resolveChildDir(parentDir, childId, label) {
12
+ const resolved = resolve(join(parentDir, childId));
13
+ const rel = relative(resolve(parentDir), resolved);
14
+ if (rel.startsWith('..') || rel.startsWith(sep + sep)) {
15
+ throw new Error(`Invalid ${label} ID: ${childId}`);
16
+ }
17
+ return resolved;
18
+ }
19
+ /** Templates directory */
20
+ export function getTemplatesDir() {
21
+ return join(getPackageRoot(), 'templates');
22
+ }
23
+ /** Resolve a specific template directory by ID */
24
+ export function resolveTemplateDir(templateId) {
25
+ return resolveChildDir(getTemplatesDir(), templateId, 'template');
26
+ }
27
+ /** External templates directory */
28
+ export function getExternalDir() {
29
+ return join(getPackageRoot(), 'external');
30
+ }
31
+ /** Resolve a specific external template directory by ID */
32
+ export function resolveExternalDir(externalId) {
33
+ return resolveChildDir(getExternalDir(), externalId, 'external');
34
+ }
35
+ /** Recipes directory */
36
+ export function getRecipesDir() {
37
+ return join(getPackageRoot(), 'recipes');
38
+ }
39
+ /** Resolve a specific recipe directory by ID */
40
+ export function resolveRecipeDir(recipeId) {
41
+ return resolveChildDir(getRecipesDir(), recipeId, 'recipe');
42
+ }
43
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/utils/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC,0CAA0C;AAC1C,MAAM,UAAU,cAAc;IAC5B,mDAAmD;IACnD,OAAO,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AACrC,CAAC;AAED,6EAA6E;AAC7E,SAAS,eAAe,CAAC,SAAiB,EAAE,OAAe,EAAE,KAAa;IACxE,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;IACnD,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,CAAC;IACnD,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,GAAG,GAAG,CAAC,EAAE,CAAC;QACtD,MAAM,IAAI,KAAK,CAAC,WAAW,KAAK,QAAQ,OAAO,EAAE,CAAC,CAAC;IACrD,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,0BAA0B;AAC1B,MAAM,UAAU,eAAe;IAC7B,OAAO,IAAI,CAAC,cAAc,EAAE,EAAE,WAAW,CAAC,CAAC;AAC7C,CAAC;AAED,kDAAkD;AAClD,MAAM,UAAU,kBAAkB,CAAC,UAAkB;IACnD,OAAO,eAAe,CAAC,eAAe,EAAE,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;AACpE,CAAC;AAED,mCAAmC;AACnC,MAAM,UAAU,cAAc;IAC5B,OAAO,IAAI,CAAC,cAAc,EAAE,EAAE,UAAU,CAAC,CAAC;AAC5C,CAAC;AAED,2DAA2D;AAC3D,MAAM,UAAU,kBAAkB,CAAC,UAAkB;IACnD,OAAO,eAAe,CAAC,cAAc,EAAE,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;AACnE,CAAC;AAED,wBAAwB;AACxB,MAAM,UAAU,aAAa;IAC3B,OAAO,IAAI,CAAC,cAAc,EAAE,EAAE,SAAS,CAAC,CAAC;AAC3C,CAAC;AAED,gDAAgD;AAChD,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,OAAO,eAAe,CAAC,aAAa,EAAE,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAC9D,CAAC"}
@@ -0,0 +1,27 @@
1
+ Creative Commons Attribution-NoDerivatives 4.0 International (CC BY-ND 4.0)
2
+
3
+ The DOCX files in this directory are redistributed under the CC BY-ND 4.0 license.
4
+ They are unmodified copies of the originals published by their respective authors.
5
+
6
+ You are free to:
7
+ - Share: copy and redistribute the material in any medium or format for any purpose,
8
+ even commercially.
9
+
10
+ Under the following terms:
11
+ - Attribution: You must give appropriate credit, provide a link to the license, and
12
+ indicate if changes were made.
13
+ - NoDerivatives: If you remix, transform, or build upon the material, you may not
14
+ distribute the modified material.
15
+
16
+ Full license text: https://creativecommons.org/licenses/by-nd/4.0/legalcode
17
+
18
+ ---
19
+
20
+ Y Combinator Post-Money SAFE Documents
21
+ Copyright Y Combinator
22
+ Source: https://www.ycombinator.com/documents
23
+
24
+ - yc-safe-valuation-cap/template.docx — Post-Money SAFE, Valuation Cap Only
25
+ - yc-safe-discount/template.docx — Post-Money SAFE, Discount Only
26
+ - yc-safe-mfn/template.docx — Post-Money SAFE, MFN Only
27
+ - yc-safe-pro-rata-side-letter/template.docx — Pro Rata Side Letter