@leji-org/leji 1.0.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.
- package/README.md +36 -0
- package/assets-manifest.json +25 -0
- package/cli.json +82 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +4 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/conformance.d.ts +24 -0
- package/dist/commands/conformance.js +111 -0
- package/dist/commands/conformance.js.map +1 -0
- package/dist/commands/docs.d.ts +32 -0
- package/dist/commands/docs.js +196 -0
- package/dist/commands/docs.js.map +1 -0
- package/dist/commands/freshness.d.ts +21 -0
- package/dist/commands/freshness.js +41 -0
- package/dist/commands/freshness.js.map +1 -0
- package/dist/commands/indexgen.d.ts +55 -0
- package/dist/commands/indexgen.js +256 -0
- package/dist/commands/indexgen.js.map +1 -0
- package/dist/commands/init.d.ts +28 -0
- package/dist/commands/init.js +378 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/validate.d.ts +25 -0
- package/dist/commands/validate.js +359 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +324 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/findings.d.ts +17 -0
- package/dist/lib/findings.js +29 -0
- package/dist/lib/findings.js.map +1 -0
- package/dist/lib/frontmatter.d.ts +14 -0
- package/dist/lib/frontmatter.js +28 -0
- package/dist/lib/frontmatter.js.map +1 -0
- package/dist/lib/fsx.d.ts +21 -0
- package/dist/lib/fsx.js +100 -0
- package/dist/lib/fsx.js.map +1 -0
- package/dist/lib/git.d.ts +10 -0
- package/dist/lib/git.js +55 -0
- package/dist/lib/git.js.map +1 -0
- package/dist/lib/layer.d.ts +32 -0
- package/dist/lib/layer.js +138 -0
- package/dist/lib/layer.js.map +1 -0
- package/dist/lib/manifest.d.ts +62 -0
- package/dist/lib/manifest.js +54 -0
- package/dist/lib/manifest.js.map +1 -0
- package/dist/lib/schemas.d.ts +38 -0
- package/dist/lib/schemas.js +57 -0
- package/dist/lib/schemas.js.map +1 -0
- package/package.json +61 -0
- package/schemas/README.md +3 -0
- package/schemas/agent-profile.schema.json +129 -0
- package/schemas/context-changelog.schema.json +150 -0
- package/schemas/context-index.schema.json +137 -0
- package/schemas/context-manifest.schema.json +253 -0
- package/schemas/decision-record.schema.json +84 -0
- package/templates/README.md +5 -0
- package/templates/agent-profile.md +25 -0
- package/templates/agents/core.md +27 -0
- package/templates/boot-profile.md +39 -0
- package/templates/decision-record.md +28 -0
- package/templates/docs-viewer-assets/PROVENANCE.txt +18 -0
- package/templates/docs-viewer-assets/docsify-sidebar-collapse.min.css +24 -0
- package/templates/docs-viewer-assets/docsify-sidebar-collapse.min.js +149 -0
- package/templates/docs-viewer-assets/docsify.min.js +1 -0
- package/templates/docs-viewer-assets/search.min.js +314 -0
- package/templates/docs-viewer-assets/vue.css +1063 -0
- package/templates/docs-viewer.html +63 -0
- package/templates/leji.json +56 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
import { sortFindings, summarize } from './lib/findings.js';
|
|
2
|
+
import { loadManifest } from './lib/manifest.js';
|
|
3
|
+
import { SDK_VERSION, SUPPORTED_LINES, loadCliSpec } from './lib/schemas.js';
|
|
4
|
+
import { checkIndex, writeIndex } from './commands/indexgen.js';
|
|
5
|
+
import { checkChangelogAppendOnly, validateLayer } from './commands/validate.js';
|
|
6
|
+
import { conformanceReport } from './commands/conformance.js';
|
|
7
|
+
import { generateDocs, resolveDocsPort, serveDocs } from './commands/docs.js';
|
|
8
|
+
import { freshnessReport } from './commands/freshness.js';
|
|
9
|
+
import { enteringTheLayer, initLayer } from './commands/init.js';
|
|
10
|
+
export { validateLayer } from './commands/validate.js';
|
|
11
|
+
export { checkIndex, generateIndex, writeIndex } from './commands/indexgen.js';
|
|
12
|
+
export { checkChangelogAppendOnly } from './commands/validate.js';
|
|
13
|
+
export { conformanceReport } from './commands/conformance.js';
|
|
14
|
+
export { buildSidebar, generateDocs, resolveDocsPort, serveDocs } from './commands/docs.js';
|
|
15
|
+
export { freshnessReport } from './commands/freshness.js';
|
|
16
|
+
export { initLayer } from './commands/init.js';
|
|
17
|
+
export { loadManifest } from './lib/manifest.js';
|
|
18
|
+
export { SDK_VERSION, SUPPORTED_LINES } from './lib/schemas.js';
|
|
19
|
+
/** Terminal help, generated from cli.json so it cannot drift from the docs site. */
|
|
20
|
+
function buildUsage() {
|
|
21
|
+
const spec = loadCliSpec();
|
|
22
|
+
const out = [
|
|
23
|
+
`leji ${SDK_VERSION}: reference CLI for the Leji specification (spec line ${SUPPORTED_LINES.join(', ')})`,
|
|
24
|
+
'',
|
|
25
|
+
`Usage: ${spec.usage}`,
|
|
26
|
+
'',
|
|
27
|
+
'Commands:',
|
|
28
|
+
];
|
|
29
|
+
const cmdWidth = Math.max(...spec.commands.map((c) => c.name.length)) + 3;
|
|
30
|
+
for (const c of spec.commands)
|
|
31
|
+
out.push(` ${c.name.padEnd(cmdWidth)}${c.summary}`);
|
|
32
|
+
const cmdOptions = spec.commands.flatMap((c) => c.options.map((o) => ({ ...o, scope: c.name })));
|
|
33
|
+
const optWidth = Math.max(...spec.globalOptions.map((o) => o.flags.length), ...cmdOptions.map((o) => o.flags.length)) + 3;
|
|
34
|
+
out.push('', 'Options:');
|
|
35
|
+
for (const o of spec.globalOptions)
|
|
36
|
+
out.push(` ${o.flags.padEnd(optWidth)}${o.summary}`);
|
|
37
|
+
for (const o of cmdOptions)
|
|
38
|
+
out.push(` ${o.flags.padEnd(optWidth)}${o.scope}: ${o.summary}`);
|
|
39
|
+
out.push('', 'Full reference: https://leji.org/cli/');
|
|
40
|
+
return out.join('\n');
|
|
41
|
+
}
|
|
42
|
+
const USAGE = buildUsage();
|
|
43
|
+
function parseFlags(argv) {
|
|
44
|
+
const flags = {
|
|
45
|
+
root: '.',
|
|
46
|
+
json: false,
|
|
47
|
+
check: false,
|
|
48
|
+
strict: false,
|
|
49
|
+
yes: false,
|
|
50
|
+
serve: false,
|
|
51
|
+
dir: '.',
|
|
52
|
+
};
|
|
53
|
+
const rest = [];
|
|
54
|
+
for (let i = 0; i < argv.length; i++) {
|
|
55
|
+
const arg = argv[i];
|
|
56
|
+
switch (arg) {
|
|
57
|
+
case '--root':
|
|
58
|
+
flags.root = argv[++i] ?? '';
|
|
59
|
+
if (!flags.root)
|
|
60
|
+
return { flags, rest, error: '--root requires a value' };
|
|
61
|
+
break;
|
|
62
|
+
case '--dir':
|
|
63
|
+
flags.dir = argv[++i] ?? '';
|
|
64
|
+
if (!flags.dir)
|
|
65
|
+
return { flags, rest, error: '--dir requires a value' };
|
|
66
|
+
break;
|
|
67
|
+
case '--level': {
|
|
68
|
+
const v = argv[++i];
|
|
69
|
+
if (v !== 'core' && v !== 'indexed')
|
|
70
|
+
return { flags, rest, error: '--level must be core or indexed' };
|
|
71
|
+
flags.level = v;
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
case '--name':
|
|
75
|
+
flags.name = argv[++i];
|
|
76
|
+
if (!flags.name)
|
|
77
|
+
return { flags, rest, error: '--name requires a value' };
|
|
78
|
+
break;
|
|
79
|
+
case '--serve':
|
|
80
|
+
flags.serve = true;
|
|
81
|
+
break;
|
|
82
|
+
case '--port': {
|
|
83
|
+
const v = Number(argv[++i]);
|
|
84
|
+
if (!Number.isInteger(v) || v < 0 || v > 65535)
|
|
85
|
+
return { flags, rest, error: '--port must be 0-65535' };
|
|
86
|
+
flags.port = v;
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
case '--json':
|
|
90
|
+
flags.json = true;
|
|
91
|
+
break;
|
|
92
|
+
case '--check':
|
|
93
|
+
flags.check = true;
|
|
94
|
+
break;
|
|
95
|
+
case '--strict':
|
|
96
|
+
flags.strict = true;
|
|
97
|
+
break;
|
|
98
|
+
case '--yes':
|
|
99
|
+
case '-y':
|
|
100
|
+
flags.yes = true;
|
|
101
|
+
break;
|
|
102
|
+
default:
|
|
103
|
+
if (arg.startsWith('-') && arg !== '-h' && arg !== '--help' && arg !== '-V' && arg !== '--version') {
|
|
104
|
+
return { flags, rest, error: `unknown option ${arg}` };
|
|
105
|
+
}
|
|
106
|
+
rest.push(arg);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return { flags, rest };
|
|
110
|
+
}
|
|
111
|
+
// Per-command flag validation, driven by cli.json (the documented surface): each
|
|
112
|
+
// command accepts the global options plus its own declared options, and any other
|
|
113
|
+
// command flag is a usage error rather than being silently ignored. (Meta-flag
|
|
114
|
+
// `-h`/`-V` handling, short-circuited above, is a separate concern.)
|
|
115
|
+
const VALUE_FLAGS = new Set(['--root', '--dir', '--level', '--name', '--port']);
|
|
116
|
+
function flagTokens(flagsStr) {
|
|
117
|
+
// "--yes, -y" -> ["--yes","-y"]; "--port <n>" -> ["--port"].
|
|
118
|
+
return flagsStr
|
|
119
|
+
.split(',')
|
|
120
|
+
.map((s) => s.trim().split(/\s+/)[0])
|
|
121
|
+
.filter(Boolean);
|
|
122
|
+
}
|
|
123
|
+
function seenFlags(argv) {
|
|
124
|
+
const out = [];
|
|
125
|
+
for (let i = 0; i < argv.length; i++) {
|
|
126
|
+
const a = argv[i];
|
|
127
|
+
if (a.startsWith('-')) {
|
|
128
|
+
out.push(a);
|
|
129
|
+
if (VALUE_FLAGS.has(a))
|
|
130
|
+
i++; // skip the flag's value, not a flag itself
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return out;
|
|
134
|
+
}
|
|
135
|
+
function allowedFlagsFor(command, sub) {
|
|
136
|
+
const spec = loadCliSpec();
|
|
137
|
+
const name = command === 'changelog' ? `changelog ${sub ?? ''}`.trim() : command;
|
|
138
|
+
const cmd = spec.commands.find((c) => c.name === name);
|
|
139
|
+
if (!cmd)
|
|
140
|
+
return null; // unknown command: leave it to the dispatcher's default
|
|
141
|
+
const allowed = new Set();
|
|
142
|
+
for (const o of [...spec.globalOptions, ...cmd.options]) {
|
|
143
|
+
for (const t of flagTokens(o.flags))
|
|
144
|
+
allowed.add(t);
|
|
145
|
+
}
|
|
146
|
+
return allowed;
|
|
147
|
+
}
|
|
148
|
+
function printFindings(findings) {
|
|
149
|
+
for (const f of sortFindings(findings)) {
|
|
150
|
+
const where = f.path ? ` ${f.path}` : '';
|
|
151
|
+
console.log(`${f.severity === 'error' ? 'error ' : 'warning'} ${f.rule}${where}: ${f.message}`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
function emit(command, findings, json, extra = {}) {
|
|
155
|
+
const sorted = sortFindings(findings);
|
|
156
|
+
const summary = summarize(sorted);
|
|
157
|
+
const ok = summary.errors === 0;
|
|
158
|
+
if (json) {
|
|
159
|
+
console.log(JSON.stringify({ command, ok, findings: sorted, summary, ...extra }, null, 2));
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
printFindings(sorted);
|
|
163
|
+
const extras = Object.entries(extra)
|
|
164
|
+
.filter(([, v]) => typeof v === 'string' || typeof v === 'number')
|
|
165
|
+
.map(([k, v]) => `${k}: ${v}`)
|
|
166
|
+
.join(', ');
|
|
167
|
+
console.log(`${ok ? 'ok' : 'failed'} (${summary.errors} error${summary.errors === 1 ? '' : 's'}, ${summary.warnings} warning${summary.warnings === 1 ? '' : 's'}${extras ? `; ${extras}` : ''})`);
|
|
168
|
+
}
|
|
169
|
+
return ok ? 0 : 1;
|
|
170
|
+
}
|
|
171
|
+
/** Run the CLI; returns the process exit code. */
|
|
172
|
+
export async function run(argv) {
|
|
173
|
+
const { flags, rest, error } = parseFlags(argv);
|
|
174
|
+
if (error) {
|
|
175
|
+
console.error(`leji: ${error}\n`);
|
|
176
|
+
console.error(USAGE);
|
|
177
|
+
return 2;
|
|
178
|
+
}
|
|
179
|
+
const [command, sub] = rest;
|
|
180
|
+
if (!command || command === '-h' || command === '--help' || command === 'help') {
|
|
181
|
+
console.log(USAGE);
|
|
182
|
+
return command ? 0 : 2;
|
|
183
|
+
}
|
|
184
|
+
if (command === '-V' || command === '--version' || command === 'version') {
|
|
185
|
+
console.log(SDK_VERSION);
|
|
186
|
+
return 0;
|
|
187
|
+
}
|
|
188
|
+
// Reject any flag not declared for this command in cli.json (globals are allowed
|
|
189
|
+
// everywhere). Runs after the version/help short-circuit, so meta-commands still
|
|
190
|
+
// ignore flags; unknown commands fall through to the dispatcher's default.
|
|
191
|
+
const allowed = allowedFlagsFor(command, sub);
|
|
192
|
+
if (allowed) {
|
|
193
|
+
const bad = seenFlags(argv).find((t) => !allowed.has(t));
|
|
194
|
+
if (bad) {
|
|
195
|
+
const where = command === 'changelog' && sub ? `${command} ${sub}` : command;
|
|
196
|
+
console.error(`leji: ${bad} is not valid for "${where}"\n`);
|
|
197
|
+
console.error(USAGE);
|
|
198
|
+
return 2;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
try {
|
|
202
|
+
switch (command) {
|
|
203
|
+
case 'validate': {
|
|
204
|
+
const result = validateLayer(flags.root);
|
|
205
|
+
return emit('validate', result.findings, flags.json);
|
|
206
|
+
}
|
|
207
|
+
case 'index': {
|
|
208
|
+
const { manifest, findings } = loadManifest(flags.root);
|
|
209
|
+
if (!manifest)
|
|
210
|
+
return emit('index', findings, flags.json);
|
|
211
|
+
if (flags.check) {
|
|
212
|
+
const result = checkIndex(flags.root, manifest);
|
|
213
|
+
return emit('index --check', [...findings, ...result.findings], flags.json, {
|
|
214
|
+
stale: result.stale ?? true,
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
const result = writeIndex(flags.root, manifest);
|
|
218
|
+
return emit('index', [...findings, ...result.findings], flags.json, {
|
|
219
|
+
written: manifest.machine?.indexPath ?? '',
|
|
220
|
+
entries: result.index?.entries.length ?? 0,
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
case 'changelog': {
|
|
224
|
+
if (sub !== 'check') {
|
|
225
|
+
console.error('leji: usage: leji changelog check\n');
|
|
226
|
+
return 2;
|
|
227
|
+
}
|
|
228
|
+
const { manifest, findings } = loadManifest(flags.root);
|
|
229
|
+
if (!manifest)
|
|
230
|
+
return emit('changelog check', findings, flags.json);
|
|
231
|
+
const rel = manifest.machine?.changelogPath;
|
|
232
|
+
if (!rel) {
|
|
233
|
+
findings.push({
|
|
234
|
+
rule: 'changelog-required',
|
|
235
|
+
severity: 'error',
|
|
236
|
+
path: 'leji.json',
|
|
237
|
+
message: 'no machine.changelogPath declared in leji.json',
|
|
238
|
+
});
|
|
239
|
+
return emit('changelog check', findings, flags.json);
|
|
240
|
+
}
|
|
241
|
+
const result = checkChangelogAppendOnly(flags.root, rel, flags.strict);
|
|
242
|
+
return emit('changelog check', [...findings, ...result.findings], flags.json, {
|
|
243
|
+
verified: result.verified,
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
case 'freshness': {
|
|
247
|
+
const { manifest, findings } = loadManifest(flags.root);
|
|
248
|
+
if (!manifest)
|
|
249
|
+
return emit('freshness', findings, flags.json);
|
|
250
|
+
const report = freshnessReport(flags.root, manifest, flags.strict);
|
|
251
|
+
if (!flags.json) {
|
|
252
|
+
for (const item of report.upcoming) {
|
|
253
|
+
console.log(`upcoming ${item.path}: review after ${item.reviewAfter}`);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return emit('freshness', [...findings, ...report.findings], flags.json, {
|
|
257
|
+
declared: report.declared,
|
|
258
|
+
expired: flags.json ? report.expired : report.expired.length,
|
|
259
|
+
upcoming: flags.json ? report.upcoming : report.upcoming.length,
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
case 'conformance': {
|
|
263
|
+
const result = conformanceReport(flags.root);
|
|
264
|
+
if (!flags.json) {
|
|
265
|
+
for (const item of result.items) {
|
|
266
|
+
const mark = item.status === 'pass' ? 'pass ' : item.status === 'fail' ? 'FAIL ' : 'manual';
|
|
267
|
+
console.log(`${mark} [${item.level}] ${item.description}${item.detail ? ` — ${item.detail}` : ''}`);
|
|
268
|
+
}
|
|
269
|
+
console.log('');
|
|
270
|
+
}
|
|
271
|
+
return emit('conformance', result.findings, flags.json, {
|
|
272
|
+
claimedLevel: result.claimedLevel ?? 'none',
|
|
273
|
+
verifiedLevel: result.verifiedLevel ?? 'none',
|
|
274
|
+
...(flags.json ? { items: result.items } : {}),
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
case 'docs': {
|
|
278
|
+
const { manifest, findings } = loadManifest(flags.root);
|
|
279
|
+
if (!manifest)
|
|
280
|
+
return emit('docs', findings, flags.json);
|
|
281
|
+
const result = generateDocs(flags.root, manifest);
|
|
282
|
+
const code = emit('docs', [...findings, ...result.findings], flags.json, {
|
|
283
|
+
written: result.written.join(', '),
|
|
284
|
+
entries: result.entries,
|
|
285
|
+
});
|
|
286
|
+
if (!flags.serve || code !== 0) {
|
|
287
|
+
if (!flags.json && code === 0) {
|
|
288
|
+
console.log(`serve locally: leji docs --serve (or any static server at the repository root)`);
|
|
289
|
+
}
|
|
290
|
+
return code;
|
|
291
|
+
}
|
|
292
|
+
const server = await serveDocs(flags.root, resolveDocsPort(manifest, flags.port));
|
|
293
|
+
const address = server.address();
|
|
294
|
+
const port = typeof address === 'object' && address ? address.port : resolveDocsPort(manifest, flags.port);
|
|
295
|
+
console.log(`serving http://127.0.0.1:${port}/${manifest.rootPath}; Ctrl+C to stop`);
|
|
296
|
+
// Keep the process alive until the server closes (Ctrl+C).
|
|
297
|
+
await new Promise((resolve) => server.on('close', resolve));
|
|
298
|
+
return 0;
|
|
299
|
+
}
|
|
300
|
+
case 'init': {
|
|
301
|
+
const result = await initLayer({
|
|
302
|
+
dir: flags.dir === '.' && flags.root !== '.' ? flags.root : flags.dir,
|
|
303
|
+
yes: flags.yes,
|
|
304
|
+
name: flags.name,
|
|
305
|
+
level: flags.level,
|
|
306
|
+
});
|
|
307
|
+
console.log(`\nWrote ${result.written.length} files:`);
|
|
308
|
+
for (const rel of result.written)
|
|
309
|
+
console.log(` ${rel}`);
|
|
310
|
+
console.log(enteringTheLayer(result.manifest));
|
|
311
|
+
return 0;
|
|
312
|
+
}
|
|
313
|
+
default:
|
|
314
|
+
console.error(`leji: unknown command "${command}"\n`);
|
|
315
|
+
console.error(USAGE);
|
|
316
|
+
return 2;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
catch (e) {
|
|
320
|
+
console.error(`leji: ${e.message}`);
|
|
321
|
+
return 2;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type Severity = 'error' | 'warning';
|
|
2
|
+
export interface Finding {
|
|
3
|
+
/** Stable rule identifier, shared verbatim with the Python SDK. */
|
|
4
|
+
rule: string;
|
|
5
|
+
severity: Severity;
|
|
6
|
+
/** Repository-root-relative POSIX path the finding points at, when it has one. */
|
|
7
|
+
path?: string;
|
|
8
|
+
message: string;
|
|
9
|
+
}
|
|
10
|
+
export interface FindingSummary {
|
|
11
|
+
errors: number;
|
|
12
|
+
warnings: number;
|
|
13
|
+
}
|
|
14
|
+
export declare function finding(rule: string, severity: Severity, message: string, path?: string): Finding;
|
|
15
|
+
export declare function sortFindings(findings: Finding[]): Finding[];
|
|
16
|
+
export declare function summarize(findings: Finding[]): FindingSummary;
|
|
17
|
+
export declare function hasErrors(findings: Finding[]): boolean;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export function finding(rule, severity, message, path) {
|
|
2
|
+
return path === undefined ? { rule, severity, message } : { rule, severity, path, message };
|
|
3
|
+
}
|
|
4
|
+
export function sortFindings(findings) {
|
|
5
|
+
return [...findings].sort((a, b) => {
|
|
6
|
+
const pa = a.path ?? '';
|
|
7
|
+
const pb = b.path ?? '';
|
|
8
|
+
if (pa !== pb)
|
|
9
|
+
return pa < pb ? -1 : 1;
|
|
10
|
+
if (a.rule !== b.rule)
|
|
11
|
+
return a.rule < b.rule ? -1 : 1;
|
|
12
|
+
return a.message < b.message ? -1 : a.message > b.message ? 1 : 0;
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
export function summarize(findings) {
|
|
16
|
+
let errors = 0;
|
|
17
|
+
let warnings = 0;
|
|
18
|
+
for (const f of findings) {
|
|
19
|
+
if (f.severity === 'error')
|
|
20
|
+
errors++;
|
|
21
|
+
else
|
|
22
|
+
warnings++;
|
|
23
|
+
}
|
|
24
|
+
return { errors, warnings };
|
|
25
|
+
}
|
|
26
|
+
export function hasErrors(findings) {
|
|
27
|
+
return findings.some((f) => f.severity === 'error');
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=findings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"findings.js","sourceRoot":"","sources":["../../src/lib/findings.ts"],"names":[],"mappings":"AAgBA,MAAM,UAAU,OAAO,CAAC,IAAY,EAAE,QAAkB,EAAE,OAAe,EAAE,IAAa;IACrF,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAC/F,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,QAAmB;IAC7C,OAAO,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QAChC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;QACxB,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;QACxB,IAAI,EAAE,KAAK,EAAE;YAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACvC,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI;YAAE,OAAO,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACvD,OAAO,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;AACN,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,QAAmB;IAC1C,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACxB,IAAI,CAAC,CAAC,QAAQ,KAAK,OAAO;YAAE,MAAM,EAAE,CAAC;;YAChC,QAAQ,EAAE,CAAC;IACnB,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,QAAmB;IAC1C,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC;AACvD,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface Frontmatter {
|
|
2
|
+
/** Parsed YAML frontmatter object, or null when the document has none. */
|
|
3
|
+
data: Record<string, unknown> | null;
|
|
4
|
+
/** Document body after the frontmatter block (the whole file when none). */
|
|
5
|
+
body: string;
|
|
6
|
+
/** Parse error message when the frontmatter block exists but is invalid YAML. */
|
|
7
|
+
error?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Extract the leading YAML frontmatter block (`---` fences) from a markdown
|
|
11
|
+
* document. Dates and booleans follow YAML 1.2 core semantics (the `yaml`
|
|
12
|
+
* package default): unquoted dates stay strings, only true/false are booleans.
|
|
13
|
+
*/
|
|
14
|
+
export declare function parseFrontmatter(text: string): Frontmatter;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { parse } from 'yaml';
|
|
2
|
+
/**
|
|
3
|
+
* Extract the leading YAML frontmatter block (`---` fences) from a markdown
|
|
4
|
+
* document. Dates and booleans follow YAML 1.2 core semantics (the `yaml`
|
|
5
|
+
* package default): unquoted dates stay strings, only true/false are booleans.
|
|
6
|
+
*/
|
|
7
|
+
export function parseFrontmatter(text) {
|
|
8
|
+
if (!text.startsWith('---\n') && !text.startsWith('---\r\n')) {
|
|
9
|
+
return { data: null, body: text };
|
|
10
|
+
}
|
|
11
|
+
const fence = /\r?\n---[ \t]*\r?\n/.exec(text.slice(3));
|
|
12
|
+
if (!fence) {
|
|
13
|
+
return { data: null, body: text, error: 'unterminated frontmatter block' };
|
|
14
|
+
}
|
|
15
|
+
const raw = text.slice(3, 3 + fence.index + 1);
|
|
16
|
+
const body = text.slice(3 + fence.index + fence[0].length);
|
|
17
|
+
try {
|
|
18
|
+
const data = parse(raw);
|
|
19
|
+
if (data === null || typeof data !== 'object' || Array.isArray(data)) {
|
|
20
|
+
return { data: null, body, error: 'frontmatter is not a YAML mapping' };
|
|
21
|
+
}
|
|
22
|
+
return { data: data, body };
|
|
23
|
+
}
|
|
24
|
+
catch (e) {
|
|
25
|
+
return { data: null, body, error: `invalid YAML: ${e.message.split('\n')[0]}` };
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=frontmatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../../src/lib/frontmatter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAW7B;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC1C,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC5D,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACrC,CAAC;IACD,MAAM,KAAK,GAAG,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACxD,IAAI,CAAC,KAAK,EAAE,CAAC;QACV,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,gCAAgC,EAAE,CAAC;IAC9E,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;IAC/C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAC3D,IAAI,CAAC;QACF,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;QACxB,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACpE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,mCAAmC,EAAE,CAAC;QAC3E,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,IAA+B,EAAE,IAAI,EAAE,CAAC;IAC1D,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACV,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,iBAAkB,CAAW,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IAC9F,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare function toPosix(p: string): string;
|
|
2
|
+
export declare function exists(abs: string): boolean;
|
|
3
|
+
export declare function isDir(abs: string): boolean;
|
|
4
|
+
export declare function isFile(abs: string): boolean;
|
|
5
|
+
export declare function readText(abs: string): string;
|
|
6
|
+
/**
|
|
7
|
+
* True when `abs` resolves (following symlinks) to a path that remains within
|
|
8
|
+
* `rootAbs` (itself resolved). Symlinks that escape the served/scanned root are
|
|
9
|
+
* rejected. A path that does not yet exist cannot escape, so it is allowed.
|
|
10
|
+
*/
|
|
11
|
+
export declare function realpathWithin(rootAbs: string, abs: string): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Recursively collect markdown files under a declared path (file or directory),
|
|
14
|
+
* returned as repository-root-relative POSIX paths, sorted. Entries whose real
|
|
15
|
+
* path (after resolving symlinks) escapes `root` are excluded.
|
|
16
|
+
*/
|
|
17
|
+
export declare function walkMd(root: string, relPath: string): string[];
|
|
18
|
+
/** Normalize a declared directory path for prefix comparison: no trailing slash. */
|
|
19
|
+
export declare function stripSlash(p: string): string;
|
|
20
|
+
/** True when relPath is the declared path itself or falls under it (POSIX). */
|
|
21
|
+
export declare function underPath(relPath: string, declared: string): boolean;
|
package/dist/lib/fsx.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
export function toPosix(p) {
|
|
4
|
+
return p.split(path.sep).join('/');
|
|
5
|
+
}
|
|
6
|
+
export function exists(abs) {
|
|
7
|
+
return fs.existsSync(abs);
|
|
8
|
+
}
|
|
9
|
+
export function isDir(abs) {
|
|
10
|
+
try {
|
|
11
|
+
return fs.statSync(abs).isDirectory();
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export function isFile(abs) {
|
|
18
|
+
try {
|
|
19
|
+
return fs.statSync(abs).isFile();
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export function readText(abs) {
|
|
26
|
+
return fs.readFileSync(abs, 'utf8');
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* True when `abs` resolves (following symlinks) to a path that remains within
|
|
30
|
+
* `rootAbs` (itself resolved). Symlinks that escape the served/scanned root are
|
|
31
|
+
* rejected. A path that does not yet exist cannot escape, so it is allowed.
|
|
32
|
+
*/
|
|
33
|
+
export function realpathWithin(rootAbs, abs) {
|
|
34
|
+
let resolvedRoot;
|
|
35
|
+
try {
|
|
36
|
+
resolvedRoot = fs.realpathSync(rootAbs);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
let real;
|
|
42
|
+
try {
|
|
43
|
+
real = fs.realpathSync(abs);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
// Non-existent target: it cannot point outside via a symlink.
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
return real === resolvedRoot || real.startsWith(resolvedRoot + path.sep);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Recursively collect markdown files under a declared path (file or directory),
|
|
53
|
+
* returned as repository-root-relative POSIX paths, sorted. Entries whose real
|
|
54
|
+
* path (after resolving symlinks) escapes `root` are excluded.
|
|
55
|
+
*/
|
|
56
|
+
export function walkMd(root, relPath) {
|
|
57
|
+
const rootAbs = path.resolve(root);
|
|
58
|
+
const abs = path.join(root, relPath);
|
|
59
|
+
if (isFile(abs)) {
|
|
60
|
+
return relPath.endsWith('.md') && realpathWithin(rootAbs, abs) ? [toPosix(relPath)] : [];
|
|
61
|
+
}
|
|
62
|
+
if (!isDir(abs))
|
|
63
|
+
return [];
|
|
64
|
+
const out = [];
|
|
65
|
+
const stack = [abs];
|
|
66
|
+
while (stack.length > 0) {
|
|
67
|
+
const dir = stack.pop();
|
|
68
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
69
|
+
if (entry.name.startsWith('.'))
|
|
70
|
+
continue;
|
|
71
|
+
const full = path.join(dir, entry.name);
|
|
72
|
+
if (entry.isDirectory()) {
|
|
73
|
+
if (entry.name === 'node_modules')
|
|
74
|
+
continue;
|
|
75
|
+
if (!realpathWithin(rootAbs, full))
|
|
76
|
+
continue;
|
|
77
|
+
stack.push(full);
|
|
78
|
+
}
|
|
79
|
+
else if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
80
|
+
if (!realpathWithin(rootAbs, full))
|
|
81
|
+
continue;
|
|
82
|
+
out.push(toPosix(path.relative(root, full)));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return out.sort();
|
|
87
|
+
}
|
|
88
|
+
/** Normalize a declared directory path for prefix comparison: no trailing slash. */
|
|
89
|
+
export function stripSlash(p) {
|
|
90
|
+
return p.endsWith('/') ? p.slice(0, -1) : p;
|
|
91
|
+
}
|
|
92
|
+
/** True when relPath is the declared path itself or falls under it (POSIX). */
|
|
93
|
+
export function underPath(relPath, declared) {
|
|
94
|
+
const base = stripSlash(declared);
|
|
95
|
+
// An empty or "." root means the repository root: everything is under it.
|
|
96
|
+
if (base === '' || base === '.')
|
|
97
|
+
return true;
|
|
98
|
+
return relPath === base || relPath.startsWith(base + '/');
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=fsx.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fsx.js","sourceRoot":"","sources":["../../src/lib/fsx.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Absolute path of the git worktree containing root, or null when not in git. */
|
|
2
|
+
export declare function gitToplevel(root: string): string | null;
|
|
3
|
+
/**
|
|
4
|
+
* Last commit date (YYYY-MM-DD) of a file, or null when untracked, modified
|
|
5
|
+
* in the working tree, or outside a git repository. Callers fall back to a
|
|
6
|
+
* current date so that regeneration and the eventual commit stay consistent.
|
|
7
|
+
*/
|
|
8
|
+
export declare function gitLastModified(root: string, relPath: string): string | null;
|
|
9
|
+
/** Content of the file at HEAD, or null (new file, no git, or no HEAD yet). */
|
|
10
|
+
export declare function gitShowHead(root: string, relPath: string): string | null;
|
package/dist/lib/git.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
import { toPosix } from './fsx.js';
|
|
5
|
+
function git(root, args) {
|
|
6
|
+
try {
|
|
7
|
+
return execFileSync('git', ['-C', root, ...args], {
|
|
8
|
+
encoding: 'utf8',
|
|
9
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
10
|
+
timeout: 10_000,
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/** Absolute path of the git worktree containing root, or null when not in git. */
|
|
18
|
+
export function gitToplevel(root) {
|
|
19
|
+
const out = git(root, ['rev-parse', '--show-toplevel']);
|
|
20
|
+
return out ? out.trim() : null;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Last commit date (YYYY-MM-DD) of a file, or null when untracked, modified
|
|
24
|
+
* in the working tree, or outside a git repository. Callers fall back to a
|
|
25
|
+
* current date so that regeneration and the eventual commit stay consistent.
|
|
26
|
+
*/
|
|
27
|
+
export function gitLastModified(root, relPath) {
|
|
28
|
+
const status = git(root, ['status', '--porcelain', '--', relPath]);
|
|
29
|
+
if (status === null || status.trim() !== '')
|
|
30
|
+
return null;
|
|
31
|
+
const out = git(root, ['log', '-1', '--format=%cs', '--', relPath]);
|
|
32
|
+
const date = out?.trim();
|
|
33
|
+
return date ? date : null;
|
|
34
|
+
}
|
|
35
|
+
/** Content of the file at HEAD, or null (new file, no git, or no HEAD yet). */
|
|
36
|
+
export function gitShowHead(root, relPath) {
|
|
37
|
+
const top = gitToplevel(root);
|
|
38
|
+
if (!top)
|
|
39
|
+
return null;
|
|
40
|
+
// realpath both sides: on macOS /tmp is a symlink and git reports the
|
|
41
|
+
// resolved toplevel, which would break the relative-path computation.
|
|
42
|
+
let resolvedTop;
|
|
43
|
+
let resolvedFile;
|
|
44
|
+
try {
|
|
45
|
+
resolvedTop = fs.realpathSync(top);
|
|
46
|
+
resolvedFile = fs.realpathSync(path.join(root, relPath));
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
// The declared file was deleted (or top vanished): no HEAD baseline.
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
const fromTop = toPosix(path.relative(resolvedTop, resolvedFile));
|
|
53
|
+
return git(root, ['show', `HEAD:${fromTop}`]);
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=git.js.map
|