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.
- package/LICENSE +21 -0
- package/README.md +161 -0
- package/bin/open-agreements.js +2 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +102 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/commands/fill.d.ts +7 -0
- package/dist/commands/fill.d.ts.map +1 -0
- package/dist/commands/fill.js +84 -0
- package/dist/commands/fill.js.map +1 -0
- package/dist/commands/list.d.ts +6 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +202 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/recipe.d.ts +21 -0
- package/dist/commands/recipe.d.ts.map +1 -0
- package/dist/commands/recipe.js +71 -0
- package/dist/commands/recipe.js.map +1 -0
- package/dist/commands/scan.d.ts +12 -0
- package/dist/commands/scan.d.ts.map +1 -0
- package/dist/commands/scan.js +122 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/commands/validate.d.ts +6 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +139 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/core/command-generation/adapters/claude.d.ts +11 -0
- package/dist/core/command-generation/adapters/claude.d.ts.map +1 -0
- package/dist/core/command-generation/adapters/claude.js +85 -0
- package/dist/core/command-generation/adapters/claude.js.map +1 -0
- package/dist/core/command-generation/types.d.ts +14 -0
- package/dist/core/command-generation/types.d.ts.map +1 -0
- package/dist/core/command-generation/types.js +2 -0
- package/dist/core/command-generation/types.js.map +1 -0
- package/dist/core/engine.d.ts +13 -0
- package/dist/core/engine.d.ts.map +1 -0
- package/dist/core/engine.js +149 -0
- package/dist/core/engine.js.map +1 -0
- package/dist/core/external/index.d.ts +8 -0
- package/dist/core/external/index.d.ts.map +1 -0
- package/dist/core/external/index.js +92 -0
- package/dist/core/external/index.js.map +1 -0
- package/dist/core/external/types.d.ts +18 -0
- package/dist/core/external/types.d.ts.map +1 -0
- package/dist/core/external/types.js +2 -0
- package/dist/core/external/types.js.map +1 -0
- package/dist/core/fill-pipeline.d.ts +61 -0
- package/dist/core/fill-pipeline.d.ts.map +1 -0
- package/dist/core/fill-pipeline.js +279 -0
- package/dist/core/fill-pipeline.js.map +1 -0
- package/dist/core/fill-utils.d.ts +39 -0
- package/dist/core/fill-utils.d.ts.map +1 -0
- package/dist/core/fill-utils.js +127 -0
- package/dist/core/fill-utils.js.map +1 -0
- package/dist/core/metadata.d.ts +396 -0
- package/dist/core/metadata.d.ts.map +1 -0
- package/dist/core/metadata.js +126 -0
- package/dist/core/metadata.js.map +1 -0
- package/dist/core/recipe/cleaner.d.ts +13 -0
- package/dist/core/recipe/cleaner.d.ts.map +1 -0
- package/dist/core/recipe/cleaner.js +106 -0
- package/dist/core/recipe/cleaner.js.map +1 -0
- package/dist/core/recipe/downloader.d.ts +8 -0
- package/dist/core/recipe/downloader.d.ts.map +1 -0
- package/dist/core/recipe/downloader.js +58 -0
- package/dist/core/recipe/downloader.js.map +1 -0
- package/dist/core/recipe/index.d.ts +14 -0
- package/dist/core/recipe/index.d.ts.map +1 -0
- package/dist/core/recipe/index.js +91 -0
- package/dist/core/recipe/index.js.map +1 -0
- package/dist/core/recipe/ooxml-parts.d.ts +21 -0
- package/dist/core/recipe/ooxml-parts.d.ts.map +1 -0
- package/dist/core/recipe/ooxml-parts.js +33 -0
- package/dist/core/recipe/ooxml-parts.js.map +1 -0
- package/dist/core/recipe/patcher.d.ts +17 -0
- package/dist/core/recipe/patcher.d.ts.map +1 -0
- package/dist/core/recipe/patcher.js +240 -0
- package/dist/core/recipe/patcher.js.map +1 -0
- package/dist/core/recipe/types.d.ts +28 -0
- package/dist/core/recipe/types.d.ts.map +1 -0
- package/dist/core/recipe/types.js +2 -0
- package/dist/core/recipe/types.js.map +1 -0
- package/dist/core/recipe/verifier.d.ts +24 -0
- package/dist/core/recipe/verifier.d.ts.map +1 -0
- package/dist/core/recipe/verifier.js +143 -0
- package/dist/core/recipe/verifier.js.map +1 -0
- package/dist/core/validation/external.d.ts +16 -0
- package/dist/core/validation/external.d.ts.map +1 -0
- package/dist/core/validation/external.js +106 -0
- package/dist/core/validation/external.js.map +1 -0
- package/dist/core/validation/license.d.ts +15 -0
- package/dist/core/validation/license.d.ts.map +1 -0
- package/dist/core/validation/license.js +30 -0
- package/dist/core/validation/license.js.map +1 -0
- package/dist/core/validation/output.d.ts +12 -0
- package/dist/core/validation/output.d.ts.map +1 -0
- package/dist/core/validation/output.js +47 -0
- package/dist/core/validation/output.js.map +1 -0
- package/dist/core/validation/recipe.d.ts +19 -0
- package/dist/core/validation/recipe.d.ts.map +1 -0
- package/dist/core/validation/recipe.js +148 -0
- package/dist/core/validation/recipe.js.map +1 -0
- package/dist/core/validation/template.d.ts +11 -0
- package/dist/core/validation/template.d.ts.map +1 -0
- package/dist/core/validation/template.js +159 -0
- package/dist/core/validation/template.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/paths.d.ts +15 -0
- package/dist/utils/paths.d.ts.map +1 -0
- package/dist/utils/paths.js +43 -0
- package/dist/utils/paths.js.map +1 -0
- package/external/LICENSE +27 -0
- package/external/README.md +38 -0
- package/external/yc-safe-discount/README.md +16 -0
- package/external/yc-safe-discount/clean.json +4 -0
- package/external/yc-safe-discount/metadata.yaml +71 -0
- package/external/yc-safe-discount/replacements.json +13 -0
- package/external/yc-safe-discount/template.docx +0 -0
- package/external/yc-safe-mfn/README.md +16 -0
- package/external/yc-safe-mfn/clean.json +4 -0
- package/external/yc-safe-mfn/metadata.yaml +64 -0
- package/external/yc-safe-mfn/replacements.json +12 -0
- package/external/yc-safe-mfn/template.docx +0 -0
- package/external/yc-safe-pro-rata-side-letter/README.md +16 -0
- package/external/yc-safe-pro-rata-side-letter/clean.json +4 -0
- package/external/yc-safe-pro-rata-side-letter/metadata.yaml +49 -0
- package/external/yc-safe-pro-rata-side-letter/replacements.json +9 -0
- package/external/yc-safe-pro-rata-side-letter/template.docx +0 -0
- package/external/yc-safe-valuation-cap/README.md +16 -0
- package/external/yc-safe-valuation-cap/clean.json +4 -0
- package/external/yc-safe-valuation-cap/metadata.yaml +64 -0
- package/external/yc-safe-valuation-cap/replacements.json +12 -0
- package/external/yc-safe-valuation-cap/template.docx +0 -0
- package/package.json +77 -0
- package/recipes/nvca-certificate-of-incorporation/clean.json +8 -0
- package/recipes/nvca-certificate-of-incorporation/metadata.yaml +43 -0
- package/recipes/nvca-certificate-of-incorporation/replacements.json +9 -0
- package/recipes/nvca-certificate-of-incorporation/schema.json +11 -0
- package/recipes/nvca-indemnification-agreement/clean.json +7 -0
- package/recipes/nvca-indemnification-agreement/metadata.yaml +83 -0
- package/recipes/nvca-indemnification-agreement/replacements.json +17 -0
- package/recipes/nvca-indemnification-agreement/schema.json +19 -0
- package/recipes/nvca-investors-rights-agreement/clean.json +12 -0
- package/recipes/nvca-investors-rights-agreement/metadata.yaml +75 -0
- package/recipes/nvca-investors-rights-agreement/replacements.json +18 -0
- package/recipes/nvca-investors-rights-agreement/schema.json +18 -0
- package/recipes/nvca-management-rights-letter/clean.json +7 -0
- package/recipes/nvca-management-rights-letter/metadata.yaml +50 -0
- package/recipes/nvca-management-rights-letter/replacements.json +11 -0
- package/recipes/nvca-management-rights-letter/schema.json +13 -0
- package/recipes/nvca-rofr-co-sale-agreement/clean.json +7 -0
- package/recipes/nvca-rofr-co-sale-agreement/metadata.yaml +80 -0
- package/recipes/nvca-rofr-co-sale-agreement/replacements.json +17 -0
- package/recipes/nvca-rofr-co-sale-agreement/schema.json +19 -0
- package/recipes/nvca-stock-purchase-agreement/clean.json +10 -0
- package/recipes/nvca-stock-purchase-agreement/metadata.yaml +74 -0
- package/recipes/nvca-stock-purchase-agreement/replacements.json +20 -0
- package/recipes/nvca-stock-purchase-agreement/schema.json +19 -0
- package/recipes/nvca-voting-agreement/README.md +53 -0
- package/recipes/nvca-voting-agreement/clean.json +7 -0
- package/recipes/nvca-voting-agreement/metadata.yaml +70 -0
- package/recipes/nvca-voting-agreement/replacements.json +18 -0
- package/recipes/nvca-voting-agreement/schema.json +28 -0
- package/skills/open-agreements/SKILL.md +166 -0
- package/templates/bonterms-mutual-nda/README.md +27 -0
- package/templates/bonterms-mutual-nda/metadata.yaml +58 -0
- package/templates/bonterms-mutual-nda/template.docx +0 -0
- package/templates/bonterms-professional-services-agreement/README.md +24 -0
- package/templates/bonterms-professional-services-agreement/metadata.yaml +40 -0
- package/templates/bonterms-professional-services-agreement/template.docx +0 -0
- package/templates/common-paper-ai-addendum/README.md +23 -0
- package/templates/common-paper-ai-addendum/metadata.yaml +33 -0
- package/templates/common-paper-ai-addendum/template.docx +0 -0
- package/templates/common-paper-ai-addendum-in-app/README.md +21 -0
- package/templates/common-paper-ai-addendum-in-app/metadata.yaml +23 -0
- package/templates/common-paper-ai-addendum-in-app/template.docx +0 -0
- package/templates/common-paper-amendment/README.md +27 -0
- package/templates/common-paper-amendment/metadata.yaml +53 -0
- package/templates/common-paper-amendment/template.docx +0 -0
- package/templates/common-paper-business-associate-agreement/README.md +29 -0
- package/templates/common-paper-business-associate-agreement/metadata.yaml +63 -0
- package/templates/common-paper-business-associate-agreement/template.docx +0 -0
- package/templates/common-paper-cloud-service-agreement/README.md +32 -0
- package/templates/common-paper-cloud-service-agreement/metadata.yaml +488 -0
- package/templates/common-paper-cloud-service-agreement/template.docx +0 -0
- package/templates/common-paper-csa-click-through/README.md +33 -0
- package/templates/common-paper-csa-click-through/metadata.yaml +83 -0
- package/templates/common-paper-csa-click-through/template.docx +0 -0
- package/templates/common-paper-csa-with-ai/README.md +49 -0
- package/templates/common-paper-csa-with-ai/metadata.yaml +166 -0
- package/templates/common-paper-csa-with-ai/template.docx +0 -0
- package/templates/common-paper-csa-with-sla/README.md +53 -0
- package/templates/common-paper-csa-with-sla/metadata.yaml +185 -0
- package/templates/common-paper-csa-with-sla/template.docx +0 -0
- package/templates/common-paper-csa-without-sla/README.md +47 -0
- package/templates/common-paper-csa-without-sla/metadata.yaml +155 -0
- package/templates/common-paper-csa-without-sla/template.docx +0 -0
- package/templates/common-paper-data-processing-agreement/README.md +46 -0
- package/templates/common-paper-data-processing-agreement/metadata.yaml +149 -0
- package/templates/common-paper-data-processing-agreement/template.docx +0 -0
- package/templates/common-paper-design-partner-agreement/README.md +29 -0
- package/templates/common-paper-design-partner-agreement/metadata.yaml +65 -0
- package/templates/common-paper-design-partner-agreement/template.docx +0 -0
- package/templates/common-paper-independent-contractor-agreement/README.md +27 -0
- package/templates/common-paper-independent-contractor-agreement/metadata.yaml +55 -0
- package/templates/common-paper-independent-contractor-agreement/template.docx +0 -0
- package/templates/common-paper-letter-of-intent/README.md +25 -0
- package/templates/common-paper-letter-of-intent/metadata.yaml +43 -0
- package/templates/common-paper-letter-of-intent/template.docx +0 -0
- package/templates/common-paper-mutual-nda/README.md +29 -0
- package/templates/common-paper-mutual-nda/metadata.yaml +59 -0
- package/templates/common-paper-mutual-nda/template.docx +0 -0
- package/templates/common-paper-one-way-nda/README.md +27 -0
- package/templates/common-paper-one-way-nda/metadata.yaml +60 -0
- package/templates/common-paper-one-way-nda/template.docx +0 -0
- package/templates/common-paper-order-form/README.md +36 -0
- package/templates/common-paper-order-form/metadata.yaml +98 -0
- package/templates/common-paper-order-form/template.docx +0 -0
- package/templates/common-paper-order-form-with-sla/README.md +42 -0
- package/templates/common-paper-order-form-with-sla/metadata.yaml +129 -0
- package/templates/common-paper-order-form-with-sla/template.docx +0 -0
- package/templates/common-paper-partnership-agreement/README.md +34 -0
- package/templates/common-paper-partnership-agreement/metadata.yaml +90 -0
- package/templates/common-paper-partnership-agreement/template.docx +0 -0
- package/templates/common-paper-pilot-agreement/README.md +34 -0
- package/templates/common-paper-pilot-agreement/metadata.yaml +90 -0
- package/templates/common-paper-pilot-agreement/template.docx +0 -0
- package/templates/common-paper-professional-services-agreement/README.md +44 -0
- package/templates/common-paper-professional-services-agreement/metadata.yaml +141 -0
- package/templates/common-paper-professional-services-agreement/template.docx +0 -0
- package/templates/common-paper-software-license-agreement/README.md +18 -0
- package/templates/common-paper-software-license-agreement/metadata.yaml +13 -0
- package/templates/common-paper-software-license-agreement/template.docx +0 -0
- package/templates/common-paper-statement-of-work/README.md +32 -0
- package/templates/common-paper-statement-of-work/metadata.yaml +78 -0
- package/templates/common-paper-statement-of-work/template.docx +0 -0
- package/templates/common-paper-term-sheet/README.md +22 -0
- package/templates/common-paper-term-sheet/metadata.yaml +28 -0
- 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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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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"}
|
package/external/LICENSE
ADDED
|
@@ -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
|