forgeprint 0.1.1

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 (71) hide show
  1. package/LICENSE +16 -0
  2. package/README.md +41 -0
  3. package/dist/bin.d.ts +3 -0
  4. package/dist/bin.d.ts.map +1 -0
  5. package/dist/bin.js +10 -0
  6. package/dist/bin.js.map +1 -0
  7. package/dist/build-codeowners.d.ts +8 -0
  8. package/dist/build-codeowners.d.ts.map +1 -0
  9. package/dist/build-codeowners.js +26 -0
  10. package/dist/build-codeowners.js.map +1 -0
  11. package/dist/build-index.d.ts +45 -0
  12. package/dist/build-index.d.ts.map +1 -0
  13. package/dist/build-index.js +41 -0
  14. package/dist/build-index.js.map +1 -0
  15. package/dist/build-schema.d.ts +4 -0
  16. package/dist/build-schema.d.ts.map +1 -0
  17. package/dist/build-schema.js +38 -0
  18. package/dist/build-schema.js.map +1 -0
  19. package/dist/catalog.d.ts +23 -0
  20. package/dist/catalog.d.ts.map +1 -0
  21. package/dist/catalog.js +55 -0
  22. package/dist/catalog.js.map +1 -0
  23. package/dist/cli.d.ts +8 -0
  24. package/dist/cli.d.ts.map +1 -0
  25. package/dist/cli.js +128 -0
  26. package/dist/cli.js.map +1 -0
  27. package/dist/config.d.ts +13 -0
  28. package/dist/config.d.ts.map +1 -0
  29. package/dist/config.js +30 -0
  30. package/dist/config.js.map +1 -0
  31. package/dist/index.d.ts +15 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +15 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/json.d.ts +5 -0
  36. package/dist/json.d.ts.map +1 -0
  37. package/dist/json.js +9 -0
  38. package/dist/json.js.map +1 -0
  39. package/dist/lint-setup.d.ts +19 -0
  40. package/dist/lint-setup.d.ts.map +1 -0
  41. package/dist/lint-setup.js +278 -0
  42. package/dist/lint-setup.js.map +1 -0
  43. package/dist/manifest.d.ts +104 -0
  44. package/dist/manifest.d.ts.map +1 -0
  45. package/dist/manifest.js +93 -0
  46. package/dist/manifest.js.map +1 -0
  47. package/dist/options.d.ts +43 -0
  48. package/dist/options.d.ts.map +1 -0
  49. package/dist/options.js +127 -0
  50. package/dist/options.js.map +1 -0
  51. package/dist/paths.d.ts +16 -0
  52. package/dist/paths.d.ts.map +1 -0
  53. package/dist/paths.js +37 -0
  54. package/dist/paths.js.map +1 -0
  55. package/dist/similarity.d.ts +61 -0
  56. package/dist/similarity.d.ts.map +1 -0
  57. package/dist/similarity.js +184 -0
  58. package/dist/similarity.js.map +1 -0
  59. package/dist/taxonomy.d.ts +24 -0
  60. package/dist/taxonomy.d.ts.map +1 -0
  61. package/dist/taxonomy.js +46 -0
  62. package/dist/taxonomy.js.map +1 -0
  63. package/dist/testing.d.ts +23 -0
  64. package/dist/testing.d.ts.map +1 -0
  65. package/dist/testing.js +107 -0
  66. package/dist/testing.js.map +1 -0
  67. package/dist/validate.d.ts +16 -0
  68. package/dist/validate.d.ts.map +1 -0
  69. package/dist/validate.js +122 -0
  70. package/dist/validate.js.map +1 -0
  71. package/package.json +58 -0
