@okfit/profiles 0.8.3 → 0.9.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/Publications.js +133 -0
- package/README.md +48 -0
- package/SoftwareProject.js +66 -0
- package/index.d.ts +80 -2
- package/index.js +2 -1
- package/package.json +2 -2
- package/presets/index.js +51 -0
- package/presets/surfaces.js +318 -0
package/Publications.js
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { Derivation } from "./Derivation.js";
|
|
2
|
+
import { ConceptId, Diagnostic, DiagnosticRange, OkfitConfig } from "@okfit/core";
|
|
3
|
+
import { Effect, Option } from "effect";
|
|
4
|
+
|
|
5
|
+
//#region src/Publications.ts
|
|
6
|
+
/**
|
|
7
|
+
* The concept type name of a documentation surface.
|
|
8
|
+
*
|
|
9
|
+
* @public
|
|
10
|
+
*/
|
|
11
|
+
const SURFACE_TYPE = "Surface";
|
|
12
|
+
/**
|
|
13
|
+
* The concept type name of a published page rendered from bundle concepts.
|
|
14
|
+
*
|
|
15
|
+
* @public
|
|
16
|
+
*/
|
|
17
|
+
const PUBLICATION_TYPE = "Publication";
|
|
18
|
+
const resolveRef = (from, raw) => {
|
|
19
|
+
const segments = from.split("/").slice(0, -1);
|
|
20
|
+
for (const part of raw.replace(/\.md$/u, "").split("/")) {
|
|
21
|
+
if (part === "" || part === ".") continue;
|
|
22
|
+
if (part === "..") {
|
|
23
|
+
if (segments.length === 0) return "";
|
|
24
|
+
segments.pop();
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
segments.push(part);
|
|
28
|
+
}
|
|
29
|
+
return segments.join("/");
|
|
30
|
+
};
|
|
31
|
+
const rendersOf = (concept) => {
|
|
32
|
+
const value = concept.frontmatter.raw.renders;
|
|
33
|
+
if (!Array.isArray(value)) return void 0;
|
|
34
|
+
const out = [];
|
|
35
|
+
for (const [index, entry] of value.entries()) {
|
|
36
|
+
if (typeof entry !== "object" || entry === null || typeof entry.path !== "string") return void 0;
|
|
37
|
+
const digest = typeof entry.body_sha256 === "string" && entry.body_sha256 !== "" ? entry.body_sha256 : void 0;
|
|
38
|
+
out.push(digest === void 0 ? {
|
|
39
|
+
index,
|
|
40
|
+
path: entry.path
|
|
41
|
+
} : {
|
|
42
|
+
index,
|
|
43
|
+
path: entry.path,
|
|
44
|
+
body_sha256: digest
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return out;
|
|
48
|
+
};
|
|
49
|
+
const compare = (a, b) => a.file < b.file ? -1 : a.file > b.file ? 1 : a.code < b.code ? -1 : a.code > b.code ? 1 : 0;
|
|
50
|
+
/**
|
|
51
|
+
* A profiles-owned lint over Publication concepts: `publication-orphan` when a
|
|
52
|
+
* `surface` or `renders[].path` does not resolve to a bundle concept (or
|
|
53
|
+
* `renders` is malformed), and `publication-drift` when a rendered source's
|
|
54
|
+
* body digest no longer matches the stamped `body_sha256`. Total over
|
|
55
|
+
* severity: returns `[]` before any digest work when both codes are `"off"`.
|
|
56
|
+
*
|
|
57
|
+
* @public
|
|
58
|
+
*/
|
|
59
|
+
var Publications = class {
|
|
60
|
+
constructor() {}
|
|
61
|
+
/** Resolves a raw reference against a bundle-relative concept path; `""` when it escapes the bundle. */
|
|
62
|
+
static resolveRef = resolveRef;
|
|
63
|
+
/** The `renders` entries of a Publication, or `undefined` when malformed. */
|
|
64
|
+
static rendersOf = rendersOf;
|
|
65
|
+
/** Lints every Publication in `bundle`; diagnostics are sorted by file then code. */
|
|
66
|
+
static lint = Effect.fn("Publications.lint")(function* (bundle, config) {
|
|
67
|
+
const driftSeverity = OkfitConfig.severityFor(config, "publication-drift");
|
|
68
|
+
const orphanSeverity = OkfitConfig.severityFor(config, "publication-orphan");
|
|
69
|
+
if (driftSeverity === "off" && orphanSeverity === "off") return [];
|
|
70
|
+
const diagnostics = [];
|
|
71
|
+
const push = (concept, code, severity, message, path) => {
|
|
72
|
+
const range = DiagnosticRange.forFrontmatterPath(concept.document, path);
|
|
73
|
+
diagnostics.push(Diagnostic.make({
|
|
74
|
+
file: concept.path,
|
|
75
|
+
code,
|
|
76
|
+
severity,
|
|
77
|
+
message,
|
|
78
|
+
...range === void 0 ? {} : { range }
|
|
79
|
+
}));
|
|
80
|
+
};
|
|
81
|
+
for (const [id, concept] of bundle.concepts) {
|
|
82
|
+
if (concept.frontmatter.type !== "Publication") continue;
|
|
83
|
+
const resource = String(concept.frontmatter.raw.resource ?? concept.path);
|
|
84
|
+
if (orphanSeverity !== "off") {
|
|
85
|
+
const surface = concept.frontmatter.raw.surface;
|
|
86
|
+
if (surface !== void 0) {
|
|
87
|
+
const target = typeof surface === "string" ? Option.match(ConceptId.normalize(resolveRef(concept.path, surface)), {
|
|
88
|
+
onNone: () => void 0,
|
|
89
|
+
onSome: (key) => bundle.concepts.get(key)
|
|
90
|
+
}) : void 0;
|
|
91
|
+
if (target === void 0) push(concept, "publication-orphan", orphanSeverity, `surface ${JSON.stringify(surface)} does not resolve to a concept in the bundle`, ["surface"]);
|
|
92
|
+
else if (target.frontmatter.type !== "Surface") push(concept, "publication-orphan", orphanSeverity, `surface ${JSON.stringify(surface)} resolves to a concept of type ${JSON.stringify(target.frontmatter.type)}, not ${SURFACE_TYPE}`, ["surface"]);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
const renders = rendersOf(concept);
|
|
96
|
+
if (renders === void 0) {
|
|
97
|
+
if (orphanSeverity !== "off") push(concept, "publication-orphan", orphanSeverity, "renders must be a list of { path, body_sha256 } entries", ["renders"]);
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (renders.length === 0) {
|
|
101
|
+
if (orphanSeverity !== "off") push(concept, "publication-orphan", orphanSeverity, "renders must name at least one source", ["renders"]);
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
const stale = [];
|
|
105
|
+
for (const entry of renders) {
|
|
106
|
+
const sourceId = resolveRef(concept.path, entry.path);
|
|
107
|
+
const source = Option.match(ConceptId.normalize(sourceId), {
|
|
108
|
+
onNone: () => void 0,
|
|
109
|
+
onSome: (key) => bundle.concepts.get(key)
|
|
110
|
+
});
|
|
111
|
+
if (source === void 0) {
|
|
112
|
+
if (orphanSeverity !== "off") push(concept, "publication-orphan", orphanSeverity, `renders[${entry.index}].path ${JSON.stringify(entry.path)} does not resolve to a concept in the bundle`, [
|
|
113
|
+
"renders",
|
|
114
|
+
entry.index,
|
|
115
|
+
"path"
|
|
116
|
+
]);
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
if (driftSeverity === "off") continue;
|
|
120
|
+
if (entry.body_sha256 === void 0) {
|
|
121
|
+
stale.push(`${sourceId} (never stamped)`);
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
if ((yield* Derivation.bodyDigest(source.document.source)) !== entry.body_sha256) stale.push(`${sourceId} (changed)`);
|
|
125
|
+
}
|
|
126
|
+
if (stale.length > 0 && driftSeverity !== "off") push(concept, "publication-drift", driftSeverity, `Rendered page ${resource} is stale against: ${stale.join(", ")}; re-render it, then run okfit sync --publication ${id}`, ["renders"]);
|
|
127
|
+
}
|
|
128
|
+
return diagnostics.sort(compare);
|
|
129
|
+
});
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
//#endregion
|
|
133
|
+
export { PUBLICATION_TYPE, Publications, SURFACE_TYPE };
|
package/README.md
CHANGED
|
@@ -163,6 +163,54 @@ description = "The ISO 8601 date the failure happened or was first observed."
|
|
|
163
163
|
description = "A path relative to this concept file to the test, check, or config that now stops the failure recurring."
|
|
164
164
|
kind = "path"
|
|
165
165
|
|
|
166
|
+
[types.Surface]
|
|
167
|
+
description = "A documentation surface: where one kind of published docs lives, who reads it, and how it is written."
|
|
168
|
+
guidance = "Write the body as instructions to the author of a page on this surface: tone, structure, required and forbidden sections, and what belongs on another surface instead. Keep one Surface per audience and location, and point links_to at the Surface this one routes readers to."
|
|
169
|
+
required = ["kind", "audience", "resource"]
|
|
170
|
+
|
|
171
|
+
[types.Surface.fields.kind]
|
|
172
|
+
description = "How the surface is published."
|
|
173
|
+
|
|
174
|
+
[types.Surface.fields.kind.values]
|
|
175
|
+
site = "A built website workspace, such as an RSPress site, published at a URL."
|
|
176
|
+
repo = "Markdown read in place on the forge, such as a docs/ directory on GitHub."
|
|
177
|
+
readme = "README files: the repository root's, each package's, or both."
|
|
178
|
+
|
|
179
|
+
[types.Surface.fields.audience]
|
|
180
|
+
description = "Who the surface is written for."
|
|
181
|
+
|
|
182
|
+
[types.Surface.fields.audience.values]
|
|
183
|
+
users = "People installing or calling what this repository ships."
|
|
184
|
+
contributors = "People changing this repository: setup, workflow, and internals."
|
|
185
|
+
agents = "Coding agents working in this repository."
|
|
186
|
+
|
|
187
|
+
[types.Surface.fields.resource]
|
|
188
|
+
description = "A path relative to this concept file to the surface root, or a glob pattern when the surface spans many directories, such as every package directory."
|
|
189
|
+
kind = "path"
|
|
190
|
+
|
|
191
|
+
[types.Surface.fields.url]
|
|
192
|
+
description = "Where a site surface is published, as an absolute URL."
|
|
193
|
+
|
|
194
|
+
[types.Surface.fields.links_to]
|
|
195
|
+
description = "The Surface this one routes readers to, such as a one-page README pointing at the site."
|
|
196
|
+
kind = "path"
|
|
197
|
+
|
|
198
|
+
[types.Publication]
|
|
199
|
+
description = "A published page that restates facts this bundle owns, and the concepts it was rendered from."
|
|
200
|
+
guidance = "Create one only for a page whose content comes from bundle concepts; the bundle is the source of truth and the page is re-rendered when a source changes. Use the body for rendering notes: what is audience-specific, what is deliberately left out, and what a re-render must keep."
|
|
201
|
+
required = ["resource", "surface", "renders"]
|
|
202
|
+
|
|
203
|
+
[types.Publication.fields.resource]
|
|
204
|
+
description = "A path relative to this concept file to the published page."
|
|
205
|
+
kind = "path"
|
|
206
|
+
|
|
207
|
+
[types.Publication.fields.surface]
|
|
208
|
+
description = "The Surface concept this page is published on."
|
|
209
|
+
kind = "path"
|
|
210
|
+
|
|
211
|
+
[types.Publication.fields.renders]
|
|
212
|
+
description = "The source concepts as a list of entries that each hold a path and a body digest; okfit sync --publication stamps each digest."
|
|
213
|
+
|
|
166
214
|
[tags.architecture]
|
|
167
215
|
description = "Concerns the shape of the system rather than one module."
|
|
168
216
|
|
package/SoftwareProject.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { DOCS_PRESETS } from "./presets/index.js";
|
|
1
2
|
import { DiagnosticRange } from "@okfit/core";
|
|
2
3
|
|
|
3
4
|
//#region src/SoftwareProject.ts
|
|
@@ -170,6 +171,62 @@ const config = {
|
|
|
170
171
|
kind: "path"
|
|
171
172
|
}
|
|
172
173
|
}
|
|
174
|
+
},
|
|
175
|
+
Surface: {
|
|
176
|
+
description: "A documentation surface: where one kind of published docs lives, who reads it, and how it is written.",
|
|
177
|
+
guidance: "Write the body as instructions to the author of a page on this surface: tone, structure, required and forbidden sections, and what belongs on another surface instead. Keep one Surface per audience and location, and point links_to at the Surface this one routes readers to.",
|
|
178
|
+
required: [
|
|
179
|
+
"kind",
|
|
180
|
+
"audience",
|
|
181
|
+
"resource"
|
|
182
|
+
],
|
|
183
|
+
fields: {
|
|
184
|
+
kind: {
|
|
185
|
+
description: "How the surface is published.",
|
|
186
|
+
values: {
|
|
187
|
+
site: "A built website workspace, such as an RSPress site, published at a URL.",
|
|
188
|
+
repo: "Markdown read in place on the forge, such as a docs/ directory on GitHub.",
|
|
189
|
+
readme: "README files: the repository root's, each package's, or both."
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
audience: {
|
|
193
|
+
description: "Who the surface is written for.",
|
|
194
|
+
values: {
|
|
195
|
+
users: "People installing or calling what this repository ships.",
|
|
196
|
+
contributors: "People changing this repository: setup, workflow, and internals.",
|
|
197
|
+
agents: "Coding agents working in this repository."
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
resource: {
|
|
201
|
+
description: "A path relative to this concept file to the surface root, or a glob pattern when the surface spans many directories, such as every package directory.",
|
|
202
|
+
kind: "path"
|
|
203
|
+
},
|
|
204
|
+
url: { description: "Where a site surface is published, as an absolute URL." },
|
|
205
|
+
links_to: {
|
|
206
|
+
description: "The Surface this one routes readers to, such as a one-page README pointing at the site.",
|
|
207
|
+
kind: "path"
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
Publication: {
|
|
212
|
+
description: "A published page that restates facts this bundle owns, and the concepts it was rendered from.",
|
|
213
|
+
guidance: "Create one only for a page whose content comes from bundle concepts; the bundle is the source of truth and the page is re-rendered when a source changes. Use the body for rendering notes: what is audience-specific, what is deliberately left out, and what a re-render must keep.",
|
|
214
|
+
required: [
|
|
215
|
+
"resource",
|
|
216
|
+
"surface",
|
|
217
|
+
"renders"
|
|
218
|
+
],
|
|
219
|
+
fields: {
|
|
220
|
+
resource: {
|
|
221
|
+
description: "A path relative to this concept file to the published page.",
|
|
222
|
+
kind: "path"
|
|
223
|
+
},
|
|
224
|
+
surface: {
|
|
225
|
+
description: "The Surface concept this page is published on.",
|
|
226
|
+
kind: "path"
|
|
227
|
+
},
|
|
228
|
+
renders: { description: "The source concepts as a list of entries that each hold a path and a body digest; okfit sync --publication stamps each digest." }
|
|
229
|
+
}
|
|
173
230
|
}
|
|
174
231
|
},
|
|
175
232
|
tags: {
|
|
@@ -256,6 +313,14 @@ const layout = {
|
|
|
256
313
|
{
|
|
257
314
|
directory: "incidents",
|
|
258
315
|
type: "Incident"
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
directory: "surfaces",
|
|
319
|
+
type: "Surface"
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
directory: "publications",
|
|
323
|
+
type: "Publication"
|
|
259
324
|
}
|
|
260
325
|
]
|
|
261
326
|
};
|
|
@@ -306,6 +371,7 @@ const softwareProject = {
|
|
|
306
371
|
name: "software-project",
|
|
307
372
|
config,
|
|
308
373
|
layout,
|
|
374
|
+
docsPresets: DOCS_PRESETS,
|
|
309
375
|
check
|
|
310
376
|
};
|
|
311
377
|
|
package/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Context, Crypto, DateTime, Effect, FileSystem, Layer, Option, Path, PlatformError, Schema } from "effect";
|
|
2
2
|
import { Git, GitCommandError, NotARepositoryError, UnknownRefError } from "@effected/git";
|
|
3
|
-
import { Actor, Diagnostic, DiagnosticRange, LoadedBundle, OkfitConfig } from "@okfit/core";
|
|
3
|
+
import { Actor, Diagnostic, DiagnosticRange, LoadedBundle, LoadedConcept, OkfitConfig } from "@okfit/core";
|
|
4
4
|
import { ChildProcessSpawner } from "effect/process";
|
|
5
5
|
//#region src/BodyProvenance.d.ts
|
|
6
6
|
/**
|
|
@@ -354,6 +354,41 @@ export declare const ProfileDiagnostic: Schema.Struct<{
|
|
|
354
354
|
* @public
|
|
355
355
|
*/
|
|
356
356
|
export type ProfileDiagnostic = typeof ProfileDiagnostic.Type;
|
|
357
|
+
/**
|
|
358
|
+
* One Surface concept a docs preset writes: a bundle-relative `file` and the
|
|
359
|
+
* frontmatter and body to write there. `resource` is relative to the file.
|
|
360
|
+
* The `site` preset's `url` is an `https://example.invalid` placeholder the
|
|
361
|
+
* docs skill replaces.
|
|
362
|
+
*
|
|
363
|
+
* @public
|
|
364
|
+
*/
|
|
365
|
+
interface SurfaceTemplate {
|
|
366
|
+
readonly file: string;
|
|
367
|
+
readonly frontmatter: {
|
|
368
|
+
readonly type: "Surface";
|
|
369
|
+
readonly status: "draft";
|
|
370
|
+
readonly title: string;
|
|
371
|
+
readonly description: string;
|
|
372
|
+
readonly kind: "site" | "repo" | "readme";
|
|
373
|
+
readonly audience: "users" | "contributors" | "agents";
|
|
374
|
+
readonly resource: string;
|
|
375
|
+
readonly links_to?: string;
|
|
376
|
+
readonly url?: string;
|
|
377
|
+
};
|
|
378
|
+
readonly body: string;
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* A named set of Surface templates for one repository shape. `additive` is
|
|
382
|
+
* true only for `site`, which layers on another preset instead of replacing it.
|
|
383
|
+
*
|
|
384
|
+
* @public
|
|
385
|
+
*/
|
|
386
|
+
interface DocsPreset {
|
|
387
|
+
readonly name: "npm-package" | "monorepo-router" | "monorepo-shared-docs" | "site";
|
|
388
|
+
readonly description: string;
|
|
389
|
+
readonly additive: boolean;
|
|
390
|
+
readonly surfaces: ReadonlyArray<SurfaceTemplate>;
|
|
391
|
+
}
|
|
357
392
|
/**
|
|
358
393
|
* A named profile (P-38): a partial `OkfitConfig` the CLI merges as
|
|
359
394
|
* `DEFAULTS < profile < file`, a scaffolding `Layout`, and a pure `check`
|
|
@@ -365,6 +400,7 @@ interface Profile {
|
|
|
365
400
|
readonly name: ProfileName;
|
|
366
401
|
readonly config: OkfitConfig;
|
|
367
402
|
readonly layout: Layout;
|
|
403
|
+
readonly docsPresets: ReadonlyArray<DocsPreset>;
|
|
368
404
|
readonly check: (bundle: LoadedBundle) => ReadonlyArray<ProfileDiagnostic>;
|
|
369
405
|
}
|
|
370
406
|
//#endregion
|
|
@@ -442,5 +478,47 @@ export declare class Provenance {
|
|
|
442
478
|
}) => Effect.Effect<ReadonlyArray<Diagnostic>, GitHistoryError | GitCommandError | UnknownRefError | PlatformError.PlatformError, Git | GitHistory | FileSystem.FileSystem | Path.Path | Crypto.Crypto>;
|
|
443
479
|
}
|
|
444
480
|
//#endregion
|
|
445
|
-
|
|
481
|
+
//#region src/Publications.d.ts
|
|
482
|
+
/**
|
|
483
|
+
* The concept type name of a documentation surface.
|
|
484
|
+
*
|
|
485
|
+
* @public
|
|
486
|
+
*/
|
|
487
|
+
export declare const SURFACE_TYPE: "Surface";
|
|
488
|
+
/**
|
|
489
|
+
* The concept type name of a published page rendered from bundle concepts.
|
|
490
|
+
*
|
|
491
|
+
* @public
|
|
492
|
+
*/
|
|
493
|
+
export declare const PUBLICATION_TYPE: "Publication";
|
|
494
|
+
/**
|
|
495
|
+
* One entry of a Publication's `renders` list, with its position.
|
|
496
|
+
*
|
|
497
|
+
* @public
|
|
498
|
+
*/
|
|
499
|
+
interface RendersEntry {
|
|
500
|
+
readonly index: number;
|
|
501
|
+
readonly path: string;
|
|
502
|
+
readonly body_sha256?: string;
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* A profiles-owned lint over Publication concepts: `publication-orphan` when a
|
|
506
|
+
* `surface` or `renders[].path` does not resolve to a bundle concept (or
|
|
507
|
+
* `renders` is malformed), and `publication-drift` when a rendered source's
|
|
508
|
+
* body digest no longer matches the stamped `body_sha256`. Total over
|
|
509
|
+
* severity: returns `[]` before any digest work when both codes are `"off"`.
|
|
510
|
+
*
|
|
511
|
+
* @public
|
|
512
|
+
*/
|
|
513
|
+
export declare class Publications {
|
|
514
|
+
private constructor();
|
|
515
|
+
/** Resolves a raw reference against a bundle-relative concept path; `""` when it escapes the bundle. */
|
|
516
|
+
static readonly resolveRef: (from: string, raw: string) => string;
|
|
517
|
+
/** The `renders` entries of a Publication, or `undefined` when malformed. */
|
|
518
|
+
static readonly rendersOf: (concept: LoadedConcept) => ReadonlyArray<RendersEntry> | undefined;
|
|
519
|
+
/** Lints every Publication in `bundle`; diagnostics are sorted by file then code. */
|
|
520
|
+
static readonly lint: (bundle: LoadedBundle, config: OkfitConfig) => Effect.Effect<ReadonlyArray<Diagnostic>, PlatformError.PlatformError, Crypto.Crypto>;
|
|
521
|
+
}
|
|
522
|
+
//#endregion
|
|
523
|
+
export type { DocsPreset, GeneratedAtError, GeneratedAtOptions, GeneratedByError, GeneratedByOptions, GitHistoryShape, GitIdentity, Layout, LayoutDirectory, PathLogOptions, Profile, ProfileName, RendersEntry, SurfaceTemplate, UncommittedReason, Writer };
|
|
446
524
|
//# sourceMappingURL=index.d.ts.map
|
package/index.js
CHANGED
|
@@ -4,5 +4,6 @@ import { AgentActorUnconfiguredError, Derivation, HumanActorUnresolvedError } fr
|
|
|
4
4
|
import { PROFILE_NAMES, ProfileDiagnostic, ProfileDiagnosticCode } from "./Profile.js";
|
|
5
5
|
import { Profiles } from "./Profiles.js";
|
|
6
6
|
import { Provenance } from "./Provenance.js";
|
|
7
|
+
import { PUBLICATION_TYPE, Publications, SURFACE_TYPE } from "./Publications.js";
|
|
7
8
|
|
|
8
|
-
export { AgentActorUnconfiguredError, BodyCommitted, BodyProvenance, BodyUncommitted, Derivation, GitHistory, GitHistoryError, HumanActorUnresolvedError, PROFILE_NAMES, PathHistoryEntry, ProfileDiagnostic, ProfileDiagnosticCode, Profiles, Provenance };
|
|
9
|
+
export { AgentActorUnconfiguredError, BodyCommitted, BodyProvenance, BodyUncommitted, Derivation, GitHistory, GitHistoryError, HumanActorUnresolvedError, PROFILE_NAMES, PUBLICATION_TYPE, PathHistoryEntry, ProfileDiagnostic, ProfileDiagnosticCode, Profiles, Provenance, Publications, SURFACE_TYPE };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@okfit/profiles",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Named OKF configuration profiles for okfit, starting with the software-project profile.",
|
|
6
6
|
"keywords": [
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"peerDependencies": {
|
|
38
38
|
"@effected/git": "^0.20.0",
|
|
39
39
|
"@effected/markdown": "^0.15.0",
|
|
40
|
-
"@okfit/core": "^0.
|
|
40
|
+
"@okfit/core": "^0.9.0",
|
|
41
41
|
"effect": "^4.0.0"
|
|
42
42
|
},
|
|
43
43
|
"engines": {
|
package/presets/index.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { CONTRIBUTOR_GUIDES, DOCS_PACKAGE, DOCS_PACKAGES, DOCS_REPO, README_PACKAGE, README_PACKAGES, README_PACKAGES_ONE_PAGE, README_PACKAGE_ONE_PAGE, README_ROOT, README_ROOT_ONE_PAGE, SITE } from "./surfaces.js";
|
|
2
|
+
|
|
3
|
+
//#region src/presets/index.ts
|
|
4
|
+
/**
|
|
5
|
+
* The docs-surface presets the `software-project` profile offers, one per
|
|
6
|
+
* repository shape. Three replace a repository's surfaces; `site` is
|
|
7
|
+
* additive and swaps the README templates for one-page variants that link to
|
|
8
|
+
* the site.
|
|
9
|
+
*
|
|
10
|
+
* @public
|
|
11
|
+
*/
|
|
12
|
+
const DOCS_PRESETS = [
|
|
13
|
+
{
|
|
14
|
+
name: "npm-package",
|
|
15
|
+
description: "A single package published to npm: a README surface that links to a docs/ folder surface.",
|
|
16
|
+
additive: false,
|
|
17
|
+
surfaces: [README_PACKAGE, DOCS_PACKAGE]
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: "monorepo-router",
|
|
21
|
+
description: "A monorepo whose root README routes to per-package READMEs.",
|
|
22
|
+
additive: false,
|
|
23
|
+
surfaces: [README_ROOT, README_PACKAGES]
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: "monorepo-shared-docs",
|
|
27
|
+
description: "A monorepo with routing READMEs plus a shared root docs/ folder, contributor guides and per-package docs/ folders read on the forge.",
|
|
28
|
+
additive: false,
|
|
29
|
+
surfaces: [
|
|
30
|
+
README_ROOT,
|
|
31
|
+
README_PACKAGES,
|
|
32
|
+
DOCS_REPO,
|
|
33
|
+
DOCS_PACKAGES,
|
|
34
|
+
CONTRIBUTOR_GUIDES
|
|
35
|
+
]
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: "site",
|
|
39
|
+
description: "A documentation website plus one-page README variants that link to it; keep the variants that match the repository shape.",
|
|
40
|
+
additive: true,
|
|
41
|
+
surfaces: [
|
|
42
|
+
SITE,
|
|
43
|
+
README_ROOT_ONE_PAGE,
|
|
44
|
+
README_PACKAGES_ONE_PAGE,
|
|
45
|
+
README_PACKAGE_ONE_PAGE
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
//#endregion
|
|
51
|
+
export { DOCS_PRESETS };
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
//#region src/presets/surfaces.ts
|
|
2
|
+
const FENCE = "```";
|
|
3
|
+
/**
|
|
4
|
+
* The durable prose rules every surface body repeats, ported from the
|
|
5
|
+
* design-docs `user-docs` agent. Kept as one list so the rules cannot drift
|
|
6
|
+
* between surfaces.
|
|
7
|
+
*/
|
|
8
|
+
const RULES = [
|
|
9
|
+
"## Prose rules",
|
|
10
|
+
"",
|
|
11
|
+
"- Use sentence case for every heading: `## API reference`, not `## API Reference`. Acronyms and proper nouns keep their case.",
|
|
12
|
+
"- Put every paragraph and list item on one source line; never hard-wrap prose.",
|
|
13
|
+
"- Give every code fence a language identifier.",
|
|
14
|
+
"- Show the expected output of every example that logs a value or runs a command, as comments on the lines after it: `// ...` for JavaScript and TypeScript, `# ...` for shell.",
|
|
15
|
+
"- Never invent output, paths, identifiers or messages; when the real output cannot be verified from the source or by running the command, write a generic placeholder such as `# example output (varies by environment)`.",
|
|
16
|
+
"- Lead install commands with npm or npx and list at most one alternative (pnpm, yarn or bun) below it, unless the page is about package-manager-specific behavior.",
|
|
17
|
+
"- Never write a specific version number in prose; the npm badge and `package.json` are the source of truth. Do not state versions except in a migration guide between major versions.",
|
|
18
|
+
"- Match the language of the surrounding source and docs, and avoid filler, hype and AI-sounding phrasing.",
|
|
19
|
+
"- Never invent a tagline, feature or example: take them from `package.json`, the exported symbols and existing docs, and ask when none exist."
|
|
20
|
+
].join("\n");
|
|
21
|
+
const SINGLE_PACKAGE_SKELETON = [
|
|
22
|
+
`${FENCE}markdown`,
|
|
23
|
+
"# <package-name>",
|
|
24
|
+
"",
|
|
25
|
+
"<badges, built with the docs badge tooling rather than typed by hand>",
|
|
26
|
+
"",
|
|
27
|
+
"<one-paragraph tagline: what this is, what it does, why someone wants it>",
|
|
28
|
+
"",
|
|
29
|
+
"## Install",
|
|
30
|
+
"",
|
|
31
|
+
"<npm command and at most one alternative line>",
|
|
32
|
+
"",
|
|
33
|
+
"Requires <runtime> <engine range>.",
|
|
34
|
+
"",
|
|
35
|
+
"## Quick start",
|
|
36
|
+
"",
|
|
37
|
+
"<minimal worked example in one code block, with expected output as comments>",
|
|
38
|
+
"",
|
|
39
|
+
"## Features",
|
|
40
|
+
"",
|
|
41
|
+
"<bulleted list, one sentence each>",
|
|
42
|
+
"",
|
|
43
|
+
"## Documentation",
|
|
44
|
+
"",
|
|
45
|
+
"<one bullet per topical page in docs/; omit the section when docs/ has none>",
|
|
46
|
+
"",
|
|
47
|
+
"## License",
|
|
48
|
+
"",
|
|
49
|
+
"[<license>](LICENSE)",
|
|
50
|
+
FENCE
|
|
51
|
+
].join("\n");
|
|
52
|
+
const MONOREPO_ROOT_SKELETON = [
|
|
53
|
+
`${FENCE}markdown`,
|
|
54
|
+
"# <repo-name>",
|
|
55
|
+
"",
|
|
56
|
+
"<one paragraph: what the repository is and where it sits in its ecosystem>",
|
|
57
|
+
"",
|
|
58
|
+
"## Packages",
|
|
59
|
+
"",
|
|
60
|
+
"<table with Package and Purpose columns, each package linked to its directory>",
|
|
61
|
+
"",
|
|
62
|
+
"## Install",
|
|
63
|
+
"",
|
|
64
|
+
"<the common install command, or a pointer to each package README>",
|
|
65
|
+
"",
|
|
66
|
+
"## Requirements",
|
|
67
|
+
"",
|
|
68
|
+
"- <runtime> <engine range>",
|
|
69
|
+
"",
|
|
70
|
+
"## License",
|
|
71
|
+
"",
|
|
72
|
+
"[<license>](LICENSE)",
|
|
73
|
+
FENCE
|
|
74
|
+
].join("\n");
|
|
75
|
+
const DOCS_TOC_SKELETON = [
|
|
76
|
+
`${FENCE}markdown`,
|
|
77
|
+
"# <package-name> documentation",
|
|
78
|
+
"",
|
|
79
|
+
"<one-paragraph recap of the package, taken from the README tagline>",
|
|
80
|
+
"",
|
|
81
|
+
"## Install",
|
|
82
|
+
"",
|
|
83
|
+
"<the same npm install block as the README, optionally trimmed>",
|
|
84
|
+
"",
|
|
85
|
+
"## Pages",
|
|
86
|
+
"",
|
|
87
|
+
"<one bullet per page: a link and a one-line description>",
|
|
88
|
+
FENCE
|
|
89
|
+
].join("\n");
|
|
90
|
+
const ONE_PAGE_PACKAGE_SKELETON = [
|
|
91
|
+
`${FENCE}markdown`,
|
|
92
|
+
"# <package-name>",
|
|
93
|
+
"",
|
|
94
|
+
"<badges, built with the docs badge tooling rather than typed by hand>",
|
|
95
|
+
"",
|
|
96
|
+
"<one-paragraph tagline>",
|
|
97
|
+
"",
|
|
98
|
+
"## Install",
|
|
99
|
+
"",
|
|
100
|
+
"<npm command and at most one alternative line>",
|
|
101
|
+
"",
|
|
102
|
+
"## Quick start",
|
|
103
|
+
"",
|
|
104
|
+
"<one minimal example with expected output as comments>",
|
|
105
|
+
"",
|
|
106
|
+
"**Full documentation: <link to the site>**",
|
|
107
|
+
FENCE
|
|
108
|
+
].join("\n");
|
|
109
|
+
const ONE_PAGE_ROOT_SKELETON = [
|
|
110
|
+
`${FENCE}markdown`,
|
|
111
|
+
"# <repo-name>",
|
|
112
|
+
"",
|
|
113
|
+
"<one-paragraph summary of the repository>",
|
|
114
|
+
"",
|
|
115
|
+
"**Full documentation: <link to the site>**",
|
|
116
|
+
"",
|
|
117
|
+
"## Packages",
|
|
118
|
+
"",
|
|
119
|
+
"<table with Package and Purpose columns, each package linked to its directory>",
|
|
120
|
+
FENCE
|
|
121
|
+
].join("\n");
|
|
122
|
+
const CONTRIBUTOR_GUIDE_SKELETON = [
|
|
123
|
+
`${FENCE}markdown`,
|
|
124
|
+
"# <task, as a verb phrase: Make a pull request>",
|
|
125
|
+
"",
|
|
126
|
+
"<one sentence: what this guide gets the reader to>",
|
|
127
|
+
"",
|
|
128
|
+
"## Who this is for",
|
|
129
|
+
"",
|
|
130
|
+
"<the reader, e.g. a first-time contributor with a fork, and what they should already know>",
|
|
131
|
+
"",
|
|
132
|
+
"## Before you start",
|
|
133
|
+
"",
|
|
134
|
+
"<prerequisites as a list: tools and versions, access, a clean checkout, an issue to work from>",
|
|
135
|
+
"",
|
|
136
|
+
"## Steps",
|
|
137
|
+
"",
|
|
138
|
+
"1. <imperative step, with the exact command in a code fence>",
|
|
139
|
+
"2. <next step>",
|
|
140
|
+
"",
|
|
141
|
+
"## What success looks like",
|
|
142
|
+
"",
|
|
143
|
+
"<the observable end state: the passing check, the open PR, the command output>",
|
|
144
|
+
"",
|
|
145
|
+
"## Rules this guide follows",
|
|
146
|
+
"",
|
|
147
|
+
"<one bullet per rule the steps restate, each linking to the page that owns it>",
|
|
148
|
+
FENCE
|
|
149
|
+
].join("\n");
|
|
150
|
+
const body = (...parts) => parts.join("\n\n");
|
|
151
|
+
/** The package README: published to npm, the package's onboarding page. */
|
|
152
|
+
const README_PACKAGE = {
|
|
153
|
+
file: "surfaces/readme-package.md",
|
|
154
|
+
frontmatter: {
|
|
155
|
+
type: "Surface",
|
|
156
|
+
status: "draft",
|
|
157
|
+
title: "Package README",
|
|
158
|
+
description: "The README published to npm for a package, written for people who install it.",
|
|
159
|
+
kind: "readme",
|
|
160
|
+
audience: "users",
|
|
161
|
+
resource: "../../README.md",
|
|
162
|
+
links_to: "docs-repo.md"
|
|
163
|
+
},
|
|
164
|
+
body: body("# Package README", "## Who reads this", "People deciding whether to install the package and getting their first call working. They arrive from npm or the repository page with no context.", "## Required structure", "Follow this outline and fill it from the codebase: the tagline from `package.json` `description`, the features from the exported symbols, and the quick start from the simplest real call. Omit any section you cannot ground.", SINGLE_PACKAGE_SKELETON, "If `package.json` has no `engines` field, omit the runtime badge and the requirements line rather than guessing a range.", "## Other surfaces", "Contributor setup, internals and architecture belong in contributor docs; deep topical guides belong in `docs/`, listed under the Documentation section.", RULES)
|
|
165
|
+
};
|
|
166
|
+
/** The one-page package README that routes readers to the documentation site. */
|
|
167
|
+
const README_PACKAGE_ONE_PAGE = {
|
|
168
|
+
file: "surfaces/readme-package.md",
|
|
169
|
+
frontmatter: {
|
|
170
|
+
type: "Surface",
|
|
171
|
+
status: "draft",
|
|
172
|
+
title: "Package README",
|
|
173
|
+
description: "A one-page README published to npm that routes readers to the documentation site.",
|
|
174
|
+
kind: "readme",
|
|
175
|
+
audience: "users",
|
|
176
|
+
resource: "../../README.md",
|
|
177
|
+
links_to: "site.md"
|
|
178
|
+
},
|
|
179
|
+
body: body("# Package README", "## Who reads this", "People deciding whether to install the package. The documentation site carries the full guides, so this page stays short.", "## Required structure", "Write exactly this and nothing more: the title, the badges, a tagline, the install command, one quick start, and a prominent link to the documentation site.", ONE_PAGE_PACKAGE_SKELETON, "Leave out Features, Documentation and every other section; the site carries them.", "## Other surfaces", "Anything longer than a quick start belongs on the documentation site this surface links to.", RULES)
|
|
180
|
+
};
|
|
181
|
+
/** The monorepo root README: a developer-facing hub, no badges. */
|
|
182
|
+
const README_ROOT = {
|
|
183
|
+
file: "surfaces/readme-root.md",
|
|
184
|
+
frontmatter: {
|
|
185
|
+
type: "Surface",
|
|
186
|
+
status: "draft",
|
|
187
|
+
title: "Repository README",
|
|
188
|
+
description: "The monorepo root README: a hub that explains the packages and how they relate.",
|
|
189
|
+
kind: "readme",
|
|
190
|
+
audience: "contributors",
|
|
191
|
+
resource: "../../README.md"
|
|
192
|
+
},
|
|
193
|
+
body: body("# Repository README", "## Who reads this", "Contributors and visitors who landed on the repository and need to find the package they want. This page routes; it does not document any one package.", "## Required structure", "Follow this outline. Carry no badges on this page; they belong on each package README.", MONOREPO_ROOT_SKELETON, "Add an Ecosystem section only when the repository spans related but separate packages.", "## Other surfaces", "Per-package install and usage belong in each package README; contributor workflow belongs in contributor docs.", RULES)
|
|
194
|
+
};
|
|
195
|
+
/** The monorepo root README that routes readers to the documentation site. */
|
|
196
|
+
const README_ROOT_ONE_PAGE = {
|
|
197
|
+
file: "surfaces/readme-root.md",
|
|
198
|
+
frontmatter: {
|
|
199
|
+
type: "Surface",
|
|
200
|
+
status: "draft",
|
|
201
|
+
title: "Repository README",
|
|
202
|
+
description: "A one-page monorepo root README that routes readers to the documentation site.",
|
|
203
|
+
kind: "readme",
|
|
204
|
+
audience: "contributors",
|
|
205
|
+
resource: "../../README.md",
|
|
206
|
+
links_to: "site.md"
|
|
207
|
+
},
|
|
208
|
+
body: body("# Repository README", "## Who reads this", "People who landed on the repository and need to find the package or guide they want.", "## Required structure", "Write exactly this and nothing more: the title, a one-paragraph summary, a prominent link to the documentation site, and the packages table. Carry no badges.", ONE_PAGE_ROOT_SKELETON, "## Other surfaces", "Guides and reference belong on the documentation site this surface links to.", RULES)
|
|
209
|
+
};
|
|
210
|
+
/** The README inside each monorepo package. */
|
|
211
|
+
const README_PACKAGES = {
|
|
212
|
+
file: "surfaces/readme-packages.md",
|
|
213
|
+
frontmatter: {
|
|
214
|
+
type: "Surface",
|
|
215
|
+
status: "draft",
|
|
216
|
+
title: "Sub-package READMEs",
|
|
217
|
+
description: "The README inside each monorepo package, published to npm with the package.",
|
|
218
|
+
kind: "readme",
|
|
219
|
+
audience: "users",
|
|
220
|
+
resource: "../../packages/*/README.md"
|
|
221
|
+
},
|
|
222
|
+
body: body("# Sub-package READMEs", "## Who reads this", "People installing one package from npm. They never see the monorepo root README, so each page stands alone.", "## Required structure", "Use the single-package outline, with the badges built from that package's own `package.json`.", SINGLE_PACKAGE_SKELETON, "## Other surfaces", "How the packages relate belongs on the repository README; contributor workflow belongs in contributor docs.", RULES)
|
|
223
|
+
};
|
|
224
|
+
/** The one-page sub-package README that routes readers to the documentation site. */
|
|
225
|
+
const README_PACKAGES_ONE_PAGE = {
|
|
226
|
+
file: "surfaces/readme-packages.md",
|
|
227
|
+
frontmatter: {
|
|
228
|
+
type: "Surface",
|
|
229
|
+
status: "draft",
|
|
230
|
+
title: "Sub-package READMEs",
|
|
231
|
+
description: "A one-page README inside each monorepo package that routes readers to the documentation site.",
|
|
232
|
+
kind: "readme",
|
|
233
|
+
audience: "users",
|
|
234
|
+
resource: "../../packages/*/README.md",
|
|
235
|
+
links_to: "site.md"
|
|
236
|
+
},
|
|
237
|
+
body: body("# Sub-package READMEs", "## Who reads this", "People installing one package from npm. The documentation site carries the full guides, so each page stays short.", "## Required structure", "Write exactly this and nothing more: the title, the badges, a tagline, the install command, one quick start, and a prominent link to the package's page on the documentation site.", ONE_PAGE_PACKAGE_SKELETON, "## Other surfaces", "Anything longer than a quick start belongs on the documentation site this surface links to.", RULES)
|
|
238
|
+
};
|
|
239
|
+
const docsRepo = (options) => ({
|
|
240
|
+
file: options.file,
|
|
241
|
+
frontmatter: {
|
|
242
|
+
type: "Surface",
|
|
243
|
+
status: "draft",
|
|
244
|
+
title: options.title,
|
|
245
|
+
description: options.description,
|
|
246
|
+
kind: "repo",
|
|
247
|
+
audience: options.audience,
|
|
248
|
+
resource: options.resource,
|
|
249
|
+
...options.linksTo === void 0 ? {} : { links_to: options.linksTo }
|
|
250
|
+
},
|
|
251
|
+
body: body(`# ${options.title1}`, "## Who reads this", options.reader, "## Required structure", "Name every page `{NN}-{slug}.md`: a two-digit zero-padded number and a kebab-case slug, such as `01-getting-started.md`. Start from `01-getting-started.md`, `02-api-reference.md` and `03-troubleshooting.md`; later topical pages slot between the first and the last two. Keep `README.md` as the table of contents:", DOCS_TOC_SKELETON, "List the pages with the docs table-of-contents tooling rather than by hand, and rename any page that breaks the filename format with `git mv`.", "## Other surfaces", "The one-page pitch and install command belong in the README; contributor workflow belongs in contributor docs.", RULES)
|
|
252
|
+
});
|
|
253
|
+
const USERS_DOCS_READER = "People who finished the README and want a guide, the API reference or troubleshooting help. They read the files on the forge, so every page must read well as plain markdown.";
|
|
254
|
+
/** A `docs/` folder of topical pages for a single package, read on the forge. */
|
|
255
|
+
const DOCS_PACKAGE = docsRepo({
|
|
256
|
+
file: "surfaces/docs-repo.md",
|
|
257
|
+
title: "Repository docs folder",
|
|
258
|
+
title1: "Repository docs folder",
|
|
259
|
+
description: "Topical markdown pages in docs/, read in place on the forge and linked from the README.",
|
|
260
|
+
audience: "users",
|
|
261
|
+
resource: "../../docs",
|
|
262
|
+
reader: USERS_DOCS_READER
|
|
263
|
+
});
|
|
264
|
+
/** The root `docs/` folder of a monorepo: shared contributor pages read on the forge. */
|
|
265
|
+
const DOCS_REPO = docsRepo({
|
|
266
|
+
file: "surfaces/docs-repo.md",
|
|
267
|
+
title: "Repository docs folder",
|
|
268
|
+
title1: "Repository docs folder",
|
|
269
|
+
description: "Shared contributor pages in the root docs/, read in place on the forge and linked from the root README.",
|
|
270
|
+
audience: "contributors",
|
|
271
|
+
resource: "../../docs",
|
|
272
|
+
linksTo: "readme-root.md",
|
|
273
|
+
reader: "Contributors who need the shared workflow, architecture notes or release process. They read the files on the forge, so every page must read well as plain markdown."
|
|
274
|
+
});
|
|
275
|
+
/** The `docs/` folder inside each monorepo package. */
|
|
276
|
+
const DOCS_PACKAGES = docsRepo({
|
|
277
|
+
file: "surfaces/docs-packages.md",
|
|
278
|
+
title: "Sub-package docs folders",
|
|
279
|
+
title1: "Sub-package docs folders",
|
|
280
|
+
description: "Topical markdown pages in each package's docs/, read in place on the forge and linked from its README.",
|
|
281
|
+
audience: "users",
|
|
282
|
+
resource: "../../packages/*/docs",
|
|
283
|
+
linksTo: "readme-packages.md",
|
|
284
|
+
reader: USERS_DOCS_READER
|
|
285
|
+
});
|
|
286
|
+
/** Step-by-step contributor guides in the root `docs/`, read on the forge. */
|
|
287
|
+
const CONTRIBUTOR_GUIDES = {
|
|
288
|
+
file: "surfaces/contributor-guides.md",
|
|
289
|
+
frontmatter: {
|
|
290
|
+
type: "Surface",
|
|
291
|
+
status: "draft",
|
|
292
|
+
title: "Contributor guides",
|
|
293
|
+
description: "Task-shaped contributor guides in the root docs/, such as making a pull request, read in place on the forge.",
|
|
294
|
+
kind: "repo",
|
|
295
|
+
audience: "contributors",
|
|
296
|
+
resource: "../../docs",
|
|
297
|
+
links_to: "readme-root.md"
|
|
298
|
+
},
|
|
299
|
+
body: body("# Contributor guides", "## Who reads this", "Contributors about to do one concrete thing in the repository, such as open a pull request or cut a release. They follow the page top to bottom with a terminal open, so each guide is a procedure, not an essay.", "## Required structure", "Write one guide per task, named `{NN}-{slug}.md` like every other page in `docs/`, for example `01-making-a-pull-request.md`. Use this outline and omit no section:", CONTRIBUTOR_GUIDE_SKELETON, "State each rule the steps rely on once, in its own bullet under the last section, and link to the page that owns it rather than restating the rationale. Take commands from the repository's scripts and verify them before writing them down.", "## Other surfaces", "Reference material and architecture notes belong in the shared docs folder surface; the root README only routes to these guides.", RULES)
|
|
300
|
+
};
|
|
301
|
+
/** The documentation website. */
|
|
302
|
+
const SITE = {
|
|
303
|
+
file: "surfaces/site.md",
|
|
304
|
+
frontmatter: {
|
|
305
|
+
type: "Surface",
|
|
306
|
+
status: "draft",
|
|
307
|
+
title: "Documentation site",
|
|
308
|
+
description: "The published documentation website: guides, reference and tutorials for people using the project.",
|
|
309
|
+
kind: "site",
|
|
310
|
+
audience: "users",
|
|
311
|
+
resource: "../../website",
|
|
312
|
+
url: "https://example.invalid"
|
|
313
|
+
},
|
|
314
|
+
body: body("# Documentation site", "## Who reads this", "People using the project who want guides, reference and worked tutorials. This is the long-form home; the READMEs only point here.", "## Required structure", "Organize pages by what the reader is trying to do: a getting-started path first, task guides next, reference last. Give every page one clear job, a sentence-case title and a short summary before the first heading. Link between pages instead of repeating their content.", "Replace the placeholder `url` in this concept's frontmatter with the real published address before relying on it.", "## Other surfaces", "The README carries only the pitch, the install command and one quick start, and links here for everything else; contributor workflow belongs in contributor docs.", RULES)
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
//#endregion
|
|
318
|
+
export { CONTRIBUTOR_GUIDES, DOCS_PACKAGE, DOCS_PACKAGES, DOCS_REPO, README_PACKAGE, README_PACKAGES, README_PACKAGES_ONE_PAGE, README_PACKAGE_ONE_PAGE, README_ROOT, README_ROOT_ONE_PAGE, SITE };
|