lat.md 0.7.0 → 0.7.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 +3 -2
- package/dist/src/cli/refs.js +1 -1
- package/dist/src/cli/search.js +2 -8
- package/dist/src/cli/section.js +9 -4
- package/dist/src/format.d.ts +1 -0
- package/dist/src/format.js +10 -1
- package/dist/src/lattice.d.ts +0 -1
- package/dist/src/lattice.js +2 -5
- package/dist/src/parser.js +2 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -33,7 +33,7 @@ After installing, run `lat init` in the repo you want to use lat in.
|
|
|
33
33
|
|
|
34
34
|
## How it works
|
|
35
35
|
|
|
36
|
-
Run `lat init` to scaffold a `lat.md/` directory, then write markdown files describing your architecture, business logic, test specs — whatever matters. Link between sections using `[[file#Section#Subsection]]` syntax. Annotate source code with `// @lat: [[section-id]]` (or `# @lat: [[section-id]]` in Python) comments to tie implementation back to concepts.
|
|
36
|
+
Run `lat init` to scaffold a `lat.md/` directory, then write markdown files describing your architecture, business logic, test specs — whatever matters. Link between sections using `[[file#Section#Subsection]]` syntax. Link to source code symbols with `[[src/auth.ts#validateToken]]`. Annotate source code with `// @lat: [[section-id]]` (or `# @lat: [[section-id]]` in Python) comments to tie implementation back to concepts.
|
|
37
37
|
|
|
38
38
|
```
|
|
39
39
|
my-project/
|
|
@@ -53,9 +53,10 @@ my-project/
|
|
|
53
53
|
npx lat.md init # scaffold a lat.md/ directory
|
|
54
54
|
npx lat.md check # validate all wiki links and code refs
|
|
55
55
|
npx lat.md locate "OAuth Flow" # find sections by name (exact, fuzzy)
|
|
56
|
+
npx lat.md section "auth#OAuth Flow" # show a section with its links and refs
|
|
56
57
|
npx lat.md refs "auth#OAuth Flow" # find what references a section
|
|
57
58
|
npx lat.md search "how do we auth?" # semantic search via embeddings
|
|
58
|
-
npx lat.md
|
|
59
|
+
npx lat.md expand "fix [[OAuth Flow]]" # expand [[refs]] in a prompt for agents
|
|
59
60
|
```
|
|
60
61
|
|
|
61
62
|
## Configuration
|
package/dist/src/cli/refs.js
CHANGED
|
@@ -97,7 +97,7 @@ export async function refsCommand(ctx, query, scope) {
|
|
|
97
97
|
parts.push(formatResultList(ctx, `References to "${target.id}":`, mdRefs));
|
|
98
98
|
}
|
|
99
99
|
if (codeRefs.length > 0) {
|
|
100
|
-
parts.push(
|
|
100
|
+
parts.push('## Code references:' +
|
|
101
101
|
'\n\n' +
|
|
102
102
|
codeRefs.map((l) => `${s.dim('*')} ${l}`).join('\n'));
|
|
103
103
|
}
|
package/dist/src/cli/search.js
CHANGED
|
@@ -3,7 +3,7 @@ import { detectProvider } from '../search/provider.js';
|
|
|
3
3
|
import { indexSections } from '../search/index.js';
|
|
4
4
|
import { searchSections } from '../search/search.js';
|
|
5
5
|
import { loadAllSections, flattenSections, } from '../lattice.js';
|
|
6
|
-
import { formatResultList } from '../format.js';
|
|
6
|
+
import { formatResultList, formatNavHints } from '../format.js';
|
|
7
7
|
async function withDb(latDir, key, progress, fn) {
|
|
8
8
|
const provider = detectProvider(key);
|
|
9
9
|
const db = openDb(latDir);
|
|
@@ -94,14 +94,8 @@ export async function searchCommand(ctx, query, opts, progress) {
|
|
|
94
94
|
if (result.matches.length === 0) {
|
|
95
95
|
return { output: 'No results found.' };
|
|
96
96
|
}
|
|
97
|
-
const navHints = ctx.mode === 'cli'
|
|
98
|
-
? '- `lat section "section#id"` \u2014 show full content with outgoing/incoming refs\n' +
|
|
99
|
-
'- `lat search "new query"` \u2014 search for something else'
|
|
100
|
-
: '- `lat_section` \u2014 show full content with outgoing/incoming refs\n' +
|
|
101
|
-
'- `lat_search` \u2014 search for something else';
|
|
102
97
|
return {
|
|
103
98
|
output: formatResultList(ctx, `Search results for "${query}":`, result.matches) +
|
|
104
|
-
|
|
105
|
-
navHints,
|
|
99
|
+
formatNavHints(ctx),
|
|
106
100
|
};
|
|
107
101
|
}
|
package/dist/src/cli/section.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
2
|
import { join, relative } from 'node:path';
|
|
3
3
|
import { loadAllSections, findSections, flattenSections, extractRefs, buildFileIndex, resolveRef, listLatticeFiles, } from '../lattice.js';
|
|
4
|
-
import { formatSectionId } from '../format.js';
|
|
4
|
+
import { formatSectionId, formatNavHints } from '../format.js';
|
|
5
5
|
/**
|
|
6
6
|
* Look up a section by id, return its content, outgoing wiki link targets,
|
|
7
7
|
* and incoming references from other sections.
|
|
@@ -84,13 +84,17 @@ export function formatSectionOutput(ctx, result) {
|
|
|
84
84
|
const { section, content, outgoingRefs, incomingRefs } = result;
|
|
85
85
|
const relPath = relative(process.cwd(), join(ctx.projectRoot, section.filePath));
|
|
86
86
|
const loc = `${s.cyan(relPath)}${s.dim(`:${section.startLine}-${section.endLine}`)}`;
|
|
87
|
+
const quoted = content
|
|
88
|
+
.split('\n')
|
|
89
|
+
.map((line) => (line ? `> ${line}` : '>'))
|
|
90
|
+
.join('\n');
|
|
87
91
|
const parts = [
|
|
88
92
|
`${s.bold('[[' + formatSectionId(section.id, s) + ']]')} (${loc})`,
|
|
89
93
|
'',
|
|
90
|
-
|
|
94
|
+
quoted,
|
|
91
95
|
];
|
|
92
96
|
if (outgoingRefs.length > 0) {
|
|
93
|
-
parts.push('',
|
|
97
|
+
parts.push('', '## This section references:', '');
|
|
94
98
|
for (const ref of outgoingRefs) {
|
|
95
99
|
const body = ref.resolved.firstParagraph
|
|
96
100
|
? ` ${s.dim('—')} ${truncate(ref.resolved.firstParagraph, 120)}`
|
|
@@ -99,7 +103,7 @@ export function formatSectionOutput(ctx, result) {
|
|
|
99
103
|
}
|
|
100
104
|
}
|
|
101
105
|
if (incomingRefs.length > 0) {
|
|
102
|
-
parts.push('',
|
|
106
|
+
parts.push('', '## Referenced by:', '');
|
|
103
107
|
for (const ref of incomingRefs) {
|
|
104
108
|
const body = ref.section.firstParagraph
|
|
105
109
|
? ` ${s.dim('—')} ${truncate(ref.section.firstParagraph, 120)}`
|
|
@@ -107,6 +111,7 @@ export function formatSectionOutput(ctx, result) {
|
|
|
107
111
|
parts.push(`${s.dim('*')} [[${formatSectionId(ref.section.id, s)}]]${body}`);
|
|
108
112
|
}
|
|
109
113
|
}
|
|
114
|
+
parts.push(formatNavHints(ctx));
|
|
110
115
|
return parts.join('\n');
|
|
111
116
|
}
|
|
112
117
|
export async function sectionCommand(ctx, query) {
|
package/dist/src/format.d.ts
CHANGED
|
@@ -5,3 +5,4 @@ export declare function formatSectionPreview(ctx: CmdContext, section: Section,
|
|
|
5
5
|
reason?: string;
|
|
6
6
|
}): string;
|
|
7
7
|
export declare function formatResultList(ctx: CmdContext, header: string, matches: SectionMatch[]): string;
|
|
8
|
+
export declare function formatNavHints(ctx: CmdContext): string;
|
package/dist/src/format.js
CHANGED
|
@@ -21,7 +21,7 @@ export function formatSectionPreview(ctx, section, opts) {
|
|
|
21
21
|
return lines.join('\n');
|
|
22
22
|
}
|
|
23
23
|
export function formatResultList(ctx, header, matches) {
|
|
24
|
-
const lines = ['',
|
|
24
|
+
const lines = ['', `## ${header}`, ''];
|
|
25
25
|
for (let i = 0; i < matches.length; i++) {
|
|
26
26
|
if (i > 0)
|
|
27
27
|
lines.push('');
|
|
@@ -32,3 +32,12 @@ export function formatResultList(ctx, header, matches) {
|
|
|
32
32
|
lines.push('');
|
|
33
33
|
return lines.join('\n');
|
|
34
34
|
}
|
|
35
|
+
export function formatNavHints(ctx) {
|
|
36
|
+
const s = ctx.styler;
|
|
37
|
+
const hints = ctx.mode === 'cli'
|
|
38
|
+
? `${s.dim('*')} \`lat section "section#id"\` \u2014 show full content with outgoing/incoming refs\n` +
|
|
39
|
+
`${s.dim('*')} \`lat search "new query"\` \u2014 search for something else`
|
|
40
|
+
: `${s.dim('*')} \`lat_section\` \u2014 show full content with outgoing/incoming refs\n` +
|
|
41
|
+
`${s.dim('*')} \`lat_search\` \u2014 search for something else`;
|
|
42
|
+
return `\n## To navigate further:\n\n${hints}`;
|
|
43
|
+
}
|
package/dist/src/lattice.d.ts
CHANGED
|
@@ -19,7 +19,6 @@ export type LatFrontmatter = {
|
|
|
19
19
|
requireCodeMention?: boolean;
|
|
20
20
|
};
|
|
21
21
|
export declare function parseFrontmatter(content: string): LatFrontmatter;
|
|
22
|
-
export declare function stripFrontmatter(content: string): string;
|
|
23
22
|
export declare function findLatticeDir(from?: string): string | null;
|
|
24
23
|
export declare function findProjectRoot(from?: string): string | null;
|
|
25
24
|
export declare function listLatticeFiles(latticeDir: string): Promise<string[]>;
|
package/dist/src/lattice.js
CHANGED
|
@@ -15,9 +15,6 @@ export function parseFrontmatter(content) {
|
|
|
15
15
|
}
|
|
16
16
|
return result;
|
|
17
17
|
}
|
|
18
|
-
export function stripFrontmatter(content) {
|
|
19
|
-
return content.replace(/^---\n[\s\S]*?\n---\n*/, '');
|
|
20
|
-
}
|
|
21
18
|
export function findLatticeDir(from) {
|
|
22
19
|
let dir = resolve(from ?? process.cwd());
|
|
23
20
|
while (true) {
|
|
@@ -69,7 +66,7 @@ function lastLine(content) {
|
|
|
69
66
|
return lines[lines.length - 1] === '' ? lines.length - 1 : lines.length;
|
|
70
67
|
}
|
|
71
68
|
export function parseSections(filePath, content, projectRoot) {
|
|
72
|
-
const tree = parse(
|
|
69
|
+
const tree = parse(content);
|
|
73
70
|
const file = projectRoot
|
|
74
71
|
? relative(projectRoot, filePath).replace(/\.md$/, '')
|
|
75
72
|
: basename(filePath, '.md');
|
|
@@ -522,7 +519,7 @@ export function findSections(sections, query) {
|
|
|
522
519
|
];
|
|
523
520
|
}
|
|
524
521
|
export function extractRefs(filePath, content, projectRoot) {
|
|
525
|
-
const tree = parse(
|
|
522
|
+
const tree = parse(content);
|
|
526
523
|
const file = projectRoot
|
|
527
524
|
? relative(projectRoot, filePath).replace(/\.md$/, '')
|
|
528
525
|
: basename(filePath, '.md');
|
package/dist/src/parser.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { unified } from 'unified';
|
|
2
2
|
import remarkParse from 'remark-parse';
|
|
3
3
|
import remarkStringify from 'remark-stringify';
|
|
4
|
+
import remarkFrontmatter from 'remark-frontmatter';
|
|
4
5
|
import { wikiLinkSyntax, wikiLinkFromMarkdown, wikiLinkToMarkdown, } from './extensions/wiki-link/index.js';
|
|
5
6
|
const processor = unified()
|
|
6
7
|
.use(remarkParse)
|
|
8
|
+
.use(remarkFrontmatter)
|
|
7
9
|
.use(remarkStringify)
|
|
8
10
|
.data('micromarkExtensions', [wikiLinkSyntax()])
|
|
9
11
|
.data('fromMarkdownExtensions', [wikiLinkFromMarkdown()])
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lat.md",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "A knowledge graph for your codebase, written in markdown",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "pnpm@10.30.2",
|
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
"commander": "^14.0.3",
|
|
56
56
|
"ignore-walk": "^8.0.0",
|
|
57
57
|
"mdast-util-to-markdown": "^2.1.0",
|
|
58
|
+
"remark-frontmatter": "^5.0.0",
|
|
58
59
|
"remark-parse": "^11.0.0",
|
|
59
60
|
"remark-stringify": "^11.0.0",
|
|
60
61
|
"unified": "^11.0.0",
|