@opum-ai/lore 0.1.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.
Files changed (91) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +306 -0
  3. package/bin/lore.cjs +109 -0
  4. package/package.json +67 -0
  5. package/src/adapters/backlog.ts +1084 -0
  6. package/src/adapters/git.ts +221 -0
  7. package/src/cli.ts +667 -0
  8. package/src/commands/agent.ts +301 -0
  9. package/src/commands/agents.ts +302 -0
  10. package/src/commands/args.ts +209 -0
  11. package/src/commands/changed.ts +70 -0
  12. package/src/commands/check.ts +1031 -0
  13. package/src/commands/codex-bridge.ts +49 -0
  14. package/src/commands/concurrency.ts +48 -0
  15. package/src/commands/context.ts +292 -0
  16. package/src/commands/discover.ts +89 -0
  17. package/src/commands/explorer.ts +253 -0
  18. package/src/commands/export.ts +93 -0
  19. package/src/commands/fswrite.ts +928 -0
  20. package/src/commands/graph.ts +291 -0
  21. package/src/commands/help.ts +151 -0
  22. package/src/commands/impact.ts +59 -0
  23. package/src/commands/init.ts +583 -0
  24. package/src/commands/instructions.ts +91 -0
  25. package/src/commands/link.ts +929 -0
  26. package/src/commands/new.ts +476 -0
  27. package/src/commands/orphans.ts +457 -0
  28. package/src/commands/path.ts +67 -0
  29. package/src/commands/provenance.ts +68 -0
  30. package/src/commands/query.ts +312 -0
  31. package/src/commands/reconcile-shared.ts +280 -0
  32. package/src/commands/rename.ts +585 -0
  33. package/src/commands/replace.ts +320 -0
  34. package/src/commands/scaffold.ts +346 -0
  35. package/src/commands/schema.ts +293 -0
  36. package/src/commands/snapshot.ts +130 -0
  37. package/src/commands/supersede.ts +400 -0
  38. package/src/commands/sync.ts +371 -0
  39. package/src/commands/tasks.ts +271 -0
  40. package/src/commands/traversal.ts +151 -0
  41. package/src/commands/validate.ts +226 -0
  42. package/src/config.ts +598 -0
  43. package/src/core/agent-bridge.ts +287 -0
  44. package/src/core/agent-context.ts +498 -0
  45. package/src/core/agent-profile.ts +447 -0
  46. package/src/core/bundle.ts +893 -0
  47. package/src/core/check.ts +853 -0
  48. package/src/core/codex-bridge.ts +100 -0
  49. package/src/core/concept.ts +597 -0
  50. package/src/core/consumer-scaffold.ts +433 -0
  51. package/src/core/context.ts +271 -0
  52. package/src/core/explorer-contract.ts +441 -0
  53. package/src/core/explorer-qualification.ts +58 -0
  54. package/src/core/explorer.ts +518 -0
  55. package/src/core/finding.ts +31 -0
  56. package/src/core/graph.ts +201 -0
  57. package/src/core/indexes.ts +436 -0
  58. package/src/core/instructions.ts +209 -0
  59. package/src/core/ladybug-driver.ts +1795 -0
  60. package/src/core/ladybug-lifecycle.ts +1178 -0
  61. package/src/core/ladybug-native.ts +95 -0
  62. package/src/core/ladybug-source.ts +667 -0
  63. package/src/core/links.ts +681 -0
  64. package/src/core/log.ts +253 -0
  65. package/src/core/managed-block.ts +540 -0
  66. package/src/core/manifest.ts +718 -0
  67. package/src/core/order.ts +13 -0
  68. package/src/core/profile.ts +1007 -0
  69. package/src/core/projection.ts +195 -0
  70. package/src/core/query.ts +542 -0
  71. package/src/core/reconcile.ts +236 -0
  72. package/src/core/replace.ts +419 -0
  73. package/src/core/retrieval.ts +213 -0
  74. package/src/core/rewrite.ts +940 -0
  75. package/src/core/scaffold.ts +255 -0
  76. package/src/core/schema.ts +366 -0
  77. package/src/core/snapshot-runtime.ts +52 -0
  78. package/src/core/snapshot-store.ts +287 -0
  79. package/src/core/snapshot.ts +711 -0
  80. package/src/core/template.ts +429 -0
  81. package/src/core/traversal.ts +487 -0
  82. package/src/core/validate.ts +517 -0
  83. package/src/core/workspace-contract.ts +473 -0
  84. package/src/core/workspace-projection.ts +365 -0
  85. package/src/core/workspace-retrieval.ts +196 -0
  86. package/src/core/workspace-source.ts +174 -0
  87. package/src/errors.ts +697 -0
  88. package/src/meta.ts +7 -0
  89. package/src/output.ts +589 -0
  90. package/src/scripts/upstream-backlog-watch.ts +288 -0
  91. package/src/state.ts +390 -0
