@opum-ai/lore 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -22
- package/bin/lore.cjs +35 -7
- package/package.json +17 -17
- package/src/adapters/backlog.ts +0 -1084
- package/src/adapters/git.ts +0 -221
- package/src/cli.ts +0 -667
- package/src/commands/agent.ts +0 -301
- package/src/commands/agents.ts +0 -302
- package/src/commands/args.ts +0 -209
- package/src/commands/changed.ts +0 -70
- package/src/commands/check.ts +0 -1031
- package/src/commands/codex-bridge.ts +0 -49
- package/src/commands/concurrency.ts +0 -48
- package/src/commands/context.ts +0 -292
- package/src/commands/discover.ts +0 -89
- package/src/commands/explorer.ts +0 -253
- package/src/commands/export.ts +0 -93
- package/src/commands/fswrite.ts +0 -928
- package/src/commands/graph.ts +0 -291
- package/src/commands/help.ts +0 -151
- package/src/commands/impact.ts +0 -59
- package/src/commands/init.ts +0 -583
- package/src/commands/instructions.ts +0 -91
- package/src/commands/link.ts +0 -929
- package/src/commands/new.ts +0 -476
- package/src/commands/orphans.ts +0 -457
- package/src/commands/path.ts +0 -67
- package/src/commands/provenance.ts +0 -68
- package/src/commands/query.ts +0 -312
- package/src/commands/reconcile-shared.ts +0 -280
- package/src/commands/rename.ts +0 -585
- package/src/commands/replace.ts +0 -320
- package/src/commands/scaffold.ts +0 -346
- package/src/commands/schema.ts +0 -293
- package/src/commands/snapshot.ts +0 -130
- package/src/commands/supersede.ts +0 -400
- package/src/commands/sync.ts +0 -371
- package/src/commands/tasks.ts +0 -271
- package/src/commands/traversal.ts +0 -151
- package/src/commands/validate.ts +0 -226
- package/src/config.ts +0 -598
- package/src/core/agent-bridge.ts +0 -287
- package/src/core/agent-context.ts +0 -498
- package/src/core/agent-profile.ts +0 -447
- package/src/core/bundle.ts +0 -893
- package/src/core/check.ts +0 -853
- package/src/core/codex-bridge.ts +0 -100
- package/src/core/concept.ts +0 -597
- package/src/core/consumer-scaffold.ts +0 -433
- package/src/core/context.ts +0 -271
- package/src/core/explorer-contract.ts +0 -441
- package/src/core/explorer-qualification.ts +0 -58
- package/src/core/explorer.ts +0 -518
- package/src/core/finding.ts +0 -31
- package/src/core/graph.ts +0 -201
- package/src/core/indexes.ts +0 -436
- package/src/core/instructions.ts +0 -209
- package/src/core/ladybug-driver.ts +0 -1795
- package/src/core/ladybug-lifecycle.ts +0 -1178
- package/src/core/ladybug-native.ts +0 -95
- package/src/core/ladybug-source.ts +0 -667
- package/src/core/links.ts +0 -681
- package/src/core/log.ts +0 -253
- package/src/core/managed-block.ts +0 -540
- package/src/core/manifest.ts +0 -718
- package/src/core/order.ts +0 -13
- package/src/core/profile.ts +0 -1007
- package/src/core/projection.ts +0 -195
- package/src/core/query.ts +0 -542
- package/src/core/reconcile.ts +0 -236
- package/src/core/replace.ts +0 -419
- package/src/core/retrieval.ts +0 -213
- package/src/core/rewrite.ts +0 -940
- package/src/core/scaffold.ts +0 -255
- package/src/core/schema.ts +0 -366
- package/src/core/snapshot-runtime.ts +0 -52
- package/src/core/snapshot-store.ts +0 -287
- package/src/core/snapshot.ts +0 -711
- package/src/core/template.ts +0 -429
- package/src/core/traversal.ts +0 -487
- package/src/core/validate.ts +0 -517
- package/src/core/workspace-contract.ts +0 -473
- package/src/core/workspace-projection.ts +0 -365
- package/src/core/workspace-retrieval.ts +0 -196
- package/src/core/workspace-source.ts +0 -174
- package/src/errors.ts +0 -697
- package/src/meta.ts +0 -7
- package/src/output.ts +0 -589
- package/src/scripts/upstream-backlog-watch.ts +0 -288
- package/src/state.ts +0 -390
|
@@ -1,433 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* core/consumer-scaffold.ts — the **pure** content builders behind `lore scaffold <target>`
|
|
3
|
-
* (LORE-39/40; cli-surface §"Consumer scaffolding", ADR-0010).
|
|
4
|
-
*
|
|
5
|
-
* Each target's config is generated **additively, outside `docs/`** so the OKF bundle stays
|
|
6
|
-
* the single source of truth (ADR-0010 §2) — with one intentional exception: {@link buildObsidianScaffold}
|
|
7
|
-
* writes `docs/.obsidian/app.json` and `docs/.obsidian/.gitignore` *inside* `docs/`, because
|
|
8
|
-
* Obsidian's vault-scoping requirement (consumer-compatibility.md §3.2) needs `docs/` itself to be
|
|
9
|
-
* the vault root. Every other target's output, and everything else under `docs/`, is never mutated
|
|
10
|
-
* to satisfy a consumer.
|
|
11
|
-
* Like {@link buildScaffold} (`lore init`'s pure plan builder), these functions touch no
|
|
12
|
-
* filesystem and read no clock; the side effects (never-clobber vs. `--force` overwrite) live
|
|
13
|
-
* in `commands/scaffold.ts`.
|
|
14
|
-
*
|
|
15
|
-
* `mkdocs.yml`'s exact settings (§3.3 of
|
|
16
|
-
* [consumer-compatibility.md](../../docs/reference/consumer-compatibility.md)) and the
|
|
17
|
-
* `docs/tags.md` tag-index page were verified against a real `mkdocs build` of this repo's own
|
|
18
|
-
* bundle before being pinned here — `plugins: [tags]` alone builds cleanly, but a dedicated
|
|
19
|
-
* `<!-- material/tags -->` page is what actually renders the tag index (an empty/absent one
|
|
20
|
-
* leaves the plugin silently inert). `docs/tags.md` is a normal, appendable OKF concept once
|
|
21
|
-
* scaffolded — not a `RESERVED_STEMS` entry like `index`/`log` — because nothing regenerates it
|
|
22
|
-
* wholesale afterward; a user may rename or supersede it like any other doc.
|
|
23
|
-
*
|
|
24
|
-
* `docs/tags.md` is serialized against the **structural default profile**, never the active
|
|
25
|
-
* one, via the shared {@link serializeStructuralConcept} (`scaffold.ts`) — the same helper
|
|
26
|
-
* `rootIndexDocument` uses for `docs/index.md`, and for the identical reason: it is lore's own
|
|
27
|
-
* fixed-shape utility page, so a custom profile that adds a required field to `Reference` must not
|
|
28
|
-
* make `lore scaffold mkdocs` fail to write it.
|
|
29
|
-
*
|
|
30
|
-
* `website/`'s three files (`docusaurus.config.js`, `sidebars.js`, `package.json`) were verified
|
|
31
|
-
* against a real `docusaurus build` (v3.10.2) of this repo's own bundle before being pinned here.
|
|
32
|
-
* `docusaurus.config.js`/`sidebars.js` MUST be CommonJS (`module.exports = {...}`), not the ESM
|
|
33
|
-
* `export default` shown in consumer-compatibility.md's superseded snippet — that form crashes
|
|
34
|
-
* the production build (`TypeError: require.resolveWeak is not a function`, an ESM/webpack-SSR
|
|
35
|
-
* interaction), not a config-content bug; the exact same settings succeed once the file is CJS.
|
|
36
|
-
* Unlike MkDocs (a standalone pip-installed tool), Docusaurus's CLI is a project-local
|
|
37
|
-
* devDependency that resolves its preset/theme from the site's own `node_modules`, so `website/`
|
|
38
|
-
* needs its own `package.json` — `@docusaurus/core` and `@docusaurus/preset-classic` pinned to
|
|
39
|
-
* the same exact version (Docusaurus packages must stay in lockstep) and no `"type": "module"`.
|
|
40
|
-
* `website/` carries no OKF concept file (unlike mkdocs's `docs/tags.md`) — the sidebar is fully
|
|
41
|
-
* autogenerated from `docs/`, so nothing needs `serializeStructuralConcept` here.
|
|
42
|
-
*/
|
|
43
|
-
|
|
44
|
-
import type { Concept } from "./concept";
|
|
45
|
-
import { idFromPath } from "./concept";
|
|
46
|
-
import { defaultProfile, type Profile } from "./profile";
|
|
47
|
-
import { DOCS_DIR, serializeStructuralConcept } from "./scaffold";
|
|
48
|
-
|
|
49
|
-
/** The repo-root-relative path of the scaffolded MkDocs config, sibling to `docs/` (ADR-0010 §2). */
|
|
50
|
-
export const MKDOCS_CONFIG_REL_PATH = "mkdocs.yml";
|
|
51
|
-
|
|
52
|
-
/** The repo-relative path of the scaffolded MkDocs Material tag-index page. */
|
|
53
|
-
export const TAGS_INDEX_REL_PATH = `${DOCS_DIR}/tags.md`;
|
|
54
|
-
|
|
55
|
-
/** The repo-root-relative directory of the scaffolded Docusaurus site, sibling to `docs/` (ADR-0010 §2). */
|
|
56
|
-
export const WEBSITE_DIR = "website";
|
|
57
|
-
|
|
58
|
-
/** The repo-relative path of the scaffolded Docusaurus config. */
|
|
59
|
-
export const DOCUSAURUS_CONFIG_REL_PATH = `${WEBSITE_DIR}/docusaurus.config.js`;
|
|
60
|
-
|
|
61
|
-
/** The repo-relative path of the scaffolded, fully-autogenerated Docusaurus sidebar. */
|
|
62
|
-
export const SIDEBARS_REL_PATH = `${WEBSITE_DIR}/sidebars.js`;
|
|
63
|
-
|
|
64
|
-
/** The repo-relative path of the scaffolded Docusaurus site's own package manifest. */
|
|
65
|
-
export const WEBSITE_PACKAGE_JSON_REL_PATH = `${WEBSITE_DIR}/package.json`;
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* The repo-relative directory of the scaffolded Obsidian vault config — inside `docs/`, unlike
|
|
69
|
-
* `website/`/`mkdocs.yml`, since the recommended setup opens `docs/` itself as the vault
|
|
70
|
-
* (consumer-compatibility.md §3.2).
|
|
71
|
-
*/
|
|
72
|
-
export const OBSIDIAN_DIR = `${DOCS_DIR}/.obsidian`;
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* The repo-relative path of the scaffolded Obsidian vault config. Only this file (plus
|
|
76
|
-
* {@link OBSIDIAN_GITIGNORE_REL_PATH} itself) is meant to be committed — the scaffolded
|
|
77
|
-
* `.gitignore` excludes everything under `docs/.obsidian/` *except* the two of them
|
|
78
|
-
* (`*` plus `!app.json`/`!.gitignore` negations), rather than enumerating the rest of Obsidian's
|
|
79
|
-
* per-user vault state file by file, since Obsidian creates more of those than any fixed list can
|
|
80
|
-
* keep up with. A future file scaffolded under `docs/.obsidian/` needs its own negation line to
|
|
81
|
-
* be committed.
|
|
82
|
-
*/
|
|
83
|
-
export const OBSIDIAN_APP_JSON_REL_PATH = `${OBSIDIAN_DIR}/app.json`;
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* The repo-relative path of the scaffolded, self-contained Obsidian `.gitignore`
|
|
87
|
-
* (consumer-compatibility.md §3.2: "A `.gitignore` entry for `docs/.obsidian/workspace*.json` and
|
|
88
|
-
* the cache (commit `app.json` only)"). Scoped *inside* `docs/.obsidian/` rather than appended to
|
|
89
|
-
* a repo-root `.gitignore` — every pattern below is relative to this file's own directory — so
|
|
90
|
-
* scaffolding it never has to read, merge into, or risk clobbering a consumer's pre-existing
|
|
91
|
-
* root `.gitignore`; it fits the same create-fresh/`--force`-to-overwrite model every other
|
|
92
|
-
* scaffolded file already uses. Its exclude-all-except pattern is a strict superset of the doc's
|
|
93
|
-
* literal `workspace*.json`/cache wording — see {@link OBSIDIAN_APP_JSON_REL_PATH}'s own doc for why.
|
|
94
|
-
*/
|
|
95
|
-
export const OBSIDIAN_GITIGNORE_REL_PATH = `${OBSIDIAN_DIR}/.gitignore`;
|
|
96
|
-
|
|
97
|
-
/** The exact, lockstep-pinned Docusaurus version this scaffold was verified against. */
|
|
98
|
-
const DOCUSAURUS_VERSION = "3.10.2";
|
|
99
|
-
|
|
100
|
-
/** A single file a consumer scaffold wants to exist, with the exact bytes to write. */
|
|
101
|
-
export interface ConsumerScaffoldFile {
|
|
102
|
-
/** Repo-relative POSIX path. */
|
|
103
|
-
readonly path: string;
|
|
104
|
-
/** The exact bytes to write — pinned by golden tests, applied verbatim by the command. */
|
|
105
|
-
readonly contents: string;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/** The complete, filesystem-free description of one consumer's scaffolded config. */
|
|
109
|
-
export interface ConsumerScaffoldPlan {
|
|
110
|
-
/** Directories to ensure exist first, parents before children (mirrors `ScaffoldPlan.dirs`). */
|
|
111
|
-
readonly dirs: readonly string[];
|
|
112
|
-
/** Files to create (or, under `--force`, overwrite), in a stable order. */
|
|
113
|
-
readonly files: readonly ConsumerScaffoldFile[];
|
|
114
|
-
/**
|
|
115
|
-
* Extra guidance lines the command prints after the file summary, for a target whose scaffolded
|
|
116
|
-
* file cannot fully guarantee the desired behavior on its own (e.g. Obsidian's `app.json`, which
|
|
117
|
-
* some Obsidian builds do not read at all — the Settings UI is the real guarantee). Omitted by
|
|
118
|
-
* targets with nothing to add (mkdocs, docusaurus).
|
|
119
|
-
*/
|
|
120
|
-
readonly notes?: readonly string[];
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/** Options for {@link buildMkdocsScaffold}, {@link buildDocusaurusScaffold}, and {@link buildObsidianScaffold}. */
|
|
124
|
-
export interface ConsumerScaffoldOptions {
|
|
125
|
-
/**
|
|
126
|
-
* ISO-8601 datetime stamped on `docs/tags.md`'s frontmatter, mirroring `buildScaffold`'s
|
|
127
|
-
* injected-clock seam (lore-design §8) so the plan stays deterministic and golden-testable.
|
|
128
|
-
* Unused by {@link buildDocusaurusScaffold} and {@link buildObsidianScaffold}, neither of which
|
|
129
|
-
* emits an OKF concept file; kept here so all three builders share one options shape and the
|
|
130
|
-
* command layer calls them uniformly.
|
|
131
|
-
*/
|
|
132
|
-
readonly timestamp: string;
|
|
133
|
-
/**
|
|
134
|
-
* The MkDocs `site_name` / Docusaurus `title` (required by both; there is no sane
|
|
135
|
-
* zero-config default). The command layer derives this from the repo directory name — the
|
|
136
|
-
* one filesystem read these otherwise-pure builders need, kept at the boundary rather than
|
|
137
|
-
* smuggled in here. Unused by {@link buildObsidianScaffold}, whose `app.json` carries no
|
|
138
|
-
* site-name-equivalent setting.
|
|
139
|
-
*/
|
|
140
|
-
readonly siteName: string;
|
|
141
|
-
/**
|
|
142
|
-
* The active profile, used only to decide whether `docs/tags.md` carries the
|
|
143
|
-
* `$schema` editor modeline (only when the profile actually defines `Reference`).
|
|
144
|
-
* Defaults to the built-in {@link defaultProfile}. Unused by {@link buildDocusaurusScaffold}
|
|
145
|
-
* and {@link buildObsidianScaffold}, for the same reason as `timestamp`.
|
|
146
|
-
*/
|
|
147
|
-
readonly profile?: Profile;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Build the {@link ConsumerScaffoldPlan} for `lore scaffold mkdocs`: a repo-root `mkdocs.yml`
|
|
152
|
-
* and a `docs/tags.md` tag-index page. Pure — identical `options` always produce identical bytes.
|
|
153
|
-
*/
|
|
154
|
-
export function buildMkdocsScaffold(options: ConsumerScaffoldOptions): ConsumerScaffoldPlan {
|
|
155
|
-
const profile = options.profile ?? defaultProfile();
|
|
156
|
-
return {
|
|
157
|
-
dirs: [DOCS_DIR],
|
|
158
|
-
files: [
|
|
159
|
-
{ path: MKDOCS_CONFIG_REL_PATH, contents: mkdocsConfigYaml(options.siteName) },
|
|
160
|
-
{ path: TAGS_INDEX_REL_PATH, contents: tagsIndexDocument(options.timestamp, profile) },
|
|
161
|
-
],
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* Build the {@link ConsumerScaffoldPlan} for `lore scaffold docusaurus`: a `website/` directory
|
|
167
|
-
* with `package.json`, `docusaurus.config.js`, and `sidebars.js`. Pure — identical `options`
|
|
168
|
-
* always produce identical bytes.
|
|
169
|
-
*/
|
|
170
|
-
export function buildDocusaurusScaffold(options: ConsumerScaffoldOptions): ConsumerScaffoldPlan {
|
|
171
|
-
return {
|
|
172
|
-
dirs: [WEBSITE_DIR],
|
|
173
|
-
files: [
|
|
174
|
-
{ path: WEBSITE_PACKAGE_JSON_REL_PATH, contents: websitePackageJson() },
|
|
175
|
-
{ path: DOCUSAURUS_CONFIG_REL_PATH, contents: docusaurusConfigJs(options.siteName) },
|
|
176
|
-
{ path: SIDEBARS_REL_PATH, contents: sidebarsJs() },
|
|
177
|
-
],
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Build the {@link ConsumerScaffoldPlan} for `lore scaffold obsidian` (LORE-41): the
|
|
183
|
-
* `docs/.obsidian/app.json` preset plus the scoped `docs/.obsidian/.gitignore` that keeps
|
|
184
|
-
* Obsidian's per-user vault state (workspace layout, cache, plugins/, ...) untracked while still
|
|
185
|
-
* committing the two of them (consumer-compatibility.md §3.2), plus {@link OBSIDIAN_GUIDANCE_NOTES}.
|
|
186
|
-
* Pure — identical `options` always produce identical bytes; unlike {@link buildMkdocsScaffold}, no
|
|
187
|
-
* OKF concept file is emitted, so every `options` field goes unused here, the same reason
|
|
188
|
-
* {@link buildDocusaurusScaffold} ignores `timestamp`/`profile`.
|
|
189
|
-
*/
|
|
190
|
-
export function buildObsidianScaffold(_options: ConsumerScaffoldOptions): ConsumerScaffoldPlan {
|
|
191
|
-
return {
|
|
192
|
-
dirs: [DOCS_DIR, OBSIDIAN_DIR],
|
|
193
|
-
files: [
|
|
194
|
-
{ path: OBSIDIAN_APP_JSON_REL_PATH, contents: obsidianAppJson() },
|
|
195
|
-
{ path: OBSIDIAN_GITIGNORE_REL_PATH, contents: obsidianGitignore() },
|
|
196
|
-
],
|
|
197
|
-
notes: OBSIDIAN_GUIDANCE_NOTES,
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
/** The reserved tag-index page's `type` — a plain `Reference`, like the bundle root index. */
|
|
202
|
-
const TAGS_INDEX_TYPE = "Reference";
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* The `docs/tags.md` bytes: a valid OKF `Reference` concept (so it stays lint-clean and
|
|
206
|
-
* OKF-legal) whose body carries the `<!-- material/tags -->` marker the MkDocs Material `tags`
|
|
207
|
-
* plugin scans to render the tag index. Serialized via the shared {@link serializeStructuralConcept}
|
|
208
|
-
* — see the module docstring for why — which conditionally carries the `$schema` modeline only
|
|
209
|
-
* when the *active* profile defines `Reference`.
|
|
210
|
-
*/
|
|
211
|
-
function tagsIndexDocument(timestamp: string, profile: Profile): string {
|
|
212
|
-
const concept: Concept = {
|
|
213
|
-
id: idFromPath(TAGS_INDEX_REL_PATH),
|
|
214
|
-
path: TAGS_INDEX_REL_PATH,
|
|
215
|
-
type: TAGS_INDEX_TYPE,
|
|
216
|
-
frontmatter: {
|
|
217
|
-
type: TAGS_INDEX_TYPE,
|
|
218
|
-
title: "Tags",
|
|
219
|
-
summary: "Autogenerated tag index for this OKF bundle, rendered by the MkDocs Material `tags` plugin.",
|
|
220
|
-
timestamp,
|
|
221
|
-
},
|
|
222
|
-
body: TAGS_INDEX_BODY,
|
|
223
|
-
};
|
|
224
|
-
return serializeStructuralConcept(concept, profile);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
/** The body of the scaffolded tag-index page (after the frontmatter fence). */
|
|
228
|
-
const TAGS_INDEX_BODY = `
|
|
229
|
-
# Tags
|
|
230
|
-
|
|
231
|
-
<!-- material/tags -->
|
|
232
|
-
`;
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* The shared "generated once, user-owned" disclaimer every scaffolded config's header comment
|
|
236
|
-
* carries, so the wording and `--force` phrasing live in one place instead of being copy-pasted
|
|
237
|
-
* per target. `commentPrefix` is `#` (YAML) or `//` (JS); `target`/`docSection` name the specific
|
|
238
|
-
* `lore scaffold <target>` invocation and the consumer-compatibility.md section to cite.
|
|
239
|
-
*/
|
|
240
|
-
function generatedHeader(commentPrefix: string, target: string, docSection: string): string {
|
|
241
|
-
return `${commentPrefix} Generated once by \`lore scaffold ${target}\` — user-owned; re-run with --force to regenerate.
|
|
242
|
-
${commentPrefix} See docs/reference/consumer-compatibility.md ${docSection} and ADR-0010 for the rationale.`;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* The scaffolded `mkdocs.yml` bytes (consumer-compatibility.md §3.3; ADR-0010 §2). Every setting
|
|
247
|
-
* mirrors that documented rationale — repeated here as inline comments since this is the file a
|
|
248
|
-
* team actually reads and edits, not the doc:
|
|
249
|
-
*
|
|
250
|
-
* - `navigation.indexes` — `index.md` becomes each section's landing page (not just a sibling link).
|
|
251
|
-
* - `plugins: [search, tags]` — the built-in search plus the frontmatter `tags` → chips/tag-index plugin.
|
|
252
|
-
* - `strict: false` plus `not_found: warn` (links, nav, anchors) — honors OKF's broken-link
|
|
253
|
-
* tolerance so an in-progress or cross-tree (`backlog/`) link never fails the build.
|
|
254
|
-
* - `absolute_links: relative_to_docs` (MkDocs >= 1.6) — the safety net for any `/`-absolute
|
|
255
|
-
* link that survives the portability lint.
|
|
256
|
-
* - `not_in_nav: /log.md` — the machine-regenerated log stays out of the autogenerated nav tree.
|
|
257
|
-
*/
|
|
258
|
-
function mkdocsConfigYaml(siteName: string): string {
|
|
259
|
-
return `${generatedHeader("#", "mkdocs", "§3.3")}
|
|
260
|
-
site_name: ${JSON.stringify(siteName)}
|
|
261
|
-
docs_dir: docs
|
|
262
|
-
theme:
|
|
263
|
-
name: material
|
|
264
|
-
features:
|
|
265
|
-
- navigation.indexes
|
|
266
|
-
plugins:
|
|
267
|
-
- search
|
|
268
|
-
- tags
|
|
269
|
-
strict: false
|
|
270
|
-
validation:
|
|
271
|
-
links:
|
|
272
|
-
absolute_links: relative_to_docs
|
|
273
|
-
not_found: warn
|
|
274
|
-
anchors: warn
|
|
275
|
-
nav:
|
|
276
|
-
omitted_files: ignore
|
|
277
|
-
not_found: warn
|
|
278
|
-
not_in_nav: |
|
|
279
|
-
/log.md
|
|
280
|
-
`;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
/**
|
|
284
|
-
* The exact React version this scaffold was verified against — within `@docusaurus/preset-classic@3.10.2`'s
|
|
285
|
-
* verified peer range (`^18.0.0 || ^19.0.0`). `react`/`react-dom` are pinned exactly, like
|
|
286
|
-
* `@docusaurus/core`/`@docusaurus/preset-classic`, rather than left on a caret range: no
|
|
287
|
-
* lockfile is scaffolded (matching MkDocs's own floor-not-exact CI precedent, which has no
|
|
288
|
-
* requirements file at all), so an exact pin on every *direct* dependency is the cheapest
|
|
289
|
-
* available guard against a fresh `npm install` silently resolving a different, unverified
|
|
290
|
-
* top-level React on a later run — it cannot pin transitive dependencies, which is the
|
|
291
|
-
* inherent tradeoff of not committing a lockfile.
|
|
292
|
-
*/
|
|
293
|
-
const REACT_VERSION = "19.2.7";
|
|
294
|
-
|
|
295
|
-
/**
|
|
296
|
-
* The scaffolded `website/package.json` bytes. Docusaurus's CLI is a project-local
|
|
297
|
-
* devDependency (unlike MkDocs, which is pip-installed and standalone) — `@docusaurus/core`
|
|
298
|
-
* and `@docusaurus/preset-classic` are pinned to the exact same {@link DOCUSAURUS_VERSION}
|
|
299
|
-
* (Docusaurus packages must stay in lockstep; a caret range on one but not the other can
|
|
300
|
-
* resolve mismatched minors). Deliberately no `"type": "module"` — see the module docstring
|
|
301
|
-
* for why the config files must load as CommonJS.
|
|
302
|
-
*/
|
|
303
|
-
function websitePackageJson(): string {
|
|
304
|
-
const pkg = {
|
|
305
|
-
name: "website",
|
|
306
|
-
private: true,
|
|
307
|
-
scripts: {
|
|
308
|
-
build: "docusaurus build",
|
|
309
|
-
},
|
|
310
|
-
dependencies: {
|
|
311
|
-
"@docusaurus/core": DOCUSAURUS_VERSION,
|
|
312
|
-
"@docusaurus/preset-classic": DOCUSAURUS_VERSION,
|
|
313
|
-
react: REACT_VERSION,
|
|
314
|
-
"react-dom": REACT_VERSION,
|
|
315
|
-
},
|
|
316
|
-
};
|
|
317
|
-
return `${JSON.stringify(pkg, null, 2)}\n`;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
/**
|
|
321
|
-
* The scaffolded `docusaurus.config.js` bytes (consumer-compatibility.md §3.4; ADR-0010 §2).
|
|
322
|
-
* Every setting mirrors that documented rationale — repeated here as inline comments since
|
|
323
|
-
* this is the file a team actually reads and edits, not the doc:
|
|
324
|
-
*
|
|
325
|
-
* - `markdown.format: 'detect'` — the load-bearing flip: without it, raw `<`/`{` in
|
|
326
|
-
* hand-written OKF prose (and `<!-- lore:tasks:begin -->`-style comments) is parsed as
|
|
327
|
-
* MDX/JSX and breaks the build.
|
|
328
|
-
* - `markdown.hooks.onBrokenMarkdownLinks: 'warn'` (moved here in Docusaurus v3.9) plus
|
|
329
|
-
* `onBrokenLinks: 'warn'` / `onBrokenAnchors: 'warn'` — the default `onBrokenLinks: 'throw'`
|
|
330
|
-
* would fail the build on OKF's tolerated broken links (cross-tree `backlog/` links, in-progress docs).
|
|
331
|
-
* - `docs.path: '../docs'` / `routeBasePath: '/'` — points the site at the existing bundle
|
|
332
|
-
* without copying or mutating it (ADR-0010 §2: scaffolding is additive, outside `docs/`).
|
|
333
|
-
* - `blog: false` — avoids parent-folder MDX-loader conflicts; OKF bundles have no blog.
|
|
334
|
-
* - `trailingSlash: false` — pinned to avoid relative-link drift.
|
|
335
|
-
* - `url` / `baseUrl` are placeholders sufficient for `docusaurus build` (which requires both);
|
|
336
|
-
* only a real deploy needs `organizationName`/`projectName`, which this scaffold does not set.
|
|
337
|
-
*/
|
|
338
|
-
function docusaurusConfigJs(siteName: string): string {
|
|
339
|
-
return `${generatedHeader("//", "docusaurus", "§3.4")}
|
|
340
|
-
//
|
|
341
|
-
// CommonJS, not ESM: an \`export default\` form here crashes the production build
|
|
342
|
-
// (require.resolveWeak is not a function, an ESM/webpack-SSR interaction) — verified against
|
|
343
|
-
// a real \`docusaurus build\`. Do not add "type": "module" to this site's package.json.
|
|
344
|
-
module.exports = {
|
|
345
|
-
title: ${JSON.stringify(siteName)},
|
|
346
|
-
url: "https://example.com",
|
|
347
|
-
baseUrl: "/",
|
|
348
|
-
trailingSlash: false,
|
|
349
|
-
onBrokenLinks: "warn",
|
|
350
|
-
onBrokenAnchors: "warn",
|
|
351
|
-
markdown: {
|
|
352
|
-
format: "detect",
|
|
353
|
-
hooks: {
|
|
354
|
-
onBrokenMarkdownLinks: "warn",
|
|
355
|
-
},
|
|
356
|
-
},
|
|
357
|
-
presets: [
|
|
358
|
-
[
|
|
359
|
-
"classic",
|
|
360
|
-
{
|
|
361
|
-
docs: {
|
|
362
|
-
path: "../docs",
|
|
363
|
-
routeBasePath: "/",
|
|
364
|
-
sidebarPath: "./sidebars.js",
|
|
365
|
-
},
|
|
366
|
-
blog: false,
|
|
367
|
-
},
|
|
368
|
-
],
|
|
369
|
-
],
|
|
370
|
-
};
|
|
371
|
-
`;
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
/**
|
|
375
|
-
* The scaffolded `sidebars.js` bytes: a single fully-autogenerated sidebar built from the
|
|
376
|
-
* bundle tree (consumer-compatibility.md §3.4) — no per-page sidebar maintenance.
|
|
377
|
-
*/
|
|
378
|
-
function sidebarsJs(): string {
|
|
379
|
-
return `${generatedHeader("//", "docusaurus", "§3.4")}
|
|
380
|
-
module.exports = {
|
|
381
|
-
docs: [{ type: "autogenerated", dirName: "." }],
|
|
382
|
-
};
|
|
383
|
-
`;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
/**
|
|
387
|
-
* Guidance printed after a `lore scaffold obsidian` run. `app.json`'s keys mirror the Settings →
|
|
388
|
-
* Files & Links values below, but Obsidian only reads `app.json` on startup and some builds
|
|
389
|
-
* (mobile in particular) do not honor it at all — the UI is the real guarantee
|
|
390
|
-
* (consumer-compatibility.md §3.2), so the command surfaces it instead of leaving it undocumented.
|
|
391
|
-
*/
|
|
392
|
-
export const OBSIDIAN_GUIDANCE_NOTES: readonly string[] = Object.freeze([
|
|
393
|
-
"Open docs/ itself as the vault (not the repo root), so only the OKF bundle is indexed.",
|
|
394
|
-
"app.json is a best-effort preset — confirm Settings → Files & Links matches:",
|
|
395
|
-
" New link format = Relative path to file",
|
|
396
|
-
" Use [[Wikilinks]] = OFF",
|
|
397
|
-
" Automatically update internal links = ON",
|
|
398
|
-
]);
|
|
399
|
-
|
|
400
|
-
/**
|
|
401
|
-
* The scaffolded `docs/.obsidian/app.json` bytes (consumer-compatibility.md §3.2): plain JSON, no
|
|
402
|
-
* header comment (unlike `mkdocs.yml`/`docusaurus.config.js`) since Obsidian owns this file and
|
|
403
|
-
* JSON has no comment syntax to carry one in. `useMarkdownLinks`/`newLinkFormat: "relative"` make
|
|
404
|
-
* new links GitHub-compatible (`[text](path.md)`, not `[[wikilinks]]`); `alwaysUpdateLinks` keeps
|
|
405
|
-
* them correct across renames — the same three settings consumer-compatibility.md's manual
|
|
406
|
-
* Files & Links walkthrough recommends.
|
|
407
|
-
*/
|
|
408
|
-
function obsidianAppJson(): string {
|
|
409
|
-
const config = {
|
|
410
|
-
useMarkdownLinks: true,
|
|
411
|
-
newLinkFormat: "relative",
|
|
412
|
-
alwaysUpdateLinks: true,
|
|
413
|
-
};
|
|
414
|
-
return `${JSON.stringify(config, null, 2)}\n`;
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
/**
|
|
418
|
-
* The scaffolded `docs/.obsidian/.gitignore` bytes ({@link OBSIDIAN_GITIGNORE_REL_PATH}):
|
|
419
|
-
* exclude-all-except, scoped to `docs/.obsidian/` itself so every pattern below is relative to
|
|
420
|
-
* that directory rather than the repo root. `*` ignores everything Obsidian writes there
|
|
421
|
-
* (`workspace.json`, `workspace-mobile.json`, `cache/`, `plugins/`, `snippets/`, ...) — a strict
|
|
422
|
-
* superset of consumer-compatibility.md §3.2's literal `workspace*.json`/cache wording, chosen for
|
|
423
|
-
* the same reason this repo's own root `.gitignore` uses it for its own `docs/.obsidian/`: Obsidian
|
|
424
|
-
* creates more per-user state files than any fixed list can keep up with. `!.gitignore` and
|
|
425
|
-
* `!app.json` re-include the two files this scaffold actually wants committed.
|
|
426
|
-
*/
|
|
427
|
-
function obsidianGitignore(): string {
|
|
428
|
-
return `${generatedHeader("#", "obsidian", "§3.2")}
|
|
429
|
-
*
|
|
430
|
-
!.gitignore
|
|
431
|
-
!app.json
|
|
432
|
-
`;
|
|
433
|
-
}
|