@marlinjai/clearify 2.1.0 → 2.2.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.
package/README.md CHANGED
@@ -62,6 +62,7 @@ export default defineConfig({
62
62
 
63
63
  - Node.js 22 or later
64
64
  - npm, pnpm, or yarn
65
+ - Zod 4.6.7 or later (clearify validates config with the Zod 4 API; versions below 4.6.6 are affected by GHSA-mrhx-c7xc-m3w5)
65
66
  - For hub onboarding: a GitHub account and (for CLI-assisted secret provisioning) a GitHub OAuth App. See [Installation](./docs/public/installation.md) for prerequisites per path.
66
67
 
67
68
  ## Links
@@ -10,6 +10,16 @@ import { globbySync } from "globby";
10
10
  function toTitleCase(str) {
11
11
  return str.replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
12
12
  }
13
+ function inferDocType(filePath) {
14
+ const normalized = filePath.replace(/\\/g, "/").toLowerCase();
15
+ const file = basename(normalized, extname(normalized));
16
+ if (file === "readme") return "readme";
17
+ if (file === "changelog" || file === "changes") return "changelog";
18
+ if (file === "roadmap") return "roadmap";
19
+ if (file.includes("handover") || /\/handovers(\/|$)/.test(normalized)) return "handover";
20
+ if (/\/(plans|specs|superpowers|research|decisions)(\/|$)/.test(normalized)) return "plan";
21
+ return "documentation";
22
+ }
13
23
  function fileToRoutePath(filePath, docsDir, basePath = "/") {
14
24
  const rel = relative(docsDir, filePath);
15
25
  const ext = extname(rel);
@@ -42,7 +52,8 @@ function scanDocs(docsDir, exclude = [], basePath = "/") {
42
52
  icon: data.icon,
43
53
  order: data.order,
44
54
  summary: data.summary,
45
- category: data.category,
55
+ // `type` per the shared contract; inferred from path when omitted.
56
+ type: data.type ?? inferDocType(filePath),
46
57
  tags: data.tags,
47
58
  projects: data.projects,
48
59
  status: data.status,
@@ -197,6 +208,7 @@ function buildSectionData(section, rootFiles, customNavigation) {
197
208
  }
198
209
 
199
210
  export {
211
+ inferDocType,
200
212
  scanDocs,
201
213
  buildNavigation,
202
214
  buildRoutes,
@@ -13,7 +13,7 @@ import {
13
13
  } from "./chunk-ZWF6VCSQ.js";
14
14
  import {
15
15
  buildSectionData
16
- } from "./chunk-CTL4YL7C.js";
16
+ } from "./chunk-77IOLCAM.js";
17
17
 
18
18
  // src/vite-plugin/index.ts
19
19
  import { resolve, dirname } from "path";
@@ -5,22 +5,28 @@ import {
5
5
  } from "./chunk-ZWF6VCSQ.js";
6
6
  import {
7
7
  scanDocs
8
- } from "./chunk-CTL4YL7C.js";
8
+ } from "./chunk-77IOLCAM.js";
9
9
 
10
10
  // src/node/check.ts
11
11
  import { resolve, relative } from "path";
12
12
  import { readFileSync, existsSync } from "fs";
13
13
  import matter from "gray-matter";
14
- var VALID_CATEGORIES = [
14
+ var VALID_TYPES = [
15
+ "readme",
15
16
  "documentation",
16
- "internal",
17
17
  "plan",
18
- "research",
19
- "decision",
20
18
  "roadmap",
21
- "changelog"
19
+ "changelog",
20
+ "handover"
21
+ ];
22
+ var VALID_STATUSES = [
23
+ "draft",
24
+ "decided",
25
+ "in-progress",
26
+ "completed",
27
+ "archived",
28
+ "rejected"
22
29
  ];
23
- var VALID_STATUSES = ["active", "superseded", "archived"];
24
30
  function isStrictPath(filePath) {
25
31
  const normalized = filePath.replace(/\\/g, "/");
26
32
  return /\/docs\/plans(\/|$)/.test(normalized) || /\/docs\/internal(\/|$)/.test(normalized);
@@ -43,8 +49,8 @@ function validateFrontmatter(doc, userRoot) {
43
49
  if (!rawFm.summary) {
44
50
  issues.push({ file: rel, field: "summary", message: "missing required field", severity: "error" });
45
51
  }
46
- if (!rawFm.category) {
47
- issues.push({ file: rel, field: "category", message: "missing required field", severity: "error" });
52
+ if (!rawFm.type) {
53
+ issues.push({ file: rel, field: "type", message: "recommended field missing (inferred from path)", severity: "warning" });
48
54
  }
49
55
  } else {
50
56
  if (!rawFm.title) {
@@ -53,16 +59,16 @@ function validateFrontmatter(doc, userRoot) {
53
59
  if (!rawFm.summary) {
54
60
  issues.push({ file: rel, field: "summary", message: "recommended field missing", severity: "warning" });
55
61
  }
56
- if (!rawFm.category) {
57
- issues.push({ file: rel, field: "category", message: "recommended field missing", severity: "warning" });
62
+ if (!rawFm.type) {
63
+ issues.push({ file: rel, field: "type", message: "recommended field missing (inferred from path)", severity: "warning" });
58
64
  }
59
65
  }
60
- if (rawFm.category !== void 0) {
61
- if (!VALID_CATEGORIES.includes(rawFm.category)) {
66
+ if (rawFm.type !== void 0) {
67
+ if (!VALID_TYPES.includes(rawFm.type)) {
62
68
  issues.push({
63
69
  file: rel,
64
- field: "category",
65
- message: `invalid value "${rawFm.category}" (allowed: ${VALID_CATEGORIES.join(", ")})`,
70
+ field: "type",
71
+ message: `invalid value "${rawFm.type}" (allowed: ${VALID_TYPES.join(", ")})`,
66
72
  severity: "error"
67
73
  });
68
74
  }
@@ -259,6 +265,8 @@ function levenshtein(a, b) {
259
265
  }
260
266
 
261
267
  export {
268
+ VALID_TYPES,
269
+ VALID_STATUSES,
262
270
  checkFrontmatter,
263
271
  checkLinks
264
272
  };
@@ -12,7 +12,7 @@ import {
12
12
  } from "./chunk-TVDWHKQF.js";
13
13
  import {
14
14
  clearifyPlugin
15
- } from "./chunk-Q5FUAK6J.js";
15
+ } from "./chunk-LVPVSOXK.js";
16
16
  import {
17
17
  loadUserConfig,
18
18
  resolveConfig,
@@ -20,7 +20,7 @@ import {
20
20
  } from "./chunk-ZWF6VCSQ.js";
21
21
  import {
22
22
  buildSectionData
23
- } from "./chunk-CTL4YL7C.js";
23
+ } from "./chunk-77IOLCAM.js";
24
24
 
25
25
  // src/node/build.ts
26
26
  import { build as viteBuild } from "vite";
@@ -1,2 +1,2 @@
1
1
  import '../types/index.js';
2
- export { D as DocFile, R as RootFileOptions, S as SectionData, b as buildNavigation, a as buildRoutes, c as buildSectionData, s as scanDocs } from './search.js';
2
+ export { D as DocFile, R as RootFileOptions, S as SectionData, b as buildNavigation, a as buildRoutes, c as buildSectionData, i as inferDocType, s as scanDocs } from './search.js';
@@ -2,12 +2,14 @@ import {
2
2
  buildNavigation,
3
3
  buildRoutes,
4
4
  buildSectionData,
5
+ inferDocType,
5
6
  scanDocs
6
- } from "../chunk-CTL4YL7C.js";
7
+ } from "../chunk-77IOLCAM.js";
7
8
  import "../chunk-5TD7NQIW.js";
8
9
  export {
9
10
  buildNavigation,
10
11
  buildRoutes,
11
12
  buildSectionData,
13
+ inferDocType,
12
14
  scanDocs
13
15
  };
@@ -1,4 +1,4 @@
1
- import { PageFrontmatter, ResolvedSection, SectionNavigation, RouteEntry, NavigationItem } from '../types/index.js';
1
+ import { PageFrontmatter, ResolvedSection, SectionNavigation, RouteEntry, NavigationItem, DocType } from '../types/index.js';
2
2
 
3
3
  interface SearchEntry {
4
4
  id: number;
@@ -11,6 +11,13 @@ interface SearchEntry {
11
11
  }
12
12
  declare function buildSearchIndex(docs: DocFile[], sectionId?: string, sectionLabel?: string): SearchEntry[];
13
13
 
14
+ /**
15
+ * Infer the document `type` from its file path when frontmatter omits it.
16
+ * Mirrors the path-inference rules in the shared contract:
17
+ * knowledge-base/standards/document-lifecycle.md (the single source of truth).
18
+ * Returns undefined when nothing matches, leaving `type` unset (never filtered).
19
+ */
20
+ declare function inferDocType(filePath: string): DocType | undefined;
14
21
  interface DocFile {
15
22
  filePath: string;
16
23
  routePath: string;
@@ -33,4 +40,4 @@ interface RootFileOptions {
33
40
  }
34
41
  declare function buildSectionData(section: ResolvedSection, rootFiles?: RootFileOptions, customNavigation?: NavigationItem[] | null): SectionData;
35
42
 
36
- export { type DocFile as D, type RootFileOptions as R, type SectionData as S, type SearchEntry, buildRoutes as a, buildNavigation as b, buildSearchIndex, buildSectionData as c, scanDocs as s };
43
+ export { type DocFile as D, type RootFileOptions as R, type SectionData as S, type SearchEntry, buildRoutes as a, buildNavigation as b, buildSearchIndex, buildSectionData as c, inferDocType as i, scanDocs as s };
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  buildSite
3
- } from "../chunk-PZA4UAFG.js";
3
+ } from "../chunk-XAX53RY5.js";
4
4
  import "../chunk-PRTER35L.js";
5
5
  import "../chunk-SCZZB7OE.js";
6
6
  import "../chunk-TVDWHKQF.js";
7
- import "../chunk-Q5FUAK6J.js";
7
+ import "../chunk-LVPVSOXK.js";
8
8
  import "../chunk-B2Q23JW3.js";
9
9
  import "../chunk-ZWF6VCSQ.js";
10
10
  import "../chunk-AJBCHKBP.js";
11
11
  import "../chunk-V7LLYIRO.js";
12
- import "../chunk-CTL4YL7C.js";
12
+ import "../chunk-77IOLCAM.js";
13
13
  import "../chunk-5TD7NQIW.js";
14
14
  export {
15
15
  buildSite
@@ -1,10 +1,14 @@
1
+ import { DocStatus, DocType } from '../types/index.js';
2
+
1
3
  interface CheckOptions {
2
4
  frontmatterOnly?: boolean;
3
5
  }
6
+ declare const VALID_TYPES: DocType[];
7
+ declare const VALID_STATUSES: DocStatus[];
4
8
  declare function checkFrontmatter(): Promise<{
5
9
  errors: number;
6
10
  warnings: number;
7
11
  }>;
8
12
  declare function checkLinks(options?: CheckOptions): Promise<void>;
9
13
 
10
- export { type CheckOptions, checkFrontmatter, checkLinks };
14
+ export { type CheckOptions, VALID_STATUSES, VALID_TYPES, checkFrontmatter, checkLinks };
@@ -1,13 +1,17 @@
1
1
  import {
2
+ VALID_STATUSES,
3
+ VALID_TYPES,
2
4
  checkFrontmatter,
3
5
  checkLinks
4
- } from "../chunk-GZE6QLJT.js";
6
+ } from "../chunk-V5J36LF5.js";
5
7
  import "../chunk-ZWF6VCSQ.js";
6
8
  import "../chunk-AJBCHKBP.js";
7
9
  import "../chunk-V7LLYIRO.js";
8
- import "../chunk-CTL4YL7C.js";
10
+ import "../chunk-77IOLCAM.js";
9
11
  import "../chunk-5TD7NQIW.js";
10
12
  export {
13
+ VALID_STATUSES,
14
+ VALID_TYPES,
11
15
  checkFrontmatter,
12
16
  checkLinks
13
17
  };
@@ -2,6 +2,7 @@ import * as vite from 'vite';
2
2
  export { buildSite as build } from './build.js';
3
3
  export { init } from './init.js';
4
4
  export { checkFrontmatter, checkLinks } from './check.js';
5
+ import '../types/index.js';
5
6
 
6
7
  declare function createServer(options?: {
7
8
  port?: number;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  buildSite
3
- } from "../chunk-PZA4UAFG.js";
3
+ } from "../chunk-XAX53RY5.js";
4
4
  import {
5
5
  remarkMermaidToComponent
6
6
  } from "../chunk-PRTER35L.js";
@@ -8,7 +8,7 @@ import "../chunk-SCZZB7OE.js";
8
8
  import "../chunk-TVDWHKQF.js";
9
9
  import {
10
10
  clearifyPlugin
11
- } from "../chunk-Q5FUAK6J.js";
11
+ } from "../chunk-LVPVSOXK.js";
12
12
  import "../chunk-B2Q23JW3.js";
13
13
  import {
14
14
  init
@@ -16,14 +16,14 @@ import {
16
16
  import {
17
17
  checkFrontmatter,
18
18
  checkLinks
19
- } from "../chunk-GZE6QLJT.js";
19
+ } from "../chunk-V5J36LF5.js";
20
20
  import {
21
21
  loadUserConfig,
22
22
  resolveConfig
23
23
  } from "../chunk-ZWF6VCSQ.js";
24
24
  import "../chunk-AJBCHKBP.js";
25
25
  import "../chunk-V7LLYIRO.js";
26
- import "../chunk-CTL4YL7C.js";
26
+ import "../chunk-77IOLCAM.js";
27
27
  import "../chunk-5TD7NQIW.js";
28
28
 
29
29
  // src/node/index.ts
@@ -77,17 +77,35 @@ interface NavigationItem {
77
77
  badgeColor?: string;
78
78
  children?: NavigationItem[];
79
79
  }
80
- type DocCategory = 'documentation' | 'internal' | 'plan' | 'research' | 'decision' | 'roadmap' | 'changelog';
80
+ /**
81
+ * Document type vocabulary. Source of truth:
82
+ * knowledge-base/standards/document-lifecycle.md (the single contract both
83
+ * the Session Dashboard and Clearify read). Keep this union in sync with the
84
+ * "Type" table in that standard. `category` (the legacy field) and its values
85
+ * (`internal`, `research`, `decision`) were reconciled away in favor of `type`.
86
+ */
87
+ type DocType = 'readme' | 'documentation' | 'plan' | 'roadmap' | 'changelog' | 'handover';
88
+ /**
89
+ * Document status vocabulary. Source of truth:
90
+ * knowledge-base/standards/document-lifecycle.md.
91
+ *
92
+ * For `type: plan` this tracks the workflow lifecycle (all six values).
93
+ * For `type: documentation` only `draft` is meaningful (omitted = published).
94
+ * Status is optional on every type and a missing status is never filtered.
95
+ */
96
+ type DocStatus = 'draft' | 'decided' | 'in-progress' | 'completed' | 'archived' | 'rejected';
81
97
  interface PageFrontmatter {
82
98
  title?: string;
83
99
  description?: string;
84
100
  icon?: string;
85
101
  order?: number;
86
102
  summary?: string;
87
- category?: DocCategory;
103
+ /** See {@link DocType}. Inferred from path when omitted. */
104
+ type?: DocType;
88
105
  tags?: string[];
89
106
  projects?: string[];
90
- status?: 'active' | 'superseded' | 'archived';
107
+ /** See {@link DocStatus}. Missing status is treated as unset (not filtered). */
108
+ status?: DocStatus;
91
109
  date?: string;
92
110
  }
93
111
  interface RouteEntry {
@@ -199,4 +217,4 @@ interface ClearifyDataConfig {
199
217
  }
200
218
  declare function defineConfig(config: Partial<ClearifyConfig>): Partial<ClearifyConfig>;
201
219
 
202
- export { type ClearifyConfig, type ClearifyDataConfig, type DocCategory, type HubConfig, type HubProject, type HubProjectPartial, type HubProjectPlacement, type HubProjectSource, type NavigationItem, type PageFrontmatter, type RemoteGitSource, type ResolvedSection, type RouteEntry, type SectionConfig, type SectionNavigation, defineConfig };
220
+ export { type ClearifyConfig, type ClearifyDataConfig, type DocStatus, type DocType, type HubConfig, type HubProject, type HubProjectPartial, type HubProjectPlacement, type HubProjectSource, type NavigationItem, type PageFrontmatter, type RemoteGitSource, type ResolvedSection, type RouteEntry, type SectionConfig, type SectionNavigation, defineConfig };
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  clearifyPlugin
3
- } from "../chunk-Q5FUAK6J.js";
3
+ } from "../chunk-LVPVSOXK.js";
4
4
  import "../chunk-B2Q23JW3.js";
5
5
  import "../chunk-ZWF6VCSQ.js";
6
6
  import "../chunk-AJBCHKBP.js";
7
7
  import "../chunk-V7LLYIRO.js";
8
- import "../chunk-CTL4YL7C.js";
8
+ import "../chunk-77IOLCAM.js";
9
9
  import "../chunk-5TD7NQIW.js";
10
10
  export {
11
11
  clearifyPlugin
package/package.json CHANGED
@@ -1,6 +1,9 @@
1
1
  {
2
2
  "name": "@marlinjai/clearify",
3
- "version": "2.1.0",
3
+ "publishConfig": {
4
+ "access": "public"
5
+ },
6
+ "version": "2.2.1",
4
7
  "description": "An open-source documentation site generator. Turn markdown into beautiful docs.",
5
8
  "type": "module",
6
9
  "bin": {
@@ -29,7 +32,8 @@
29
32
  "dev:self": "node bin/clearify.js dev",
30
33
  "prepare": "husky",
31
34
  "release": "semantic-release",
32
- "test": "vitest run"
35
+ "test": "vitest run",
36
+ "check:roadmap": "npx --yes github:marlinjai/actions-shared#roadmap-check-v1 --root ."
33
37
  },
34
38
  "dependencies": {
35
39
  "@inquirer/password": "^5.0.11",
@@ -57,7 +61,7 @@
57
61
  "tailwindcss": "^4.1.18",
58
62
  "unist-util-visit": "^5.0.0",
59
63
  "vite": "^6.1.0",
60
- "zod": "^4.3.6"
64
+ "zod": "^4.6.7"
61
65
  },
62
66
  "peerDependencies": {
63
67
  "puppeteer": ">=22.0.0",
@@ -80,7 +84,7 @@
80
84
  "@types/react-dom": "^18.3.5",
81
85
  "esbuild": "^0.27.3",
82
86
  "husky": "^9.1.7",
83
- "puppeteer": "^24.37.2",
87
+ "puppeteer": "^25.0.0",
84
88
  "semantic-release": "^25.0.3",
85
89
  "tsup": "^8.3.6",
86
90
  "typescript": "^5.7.3",