@@ -0,0 +1,209 @@
1
+ /**
2
+ * core/instructions.ts — the static guidance `lore instructions` serves.
3
+ *
4
+ * `lore instructions [<topic>]` is the just-in-time channel described in
5
+ * docs/runbooks/agent-onboarding.md §2.3: instead of carrying lore's guidance
6
+ * resident in an agent's context, it prints exactly the topic needed for the
7
+ * current step of the canonical loop, mirroring the `backlog instructions
8
+ * <topic>` idiom this project itself uses.
9
+ *
10
+ * Every topic here is a condensed restatement of guidance that already lives
11
+ * elsewhere (the runbook, the ADRs, the CLI contract) — this module invents no
12
+ * new policy, it only makes existing policy pullable on demand. Content is
13
+ * static and root-independent: no bundle load, no config read, so the command
14
+ * layer needs no `root`.
15
+ */
16
+
17
+ /** One guidance topic `lore instructions` can print. */
18
+ export interface InstructionTopic {
19
+ /** The key passed as `lore instructions <key>` (`overview` is the no-arg default). */
20
+ readonly key: string;
21
+ /** A one-line description — the pretty-mode heading and the topic-index entry. */
22
+ readonly title: string;
23
+ /** The full guidance body: plain prose, no ANSI, no trailing newline. */
24
+ readonly body: string;
25
+ }
26
+
27
+ const LINKING: InstructionTopic = {
28
+ key: "linking",
29
+ title: "Story <-> Task coupling (`lore link` / `lore unlink`)",
30
+ body: `A Story concept's frontmatter \`tasks:\` list is the source of coupling to
31
+ Backlog.md -- those are the task ids the Story owns. Roll up their current live
32
+ status with \`lore tasks <conceptId>\` (pass the Story, not a task id -- the
33
+ read-only rollup \`lore sync\` writes into the managed block); to inspect one
34
+ task, use \`backlog task view <taskId> --plain\`. Never trust the Story's own
35
+ written \`status\`, which only refreshes when \`lore sync\` runs.
36
+
37
+ To couple a new task to a Story, create it in Backlog (\`backlog task create
38
+ ...\`) then run \`lore link <story> <taskId...>\` -- this updates both the
39
+ Story's frontmatter \`tasks:\` list and the task's \`doc:<conceptId>\`
40
+ back-reference label in one step, validating every given id exists first
41
+ and failing the whole command loud (not_found, exit 3) before writing
42
+ anything if one doesn't. \`lore unlink <story> <taskId...>\` removes the
43
+ coupling the same way, but is more forgiving: a task id no longer present
44
+ in Backlog is simply skipped (exit 0), not an error.
45
+
46
+ \`lore link\`/\`lore unlink\` edit \`backlog/tasks/*.md\` directly and commit
47
+ those edits themselves -- each calls \`commitBacklogFiles\`, scoped to
48
+ exactly the files it touched, right after writing them, so nothing is left
49
+ pending for \`lore sync\` on their account. \`lore sync\`'s own commit step
50
+ is now a catch-all sweep: it still commits anything left dirty under
51
+ \`backlog/\` from another source (a human's direct \`backlog task edit\`, or
52
+ a prior run's commit that failed). Never hand-edit or \`git add\` files
53
+ under \`backlog/tasks/\` yourself; whichever command touches them commits
54
+ them.
55
+
56
+ See ADR-0009 (Story <-> Task coupling & reconciliation) and ADR-0012
57
+ (Backlog coexistence & git ownership).`,
58
+ };
59
+
60
+ const SYNC: InstructionTopic = {
61
+ key: "sync",
62
+ title: "Reconciling status and managed blocks (`lore sync`)",
63
+ body: `\`lore sync [paths...]\` is the write step that makes the bundle coherent:
64
+ it recomputes each Story's \`status\` from its coupled tasks' live Backlog
65
+ state (ADR-0009's reconciliation rules), rewrites the
66
+ \`<!-- lore:tasks:begin -->\` ... \`<!-- lore:tasks:end -->\` managed blocks from
67
+ that live data, regenerates the bundle's index/log, and commits \`backlog/\`
68
+ if \`lore link\`/\`lore unlink\` left it dirty.
69
+
70
+ It is idempotent: run it again with no upstream change and it produces
71
+ byte-identical output -- a clean, empty diff. The \`--json\` payload is
72
+ \`kind: sync.result\` and reports exactly what changed (status rewrites,
73
+ managed-block diffs, regenerated files), plus \`orphanedIndexes\`:
74
+ repo-relative paths of on-disk \`index.md\` files whose directory no longer
75
+ holds any concept (e.g. after a manual \`rm\`/\`mv\` outside \`lore rename\`) --
76
+ reported so they're never silently unmentioned, but left untouched on disk,
77
+ not auto-written or removed.
78
+
79
+ Never hand-edit inside a managed block: the next \`lore sync\` silently
80
+ overwrites it, and \`lore replace\` silently skips any match inside one --
81
+ neither errors. (Malformed markers themselves -- missing, duplicated,
82
+ crossed, or a collapsed same-line begin/end pair -- are a \`validation\`
83
+ error, exit 6; that's a different failure than an ordinary hand-edit.)
84
+ Author prose only outside the markers.
85
+
86
+ Run \`lore sync\` after any task status change or after linking/unlinking a
87
+ task, before \`lore check\` -- check is read-only and will only tell you sync
88
+ is needed, not fix it for you.`,
89
+ };
90
+
91
+ const CHECK: InstructionTopic = {
92
+ key: "check",
93
+ title: "The CI gate: drift, links, anchors, portability (`lore check`)",
94
+ body: `\`lore check [paths...]\` is lore's read-only CI gate. It always emits the
95
+ full \`check.report\` on stdout (\`kind: check.report\` under \`--json\`) --
96
+ findings for broken internal links, rotted heading anchors, reconciliation
97
+ drift (a Story's written status or managed block gone stale), and, under
98
+ \`--strict\`, portability-lint warnings. It then *returns* exit 6 when any of
99
+ those is error-tier (or any warning exists under \`--strict\`) -- a plain
100
+ exit code, not a thrown error: nothing throws on this path, so there is no
101
+ \`--json\` error envelope for a failing report (the report itself, already on
102
+ stdout, is the payload). cli-contract.md's exit table labels this condition
103
+ \`drift\` for documentation purposes only, to distinguish it from
104
+ \`validation\` -- \`lore validate\`'s own error_type for a different command;
105
+ check has no error_type split of its own to branch on.
106
+
107
+ check's throws (each carries a \`--json\` error envelope) are \`usage\`
108
+ (exit 2, a bad flag, or a bundle-root path argument that exists but isn't a
109
+ directory), \`not_found\` (exit 3, a given bundle-root path that doesn't
110
+ exist, or, when a discovered concept links a Backlog task, that task's id no
111
+ longer existing), \`denied\` (exit 4, a bundle-root path that exists but
112
+ can't be read), and \`validation\` (exit 6; its causes include a malformed
113
+ status flow or override in the reconcile config, validated up front before
114
+ any task resolution; malformed frontmatter on a \`tasks:\`-linked concept,
115
+ caught per-file while scanning for reconciliation eligibility -- before any
116
+ task resolution runs, but not re-thrown until after the report has already
117
+ emitted; a resolved task whose live status is in neither the configured
118
+ status flow nor its \`[reconcile.overrides]\`, discovered only once that
119
+ task's own detail has already been resolved; and corrupted managed-block
120
+ markers, hit per-concept while regenerating that concept's
121
+ \`<!-- lore:tasks -->\` region during drift detection -- i.e. *after* that
122
+ concept's own tasks are already resolved). \`validation\`'s exit code
123
+ coincides with the drift-tier report's exit 6 above, but the two are
124
+ distinct: \`validation\` is a thrown error with a \`--json\` envelope; the
125
+ report's exit 6 is a plain returned code with no throw.
126
+
127
+ Because check writes nothing and lore's core has no LLM dependency, it is
128
+ deterministic: a clean \`lore check\` locally means a clean \`lore check\` in
129
+ CI, with no flakiness to chase. A typical loop: run check; exit 0 means
130
+ done; exit 6 means read the report and run \`lore sync\` for any drift
131
+ finding, then re-check; exit 3 means fix the path argument; an uncaught 1
132
+ needs investigation, not a blind sync.
133
+
134
+ Treat \`lore check\` exiting 0 as the actual definition of "done" for any
135
+ docs-touching change -- not typecheck or lint alone.`,
136
+ };
137
+
138
+ const VALIDATION: InstructionTopic = {
139
+ key: "validation",
140
+ title: "Per-file OKF/schema conformance (`lore validate`)",
141
+ body: `\`lore validate [paths...]\` is a tiered, per-file conformance reporter,
142
+ distinct from \`check\`'s cross-file drift/link/portability pass. It
143
+ validates: OKF §9 conformance (frontmatter parses, \`type\` is present and
144
+ non-empty) as an error if violated; per-type frontmatter shape and required
145
+ sections against a Zod schema generated from the declarative
146
+ \`.lore/profile.toml\` (the source of truth per ADR-0006's LORE-46 amendment)
147
+ as an error if violated for known types; an unknown \`type\` or extra
148
+ frontmatter keys as a warning only (OKF tolerates unknown fields -- custom
149
+ frontmatter passes through untouched); a stale \`resource:\` value that no
150
+ longer matches what the profile computes for the concept's current path as
151
+ a warning (rule "resource"); and frontmatter values that would serialize
152
+ ambiguously as quote-safety findings -- mostly errors (an unquoted YAML
153
+ indicator char, a YAML-1.1 boolean like bare \`no\`/\`yes\`, or a colon
154
+ followed by a space, which YAML would otherwise misread as a nested
155
+ mapping), with only a bare \`YYYY-MM-DD\` date downgraded to a warning. A
156
+ colon with no trailing space is not flagged -- a URL like \`https://...\`
157
+ or an ISO timestamp like \`2024-01-01T00:00:00\` is accepted even though
158
+ it contains a colon.
159
+
160
+ With no path arguments it walks the whole bundle; pass explicit \`[paths...]\`
161
+ to scope it (e.g. from a pre-commit hook checking only staged files).
162
+ \`--type <T>\` narrows the report to one concept type; \`--strict\` treats any
163
+ warning as a failure for the exit code.
164
+
165
+ It emits the full \`validate.report\` on stdout regardless of outcome, then
166
+ returns exit 6 when any error-tier finding exists (or any warning under
167
+ \`--strict\`) -- the report is the payload, the exit code is the gate signal.`,
168
+ };
169
+
170
+ /** The detailed, task-scoped topics (everything except `overview`). */
171
+ const DETAIL_TOPICS: readonly InstructionTopic[] = [LINKING, SYNC, CHECK, VALIDATION];
172
+
173
+ /** Render the `key title` topic-index lines shared by the overview body and (indirectly) its JSON `topics` field. */
174
+ function topicIndexLines(topics: readonly InstructionTopic[]): string {
175
+ const width = Math.max(...topics.map((topic) => topic.key.length));
176
+ return topics.map((topic) => ` ${topic.key.padEnd(width)} ${topic.title}`).join("\n");
177
+ }
178
+
179
+ const OVERVIEW: InstructionTopic = {
180
+ key: "overview",
181
+ title: "The canonical agent loop and topic index",
182
+ body: `lore's canonical agent loop: read docs/index.md (the bundle's entry point)
183
+ -> follow a Story concept -> check its coupled tasks' live status (see the
184
+ \`linking\` topic) -> do the work (author prose outside lore-managed regions)
185
+ -> \`lore sync\` to reconcile status and regenerate managed blocks -> \`lore
186
+ check\` as the CI gate (exit 6 on a failing report -- see the \`check\`
187
+ topic).
188
+
189
+ lore is CLI-first and deterministic: no LLM dependency, so the same inputs
190
+ against an unchanged bundle always produce the same output and exit code.
191
+ Every command supports \`--json\` (the \`{schemaVersion, kind, data}\`
192
+ envelope) and \`--plain\` (ANSI-free text, auto-selected when stdout isn't a
193
+ TTY); branch on the semantic exit code (0 ok, 2 usage, 3 not_found, 4 denied,
194
+ 5 conflict, 6 validation/drift) rather than parsing prose.
195
+
196
+ Topics:
197
+ ${topicIndexLines(DETAIL_TOPICS)}
198
+
199
+ Run \`lore instructions <topic>\` for detail on any of these. Full reference:
200
+ docs/runbooks/agent-onboarding.md.`,
201
+ };
202
+
203
+ /** Every topic `lore instructions` can serve, `overview` first — the order the topic index/JSON `topics` field lists them in. */
204
+ export const INSTRUCTION_TOPICS: readonly InstructionTopic[] = [OVERVIEW, ...DETAIL_TOPICS];
205
+
206
+ /** Look up a topic by its exact key (case-sensitive, no fuzzy match), or `undefined` if unknown. */
207
+ export function findInstructionTopic(key: string): InstructionTopic | undefined {
208
+ return INSTRUCTION_TOPICS.find((topic) => topic.key === key);
209
+ }