@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.
Files changed (90) hide show
  1. package/README.md +33 -22
  2. package/bin/lore.cjs +35 -7
  3. package/package.json +17 -17
  4. package/src/adapters/backlog.ts +0 -1084
  5. package/src/adapters/git.ts +0 -221
  6. package/src/cli.ts +0 -667
  7. package/src/commands/agent.ts +0 -301
  8. package/src/commands/agents.ts +0 -302
  9. package/src/commands/args.ts +0 -209
  10. package/src/commands/changed.ts +0 -70
  11. package/src/commands/check.ts +0 -1031
  12. package/src/commands/codex-bridge.ts +0 -49
  13. package/src/commands/concurrency.ts +0 -48
  14. package/src/commands/context.ts +0 -292
  15. package/src/commands/discover.ts +0 -89
  16. package/src/commands/explorer.ts +0 -253
  17. package/src/commands/export.ts +0 -93
  18. package/src/commands/fswrite.ts +0 -928
  19. package/src/commands/graph.ts +0 -291
  20. package/src/commands/help.ts +0 -151
  21. package/src/commands/impact.ts +0 -59
  22. package/src/commands/init.ts +0 -583
  23. package/src/commands/instructions.ts +0 -91
  24. package/src/commands/link.ts +0 -929
  25. package/src/commands/new.ts +0 -476
  26. package/src/commands/orphans.ts +0 -457
  27. package/src/commands/path.ts +0 -67
  28. package/src/commands/provenance.ts +0 -68
  29. package/src/commands/query.ts +0 -312
  30. package/src/commands/reconcile-shared.ts +0 -280
  31. package/src/commands/rename.ts +0 -585
  32. package/src/commands/replace.ts +0 -320
  33. package/src/commands/scaffold.ts +0 -346
  34. package/src/commands/schema.ts +0 -293
  35. package/src/commands/snapshot.ts +0 -130
  36. package/src/commands/supersede.ts +0 -400
  37. package/src/commands/sync.ts +0 -371
  38. package/src/commands/tasks.ts +0 -271
  39. package/src/commands/traversal.ts +0 -151
  40. package/src/commands/validate.ts +0 -226
  41. package/src/config.ts +0 -598
  42. package/src/core/agent-bridge.ts +0 -287
  43. package/src/core/agent-context.ts +0 -498
  44. package/src/core/agent-profile.ts +0 -447
  45. package/src/core/bundle.ts +0 -893
  46. package/src/core/check.ts +0 -853
  47. package/src/core/codex-bridge.ts +0 -100
  48. package/src/core/concept.ts +0 -597
  49. package/src/core/consumer-scaffold.ts +0 -433
  50. package/src/core/context.ts +0 -271
  51. package/src/core/explorer-contract.ts +0 -441
  52. package/src/core/explorer-qualification.ts +0 -58
  53. package/src/core/explorer.ts +0 -518
  54. package/src/core/finding.ts +0 -31
  55. package/src/core/graph.ts +0 -201
  56. package/src/core/indexes.ts +0 -436
  57. package/src/core/instructions.ts +0 -209
  58. package/src/core/ladybug-driver.ts +0 -1795
  59. package/src/core/ladybug-lifecycle.ts +0 -1178
  60. package/src/core/ladybug-native.ts +0 -95
  61. package/src/core/ladybug-source.ts +0 -667
  62. package/src/core/links.ts +0 -681
  63. package/src/core/log.ts +0 -253
  64. package/src/core/managed-block.ts +0 -540
  65. package/src/core/manifest.ts +0 -718
  66. package/src/core/order.ts +0 -13
  67. package/src/core/profile.ts +0 -1007
  68. package/src/core/projection.ts +0 -195
  69. package/src/core/query.ts +0 -542
  70. package/src/core/reconcile.ts +0 -236
  71. package/src/core/replace.ts +0 -419
  72. package/src/core/retrieval.ts +0 -213
  73. package/src/core/rewrite.ts +0 -940
  74. package/src/core/scaffold.ts +0 -255
  75. package/src/core/schema.ts +0 -366
  76. package/src/core/snapshot-runtime.ts +0 -52
  77. package/src/core/snapshot-store.ts +0 -287
  78. package/src/core/snapshot.ts +0 -711
  79. package/src/core/template.ts +0 -429
  80. package/src/core/traversal.ts +0 -487
  81. package/src/core/validate.ts +0 -517
  82. package/src/core/workspace-contract.ts +0 -473
  83. package/src/core/workspace-projection.ts +0 -365
  84. package/src/core/workspace-retrieval.ts +0 -196
  85. package/src/core/workspace-source.ts +0 -174
  86. package/src/errors.ts +0 -697
  87. package/src/meta.ts +0 -7
  88. package/src/output.ts +0 -589
  89. package/src/scripts/upstream-backlog-watch.ts +0 -288
  90. 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
- }