@plebeiantech/lat.md 0.12.3-fork.4 → 0.12.3-fork.6

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 (64) hide show
  1. package/dist/src/cli/check-coverage.d.ts +2 -0
  2. package/dist/src/cli/check-coverage.js +71 -0
  3. package/dist/src/cli/check-mode.d.ts +6 -0
  4. package/dist/src/cli/check-mode.js +44 -2
  5. package/dist/src/cli/check.js +5 -1
  6. package/dist/src/cli/fork-instructions.d.ts +19 -0
  7. package/dist/src/cli/fork-instructions.js +183 -0
  8. package/dist/src/cli/fork-scaffold.d.ts +16 -0
  9. package/dist/src/cli/fork-scaffold.js +129 -0
  10. package/dist/src/cli/index.js +29 -4
  11. package/dist/src/cli/init.js +4 -0
  12. package/dist/src/cli/search.js +6 -4
  13. package/dist/src/cli/ui-build.d.ts +4 -0
  14. package/dist/src/cli/ui-build.js +13 -0
  15. package/dist/src/cli/ui.js +18 -2
  16. package/dist/src/code-refs.js +25 -4
  17. package/dist/src/fork/upstream-drift-cli.d.ts +1 -0
  18. package/dist/src/fork/upstream-drift-cli.js +2 -0
  19. package/dist/src/fork/upstream-drift.d.ts +26 -0
  20. package/dist/src/fork/upstream-drift.js +185 -0
  21. package/dist/src/fork/upstream-guard-cli.d.ts +1 -0
  22. package/dist/src/fork/upstream-guard-cli.js +2 -0
  23. package/dist/src/fork/upstream-guard.d.ts +72 -0
  24. package/dist/src/fork/upstream-guard.js +445 -0
  25. package/dist/src/init-version.d.ts +1 -1
  26. package/dist/src/init-version.js +1 -1
  27. package/dist/src/lattice.d.ts +2 -1
  28. package/dist/src/lattice.js +1 -0
  29. package/dist/src/search/search.d.ts +1 -0
  30. package/dist/src/search/search.js +15 -9
  31. package/dist/src/view/client/assets/index-VZwPPiFE.js +334 -0
  32. package/dist/src/view/client/assets/index-W8ktvNj9.css +1 -0
  33. package/dist/src/view/client/assets/logo-CNF8zs47.svg +182 -0
  34. package/dist/src/view/client/index.html +2 -2
  35. package/dist/src/view/git-diff.js +17 -0
  36. package/dist/src/view/graph.d.ts +6 -0
  37. package/dist/src/view/graph.js +176 -0
  38. package/dist/src/view/markdown.d.ts +5 -1
  39. package/dist/src/view/markdown.js +112 -25
  40. package/dist/src/view/protocol.d.ts +43 -0
  41. package/dist/src/view/protocol.js +1 -1
  42. package/dist/src/view/references.d.ts +2 -0
  43. package/dist/src/view/references.js +30 -8
  44. package/dist/src/view/repository.d.ts +5 -2
  45. package/dist/src/view/repository.js +13 -12
  46. package/dist/src/view/search.js +1 -0
  47. package/dist/src/view/server.d.ts +3 -0
  48. package/dist/src/view/server.js +42 -9
  49. package/dist/src/view/source-target.d.ts +8 -0
  50. package/dist/src/view/source-target.js +22 -0
  51. package/dist/src/view/static-build.d.ts +16 -0
  52. package/dist/src/view/static-build.js +408 -0
  53. package/dist/src/view/static-protocol.d.ts +23 -0
  54. package/dist/src/view/static-protocol.js +10 -0
  55. package/dist/src/view/store.d.ts +9 -1
  56. package/dist/src/view/store.js +82 -15
  57. package/dist/src/view/table-of-contents.d.ts +9 -0
  58. package/dist/src/view/table-of-contents.js +103 -0
  59. package/package.json +3 -1
  60. package/templates/AGENTS.md +2 -13
  61. package/templates/fork/conventions.md +95 -0
  62. package/templates/skill/SKILL.md +3 -14
  63. package/dist/src/view/client/assets/index-B0n0u03y.css +0 -1
  64. package/dist/src/view/client/assets/index-xm2_px4q.js +0 -23
