@grove-dev/core 0.1.5 → 0.2.5

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Turtuvshin Byambaa
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -1,55 +1,43 @@
1
- import { type CuratedConfig } from "./schema.js";
1
+ import { type GroveConfig } from "./schema.js";
2
2
  /**
3
- * The full payload written to data/generated/apps.full.json.
3
+ * The full payload written to data/generated/records.full.json.
4
4
  * Carries every normalized record, regardless of visibility.
5
5
  */
6
- export interface AppsFullPayload {
6
+ export interface RecordsFullPayload {
7
7
  schemaVersion: number;
8
+ blueprint: string;
8
9
  generatedAt: string;
9
- totalApps: number;
10
- visibleApps: number;
11
- apps: Array<Record<string, unknown>>;
10
+ totalRecords: number;
11
+ visibleRecords: number;
12
+ records: Array<Record<string, unknown>>;
12
13
  }
13
14
  /**
14
- * The slim payload written to data/generated/apps.index.json.
15
+ * The slim payload written to data/generated/records.index.json.
15
16
  * Carries only what list and search pages need.
16
17
  */
17
- export interface AppsIndexPayload {
18
+ export interface RecordsIndexPayload {
18
19
  schemaVersion: number;
20
+ blueprint: string;
19
21
  generatedAt: string;
20
- totalApps: number;
21
- apps: Array<Record<string, unknown>>;
22
+ totalRecords: number;
23
+ records: Array<Record<string, unknown>>;
22
24
  }
23
25
  /**
24
- * The TS file written to src/data/config.ts. Sites import this for
25
- * a typed view of curated.config.ts. Auto-generated; do not edit.
26
- */
27
- export interface SiteConfigTsInput {
28
- name: string;
29
- tagline: string;
30
- description: string;
31
- siteUrl: string;
32
- repoUrl: string;
33
- itemLabel: string;
34
- }
35
- export declare function buildSiteConfigTs(input: SiteConfigTsInput): string;
36
- /**
37
- * Read every apps/*.yml in the project, normalize, and build:
38
- * - data/generated/apps.full.json (full records, all visibility)
39
- * - data/generated/apps.index.json (slim, visible-only)
40
- * - data/generated/apps.json (compatibility alias of apps.full.json)
41
- * - src/data/config.ts (typed view of curated.config.ts)
26
+ * `generate` reads every records/*.yml in the project, normalizes them
27
+ * via the blueprint schema, and writes:
28
+ * - data/generated/records.full.json (full records, all visibility)
29
+ * - data/generated/records.index.json (slim, visible-only)
30
+ * - data/generated/records.json (alias of records.full.json)
42
31
  *
43
- * Returns a small summary; throws on schema errors.
32
+ * Returns file paths and counters; throws on schema errors.
44
33
  */
45
- export interface BuildDataResult {
46
- totalApps: number;
47
- visibleApps: number;
34
+ export interface GenerateResult {
35
+ totalRecords: number;
36
+ visibleRecords: number;
48
37
  fullPath: string;
49
38
  indexPath: string;
50
39
  aliasPath: string;
51
- configTsPath: string;
52
40
  errors: string[];
53
41
  }
54
- export declare function buildData(cwd?: string, config?: CuratedConfig): Promise<BuildDataResult>;
42
+ export declare function generate(cwd?: string, config?: GroveConfig): Promise<GenerateResult>;
55
43
  //# sourceMappingURL=build-data.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"build-data.d.ts","sourceRoot":"","sources":["../src/build-data.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,aAAa,EAInB,MAAM,aAAa,CAAC;AAGrB;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACtC;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACtC;AAED;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM,CAwBlE;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,wBAAsB,SAAS,CAC7B,GAAG,SAAgB,EACnB,MAAM,CAAC,EAAE,aAAa,GACrB,OAAO,CAAC,eAAe,CAAC,CAyF1B"}
1
+ {"version":3,"file":"build-data.d.ts","sourceRoot":"","sources":["../src/build-data.ts"],"names":[],"mappings":"AAGA,OAAO,EAML,KAAK,WAAW,EAEjB,MAAM,aAAa,CAAC;AA2DrB;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACzC;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACzC;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,wBAAsB,QAAQ,CAC5B,GAAG,SAAgB,EACnB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,cAAc,CAAC,CAoGzB"}
@@ -1,115 +1,152 @@
1
1
  import { mkdir, readdir, readFile, writeFile } from "node:fs/promises";
2
2
  import { basename, join, resolve } from "node:path";
3
- import { normalizeAppRecord, parseAppYaml, toIndexApp, } from "./schema.js";
3
+ import { parse as parseYaml } from "yaml";
4
+ import { blueprintKind, recordsFileSchema, toIndexRecord, unwrapDecisions, decisionsFileSchema, } from "./schema.js";
4
5
  import { loadConfig } from "./config.js";
5
- export function buildSiteConfigTs(input) {
6
- return `/**
7
- * AUTO-GENERATED by grove build-data — do not edit by hand.
8
- * Re-run \`grove build-data\` after changing curated.config.ts.
6
+ /**
7
+ * Apply a minimal decisions.yml override to a normalized record. The
8
+ * human curation layer is the single source of truth for visibility:
9
+ * - For project records: decision.visibility (when present) wins
10
+ * over record.health.visibility. The health block's other fields
11
+ * (status, tier, etc.) are untouched.
12
+ * - For resource-hub and ecosystem-map records: decision.visibility
13
+ * is written to the record's top-level `visibility` field (these
14
+ * blueprints have no `health` block).
15
+ *
16
+ * The full override pipeline (with reasons surfaced in the index
17
+ * payload) is a V2 feature; V1 keeps the merge intentional and small.
9
18
  */
10
-
11
- export type SiteConfig = {
12
- name: string;
13
- tagline: string;
14
- description: string;
15
- siteUrl: string;
16
- repoUrl: string;
17
- itemLabel: string;
18
- };
19
-
20
- export const siteConfig: SiteConfig = {
21
- name: ${JSON.stringify(input.name)},
22
- tagline: ${JSON.stringify(input.tagline)},
23
- description: ${JSON.stringify(input.description)},
24
- siteUrl: ${JSON.stringify(input.siteUrl)},
25
- repoUrl: ${JSON.stringify(input.repoUrl)},
26
- itemLabel: ${JSON.stringify(input.itemLabel)},
27
- };
28
- `;
19
+ function applyDecision(record, visibilityById) {
20
+ const override = visibilityById.get(record.slug);
21
+ if (!override)
22
+ return record;
23
+ if (record.kind === "project") {
24
+ const existing = record.health;
25
+ const fallback = {
26
+ status: "unknown",
27
+ maturity: "unknown",
28
+ tier: "listed",
29
+ visibility: "keep",
30
+ cleanupCandidate: false,
31
+ staleReason: null,
32
+ confidence: "medium",
33
+ reasons: [],
34
+ };
35
+ const merged = { ...(existing ?? fallback), visibility: override };
36
+ return { ...record, health: merged };
37
+ }
38
+ // Resource-hub / ecosystem-map: no `health` block; the top-level
39
+ // `visibility` field on the base schema is the source of truth.
40
+ return { ...record, visibility: override };
29
41
  }
30
- export async function buildData(cwd = process.cwd(), config) {
31
- const cfg = config ?? (await loadConfig(cwd));
32
- const appsDir = resolve(cwd, cfg.paths.appsDir);
33
- const outDir = resolve(cwd, cfg.paths.generatedDir);
34
- await mkdir(outDir, { recursive: true });
35
- let entries = [];
42
+ async function loadDecisionVisibility(decisionsPath, cwd) {
36
43
  try {
37
- entries = await readdir(appsDir);
44
+ const raw = await readFile(resolve(cwd, decisionsPath), "utf8");
45
+ const parsed = decisionsFileSchema.parse(parseYaml(raw) ?? {});
46
+ const decisions = unwrapDecisions(parsed);
47
+ const out = new Map();
48
+ for (const d of decisions)
49
+ out.set(d.id, d.decision.visibility);
50
+ return out;
38
51
  }
39
52
  catch {
40
- entries = [];
53
+ // missing or invalid decisions.yml → no overrides
54
+ return new Map();
41
55
  }
56
+ }
57
+ export async function generate(cwd = process.cwd(), config) {
58
+ const cfg = config ?? (await loadConfig(cwd));
59
+ const recordsDir = resolve(cwd, cfg.paths.recordsDir);
60
+ const outDir = resolve(cwd, cfg.paths.generatedDir);
61
+ await mkdir(outDir, { recursive: true });
62
+ // Re-emit the site config as JSON alongside the records so the
63
+ // Astro (or any framework) template can pick up the user's
64
+ // branding, theme, and nav without parsing `grove.config.ts`
65
+ // at render time. The CLI runs `generate` ahead of `build`,
66
+ // so this stays in sync with the consumer's config edits.
67
+ const siteConfigPayload = {
68
+ blueprint: cfg.blueprint,
69
+ name: cfg.site.name,
70
+ tagline: cfg.site.tagline,
71
+ description: cfg.site.description ?? cfg.site.tagline,
72
+ siteUrl: cfg.site.url ?? "https://example.com",
73
+ repoUrl: cfg.site.repoUrl ?? "",
74
+ nav: cfg.nav,
75
+ theme: cfg.theme,
76
+ integrations: cfg.integrations,
77
+ };
78
+ await writeFile(join(outDir, "site-config.json"), JSON.stringify(siteConfigPayload, null, 2), "utf8");
79
+ const expectedKind = blueprintKind[cfg.blueprint];
80
+ const entries = await readdir(recordsDir).catch(() => []);
42
81
  const files = entries.filter((f) => f.endsWith(".yml")).sort();
43
- const apps = [];
82
+ // Load human curation decisions once; missing file → empty map.
83
+ const visibilityById = await loadDecisionVisibility(cfg.paths.decisions, cwd);
84
+ const out = [];
44
85
  const errors = [];
45
86
  for (const file of files) {
46
87
  const fileSlug = basename(file, ".yml");
47
88
  try {
48
- const text = await readFile(join(appsDir, file), "utf8");
49
- const raw = parseAppYaml(text, fileSlug);
50
- const app = normalizeAppRecord(raw, fileSlug);
51
- if (app.slug !== fileSlug) {
52
- app.slug = fileSlug;
53
- }
54
- apps.push(app);
89
+ const text = await readFile(join(recordsDir, file), "utf8");
90
+ const raw = (parseYaml(text) ?? {});
91
+ if (!raw.kind)
92
+ raw.kind = expectedKind;
93
+ const normalized = recordsFileSchema.parse(raw);
94
+ normalized.slug = fileSlug;
95
+ // Apply decisions.yml visibility override on top of the record.
96
+ // The index payload then derives visibility from record.health,
97
+ // which is now the merged result.
98
+ out.push(applyDecision(normalized, visibilityById));
55
99
  }
56
100
  catch (err) {
57
101
  errors.push(`${file}: ${err.message}`);
58
102
  }
59
103
  }
60
104
  if (errors.length > 0) {
61
- const e = new Error(`build-data failed: ${errors.length} schema error(s)`);
105
+ const e = new Error(`generate failed: ${errors.length} schema error(s)`);
62
106
  e.details = errors;
63
107
  throw e;
64
108
  }
65
- apps.sort((a, b) => {
66
- const sa = a.stars ?? 0;
67
- const sb = b.stars ?? 0;
68
- if (sb !== sa)
69
- return sb - sa;
70
- return (a.name ?? "").localeCompare(b.name ?? "");
109
+ out.sort((a, b) => nameOf(a).localeCompare(nameOf(b)));
110
+ const indexRecords = out
111
+ .map((record) => toIndexRecord(record))
112
+ .filter((r) => {
113
+ const vis = r.visibility;
114
+ return vis !== "hide" && vis !== "remove";
71
115
  });
72
- const indexApps = apps
73
- .map((app) => toIndexApp(app))
74
- .filter((a) => a.visibility !== "hide");
75
116
  const generatedAt = new Date().toISOString();
76
117
  const fullPayload = {
77
118
  schemaVersion: 1,
119
+ blueprint: cfg.blueprint,
78
120
  generatedAt,
79
- totalApps: apps.length,
80
- visibleApps: indexApps.length,
81
- apps: apps,
121
+ totalRecords: out.length,
122
+ visibleRecords: indexRecords.length,
123
+ records: out,
82
124
  };
83
125
  const indexPayload = {
84
126
  schemaVersion: 1,
127
+ blueprint: cfg.blueprint,
85
128
  generatedAt,
86
- totalApps: indexApps.length,
87
- apps: indexApps,
129
+ totalRecords: indexRecords.length,
130
+ records: indexRecords,
88
131
  };
89
- const fullPath = join(outDir, "apps.full.json");
90
- const indexPath = join(outDir, "apps.index.json");
91
- const aliasPath = join(outDir, "apps.json");
132
+ const fullPath = join(outDir, "records.full.json");
133
+ const indexPath = join(outDir, "records.index.json");
134
+ const aliasPath = join(outDir, "records.json");
92
135
  await writeFile(fullPath, JSON.stringify(fullPayload, null, 2), "utf8");
93
136
  await writeFile(indexPath, JSON.stringify(indexPayload, null, 2), "utf8");
94
137
  await writeFile(aliasPath, JSON.stringify(fullPayload, null, 2), "utf8");
95
- const configTsPath = resolve(cwd, "src/data/config.ts");
96
- const configTs = buildSiteConfigTs({
97
- name: cfg.name,
98
- tagline: cfg.tagline,
99
- description: cfg.description ?? cfg.tagline,
100
- siteUrl: cfg.siteUrl ?? "https://example.com",
101
- repoUrl: cfg.repoUrl ?? "",
102
- itemLabel: cfg.itemLabel,
103
- });
104
- await writeFile(configTsPath, configTs, "utf8");
105
138
  return {
106
- totalApps: apps.length,
107
- visibleApps: indexApps.length,
139
+ totalRecords: out.length,
140
+ visibleRecords: indexRecords.length,
108
141
  fullPath,
109
142
  indexPath,
110
143
  aliasPath,
111
- configTsPath,
112
144
  errors,
113
145
  };
114
146
  }
147
+ function nameOf(record) {
148
+ if (record.kind === "resource")
149
+ return record.title;
150
+ return record.name;
151
+ }
115
152
  //# sourceMappingURL=build-data.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"build-data.js","sourceRoot":"","sources":["../src/build-data.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"build-data.js","sourceRoot":"","sources":["../src/build-data.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAC1C,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,mBAAmB,GAGpB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC;;;;;;;;;;;;GAYG;AACH,SAAS,aAAa,CACpB,MAAgB,EAChB,cAAmC;IAEnC,MAAM,QAAQ,GAAG,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACjD,IAAI,CAAC,QAAQ;QAAE,OAAO,MAAM,CAAC;IAC7B,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC9B,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC;QAC/B,MAAM,QAAQ,GAAG;YACf,MAAM,EAAE,SAAkB;YAC1B,QAAQ,EAAE,SAAkB;YAC5B,IAAI,EAAE,QAAiB;YACvB,UAAU,EAAE,MAAe;YAC3B,gBAAgB,EAAE,KAAK;YACvB,WAAW,EAAE,IAAI;YACjB,UAAU,EAAE,QAAiB;YAC7B,OAAO,EAAE,EAAc;SACxB,CAAC;QACF,MAAM,MAAM,GAAG,EAAE,GAAG,CAAC,QAAQ,IAAI,QAAQ,CAAC,EAAE,UAAU,EAAE,QAAsC,EAAE,CAAC;QACjG,OAAO,EAAE,GAAG,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IACvC,CAAC;IACD,iEAAiE;IACjE,gEAAgE;IAChE,OAAO,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,QAAoC,EAAE,CAAC;AACzE,CAAC;AAED,KAAK,UAAU,sBAAsB,CACnC,aAAqB,EACrB,GAAW;IAEX,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,aAAa,CAAC,EAAE,MAAM,CAAC,CAAC;QAChE,MAAM,MAAM,GAAG,mBAAmB,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;QAC/D,MAAM,SAAS,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;QAC1C,MAAM,GAAG,GAAG,IAAI,GAAG,EAAkB,CAAC;QACtC,KAAK,MAAM,CAAC,IAAI,SAAS;YAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QAChE,OAAO,GAAG,CAAC;IACb,CAAC;IAAC,MAAM,CAAC;QACP,kDAAkD;QAClD,OAAO,IAAI,GAAG,EAAE,CAAC;IACnB,CAAC;AACH,CAAC;AA6CD,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,EACnB,MAAoB;IAEpB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9C,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACtD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IACpD,MAAM,KAAK,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEzC,+DAA+D;IAC/D,2DAA2D;IAC3D,6DAA6D;IAC7D,4DAA4D;IAC5D,0DAA0D;IAC1D,MAAM,iBAAiB,GAAG;QACxB,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI;QACnB,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,OAAO;QACzB,WAAW,EAAE,GAAG,CAAC,IAAI,CAAC,WAAW,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO;QACrD,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,qBAAqB;QAC9C,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE;QAC/B,GAAG,EAAE,GAAG,CAAC,GAAG;QACZ,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,YAAY,EAAE,GAAG,CAAC,YAAY;KAC/B,CAAC;IACF,MAAM,SAAS,CACb,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,EAChC,IAAI,CAAC,SAAS,CAAC,iBAAiB,EAAE,IAAI,EAAE,CAAC,CAAC,EAC1C,MAAM,CACP,CAAC;IAEF,MAAM,YAAY,GAAG,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAClD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAc,CAAC,CAAC;IACtE,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAE/D,gEAAgE;IAChE,MAAM,cAAc,GAAG,MAAM,sBAAsB,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;IAE9E,MAAM,GAAG,GAAe,EAAE,CAAC;IAC3B,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACxC,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;YAC5D,MAAM,GAAG,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,CAA4B,CAAC;YAC/D,IAAI,CAAC,GAAG,CAAC,IAAI;gBAAE,GAAG,CAAC,IAAI,GAAG,YAAY,CAAC;YACvC,MAAM,UAAU,GAAG,iBAAiB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAChD,UAAU,CAAC,IAAI,GAAG,QAAQ,CAAC;YAC3B,gEAAgE;YAChE,gEAAgE;YAChE,kCAAkC;YAClC,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC,CAAC;QACtD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,KAAM,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,CAAC,GAAG,IAAI,KAAK,CAAC,oBAAoB,MAAM,CAAC,MAAM,kBAAkB,CAAC,CAAC;QACxE,CAAoC,CAAC,OAAO,GAAG,MAAM,CAAC;QACvD,MAAM,CAAC,CAAC;IACV,CAAC;IAED,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAEvD,MAAM,YAAY,GAAG,GAAG;SACrB,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;SACtC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;QACZ,MAAM,GAAG,GAAI,CAA6B,CAAC,UAAU,CAAC;QACtD,OAAO,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,QAAQ,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEL,MAAM,WAAW,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC7C,MAAM,WAAW,GAAuB;QACtC,aAAa,EAAE,CAAC;QAChB,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,WAAW;QACX,YAAY,EAAE,GAAG,CAAC,MAAM;QACxB,cAAc,EAAE,YAAY,CAAC,MAAM;QACnC,OAAO,EAAE,GAAgD;KAC1D,CAAC;IACF,MAAM,YAAY,GAAwB;QACxC,aAAa,EAAE,CAAC;QAChB,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,WAAW;QACX,YAAY,EAAE,YAAY,CAAC,MAAM;QACjC,OAAO,EAAE,YAAyD;KACnE,CAAC;IAEF,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;IACnD,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;IACrD,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAC/C,MAAM,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IACxE,MAAM,SAAS,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAC1E,MAAM,SAAS,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAEzE,OAAO;QACL,YAAY,EAAE,GAAG,CAAC,MAAM;QACxB,cAAc,EAAE,YAAY,CAAC,MAAM;QACnC,QAAQ;QACR,SAAS;QACT,SAAS;QACT,MAAM;KACP,CAAC;AACJ,CAAC;AAED,SAAS,MAAM,CAAC,MAAgB;IAC9B,IAAI,MAAM,CAAC,IAAI,KAAK,UAAU;QAAE,OAAO,MAAM,CAAC,KAAK,CAAC;IACpD,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC"}
package/dist/config.d.ts CHANGED
@@ -1,5 +1,16 @@
1
- import { type CuratedConfig } from "./schema.js";
2
- export type { CuratedConfig };
3
- export declare function loadConfig(cwd?: string, configPath?: string): Promise<CuratedConfig>;
4
- export declare function defineConfig(config: CuratedConfig): CuratedConfig;
1
+ import { type GroveConfig } from "./schema.js";
2
+ export type { GroveConfig };
3
+ /**
4
+ * Load the Grove project config. The config file is the single source
5
+ * of truth for blueprint, site metadata, paths, integrations, theme,
6
+ * and component overrides.
7
+ *
8
+ * Default name: `grove.config.ts`. Override with the second arg.
9
+ */
10
+ export declare function loadConfig(cwd?: string, configPath?: string): Promise<GroveConfig>;
11
+ /**
12
+ * Define and validate a Grove config. Used at the bottom of a
13
+ * `grove.config.ts` file so editors get good type hints.
14
+ */
15
+ export declare function defineConfig(config: GroveConfig): GroveConfig;
5
16
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAEtE,YAAY,EAAE,aAAa,EAAE,CAAC;AAE9B,wBAAsB,UAAU,CAAC,GAAG,SAAgB,EAAE,UAAU,SAAsB,GAAG,OAAO,CAAC,aAAa,CAAC,CAM9G;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,aAAa,GAAG,aAAa,CAEjE"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,OAAO,EAAqB,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAElE,YAAY,EAAE,WAAW,EAAE,CAAC;AAE5B;;;;;;GAMG;AACH,wBAAsB,UAAU,CAC9B,GAAG,SAAgB,EACnB,UAAU,SAAoB,GAC7B,OAAO,CAAC,WAAW,CAAC,CAMtB;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,WAAW,CAE7D"}
package/dist/config.js CHANGED
@@ -1,14 +1,25 @@
1
1
  import { resolve } from "node:path";
2
2
  import { createJiti } from "jiti";
3
- import { curatedConfigSchema } from "./schema.js";
4
- export async function loadConfig(cwd = process.cwd(), configPath = "curated.config.ts") {
3
+ import { groveConfigSchema } from "./schema.js";
4
+ /**
5
+ * Load the Grove project config. The config file is the single source
6
+ * of truth for blueprint, site metadata, paths, integrations, theme,
7
+ * and component overrides.
8
+ *
9
+ * Default name: `grove.config.ts`. Override with the second arg.
10
+ */
11
+ export async function loadConfig(cwd = process.cwd(), configPath = "grove.config.ts") {
5
12
  const resolved = resolve(cwd, configPath);
6
13
  const jiti = createJiti(import.meta.url);
7
- const mod = await jiti.import(resolved, { default: true });
14
+ const mod = (await jiti.import(resolved, { default: true }));
8
15
  const raw = mod.default ?? mod.config ?? mod;
9
- return curatedConfigSchema.parse(raw);
16
+ return groveConfigSchema.parse(raw);
10
17
  }
18
+ /**
19
+ * Define and validate a Grove config. Used at the bottom of a
20
+ * `grove.config.ts` file so editors get good type hints.
21
+ */
11
22
  export function defineConfig(config) {
12
- return curatedConfigSchema.parse(config);
23
+ return groveConfigSchema.parse(config);
13
24
  }
14
25
  //# sourceMappingURL=config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAClC,OAAO,EAAE,mBAAmB,EAAsB,MAAM,aAAa,CAAC;AAItE,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,EAAE,UAAU,GAAG,mBAAmB;IACpF,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACzC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAA4B,CAAC;IACtF,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC;IAC7C,OAAO,mBAAmB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAAqB;IAChD,OAAO,mBAAmB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;AAC3C,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAClC,OAAO,EAAE,iBAAiB,EAAoB,MAAM,aAAa,CAAC;AAIlE;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,EACnB,UAAU,GAAG,iBAAiB;IAE9B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACzC,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAA4B,CAAC;IACxF,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC;IAC7C,OAAO,iBAAiB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AACtC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,MAAmB;IAC9C,OAAO,iBAAiB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;AACzC,CAAC"}
@@ -1,28 +1,31 @@
1
- import { type AppRecord } from "./schema.js";
2
- import { type CuratedConfig } from "./config.js";
3
- export interface ReviewCandidate {
1
+ import { type GroveConfig, type Resource } from "./schema.js";
2
+ export interface CleanupCandidate {
4
3
  slug: string;
5
4
  name: string;
6
- repoUrl: string;
5
+ url: string;
7
6
  status: string;
8
7
  tier: string;
9
8
  staleReason: string | null;
10
9
  lastCommitAt: string | null;
11
10
  stars: number;
12
11
  }
13
- export interface ReviewReport {
12
+ export interface CleanupReport {
14
13
  generatedAt: string;
14
+ blueprint: string;
15
15
  totalCandidates: number;
16
- candidates: ReviewCandidate[];
16
+ candidates: CleanupCandidate[];
17
17
  }
18
- /** Compute the set of review candidates from normalized app records. */
19
- export declare function pickReviewCandidates(apps: AppRecord[]): AppRecord[];
18
+ /** Filter records down to the ones that need a human curation pass. */
19
+ export declare function pickCleanupCandidates(records: Resource[]): Resource[];
20
20
  /**
21
- * Read every apps/*.yml, normalize, then write data/generated/review-report.json
22
- * with cleanup candidates (unknown / needs_review / cleanupCandidate).
21
+ * Read every record YAML under `config.paths.recordsDir`, normalize,
22
+ * then write `data/generated/cleanup-report.json` with the list of
23
+ * records that need human attention (stale / unknown / cleanup).
24
+ *
25
+ * V1 name for what was previously `review`.
23
26
  */
24
- export declare function buildReviewReport(cwd?: string, config?: CuratedConfig): Promise<{
25
- report: ReviewReport;
27
+ export declare function cleanupStale(cwd?: string, config?: GroveConfig): Promise<{
28
+ report: CleanupReport;
26
29
  path: string;
27
30
  }>;
28
31
  //# sourceMappingURL=decisions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"decisions.d.ts","sourceRoot":"","sources":["../src/decisions.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAoC,MAAM,aAAa,CAAC;AAC/E,OAAO,EAAE,KAAK,aAAa,EAAc,MAAM,aAAa,CAAC;AAE7D,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,eAAe,EAAE,CAAC;CAC/B;AAeD,wEAAwE;AACxE,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,SAAS,EAAE,CAOnE;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,GAAG,SAAgB,EACnB,MAAM,CAAC,EAAE,aAAa,GACrB,OAAO,CAAC;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CA6BjD"}
1
+ {"version":3,"file":"decisions.d.ts","sourceRoot":"","sources":["../src/decisions.ts"],"names":[],"mappings":"AAGA,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,QAAQ,EACd,MAAM,aAAa,CAAC;AAGrB,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,gBAAgB,EAAE,CAAC;CAChC;AAsBD,uEAAuE;AACvE,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,QAAQ,EAAE,GAAG,QAAQ,EAAE,CAOrE;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAChC,GAAG,SAAgB,EACnB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAmClD"}
package/dist/decisions.js CHANGED
@@ -1,56 +1,76 @@
1
1
  import { mkdir, readdir, readFile, writeFile } from "node:fs/promises";
2
2
  import { basename, join, resolve } from "node:path";
3
- import { normalizeAppRecord, parseAppYaml } from "./schema.js";
3
+ import { parse as parseYaml } from "yaml";
4
+ import { blueprintKind, recordsFileSchema, } from "./schema.js";
4
5
  import { loadConfig } from "./config.js";
5
- function toCandidate(app) {
6
+ function toCandidate(record) {
7
+ const name = record.kind === "resource" ? record.title : record.name;
8
+ const url = record.links?.github ?? record.links?.website ?? record.links?.source ?? "";
9
+ const health = record
10
+ .health;
11
+ const gh = record
12
+ .github?.repository;
6
13
  return {
7
- slug: app.slug,
8
- name: app.name,
9
- repoUrl: app.repoUrl,
10
- status: app.status,
11
- tier: app.tier,
12
- staleReason: app.staleReason,
13
- lastCommitAt: app.lastCommitAt ?? null,
14
- stars: app.stars ?? 0,
14
+ slug: record.slug,
15
+ name,
16
+ url,
17
+ status: health?.status ?? "unknown",
18
+ tier: health?.tier ?? "experimental",
19
+ staleReason: health?.staleReason ?? null,
20
+ lastCommitAt: gh?.pushed_at ?? null,
21
+ stars: gh?.stargazers_count ?? 0,
15
22
  };
16
23
  }
17
- /** Compute the set of review candidates from normalized app records. */
18
- export function pickReviewCandidates(apps) {
19
- return apps.filter((app) => app.cleanupCandidate ||
20
- app.status === "unknown" ||
21
- app.status === "needs_review");
24
+ /** Filter records down to the ones that need a human curation pass. */
25
+ export function pickCleanupCandidates(records) {
26
+ return records.filter((r) => {
27
+ const health = r.health;
28
+ if (health?.cleanupCandidate)
29
+ return true;
30
+ if (health?.status === "unknown" || health?.status === "needs_review")
31
+ return true;
32
+ return false;
33
+ });
22
34
  }
23
35
  /**
24
- * Read every apps/*.yml, normalize, then write data/generated/review-report.json
25
- * with cleanup candidates (unknown / needs_review / cleanupCandidate).
36
+ * Read every record YAML under `config.paths.recordsDir`, normalize,
37
+ * then write `data/generated/cleanup-report.json` with the list of
38
+ * records that need human attention (stale / unknown / cleanup).
39
+ *
40
+ * V1 name for what was previously `review`.
26
41
  */
27
- export async function buildReviewReport(cwd = process.cwd(), config) {
42
+ export async function cleanupStale(cwd = process.cwd(), config) {
28
43
  const cfg = config ?? (await loadConfig(cwd));
29
- const appsDir = resolve(cwd, cfg.paths.appsDir);
44
+ const recordsDir = resolve(cwd, cfg.paths.recordsDir);
30
45
  const outDir = resolve(cwd, cfg.paths.generatedDir);
31
46
  await mkdir(outDir, { recursive: true });
32
- let entries = [];
33
- try {
34
- entries = await readdir(appsDir);
35
- }
36
- catch {
37
- entries = [];
38
- }
47
+ const expectedKind = blueprintKind[cfg.blueprint];
48
+ const entries = await readdir(recordsDir).catch(() => []);
39
49
  const files = entries.filter((f) => f.endsWith(".yml")).sort();
40
- const apps = [];
50
+ const records = [];
41
51
  for (const file of files) {
42
52
  const fileSlug = basename(file, ".yml");
43
- const text = await readFile(join(appsDir, file), "utf8");
44
- const raw = parseAppYaml(text, fileSlug);
45
- apps.push(normalizeAppRecord(raw, fileSlug));
53
+ const text = await readFile(join(recordsDir, file), "utf8");
54
+ const raw = (parseYaml(text) ?? {});
55
+ if (!raw.kind)
56
+ raw.kind = expectedKind;
57
+ try {
58
+ const normalized = recordsFileSchema.parse(raw);
59
+ normalized.slug = fileSlug;
60
+ records.push(normalized);
61
+ }
62
+ catch {
63
+ // skip — validation surfaces the error
64
+ }
46
65
  }
47
- const candidates = pickReviewCandidates(apps).map(toCandidate);
66
+ const candidates = pickCleanupCandidates(records).map(toCandidate);
48
67
  const report = {
49
68
  generatedAt: new Date().toISOString(),
69
+ blueprint: cfg.blueprint,
50
70
  totalCandidates: candidates.length,
51
71
  candidates,
52
72
  };
53
- const path = join(outDir, "review-report.json");
73
+ const path = join(outDir, "cleanup-report.json");
54
74
  await writeFile(path, JSON.stringify(report, null, 2), "utf8");
55
75
  return { report, path };
56
76
  }
@@ -1 +1 @@
1
- {"version":3,"file":"decisions.js","sourceRoot":"","sources":["../src/decisions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"decisions.js","sourceRoot":"","sources":["../src/decisions.ts"],"names":[],"mappings":"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"}
package/dist/enrich.d.ts CHANGED
@@ -7,8 +7,8 @@
7
7
  * the page render doesn't include the standard "X license" link text.
8
8
  *
9
9
  * The returned shape is compatible with the GitHub REST `repository`
10
- * block used in `data/apps/<slug>.yml`, so a subsequent token-backed
11
- * sync can fill in the rest of the fields.
10
+ * block used in `data/records/<slug>.yml` for `kind: project` records,
11
+ * so a subsequent token-backed sync can fill in the rest of the fields.
12
12
  */
13
13
  export interface EnrichedFields {
14
14
  license: string | null;