package/LICENSE ADDED
@@ -0,0 +1,16 @@
1
+ PolyForm Shield License 1.0.0
2
+
3
+ <https://polyformproject.org/licenses/shield/1.0.0>
4
+
5
+ Required Notice: Copyright 2026 Forgeprint (https://github.com/forgeprint)
6
+
7
+ You may use, modify and contribute to this software. You may not use it to
8
+ provide a product that competes with Forgeprint. The full licence text is at
9
+ the URL above and in the LICENSE file of the repository:
10
+
11
+ https://github.com/forgeprint/forgeprint/blob/main/LICENSE
12
+
13
+ Catalog content (blueprints, schema, skills) is licensed separately under
14
+ CC BY 4.0. The Forgeprint name and logo are covered by TRADEMARK.md.
15
+
16
+ Forgeprint is source-available, not OSI open source.
package/README.md ADDED
@@ -0,0 +1,41 @@
1
+ # forgeprint
2
+
3
+ The [Forgeprint](https://github.com/forgeprint/forgeprint) catalog tooling.
4
+ Every check that runs in CI is a command here, so a contributor gets the same
5
+ answer on a laptop that the pipeline gives on a pull request — by design, not
6
+ by luck ([ADR 0002](https://github.com/forgeprint/forgeprint/blob/main/docs/decisions/0002-actions-optional.md)).
7
+
8
+ ```bash
9
+ npx forgeprint validate
10
+ ```
11
+
12
+ ## Commands
13
+
14
+ | Command | What it does |
15
+ | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
16
+ | `forgeprint validate` | Schema, taxonomy, required files, and the catalog-wide rules: one blueprint per stack + project type + requirements, a CHANGELOG entry per version, generated files that are not stale |
17
+ | `forgeprint lint-setup <slug>` | Holds `setup.md` to a script's standards: numbered steps, a verification per step, pinned versions, no privileged or unpinned commands, option guards that resolve |
18
+ | `forgeprint similarity <slug>` | Duplicate report — tag overlap plus TF-IDF similarity of `AGENTS.md` and `setup.md` against every other blueprint |
19
+ | `forgeprint build-index` | Regenerate `docs/index.json` |
20
+ | `forgeprint build-schema` | Regenerate `schema/manifest.schema.json` from the taxonomy |
21
+ | `forgeprint build-codeowners` | Regenerate `.github/CODEOWNERS` from the manifests |
22
+
23
+ Run them from anywhere inside a Forgeprint checkout; the repository root is
24
+ found the way git finds it.
25
+
26
+ ## As a library
27
+
28
+ The catalog reader, the manifest schema, the setup linter, the option resolver
29
+ and the similarity report are all exported, which is what
30
+ [`forgeprint-mcp`](https://www.npmjs.com/package/forgeprint-mcp) is built on.
31
+
32
+ ```ts
33
+ import { lintSetup, resolveSetupOptions, validateCatalog } from 'forgeprint';
34
+ ```
35
+
36
+ `forgeprint/testing` exposes the fixture helpers used by the test suite.
37
+
38
+ ## Licence
39
+
40
+ PolyForm Shield 1.0.0 — see `LICENSE`. Forgeprint is source-available, not OSI
41
+ open source. The blueprints in the catalog are CC BY 4.0.
package/dist/bin.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=bin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":""}
package/dist/bin.js ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ import { createProgram } from './cli.js';
3
+ try {
4
+ createProgram().parse(process.argv);
5
+ }
6
+ catch (error) {
7
+ console.error(`error ${error instanceof Error ? error.message : String(error)}`);
8
+ process.exitCode = 1;
9
+ }
10
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,IAAI,CAAC;IACH,aAAa,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AACtC,CAAC;AAAC,OAAO,KAAK,EAAE,CAAC;IACf,OAAO,CAAC,KAAK,CAAC,UAAU,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { Blueprint } from './catalog.js';
2
+ /**
3
+ * Render `.github/CODEOWNERS` from the `maintainers` field of every manifest.
4
+ * `coreMaintainer` owns the repository root, so that the Code Owners review
5
+ * requirement always reaches them.
6
+ */
7
+ export declare function renderCodeowners(blueprints: readonly Blueprint[], coreMaintainer: string): string;
8
+ //# sourceMappingURL=build-codeowners.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-codeowners.d.ts","sourceRoot":"","sources":["../src/build-codeowners.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAU9C;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,EAAE,cAAc,EAAE,MAAM,GAAG,MAAM,CAYjG"}
@@ -0,0 +1,26 @@
1
+ const HEADER = [
2
+ '# Generated by `forgeprint build-codeowners`. Do not edit by hand.',
3
+ '#',
4
+ '# The root owner reviews everything: merge decisions stay with the core',
5
+ '# maintainer (CLAUDE.md rule 12). Blueprint maintainers own their own folder',
6
+ '# and approve changes to it; they do not merge.',
7
+ ];
8
+ /**
9
+ * Render `.github/CODEOWNERS` from the `maintainers` field of every manifest.
10
+ * `coreMaintainer` owns the repository root, so that the Code Owners review
11
+ * requirement always reaches them.
12
+ */
13
+ export function renderCodeowners(blueprints, coreMaintainer) {
14
+ const lines = [...HEADER, '', `* @${coreMaintainer}`, ''];
15
+ const owned = [...blueprints].sort((a, b) => a.slug.localeCompare(b.slug));
16
+ if (owned.length > 0) {
17
+ lines.push('# One line per blueprint, ordered by slug.');
18
+ for (const blueprint of owned) {
19
+ const owners = blueprint.manifest.maintainers.map((handle) => `@${handle}`).join(' ');
20
+ lines.push(`/blueprints/${blueprint.slug}/ ${owners}`);
21
+ }
22
+ lines.push('');
23
+ }
24
+ return lines.join('\n');
25
+ }
26
+ //# sourceMappingURL=build-codeowners.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-codeowners.js","sourceRoot":"","sources":["../src/build-codeowners.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,GAAG;IACb,oEAAoE;IACpE,GAAG;IACH,yEAAyE;IACzE,8EAA8E;IAC9E,iDAAiD;CAClD,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,UAAgC,EAAE,cAAsB;IACvF,MAAM,KAAK,GAAG,CAAC,GAAG,MAAM,EAAE,EAAE,EAAE,MAAM,cAAc,EAAE,EAAE,EAAE,CAAC,CAAC;IAC1D,MAAM,KAAK,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAC3E,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrB,KAAK,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;QACzD,KAAK,MAAM,SAAS,IAAI,KAAK,EAAE,CAAC;YAC9B,MAAM,MAAM,GAAG,SAAS,CAAC,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACtF,KAAK,CAAC,IAAI,CAAC,eAAe,SAAS,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC,CAAC;QACzD,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,45 @@
1
+ import { type Blueprint } from './catalog.js';
2
+ import type { Taxonomy } from './taxonomy.js';
3
+ /**
4
+ * The published catalog index. It is committed to the repository so that GitHub
5
+ * Pages can serve it from the branch without a build service (ADR 0002).
6
+ *
7
+ * The index carries no timestamp on purpose: a generated file that changes on
8
+ * every run cannot be checked for drift.
9
+ */
10
+ export interface CatalogIndex {
11
+ readonly schema: 1;
12
+ readonly taxonomy: Taxonomy;
13
+ readonly blueprints: readonly IndexEntry[];
14
+ }
15
+ export interface IndexEntry {
16
+ readonly slug: string;
17
+ readonly name: string;
18
+ readonly version: string;
19
+ readonly tier: string;
20
+ readonly maintainers: readonly string[];
21
+ readonly summary: string;
22
+ readonly stack: readonly string[];
23
+ readonly languages: readonly string[];
24
+ readonly platforms: readonly string[];
25
+ readonly distribution: readonly string[];
26
+ readonly project_type: string;
27
+ readonly audience: readonly string[];
28
+ readonly requirements: readonly string[];
29
+ readonly agents: readonly string[];
30
+ readonly options: Record<string, string[]>;
31
+ readonly provides: {
32
+ readonly mcp: string[];
33
+ readonly skills: string[];
34
+ };
35
+ readonly requires_tools: readonly string[];
36
+ readonly deprecated: boolean;
37
+ readonly supersedes: string | null;
38
+ readonly files: readonly string[];
39
+ readonly i18n: readonly string[];
40
+ }
41
+ export declare function loadBlueprints(root: string, taxonomy: Taxonomy): Blueprint[];
42
+ export declare function indexEntry(blueprint: Blueprint): IndexEntry;
43
+ export declare function buildIndex(blueprints: readonly Blueprint[], taxonomy: Taxonomy): CatalogIndex;
44
+ export declare function renderIndex(blueprints: readonly Blueprint[], taxonomy: Taxonomy): string;
45
+ //# sourceMappingURL=build-index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-index.d.ts","sourceRoot":"","sources":["../src/build-index.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AAEtB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACnB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,SAAS,UAAU,EAAE,CAAC;CAC5C;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC3C,QAAQ,CAAC,QAAQ,EAAE;QAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IACzE,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;CAClC;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,SAAS,EAAE,CAK5E;AAED,wBAAgB,UAAU,CAAC,SAAS,EAAE,SAAS,GAAG,UAAU,CAyB3D;AAED,wBAAgB,UAAU,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,EAAE,QAAQ,EAAE,QAAQ,GAAG,YAAY,CAE7F;AAED,wBAAgB,WAAW,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,EAAE,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAExF"}
@@ -0,0 +1,41 @@
1
+ import { listBlueprintSlugs, readBlueprintFolder, readManifest, translations, } from './catalog.js';
2
+ import { stableJson } from './json.js';
3
+ export function loadBlueprints(root, taxonomy) {
4
+ return listBlueprintSlugs(root).map((slug) => {
5
+ const folder = readBlueprintFolder(root, slug);
6
+ return { ...folder, manifest: readManifest(taxonomy, folder) };
7
+ });
8
+ }
9
+ export function indexEntry(blueprint) {
10
+ const m = blueprint.manifest;
11
+ return {
12
+ slug: m.slug,
13
+ name: m.name,
14
+ version: m.version,
15
+ tier: m.tier,
16
+ maintainers: m.maintainers,
17
+ summary: m.summary,
18
+ stack: m.stack,
19
+ languages: m.languages,
20
+ platforms: m.platforms,
21
+ distribution: m.distribution,
22
+ project_type: m.project_type,
23
+ audience: m.audience,
24
+ requirements: m.requirements,
25
+ agents: m.agents,
26
+ options: m.options ?? {},
27
+ provides: { mcp: m.provides?.mcp ?? [], skills: m.provides?.skills ?? [] },
28
+ requires_tools: m.requires_tools ?? [],
29
+ deprecated: m.deprecated,
30
+ supersedes: m.supersedes,
31
+ files: blueprint.files,
32
+ i18n: translations(blueprint),
33
+ };
34
+ }
35
+ export function buildIndex(blueprints, taxonomy) {
36
+ return { schema: 1, taxonomy, blueprints: blueprints.map(indexEntry) };
37
+ }
38
+ export function renderIndex(blueprints, taxonomy) {
39
+ return stableJson(buildIndex(blueprints, taxonomy));
40
+ }
41
+ //# sourceMappingURL=build-index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-index.js","sourceRoot":"","sources":["../src/build-index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,YAAY,EACZ,YAAY,GAEb,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAwCvC,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,QAAkB;IAC7D,OAAO,kBAAkB,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QAC3C,MAAM,MAAM,GAAG,mBAAmB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC/C,OAAO,EAAE,GAAG,MAAM,EAAE,QAAQ,EAAE,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC;IACjE,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,SAAoB;IAC7C,MAAM,CAAC,GAAG,SAAS,CAAC,QAAQ,CAAC;IAC7B,OAAO;QACL,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,WAAW,EAAE,CAAC,CAAC,WAAW;QAC1B,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,SAAS,EAAE,CAAC,CAAC,SAAS;QACtB,SAAS,EAAE,CAAC,CAAC,SAAS;QACtB,YAAY,EAAE,CAAC,CAAC,YAAY;QAC5B,YAAY,EAAE,CAAC,CAAC,YAAY;QAC5B,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,YAAY,EAAE,CAAC,CAAC,YAAY;QAC5B,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,OAAO,EAAE,CAAC,CAAC,OAAO,IAAI,EAAE;QACxB,QAAQ,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,QAAQ,EAAE,GAAG,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,EAAE;QAC1E,cAAc,EAAE,CAAC,CAAC,cAAc,IAAI,EAAE;QACtC,UAAU,EAAE,CAAC,CAAC,UAAU;QACxB,UAAU,EAAE,CAAC,CAAC,UAAU;QACxB,KAAK,EAAE,SAAS,CAAC,KAAK;QACtB,IAAI,EAAE,YAAY,CAAC,SAAS,CAAC;KAC9B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,UAAgC,EAAE,QAAkB;IAC7E,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;AACzE,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,UAAgC,EAAE,QAAkB;IAC9E,OAAO,UAAU,CAAC,UAAU,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC;AACtD,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { Taxonomy } from './taxonomy.js';
2
+ /** Render the manifest schema as JSON Schema text, for editors and other tools. */
3
+ export declare function buildManifestJsonSchema(taxonomy: Taxonomy): string;
4
+ //# sourceMappingURL=build-schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-schema.d.ts","sourceRoot":"","sources":["../src/build-schema.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAW9C,mFAAmF;AACnF,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAUlE"}
@@ -0,0 +1,38 @@
1
+ import { z } from 'zod';
2
+ import { manifestObjectSchema } from './manifest.js';
3
+ import { stableJson } from './json.js';
4
+ const HEADER = {
5
+ title: 'Forgeprint blueprint manifest',
6
+ description: 'Generated from schema/taxonomy.yaml by `forgeprint build-schema`. Do not edit by hand. ' +
7
+ 'Rules that JSON Schema cannot express — the option field limit, the uniqueness of the ' +
8
+ 'stack/project_type/requirements combination, and CHANGELOG consistency — are enforced by ' +
9
+ '`forgeprint validate`.',
10
+ };
11
+ /** Render the manifest schema as JSON Schema text, for editors and other tools. */
12
+ export function buildManifestJsonSchema(taxonomy) {
13
+ const generated = z.toJSONSchema(manifestObjectSchema(taxonomy), {
14
+ target: 'draft-2020-12',
15
+ });
16
+ const { $schema, ...rest } = generated;
17
+ return stableJson({
18
+ $schema: $schema ?? 'https://json-schema.org/draft/2020-12/schema',
19
+ ...HEADER,
20
+ ...markArraysUnique(rest),
21
+ });
22
+ }
23
+ /**
24
+ * Every array field in a manifest rejects duplicates. That rule lives in a Zod
25
+ * refinement, which has no JSON Schema equivalent, so it is restored here.
26
+ */
27
+ function markArraysUnique(node) {
28
+ if (Array.isArray(node))
29
+ return node.map(markArraysUnique);
30
+ if (node === null || typeof node !== 'object')
31
+ return node;
32
+ const entries = Object.entries(node).map(([key, value]) => [key, markArraysUnique(value)]);
33
+ const result = Object.fromEntries(entries);
34
+ if (result['type'] === 'array')
35
+ result['uniqueItems'] = true;
36
+ return result;
37
+ }
38
+ //# sourceMappingURL=build-schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-schema.js","sourceRoot":"","sources":["../src/build-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAGvC,MAAM,MAAM,GAAG;IACb,KAAK,EAAE,+BAA+B;IACtC,WAAW,EACT,yFAAyF;QACzF,wFAAwF;QACxF,2FAA2F;QAC3F,wBAAwB;CAC3B,CAAC;AAEF,mFAAmF;AACnF,MAAM,UAAU,uBAAuB,CAAC,QAAkB;IACxD,MAAM,SAAS,GAAG,CAAC,CAAC,YAAY,CAAC,oBAAoB,CAAC,QAAQ,CAAC,EAAE;QAC/D,MAAM,EAAE,eAAe;KACxB,CAA4B,CAAC;IAC9B,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,GAAG,SAAS,CAAC;IACvC,OAAO,UAAU,CAAC;QAChB,OAAO,EAAE,OAAO,IAAI,8CAA8C;QAClE,GAAG,MAAM;QACT,GAAI,gBAAgB,CAAC,IAAI,CAA6B;KACvD,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,SAAS,gBAAgB,CAAC,IAAa;IACrC,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAC3D,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC3D,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,IAA+B,CAAC,CAAC,GAAG,CACjE,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,gBAAgB,CAAC,KAAK,CAAC,CAAU,CAC1D,CAAC;IACF,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IAC3C,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,OAAO;QAAE,MAAM,CAAC,aAAa,CAAC,GAAG,IAAI,CAAC;IAC7D,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,23 @@
1
+ import { type Manifest } from './manifest.js';
2
+ import { type Taxonomy } from './taxonomy.js';
3
+ export interface BlueprintFolder {
4
+ /** Folder name under `blueprints/`. */
5
+ readonly slug: string;
6
+ readonly dir: string;
7
+ /** Every file in the folder, as forward-slash paths relative to it, sorted. */
8
+ readonly files: readonly string[];
9
+ }
10
+ export interface Blueprint extends BlueprintFolder {
11
+ readonly manifest: Manifest;
12
+ }
13
+ /** Blueprint folder names, sorted, so that every generated file is stable. */
14
+ export declare function listBlueprintSlugs(root: string): string[];
15
+ export declare function readBlueprintFolder(root: string, slug: string): BlueprintFolder;
16
+ export declare function missingRequiredFiles(folder: BlueprintFolder): string[];
17
+ /** Parse and validate one manifest. Throws with a readable message on failure. */
18
+ export declare function parseManifest(taxonomy: Taxonomy, source: string): Manifest;
19
+ export declare function readManifest(taxonomy: Taxonomy, folder: BlueprintFolder): Manifest;
20
+ export declare function readBlueprintFile(folder: BlueprintFolder, file: string): string;
21
+ /** Community translations of overview.md, as language codes, sorted. */
22
+ export declare function translations(folder: BlueprintFolder): string[];
23
+ //# sourceMappingURL=catalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AAIA,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,EAAiB,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE7D,MAAM,WAAW,eAAe;IAC9B,uCAAuC;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,+EAA+E;IAC/E,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,SAAU,SAAQ,eAAe;IAChD,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;CAC7B;AAED,8EAA8E;AAC9E,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAOzD;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,eAAe,CAU/E;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,EAAE,CAEtE;AAED,kFAAkF;AAClF,wBAAgB,aAAa,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,QAAQ,CAI1E;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,eAAe,GAAG,QAAQ,CAElF;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE/E;AAED,wEAAwE;AACxE,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,EAAE,CAM9D"}
@@ -0,0 +1,55 @@
1
+ import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
2
+ import { join, relative, sep } from 'node:path';
3
+ import { parse } from 'yaml';
4
+ import { repoPaths, REQUIRED_BLUEPRINT_FILES } from './paths.js';
5
+ import { manifestSchema } from './manifest.js';
6
+ import { describeError } from './taxonomy.js';
7
+ /** Blueprint folder names, sorted, so that every generated file is stable. */
8
+ export function listBlueprintSlugs(root) {
9
+ const dir = repoPaths.blueprintsDir(root);
10
+ if (!existsSync(dir))
11
+ return [];
12
+ return readdirSync(dir, { withFileTypes: true })
13
+ .filter((entry) => entry.isDirectory())
14
+ .map((entry) => entry.name)
15
+ .sort();
16
+ }
17
+ export function readBlueprintFolder(root, slug) {
18
+ const dir = repoPaths.blueprintDir(root, slug);
19
+ if (!existsSync(dir) || !statSync(dir).isDirectory()) {
20
+ throw new Error(`No such blueprint: ${slug}`);
21
+ }
22
+ const files = readdirSync(dir, { recursive: true, withFileTypes: true })
23
+ .filter((entry) => entry.isFile())
24
+ .map((entry) => toPosix(relative(dir, join(entry.parentPath, entry.name))))
25
+ .sort();
26
+ return { slug, dir, files };
27
+ }
28
+ export function missingRequiredFiles(folder) {
29
+ return REQUIRED_BLUEPRINT_FILES.filter((file) => !folder.files.includes(file));
30
+ }
31
+ /** Parse and validate one manifest. Throws with a readable message on failure. */
32
+ export function parseManifest(taxonomy, source) {
33
+ const result = manifestSchema(taxonomy).safeParse(parse(source));
34
+ if (!result.success)
35
+ throw new Error(describeError(result.error));
36
+ return result.data;
37
+ }
38
+ export function readManifest(taxonomy, folder) {
39
+ return parseManifest(taxonomy, readFileSync(join(folder.dir, 'manifest.yaml'), 'utf8'));
40
+ }
41
+ export function readBlueprintFile(folder, file) {
42
+ return readFileSync(join(folder.dir, ...file.split('/')), 'utf8');
43
+ }
44
+ /** Community translations of overview.md, as language codes, sorted. */
45
+ export function translations(folder) {
46
+ return folder.files
47
+ .filter((file) => file.startsWith('i18n/') && file.endsWith('/overview.md'))
48
+ .map((file) => file.split('/')[1] ?? '')
49
+ .filter((lang) => lang.length > 0)
50
+ .sort();
51
+ }
52
+ function toPosix(path) {
53
+ return sep === '/' ? path : path.split(sep).join('/');
54
+ }
55
+ //# sourceMappingURL=catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ import { Command } from 'commander';
2
+ export declare const VERSION = "0.1.0";
3
+ /**
4
+ * Every pipeline step is a command here, so that contributors and maintainers
5
+ * get the same result locally that CI produces (ADR 0002).
6
+ */
7
+ export declare function createProgram(): Command;
8
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAYpC,eAAO,MAAM,OAAO,UAAU,CAAC;AAM/B;;;GAGG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAmHvC"}
package/dist/cli.js ADDED
@@ -0,0 +1,128 @@
1
+ import { mkdirSync, writeFileSync } from 'node:fs';
2
+ import { dirname } from 'node:path';
3
+ import { Command } from 'commander';
4
+ import { renderCodeowners } from './build-codeowners.js';
5
+ import { loadBlueprints, renderIndex } from './build-index.js';
6
+ import { buildManifestJsonSchema } from './build-schema.js';
7
+ import { readBlueprintFile, readBlueprintFolder, readManifest } from './catalog.js';
8
+ import { CONFIG_FILE, loadConfig } from './config.js';
9
+ import { lintSetup } from './lint-setup.js';
10
+ import { compareBlueprints, DEFAULT_THRESHOLD, renderReport } from './similarity.js';
11
+ import { findRepoRoot, repoPaths } from './paths.js';
12
+ import { loadTaxonomy } from './taxonomy.js';
13
+ import { validateCatalog } from './validate.js';
14
+ export const VERSION = '0.1.0';
15
+ /**
16
+ * Every pipeline step is a command here, so that contributors and maintainers
17
+ * get the same result locally that CI produces (ADR 0002).
18
+ */
19
+ export function createProgram() {
20
+ const program = new Command();
21
+ program
22
+ .name('forgeprint')
23
+ .description('Forgeprint catalog tooling')
24
+ .version(VERSION)
25
+ .option('--root <dir>', 'repository root (default: nearest one above the working directory)');
26
+ const rootOf = () => findRepoRoot(program.opts().root);
27
+ program
28
+ .command('validate')
29
+ .description('check every blueprint against the schema, the taxonomy and the catalog rules')
30
+ .action(() => {
31
+ const root = rootOf();
32
+ const report = validateCatalog(root);
33
+ for (const problem of report.problems) {
34
+ const where = problem.blueprint === undefined ? '' : `${problem.blueprint}: `;
35
+ console.error(`error ${where}${problem.message}`);
36
+ }
37
+ if (report.ok) {
38
+ console.log(`ok ${report.checked} blueprint(s) valid`);
39
+ return;
40
+ }
41
+ console.error(`\n${report.problems.length} problem(s) in ${report.checked} blueprint(s)`);
42
+ process.exitCode = 1;
43
+ });
44
+ program
45
+ .command('lint-setup')
46
+ .argument('<slug>', 'blueprint to check')
47
+ .description('check a blueprint setup.md against the structure and safety rules')
48
+ .action((slug) => {
49
+ const root = rootOf();
50
+ const folder = readBlueprintFolder(root, slug);
51
+ const manifest = readManifest(loadTaxonomy(root), folder);
52
+ const problems = lintSetup(readBlueprintFile(folder, 'setup.md'), {
53
+ options: manifest.options ?? {},
54
+ });
55
+ for (const problem of problems) {
56
+ console.error(`error setup.md:${problem.line} ${problem.rule}: ${problem.message}`);
57
+ }
58
+ if (problems.length === 0) {
59
+ console.log(`ok ${slug}/setup.md passes the setup rules`);
60
+ return;
61
+ }
62
+ console.error(`
63
+ ${problems.length} problem(s) in ${slug}/setup.md`);
64
+ process.exitCode = 1;
65
+ });
66
+ program
67
+ .command('similarity')
68
+ .argument('<slug>', 'blueprint to compare against the rest of the catalog')
69
+ .option('--threshold <ratio>', 'flag above this similarity', String(DEFAULT_THRESHOLD))
70
+ .option('--fail-on-flag', 'exit non-zero on a red flag, not only on a rule 9 rejection')
71
+ .description('report how close a blueprint is to the ones already in the catalog')
72
+ .action((slug, options) => {
73
+ const root = rootOf();
74
+ const taxonomy = loadTaxonomy(root);
75
+ const blueprints = loadBlueprints(root, taxonomy);
76
+ const subject = blueprints.find((blueprint) => blueprint.slug === slug);
77
+ if (subject === undefined)
78
+ throw new Error(`No such blueprint: ${slug}`);
79
+ const threshold = Number(options.threshold);
80
+ if (!Number.isFinite(threshold) || threshold <= 0 || threshold > 1) {
81
+ throw new Error('--threshold must be a ratio between 0 and 1');
82
+ }
83
+ const report = compareBlueprints(subject, blueprints.filter((blueprint) => blueprint.slug !== slug), threshold);
84
+ console.log(renderReport(report));
85
+ // A red flag is a question for the reviewer, which the pull request
86
+ // template makes them answer (rule 11). Only the objective rule — one
87
+ // blueprint per stack + project_type + requirements — fails the command.
88
+ if (report.closest?.sameCombination === true || options.failOnFlag === true) {
89
+ if (report.flagged || report.closest?.sameCombination === true)
90
+ process.exitCode = 1;
91
+ }
92
+ });
93
+ program
94
+ .command('build-index')
95
+ .description('regenerate docs/index.json from the catalog')
96
+ .action(() => {
97
+ const root = rootOf();
98
+ const taxonomy = loadTaxonomy(root);
99
+ write(repoPaths.index(root), renderIndex(loadBlueprints(root, taxonomy), taxonomy));
100
+ });
101
+ program
102
+ .command('build-schema')
103
+ .description('regenerate schema/manifest.schema.json from the taxonomy')
104
+ .action(() => {
105
+ const root = rootOf();
106
+ write(repoPaths.manifestSchema(root), buildManifestJsonSchema(loadTaxonomy(root)));
107
+ });
108
+ program
109
+ .command('build-codeowners')
110
+ .description('regenerate .github/CODEOWNERS from every manifest maintainers field')
111
+ .option('--owner <handle>', `core maintainer (default: core_maintainer in ${CONFIG_FILE})`)
112
+ .action((options) => {
113
+ const root = rootOf();
114
+ const owner = options.owner ?? loadConfig(root).core_maintainer;
115
+ if (owner === undefined) {
116
+ throw new Error(`No core maintainer: pass --owner or set core_maintainer in ${CONFIG_FILE}`);
117
+ }
118
+ const taxonomy = loadTaxonomy(root);
119
+ write(repoPaths.codeowners(root), renderCodeowners(loadBlueprints(root, taxonomy), owner));
120
+ });
121
+ return program;
122
+ }
123
+ function write(file, contents) {
124
+ mkdirSync(dirname(file), { recursive: true });
125
+ writeFileSync(file, contents, 'utf8');
126
+ console.log(`wrote ${file}`);
127
+ }
128
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Repository-level settings that the tooling cannot infer. Optional: every
4
+ * command that needs a value also accepts it as a flag.
5
+ */
6
+ export declare const configSchema: z.ZodObject<{
7
+ core_maintainer: z.ZodOptional<z.ZodString>;
8
+ repository: z.ZodOptional<z.ZodString>;
9
+ }, z.core.$strict>;
10
+ export type Config = z.infer<typeof configSchema>;
11
+ export declare const CONFIG_FILE = "forgeprint.json";
12
+ export declare function loadConfig(root: string): Config;
13
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;;GAGG;AACH,eAAO,MAAM,YAAY;;;kBAQd,CAAC;AAEZ,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAElD,eAAO,MAAM,WAAW,oBAAoB,CAAC;AAE7C,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQ/C"}
package/dist/config.js ADDED
@@ -0,0 +1,30 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { z } from 'zod';
4
+ import { describeError } from './taxonomy.js';
5
+ /**
6
+ * Repository-level settings that the tooling cannot infer. Optional: every
7
+ * command that needs a value also accepts it as a flag.
8
+ */
9
+ export const configSchema = z
10
+ .object({
11
+ /** GitHub login that owns the repository root in CODEOWNERS (rule 12). */
12
+ core_maintainer: z.string().min(1),
13
+ /** `owner/repo`, used in generated links. */
14
+ repository: z.string().regex(/^[^/\s]+\/[^/\s]+$/),
15
+ })
16
+ .partial()
17
+ .strict();
18
+ export const CONFIG_FILE = 'forgeprint.json';
19
+ export function loadConfig(root) {
20
+ const file = join(root, CONFIG_FILE);
21
+ if (!existsSync(file))
22
+ return {};
23
+ try {
24
+ return configSchema.parse(JSON.parse(readFileSync(file, 'utf8')));
25
+ }
26
+ catch (error) {
27
+ throw new Error(`Invalid ${CONFIG_FILE}: ${describeError(error)}`, { cause: error });
28
+ }
29
+ }
30
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC;KAC1B,MAAM,CAAC;IACN,0EAA0E;IAC1E,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAClC,6CAA6C;IAC7C,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,oBAAoB,CAAC;CACnD,CAAC;KACD,OAAO,EAAE;KACT,MAAM,EAAE,CAAC;AAIZ,MAAM,CAAC,MAAM,WAAW,GAAG,iBAAiB,CAAC;AAE7C,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IACrC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IACjC,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IACpE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,WAAW,WAAW,KAAK,aAAa,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IACvF,CAAC;AACH,CAAC"}
@@ -0,0 +1,15 @@
1
+ export * from './build-codeowners.js';
2
+ export * from './build-index.js';
3
+ export * from './build-schema.js';
4
+ export * from './catalog.js';
5
+ export * from './cli.js';
6
+ export * from './config.js';
7
+ export * from './json.js';
8
+ export * from './lint-setup.js';
9
+ export * from './manifest.js';
10
+ export * from './options.js';
11
+ export * from './paths.js';
12
+ export * from './similarity.js';
13
+ export * from './taxonomy.js';
14
+ export * from './validate.js';
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,15 @@
1
+ export * from './build-codeowners.js';
2
+ export * from './build-index.js';
3
+ export * from './build-schema.js';
4
+ export * from './catalog.js';
5
+ export * from './cli.js';
6
+ export * from './config.js';
7
+ export * from './json.js';
8
+ export * from './lint-setup.js';
9
+ export * from './manifest.js';
10
+ export * from './options.js';
11
+ export * from './paths.js';
12
+ export * from './similarity.js';
13
+ export * from './taxonomy.js';
14
+ export * from './validate.js';
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC"}
package/dist/json.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ /** Serialize a generated artifact: 2-space JSON with a trailing newline. */
2
+ export declare function stableJson(value: unknown): string;
3
+ /** Normalize line endings so drift checks do not fire on checkout differences. */
4
+ export declare function normalizeNewlines(text: string): string;
5
+ //# sourceMappingURL=json.d.ts.map