@@ -0,0 +1,408 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { cp, lstat, mkdir, mkdtemp, readFile, rename, rm, writeFile, } from 'node:fs/promises';
3
+ import { dirname, join, parse, relative, resolve, sep } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { DEFAULT_VIEW_LOGO_TEXT } from './protocol.js';
6
+ import { viewStaticSourceKey, } from './static-protocol.js';
7
+ import { createViewStore } from './store.js';
8
+ const BUILD_MARKER = '.lat-ui-build';
9
+ const defaultClientDir = fileURLToPath(new URL('./client/', import.meta.url));
10
+ function isInside(parent, child) {
11
+ const rel = relative(parent, child);
12
+ return rel === '' || (rel !== '..' && !rel.startsWith(`..${sep}`));
13
+ }
14
+ export function normalizeStaticViewBasePath(value) {
15
+ const parsed = new URL(value || '/', 'http://lat.local');
16
+ if (parsed.origin !== 'http://lat.local' ||
17
+ parsed.search ||
18
+ parsed.hash ||
19
+ !value.startsWith('/')) {
20
+ throw new Error('Static UI base path must be an absolute URL path');
21
+ }
22
+ return parsed.pathname.endsWith('/')
23
+ ? parsed.pathname
24
+ : `${parsed.pathname}/`;
25
+ }
26
+ function staticViewPayloadDir(outputDir, basePath) {
27
+ const segments = basePath
28
+ .slice(1, -1)
29
+ .split('/')
30
+ .filter(Boolean)
31
+ .map((segment) => {
32
+ const decoded = decodeURIComponent(segment);
33
+ if (decoded === '.' ||
34
+ decoded === '..' ||
35
+ decoded.includes('/') ||
36
+ decoded.includes('\\')) {
37
+ throw new Error('Static UI base path contains an unsafe segment');
38
+ }
39
+ return decoded;
40
+ });
41
+ return join(outputDir, ...segments);
42
+ }
43
+ function decodeHtmlUrlAttribute(value) {
44
+ return value.replace(/&(amp|#38|#x26);/gi, '&');
45
+ }
46
+ /** Convert a live view route to its physical static-directory URL. */
47
+ export function staticViewUrl(value, basePath) {
48
+ if (!value || value.startsWith('#'))
49
+ return value;
50
+ let url;
51
+ try {
52
+ url = new URL(decodeHtmlUrlAttribute(value), 'http://lat.local');
53
+ }
54
+ catch {
55
+ return value;
56
+ }
57
+ if (url.origin !== 'http://lat.local')
58
+ return value;
59
+ for (const prefix of ['/docs/', '/code/']) {
60
+ if (!url.pathname.startsWith(prefix))
61
+ continue;
62
+ const route = url.pathname.slice(1).replace(/\/+$/, '');
63
+ return `${basePath}${route}/${url.search}${url.hash}`;
64
+ }
65
+ if (url.pathname === '/graph') {
66
+ return `${basePath}graph/${url.search}${url.hash}`;
67
+ }
68
+ return value;
69
+ }
70
+ function documentPathFromUrl(value) {
71
+ if (!value.pathname.startsWith('/docs/'))
72
+ return null;
73
+ try {
74
+ return value.pathname
75
+ .slice('/docs/'.length)
76
+ .split('/')
77
+ .map(decodeURIComponent)
78
+ .join('/');
79
+ }
80
+ catch {
81
+ return null;
82
+ }
83
+ }
84
+ function rewriteHtmlLink(value, basePath, sourcePath, documentPaths) {
85
+ const direct = staticViewUrl(value, basePath);
86
+ if (direct !== value || !sourcePath || value.startsWith('#'))
87
+ return direct;
88
+ let resolved;
89
+ try {
90
+ const currentPath = sourcePath.split('/').map(encodeURIComponent).join('/');
91
+ resolved = new URL(decodeHtmlUrlAttribute(value), `http://lat.local/docs/${currentPath}`);
92
+ }
93
+ catch {
94
+ return value;
95
+ }
96
+ const documentPath = documentPathFromUrl(resolved);
97
+ if (resolved.origin !== 'http://lat.local' ||
98
+ !documentPath ||
99
+ !documentPaths.has(documentPath)) {
100
+ return value;
101
+ }
102
+ return staticViewUrl(`${resolved.pathname}${resolved.search}${resolved.hash}`, basePath);
103
+ }
104
+ function rewriteHtmlLinks(html, basePath, sourcePath, documentPaths) {
105
+ return html.replace(/href="([^"]*)"/g, (attribute, value) => {
106
+ const rewritten = rewriteHtmlLink(value, basePath, sourcePath, documentPaths);
107
+ if (rewritten === value)
108
+ return attribute;
109
+ return `href="${rewritten.replaceAll('&', '&').replaceAll('"', '"')}"`;
110
+ });
111
+ }
112
+ function rewriteMarkdownReference(reference, basePath, sourcePath, documentPaths) {
113
+ return {
114
+ ...reference,
115
+ paragraphHtml: rewriteHtmlLinks(reference.paragraphHtml, basePath, sourcePath, documentPaths),
116
+ url: staticViewUrl(reference.url, basePath),
117
+ };
118
+ }
119
+ function rewriteBackReference(reference, basePath, sectionPaths, documentPaths) {
120
+ return reference.kind === 'markdown'
121
+ ? rewriteMarkdownReference(reference, basePath, sectionPaths.get(reference.sectionId.split('#', 1)[0]) ?? null, documentPaths)
122
+ : { ...reference, url: staticViewUrl(reference.url, basePath) };
123
+ }
124
+ function rewriteDocument(document, basePath, sectionPaths, documentPaths) {
125
+ return {
126
+ ...document,
127
+ html: rewriteHtmlLinks(document.html, basePath, document.path, documentPaths),
128
+ gitHtml: null,
129
+ backReferences: document.backReferences.map((section) => ({
130
+ ...section,
131
+ references: section.references.map((reference) => rewriteBackReference(reference, basePath, sectionPaths, documentPaths)),
132
+ })),
133
+ };
134
+ }
135
+ function rewriteSourceReference(reference, basePath, sectionPaths, documentPaths) {
136
+ const sectionPath = reference.sectionId.split('#', 1)[0];
137
+ return {
138
+ ...reference,
139
+ paragraphHtml: rewriteHtmlLinks(reference.paragraphHtml, basePath, sectionPaths.get(sectionPath) ?? null, documentPaths),
140
+ url: staticViewUrl(reference.url, basePath),
141
+ };
142
+ }
143
+ function rewriteSource(source, basePath, sectionPaths, documentPaths) {
144
+ return {
145
+ ...source,
146
+ context: source.context
147
+ ? rewriteSourceReference(source.context, basePath, sectionPaths, documentPaths)
148
+ : null,
149
+ otherReferences: source.otherReferences.map((reference) => rewriteSourceReference(reference, basePath, sectionPaths, documentPaths)),
150
+ };
151
+ }
152
+ function rewriteGraph(graph, basePath) {
153
+ return {
154
+ ...graph,
155
+ nodes: graph.nodes.map(({ gitStatus: _gitStatus, ...node }) => ({
156
+ ...node,
157
+ url: staticViewUrl(node.url, basePath),
158
+ })),
159
+ };
160
+ }
161
+ function positiveInteger(value) {
162
+ const parsed = Number(value);
163
+ return Number.isInteger(parsed) && parsed > 0 ? parsed : 0;
164
+ }
165
+ function sourceRequest(value) {
166
+ const url = new URL(decodeHtmlUrlAttribute(value), 'http://lat.local');
167
+ if (!url.pathname.startsWith('/code/'))
168
+ return null;
169
+ let path;
170
+ let symbol;
171
+ try {
172
+ path = url.pathname
173
+ .slice('/code/'.length)
174
+ .split('/')
175
+ .map(decodeURIComponent)
176
+ .join('/');
177
+ symbol = decodeURIComponent(url.hash.slice(1));
178
+ }
179
+ catch {
180
+ return null;
181
+ }
182
+ return {
183
+ path,
184
+ symbol,
185
+ from: url.searchParams.get('from') ?? '',
186
+ line: positiveInteger(url.searchParams.get('line')),
187
+ at: positiveInteger(url.searchParams.get('at')),
188
+ };
189
+ }
190
+ function sourceRequestsFromDocument(document, requests) {
191
+ const add = (value) => {
192
+ const request = sourceRequest(value);
193
+ if (request)
194
+ requests.set(viewStaticSourceKey(request), request);
195
+ };
196
+ for (const match of document.html.matchAll(/href="([^"]*)"/g))
197
+ add(match[1]);
198
+ for (const section of document.backReferences) {
199
+ for (const reference of section.references) {
200
+ add(reference.url);
201
+ if (reference.kind === 'markdown') {
202
+ for (const match of reference.paragraphHtml.matchAll(/href="([^"]*)"/g)) {
203
+ add(match[1]);
204
+ }
205
+ }
206
+ }
207
+ }
208
+ }
209
+ function sourceRequestsFromSource(source, requests) {
210
+ const references = [
211
+ ...(source.context ? [source.context] : []),
212
+ ...source.otherReferences,
213
+ ];
214
+ for (const reference of references) {
215
+ for (const match of reference.paragraphHtml.matchAll(/href="([^"]*)"/g)) {
216
+ const request = sourceRequest(match[1]);
217
+ if (request)
218
+ requests.set(viewStaticSourceKey(request), request);
219
+ }
220
+ }
221
+ }
222
+ function dataFile(kind, key) {
223
+ const digest = createHash('sha256').update(key).digest('hex').slice(0, 20);
224
+ return `data/${kind}/${digest}.json`;
225
+ }
226
+ async function writeJson(path, value) {
227
+ await mkdir(dirname(path), { recursive: true });
228
+ await writeFile(path, `${JSON.stringify(value)}\n`);
229
+ }
230
+ async function outputExists(path) {
231
+ try {
232
+ await lstat(path);
233
+ return true;
234
+ }
235
+ catch (error) {
236
+ if (error.code === 'ENOENT')
237
+ return false;
238
+ throw error;
239
+ }
240
+ }
241
+ async function validateOutput(outputDir, projectRoot) {
242
+ if (outputDir === parse(outputDir).root ||
243
+ outputDir === projectRoot ||
244
+ isInside(outputDir, projectRoot)) {
245
+ throw new Error('Static UI output must not contain the project root');
246
+ }
247
+ if (await outputExists(outputDir)) {
248
+ throw new Error(`Static UI output already exists: ${outputDir}`);
249
+ }
250
+ }
251
+ function sectionDocumentPaths(documents) {
252
+ const result = new Map();
253
+ for (const path of documents.keys()) {
254
+ result.set(`lat.md/${path.slice(0, -'.md'.length)}`, path);
255
+ }
256
+ return result;
257
+ }
258
+ function clientShell(html, basePath) {
259
+ const assets = html.replace(/(["'])\/assets\//g, (_match, quote) => `${quote}${basePath}assets/`);
260
+ const configValue = JSON.stringify({ basePath }).replaceAll('<', '\\u003c');
261
+ const config = `<script>globalThis.__LAT_STATIC_VIEW__=${configValue}</script>`;
262
+ return assets.includes('</head>')
263
+ ? assets.replace('</head>', ` ${config}\n </head>`)
264
+ : `${config}\n${assets}`;
265
+ }
266
+ function redirectShell(target) {
267
+ const escaped = target.replaceAll('&', '&amp;').replaceAll('"', '&quot;');
268
+ const scriptTarget = JSON.stringify(target).replaceAll('<', '\\u003c');
269
+ return `<!doctype html>
270
+ <html lang="en">
271
+ <head>
272
+ <meta charset="UTF-8" />
273
+ <meta http-equiv="refresh" content="0;url=${escaped}" />
274
+ <title>lat.md</title>
275
+ </head>
276
+ <body><script>window.location.replace(${scriptTarget} + window.location.hash)</script></body>
277
+ </html>
278
+ `;
279
+ }
280
+ async function writeRouteShell(outputDir, route, shell) {
281
+ const path = join(outputDir, ...route.split('/'), 'index.html');
282
+ await mkdir(dirname(path), { recursive: true });
283
+ await writeFile(path, shell);
284
+ }
285
+ /** Build a serverless snapshot of the current read-only Lat UI. */
286
+ export async function buildStaticView(ctx, requestedOutput, options = {}) {
287
+ const outputDir = resolve(ctx.projectRoot, requestedOutput);
288
+ const basePath = normalizeStaticViewBasePath(options.basePath ?? '/');
289
+ const clientDir = options.clientDir ?? defaultClientDir;
290
+ const logoText = options.logoText ?? DEFAULT_VIEW_LOGO_TEXT;
291
+ await validateOutput(outputDir, ctx.projectRoot);
292
+ await mkdir(dirname(outputDir), { recursive: true });
293
+ const stagingDir = await mkdtemp(join(dirname(outputDir), '.lat-ui-build-'));
294
+ const store = await createViewStore(ctx.latDir, ctx.projectRoot, {
295
+ codeExcludePaths: [outputDir],
296
+ git: false,
297
+ watch: false,
298
+ });
299
+ try {
300
+ const clientHtml = await readFile(join(clientDir, 'index.html'), 'utf8');
301
+ const payloadDir = staticViewPayloadDir(stagingDir, basePath);
302
+ await mkdir(payloadDir, { recursive: true });
303
+ await cp(clientDir, payloadDir, { recursive: true });
304
+ const shell = clientShell(clientHtml, basePath);
305
+ const index = { ...store.getIndex(), git: null, logoText };
306
+ const documents = new Map();
307
+ const sourceRequests = new Map();
308
+ for (const path of index.files) {
309
+ const document = await store.getDocument(path);
310
+ documents.set(path, document);
311
+ sourceRequestsFromDocument(document, sourceRequests);
312
+ }
313
+ const documentPaths = new Set(documents.keys());
314
+ const sectionPaths = sectionDocumentPaths(documents);
315
+ const graph = store.getGraph();
316
+ for (const node of graph.nodes) {
317
+ const request = sourceRequest(node.url);
318
+ if (request)
319
+ sourceRequests.set(viewStaticSourceKey(request), request);
320
+ }
321
+ const sources = new Map();
322
+ const pending = [...sourceRequests.keys()];
323
+ for (let index = 0; index < pending.length; index++) {
324
+ const key = pending[index];
325
+ if (sources.has(key))
326
+ continue;
327
+ const request = sourceRequests.get(key);
328
+ const origin = request.from && request.line > 0
329
+ ? { sectionId: request.from, line: request.line }
330
+ : undefined;
331
+ let source;
332
+ try {
333
+ source = await store.getSource(request.path, request.symbol, origin, request.at);
334
+ }
335
+ catch (error) {
336
+ const target = `${request.path}${request.symbol ? `#${request.symbol}` : ''}`;
337
+ throw new Error(`Could not export source ${target}: ${error.message}`);
338
+ }
339
+ sources.set(key, source);
340
+ const before = sourceRequests.size;
341
+ sourceRequestsFromSource(source, sourceRequests);
342
+ if (sourceRequests.size > before) {
343
+ for (const next of sourceRequests.keys()) {
344
+ if (!sources.has(next) && !pending.includes(next))
345
+ pending.push(next);
346
+ }
347
+ }
348
+ }
349
+ const manifest = {
350
+ version: 1,
351
+ index,
352
+ graph: 'data/graph.json',
353
+ documents: {},
354
+ sources: {},
355
+ };
356
+ await writeJson(join(payloadDir, manifest.graph), rewriteGraph(graph, basePath));
357
+ for (const [path, document] of documents) {
358
+ const dataPath = dataFile('documents', path);
359
+ manifest.documents[path] = dataPath;
360
+ await writeJson(join(payloadDir, dataPath), rewriteDocument(document, basePath, sectionPaths, documentPaths));
361
+ const route = `docs/${path}`;
362
+ await writeRouteShell(payloadDir, route, shell);
363
+ }
364
+ const sourceFiles = new Map();
365
+ for (const [key, source] of sources) {
366
+ const rewritten = rewriteSource(source, basePath, sectionPaths, documentPaths);
367
+ const { path, content, highlightedHtmlLines, ...view } = rewritten;
368
+ let fileDataPath = sourceFiles.get(path);
369
+ if (!fileDataPath) {
370
+ fileDataPath = dataFile('source-files', path);
371
+ sourceFiles.set(path, fileDataPath);
372
+ await writeJson(join(payloadDir, fileDataPath), {
373
+ path,
374
+ content,
375
+ highlightedHtmlLines,
376
+ });
377
+ }
378
+ const viewDataPath = dataFile('source-views', key);
379
+ manifest.sources[key] = { file: fileDataPath, view: viewDataPath };
380
+ await writeJson(join(payloadDir, viewDataPath), view);
381
+ }
382
+ for (const path of sourceFiles.keys()) {
383
+ const route = `code/${path}`;
384
+ await writeRouteShell(payloadDir, route, shell);
385
+ }
386
+ await writeRouteShell(payloadDir, 'graph', shell);
387
+ await writeJson(join(payloadDir, 'data/manifest.json'), manifest);
388
+ const entryRedirect = redirectShell(staticViewUrl(`/docs/${index.entry}`, basePath));
389
+ await writeFile(join(payloadDir, 'index.html'), entryRedirect);
390
+ if (payloadDir !== stagingDir) {
391
+ await writeFile(join(stagingDir, 'index.html'), entryRedirect);
392
+ }
393
+ await writeFile(join(stagingDir, BUILD_MARKER), `${JSON.stringify({ version: 1 })}\n`);
394
+ await rename(stagingDir, outputDir);
395
+ return {
396
+ documents: documents.size,
397
+ outputDir,
398
+ sources: sources.size,
399
+ };
400
+ }
401
+ catch (error) {
402
+ await rm(stagingDir, { recursive: true, force: true });
403
+ throw error;
404
+ }
405
+ finally {
406
+ await store.close();
407
+ }
408
+ }
@@ -0,0 +1,23 @@
1
+ import type { ViewIndex, ViewSourceDocument } from './protocol.js';
2
+ export type ViewStaticSourceRequest = {
3
+ path: string;
4
+ symbol: string;
5
+ from: string;
6
+ line: number;
7
+ at: number;
8
+ };
9
+ export type ViewStaticSourceFile = Pick<ViewSourceDocument, 'path' | 'content' | 'highlightedHtmlLines'>;
10
+ export type ViewStaticSourceView = Omit<ViewSourceDocument, keyof ViewStaticSourceFile>;
11
+ export type ViewStaticSourceEntry = {
12
+ file: string;
13
+ view: string;
14
+ };
15
+ export type ViewStaticManifest = {
16
+ version: 1;
17
+ index: ViewIndex;
18
+ graph: string;
19
+ documents: Record<string, string>;
20
+ sources: Record<string, ViewStaticSourceEntry>;
21
+ };
22
+ /** Stable lookup key shared by the static exporter and browser adapter. */
23
+ export declare function viewStaticSourceKey(request: ViewStaticSourceRequest): string;
@@ -0,0 +1,10 @@
1
+ /** Stable lookup key shared by the static exporter and browser adapter. */
2
+ export function viewStaticSourceKey(request) {
3
+ return JSON.stringify([
4
+ request.path,
5
+ request.symbol,
6
+ request.from,
7
+ request.line,
8
+ request.at,
9
+ ]);
10
+ }
@@ -1,6 +1,6 @@
1
1
  import { type Section } from '../lattice.js';
2
2
  import { type ViewGitRepository, type ViewGitSnapshot } from './git.js';
3
- import type { ViewDocument, ViewDocumentError, ViewIndex, ViewProjectChange, ViewSourceDocument } from './protocol.js';
3
+ import type { ViewDocument, ViewDocumentError, ViewGraph, ViewIndex, ViewProjectChange, ViewSourceDocument } from './protocol.js';
4
4
  import { type ViewCodeReferenceFile, type ViewParsedMarkdownFile, type ViewReferenceIndex } from './references.js';
5
5
  export type ViewProjectSnapshot = {
6
6
  generation: number;
@@ -8,13 +8,16 @@ export type ViewProjectSnapshot = {
8
8
  files: ReadonlyMap<string, ViewParsedMarkdownFile>;
9
9
  allSections: Section[];
10
10
  references: ViewReferenceIndex;
11
+ graph: ViewGraph;
11
12
  diagnostics: ReadonlyMap<string, readonly ViewDocumentError[]>;
12
13
  git: ViewGitSnapshot;
13
14
  index: ViewIndex;
14
15
  };
15
16
  export type ViewStoreOptions = {
17
+ codeExcludePaths?: string[];
16
18
  debounceMs?: number;
17
19
  git?: boolean;
20
+ gitPollMs?: number;
18
21
  watch?: boolean;
19
22
  };
20
23
  type ViewStoreListener = (change: ViewProjectChange) => void;
@@ -33,6 +36,8 @@ export declare class ViewStore {
33
36
  private watcher;
34
37
  private pendingPaths;
35
38
  private debounceTimer;
39
+ private gitPollTimer;
40
+ private gitPollQueued;
36
41
  private refreshTail;
37
42
  private closed;
38
43
  constructor(latDir: string, projectRoot: string, realLatDir: string, snapshot: ViewProjectSnapshot, codeFiles: Map<string, ViewCodeReferenceFile>, codeScope: Set<string>, gitRepository: ViewGitRepository | null, options: ViewStoreOptions);
@@ -41,14 +46,17 @@ export declare class ViewStore {
41
46
  startWatching(): void;
42
47
  subscribe(listener: ViewStoreListener): () => void;
43
48
  getIndex(): ViewIndex;
49
+ getGraph(): ViewGraph;
44
50
  getDocument(requestedPath: string): Promise<ViewDocument>;
45
51
  getSource(requestedPath: string, requestedSymbol?: string, origin?: {
46
52
  sectionId: string;
47
53
  line: number;
48
54
  }, requestedLine?: number): Promise<ViewSourceDocument>;
49
55
  refresh(paths: string[]): Promise<void>;
56
+ private queueRefresh;
50
57
  close(): Promise<void>;
51
58
  private scheduleRefresh;
59
+ private startGitPolling;
52
60
  private readMarkdownFile;
53
61
  private applyRefresh;
54
62
  }