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,126 @@
1
+ import { z } from 'zod';
2
+ import { readFileSync, existsSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import yaml from 'js-yaml';
5
+ export const LicenseEnum = z.enum(['CC-BY-4.0', 'CC0-1.0', 'CC-BY-ND-4.0']);
6
+ export const FieldDefinitionSchema = z.object({
7
+ name: z.string(),
8
+ type: z.enum(['string', 'date', 'number', 'boolean', 'enum']),
9
+ description: z.string(),
10
+ required: z.boolean(),
11
+ default: z.string().optional(),
12
+ options: z.array(z.string()).optional(),
13
+ section: z.string().optional(),
14
+ }).refine((f) => f.type !== 'enum' || (f.options !== undefined && f.options.length > 0), { message: 'Fields with type "enum" must have a non-empty options array' }).refine((f) => {
15
+ if (f.default === undefined)
16
+ return true;
17
+ if (f.type === 'number')
18
+ return !isNaN(Number(f.default));
19
+ if (f.type === 'boolean')
20
+ return f.default === 'true' || f.default === 'false';
21
+ return true;
22
+ }, { message: 'Default value must be valid for the declared field type' });
23
+ export const TemplateMetadataSchema = z.object({
24
+ name: z.string(),
25
+ description: z.string().optional(),
26
+ source_url: z.string().url(),
27
+ version: z.string(),
28
+ license: LicenseEnum,
29
+ allow_derivatives: z.boolean(),
30
+ attribution_text: z.string(),
31
+ fields: z.array(FieldDefinitionSchema),
32
+ });
33
+ // --- External template schemas ---
34
+ export const ExternalMetadataSchema = TemplateMetadataSchema.extend({
35
+ source_sha256: z.string(),
36
+ });
37
+ // --- Recipe schemas ---
38
+ export const CleanConfigSchema = z.object({
39
+ removeFootnotes: z.boolean().default(false),
40
+ removeParagraphPatterns: z.array(z.string()).default([]),
41
+ });
42
+ export const RecipeMetadataSchema = z.object({
43
+ name: z.string(),
44
+ description: z.string().optional(),
45
+ source_url: z.string().url(),
46
+ source_version: z.string(),
47
+ license_note: z.string(),
48
+ optional: z.boolean().default(false),
49
+ source_sha256: z.string().optional(),
50
+ fields: z.array(FieldDefinitionSchema).default([]),
51
+ });
52
+ // --- Template loaders ---
53
+ export function loadMetadata(templateDir) {
54
+ const metadataPath = join(templateDir, 'metadata.yaml');
55
+ const raw = readFileSync(metadataPath, 'utf-8');
56
+ const parsed = yaml.load(raw);
57
+ return TemplateMetadataSchema.parse(parsed);
58
+ }
59
+ export function validateMetadata(templateDir) {
60
+ try {
61
+ loadMetadata(templateDir);
62
+ return { valid: true, errors: [] };
63
+ }
64
+ catch (err) {
65
+ if (err instanceof z.ZodError) {
66
+ return {
67
+ valid: false,
68
+ errors: err.issues.map((i) => `${i.path.join('.')}: ${i.message}`),
69
+ };
70
+ }
71
+ return { valid: false, errors: [err.message] };
72
+ }
73
+ }
74
+ // --- External template loaders ---
75
+ export function loadExternalMetadata(externalDir) {
76
+ const metadataPath = join(externalDir, 'metadata.yaml');
77
+ const raw = readFileSync(metadataPath, 'utf-8');
78
+ const parsed = yaml.load(raw);
79
+ return ExternalMetadataSchema.parse(parsed);
80
+ }
81
+ export function validateExternalMetadata(externalDir) {
82
+ try {
83
+ loadExternalMetadata(externalDir);
84
+ return { valid: true, errors: [] };
85
+ }
86
+ catch (err) {
87
+ if (err instanceof z.ZodError) {
88
+ return {
89
+ valid: false,
90
+ errors: err.issues.map((i) => `${i.path.join('.')}: ${i.message}`),
91
+ };
92
+ }
93
+ return { valid: false, errors: [err.message] };
94
+ }
95
+ }
96
+ // --- Recipe loaders ---
97
+ export function loadRecipeMetadata(recipeDir) {
98
+ const metadataPath = join(recipeDir, 'metadata.yaml');
99
+ const raw = readFileSync(metadataPath, 'utf-8');
100
+ const parsed = yaml.load(raw);
101
+ return RecipeMetadataSchema.parse(parsed);
102
+ }
103
+ export function loadCleanConfig(recipeDir) {
104
+ const cleanPath = join(recipeDir, 'clean.json');
105
+ if (!existsSync(cleanPath)) {
106
+ return { removeFootnotes: false, removeParagraphPatterns: [] };
107
+ }
108
+ const raw = readFileSync(cleanPath, 'utf-8');
109
+ return CleanConfigSchema.parse(JSON.parse(raw));
110
+ }
111
+ export function validateRecipeMetadata(recipeDir) {
112
+ try {
113
+ loadRecipeMetadata(recipeDir);
114
+ return { valid: true, errors: [] };
115
+ }
116
+ catch (err) {
117
+ if (err instanceof z.ZodError) {
118
+ return {
119
+ valid: false,
120
+ errors: err.issues.map((i) => `${i.path.join('.')}: ${i.message}`),
121
+ };
122
+ }
123
+ return { valid: false, errors: [err.message] };
124
+ }
125
+ }
126
+ //# sourceMappingURL=metadata.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../src/core/metadata.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { CleanConfig } from '../metadata.js';
2
+ /**
3
+ * Clean a DOCX document by removing footnotes and pattern-matched paragraphs.
4
+ * Operates at the OOXML level to preserve formatting of retained content.
5
+ *
6
+ * Processes all general OOXML text parts (document, headers, footers, endnotes).
7
+ * Footnotes.xml is handled separately with its separator/continuationSeparator logic.
8
+ *
9
+ * Note: Internal helpers use `any` for DOM nodes because @xmldom/xmldom's types
10
+ * are incompatible with the global DOM types (missing EventTarget methods).
11
+ */
12
+ export declare function cleanDocument(inputPath: string, outputPath: string, config: CleanConfig): Promise<string>;
13
+ //# sourceMappingURL=cleaner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cleaner.d.ts","sourceRoot":"","sources":["../../../src/core/recipe/cleaner.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAKlD;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CACjC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,MAAM,CAAC,CAwCjB"}
@@ -0,0 +1,106 @@
1
+ import AdmZip from 'adm-zip';
2
+ import { DOMParser, XMLSerializer } from '@xmldom/xmldom';
3
+ import { enumerateTextParts, getGeneralTextPartNames } from './ooxml-parts.js';
4
+ const W_NS = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main';
5
+ /**
6
+ * Clean a DOCX document by removing footnotes and pattern-matched paragraphs.
7
+ * Operates at the OOXML level to preserve formatting of retained content.
8
+ *
9
+ * Processes all general OOXML text parts (document, headers, footers, endnotes).
10
+ * Footnotes.xml is handled separately with its separator/continuationSeparator logic.
11
+ *
12
+ * Note: Internal helpers use `any` for DOM nodes because @xmldom/xmldom's types
13
+ * are incompatible with the global DOM types (missing EventTarget methods).
14
+ */
15
+ export async function cleanDocument(inputPath, outputPath, config) {
16
+ const zip = new AdmZip(inputPath);
17
+ const parser = new DOMParser();
18
+ const serializer = new XMLSerializer();
19
+ const parts = enumerateTextParts(zip);
20
+ const generalParts = getGeneralTextPartNames(parts);
21
+ // Clean all general text parts (document, headers, footers, endnotes)
22
+ for (const partName of generalParts) {
23
+ const entry = zip.getEntry(partName);
24
+ if (!entry)
25
+ continue;
26
+ const xml = entry.getData().toString('utf-8');
27
+ const doc = parser.parseFromString(xml, 'text/xml');
28
+ if (config.removeFootnotes) {
29
+ removeFootnoteReferences(doc);
30
+ }
31
+ if (config.removeParagraphPatterns.length > 0) {
32
+ removeParagraphsByPattern(doc, config.removeParagraphPatterns);
33
+ }
34
+ zip.updateFile(partName, Buffer.from(serializer.serializeToString(doc), 'utf-8'));
35
+ }
36
+ // Clean footnotes.xml separately (has separator/continuationSeparator logic)
37
+ if (config.removeFootnotes && parts.footnotes) {
38
+ const footnotesEntry = zip.getEntry(parts.footnotes);
39
+ if (footnotesEntry) {
40
+ const xml = footnotesEntry.getData().toString('utf-8');
41
+ const doc = parser.parseFromString(xml, 'text/xml');
42
+ removeNormalFootnotes(doc);
43
+ zip.updateFile(parts.footnotes, Buffer.from(serializer.serializeToString(doc), 'utf-8'));
44
+ }
45
+ }
46
+ zip.writeZip(outputPath);
47
+ return outputPath;
48
+ }
49
+ /* eslint-disable @typescript-eslint/no-explicit-any --
50
+ @xmldom/xmldom types are incompatible with global DOM types */
51
+ function removeFootnoteReferences(doc) {
52
+ const refs = doc.getElementsByTagNameNS(W_NS, 'footnoteReference');
53
+ const runsToRemove = [];
54
+ for (let i = 0; i < refs.length; i++) {
55
+ let node = refs[i];
56
+ while (node && !(node.localName === 'r' && node.namespaceURI === W_NS)) {
57
+ node = node.parentNode;
58
+ }
59
+ if (node) {
60
+ runsToRemove.push(node);
61
+ }
62
+ }
63
+ for (const run of runsToRemove) {
64
+ run.parentNode?.removeChild(run);
65
+ }
66
+ }
67
+ function removeNormalFootnotes(doc) {
68
+ const footnotes = doc.getElementsByTagNameNS(W_NS, 'footnote');
69
+ const toRemove = [];
70
+ for (let i = 0; i < footnotes.length; i++) {
71
+ const fn = footnotes[i];
72
+ const fnType = fn.getAttributeNS(W_NS, 'type');
73
+ if (fnType !== 'separator' && fnType !== 'continuationSeparator') {
74
+ toRemove.push(fn);
75
+ }
76
+ }
77
+ for (const fn of toRemove) {
78
+ fn.parentNode?.removeChild(fn);
79
+ }
80
+ }
81
+ function removeParagraphsByPattern(doc, patterns) {
82
+ const regexes = patterns.map((p) => new RegExp(p, 'i'));
83
+ const paragraphs = doc.getElementsByTagNameNS(W_NS, 'p');
84
+ const toRemove = [];
85
+ for (let i = 0; i < paragraphs.length; i++) {
86
+ const para = paragraphs[i];
87
+ const text = extractParagraphText(para);
88
+ if (text && regexes.some((r) => r.test(text))) {
89
+ toRemove.push(para);
90
+ }
91
+ }
92
+ for (const para of toRemove) {
93
+ para.parentNode?.removeChild(para);
94
+ }
95
+ }
96
+ function extractParagraphText(para) {
97
+ if (!para.getElementsByTagNameNS)
98
+ return '';
99
+ const textElements = para.getElementsByTagNameNS(W_NS, 't');
100
+ const parts = [];
101
+ for (let i = 0; i < textElements.length; i++) {
102
+ parts.push(textElements[i].textContent ?? '');
103
+ }
104
+ return parts.join('').trim();
105
+ }
106
+ //# sourceMappingURL=cleaner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cleaner.js","sourceRoot":"","sources":["../../../src/core/recipe/cleaner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { RecipeMetadata } from '../metadata.js';
2
+ /**
3
+ * Ensure the source DOCX for a recipe is available locally.
4
+ * Downloads from source_url on first use, caches in ~/.open-agreements/cache/<recipe-id>/source.docx.
5
+ * Verifies SHA-256 integrity when source_sha256 is set in metadata.
6
+ */
7
+ export declare function ensureSourceDocx(recipeId: string, metadata: RecipeMetadata): Promise<string>;
8
+ //# sourceMappingURL=downloader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"downloader.d.ts","sourceRoot":"","sources":["../../../src/core/recipe/downloader.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAarD;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAgDlG"}
@@ -0,0 +1,58 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { homedir } from 'node:os';
4
+ import { createHash } from 'node:crypto';
5
+ const CACHE_ROOT = join(homedir(), '.open-agreements', 'cache');
6
+ function getCachePath(recipeId) {
7
+ return join(CACHE_ROOT, recipeId, 'source.docx');
8
+ }
9
+ function verifyHash(buf, expected) {
10
+ const actual = createHash('sha256').update(buf).digest('hex');
11
+ return actual === expected;
12
+ }
13
+ /**
14
+ * Ensure the source DOCX for a recipe is available locally.
15
+ * Downloads from source_url on first use, caches in ~/.open-agreements/cache/<recipe-id>/source.docx.
16
+ * Verifies SHA-256 integrity when source_sha256 is set in metadata.
17
+ */
18
+ export async function ensureSourceDocx(recipeId, metadata) {
19
+ const cachePath = getCachePath(recipeId);
20
+ // Check cached file
21
+ if (existsSync(cachePath)) {
22
+ if (metadata.source_sha256) {
23
+ const buf = readFileSync(cachePath);
24
+ if (verifyHash(buf, metadata.source_sha256)) {
25
+ return cachePath;
26
+ }
27
+ console.log(`Cached file for ${recipeId} failed integrity check, re-downloading...`);
28
+ }
29
+ else {
30
+ return cachePath;
31
+ }
32
+ }
33
+ // Download
34
+ console.log(`Downloading ${metadata.name} from ${metadata.source_url}...`);
35
+ const response = await fetch(metadata.source_url);
36
+ if (!response.ok) {
37
+ throw new Error(`Failed to download ${recipeId}: HTTP ${response.status} ${response.statusText}\n` +
38
+ ` URL: ${metadata.source_url}`);
39
+ }
40
+ const buf = Buffer.from(await response.arrayBuffer());
41
+ // Verify hash if available
42
+ if (metadata.source_sha256) {
43
+ if (!verifyHash(buf, metadata.source_sha256)) {
44
+ const actual = createHash('sha256').update(buf).digest('hex');
45
+ throw new Error(`Integrity check failed for ${recipeId}: downloaded file hash does not match.\n` +
46
+ ` Expected SHA-256: ${metadata.source_sha256}\n` +
47
+ ` Actual SHA-256: ${actual}\n` +
48
+ ` URL: ${metadata.source_url}`);
49
+ }
50
+ }
51
+ // Write to cache
52
+ const cacheDir = join(CACHE_ROOT, recipeId);
53
+ mkdirSync(cacheDir, { recursive: true });
54
+ writeFileSync(cachePath, buf);
55
+ console.log(`Cached: ${cachePath}`);
56
+ return cachePath;
57
+ }
58
+ //# sourceMappingURL=downloader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"downloader.js","sourceRoot":"","sources":["../../../src/core/recipe/downloader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { RecipeRunOptions, RecipeRunResult } from './types.js';
2
+ /**
3
+ * Run the full recipe pipeline: clean → patch → fill → verify.
4
+ * If no inputPath is provided, auto-downloads the source document from source_url.
5
+ */
6
+ export declare function runRecipe(options: RecipeRunOptions): Promise<RecipeRunResult>;
7
+ export { cleanDocument } from './cleaner.js';
8
+ export { patchDocument } from './patcher.js';
9
+ export { verifyOutput, normalizeText, extractAllText } from './verifier.js';
10
+ export { ensureSourceDocx } from './downloader.js';
11
+ export { enumerateTextParts, getGeneralTextPartNames } from './ooxml-parts.js';
12
+ export type { OoxmlTextParts } from './ooxml-parts.js';
13
+ export type { RecipeRunOptions, RecipeRunResult, VerifyResult, VerifyCheck } from './types.js';
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/recipe/index.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAEpE;;;GAGG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CAkFnF;AAED,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC5E,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAC/E,YAAY,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvD,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,91 @@
1
+ import { mkdtempSync, copyFileSync, rmSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { tmpdir } from 'node:os';
4
+ import { readFileSync, writeFileSync } from 'node:fs';
5
+ import { loadRecipeMetadata, loadCleanConfig } from '../metadata.js';
6
+ import { resolveRecipeDir } from '../../utils/paths.js';
7
+ import { cleanDocument } from './cleaner.js';
8
+ import { patchDocument } from './patcher.js';
9
+ import { verifyOutput } from './verifier.js';
10
+ import { ensureSourceDocx } from './downloader.js';
11
+ import { prepareFillData, fillDocx } from '../fill-pipeline.js';
12
+ /**
13
+ * Run the full recipe pipeline: clean → patch → fill → verify.
14
+ * If no inputPath is provided, auto-downloads the source document from source_url.
15
+ */
16
+ export async function runRecipe(options) {
17
+ const { recipeId, outputPath, values, keepIntermediate } = options;
18
+ const recipeDir = resolveRecipeDir(recipeId);
19
+ const metadata = loadRecipeMetadata(recipeDir);
20
+ const cleanConfig = loadCleanConfig(recipeDir);
21
+ // Resolve input: explicit path or auto-download
22
+ const inputPath = options.inputPath ?? await ensureSourceDocx(recipeId, metadata);
23
+ // Load replacements.json
24
+ const replacementsPath = join(recipeDir, 'replacements.json');
25
+ const replacements = JSON.parse(readFileSync(replacementsPath, 'utf-8'));
26
+ // Create temp directory for intermediate files
27
+ const tempDir = mkdtempSync(join(tmpdir(), `recipe-${recipeId}-`));
28
+ const stages = {
29
+ clean: '',
30
+ patch: '',
31
+ fill: '',
32
+ };
33
+ try {
34
+ // Copy input to temp dir
35
+ const sourcePath = join(tempDir, 'source.docx');
36
+ copyFileSync(inputPath, sourcePath);
37
+ // Stage 1: Clean
38
+ const cleanedPath = join(tempDir, 'cleaned.docx');
39
+ await cleanDocument(sourcePath, cleanedPath, cleanConfig);
40
+ stages.clean = cleanedPath;
41
+ // Stage 2: Patch (replace [brackets] with {template_tags})
42
+ const patchedPath = join(tempDir, 'patched.docx');
43
+ await patchDocument(cleanedPath, patchedPath, replacements);
44
+ stages.patch = patchedPath;
45
+ // Stage 3: Fill (render template tags with values)
46
+ const fillData = prepareFillData({
47
+ values,
48
+ fields: metadata.fields,
49
+ useBlankPlaceholder: true,
50
+ });
51
+ const filledPath = join(tempDir, 'filled.docx');
52
+ const templateBuf = readFileSync(patchedPath);
53
+ const filledBuf = await fillDocx({
54
+ templateBuffer: templateBuf,
55
+ data: fillData,
56
+ });
57
+ writeFileSync(filledPath, filledBuf);
58
+ stages.fill = filledPath;
59
+ // Stage 4: Verify
60
+ const verifyResult = await verifyOutput(filledPath, values, replacements, cleanConfig);
61
+ if (!verifyResult.passed) {
62
+ const failures = verifyResult.checks
63
+ .filter((c) => !c.passed)
64
+ .map((c) => `${c.name}: ${c.details ?? 'failed'}`)
65
+ .join('; ');
66
+ console.warn(`Warning: verification issues: ${failures}`);
67
+ }
68
+ // Copy final output to destination
69
+ copyFileSync(filledPath, outputPath);
70
+ if (keepIntermediate) {
71
+ console.log(`Intermediate files preserved at: ${tempDir}`);
72
+ }
73
+ return {
74
+ outputPath,
75
+ metadata,
76
+ fieldsUsed: Object.keys(values),
77
+ stages,
78
+ };
79
+ }
80
+ finally {
81
+ if (!keepIntermediate) {
82
+ rmSync(tempDir, { recursive: true, force: true });
83
+ }
84
+ }
85
+ }
86
+ export { cleanDocument } from './cleaner.js';
87
+ export { patchDocument } from './patcher.js';
88
+ export { verifyOutput, normalizeText, extractAllText } from './verifier.js';
89
+ export { ensureSourceDocx } from './downloader.js';
90
+ export { enumerateTextParts, getGeneralTextPartNames } from './ooxml-parts.js';
91
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/recipe/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import AdmZip from 'adm-zip';
2
+ export interface OoxmlTextParts {
3
+ document: string | null;
4
+ headers: string[];
5
+ footers: string[];
6
+ endnotes: string | null;
7
+ footnotes: string | null;
8
+ }
9
+ /**
10
+ * Enumerate all OOXML text parts present in a DOCX zip.
11
+ */
12
+ export declare function enumerateTextParts(zip: AdmZip): OoxmlTextParts;
13
+ /**
14
+ * Return a flat list of part names that should be processed by the patcher,
15
+ * cleaner (for footnote refs and paragraph patterns), verifier, and scanner.
16
+ *
17
+ * Excludes footnotes.xml because it has separator/continuationSeparator logic
18
+ * that requires special handling in the cleaner.
19
+ */
20
+ export declare function getGeneralTextPartNames(parts: OoxmlTextParts): string[];
21
+ //# sourceMappingURL=ooxml-parts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ooxml-parts.d.ts","sourceRoot":"","sources":["../../../src/core/recipe/ooxml-parts.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,SAAS,CAAC;AAE7B,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAa9D;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,EAAE,CAOvE"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Enumerate all OOXML text parts present in a DOCX zip.
3
+ */
4
+ export function enumerateTextParts(zip) {
5
+ const entries = zip.getEntries().map((e) => e.entryName);
6
+ const headerPattern = /^word\/header\d+\.xml$/;
7
+ const footerPattern = /^word\/footer\d+\.xml$/;
8
+ return {
9
+ document: entries.includes('word/document.xml') ? 'word/document.xml' : null,
10
+ headers: entries.filter((e) => headerPattern.test(e)).sort(),
11
+ footers: entries.filter((e) => footerPattern.test(e)).sort(),
12
+ endnotes: entries.includes('word/endnotes.xml') ? 'word/endnotes.xml' : null,
13
+ footnotes: entries.includes('word/footnotes.xml') ? 'word/footnotes.xml' : null,
14
+ };
15
+ }
16
+ /**
17
+ * Return a flat list of part names that should be processed by the patcher,
18
+ * cleaner (for footnote refs and paragraph patterns), verifier, and scanner.
19
+ *
20
+ * Excludes footnotes.xml because it has separator/continuationSeparator logic
21
+ * that requires special handling in the cleaner.
22
+ */
23
+ export function getGeneralTextPartNames(parts) {
24
+ const names = [];
25
+ if (parts.document)
26
+ names.push(parts.document);
27
+ names.push(...parts.headers);
28
+ names.push(...parts.footers);
29
+ if (parts.endnotes)
30
+ names.push(parts.endnotes);
31
+ return names;
32
+ }
33
+ //# sourceMappingURL=ooxml-parts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ooxml-parts.js","sourceRoot":"","sources":["../../../src/core/recipe/ooxml-parts.ts"],"names":[],"mappings":"AAUA;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAC5C,MAAM,OAAO,GAAG,GAAG,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAEzD,MAAM,aAAa,GAAG,wBAAwB,CAAC;IAC/C,MAAM,aAAa,GAAG,wBAAwB,CAAC;IAE/C,OAAO;QACL,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,IAAI;QAC5E,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;QAC5D,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;QAC5D,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,IAAI;QAC5E,SAAS,EAAE,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,IAAI;KAChF,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAAqB;IAC3D,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,KAAK,CAAC,QAAQ;QAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC/C,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;IAC7B,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;IAC7B,IAAI,KAAK,CAAC,QAAQ;QAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC/C,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,17 @@
1
+ import type { Element } from '@xmldom/xmldom';
2
+ /**
3
+ * Patch a DOCX document by replacing bracketed placeholders with template tags.
4
+ * Uses a char_map algorithm to handle cross-run replacements where Word splits
5
+ * placeholder text across multiple XML run elements.
6
+ *
7
+ * Processes all general OOXML text parts (document, headers, footers, endnotes).
8
+ */
9
+ export declare function patchDocument(inputPath: string, outputPath: string, replacements: Record<string, string>): Promise<string>;
10
+ export declare function getRunText(run: Element): string;
11
+ /**
12
+ * Check if a run is safe to remove when its text is empty.
13
+ * Returns true only if all element children are <w:rPr> or <w:t>.
14
+ * Returns false if the run contains drawings, fields, breaks, or other non-text elements.
15
+ */
16
+ export declare function isRunSafeToRemove(run: Element): boolean;
17
+ //# sourceMappingURL=patcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patcher.d.ts","sourceRoot":"","sources":["../../../src/core/recipe/patcher.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAY,OAAO,EAAQ,MAAM,gBAAgB,CAAC;AAsB9D;;;;;;GAMG;AACH,wBAAsB,aAAa,CACjC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACnC,OAAO,CAAC,MAAM,CAAC,CA4CjB;AAiBD,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAO/C;AAiDD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAcvD"}