@vortex-os/base 0.0.1 → 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.
- package/README.md +50 -36
- package/dist/index.d.ts +1526 -23
- package/dist/index.js +3279 -20
- package/dist/index.js.map +1 -1
- package/package.json +16 -9
- package/dist/index.d.ts.map +0 -1
- package/src/index.ts +0 -33
package/dist/index.js
CHANGED
|
@@ -1,22 +1,3281 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __export = (target, all) => {
|
|
3
|
+
for (var name in all)
|
|
4
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
// ../core/dist/index.js
|
|
8
|
+
var dist_exports = {};
|
|
9
|
+
__export(dist_exports, {
|
|
10
|
+
Privacy: () => Privacy,
|
|
11
|
+
isVisibleAt: () => isVisibleAt,
|
|
12
|
+
makeContext: () => makeContext,
|
|
13
|
+
maxPrivacy: () => maxPrivacy,
|
|
14
|
+
moduleDir: () => moduleDir,
|
|
15
|
+
normalizePrivacy: () => normalizePrivacy,
|
|
16
|
+
parseFrontmatter: () => parseFrontmatter,
|
|
17
|
+
serializeFrontmatter: () => serializeFrontmatter
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// ../core/dist/types.js
|
|
21
|
+
var Privacy = {
|
|
22
|
+
Public: "public",
|
|
23
|
+
Internal: "internal",
|
|
24
|
+
Personal: "personal"
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// ../core/dist/frontmatter.js
|
|
28
|
+
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
29
|
+
var FENCE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
|
|
30
|
+
var BOM = "\uFEFF";
|
|
31
|
+
function parseFrontmatter(source) {
|
|
32
|
+
const cleaned = source.startsWith(BOM) ? source.slice(1) : source;
|
|
33
|
+
const match = cleaned.match(FENCE);
|
|
34
|
+
if (!match) {
|
|
35
|
+
return {
|
|
36
|
+
frontmatter: {},
|
|
37
|
+
body: cleaned
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const yaml = match[1] ?? "";
|
|
41
|
+
const body = cleaned.slice(match[0].length);
|
|
42
|
+
let parsed;
|
|
43
|
+
try {
|
|
44
|
+
parsed = parseYaml(yaml) ?? {};
|
|
45
|
+
} catch {
|
|
46
|
+
parsed = {};
|
|
47
|
+
}
|
|
48
|
+
return { frontmatter: parsed, body };
|
|
49
|
+
}
|
|
50
|
+
function serializeFrontmatter(doc) {
|
|
51
|
+
const keys = Object.keys(doc.frontmatter ?? {});
|
|
52
|
+
if (keys.length === 0)
|
|
53
|
+
return doc.body;
|
|
54
|
+
const yaml = stringifyYaml(doc.frontmatter).trimEnd();
|
|
55
|
+
return `---
|
|
56
|
+
${yaml}
|
|
57
|
+
---
|
|
58
|
+
${doc.body}`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ../core/dist/privacy.js
|
|
62
|
+
var ORDER = {
|
|
63
|
+
public: 0,
|
|
64
|
+
internal: 1,
|
|
65
|
+
personal: 2
|
|
66
|
+
};
|
|
67
|
+
function isVisibleAt(docPrivacy, viewerPrivacy) {
|
|
68
|
+
return ORDER[docPrivacy] <= ORDER[viewerPrivacy];
|
|
69
|
+
}
|
|
70
|
+
function maxPrivacy(a, b2) {
|
|
71
|
+
return ORDER[a] >= ORDER[b2] ? a : b2;
|
|
72
|
+
}
|
|
73
|
+
function normalizePrivacy(value, fallback = "internal") {
|
|
74
|
+
if (value === "public" || value === "internal" || value === "personal") {
|
|
75
|
+
return value;
|
|
76
|
+
}
|
|
77
|
+
return fallback;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ../core/dist/paths.js
|
|
81
|
+
import { resolve, join } from "path";
|
|
82
|
+
function makeContext(repoRoot) {
|
|
83
|
+
const root = resolve(repoRoot);
|
|
84
|
+
return {
|
|
85
|
+
repoRoot: root,
|
|
86
|
+
agentDir: join(root, ".agent"),
|
|
87
|
+
dataDir: join(root, "data"),
|
|
88
|
+
modulesDir: join(root, "modules"),
|
|
89
|
+
pluginsDir: join(root, "plugins")
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function moduleDir(ctx, moduleName) {
|
|
93
|
+
return join(ctx.modulesDir, moduleName);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ../modules/slash-commands/dist/index.js
|
|
97
|
+
var dist_exports2 = {};
|
|
98
|
+
__export(dist_exports2, {
|
|
99
|
+
CommandNotFoundError: () => CommandNotFoundError,
|
|
100
|
+
CommandRegistry: () => CommandRegistry,
|
|
101
|
+
runSlash: () => runSlash
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// ../modules/slash-commands/dist/registry.js
|
|
105
|
+
var CommandRegistry = class {
|
|
106
|
+
commands = /* @__PURE__ */ new Map();
|
|
107
|
+
register(command) {
|
|
108
|
+
if (this.commands.has(command.name)) {
|
|
109
|
+
throw new Error(`Command "${command.name}" is already registered`);
|
|
110
|
+
}
|
|
111
|
+
this.commands.set(command.name, command);
|
|
112
|
+
}
|
|
113
|
+
unregister(name) {
|
|
114
|
+
return this.commands.delete(name);
|
|
115
|
+
}
|
|
116
|
+
has(name) {
|
|
117
|
+
return this.commands.has(name);
|
|
118
|
+
}
|
|
119
|
+
get(name) {
|
|
120
|
+
return this.commands.get(name);
|
|
121
|
+
}
|
|
122
|
+
list() {
|
|
123
|
+
return Array.from(this.commands.values());
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
// ../modules/slash-commands/dist/runner.js
|
|
128
|
+
var CommandNotFoundError = class extends Error {
|
|
129
|
+
commandName;
|
|
130
|
+
constructor(commandName) {
|
|
131
|
+
super(`Unknown command: ${commandName}`);
|
|
132
|
+
this.name = "CommandNotFoundError";
|
|
133
|
+
this.commandName = commandName;
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
async function runSlash(input, { registry, context }) {
|
|
137
|
+
const trimmed = input.trim().replace(/^\//, "");
|
|
138
|
+
if (trimmed.length === 0) {
|
|
139
|
+
throw new Error("Empty command input");
|
|
140
|
+
}
|
|
141
|
+
const tokens = trimmed.split(/\s+/);
|
|
142
|
+
const name = tokens[0] ?? "";
|
|
143
|
+
const tail = tokens.slice(1);
|
|
144
|
+
const command = registry.get(name);
|
|
145
|
+
if (!command) {
|
|
146
|
+
throw new CommandNotFoundError(name);
|
|
147
|
+
}
|
|
148
|
+
const args = parseArgs(tail, command.args);
|
|
149
|
+
const rest = tail.join(" ");
|
|
150
|
+
const ci = {
|
|
151
|
+
raw: trimmed,
|
|
152
|
+
args,
|
|
153
|
+
rest,
|
|
154
|
+
context
|
|
155
|
+
};
|
|
156
|
+
return command.handler(ci);
|
|
157
|
+
}
|
|
158
|
+
function parseArgs(tokens, schema) {
|
|
159
|
+
const out = {};
|
|
160
|
+
if (!schema)
|
|
161
|
+
return out;
|
|
162
|
+
for (let i = 0; i < schema.length; i += 1) {
|
|
163
|
+
const arg = schema[i];
|
|
164
|
+
const value = tokens[i];
|
|
165
|
+
if (arg && value !== void 0) {
|
|
166
|
+
out[arg.name] = value;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return out;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// ../modules/memory-system/dist/index.js
|
|
173
|
+
var dist_exports3 = {};
|
|
174
|
+
__export(dist_exports3, {
|
|
175
|
+
MemoryStore: () => MemoryStore,
|
|
176
|
+
MemoryType: () => MemoryType,
|
|
177
|
+
diffStores: () => diffStores,
|
|
178
|
+
writeMemoryIndex: () => writeMemoryIndex
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
// ../modules/memory-system/dist/types.js
|
|
182
|
+
var MemoryType = {
|
|
183
|
+
User: "user",
|
|
184
|
+
Feedback: "feedback",
|
|
185
|
+
Project: "project",
|
|
186
|
+
Reference: "reference"
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
// ../modules/memory-system/dist/store.js
|
|
190
|
+
import { readdir, readFile, writeFile, mkdir, unlink, stat } from "fs/promises";
|
|
191
|
+
import { join as join2, basename, extname } from "path";
|
|
192
|
+
var MemoryStore = class {
|
|
193
|
+
dir;
|
|
194
|
+
constructor(dir) {
|
|
195
|
+
this.dir = dir;
|
|
196
|
+
}
|
|
197
|
+
/** Ensure the backing directory exists. Safe to call repeatedly. */
|
|
198
|
+
async ensure() {
|
|
199
|
+
await mkdir(this.dir, { recursive: true });
|
|
200
|
+
}
|
|
201
|
+
/** List memory ids (filename stems), sorted lexicographically. */
|
|
202
|
+
async list() {
|
|
203
|
+
try {
|
|
204
|
+
const entries = await readdir(this.dir);
|
|
205
|
+
return entries.filter((e) => e.endsWith(".md") && e !== "MEMORY.md" && e !== "_INDEX.md").map((e) => basename(e, extname(e))).sort();
|
|
206
|
+
} catch (e) {
|
|
207
|
+
if (e.code === "ENOENT")
|
|
208
|
+
return [];
|
|
209
|
+
throw e;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
/** Read a memory by id. Throws if the file does not exist. */
|
|
213
|
+
async read(id) {
|
|
214
|
+
const raw = await readFile(this.pathFor(id), "utf8");
|
|
215
|
+
const { frontmatter, body } = parseFrontmatter(raw);
|
|
216
|
+
return { id, frontmatter, body };
|
|
217
|
+
}
|
|
218
|
+
/** Write (or overwrite) a memory. Ensures the directory exists first. */
|
|
219
|
+
async write(memory) {
|
|
220
|
+
await this.ensure();
|
|
221
|
+
const source = serializeFrontmatter({
|
|
222
|
+
frontmatter: memory.frontmatter,
|
|
223
|
+
body: memory.body
|
|
224
|
+
});
|
|
225
|
+
await writeFile(this.pathFor(memory.id), source, "utf8");
|
|
226
|
+
}
|
|
227
|
+
/** Delete a memory. Returns false if it did not exist. */
|
|
228
|
+
async delete(id) {
|
|
229
|
+
try {
|
|
230
|
+
await unlink(this.pathFor(id));
|
|
231
|
+
return true;
|
|
232
|
+
} catch (e) {
|
|
233
|
+
if (e.code === "ENOENT")
|
|
234
|
+
return false;
|
|
235
|
+
throw e;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
/** Test whether a memory exists by id. */
|
|
239
|
+
async has(id) {
|
|
240
|
+
try {
|
|
241
|
+
await stat(this.pathFor(id));
|
|
242
|
+
return true;
|
|
243
|
+
} catch {
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
/** Absolute path of a memory file (file may not exist). */
|
|
248
|
+
pathFor(id) {
|
|
249
|
+
return join2(this.dir, `${id}.md`);
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
// ../modules/memory-system/dist/memory-index.js
|
|
254
|
+
import { writeFile as writeFile2 } from "fs/promises";
|
|
255
|
+
import { join as join3 } from "path";
|
|
256
|
+
async function writeMemoryIndex(store, options = {}) {
|
|
257
|
+
const ids = await store.list();
|
|
258
|
+
const lines = [];
|
|
259
|
+
if (options.preamble) {
|
|
260
|
+
lines.push(options.preamble, "");
|
|
261
|
+
}
|
|
262
|
+
lines.push(`# ${options.title ?? "Memory Index"}`, "");
|
|
263
|
+
for (const id of ids) {
|
|
264
|
+
const memory = await store.read(id);
|
|
265
|
+
lines.push(`- [${memory.frontmatter.name}](${id}.md) \u2014 ${memory.frontmatter.description}`);
|
|
266
|
+
}
|
|
267
|
+
await writeFile2(join3(store.dir, "MEMORY.md"), `${lines.join("\n")}
|
|
268
|
+
`, "utf8");
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// ../modules/memory-system/dist/sync.js
|
|
272
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
273
|
+
async function diffStores(a, b2) {
|
|
274
|
+
const [idsA, idsB] = await Promise.all([a.list(), b2.list()]);
|
|
275
|
+
const setA = new Set(idsA);
|
|
276
|
+
const setB = new Set(idsB);
|
|
277
|
+
const onlyInA = idsA.filter((id) => !setB.has(id));
|
|
278
|
+
const onlyInB = idsB.filter((id) => !setA.has(id));
|
|
279
|
+
const both = idsA.filter((id) => setB.has(id));
|
|
280
|
+
const changed = [];
|
|
281
|
+
for (const id of both) {
|
|
282
|
+
const [contentA, contentB] = await Promise.all([
|
|
283
|
+
readFile2(a.pathFor(id), "utf8"),
|
|
284
|
+
readFile2(b2.pathFor(id), "utf8")
|
|
285
|
+
]);
|
|
286
|
+
if (contentA !== contentB) {
|
|
287
|
+
changed.push(id);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
return { onlyInA, onlyInB, changed };
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// ../modules/data-lint/dist/index.js
|
|
294
|
+
var dist_exports4 = {};
|
|
295
|
+
__export(dist_exports4, {
|
|
296
|
+
lintDirectory: () => lintDirectory,
|
|
297
|
+
privacyValid: () => privacyValid,
|
|
298
|
+
requireFrontmatter: () => requireFrontmatter,
|
|
299
|
+
wikiLinkResolves: () => wikiLinkResolves
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
// ../modules/data-lint/dist/runner.js
|
|
303
|
+
import { readdir as readdir2, readFile as readFile3 } from "fs/promises";
|
|
304
|
+
import { join as join4 } from "path";
|
|
305
|
+
async function lintDirectory(options) {
|
|
306
|
+
const start = Date.now();
|
|
307
|
+
const extensions = options.extensions ?? [".md"];
|
|
308
|
+
const files = await collectFiles(options.dir, extensions);
|
|
309
|
+
const findings = [];
|
|
310
|
+
for (const file of files) {
|
|
311
|
+
const content = await readFile3(file, "utf8");
|
|
312
|
+
for (const rule of options.rules) {
|
|
313
|
+
const result = await rule.check({ file, content });
|
|
314
|
+
for (const f of result)
|
|
315
|
+
findings.push(f);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
return {
|
|
319
|
+
findings,
|
|
320
|
+
filesScanned: files.length,
|
|
321
|
+
rulesRun: options.rules.length,
|
|
322
|
+
durationMs: Date.now() - start
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
async function collectFiles(dir, extensions) {
|
|
326
|
+
const out = [];
|
|
327
|
+
const stack = [dir];
|
|
328
|
+
while (stack.length > 0) {
|
|
329
|
+
const current = stack.pop();
|
|
330
|
+
if (current === void 0)
|
|
331
|
+
break;
|
|
332
|
+
let entries;
|
|
333
|
+
try {
|
|
334
|
+
entries = await readdir2(current, { withFileTypes: true });
|
|
335
|
+
} catch (e) {
|
|
336
|
+
if (e.code === "ENOENT")
|
|
337
|
+
continue;
|
|
338
|
+
throw e;
|
|
339
|
+
}
|
|
340
|
+
for (const entry of entries) {
|
|
341
|
+
const full = join4(current, entry.name);
|
|
342
|
+
if (entry.isDirectory()) {
|
|
343
|
+
stack.push(full);
|
|
344
|
+
} else if (entry.isFile() && extensions.some((ext) => entry.name.endsWith(ext))) {
|
|
345
|
+
out.push(full);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
return out.sort();
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// ../modules/data-lint/dist/rules/require-frontmatter.js
|
|
353
|
+
function requireFrontmatter(options) {
|
|
354
|
+
return {
|
|
355
|
+
id: "require-frontmatter",
|
|
356
|
+
description: `Ensure required frontmatter keys are present: ${options.required.join(", ")}`,
|
|
357
|
+
check({ file, content }) {
|
|
358
|
+
const findings = [];
|
|
359
|
+
const { frontmatter } = parseFrontmatter(content);
|
|
360
|
+
for (const key of options.required) {
|
|
361
|
+
const value = frontmatter[key];
|
|
362
|
+
if (value === void 0 || value === null || value === "") {
|
|
363
|
+
findings.push({
|
|
364
|
+
rule: "require-frontmatter",
|
|
365
|
+
severity: "error",
|
|
366
|
+
file,
|
|
367
|
+
message: `Missing required frontmatter key: "${key}"`
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
return findings;
|
|
372
|
+
}
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// ../modules/data-lint/dist/rules/privacy-valid.js
|
|
377
|
+
var CANONICAL = /* @__PURE__ */ new Set(["public", "internal", "personal"]);
|
|
378
|
+
function privacyValid() {
|
|
379
|
+
return {
|
|
380
|
+
id: "privacy-valid",
|
|
381
|
+
description: "Ensure frontmatter privacy is one of public/internal/personal",
|
|
382
|
+
check({ file, content }) {
|
|
383
|
+
const findings = [];
|
|
384
|
+
const { frontmatter } = parseFrontmatter(content);
|
|
385
|
+
if (frontmatter.privacy === void 0)
|
|
386
|
+
return findings;
|
|
387
|
+
if (typeof frontmatter.privacy !== "string" || !CANONICAL.has(frontmatter.privacy)) {
|
|
388
|
+
findings.push({
|
|
389
|
+
rule: "privacy-valid",
|
|
390
|
+
severity: "error",
|
|
391
|
+
file,
|
|
392
|
+
message: `Invalid privacy value: ${JSON.stringify(frontmatter.privacy)}. Expected one of: public, internal, personal.`
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
return findings;
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// ../modules/data-lint/dist/rules/wiki-link-resolves.js
|
|
401
|
+
import { readdir as readdir3 } from "fs/promises";
|
|
402
|
+
import { basename as basename2, extname as extname2, join as join5 } from "path";
|
|
403
|
+
var WIKI_LINK = /\[\[([^\]|#]+)(?:[|#][^\]]*)?\]\]/g;
|
|
404
|
+
function wikiLinkResolves(options) {
|
|
405
|
+
let cache;
|
|
406
|
+
const extensions = options.extensions ?? [".md"];
|
|
407
|
+
async function buildIndex() {
|
|
408
|
+
if (cache)
|
|
409
|
+
return cache;
|
|
410
|
+
const out = /* @__PURE__ */ new Set();
|
|
411
|
+
const stack = [options.searchRoot];
|
|
412
|
+
while (stack.length > 0) {
|
|
413
|
+
const current = stack.pop();
|
|
414
|
+
if (current === void 0)
|
|
415
|
+
break;
|
|
416
|
+
let entries;
|
|
417
|
+
try {
|
|
418
|
+
entries = await readdir3(current, { withFileTypes: true });
|
|
419
|
+
} catch {
|
|
420
|
+
continue;
|
|
421
|
+
}
|
|
422
|
+
for (const entry of entries) {
|
|
423
|
+
const full = join5(current, entry.name);
|
|
424
|
+
if (entry.isDirectory()) {
|
|
425
|
+
stack.push(full);
|
|
426
|
+
} else if (entry.isFile() && extensions.some((ext) => entry.name.endsWith(ext))) {
|
|
427
|
+
out.add(basename2(entry.name, extname2(entry.name)));
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
cache = out;
|
|
432
|
+
return out;
|
|
433
|
+
}
|
|
434
|
+
return {
|
|
435
|
+
id: "wiki-link-resolves",
|
|
436
|
+
description: "Check [[wiki links]] resolve to an existing file by basename",
|
|
437
|
+
async check({ file, content }) {
|
|
438
|
+
const findings = [];
|
|
439
|
+
const index = await buildIndex();
|
|
440
|
+
const lines = content.split("\n");
|
|
441
|
+
lines.forEach((line, idx) => {
|
|
442
|
+
for (const match of line.matchAll(WIKI_LINK)) {
|
|
443
|
+
const target = match[1]?.trim();
|
|
444
|
+
if (target && !index.has(target)) {
|
|
445
|
+
findings.push({
|
|
446
|
+
rule: "wiki-link-resolves",
|
|
447
|
+
severity: "warning",
|
|
448
|
+
file,
|
|
449
|
+
line: idx + 1,
|
|
450
|
+
message: `Unresolved wiki link: [[${target}]]`
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
});
|
|
455
|
+
return findings;
|
|
456
|
+
}
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// ../modules/ai-coding-pitfalls/dist/index.js
|
|
461
|
+
var dist_exports5 = {};
|
|
462
|
+
__export(dist_exports5, {
|
|
463
|
+
PitfallCatalog: () => PitfallCatalog
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
// ../modules/ai-coding-pitfalls/dist/catalog.js
|
|
467
|
+
import { readdir as readdir4, readFile as readFile4 } from "fs/promises";
|
|
468
|
+
import { basename as basename3, extname as extname3, join as join6 } from "path";
|
|
469
|
+
var PitfallCatalog = class {
|
|
470
|
+
dir;
|
|
471
|
+
constructor(dir) {
|
|
472
|
+
this.dir = dir;
|
|
473
|
+
}
|
|
474
|
+
/** Load every pitfall in the directory, sorted by id. */
|
|
475
|
+
async list() {
|
|
476
|
+
const files = await this.entries();
|
|
477
|
+
const out = [];
|
|
478
|
+
for (const file of files) {
|
|
479
|
+
out.push(await this.loadFile(file));
|
|
480
|
+
}
|
|
481
|
+
return out.sort((a, b2) => a.id.localeCompare(b2.id));
|
|
482
|
+
}
|
|
483
|
+
/** Load a single pitfall by id. Returns `undefined` if not found. */
|
|
484
|
+
async get(id) {
|
|
485
|
+
const all = await this.list();
|
|
486
|
+
return all.find((p) => p.id === id);
|
|
487
|
+
}
|
|
488
|
+
/** Return only pitfalls matching the given category. */
|
|
489
|
+
async filterByCategory(category) {
|
|
490
|
+
const all = await this.list();
|
|
491
|
+
return all.filter((p) => p.category === category);
|
|
492
|
+
}
|
|
493
|
+
async entries() {
|
|
494
|
+
try {
|
|
495
|
+
const names = await readdir4(this.dir);
|
|
496
|
+
return names.filter((n) => n.endsWith(".md")).map((n) => join6(this.dir, n));
|
|
497
|
+
} catch (e) {
|
|
498
|
+
if (e.code === "ENOENT")
|
|
499
|
+
return [];
|
|
500
|
+
throw e;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
async loadFile(path) {
|
|
504
|
+
const raw = await readFile4(path, "utf8");
|
|
505
|
+
const { frontmatter, body } = parseFrontmatter(raw);
|
|
506
|
+
const idFromFile = basename3(path, extname3(path));
|
|
507
|
+
return {
|
|
508
|
+
id: frontmatter.id ?? idFromFile,
|
|
509
|
+
title: frontmatter.title,
|
|
510
|
+
category: frontmatter.category,
|
|
511
|
+
severity: frontmatter.severity,
|
|
512
|
+
signal: frontmatter.signal,
|
|
513
|
+
cause: frontmatter.cause,
|
|
514
|
+
mitigation: frontmatter.mitigation,
|
|
515
|
+
body: body.trimStart()
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
};
|
|
519
|
+
|
|
520
|
+
// ../modules/tool-rules/dist/index.js
|
|
521
|
+
var dist_exports6 = {};
|
|
522
|
+
__export(dist_exports6, {
|
|
523
|
+
ToolRuleCatalog: () => ToolRuleCatalog
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
// ../modules/tool-rules/dist/catalog.js
|
|
527
|
+
import { readdir as readdir5, readFile as readFile5 } from "fs/promises";
|
|
528
|
+
import { basename as basename4, extname as extname4, join as join7 } from "path";
|
|
529
|
+
var ToolRuleCatalog = class {
|
|
530
|
+
dir;
|
|
531
|
+
constructor(dir) {
|
|
532
|
+
this.dir = dir;
|
|
533
|
+
}
|
|
534
|
+
/** Load every rule in the directory, sorted by id. */
|
|
535
|
+
async list() {
|
|
536
|
+
const files = await this.entries();
|
|
537
|
+
const out = [];
|
|
538
|
+
for (const file of files) {
|
|
539
|
+
out.push(await this.loadFile(file));
|
|
540
|
+
}
|
|
541
|
+
return out.sort((a, b2) => a.id.localeCompare(b2.id));
|
|
542
|
+
}
|
|
543
|
+
/** Load a single rule by id. Returns `undefined` if not found. */
|
|
544
|
+
async get(id) {
|
|
545
|
+
const all = await this.list();
|
|
546
|
+
return all.find((r) => r.id === id);
|
|
547
|
+
}
|
|
548
|
+
/** Return only rules whose `scope` matches exactly. */
|
|
549
|
+
async filterByScope(scope) {
|
|
550
|
+
const all = await this.list();
|
|
551
|
+
return all.filter((r) => r.scope === scope);
|
|
552
|
+
}
|
|
553
|
+
/** Return only rules whose `severity` matches. */
|
|
554
|
+
async filterBySeverity(severity) {
|
|
555
|
+
const all = await this.list();
|
|
556
|
+
return all.filter((r) => r.severity === severity);
|
|
557
|
+
}
|
|
558
|
+
async entries() {
|
|
559
|
+
try {
|
|
560
|
+
const names = await readdir5(this.dir);
|
|
561
|
+
return names.filter((n) => n.endsWith(".md")).map((n) => join7(this.dir, n));
|
|
562
|
+
} catch (e) {
|
|
563
|
+
if (e.code === "ENOENT")
|
|
564
|
+
return [];
|
|
565
|
+
throw e;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
async loadFile(path) {
|
|
569
|
+
const raw = await readFile5(path, "utf8");
|
|
570
|
+
const { frontmatter, body } = parseFrontmatter(raw);
|
|
571
|
+
const idFromFile = basename4(path, extname4(path));
|
|
572
|
+
return {
|
|
573
|
+
id: frontmatter.id ?? idFromFile,
|
|
574
|
+
title: frontmatter.title,
|
|
575
|
+
scope: frontmatter.scope,
|
|
576
|
+
severity: frontmatter.severity,
|
|
577
|
+
condition: frontmatter.condition,
|
|
578
|
+
action: frontmatter.action,
|
|
579
|
+
body: body.trimStart()
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
};
|
|
583
|
+
|
|
584
|
+
// ../modules/report-generator/dist/index.js
|
|
585
|
+
var dist_exports7 = {};
|
|
586
|
+
__export(dist_exports7, {
|
|
587
|
+
DEFAULT_TEMPLATE: () => DEFAULT_TEMPLATE,
|
|
588
|
+
applyTemplate: () => applyTemplate,
|
|
589
|
+
renderHtml: () => renderHtml,
|
|
590
|
+
stripPrivateSections: () => stripPrivateSections
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
// ../node_modules/marked/lib/marked.esm.js
|
|
594
|
+
function L() {
|
|
595
|
+
return { async: false, breaks: false, extensions: null, gfm: true, hooks: null, pedantic: false, renderer: null, silent: false, tokenizer: null, walkTokens: null };
|
|
596
|
+
}
|
|
597
|
+
var T = L();
|
|
598
|
+
function G(l3) {
|
|
599
|
+
T = l3;
|
|
600
|
+
}
|
|
601
|
+
var E = { exec: () => null };
|
|
602
|
+
function d(l3, e = "") {
|
|
603
|
+
let t = typeof l3 == "string" ? l3 : l3.source, n = { replace: (r, i) => {
|
|
604
|
+
let s = typeof i == "string" ? i : i.source;
|
|
605
|
+
return s = s.replace(m.caret, "$1"), t = t.replace(r, s), n;
|
|
606
|
+
}, getRegex: () => new RegExp(t, e) };
|
|
607
|
+
return n;
|
|
608
|
+
}
|
|
609
|
+
var be = (() => {
|
|
610
|
+
try {
|
|
611
|
+
return !!new RegExp("(?<=1)(?<!1)");
|
|
612
|
+
} catch {
|
|
613
|
+
return false;
|
|
614
|
+
}
|
|
615
|
+
})();
|
|
616
|
+
var m = { codeRemoveIndent: /^(?: {1,4}| {0,3}\t)/gm, outputLinkReplace: /\\([\[\]])/g, indentCodeCompensation: /^(\s+)(?:```)/, beginningSpace: /^\s+/, endingHash: /#$/, startingSpaceChar: /^ /, endingSpaceChar: / $/, nonSpaceChar: /[^ ]/, newLineCharGlobal: /\n/g, tabCharGlobal: /\t/g, multipleSpaceGlobal: /\s+/g, blankLine: /^[ \t]*$/, doubleBlankLine: /\n[ \t]*\n[ \t]*$/, blockquoteStart: /^ {0,3}>/, blockquoteSetextReplace: /\n {0,3}((?:=+|-+) *)(?=\n|$)/g, blockquoteSetextReplace2: /^ {0,3}>[ \t]?/gm, listReplaceTabs: /^\t+/, listReplaceNesting: /^ {1,4}(?=( {4})*[^ ])/g, listIsTask: /^\[[ xX]\] /, listReplaceTask: /^\[[ xX]\] +/, anyLine: /\n.*\n/, hrefBrackets: /^<(.*)>$/, tableDelimiter: /[:|]/, tableAlignChars: /^\||\| *$/g, tableRowBlankLine: /\n[ \t]*$/, tableAlignRight: /^ *-+: *$/, tableAlignCenter: /^ *:-+: *$/, tableAlignLeft: /^ *:-+ *$/, startATag: /^<a /i, endATag: /^<\/a>/i, startPreScriptTag: /^<(pre|code|kbd|script)(\s|>)/i, endPreScriptTag: /^<\/(pre|code|kbd|script)(\s|>)/i, startAngleBracket: /^</, endAngleBracket: />$/, pedanticHrefTitle: /^([^'"]*[^\s])\s+(['"])(.*)\2/, unicodeAlphaNumeric: /[\p{L}\p{N}]/u, escapeTest: /[&<>"']/, escapeReplace: /[&<>"']/g, escapeTestNoEncode: /[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/, escapeReplaceNoEncode: /[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/g, unescapeTest: /&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig, caret: /(^|[^\[])\^/g, percentDecode: /%25/g, findPipe: /\|/g, splitPipe: / \|/, slashPipe: /\\\|/g, carriageReturn: /\r\n|\r/g, spaceLine: /^ +$/gm, notSpaceStart: /^\S*/, endingNewline: /\n$/, listItemRegex: (l3) => new RegExp(`^( {0,3}${l3})((?:[ ][^\\n]*)?(?:\\n|$))`), nextBulletRegex: (l3) => new RegExp(`^ {0,${Math.min(3, l3 - 1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ ][^\\n]*)?(?:\\n|$))`), hrRegex: (l3) => new RegExp(`^ {0,${Math.min(3, l3 - 1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`), fencesBeginRegex: (l3) => new RegExp(`^ {0,${Math.min(3, l3 - 1)}}(?:\`\`\`|~~~)`), headingBeginRegex: (l3) => new RegExp(`^ {0,${Math.min(3, l3 - 1)}}#`), htmlBeginRegex: (l3) => new RegExp(`^ {0,${Math.min(3, l3 - 1)}}<(?:[a-z].*>|!--)`, "i") };
|
|
617
|
+
var Re = /^(?:[ \t]*(?:\n|$))+/;
|
|
618
|
+
var Te = /^((?: {4}| {0,3}\t)[^\n]+(?:\n(?:[ \t]*(?:\n|$))*)?)+/;
|
|
619
|
+
var Oe = /^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/;
|
|
620
|
+
var I = /^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/;
|
|
621
|
+
var we = /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/;
|
|
622
|
+
var F = /(?:[*+-]|\d{1,9}[.)])/;
|
|
623
|
+
var ie = /^(?!bull |blockCode|fences|blockquote|heading|html|table)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html|table))+?)\n {0,3}(=+|-+) *(?:\n+|$)/;
|
|
624
|
+
var oe = d(ie).replace(/bull/g, F).replace(/blockCode/g, /(?: {4}| {0,3}\t)/).replace(/fences/g, / {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g, / {0,3}>/).replace(/heading/g, / {0,3}#{1,6}/).replace(/html/g, / {0,3}<[^\n>]+>\n/).replace(/\|table/g, "").getRegex();
|
|
625
|
+
var ye = d(ie).replace(/bull/g, F).replace(/blockCode/g, /(?: {4}| {0,3}\t)/).replace(/fences/g, / {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g, / {0,3}>/).replace(/heading/g, / {0,3}#{1,6}/).replace(/html/g, / {0,3}<[^\n>]+>\n/).replace(/table/g, / {0,3}\|?(?:[:\- ]*\|)+[\:\- ]*\n/).getRegex();
|
|
626
|
+
var j = /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/;
|
|
627
|
+
var Pe = /^[^\n]+/;
|
|
628
|
+
var Q = /(?!\s*\])(?:\\[\s\S]|[^\[\]\\])+/;
|
|
629
|
+
var Se = d(/^ {0,3}\[(label)\]: *(?:\n[ \t]*)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n[ \t]*)?| *\n[ \t]*)(title))? *(?:\n+|$)/).replace("label", Q).replace("title", /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex();
|
|
630
|
+
var $e = d(/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/).replace(/bull/g, F).getRegex();
|
|
631
|
+
var v = "address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul";
|
|
632
|
+
var U = /<!--(?:-?>|[\s\S]*?(?:-->|$))/;
|
|
633
|
+
var _e = d("^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|<![A-Z][\\s\\S]*?(?:>\\n*|$)|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|</(?!script|pre|style|textarea)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$))", "i").replace("comment", U).replace("tag", v).replace("attribute", / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex();
|
|
634
|
+
var ae = d(j).replace("hr", I).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("|lheading", "").replace("|table", "").replace("blockquote", " {0,3}>").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list", " {0,3}(?:[*+-]|1[.)]) ").replace("html", "</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag", v).getRegex();
|
|
635
|
+
var Le = d(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph", ae).getRegex();
|
|
636
|
+
var K = { blockquote: Le, code: Te, def: Se, fences: Oe, heading: we, hr: I, html: _e, lheading: oe, list: $e, newline: Re, paragraph: ae, table: E, text: Pe };
|
|
637
|
+
var re = d("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr", I).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("blockquote", " {0,3}>").replace("code", "(?: {4}| {0,3} )[^\\n]").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list", " {0,3}(?:[*+-]|1[.)]) ").replace("html", "</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag", v).getRegex();
|
|
638
|
+
var Me = { ...K, lheading: ye, table: re, paragraph: d(j).replace("hr", I).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("|lheading", "").replace("table", re).replace("blockquote", " {0,3}>").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list", " {0,3}(?:[*+-]|1[.)]) ").replace("html", "</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag", v).getRegex() };
|
|
639
|
+
var ze = { ...K, html: d(`^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)|<tag(?:"[^"]*"|'[^']*'|\\s[^'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))`).replace("comment", U).replace(/tag/g, "(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(), def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/, heading: /^(#{1,6})(.*)(?:\n+|$)/, fences: E, lheading: /^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/, paragraph: d(j).replace("hr", I).replace("heading", ` *#{1,6} *[^
|
|
640
|
+
]`).replace("lheading", oe).replace("|table", "").replace("blockquote", " {0,3}>").replace("|fences", "").replace("|list", "").replace("|html", "").replace("|tag", "").getRegex() };
|
|
641
|
+
var Ae = /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/;
|
|
642
|
+
var Ee = /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/;
|
|
643
|
+
var le = /^( {2,}|\\)\n(?!\s*$)/;
|
|
644
|
+
var Ie = /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/;
|
|
645
|
+
var D = /[\p{P}\p{S}]/u;
|
|
646
|
+
var W = /[\s\p{P}\p{S}]/u;
|
|
647
|
+
var ue = /[^\s\p{P}\p{S}]/u;
|
|
648
|
+
var Ce = d(/^((?![*_])punctSpace)/, "u").replace(/punctSpace/g, W).getRegex();
|
|
649
|
+
var pe = /(?!~)[\p{P}\p{S}]/u;
|
|
650
|
+
var Be = /(?!~)[\s\p{P}\p{S}]/u;
|
|
651
|
+
var qe = /(?:[^\s\p{P}\p{S}]|~)/u;
|
|
652
|
+
var ve = d(/link|precode-code|html/, "g").replace("link", /\[(?:[^\[\]`]|(?<a>`+)[^`]+\k<a>(?!`))*?\]\((?:\\[\s\S]|[^\\\(\)]|\((?:\\[\s\S]|[^\\\(\)])*\))*\)/).replace("precode-", be ? "(?<!`)()" : "(^^|[^`])").replace("code", /(?<b>`+)[^`]+\k<b>(?!`)/).replace("html", /<(?! )[^<>]*?>/).getRegex();
|
|
653
|
+
var ce = /^(?:\*+(?:((?!\*)punct)|[^\s*]))|^_+(?:((?!_)punct)|([^\s_]))/;
|
|
654
|
+
var De = d(ce, "u").replace(/punct/g, D).getRegex();
|
|
655
|
+
var He = d(ce, "u").replace(/punct/g, pe).getRegex();
|
|
656
|
+
var he = "^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)punctSpace(\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|notPunctSpace(\\*+)(?=notPunctSpace)";
|
|
657
|
+
var Ze = d(he, "gu").replace(/notPunctSpace/g, ue).replace(/punctSpace/g, W).replace(/punct/g, D).getRegex();
|
|
658
|
+
var Ge = d(he, "gu").replace(/notPunctSpace/g, qe).replace(/punctSpace/g, Be).replace(/punct/g, pe).getRegex();
|
|
659
|
+
var Ne = d("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)punctSpace(_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)", "gu").replace(/notPunctSpace/g, ue).replace(/punctSpace/g, W).replace(/punct/g, D).getRegex();
|
|
660
|
+
var Fe = d(/\\(punct)/, "gu").replace(/punct/g, D).getRegex();
|
|
661
|
+
var je = d(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace("scheme", /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace("email", /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex();
|
|
662
|
+
var Qe = d(U).replace("(?:-->|$)", "-->").getRegex();
|
|
663
|
+
var Ue = d("^comment|^</[a-zA-Z][\\w:-]*\\s*>|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^<![a-zA-Z]+\\s[\\s\\S]*?>|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>").replace("comment", Qe).replace("attribute", /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex();
|
|
664
|
+
var q = /(?:\[(?:\\[\s\S]|[^\[\]\\])*\]|\\[\s\S]|`+[^`]*?`+(?!`)|[^\[\]\\`])*?/;
|
|
665
|
+
var Ke = d(/^!?\[(label)\]\(\s*(href)(?:(?:[ \t]*(?:\n[ \t]*)?)(title))?\s*\)/).replace("label", q).replace("href", /<(?:\\.|[^\n<>\\])+>|[^ \t\n\x00-\x1f]*/).replace("title", /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex();
|
|
666
|
+
var de = d(/^!?\[(label)\]\[(ref)\]/).replace("label", q).replace("ref", Q).getRegex();
|
|
667
|
+
var ke = d(/^!?\[(ref)\](?:\[\])?/).replace("ref", Q).getRegex();
|
|
668
|
+
var We = d("reflink|nolink(?!\\()", "g").replace("reflink", de).replace("nolink", ke).getRegex();
|
|
669
|
+
var se = /[hH][tT][tT][pP][sS]?|[fF][tT][pP]/;
|
|
670
|
+
var X = { _backpedal: E, anyPunctuation: Fe, autolink: je, blockSkip: ve, br: le, code: Ee, del: E, emStrongLDelim: De, emStrongRDelimAst: Ze, emStrongRDelimUnd: Ne, escape: Ae, link: Ke, nolink: ke, punctuation: Ce, reflink: de, reflinkSearch: We, tag: Ue, text: Ie, url: E };
|
|
671
|
+
var Xe = { ...X, link: d(/^!?\[(label)\]\((.*?)\)/).replace("label", q).getRegex(), reflink: d(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label", q).getRegex() };
|
|
672
|
+
var N = { ...X, emStrongRDelimAst: Ge, emStrongLDelim: He, url: d(/^((?:protocol):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/).replace("protocol", se).replace("email", /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/).getRegex(), _backpedal: /(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/, del: /^(~~?)(?=[^\s~])((?:\\[\s\S]|[^\\])*?(?:\\[\s\S]|[^\s~\\]))\1(?=[^~]|$)/, text: d(/^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|protocol:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/).replace("protocol", se).getRegex() };
|
|
673
|
+
var Je = { ...N, br: d(le).replace("{2,}", "*").getRegex(), text: d(N.text).replace("\\b_", "\\b_| {2,}\\n").replace(/\{2,\}/g, "*").getRegex() };
|
|
674
|
+
var C = { normal: K, gfm: Me, pedantic: ze };
|
|
675
|
+
var M = { normal: X, gfm: N, breaks: Je, pedantic: Xe };
|
|
676
|
+
var Ve = { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" };
|
|
677
|
+
var ge = (l3) => Ve[l3];
|
|
678
|
+
function w(l3, e) {
|
|
679
|
+
if (e) {
|
|
680
|
+
if (m.escapeTest.test(l3)) return l3.replace(m.escapeReplace, ge);
|
|
681
|
+
} else if (m.escapeTestNoEncode.test(l3)) return l3.replace(m.escapeReplaceNoEncode, ge);
|
|
682
|
+
return l3;
|
|
683
|
+
}
|
|
684
|
+
function J(l3) {
|
|
685
|
+
try {
|
|
686
|
+
l3 = encodeURI(l3).replace(m.percentDecode, "%");
|
|
687
|
+
} catch {
|
|
688
|
+
return null;
|
|
689
|
+
}
|
|
690
|
+
return l3;
|
|
691
|
+
}
|
|
692
|
+
function V(l3, e) {
|
|
693
|
+
let t = l3.replace(m.findPipe, (i, s, a) => {
|
|
694
|
+
let o = false, p = s;
|
|
695
|
+
for (; --p >= 0 && a[p] === "\\"; ) o = !o;
|
|
696
|
+
return o ? "|" : " |";
|
|
697
|
+
}), n = t.split(m.splitPipe), r = 0;
|
|
698
|
+
if (n[0].trim() || n.shift(), n.length > 0 && !n.at(-1)?.trim() && n.pop(), e) if (n.length > e) n.splice(e);
|
|
699
|
+
else for (; n.length < e; ) n.push("");
|
|
700
|
+
for (; r < n.length; r++) n[r] = n[r].trim().replace(m.slashPipe, "|");
|
|
701
|
+
return n;
|
|
702
|
+
}
|
|
703
|
+
function z(l3, e, t) {
|
|
704
|
+
let n = l3.length;
|
|
705
|
+
if (n === 0) return "";
|
|
706
|
+
let r = 0;
|
|
707
|
+
for (; r < n; ) {
|
|
708
|
+
let i = l3.charAt(n - r - 1);
|
|
709
|
+
if (i === e && !t) r++;
|
|
710
|
+
else if (i !== e && t) r++;
|
|
711
|
+
else break;
|
|
712
|
+
}
|
|
713
|
+
return l3.slice(0, n - r);
|
|
714
|
+
}
|
|
715
|
+
function fe(l3, e) {
|
|
716
|
+
if (l3.indexOf(e[1]) === -1) return -1;
|
|
717
|
+
let t = 0;
|
|
718
|
+
for (let n = 0; n < l3.length; n++) if (l3[n] === "\\") n++;
|
|
719
|
+
else if (l3[n] === e[0]) t++;
|
|
720
|
+
else if (l3[n] === e[1] && (t--, t < 0)) return n;
|
|
721
|
+
return t > 0 ? -2 : -1;
|
|
722
|
+
}
|
|
723
|
+
function me(l3, e, t, n, r) {
|
|
724
|
+
let i = e.href, s = e.title || null, a = l3[1].replace(r.other.outputLinkReplace, "$1");
|
|
725
|
+
n.state.inLink = true;
|
|
726
|
+
let o = { type: l3[0].charAt(0) === "!" ? "image" : "link", raw: t, href: i, title: s, text: a, tokens: n.inlineTokens(a) };
|
|
727
|
+
return n.state.inLink = false, o;
|
|
728
|
+
}
|
|
729
|
+
function Ye(l3, e, t) {
|
|
730
|
+
let n = l3.match(t.other.indentCodeCompensation);
|
|
731
|
+
if (n === null) return e;
|
|
732
|
+
let r = n[1];
|
|
733
|
+
return e.split(`
|
|
734
|
+
`).map((i) => {
|
|
735
|
+
let s = i.match(t.other.beginningSpace);
|
|
736
|
+
if (s === null) return i;
|
|
737
|
+
let [a] = s;
|
|
738
|
+
return a.length >= r.length ? i.slice(r.length) : i;
|
|
739
|
+
}).join(`
|
|
740
|
+
`);
|
|
741
|
+
}
|
|
742
|
+
var y = class {
|
|
743
|
+
options;
|
|
744
|
+
rules;
|
|
745
|
+
lexer;
|
|
746
|
+
constructor(e) {
|
|
747
|
+
this.options = e || T;
|
|
748
|
+
}
|
|
749
|
+
space(e) {
|
|
750
|
+
let t = this.rules.block.newline.exec(e);
|
|
751
|
+
if (t && t[0].length > 0) return { type: "space", raw: t[0] };
|
|
752
|
+
}
|
|
753
|
+
code(e) {
|
|
754
|
+
let t = this.rules.block.code.exec(e);
|
|
755
|
+
if (t) {
|
|
756
|
+
let n = t[0].replace(this.rules.other.codeRemoveIndent, "");
|
|
757
|
+
return { type: "code", raw: t[0], codeBlockStyle: "indented", text: this.options.pedantic ? n : z(n, `
|
|
758
|
+
`) };
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
fences(e) {
|
|
762
|
+
let t = this.rules.block.fences.exec(e);
|
|
763
|
+
if (t) {
|
|
764
|
+
let n = t[0], r = Ye(n, t[3] || "", this.rules);
|
|
765
|
+
return { type: "code", raw: n, lang: t[2] ? t[2].trim().replace(this.rules.inline.anyPunctuation, "$1") : t[2], text: r };
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
heading(e) {
|
|
769
|
+
let t = this.rules.block.heading.exec(e);
|
|
770
|
+
if (t) {
|
|
771
|
+
let n = t[2].trim();
|
|
772
|
+
if (this.rules.other.endingHash.test(n)) {
|
|
773
|
+
let r = z(n, "#");
|
|
774
|
+
(this.options.pedantic || !r || this.rules.other.endingSpaceChar.test(r)) && (n = r.trim());
|
|
775
|
+
}
|
|
776
|
+
return { type: "heading", raw: t[0], depth: t[1].length, text: n, tokens: this.lexer.inline(n) };
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
hr(e) {
|
|
780
|
+
let t = this.rules.block.hr.exec(e);
|
|
781
|
+
if (t) return { type: "hr", raw: z(t[0], `
|
|
782
|
+
`) };
|
|
783
|
+
}
|
|
784
|
+
blockquote(e) {
|
|
785
|
+
let t = this.rules.block.blockquote.exec(e);
|
|
786
|
+
if (t) {
|
|
787
|
+
let n = z(t[0], `
|
|
788
|
+
`).split(`
|
|
789
|
+
`), r = "", i = "", s = [];
|
|
790
|
+
for (; n.length > 0; ) {
|
|
791
|
+
let a = false, o = [], p;
|
|
792
|
+
for (p = 0; p < n.length; p++) if (this.rules.other.blockquoteStart.test(n[p])) o.push(n[p]), a = true;
|
|
793
|
+
else if (!a) o.push(n[p]);
|
|
794
|
+
else break;
|
|
795
|
+
n = n.slice(p);
|
|
796
|
+
let u = o.join(`
|
|
797
|
+
`), c = u.replace(this.rules.other.blockquoteSetextReplace, `
|
|
798
|
+
$1`).replace(this.rules.other.blockquoteSetextReplace2, "");
|
|
799
|
+
r = r ? `${r}
|
|
800
|
+
${u}` : u, i = i ? `${i}
|
|
801
|
+
${c}` : c;
|
|
802
|
+
let g = this.lexer.state.top;
|
|
803
|
+
if (this.lexer.state.top = true, this.lexer.blockTokens(c, s, true), this.lexer.state.top = g, n.length === 0) break;
|
|
804
|
+
let h = s.at(-1);
|
|
805
|
+
if (h?.type === "code") break;
|
|
806
|
+
if (h?.type === "blockquote") {
|
|
807
|
+
let R = h, f = R.raw + `
|
|
808
|
+
` + n.join(`
|
|
809
|
+
`), O = this.blockquote(f);
|
|
810
|
+
s[s.length - 1] = O, r = r.substring(0, r.length - R.raw.length) + O.raw, i = i.substring(0, i.length - R.text.length) + O.text;
|
|
811
|
+
break;
|
|
812
|
+
} else if (h?.type === "list") {
|
|
813
|
+
let R = h, f = R.raw + `
|
|
814
|
+
` + n.join(`
|
|
815
|
+
`), O = this.list(f);
|
|
816
|
+
s[s.length - 1] = O, r = r.substring(0, r.length - h.raw.length) + O.raw, i = i.substring(0, i.length - R.raw.length) + O.raw, n = f.substring(s.at(-1).raw.length).split(`
|
|
817
|
+
`);
|
|
818
|
+
continue;
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
return { type: "blockquote", raw: r, tokens: s, text: i };
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
list(e) {
|
|
825
|
+
let t = this.rules.block.list.exec(e);
|
|
826
|
+
if (t) {
|
|
827
|
+
let n = t[1].trim(), r = n.length > 1, i = { type: "list", raw: "", ordered: r, start: r ? +n.slice(0, -1) : "", loose: false, items: [] };
|
|
828
|
+
n = r ? `\\d{1,9}\\${n.slice(-1)}` : `\\${n}`, this.options.pedantic && (n = r ? n : "[*+-]");
|
|
829
|
+
let s = this.rules.other.listItemRegex(n), a = false;
|
|
830
|
+
for (; e; ) {
|
|
831
|
+
let p = false, u = "", c = "";
|
|
832
|
+
if (!(t = s.exec(e)) || this.rules.block.hr.test(e)) break;
|
|
833
|
+
u = t[0], e = e.substring(u.length);
|
|
834
|
+
let g = t[2].split(`
|
|
835
|
+
`, 1)[0].replace(this.rules.other.listReplaceTabs, (H) => " ".repeat(3 * H.length)), h = e.split(`
|
|
836
|
+
`, 1)[0], R = !g.trim(), f = 0;
|
|
837
|
+
if (this.options.pedantic ? (f = 2, c = g.trimStart()) : R ? f = t[1].length + 1 : (f = t[2].search(this.rules.other.nonSpaceChar), f = f > 4 ? 1 : f, c = g.slice(f), f += t[1].length), R && this.rules.other.blankLine.test(h) && (u += h + `
|
|
838
|
+
`, e = e.substring(h.length + 1), p = true), !p) {
|
|
839
|
+
let H = this.rules.other.nextBulletRegex(f), ee = this.rules.other.hrRegex(f), te = this.rules.other.fencesBeginRegex(f), ne = this.rules.other.headingBeginRegex(f), xe = this.rules.other.htmlBeginRegex(f);
|
|
840
|
+
for (; e; ) {
|
|
841
|
+
let Z = e.split(`
|
|
842
|
+
`, 1)[0], A;
|
|
843
|
+
if (h = Z, this.options.pedantic ? (h = h.replace(this.rules.other.listReplaceNesting, " "), A = h) : A = h.replace(this.rules.other.tabCharGlobal, " "), te.test(h) || ne.test(h) || xe.test(h) || H.test(h) || ee.test(h)) break;
|
|
844
|
+
if (A.search(this.rules.other.nonSpaceChar) >= f || !h.trim()) c += `
|
|
845
|
+
` + A.slice(f);
|
|
846
|
+
else {
|
|
847
|
+
if (R || g.replace(this.rules.other.tabCharGlobal, " ").search(this.rules.other.nonSpaceChar) >= 4 || te.test(g) || ne.test(g) || ee.test(g)) break;
|
|
848
|
+
c += `
|
|
849
|
+
` + h;
|
|
850
|
+
}
|
|
851
|
+
!R && !h.trim() && (R = true), u += Z + `
|
|
852
|
+
`, e = e.substring(Z.length + 1), g = A.slice(f);
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
i.loose || (a ? i.loose = true : this.rules.other.doubleBlankLine.test(u) && (a = true));
|
|
856
|
+
let O = null, Y;
|
|
857
|
+
this.options.gfm && (O = this.rules.other.listIsTask.exec(c), O && (Y = O[0] !== "[ ] ", c = c.replace(this.rules.other.listReplaceTask, ""))), i.items.push({ type: "list_item", raw: u, task: !!O, checked: Y, loose: false, text: c, tokens: [] }), i.raw += u;
|
|
858
|
+
}
|
|
859
|
+
let o = i.items.at(-1);
|
|
860
|
+
if (o) o.raw = o.raw.trimEnd(), o.text = o.text.trimEnd();
|
|
861
|
+
else return;
|
|
862
|
+
i.raw = i.raw.trimEnd();
|
|
863
|
+
for (let p = 0; p < i.items.length; p++) if (this.lexer.state.top = false, i.items[p].tokens = this.lexer.blockTokens(i.items[p].text, []), !i.loose) {
|
|
864
|
+
let u = i.items[p].tokens.filter((g) => g.type === "space"), c = u.length > 0 && u.some((g) => this.rules.other.anyLine.test(g.raw));
|
|
865
|
+
i.loose = c;
|
|
866
|
+
}
|
|
867
|
+
if (i.loose) for (let p = 0; p < i.items.length; p++) i.items[p].loose = true;
|
|
868
|
+
return i;
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
html(e) {
|
|
872
|
+
let t = this.rules.block.html.exec(e);
|
|
873
|
+
if (t) return { type: "html", block: true, raw: t[0], pre: t[1] === "pre" || t[1] === "script" || t[1] === "style", text: t[0] };
|
|
874
|
+
}
|
|
875
|
+
def(e) {
|
|
876
|
+
let t = this.rules.block.def.exec(e);
|
|
877
|
+
if (t) {
|
|
878
|
+
let n = t[1].toLowerCase().replace(this.rules.other.multipleSpaceGlobal, " "), r = t[2] ? t[2].replace(this.rules.other.hrefBrackets, "$1").replace(this.rules.inline.anyPunctuation, "$1") : "", i = t[3] ? t[3].substring(1, t[3].length - 1).replace(this.rules.inline.anyPunctuation, "$1") : t[3];
|
|
879
|
+
return { type: "def", tag: n, raw: t[0], href: r, title: i };
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
table(e) {
|
|
883
|
+
let t = this.rules.block.table.exec(e);
|
|
884
|
+
if (!t || !this.rules.other.tableDelimiter.test(t[2])) return;
|
|
885
|
+
let n = V(t[1]), r = t[2].replace(this.rules.other.tableAlignChars, "").split("|"), i = t[3]?.trim() ? t[3].replace(this.rules.other.tableRowBlankLine, "").split(`
|
|
886
|
+
`) : [], s = { type: "table", raw: t[0], header: [], align: [], rows: [] };
|
|
887
|
+
if (n.length === r.length) {
|
|
888
|
+
for (let a of r) this.rules.other.tableAlignRight.test(a) ? s.align.push("right") : this.rules.other.tableAlignCenter.test(a) ? s.align.push("center") : this.rules.other.tableAlignLeft.test(a) ? s.align.push("left") : s.align.push(null);
|
|
889
|
+
for (let a = 0; a < n.length; a++) s.header.push({ text: n[a], tokens: this.lexer.inline(n[a]), header: true, align: s.align[a] });
|
|
890
|
+
for (let a of i) s.rows.push(V(a, s.header.length).map((o, p) => ({ text: o, tokens: this.lexer.inline(o), header: false, align: s.align[p] })));
|
|
891
|
+
return s;
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
lheading(e) {
|
|
895
|
+
let t = this.rules.block.lheading.exec(e);
|
|
896
|
+
if (t) return { type: "heading", raw: t[0], depth: t[2].charAt(0) === "=" ? 1 : 2, text: t[1], tokens: this.lexer.inline(t[1]) };
|
|
897
|
+
}
|
|
898
|
+
paragraph(e) {
|
|
899
|
+
let t = this.rules.block.paragraph.exec(e);
|
|
900
|
+
if (t) {
|
|
901
|
+
let n = t[1].charAt(t[1].length - 1) === `
|
|
902
|
+
` ? t[1].slice(0, -1) : t[1];
|
|
903
|
+
return { type: "paragraph", raw: t[0], text: n, tokens: this.lexer.inline(n) };
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
text(e) {
|
|
907
|
+
let t = this.rules.block.text.exec(e);
|
|
908
|
+
if (t) return { type: "text", raw: t[0], text: t[0], tokens: this.lexer.inline(t[0]) };
|
|
909
|
+
}
|
|
910
|
+
escape(e) {
|
|
911
|
+
let t = this.rules.inline.escape.exec(e);
|
|
912
|
+
if (t) return { type: "escape", raw: t[0], text: t[1] };
|
|
913
|
+
}
|
|
914
|
+
tag(e) {
|
|
915
|
+
let t = this.rules.inline.tag.exec(e);
|
|
916
|
+
if (t) return !this.lexer.state.inLink && this.rules.other.startATag.test(t[0]) ? this.lexer.state.inLink = true : this.lexer.state.inLink && this.rules.other.endATag.test(t[0]) && (this.lexer.state.inLink = false), !this.lexer.state.inRawBlock && this.rules.other.startPreScriptTag.test(t[0]) ? this.lexer.state.inRawBlock = true : this.lexer.state.inRawBlock && this.rules.other.endPreScriptTag.test(t[0]) && (this.lexer.state.inRawBlock = false), { type: "html", raw: t[0], inLink: this.lexer.state.inLink, inRawBlock: this.lexer.state.inRawBlock, block: false, text: t[0] };
|
|
917
|
+
}
|
|
918
|
+
link(e) {
|
|
919
|
+
let t = this.rules.inline.link.exec(e);
|
|
920
|
+
if (t) {
|
|
921
|
+
let n = t[2].trim();
|
|
922
|
+
if (!this.options.pedantic && this.rules.other.startAngleBracket.test(n)) {
|
|
923
|
+
if (!this.rules.other.endAngleBracket.test(n)) return;
|
|
924
|
+
let s = z(n.slice(0, -1), "\\");
|
|
925
|
+
if ((n.length - s.length) % 2 === 0) return;
|
|
926
|
+
} else {
|
|
927
|
+
let s = fe(t[2], "()");
|
|
928
|
+
if (s === -2) return;
|
|
929
|
+
if (s > -1) {
|
|
930
|
+
let o = (t[0].indexOf("!") === 0 ? 5 : 4) + t[1].length + s;
|
|
931
|
+
t[2] = t[2].substring(0, s), t[0] = t[0].substring(0, o).trim(), t[3] = "";
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
let r = t[2], i = "";
|
|
935
|
+
if (this.options.pedantic) {
|
|
936
|
+
let s = this.rules.other.pedanticHrefTitle.exec(r);
|
|
937
|
+
s && (r = s[1], i = s[3]);
|
|
938
|
+
} else i = t[3] ? t[3].slice(1, -1) : "";
|
|
939
|
+
return r = r.trim(), this.rules.other.startAngleBracket.test(r) && (this.options.pedantic && !this.rules.other.endAngleBracket.test(n) ? r = r.slice(1) : r = r.slice(1, -1)), me(t, { href: r && r.replace(this.rules.inline.anyPunctuation, "$1"), title: i && i.replace(this.rules.inline.anyPunctuation, "$1") }, t[0], this.lexer, this.rules);
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
reflink(e, t) {
|
|
943
|
+
let n;
|
|
944
|
+
if ((n = this.rules.inline.reflink.exec(e)) || (n = this.rules.inline.nolink.exec(e))) {
|
|
945
|
+
let r = (n[2] || n[1]).replace(this.rules.other.multipleSpaceGlobal, " "), i = t[r.toLowerCase()];
|
|
946
|
+
if (!i) {
|
|
947
|
+
let s = n[0].charAt(0);
|
|
948
|
+
return { type: "text", raw: s, text: s };
|
|
949
|
+
}
|
|
950
|
+
return me(n, i, n[0], this.lexer, this.rules);
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
emStrong(e, t, n = "") {
|
|
954
|
+
let r = this.rules.inline.emStrongLDelim.exec(e);
|
|
955
|
+
if (!r || r[3] && n.match(this.rules.other.unicodeAlphaNumeric)) return;
|
|
956
|
+
if (!(r[1] || r[2] || "") || !n || this.rules.inline.punctuation.exec(n)) {
|
|
957
|
+
let s = [...r[0]].length - 1, a, o, p = s, u = 0, c = r[0][0] === "*" ? this.rules.inline.emStrongRDelimAst : this.rules.inline.emStrongRDelimUnd;
|
|
958
|
+
for (c.lastIndex = 0, t = t.slice(-1 * e.length + s); (r = c.exec(t)) != null; ) {
|
|
959
|
+
if (a = r[1] || r[2] || r[3] || r[4] || r[5] || r[6], !a) continue;
|
|
960
|
+
if (o = [...a].length, r[3] || r[4]) {
|
|
961
|
+
p += o;
|
|
962
|
+
continue;
|
|
963
|
+
} else if ((r[5] || r[6]) && s % 3 && !((s + o) % 3)) {
|
|
964
|
+
u += o;
|
|
965
|
+
continue;
|
|
966
|
+
}
|
|
967
|
+
if (p -= o, p > 0) continue;
|
|
968
|
+
o = Math.min(o, o + p + u);
|
|
969
|
+
let g = [...r[0]][0].length, h = e.slice(0, s + r.index + g + o);
|
|
970
|
+
if (Math.min(s, o) % 2) {
|
|
971
|
+
let f = h.slice(1, -1);
|
|
972
|
+
return { type: "em", raw: h, text: f, tokens: this.lexer.inlineTokens(f) };
|
|
973
|
+
}
|
|
974
|
+
let R = h.slice(2, -2);
|
|
975
|
+
return { type: "strong", raw: h, text: R, tokens: this.lexer.inlineTokens(R) };
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
codespan(e) {
|
|
980
|
+
let t = this.rules.inline.code.exec(e);
|
|
981
|
+
if (t) {
|
|
982
|
+
let n = t[2].replace(this.rules.other.newLineCharGlobal, " "), r = this.rules.other.nonSpaceChar.test(n), i = this.rules.other.startingSpaceChar.test(n) && this.rules.other.endingSpaceChar.test(n);
|
|
983
|
+
return r && i && (n = n.substring(1, n.length - 1)), { type: "codespan", raw: t[0], text: n };
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
br(e) {
|
|
987
|
+
let t = this.rules.inline.br.exec(e);
|
|
988
|
+
if (t) return { type: "br", raw: t[0] };
|
|
989
|
+
}
|
|
990
|
+
del(e) {
|
|
991
|
+
let t = this.rules.inline.del.exec(e);
|
|
992
|
+
if (t) return { type: "del", raw: t[0], text: t[2], tokens: this.lexer.inlineTokens(t[2]) };
|
|
993
|
+
}
|
|
994
|
+
autolink(e) {
|
|
995
|
+
let t = this.rules.inline.autolink.exec(e);
|
|
996
|
+
if (t) {
|
|
997
|
+
let n, r;
|
|
998
|
+
return t[2] === "@" ? (n = t[1], r = "mailto:" + n) : (n = t[1], r = n), { type: "link", raw: t[0], text: n, href: r, tokens: [{ type: "text", raw: n, text: n }] };
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
url(e) {
|
|
1002
|
+
let t;
|
|
1003
|
+
if (t = this.rules.inline.url.exec(e)) {
|
|
1004
|
+
let n, r;
|
|
1005
|
+
if (t[2] === "@") n = t[0], r = "mailto:" + n;
|
|
1006
|
+
else {
|
|
1007
|
+
let i;
|
|
1008
|
+
do
|
|
1009
|
+
i = t[0], t[0] = this.rules.inline._backpedal.exec(t[0])?.[0] ?? "";
|
|
1010
|
+
while (i !== t[0]);
|
|
1011
|
+
n = t[0], t[1] === "www." ? r = "http://" + t[0] : r = t[0];
|
|
1012
|
+
}
|
|
1013
|
+
return { type: "link", raw: t[0], text: n, href: r, tokens: [{ type: "text", raw: n, text: n }] };
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
inlineText(e) {
|
|
1017
|
+
let t = this.rules.inline.text.exec(e);
|
|
1018
|
+
if (t) {
|
|
1019
|
+
let n = this.lexer.state.inRawBlock;
|
|
1020
|
+
return { type: "text", raw: t[0], text: t[0], escaped: n };
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
};
|
|
1024
|
+
var x = class l {
|
|
1025
|
+
tokens;
|
|
1026
|
+
options;
|
|
1027
|
+
state;
|
|
1028
|
+
tokenizer;
|
|
1029
|
+
inlineQueue;
|
|
1030
|
+
constructor(e) {
|
|
1031
|
+
this.tokens = [], this.tokens.links = /* @__PURE__ */ Object.create(null), this.options = e || T, this.options.tokenizer = this.options.tokenizer || new y(), this.tokenizer = this.options.tokenizer, this.tokenizer.options = this.options, this.tokenizer.lexer = this, this.inlineQueue = [], this.state = { inLink: false, inRawBlock: false, top: true };
|
|
1032
|
+
let t = { other: m, block: C.normal, inline: M.normal };
|
|
1033
|
+
this.options.pedantic ? (t.block = C.pedantic, t.inline = M.pedantic) : this.options.gfm && (t.block = C.gfm, this.options.breaks ? t.inline = M.breaks : t.inline = M.gfm), this.tokenizer.rules = t;
|
|
1034
|
+
}
|
|
1035
|
+
static get rules() {
|
|
1036
|
+
return { block: C, inline: M };
|
|
1037
|
+
}
|
|
1038
|
+
static lex(e, t) {
|
|
1039
|
+
return new l(t).lex(e);
|
|
1040
|
+
}
|
|
1041
|
+
static lexInline(e, t) {
|
|
1042
|
+
return new l(t).inlineTokens(e);
|
|
1043
|
+
}
|
|
1044
|
+
lex(e) {
|
|
1045
|
+
e = e.replace(m.carriageReturn, `
|
|
1046
|
+
`), this.blockTokens(e, this.tokens);
|
|
1047
|
+
for (let t = 0; t < this.inlineQueue.length; t++) {
|
|
1048
|
+
let n = this.inlineQueue[t];
|
|
1049
|
+
this.inlineTokens(n.src, n.tokens);
|
|
1050
|
+
}
|
|
1051
|
+
return this.inlineQueue = [], this.tokens;
|
|
1052
|
+
}
|
|
1053
|
+
blockTokens(e, t = [], n = false) {
|
|
1054
|
+
for (this.options.pedantic && (e = e.replace(m.tabCharGlobal, " ").replace(m.spaceLine, "")); e; ) {
|
|
1055
|
+
let r;
|
|
1056
|
+
if (this.options.extensions?.block?.some((s) => (r = s.call({ lexer: this }, e, t)) ? (e = e.substring(r.raw.length), t.push(r), true) : false)) continue;
|
|
1057
|
+
if (r = this.tokenizer.space(e)) {
|
|
1058
|
+
e = e.substring(r.raw.length);
|
|
1059
|
+
let s = t.at(-1);
|
|
1060
|
+
r.raw.length === 1 && s !== void 0 ? s.raw += `
|
|
1061
|
+
` : t.push(r);
|
|
1062
|
+
continue;
|
|
1063
|
+
}
|
|
1064
|
+
if (r = this.tokenizer.code(e)) {
|
|
1065
|
+
e = e.substring(r.raw.length);
|
|
1066
|
+
let s = t.at(-1);
|
|
1067
|
+
s?.type === "paragraph" || s?.type === "text" ? (s.raw += (s.raw.endsWith(`
|
|
1068
|
+
`) ? "" : `
|
|
1069
|
+
`) + r.raw, s.text += `
|
|
1070
|
+
` + r.text, this.inlineQueue.at(-1).src = s.text) : t.push(r);
|
|
1071
|
+
continue;
|
|
1072
|
+
}
|
|
1073
|
+
if (r = this.tokenizer.fences(e)) {
|
|
1074
|
+
e = e.substring(r.raw.length), t.push(r);
|
|
1075
|
+
continue;
|
|
1076
|
+
}
|
|
1077
|
+
if (r = this.tokenizer.heading(e)) {
|
|
1078
|
+
e = e.substring(r.raw.length), t.push(r);
|
|
1079
|
+
continue;
|
|
1080
|
+
}
|
|
1081
|
+
if (r = this.tokenizer.hr(e)) {
|
|
1082
|
+
e = e.substring(r.raw.length), t.push(r);
|
|
1083
|
+
continue;
|
|
1084
|
+
}
|
|
1085
|
+
if (r = this.tokenizer.blockquote(e)) {
|
|
1086
|
+
e = e.substring(r.raw.length), t.push(r);
|
|
1087
|
+
continue;
|
|
1088
|
+
}
|
|
1089
|
+
if (r = this.tokenizer.list(e)) {
|
|
1090
|
+
e = e.substring(r.raw.length), t.push(r);
|
|
1091
|
+
continue;
|
|
1092
|
+
}
|
|
1093
|
+
if (r = this.tokenizer.html(e)) {
|
|
1094
|
+
e = e.substring(r.raw.length), t.push(r);
|
|
1095
|
+
continue;
|
|
1096
|
+
}
|
|
1097
|
+
if (r = this.tokenizer.def(e)) {
|
|
1098
|
+
e = e.substring(r.raw.length);
|
|
1099
|
+
let s = t.at(-1);
|
|
1100
|
+
s?.type === "paragraph" || s?.type === "text" ? (s.raw += (s.raw.endsWith(`
|
|
1101
|
+
`) ? "" : `
|
|
1102
|
+
`) + r.raw, s.text += `
|
|
1103
|
+
` + r.raw, this.inlineQueue.at(-1).src = s.text) : this.tokens.links[r.tag] || (this.tokens.links[r.tag] = { href: r.href, title: r.title }, t.push(r));
|
|
1104
|
+
continue;
|
|
1105
|
+
}
|
|
1106
|
+
if (r = this.tokenizer.table(e)) {
|
|
1107
|
+
e = e.substring(r.raw.length), t.push(r);
|
|
1108
|
+
continue;
|
|
1109
|
+
}
|
|
1110
|
+
if (r = this.tokenizer.lheading(e)) {
|
|
1111
|
+
e = e.substring(r.raw.length), t.push(r);
|
|
1112
|
+
continue;
|
|
1113
|
+
}
|
|
1114
|
+
let i = e;
|
|
1115
|
+
if (this.options.extensions?.startBlock) {
|
|
1116
|
+
let s = 1 / 0, a = e.slice(1), o;
|
|
1117
|
+
this.options.extensions.startBlock.forEach((p) => {
|
|
1118
|
+
o = p.call({ lexer: this }, a), typeof o == "number" && o >= 0 && (s = Math.min(s, o));
|
|
1119
|
+
}), s < 1 / 0 && s >= 0 && (i = e.substring(0, s + 1));
|
|
1120
|
+
}
|
|
1121
|
+
if (this.state.top && (r = this.tokenizer.paragraph(i))) {
|
|
1122
|
+
let s = t.at(-1);
|
|
1123
|
+
n && s?.type === "paragraph" ? (s.raw += (s.raw.endsWith(`
|
|
1124
|
+
`) ? "" : `
|
|
1125
|
+
`) + r.raw, s.text += `
|
|
1126
|
+
` + r.text, this.inlineQueue.pop(), this.inlineQueue.at(-1).src = s.text) : t.push(r), n = i.length !== e.length, e = e.substring(r.raw.length);
|
|
1127
|
+
continue;
|
|
1128
|
+
}
|
|
1129
|
+
if (r = this.tokenizer.text(e)) {
|
|
1130
|
+
e = e.substring(r.raw.length);
|
|
1131
|
+
let s = t.at(-1);
|
|
1132
|
+
s?.type === "text" ? (s.raw += (s.raw.endsWith(`
|
|
1133
|
+
`) ? "" : `
|
|
1134
|
+
`) + r.raw, s.text += `
|
|
1135
|
+
` + r.text, this.inlineQueue.pop(), this.inlineQueue.at(-1).src = s.text) : t.push(r);
|
|
1136
|
+
continue;
|
|
1137
|
+
}
|
|
1138
|
+
if (e) {
|
|
1139
|
+
let s = "Infinite loop on byte: " + e.charCodeAt(0);
|
|
1140
|
+
if (this.options.silent) {
|
|
1141
|
+
console.error(s);
|
|
1142
|
+
break;
|
|
1143
|
+
} else throw new Error(s);
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
return this.state.top = true, t;
|
|
1147
|
+
}
|
|
1148
|
+
inline(e, t = []) {
|
|
1149
|
+
return this.inlineQueue.push({ src: e, tokens: t }), t;
|
|
1150
|
+
}
|
|
1151
|
+
inlineTokens(e, t = []) {
|
|
1152
|
+
let n = e, r = null;
|
|
1153
|
+
if (this.tokens.links) {
|
|
1154
|
+
let o = Object.keys(this.tokens.links);
|
|
1155
|
+
if (o.length > 0) for (; (r = this.tokenizer.rules.inline.reflinkSearch.exec(n)) != null; ) o.includes(r[0].slice(r[0].lastIndexOf("[") + 1, -1)) && (n = n.slice(0, r.index) + "[" + "a".repeat(r[0].length - 2) + "]" + n.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex));
|
|
1156
|
+
}
|
|
1157
|
+
for (; (r = this.tokenizer.rules.inline.anyPunctuation.exec(n)) != null; ) n = n.slice(0, r.index) + "++" + n.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex);
|
|
1158
|
+
let i;
|
|
1159
|
+
for (; (r = this.tokenizer.rules.inline.blockSkip.exec(n)) != null; ) i = r[2] ? r[2].length : 0, n = n.slice(0, r.index + i) + "[" + "a".repeat(r[0].length - i - 2) + "]" + n.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);
|
|
1160
|
+
n = this.options.hooks?.emStrongMask?.call({ lexer: this }, n) ?? n;
|
|
1161
|
+
let s = false, a = "";
|
|
1162
|
+
for (; e; ) {
|
|
1163
|
+
s || (a = ""), s = false;
|
|
1164
|
+
let o;
|
|
1165
|
+
if (this.options.extensions?.inline?.some((u) => (o = u.call({ lexer: this }, e, t)) ? (e = e.substring(o.raw.length), t.push(o), true) : false)) continue;
|
|
1166
|
+
if (o = this.tokenizer.escape(e)) {
|
|
1167
|
+
e = e.substring(o.raw.length), t.push(o);
|
|
1168
|
+
continue;
|
|
1169
|
+
}
|
|
1170
|
+
if (o = this.tokenizer.tag(e)) {
|
|
1171
|
+
e = e.substring(o.raw.length), t.push(o);
|
|
1172
|
+
continue;
|
|
1173
|
+
}
|
|
1174
|
+
if (o = this.tokenizer.link(e)) {
|
|
1175
|
+
e = e.substring(o.raw.length), t.push(o);
|
|
1176
|
+
continue;
|
|
1177
|
+
}
|
|
1178
|
+
if (o = this.tokenizer.reflink(e, this.tokens.links)) {
|
|
1179
|
+
e = e.substring(o.raw.length);
|
|
1180
|
+
let u = t.at(-1);
|
|
1181
|
+
o.type === "text" && u?.type === "text" ? (u.raw += o.raw, u.text += o.text) : t.push(o);
|
|
1182
|
+
continue;
|
|
1183
|
+
}
|
|
1184
|
+
if (o = this.tokenizer.emStrong(e, n, a)) {
|
|
1185
|
+
e = e.substring(o.raw.length), t.push(o);
|
|
1186
|
+
continue;
|
|
1187
|
+
}
|
|
1188
|
+
if (o = this.tokenizer.codespan(e)) {
|
|
1189
|
+
e = e.substring(o.raw.length), t.push(o);
|
|
1190
|
+
continue;
|
|
1191
|
+
}
|
|
1192
|
+
if (o = this.tokenizer.br(e)) {
|
|
1193
|
+
e = e.substring(o.raw.length), t.push(o);
|
|
1194
|
+
continue;
|
|
1195
|
+
}
|
|
1196
|
+
if (o = this.tokenizer.del(e)) {
|
|
1197
|
+
e = e.substring(o.raw.length), t.push(o);
|
|
1198
|
+
continue;
|
|
1199
|
+
}
|
|
1200
|
+
if (o = this.tokenizer.autolink(e)) {
|
|
1201
|
+
e = e.substring(o.raw.length), t.push(o);
|
|
1202
|
+
continue;
|
|
1203
|
+
}
|
|
1204
|
+
if (!this.state.inLink && (o = this.tokenizer.url(e))) {
|
|
1205
|
+
e = e.substring(o.raw.length), t.push(o);
|
|
1206
|
+
continue;
|
|
1207
|
+
}
|
|
1208
|
+
let p = e;
|
|
1209
|
+
if (this.options.extensions?.startInline) {
|
|
1210
|
+
let u = 1 / 0, c = e.slice(1), g;
|
|
1211
|
+
this.options.extensions.startInline.forEach((h) => {
|
|
1212
|
+
g = h.call({ lexer: this }, c), typeof g == "number" && g >= 0 && (u = Math.min(u, g));
|
|
1213
|
+
}), u < 1 / 0 && u >= 0 && (p = e.substring(0, u + 1));
|
|
1214
|
+
}
|
|
1215
|
+
if (o = this.tokenizer.inlineText(p)) {
|
|
1216
|
+
e = e.substring(o.raw.length), o.raw.slice(-1) !== "_" && (a = o.raw.slice(-1)), s = true;
|
|
1217
|
+
let u = t.at(-1);
|
|
1218
|
+
u?.type === "text" ? (u.raw += o.raw, u.text += o.text) : t.push(o);
|
|
1219
|
+
continue;
|
|
1220
|
+
}
|
|
1221
|
+
if (e) {
|
|
1222
|
+
let u = "Infinite loop on byte: " + e.charCodeAt(0);
|
|
1223
|
+
if (this.options.silent) {
|
|
1224
|
+
console.error(u);
|
|
1225
|
+
break;
|
|
1226
|
+
} else throw new Error(u);
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
return t;
|
|
1230
|
+
}
|
|
1231
|
+
};
|
|
1232
|
+
var P = class {
|
|
1233
|
+
options;
|
|
1234
|
+
parser;
|
|
1235
|
+
constructor(e) {
|
|
1236
|
+
this.options = e || T;
|
|
1237
|
+
}
|
|
1238
|
+
space(e) {
|
|
1239
|
+
return "";
|
|
1240
|
+
}
|
|
1241
|
+
code({ text: e, lang: t, escaped: n }) {
|
|
1242
|
+
let r = (t || "").match(m.notSpaceStart)?.[0], i = e.replace(m.endingNewline, "") + `
|
|
1243
|
+
`;
|
|
1244
|
+
return r ? '<pre><code class="language-' + w(r) + '">' + (n ? i : w(i, true)) + `</code></pre>
|
|
1245
|
+
` : "<pre><code>" + (n ? i : w(i, true)) + `</code></pre>
|
|
1246
|
+
`;
|
|
1247
|
+
}
|
|
1248
|
+
blockquote({ tokens: e }) {
|
|
1249
|
+
return `<blockquote>
|
|
1250
|
+
${this.parser.parse(e)}</blockquote>
|
|
1251
|
+
`;
|
|
1252
|
+
}
|
|
1253
|
+
html({ text: e }) {
|
|
1254
|
+
return e;
|
|
1255
|
+
}
|
|
1256
|
+
def(e) {
|
|
1257
|
+
return "";
|
|
1258
|
+
}
|
|
1259
|
+
heading({ tokens: e, depth: t }) {
|
|
1260
|
+
return `<h${t}>${this.parser.parseInline(e)}</h${t}>
|
|
1261
|
+
`;
|
|
1262
|
+
}
|
|
1263
|
+
hr(e) {
|
|
1264
|
+
return `<hr>
|
|
1265
|
+
`;
|
|
1266
|
+
}
|
|
1267
|
+
list(e) {
|
|
1268
|
+
let t = e.ordered, n = e.start, r = "";
|
|
1269
|
+
for (let a = 0; a < e.items.length; a++) {
|
|
1270
|
+
let o = e.items[a];
|
|
1271
|
+
r += this.listitem(o);
|
|
1272
|
+
}
|
|
1273
|
+
let i = t ? "ol" : "ul", s = t && n !== 1 ? ' start="' + n + '"' : "";
|
|
1274
|
+
return "<" + i + s + `>
|
|
1275
|
+
` + r + "</" + i + `>
|
|
1276
|
+
`;
|
|
1277
|
+
}
|
|
1278
|
+
listitem(e) {
|
|
1279
|
+
let t = "";
|
|
1280
|
+
if (e.task) {
|
|
1281
|
+
let n = this.checkbox({ checked: !!e.checked });
|
|
1282
|
+
e.loose ? e.tokens[0]?.type === "paragraph" ? (e.tokens[0].text = n + " " + e.tokens[0].text, e.tokens[0].tokens && e.tokens[0].tokens.length > 0 && e.tokens[0].tokens[0].type === "text" && (e.tokens[0].tokens[0].text = n + " " + w(e.tokens[0].tokens[0].text), e.tokens[0].tokens[0].escaped = true)) : e.tokens.unshift({ type: "text", raw: n + " ", text: n + " ", escaped: true }) : t += n + " ";
|
|
1283
|
+
}
|
|
1284
|
+
return t += this.parser.parse(e.tokens, !!e.loose), `<li>${t}</li>
|
|
1285
|
+
`;
|
|
1286
|
+
}
|
|
1287
|
+
checkbox({ checked: e }) {
|
|
1288
|
+
return "<input " + (e ? 'checked="" ' : "") + 'disabled="" type="checkbox">';
|
|
1289
|
+
}
|
|
1290
|
+
paragraph({ tokens: e }) {
|
|
1291
|
+
return `<p>${this.parser.parseInline(e)}</p>
|
|
1292
|
+
`;
|
|
1293
|
+
}
|
|
1294
|
+
table(e) {
|
|
1295
|
+
let t = "", n = "";
|
|
1296
|
+
for (let i = 0; i < e.header.length; i++) n += this.tablecell(e.header[i]);
|
|
1297
|
+
t += this.tablerow({ text: n });
|
|
1298
|
+
let r = "";
|
|
1299
|
+
for (let i = 0; i < e.rows.length; i++) {
|
|
1300
|
+
let s = e.rows[i];
|
|
1301
|
+
n = "";
|
|
1302
|
+
for (let a = 0; a < s.length; a++) n += this.tablecell(s[a]);
|
|
1303
|
+
r += this.tablerow({ text: n });
|
|
1304
|
+
}
|
|
1305
|
+
return r && (r = `<tbody>${r}</tbody>`), `<table>
|
|
1306
|
+
<thead>
|
|
1307
|
+
` + t + `</thead>
|
|
1308
|
+
` + r + `</table>
|
|
1309
|
+
`;
|
|
1310
|
+
}
|
|
1311
|
+
tablerow({ text: e }) {
|
|
1312
|
+
return `<tr>
|
|
1313
|
+
${e}</tr>
|
|
1314
|
+
`;
|
|
1315
|
+
}
|
|
1316
|
+
tablecell(e) {
|
|
1317
|
+
let t = this.parser.parseInline(e.tokens), n = e.header ? "th" : "td";
|
|
1318
|
+
return (e.align ? `<${n} align="${e.align}">` : `<${n}>`) + t + `</${n}>
|
|
1319
|
+
`;
|
|
1320
|
+
}
|
|
1321
|
+
strong({ tokens: e }) {
|
|
1322
|
+
return `<strong>${this.parser.parseInline(e)}</strong>`;
|
|
1323
|
+
}
|
|
1324
|
+
em({ tokens: e }) {
|
|
1325
|
+
return `<em>${this.parser.parseInline(e)}</em>`;
|
|
1326
|
+
}
|
|
1327
|
+
codespan({ text: e }) {
|
|
1328
|
+
return `<code>${w(e, true)}</code>`;
|
|
1329
|
+
}
|
|
1330
|
+
br(e) {
|
|
1331
|
+
return "<br>";
|
|
1332
|
+
}
|
|
1333
|
+
del({ tokens: e }) {
|
|
1334
|
+
return `<del>${this.parser.parseInline(e)}</del>`;
|
|
1335
|
+
}
|
|
1336
|
+
link({ href: e, title: t, tokens: n }) {
|
|
1337
|
+
let r = this.parser.parseInline(n), i = J(e);
|
|
1338
|
+
if (i === null) return r;
|
|
1339
|
+
e = i;
|
|
1340
|
+
let s = '<a href="' + e + '"';
|
|
1341
|
+
return t && (s += ' title="' + w(t) + '"'), s += ">" + r + "</a>", s;
|
|
1342
|
+
}
|
|
1343
|
+
image({ href: e, title: t, text: n, tokens: r }) {
|
|
1344
|
+
r && (n = this.parser.parseInline(r, this.parser.textRenderer));
|
|
1345
|
+
let i = J(e);
|
|
1346
|
+
if (i === null) return w(n);
|
|
1347
|
+
e = i;
|
|
1348
|
+
let s = `<img src="${e}" alt="${n}"`;
|
|
1349
|
+
return t && (s += ` title="${w(t)}"`), s += ">", s;
|
|
1350
|
+
}
|
|
1351
|
+
text(e) {
|
|
1352
|
+
return "tokens" in e && e.tokens ? this.parser.parseInline(e.tokens) : "escaped" in e && e.escaped ? e.text : w(e.text);
|
|
1353
|
+
}
|
|
1354
|
+
};
|
|
1355
|
+
var $ = class {
|
|
1356
|
+
strong({ text: e }) {
|
|
1357
|
+
return e;
|
|
1358
|
+
}
|
|
1359
|
+
em({ text: e }) {
|
|
1360
|
+
return e;
|
|
1361
|
+
}
|
|
1362
|
+
codespan({ text: e }) {
|
|
1363
|
+
return e;
|
|
1364
|
+
}
|
|
1365
|
+
del({ text: e }) {
|
|
1366
|
+
return e;
|
|
1367
|
+
}
|
|
1368
|
+
html({ text: e }) {
|
|
1369
|
+
return e;
|
|
1370
|
+
}
|
|
1371
|
+
text({ text: e }) {
|
|
1372
|
+
return e;
|
|
1373
|
+
}
|
|
1374
|
+
link({ text: e }) {
|
|
1375
|
+
return "" + e;
|
|
1376
|
+
}
|
|
1377
|
+
image({ text: e }) {
|
|
1378
|
+
return "" + e;
|
|
1379
|
+
}
|
|
1380
|
+
br() {
|
|
1381
|
+
return "";
|
|
1382
|
+
}
|
|
1383
|
+
};
|
|
1384
|
+
var b = class l2 {
|
|
1385
|
+
options;
|
|
1386
|
+
renderer;
|
|
1387
|
+
textRenderer;
|
|
1388
|
+
constructor(e) {
|
|
1389
|
+
this.options = e || T, this.options.renderer = this.options.renderer || new P(), this.renderer = this.options.renderer, this.renderer.options = this.options, this.renderer.parser = this, this.textRenderer = new $();
|
|
1390
|
+
}
|
|
1391
|
+
static parse(e, t) {
|
|
1392
|
+
return new l2(t).parse(e);
|
|
1393
|
+
}
|
|
1394
|
+
static parseInline(e, t) {
|
|
1395
|
+
return new l2(t).parseInline(e);
|
|
1396
|
+
}
|
|
1397
|
+
parse(e, t = true) {
|
|
1398
|
+
let n = "";
|
|
1399
|
+
for (let r = 0; r < e.length; r++) {
|
|
1400
|
+
let i = e[r];
|
|
1401
|
+
if (this.options.extensions?.renderers?.[i.type]) {
|
|
1402
|
+
let a = i, o = this.options.extensions.renderers[a.type].call({ parser: this }, a);
|
|
1403
|
+
if (o !== false || !["space", "hr", "heading", "code", "table", "blockquote", "list", "html", "def", "paragraph", "text"].includes(a.type)) {
|
|
1404
|
+
n += o || "";
|
|
1405
|
+
continue;
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
let s = i;
|
|
1409
|
+
switch (s.type) {
|
|
1410
|
+
case "space": {
|
|
1411
|
+
n += this.renderer.space(s);
|
|
1412
|
+
continue;
|
|
1413
|
+
}
|
|
1414
|
+
case "hr": {
|
|
1415
|
+
n += this.renderer.hr(s);
|
|
1416
|
+
continue;
|
|
1417
|
+
}
|
|
1418
|
+
case "heading": {
|
|
1419
|
+
n += this.renderer.heading(s);
|
|
1420
|
+
continue;
|
|
1421
|
+
}
|
|
1422
|
+
case "code": {
|
|
1423
|
+
n += this.renderer.code(s);
|
|
1424
|
+
continue;
|
|
1425
|
+
}
|
|
1426
|
+
case "table": {
|
|
1427
|
+
n += this.renderer.table(s);
|
|
1428
|
+
continue;
|
|
1429
|
+
}
|
|
1430
|
+
case "blockquote": {
|
|
1431
|
+
n += this.renderer.blockquote(s);
|
|
1432
|
+
continue;
|
|
1433
|
+
}
|
|
1434
|
+
case "list": {
|
|
1435
|
+
n += this.renderer.list(s);
|
|
1436
|
+
continue;
|
|
1437
|
+
}
|
|
1438
|
+
case "html": {
|
|
1439
|
+
n += this.renderer.html(s);
|
|
1440
|
+
continue;
|
|
1441
|
+
}
|
|
1442
|
+
case "def": {
|
|
1443
|
+
n += this.renderer.def(s);
|
|
1444
|
+
continue;
|
|
1445
|
+
}
|
|
1446
|
+
case "paragraph": {
|
|
1447
|
+
n += this.renderer.paragraph(s);
|
|
1448
|
+
continue;
|
|
1449
|
+
}
|
|
1450
|
+
case "text": {
|
|
1451
|
+
let a = s, o = this.renderer.text(a);
|
|
1452
|
+
for (; r + 1 < e.length && e[r + 1].type === "text"; ) a = e[++r], o += `
|
|
1453
|
+
` + this.renderer.text(a);
|
|
1454
|
+
t ? n += this.renderer.paragraph({ type: "paragraph", raw: o, text: o, tokens: [{ type: "text", raw: o, text: o, escaped: true }] }) : n += o;
|
|
1455
|
+
continue;
|
|
1456
|
+
}
|
|
1457
|
+
default: {
|
|
1458
|
+
let a = 'Token with "' + s.type + '" type was not found.';
|
|
1459
|
+
if (this.options.silent) return console.error(a), "";
|
|
1460
|
+
throw new Error(a);
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
return n;
|
|
1465
|
+
}
|
|
1466
|
+
parseInline(e, t = this.renderer) {
|
|
1467
|
+
let n = "";
|
|
1468
|
+
for (let r = 0; r < e.length; r++) {
|
|
1469
|
+
let i = e[r];
|
|
1470
|
+
if (this.options.extensions?.renderers?.[i.type]) {
|
|
1471
|
+
let a = this.options.extensions.renderers[i.type].call({ parser: this }, i);
|
|
1472
|
+
if (a !== false || !["escape", "html", "link", "image", "strong", "em", "codespan", "br", "del", "text"].includes(i.type)) {
|
|
1473
|
+
n += a || "";
|
|
1474
|
+
continue;
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
let s = i;
|
|
1478
|
+
switch (s.type) {
|
|
1479
|
+
case "escape": {
|
|
1480
|
+
n += t.text(s);
|
|
1481
|
+
break;
|
|
1482
|
+
}
|
|
1483
|
+
case "html": {
|
|
1484
|
+
n += t.html(s);
|
|
1485
|
+
break;
|
|
1486
|
+
}
|
|
1487
|
+
case "link": {
|
|
1488
|
+
n += t.link(s);
|
|
1489
|
+
break;
|
|
1490
|
+
}
|
|
1491
|
+
case "image": {
|
|
1492
|
+
n += t.image(s);
|
|
1493
|
+
break;
|
|
1494
|
+
}
|
|
1495
|
+
case "strong": {
|
|
1496
|
+
n += t.strong(s);
|
|
1497
|
+
break;
|
|
1498
|
+
}
|
|
1499
|
+
case "em": {
|
|
1500
|
+
n += t.em(s);
|
|
1501
|
+
break;
|
|
1502
|
+
}
|
|
1503
|
+
case "codespan": {
|
|
1504
|
+
n += t.codespan(s);
|
|
1505
|
+
break;
|
|
1506
|
+
}
|
|
1507
|
+
case "br": {
|
|
1508
|
+
n += t.br(s);
|
|
1509
|
+
break;
|
|
1510
|
+
}
|
|
1511
|
+
case "del": {
|
|
1512
|
+
n += t.del(s);
|
|
1513
|
+
break;
|
|
1514
|
+
}
|
|
1515
|
+
case "text": {
|
|
1516
|
+
n += t.text(s);
|
|
1517
|
+
break;
|
|
1518
|
+
}
|
|
1519
|
+
default: {
|
|
1520
|
+
let a = 'Token with "' + s.type + '" type was not found.';
|
|
1521
|
+
if (this.options.silent) return console.error(a), "";
|
|
1522
|
+
throw new Error(a);
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
return n;
|
|
1527
|
+
}
|
|
1528
|
+
};
|
|
1529
|
+
var S = class {
|
|
1530
|
+
options;
|
|
1531
|
+
block;
|
|
1532
|
+
constructor(e) {
|
|
1533
|
+
this.options = e || T;
|
|
1534
|
+
}
|
|
1535
|
+
static passThroughHooks = /* @__PURE__ */ new Set(["preprocess", "postprocess", "processAllTokens", "emStrongMask"]);
|
|
1536
|
+
static passThroughHooksRespectAsync = /* @__PURE__ */ new Set(["preprocess", "postprocess", "processAllTokens"]);
|
|
1537
|
+
preprocess(e) {
|
|
1538
|
+
return e;
|
|
1539
|
+
}
|
|
1540
|
+
postprocess(e) {
|
|
1541
|
+
return e;
|
|
1542
|
+
}
|
|
1543
|
+
processAllTokens(e) {
|
|
1544
|
+
return e;
|
|
1545
|
+
}
|
|
1546
|
+
emStrongMask(e) {
|
|
1547
|
+
return e;
|
|
1548
|
+
}
|
|
1549
|
+
provideLexer() {
|
|
1550
|
+
return this.block ? x.lex : x.lexInline;
|
|
1551
|
+
}
|
|
1552
|
+
provideParser() {
|
|
1553
|
+
return this.block ? b.parse : b.parseInline;
|
|
1554
|
+
}
|
|
1555
|
+
};
|
|
1556
|
+
var B = class {
|
|
1557
|
+
defaults = L();
|
|
1558
|
+
options = this.setOptions;
|
|
1559
|
+
parse = this.parseMarkdown(true);
|
|
1560
|
+
parseInline = this.parseMarkdown(false);
|
|
1561
|
+
Parser = b;
|
|
1562
|
+
Renderer = P;
|
|
1563
|
+
TextRenderer = $;
|
|
1564
|
+
Lexer = x;
|
|
1565
|
+
Tokenizer = y;
|
|
1566
|
+
Hooks = S;
|
|
1567
|
+
constructor(...e) {
|
|
1568
|
+
this.use(...e);
|
|
1569
|
+
}
|
|
1570
|
+
walkTokens(e, t) {
|
|
1571
|
+
let n = [];
|
|
1572
|
+
for (let r of e) switch (n = n.concat(t.call(this, r)), r.type) {
|
|
1573
|
+
case "table": {
|
|
1574
|
+
let i = r;
|
|
1575
|
+
for (let s of i.header) n = n.concat(this.walkTokens(s.tokens, t));
|
|
1576
|
+
for (let s of i.rows) for (let a of s) n = n.concat(this.walkTokens(a.tokens, t));
|
|
1577
|
+
break;
|
|
1578
|
+
}
|
|
1579
|
+
case "list": {
|
|
1580
|
+
let i = r;
|
|
1581
|
+
n = n.concat(this.walkTokens(i.items, t));
|
|
1582
|
+
break;
|
|
1583
|
+
}
|
|
1584
|
+
default: {
|
|
1585
|
+
let i = r;
|
|
1586
|
+
this.defaults.extensions?.childTokens?.[i.type] ? this.defaults.extensions.childTokens[i.type].forEach((s) => {
|
|
1587
|
+
let a = i[s].flat(1 / 0);
|
|
1588
|
+
n = n.concat(this.walkTokens(a, t));
|
|
1589
|
+
}) : i.tokens && (n = n.concat(this.walkTokens(i.tokens, t)));
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
return n;
|
|
1593
|
+
}
|
|
1594
|
+
use(...e) {
|
|
1595
|
+
let t = this.defaults.extensions || { renderers: {}, childTokens: {} };
|
|
1596
|
+
return e.forEach((n) => {
|
|
1597
|
+
let r = { ...n };
|
|
1598
|
+
if (r.async = this.defaults.async || r.async || false, n.extensions && (n.extensions.forEach((i) => {
|
|
1599
|
+
if (!i.name) throw new Error("extension name required");
|
|
1600
|
+
if ("renderer" in i) {
|
|
1601
|
+
let s = t.renderers[i.name];
|
|
1602
|
+
s ? t.renderers[i.name] = function(...a) {
|
|
1603
|
+
let o = i.renderer.apply(this, a);
|
|
1604
|
+
return o === false && (o = s.apply(this, a)), o;
|
|
1605
|
+
} : t.renderers[i.name] = i.renderer;
|
|
1606
|
+
}
|
|
1607
|
+
if ("tokenizer" in i) {
|
|
1608
|
+
if (!i.level || i.level !== "block" && i.level !== "inline") throw new Error("extension level must be 'block' or 'inline'");
|
|
1609
|
+
let s = t[i.level];
|
|
1610
|
+
s ? s.unshift(i.tokenizer) : t[i.level] = [i.tokenizer], i.start && (i.level === "block" ? t.startBlock ? t.startBlock.push(i.start) : t.startBlock = [i.start] : i.level === "inline" && (t.startInline ? t.startInline.push(i.start) : t.startInline = [i.start]));
|
|
1611
|
+
}
|
|
1612
|
+
"childTokens" in i && i.childTokens && (t.childTokens[i.name] = i.childTokens);
|
|
1613
|
+
}), r.extensions = t), n.renderer) {
|
|
1614
|
+
let i = this.defaults.renderer || new P(this.defaults);
|
|
1615
|
+
for (let s in n.renderer) {
|
|
1616
|
+
if (!(s in i)) throw new Error(`renderer '${s}' does not exist`);
|
|
1617
|
+
if (["options", "parser"].includes(s)) continue;
|
|
1618
|
+
let a = s, o = n.renderer[a], p = i[a];
|
|
1619
|
+
i[a] = (...u) => {
|
|
1620
|
+
let c = o.apply(i, u);
|
|
1621
|
+
return c === false && (c = p.apply(i, u)), c || "";
|
|
1622
|
+
};
|
|
1623
|
+
}
|
|
1624
|
+
r.renderer = i;
|
|
1625
|
+
}
|
|
1626
|
+
if (n.tokenizer) {
|
|
1627
|
+
let i = this.defaults.tokenizer || new y(this.defaults);
|
|
1628
|
+
for (let s in n.tokenizer) {
|
|
1629
|
+
if (!(s in i)) throw new Error(`tokenizer '${s}' does not exist`);
|
|
1630
|
+
if (["options", "rules", "lexer"].includes(s)) continue;
|
|
1631
|
+
let a = s, o = n.tokenizer[a], p = i[a];
|
|
1632
|
+
i[a] = (...u) => {
|
|
1633
|
+
let c = o.apply(i, u);
|
|
1634
|
+
return c === false && (c = p.apply(i, u)), c;
|
|
1635
|
+
};
|
|
1636
|
+
}
|
|
1637
|
+
r.tokenizer = i;
|
|
1638
|
+
}
|
|
1639
|
+
if (n.hooks) {
|
|
1640
|
+
let i = this.defaults.hooks || new S();
|
|
1641
|
+
for (let s in n.hooks) {
|
|
1642
|
+
if (!(s in i)) throw new Error(`hook '${s}' does not exist`);
|
|
1643
|
+
if (["options", "block"].includes(s)) continue;
|
|
1644
|
+
let a = s, o = n.hooks[a], p = i[a];
|
|
1645
|
+
S.passThroughHooks.has(s) ? i[a] = (u) => {
|
|
1646
|
+
if (this.defaults.async && S.passThroughHooksRespectAsync.has(s)) return (async () => {
|
|
1647
|
+
let g = await o.call(i, u);
|
|
1648
|
+
return p.call(i, g);
|
|
1649
|
+
})();
|
|
1650
|
+
let c = o.call(i, u);
|
|
1651
|
+
return p.call(i, c);
|
|
1652
|
+
} : i[a] = (...u) => {
|
|
1653
|
+
if (this.defaults.async) return (async () => {
|
|
1654
|
+
let g = await o.apply(i, u);
|
|
1655
|
+
return g === false && (g = await p.apply(i, u)), g;
|
|
1656
|
+
})();
|
|
1657
|
+
let c = o.apply(i, u);
|
|
1658
|
+
return c === false && (c = p.apply(i, u)), c;
|
|
1659
|
+
};
|
|
1660
|
+
}
|
|
1661
|
+
r.hooks = i;
|
|
1662
|
+
}
|
|
1663
|
+
if (n.walkTokens) {
|
|
1664
|
+
let i = this.defaults.walkTokens, s = n.walkTokens;
|
|
1665
|
+
r.walkTokens = function(a) {
|
|
1666
|
+
let o = [];
|
|
1667
|
+
return o.push(s.call(this, a)), i && (o = o.concat(i.call(this, a))), o;
|
|
1668
|
+
};
|
|
1669
|
+
}
|
|
1670
|
+
this.defaults = { ...this.defaults, ...r };
|
|
1671
|
+
}), this;
|
|
1672
|
+
}
|
|
1673
|
+
setOptions(e) {
|
|
1674
|
+
return this.defaults = { ...this.defaults, ...e }, this;
|
|
1675
|
+
}
|
|
1676
|
+
lexer(e, t) {
|
|
1677
|
+
return x.lex(e, t ?? this.defaults);
|
|
1678
|
+
}
|
|
1679
|
+
parser(e, t) {
|
|
1680
|
+
return b.parse(e, t ?? this.defaults);
|
|
1681
|
+
}
|
|
1682
|
+
parseMarkdown(e) {
|
|
1683
|
+
return (n, r) => {
|
|
1684
|
+
let i = { ...r }, s = { ...this.defaults, ...i }, a = this.onError(!!s.silent, !!s.async);
|
|
1685
|
+
if (this.defaults.async === true && i.async === false) return a(new Error("marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise."));
|
|
1686
|
+
if (typeof n > "u" || n === null) return a(new Error("marked(): input parameter is undefined or null"));
|
|
1687
|
+
if (typeof n != "string") return a(new Error("marked(): input parameter is of type " + Object.prototype.toString.call(n) + ", string expected"));
|
|
1688
|
+
if (s.hooks && (s.hooks.options = s, s.hooks.block = e), s.async) return (async () => {
|
|
1689
|
+
let o = s.hooks ? await s.hooks.preprocess(n) : n, u = await (s.hooks ? await s.hooks.provideLexer() : e ? x.lex : x.lexInline)(o, s), c = s.hooks ? await s.hooks.processAllTokens(u) : u;
|
|
1690
|
+
s.walkTokens && await Promise.all(this.walkTokens(c, s.walkTokens));
|
|
1691
|
+
let h = await (s.hooks ? await s.hooks.provideParser() : e ? b.parse : b.parseInline)(c, s);
|
|
1692
|
+
return s.hooks ? await s.hooks.postprocess(h) : h;
|
|
1693
|
+
})().catch(a);
|
|
1694
|
+
try {
|
|
1695
|
+
s.hooks && (n = s.hooks.preprocess(n));
|
|
1696
|
+
let p = (s.hooks ? s.hooks.provideLexer() : e ? x.lex : x.lexInline)(n, s);
|
|
1697
|
+
s.hooks && (p = s.hooks.processAllTokens(p)), s.walkTokens && this.walkTokens(p, s.walkTokens);
|
|
1698
|
+
let c = (s.hooks ? s.hooks.provideParser() : e ? b.parse : b.parseInline)(p, s);
|
|
1699
|
+
return s.hooks && (c = s.hooks.postprocess(c)), c;
|
|
1700
|
+
} catch (o) {
|
|
1701
|
+
return a(o);
|
|
1702
|
+
}
|
|
1703
|
+
};
|
|
1704
|
+
}
|
|
1705
|
+
onError(e, t) {
|
|
1706
|
+
return (n) => {
|
|
1707
|
+
if (n.message += `
|
|
1708
|
+
Please report this to https://github.com/markedjs/marked.`, e) {
|
|
1709
|
+
let r = "<p>An error occurred:</p><pre>" + w(n.message + "", true) + "</pre>";
|
|
1710
|
+
return t ? Promise.resolve(r) : r;
|
|
1711
|
+
}
|
|
1712
|
+
if (t) return Promise.reject(n);
|
|
1713
|
+
throw n;
|
|
1714
|
+
};
|
|
1715
|
+
}
|
|
1716
|
+
};
|
|
1717
|
+
var _ = new B();
|
|
1718
|
+
function k(l3, e) {
|
|
1719
|
+
return _.parse(l3, e);
|
|
1720
|
+
}
|
|
1721
|
+
k.options = k.setOptions = function(l3) {
|
|
1722
|
+
return _.setOptions(l3), k.defaults = _.defaults, G(k.defaults), k;
|
|
1723
|
+
};
|
|
1724
|
+
k.getDefaults = L;
|
|
1725
|
+
k.defaults = T;
|
|
1726
|
+
k.use = function(...l3) {
|
|
1727
|
+
return _.use(...l3), k.defaults = _.defaults, G(k.defaults), k;
|
|
1728
|
+
};
|
|
1729
|
+
k.walkTokens = function(l3, e) {
|
|
1730
|
+
return _.walkTokens(l3, e);
|
|
1731
|
+
};
|
|
1732
|
+
k.parseInline = _.parseInline;
|
|
1733
|
+
k.Parser = b;
|
|
1734
|
+
k.parser = b.parse;
|
|
1735
|
+
k.Renderer = P;
|
|
1736
|
+
k.TextRenderer = $;
|
|
1737
|
+
k.Lexer = x;
|
|
1738
|
+
k.lexer = x.lex;
|
|
1739
|
+
k.Tokenizer = y;
|
|
1740
|
+
k.Hooks = S;
|
|
1741
|
+
k.parse = k;
|
|
1742
|
+
var Zt = k.options;
|
|
1743
|
+
var Gt = k.setOptions;
|
|
1744
|
+
var Nt = k.use;
|
|
1745
|
+
var Ft = k.walkTokens;
|
|
1746
|
+
var jt = k.parseInline;
|
|
1747
|
+
var Ut = b.parse;
|
|
1748
|
+
var Kt = x.lex;
|
|
1749
|
+
|
|
1750
|
+
// ../modules/report-generator/dist/filter.js
|
|
1751
|
+
var SECTION_PATTERN = /<!--\s*vortex:privacy\s+(\w+)\s*-->([\s\S]*?)<!--\s*\/vortex:privacy\s*-->/g;
|
|
1752
|
+
function stripPrivateSections(content, targetPrivacy) {
|
|
1753
|
+
const warnings = [];
|
|
1754
|
+
const out = content.replace(SECTION_PATTERN, (_match, levelRaw, body) => {
|
|
1755
|
+
const sectionPrivacy = normalizePrivacy(levelRaw);
|
|
1756
|
+
if (isVisibleAt(sectionPrivacy, targetPrivacy)) {
|
|
1757
|
+
return body;
|
|
1758
|
+
}
|
|
1759
|
+
warnings.push({
|
|
1760
|
+
kind: "section-stripped",
|
|
1761
|
+
reason: `Stripped section with privacy=${sectionPrivacy} (above target ${targetPrivacy})`
|
|
1762
|
+
});
|
|
1763
|
+
return "";
|
|
1764
|
+
});
|
|
1765
|
+
return { content: out, warnings };
|
|
1766
|
+
}
|
|
1767
|
+
|
|
1768
|
+
// ../modules/report-generator/dist/template.js
|
|
1769
|
+
var DEFAULT_TEMPLATE = `<!DOCTYPE html>
|
|
1770
|
+
<html lang="en">
|
|
1771
|
+
<head>
|
|
1772
|
+
<meta charset="utf-8">
|
|
1773
|
+
<title>{{title}}</title>
|
|
1774
|
+
</head>
|
|
1775
|
+
<body>
|
|
1776
|
+
{{content}}
|
|
1777
|
+
</body>
|
|
1778
|
+
</html>
|
|
1779
|
+
`;
|
|
1780
|
+
function applyTemplate(template, vars) {
|
|
1781
|
+
return template.replace(/\{\{(\w+)\}\}/g, (_match, key) => {
|
|
1782
|
+
return vars[key] ?? "";
|
|
1783
|
+
});
|
|
1784
|
+
}
|
|
1785
|
+
|
|
1786
|
+
// ../modules/report-generator/dist/renderer.js
|
|
1787
|
+
async function renderHtml(source, options) {
|
|
1788
|
+
const { frontmatter, body } = parseFrontmatter(source);
|
|
1789
|
+
const documentPrivacy = normalizePrivacy(frontmatter.privacy);
|
|
1790
|
+
if (!isVisibleAt(documentPrivacy, options.targetPrivacy)) {
|
|
1791
|
+
return {
|
|
1792
|
+
html: "",
|
|
1793
|
+
documentPrivacy,
|
|
1794
|
+
visible: false,
|
|
1795
|
+
warnings: [
|
|
1796
|
+
{
|
|
1797
|
+
kind: "document-not-visible",
|
|
1798
|
+
reason: `Document privacy is ${documentPrivacy}; viewer target is ${options.targetPrivacy}.`
|
|
1799
|
+
}
|
|
1800
|
+
]
|
|
1801
|
+
};
|
|
1802
|
+
}
|
|
1803
|
+
const stripped = stripPrivateSections(body, options.targetPrivacy);
|
|
1804
|
+
const inner = await Promise.resolve(k.parse(stripped.content, { gfm: true, breaks: false }));
|
|
1805
|
+
const title = options.title ?? (typeof frontmatter.title === "string" ? frontmatter.title : "");
|
|
1806
|
+
const template = options.template ?? DEFAULT_TEMPLATE;
|
|
1807
|
+
const html = applyTemplate(template, { title, content: inner });
|
|
1808
|
+
return {
|
|
1809
|
+
html,
|
|
1810
|
+
documentPrivacy,
|
|
1811
|
+
visible: true,
|
|
1812
|
+
warnings: stripped.warnings
|
|
1813
|
+
};
|
|
1814
|
+
}
|
|
1815
|
+
|
|
1816
|
+
// ../modules/til/dist/index.js
|
|
1817
|
+
var dist_exports8 = {};
|
|
1818
|
+
__export(dist_exports8, {
|
|
1819
|
+
TilStore: () => TilStore,
|
|
1820
|
+
appendSection: () => appendSection
|
|
1821
|
+
});
|
|
1822
|
+
|
|
1823
|
+
// ../modules/til/dist/store.js
|
|
1824
|
+
import { readdir as readdir6, readFile as readFile6, stat as stat2 } from "fs/promises";
|
|
1825
|
+
import { join as join8 } from "path";
|
|
1826
|
+
var FILENAME_PATTERN = /^(\d{4}-\d{2}-\d{2})-(.+)\.md$/;
|
|
1827
|
+
var MONTH_PATTERN = /^\d{2}$/;
|
|
1828
|
+
var YEAR_PATTERN = /^\d{4}$/;
|
|
1829
|
+
var TilStore = class {
|
|
1830
|
+
rootDir;
|
|
1831
|
+
constructor(rootDir) {
|
|
1832
|
+
this.rootDir = rootDir;
|
|
1833
|
+
}
|
|
1834
|
+
/** All entries across all years and months, sorted by date ascending. */
|
|
1835
|
+
async list() {
|
|
1836
|
+
const years = await this.listSubdirs(this.rootDir, YEAR_PATTERN);
|
|
1837
|
+
const entries = [];
|
|
1838
|
+
for (const year of years) {
|
|
1839
|
+
const yearDir = join8(this.rootDir, year);
|
|
1840
|
+
const months = await this.listSubdirs(yearDir, MONTH_PATTERN);
|
|
1841
|
+
for (const month of months) {
|
|
1842
|
+
entries.push(...await this.entriesIn(join8(yearDir, month)));
|
|
1843
|
+
}
|
|
1844
|
+
}
|
|
1845
|
+
return entries.sort((a, b2) => a.date === b2.date ? a.keyword.localeCompare(b2.keyword) : a.date.localeCompare(b2.date));
|
|
1846
|
+
}
|
|
1847
|
+
/** Entries within one calendar month. */
|
|
1848
|
+
async listByMonth(year, month) {
|
|
1849
|
+
const monthDir = join8(this.rootDir, String(year).padStart(4, "0"), String(month).padStart(2, "0"));
|
|
1850
|
+
const entries = await this.entriesIn(monthDir);
|
|
1851
|
+
return entries.sort((a, b2) => a.date === b2.date ? a.keyword.localeCompare(b2.keyword) : a.date.localeCompare(b2.date));
|
|
1852
|
+
}
|
|
1853
|
+
/**
|
|
1854
|
+
* The first entry matching `date` (`YYYY-MM-DD`). If multiple files exist
|
|
1855
|
+
* for that date with different keywords, the lexicographically-first one
|
|
1856
|
+
* is returned. Use `list()` when all are needed.
|
|
1857
|
+
*/
|
|
1858
|
+
async get(date) {
|
|
1859
|
+
const [year, month] = date.split("-");
|
|
1860
|
+
if (!year || !month)
|
|
1861
|
+
return void 0;
|
|
1862
|
+
const monthDir = join8(this.rootDir, year, month);
|
|
1863
|
+
const entries = (await this.entriesIn(monthDir)).filter((e) => e.date === date).sort((a, b2) => a.keyword.localeCompare(b2.keyword));
|
|
1864
|
+
return entries[0];
|
|
1865
|
+
}
|
|
1866
|
+
/** Most recent entry by date (descending), then keyword (descending). */
|
|
1867
|
+
async getLatest() {
|
|
1868
|
+
const all = await this.list();
|
|
1869
|
+
if (all.length === 0)
|
|
1870
|
+
return void 0;
|
|
1871
|
+
return all[all.length - 1];
|
|
1872
|
+
}
|
|
1873
|
+
/** Resolve the file path for a given (date, keyword), without creating it. */
|
|
1874
|
+
pathFor(date, keyword) {
|
|
1875
|
+
const [year, month] = date.split("-");
|
|
1876
|
+
if (!year || !month) {
|
|
1877
|
+
throw new Error(`Invalid date: ${date} (expected YYYY-MM-DD)`);
|
|
1878
|
+
}
|
|
1879
|
+
return join8(this.rootDir, year, month, `${date}-${keyword}.md`);
|
|
1880
|
+
}
|
|
1881
|
+
async listSubdirs(dir, pattern) {
|
|
1882
|
+
try {
|
|
1883
|
+
const entries = await readdir6(dir, { withFileTypes: true });
|
|
1884
|
+
return entries.filter((e) => e.isDirectory() && pattern.test(e.name)).map((e) => e.name).sort();
|
|
1885
|
+
} catch (e) {
|
|
1886
|
+
if (e.code === "ENOENT")
|
|
1887
|
+
return [];
|
|
1888
|
+
throw e;
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1891
|
+
async entriesIn(monthDir) {
|
|
1892
|
+
let names;
|
|
1893
|
+
try {
|
|
1894
|
+
names = await readdir6(monthDir);
|
|
1895
|
+
} catch (e) {
|
|
1896
|
+
if (e.code === "ENOENT")
|
|
1897
|
+
return [];
|
|
1898
|
+
throw e;
|
|
1899
|
+
}
|
|
1900
|
+
const out = [];
|
|
1901
|
+
for (const name of names) {
|
|
1902
|
+
const match = name.match(FILENAME_PATTERN);
|
|
1903
|
+
if (!match)
|
|
1904
|
+
continue;
|
|
1905
|
+
const path = join8(monthDir, name);
|
|
1906
|
+
try {
|
|
1907
|
+
const info = await stat2(path);
|
|
1908
|
+
if (!info.isFile())
|
|
1909
|
+
continue;
|
|
1910
|
+
} catch {
|
|
1911
|
+
continue;
|
|
1912
|
+
}
|
|
1913
|
+
const raw = await readFile6(path, "utf8");
|
|
1914
|
+
const { frontmatter, body } = parseFrontmatter(raw);
|
|
1915
|
+
const date = match[1] ?? "";
|
|
1916
|
+
const keyword = match[2] ?? "";
|
|
1917
|
+
out.push({ date, keyword, path, frontmatter, body });
|
|
1918
|
+
}
|
|
1919
|
+
return out;
|
|
1920
|
+
}
|
|
1921
|
+
};
|
|
1922
|
+
|
|
1923
|
+
// ../modules/til/dist/append.js
|
|
1924
|
+
import { readFile as readFile7, writeFile as writeFile3 } from "fs/promises";
|
|
1925
|
+
async function appendSection(entry, title, body) {
|
|
1926
|
+
const original = await readFile7(entry.path, "utf8");
|
|
1927
|
+
const trimmed = original.replace(/\s+$/u, "");
|
|
1928
|
+
const section = `## ${title}
|
|
1929
|
+
|
|
1930
|
+
${body.trimEnd()}
|
|
1931
|
+
`;
|
|
1932
|
+
const next = `${trimmed}
|
|
1933
|
+
|
|
1934
|
+
${section}`;
|
|
1935
|
+
await writeFile3(entry.path, next, "utf8");
|
|
1936
|
+
return next;
|
|
1937
|
+
}
|
|
1938
|
+
|
|
1939
|
+
// ../modules/decision-log/dist/index.js
|
|
1940
|
+
var dist_exports9 = {};
|
|
1941
|
+
__export(dist_exports9, {
|
|
1942
|
+
DecisionStore: () => DecisionStore,
|
|
1943
|
+
renderTemplate: () => renderTemplate
|
|
1944
|
+
});
|
|
1945
|
+
|
|
1946
|
+
// ../modules/decision-log/dist/store.js
|
|
1947
|
+
import { readdir as readdir7, readFile as readFile8, stat as stat3 } from "fs/promises";
|
|
1948
|
+
import { join as join9 } from "path";
|
|
1949
|
+
var FILENAME_PATTERN2 = /^(\d{4}-\d{2}-\d{2})-(.+)\.md$/;
|
|
1950
|
+
var DecisionStore = class {
|
|
1951
|
+
rootDir;
|
|
1952
|
+
constructor(rootDir) {
|
|
1953
|
+
this.rootDir = rootDir;
|
|
1954
|
+
}
|
|
1955
|
+
/** All entries, sorted by date ascending, then slug ascending. */
|
|
1956
|
+
async list() {
|
|
1957
|
+
let names;
|
|
1958
|
+
try {
|
|
1959
|
+
names = await readdir7(this.rootDir);
|
|
1960
|
+
} catch (e) {
|
|
1961
|
+
if (e.code === "ENOENT")
|
|
1962
|
+
return [];
|
|
1963
|
+
throw e;
|
|
1964
|
+
}
|
|
1965
|
+
const out = [];
|
|
1966
|
+
for (const name of names) {
|
|
1967
|
+
const match = name.match(FILENAME_PATTERN2);
|
|
1968
|
+
if (!match)
|
|
1969
|
+
continue;
|
|
1970
|
+
const path = join9(this.rootDir, name);
|
|
1971
|
+
try {
|
|
1972
|
+
const info = await stat3(path);
|
|
1973
|
+
if (!info.isFile())
|
|
1974
|
+
continue;
|
|
1975
|
+
} catch {
|
|
1976
|
+
continue;
|
|
1977
|
+
}
|
|
1978
|
+
const raw = await readFile8(path, "utf8");
|
|
1979
|
+
const { frontmatter, body } = parseFrontmatter(raw);
|
|
1980
|
+
const date = match[1] ?? "";
|
|
1981
|
+
const slug = match[2] ?? "";
|
|
1982
|
+
out.push({ date, slug, path, frontmatter, body });
|
|
1983
|
+
}
|
|
1984
|
+
return out.sort((a, b2) => a.date === b2.date ? a.slug.localeCompare(b2.slug) : a.date.localeCompare(b2.date));
|
|
1985
|
+
}
|
|
1986
|
+
/**
|
|
1987
|
+
* Entries whose filename starts with `date` (`YYYY-MM-DD`). Multiple
|
|
1988
|
+
* decisions on the same day are returned in slug-ascending order.
|
|
1989
|
+
*/
|
|
1990
|
+
async getByDate(date) {
|
|
1991
|
+
const all = await this.list();
|
|
1992
|
+
return all.filter((e) => e.date === date);
|
|
1993
|
+
}
|
|
1994
|
+
/**
|
|
1995
|
+
* The first entry matching `date` and (optionally) `slug`. When no slug is
|
|
1996
|
+
* provided and multiple entries share the date, the lexicographically-first
|
|
1997
|
+
* one is returned.
|
|
1998
|
+
*/
|
|
1999
|
+
async get(date, slug) {
|
|
2000
|
+
const matches = await this.getByDate(date);
|
|
2001
|
+
if (slug === void 0)
|
|
2002
|
+
return matches[0];
|
|
2003
|
+
return matches.find((e) => e.slug === slug);
|
|
2004
|
+
}
|
|
2005
|
+
/** Most recent entry by date (descending), then slug (descending). */
|
|
2006
|
+
async getLatest() {
|
|
2007
|
+
const all = await this.list();
|
|
2008
|
+
if (all.length === 0)
|
|
2009
|
+
return void 0;
|
|
2010
|
+
return all[all.length - 1];
|
|
2011
|
+
}
|
|
2012
|
+
/**
|
|
2013
|
+
* Subset of entries matching the given criteria. Empty/undefined fields
|
|
2014
|
+
* are ignored. Returns entries in the same order as {@link list}.
|
|
2015
|
+
*/
|
|
2016
|
+
async filter(criteria) {
|
|
2017
|
+
const all = await this.list();
|
|
2018
|
+
return all.filter((e) => {
|
|
2019
|
+
if (criteria.status !== void 0 && e.frontmatter.status !== criteria.status) {
|
|
2020
|
+
return false;
|
|
2021
|
+
}
|
|
2022
|
+
if (criteria.tag !== void 0) {
|
|
2023
|
+
const tags = e.frontmatter.tags ?? [];
|
|
2024
|
+
if (!tags.includes(criteria.tag))
|
|
2025
|
+
return false;
|
|
2026
|
+
}
|
|
2027
|
+
if (criteria.fromDate !== void 0 && e.date < criteria.fromDate) {
|
|
2028
|
+
return false;
|
|
2029
|
+
}
|
|
2030
|
+
if (criteria.toDate !== void 0 && e.date > criteria.toDate) {
|
|
2031
|
+
return false;
|
|
2032
|
+
}
|
|
2033
|
+
return true;
|
|
2034
|
+
});
|
|
2035
|
+
}
|
|
2036
|
+
/** Resolve the file path for a given (date, slug), without creating it. */
|
|
2037
|
+
pathFor(date, slug) {
|
|
2038
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
|
|
2039
|
+
throw new Error(`Invalid date: ${date} (expected YYYY-MM-DD)`);
|
|
2040
|
+
}
|
|
2041
|
+
return join9(this.rootDir, `${date}-${slug}.md`);
|
|
2042
|
+
}
|
|
2043
|
+
};
|
|
2044
|
+
|
|
2045
|
+
// ../modules/decision-log/dist/template.js
|
|
2046
|
+
function renderTemplate(input) {
|
|
2047
|
+
const tags = ["decision-log", ...input.tags ?? []];
|
|
2048
|
+
const tagsLine = tags.map((t) => `"${t}"`).join(", ");
|
|
2049
|
+
const area = input.area ?? "work / personal / other";
|
|
2050
|
+
return [
|
|
2051
|
+
"---",
|
|
2052
|
+
"type: decision-log",
|
|
2053
|
+
"status: active",
|
|
2054
|
+
"privacy: personal",
|
|
2055
|
+
`created: ${input.date}`,
|
|
2056
|
+
`updated: ${input.date}`,
|
|
2057
|
+
`tags: [${tagsLine}]`,
|
|
2058
|
+
"---",
|
|
2059
|
+
"",
|
|
2060
|
+
`# ${input.title}`,
|
|
2061
|
+
"",
|
|
2062
|
+
`- **Date**: ${input.date}`,
|
|
2063
|
+
`- **Area**: ${area}`,
|
|
2064
|
+
"- **Tag**: #decision-log",
|
|
2065
|
+
"",
|
|
2066
|
+
"## Context",
|
|
2067
|
+
"",
|
|
2068
|
+
"{What problem prompted this decision? Why was a choice required? 2-3 sentences.}",
|
|
2069
|
+
"",
|
|
2070
|
+
"## Options",
|
|
2071
|
+
"",
|
|
2072
|
+
"| Option | Content | Pros | Cons |",
|
|
2073
|
+
"|--------|---------|------|------|",
|
|
2074
|
+
"| A | | | |",
|
|
2075
|
+
"| B | | | |",
|
|
2076
|
+
"| C | | | |",
|
|
2077
|
+
"",
|
|
2078
|
+
"## Chosen: {A/B/C}",
|
|
2079
|
+
"",
|
|
2080
|
+
"## Why this one",
|
|
2081
|
+
"",
|
|
2082
|
+
"{The core section. The real reasoning behind the choice, candidly.}",
|
|
2083
|
+
"",
|
|
2084
|
+
"## Principle (patterns emerge when this repeats)",
|
|
2085
|
+
"",
|
|
2086
|
+
"> {One sentence: the judgment criterion this decision exposed.}",
|
|
2087
|
+
"",
|
|
2088
|
+
"## Result (optional)",
|
|
2089
|
+
"",
|
|
2090
|
+
"{Fill in only for verifiable decisions. Delete the section for taste/preference records.}",
|
|
2091
|
+
""
|
|
2092
|
+
].join("\n");
|
|
2093
|
+
}
|
|
2094
|
+
|
|
2095
|
+
// ../modules/index-generator/dist/index.js
|
|
2096
|
+
var dist_exports10 = {};
|
|
2097
|
+
__export(dist_exports10, {
|
|
2098
|
+
findIndexableDirs: () => findIndexableDirs,
|
|
2099
|
+
renderIndex: () => renderIndex,
|
|
2100
|
+
scanDirectory: () => scanDirectory
|
|
2101
|
+
});
|
|
2102
|
+
|
|
2103
|
+
// ../modules/index-generator/dist/scan.js
|
|
2104
|
+
import { readdir as readdir8, readFile as readFile9, stat as stat4 } from "fs/promises";
|
|
2105
|
+
import { basename as basename5, extname as extname5, join as join10, relative } from "path";
|
|
2106
|
+
var RESERVED_FILES = /* @__PURE__ */ new Set(["README.md", "_INDEX.md"]);
|
|
2107
|
+
var H1_PATTERN = /^#\s+(.+?)\s*$/m;
|
|
2108
|
+
async function scanDirectory(rootDir, opts = {}) {
|
|
2109
|
+
const skipFilenames = /* @__PURE__ */ new Set([
|
|
2110
|
+
...RESERVED_FILES,
|
|
2111
|
+
...opts.skipFilenames ?? []
|
|
2112
|
+
]);
|
|
2113
|
+
const skipPrefixes = opts.skipPrefixes ?? [];
|
|
2114
|
+
const recursive = opts.recursive ?? false;
|
|
2115
|
+
const out = [];
|
|
2116
|
+
await walk(rootDir, rootDir, recursive, skipFilenames, skipPrefixes, out);
|
|
2117
|
+
return out.sort((a, b2) => a.relPath.localeCompare(b2.relPath));
|
|
2118
|
+
}
|
|
2119
|
+
async function walk(rootDir, currentDir, recursive, skipFilenames, skipPrefixes, out) {
|
|
2120
|
+
let entries;
|
|
2121
|
+
try {
|
|
2122
|
+
entries = await readdir8(currentDir, { withFileTypes: true });
|
|
2123
|
+
} catch (e) {
|
|
2124
|
+
if (e.code === "ENOENT")
|
|
2125
|
+
return;
|
|
2126
|
+
throw e;
|
|
2127
|
+
}
|
|
2128
|
+
for (const dirent of entries) {
|
|
2129
|
+
const name = dirent.name;
|
|
2130
|
+
if (dirent.isDirectory()) {
|
|
2131
|
+
if (!recursive)
|
|
2132
|
+
continue;
|
|
2133
|
+
if (name.startsWith(".") || name.startsWith("_"))
|
|
2134
|
+
continue;
|
|
2135
|
+
await walk(rootDir, join10(currentDir, name), recursive, skipFilenames, skipPrefixes, out);
|
|
2136
|
+
continue;
|
|
2137
|
+
}
|
|
2138
|
+
if (!dirent.isFile())
|
|
2139
|
+
continue;
|
|
2140
|
+
if (extname5(name) !== ".md")
|
|
2141
|
+
continue;
|
|
2142
|
+
if (skipFilenames.has(name))
|
|
2143
|
+
continue;
|
|
2144
|
+
const nameNoExt = basename5(name, ".md");
|
|
2145
|
+
if (skipPrefixes.some((p) => nameNoExt.startsWith(p)))
|
|
2146
|
+
continue;
|
|
2147
|
+
const fullPath = join10(currentDir, name);
|
|
2148
|
+
let info;
|
|
2149
|
+
try {
|
|
2150
|
+
info = await stat4(fullPath);
|
|
2151
|
+
if (!info.isFile())
|
|
2152
|
+
continue;
|
|
2153
|
+
} catch {
|
|
2154
|
+
continue;
|
|
2155
|
+
}
|
|
2156
|
+
const raw = await readFile9(fullPath, "utf8");
|
|
2157
|
+
const { frontmatter, body } = parseFrontmatter(raw);
|
|
2158
|
+
const title = extractTitle(body) ?? nameNoExt;
|
|
2159
|
+
const description = extractDescription(frontmatter, body);
|
|
2160
|
+
const type = stringField(frontmatter, "type");
|
|
2161
|
+
const updated = stringField(frontmatter, "updated") ?? stringField(frontmatter, "created");
|
|
2162
|
+
out.push({
|
|
2163
|
+
relPath: relative(rootDir, fullPath).split(/[\\/]/).join("/"),
|
|
2164
|
+
name: nameNoExt,
|
|
2165
|
+
title,
|
|
2166
|
+
description,
|
|
2167
|
+
type,
|
|
2168
|
+
updated
|
|
2169
|
+
});
|
|
2170
|
+
}
|
|
2171
|
+
}
|
|
2172
|
+
function extractTitle(body) {
|
|
2173
|
+
const m2 = body.match(H1_PATTERN);
|
|
2174
|
+
if (!m2)
|
|
2175
|
+
return void 0;
|
|
2176
|
+
return m2[1]?.trim();
|
|
2177
|
+
}
|
|
2178
|
+
function extractDescription(frontmatter, body) {
|
|
2179
|
+
const fm = stringField(frontmatter, "description");
|
|
2180
|
+
if (fm)
|
|
2181
|
+
return fm;
|
|
2182
|
+
const lines = body.split(/\r?\n/);
|
|
2183
|
+
for (const line of lines) {
|
|
2184
|
+
const trimmed = line.trim();
|
|
2185
|
+
if (!trimmed)
|
|
2186
|
+
continue;
|
|
2187
|
+
if (trimmed.startsWith("#"))
|
|
2188
|
+
continue;
|
|
2189
|
+
if (trimmed.startsWith(">"))
|
|
2190
|
+
continue;
|
|
2191
|
+
if (trimmed.startsWith("-") || trimmed.startsWith("*"))
|
|
2192
|
+
continue;
|
|
2193
|
+
return trimmed.length > 160 ? `${trimmed.slice(0, 157)}...` : trimmed;
|
|
2194
|
+
}
|
|
2195
|
+
return void 0;
|
|
2196
|
+
}
|
|
2197
|
+
function stringField(obj, key) {
|
|
2198
|
+
const v2 = obj[key];
|
|
2199
|
+
return typeof v2 === "string" && v2.length > 0 ? v2 : void 0;
|
|
2200
|
+
}
|
|
2201
|
+
|
|
2202
|
+
// ../modules/index-generator/dist/render.js
|
|
2203
|
+
function renderIndex(input) {
|
|
2204
|
+
const updated = input.updated ?? today();
|
|
2205
|
+
const privacy = input.privacy ?? "internal";
|
|
2206
|
+
const tags = ["index", ...input.extraTags ?? []];
|
|
2207
|
+
const tagsLine = tags.map((t) => `"${t}"`).join(", ");
|
|
2208
|
+
const lines = [
|
|
2209
|
+
"---",
|
|
2210
|
+
"type: index",
|
|
2211
|
+
"status: active",
|
|
2212
|
+
`privacy: ${privacy}`,
|
|
2213
|
+
`updated: ${updated}`,
|
|
2214
|
+
`tags: [${tagsLine}]`,
|
|
2215
|
+
"---",
|
|
2216
|
+
"",
|
|
2217
|
+
`# ${input.title}`,
|
|
2218
|
+
""
|
|
2219
|
+
];
|
|
2220
|
+
if (input.description && input.description.length > 0) {
|
|
2221
|
+
lines.push(`> ${input.description}`, "");
|
|
2222
|
+
}
|
|
2223
|
+
lines.push(`## \uD56D\uBAA9 (${input.entries.length})`, "");
|
|
2224
|
+
if (input.entries.length === 0) {
|
|
2225
|
+
lines.push("(\uBE44\uC5B4 \uC788\uC74C)", "");
|
|
2226
|
+
} else {
|
|
2227
|
+
lines.push("| \uD30C\uC77C | \uC124\uBA85 | \uAC31\uC2E0 |", "|---|---|---|");
|
|
2228
|
+
for (const e of input.entries) {
|
|
2229
|
+
const desc = sanitizeCell(e.description ?? e.title);
|
|
2230
|
+
const upd = e.updated ?? "\u2014";
|
|
2231
|
+
lines.push(`| [[${e.name}]] | ${desc} | ${upd} |`);
|
|
2232
|
+
}
|
|
2233
|
+
lines.push("");
|
|
2234
|
+
}
|
|
2235
|
+
if (input.related && input.related.length > 0) {
|
|
2236
|
+
lines.push("## \uAD00\uB828", "");
|
|
2237
|
+
for (const r of input.related) {
|
|
2238
|
+
lines.push(`- [[${r}]]`);
|
|
2239
|
+
}
|
|
2240
|
+
lines.push("");
|
|
2241
|
+
}
|
|
2242
|
+
return lines.join("\n");
|
|
2243
|
+
}
|
|
2244
|
+
function sanitizeCell(s) {
|
|
2245
|
+
return s.replace(/\|/g, "\\|").replace(/\r?\n/g, " ").trim();
|
|
2246
|
+
}
|
|
2247
|
+
function today() {
|
|
2248
|
+
const d2 = /* @__PURE__ */ new Date();
|
|
2249
|
+
const y2 = d2.getFullYear();
|
|
2250
|
+
const m2 = String(d2.getMonth() + 1).padStart(2, "0");
|
|
2251
|
+
const day = String(d2.getDate()).padStart(2, "0");
|
|
2252
|
+
return `${y2}-${m2}-${day}`;
|
|
2253
|
+
}
|
|
2254
|
+
|
|
2255
|
+
// ../modules/index-generator/dist/nested.js
|
|
2256
|
+
import { readdir as readdir9, stat as stat5 } from "fs/promises";
|
|
2257
|
+
import { extname as extname6, join as join11 } from "path";
|
|
2258
|
+
async function findIndexableDirs(rootDir, options = {}) {
|
|
2259
|
+
const minEntries = options.minEntries ?? 1;
|
|
2260
|
+
const skipPrefixes = options.skipPrefixes ?? [];
|
|
2261
|
+
const out = [];
|
|
2262
|
+
await walk2(rootDir, minEntries, skipPrefixes, out);
|
|
2263
|
+
return out;
|
|
2264
|
+
}
|
|
2265
|
+
async function walk2(dir, minEntries, skipPrefixes, out) {
|
|
2266
|
+
let entries;
|
|
2267
|
+
try {
|
|
2268
|
+
entries = await readdir9(dir, { withFileTypes: true });
|
|
2269
|
+
} catch (e) {
|
|
2270
|
+
if (e.code === "ENOENT")
|
|
2271
|
+
return;
|
|
2272
|
+
throw e;
|
|
2273
|
+
}
|
|
2274
|
+
let mdCount = 0;
|
|
2275
|
+
const subdirs = [];
|
|
2276
|
+
for (const dirent of entries) {
|
|
2277
|
+
if (dirent.isDirectory()) {
|
|
2278
|
+
if (dirent.name.startsWith("."))
|
|
2279
|
+
continue;
|
|
2280
|
+
subdirs.push(dirent.name);
|
|
2281
|
+
continue;
|
|
2282
|
+
}
|
|
2283
|
+
if (!dirent.isFile())
|
|
2284
|
+
continue;
|
|
2285
|
+
if (extname6(dirent.name) !== ".md")
|
|
2286
|
+
continue;
|
|
2287
|
+
if (dirent.name === "README.md" || dirent.name === "_INDEX.md")
|
|
2288
|
+
continue;
|
|
2289
|
+
const nameNoExt = dirent.name.slice(0, -3);
|
|
2290
|
+
if (skipPrefixes.some((p) => nameNoExt.startsWith(p)))
|
|
2291
|
+
continue;
|
|
2292
|
+
try {
|
|
2293
|
+
const info = await stat5(join11(dir, dirent.name));
|
|
2294
|
+
if (!info.isFile())
|
|
2295
|
+
continue;
|
|
2296
|
+
} catch {
|
|
2297
|
+
continue;
|
|
2298
|
+
}
|
|
2299
|
+
mdCount++;
|
|
2300
|
+
}
|
|
2301
|
+
if (mdCount >= minEntries) {
|
|
2302
|
+
out.push(dir);
|
|
2303
|
+
}
|
|
2304
|
+
for (const name of subdirs) {
|
|
2305
|
+
await walk2(join11(dir, name), minEntries, skipPrefixes, out);
|
|
2306
|
+
}
|
|
2307
|
+
}
|
|
2308
|
+
|
|
2309
|
+
// ../modules/runbooks/dist/index.js
|
|
2310
|
+
var dist_exports11 = {};
|
|
2311
|
+
__export(dist_exports11, {
|
|
2312
|
+
RunbookStore: () => RunbookStore
|
|
2313
|
+
});
|
|
2314
|
+
|
|
2315
|
+
// ../modules/runbooks/dist/store.js
|
|
2316
|
+
import { readdir as readdir10, readFile as readFile10, stat as stat6 } from "fs/promises";
|
|
2317
|
+
import { extname as extname7, join as join12 } from "path";
|
|
2318
|
+
var RESERVED_FILES2 = /* @__PURE__ */ new Set(["README.md", "_INDEX.md"]);
|
|
2319
|
+
var RunbookStore = class {
|
|
2320
|
+
rootDir;
|
|
2321
|
+
constructor(rootDir) {
|
|
2322
|
+
this.rootDir = rootDir;
|
|
2323
|
+
}
|
|
2324
|
+
/** All entries, sorted by slug ascending. */
|
|
2325
|
+
async list() {
|
|
2326
|
+
let names;
|
|
2327
|
+
try {
|
|
2328
|
+
names = await readdir10(this.rootDir);
|
|
2329
|
+
} catch (e) {
|
|
2330
|
+
if (e.code === "ENOENT")
|
|
2331
|
+
return [];
|
|
2332
|
+
throw e;
|
|
2333
|
+
}
|
|
2334
|
+
const out = [];
|
|
2335
|
+
for (const name of names) {
|
|
2336
|
+
if (extname7(name) !== ".md")
|
|
2337
|
+
continue;
|
|
2338
|
+
if (RESERVED_FILES2.has(name))
|
|
2339
|
+
continue;
|
|
2340
|
+
const path = join12(this.rootDir, name);
|
|
2341
|
+
try {
|
|
2342
|
+
const info = await stat6(path);
|
|
2343
|
+
if (!info.isFile())
|
|
2344
|
+
continue;
|
|
2345
|
+
} catch {
|
|
2346
|
+
continue;
|
|
2347
|
+
}
|
|
2348
|
+
const raw = await readFile10(path, "utf8");
|
|
2349
|
+
const { frontmatter, body } = parseFrontmatter(raw);
|
|
2350
|
+
const slug = name.slice(0, -3);
|
|
2351
|
+
out.push({ slug, path, frontmatter, body });
|
|
2352
|
+
}
|
|
2353
|
+
return out.sort((a, b2) => a.slug.localeCompare(b2.slug));
|
|
2354
|
+
}
|
|
2355
|
+
/** A single entry by slug, or undefined if not found. */
|
|
2356
|
+
async get(slug) {
|
|
2357
|
+
const all = await this.list();
|
|
2358
|
+
return all.find((e) => e.slug === slug);
|
|
2359
|
+
}
|
|
2360
|
+
/**
|
|
2361
|
+
* Subset of entries matching the given criteria. Empty/undefined fields
|
|
2362
|
+
* are ignored. Returns entries in the same order as {@link list}.
|
|
2363
|
+
*/
|
|
2364
|
+
async filter(criteria) {
|
|
2365
|
+
const all = await this.list();
|
|
2366
|
+
return all.filter((e) => {
|
|
2367
|
+
if (criteria.status !== void 0 && e.frontmatter.status !== criteria.status) {
|
|
2368
|
+
return false;
|
|
2369
|
+
}
|
|
2370
|
+
if (criteria.tag !== void 0) {
|
|
2371
|
+
const tags = e.frontmatter.tags ?? [];
|
|
2372
|
+
if (!tags.includes(criteria.tag))
|
|
2373
|
+
return false;
|
|
2374
|
+
}
|
|
2375
|
+
if (criteria.incidentType !== void 0 && e.frontmatter["incident-type"] !== criteria.incidentType) {
|
|
2376
|
+
return false;
|
|
2377
|
+
}
|
|
2378
|
+
return true;
|
|
2379
|
+
});
|
|
2380
|
+
}
|
|
2381
|
+
/**
|
|
2382
|
+
* Entries whose `last_tested` is older than `staleAfterDays` from the
|
|
2383
|
+
* given reference date (default: today). Entries without a `last_tested`
|
|
2384
|
+
* field are treated as "never tested" and are always returned.
|
|
2385
|
+
*
|
|
2386
|
+
* This is the practical reason runbooks are a module rather than plain
|
|
2387
|
+
* data — periodic reverification is a real operational need.
|
|
2388
|
+
*/
|
|
2389
|
+
async getStaleByLastTested(staleAfterDays, referenceDate) {
|
|
2390
|
+
if (!Number.isFinite(staleAfterDays) || staleAfterDays < 0) {
|
|
2391
|
+
throw new Error(`Invalid staleAfterDays: ${staleAfterDays}`);
|
|
2392
|
+
}
|
|
2393
|
+
const now = referenceDate ?? /* @__PURE__ */ new Date();
|
|
2394
|
+
const threshold = now.getTime() - staleAfterDays * 864e5;
|
|
2395
|
+
const all = await this.list();
|
|
2396
|
+
return all.filter((e) => {
|
|
2397
|
+
const lt = e.frontmatter.last_tested;
|
|
2398
|
+
if (!lt)
|
|
2399
|
+
return true;
|
|
2400
|
+
const parsed = parseIsoDate(lt);
|
|
2401
|
+
if (parsed === void 0)
|
|
2402
|
+
return true;
|
|
2403
|
+
return parsed < threshold;
|
|
2404
|
+
});
|
|
2405
|
+
}
|
|
2406
|
+
};
|
|
2407
|
+
function parseIsoDate(s) {
|
|
2408
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(s))
|
|
2409
|
+
return void 0;
|
|
2410
|
+
const t = Date.parse(`${s}T00:00:00Z`);
|
|
2411
|
+
return Number.isNaN(t) ? void 0 : t;
|
|
2412
|
+
}
|
|
2413
|
+
|
|
2414
|
+
// ../modules/link-rewriter/dist/index.js
|
|
2415
|
+
var dist_exports12 = {};
|
|
2416
|
+
__export(dist_exports12, {
|
|
2417
|
+
buildFileIndex: () => buildFileIndex,
|
|
2418
|
+
checkDirectory: () => checkDirectory,
|
|
2419
|
+
extractWikiLinks: () => extractWikiLinks,
|
|
2420
|
+
resolveLink: () => resolveLink,
|
|
2421
|
+
rewriteBody: () => rewriteBody,
|
|
2422
|
+
rewriteDirectory: () => rewriteDirectory,
|
|
2423
|
+
toRel: () => toRel,
|
|
2424
|
+
topBrokenTargets: () => topBrokenTargets
|
|
2425
|
+
});
|
|
2426
|
+
|
|
2427
|
+
// ../modules/link-rewriter/dist/extract.js
|
|
2428
|
+
var WIKI_LINK_PATTERN = /\[\[([^\]|#\n]+?)(?:#([^\]|\n]+?))?(?:\|([^\]\n]+?))?\]\]/g;
|
|
2429
|
+
function extractWikiLinks(body) {
|
|
2430
|
+
const out = [];
|
|
2431
|
+
for (const match of body.matchAll(WIKI_LINK_PATTERN)) {
|
|
2432
|
+
const name = match[1]?.trim();
|
|
2433
|
+
if (!name)
|
|
2434
|
+
continue;
|
|
2435
|
+
const anchor = match[2]?.trim();
|
|
2436
|
+
const alias = match[3]?.trim();
|
|
2437
|
+
out.push({
|
|
2438
|
+
name,
|
|
2439
|
+
anchor: anchor || void 0,
|
|
2440
|
+
alias: alias || void 0,
|
|
2441
|
+
raw: match[0]
|
|
2442
|
+
});
|
|
2443
|
+
}
|
|
2444
|
+
return out;
|
|
2445
|
+
}
|
|
2446
|
+
|
|
2447
|
+
// ../modules/link-rewriter/dist/resolve.js
|
|
2448
|
+
import { readdir as readdir11, stat as stat7 } from "fs/promises";
|
|
2449
|
+
import { basename as basename6, dirname, extname as extname8, isAbsolute, join as join13, relative as relative2, resolve as pathResolve } from "path";
|
|
2450
|
+
async function buildFileIndex(rootDir, options = {}) {
|
|
2451
|
+
const byBasename = /* @__PURE__ */ new Map();
|
|
2452
|
+
const byRelPath = /* @__PURE__ */ new Map();
|
|
2453
|
+
const additional = new Set(options.additionalExtensions ?? []);
|
|
2454
|
+
await walk3(rootDir, rootDir, byBasename, byRelPath, additional);
|
|
2455
|
+
if (options.caseInsensitive) {
|
|
2456
|
+
const byRelPathLower = /* @__PURE__ */ new Map();
|
|
2457
|
+
for (const [rel, abs] of byRelPath) {
|
|
2458
|
+
const lower = rel.toLowerCase();
|
|
2459
|
+
if (!byRelPathLower.has(lower))
|
|
2460
|
+
byRelPathLower.set(lower, abs);
|
|
2461
|
+
}
|
|
2462
|
+
return { byBasename, byRelPath, byRelPathLower, rootDir };
|
|
2463
|
+
}
|
|
2464
|
+
return { byBasename, byRelPath, rootDir };
|
|
2465
|
+
}
|
|
2466
|
+
async function walk3(rootDir, dir, byBasename, byRelPath, additionalExts) {
|
|
2467
|
+
let entries;
|
|
2468
|
+
try {
|
|
2469
|
+
entries = await readdir11(dir, { withFileTypes: true });
|
|
2470
|
+
} catch (e) {
|
|
2471
|
+
if (e.code === "ENOENT")
|
|
2472
|
+
return;
|
|
2473
|
+
throw e;
|
|
2474
|
+
}
|
|
2475
|
+
for (const dirent of entries) {
|
|
2476
|
+
const name = dirent.name;
|
|
2477
|
+
if (dirent.isDirectory()) {
|
|
2478
|
+
if (name.startsWith("."))
|
|
2479
|
+
continue;
|
|
2480
|
+
await walk3(rootDir, join13(dir, name), byBasename, byRelPath, additionalExts);
|
|
2481
|
+
continue;
|
|
2482
|
+
}
|
|
2483
|
+
if (!dirent.isFile())
|
|
2484
|
+
continue;
|
|
2485
|
+
const ext = extname8(name);
|
|
2486
|
+
const isMd = ext === ".md";
|
|
2487
|
+
if (!isMd && !additionalExts.has(ext))
|
|
2488
|
+
continue;
|
|
2489
|
+
const path = join13(dir, name);
|
|
2490
|
+
try {
|
|
2491
|
+
const info = await stat7(path);
|
|
2492
|
+
if (!info.isFile())
|
|
2493
|
+
continue;
|
|
2494
|
+
} catch {
|
|
2495
|
+
continue;
|
|
2496
|
+
}
|
|
2497
|
+
const key = isMd ? basename6(name, ".md") : name;
|
|
2498
|
+
const list = byBasename.get(key);
|
|
2499
|
+
if (list) {
|
|
2500
|
+
list.push(path);
|
|
2501
|
+
} else {
|
|
2502
|
+
byBasename.set(key, [path]);
|
|
2503
|
+
}
|
|
2504
|
+
const relRaw = relative2(rootDir, path).split(/[\\/]/).join("/");
|
|
2505
|
+
const rel = isMd ? relRaw.replace(/\.md$/, "") : relRaw;
|
|
2506
|
+
byRelPath.set(rel, path);
|
|
2507
|
+
}
|
|
2508
|
+
}
|
|
2509
|
+
function resolveLink(name, index, opts = {}) {
|
|
2510
|
+
const stripped = name.replace(/\.md$/u, "");
|
|
2511
|
+
if (!stripped.includes("/") && !stripped.includes("\\")) {
|
|
2512
|
+
const list = index.byBasename.get(stripped);
|
|
2513
|
+
if (!list || list.length === 0)
|
|
2514
|
+
return { kind: "not-found" };
|
|
2515
|
+
if (list.length === 1)
|
|
2516
|
+
return { kind: "unique", path: list[0] };
|
|
2517
|
+
return { kind: "ambiguous", candidates: list };
|
|
2518
|
+
}
|
|
2519
|
+
const normalized = stripped.replace(/\\/g, "/");
|
|
2520
|
+
if (normalized.startsWith("../") || normalized.startsWith("./")) {
|
|
2521
|
+
if (!opts.sourcePath)
|
|
2522
|
+
return { kind: "not-found" };
|
|
2523
|
+
const baseDir = dirname(opts.sourcePath);
|
|
2524
|
+
const absolute = pathResolve(baseDir, normalized);
|
|
2525
|
+
const rel = relative2(index.rootDir, absolute).split(/[\\/]/).join("/");
|
|
2526
|
+
if (rel.startsWith("..") || isAbsolute(rel)) {
|
|
2527
|
+
return { kind: "not-found" };
|
|
2528
|
+
}
|
|
2529
|
+
return lookupRelPath(rel, index);
|
|
2530
|
+
}
|
|
2531
|
+
return lookupRelPath(normalized, index);
|
|
2532
|
+
}
|
|
2533
|
+
function lookupRelPath(rel, index) {
|
|
2534
|
+
const exact = index.byRelPath.get(rel);
|
|
2535
|
+
if (exact)
|
|
2536
|
+
return { kind: "unique", path: exact };
|
|
2537
|
+
if (index.byRelPathLower) {
|
|
2538
|
+
const fallback = index.byRelPathLower.get(rel.toLowerCase());
|
|
2539
|
+
if (fallback)
|
|
2540
|
+
return { kind: "unique", path: fallback };
|
|
2541
|
+
}
|
|
2542
|
+
return { kind: "not-found" };
|
|
2543
|
+
}
|
|
2544
|
+
function toRel(path, rootDir) {
|
|
2545
|
+
return relative2(rootDir, path).split(/[\\/]/).join("/");
|
|
2546
|
+
}
|
|
2547
|
+
|
|
2548
|
+
// ../modules/link-rewriter/dist/checker.js
|
|
2549
|
+
import { readFile as readFile11 } from "fs/promises";
|
|
2550
|
+
import { extname as extname9 } from "path";
|
|
2551
|
+
async function checkDirectory(rootDir, options = {}) {
|
|
2552
|
+
const index = await buildFileIndex(rootDir, options);
|
|
2553
|
+
const broken = [];
|
|
2554
|
+
const ambiguous = [];
|
|
2555
|
+
let filesScanned = 0;
|
|
2556
|
+
let totalLinks = 0;
|
|
2557
|
+
let resolved = 0;
|
|
2558
|
+
for (const paths of index.byBasename.values()) {
|
|
2559
|
+
for (const path of paths) {
|
|
2560
|
+
if (extname9(path) !== ".md")
|
|
2561
|
+
continue;
|
|
2562
|
+
filesScanned++;
|
|
2563
|
+
const raw = await readFile11(path, "utf8");
|
|
2564
|
+
const { body } = parseFrontmatter(raw);
|
|
2565
|
+
const links = extractWikiLinks(body);
|
|
2566
|
+
totalLinks += links.length;
|
|
2567
|
+
for (const link of links) {
|
|
2568
|
+
const outcome = resolveLink(link.name, index, { sourcePath: path });
|
|
2569
|
+
if (outcome.kind === "unique") {
|
|
2570
|
+
resolved++;
|
|
2571
|
+
} else if (outcome.kind === "not-found") {
|
|
2572
|
+
broken.push({ sourcePath: path, link, reason: "not-found" });
|
|
2573
|
+
} else {
|
|
2574
|
+
ambiguous.push({
|
|
2575
|
+
sourcePath: path,
|
|
2576
|
+
link,
|
|
2577
|
+
reason: "ambiguous",
|
|
2578
|
+
candidates: outcome.candidates
|
|
2579
|
+
});
|
|
2580
|
+
}
|
|
2581
|
+
}
|
|
2582
|
+
}
|
|
2583
|
+
}
|
|
2584
|
+
return { filesScanned, totalLinks, resolved, broken, ambiguous };
|
|
2585
|
+
}
|
|
2586
|
+
function topBrokenTargets(broken, limit = 20) {
|
|
2587
|
+
const counts = /* @__PURE__ */ new Map();
|
|
2588
|
+
for (const b2 of broken) {
|
|
2589
|
+
counts.set(b2.link.name, (counts.get(b2.link.name) ?? 0) + 1);
|
|
2590
|
+
}
|
|
2591
|
+
return [...counts.entries()].map(([name, count]) => ({ name, count })).sort((a, b2) => b2.count - a.count || a.name.localeCompare(b2.name)).slice(0, limit);
|
|
2592
|
+
}
|
|
2593
|
+
|
|
2594
|
+
// ../modules/link-rewriter/dist/rewrite.js
|
|
2595
|
+
import { readFile as readFile12, writeFile as writeFile4 } from "fs/promises";
|
|
2596
|
+
import { extname as extname10 } from "path";
|
|
2597
|
+
async function rewriteDirectory(rootDir, opts) {
|
|
2598
|
+
const { redirections, dryRun = false } = opts;
|
|
2599
|
+
const index = await buildFileIndex(rootDir);
|
|
2600
|
+
let filesScanned = 0;
|
|
2601
|
+
let filesChanged = 0;
|
|
2602
|
+
let rewritesApplied = 0;
|
|
2603
|
+
const details = [];
|
|
2604
|
+
for (const paths of index.byBasename.values()) {
|
|
2605
|
+
for (const path of paths) {
|
|
2606
|
+
if (extname10(path) !== ".md")
|
|
2607
|
+
continue;
|
|
2608
|
+
filesScanned++;
|
|
2609
|
+
const raw = await readFile12(path, "utf8");
|
|
2610
|
+
const { newBody, fileRewrites } = rewriteBody(raw, redirections);
|
|
2611
|
+
if (fileRewrites.length === 0)
|
|
2612
|
+
continue;
|
|
2613
|
+
filesChanged++;
|
|
2614
|
+
rewritesApplied += fileRewrites.length;
|
|
2615
|
+
details.push({ sourcePath: path, rewrites: fileRewrites });
|
|
2616
|
+
if (!dryRun) {
|
|
2617
|
+
await writeFile4(path, newBody, "utf8");
|
|
2618
|
+
}
|
|
2619
|
+
}
|
|
2620
|
+
}
|
|
2621
|
+
return {
|
|
2622
|
+
filesScanned,
|
|
2623
|
+
filesChanged,
|
|
2624
|
+
rewritesApplied,
|
|
2625
|
+
skipped: 0,
|
|
2626
|
+
details,
|
|
2627
|
+
dryRun
|
|
2628
|
+
};
|
|
2629
|
+
}
|
|
2630
|
+
function rewriteBody(body, redirections) {
|
|
2631
|
+
const fileRewrites = [];
|
|
2632
|
+
const links = extractWikiLinks(body);
|
|
2633
|
+
if (links.length === 0)
|
|
2634
|
+
return { newBody: body, fileRewrites };
|
|
2635
|
+
let out = "";
|
|
2636
|
+
let cursor = 0;
|
|
2637
|
+
const pattern = /\[\[([^\]|#\n]+?)(?:#([^\]|\n]+?))?(?:\|([^\]\n]+?))?\]\]/g;
|
|
2638
|
+
let m2;
|
|
2639
|
+
while ((m2 = pattern.exec(body)) !== null) {
|
|
2640
|
+
const [whole, rawName, rawAnchor, rawAlias] = m2;
|
|
2641
|
+
const name = (rawName ?? "").trim();
|
|
2642
|
+
const target = redirections.get(name);
|
|
2643
|
+
if (!target)
|
|
2644
|
+
continue;
|
|
2645
|
+
out += body.slice(cursor, m2.index);
|
|
2646
|
+
let replacement = `[[${target}`;
|
|
2647
|
+
if (rawAnchor)
|
|
2648
|
+
replacement += `#${rawAnchor}`;
|
|
2649
|
+
if (rawAlias)
|
|
2650
|
+
replacement += `|${rawAlias}`;
|
|
2651
|
+
replacement += "]]";
|
|
2652
|
+
out += replacement;
|
|
2653
|
+
cursor = m2.index + whole.length;
|
|
2654
|
+
fileRewrites.push({ from: whole, to: replacement });
|
|
2655
|
+
}
|
|
2656
|
+
out += body.slice(cursor);
|
|
2657
|
+
return { newBody: out, fileRewrites };
|
|
2658
|
+
}
|
|
2659
|
+
|
|
2660
|
+
// ../plugins/session-rituals/dist/index.js
|
|
2661
|
+
var dist_exports13 = {};
|
|
2662
|
+
__export(dist_exports13, {
|
|
2663
|
+
createRitualRegistry: () => createRitualRegistry,
|
|
2664
|
+
decisionCommand: () => decisionCommand,
|
|
2665
|
+
reindexCommand: () => reindexCommand,
|
|
2666
|
+
sessionStartCommand: () => sessionStartCommand,
|
|
2667
|
+
tilCommand: () => tilCommand,
|
|
2668
|
+
vortexCommand: () => vortexCommand
|
|
2669
|
+
});
|
|
2670
|
+
|
|
2671
|
+
// ../plugins/session-rituals/dist/commands/decision.js
|
|
2672
|
+
import { writeFile as writeFile5 } from "fs/promises";
|
|
2673
|
+
import { join as join14 } from "path";
|
|
2674
|
+
import { existsSync } from "fs";
|
|
2675
|
+
var decisionCommand = {
|
|
2676
|
+
name: "decision",
|
|
2677
|
+
description: "Create a new Decision Log entry from the template.",
|
|
2678
|
+
args: [
|
|
2679
|
+
{ name: "slug", description: "Kebab-style identifier used in the filename.", required: true },
|
|
2680
|
+
{ name: "title", description: "One-line decision title (rest of the input).", required: true }
|
|
2681
|
+
],
|
|
2682
|
+
handler: async (input) => {
|
|
2683
|
+
const slug = input.args.slug;
|
|
2684
|
+
if (!slug) {
|
|
2685
|
+
throw new Error("`/decision` requires a slug argument.");
|
|
2686
|
+
}
|
|
2687
|
+
const title = extractTitle2(input.rest, slug);
|
|
2688
|
+
if (!title) {
|
|
2689
|
+
throw new Error("`/decision` requires a title after the slug.");
|
|
2690
|
+
}
|
|
2691
|
+
const date = todayIso();
|
|
2692
|
+
const dir = join14(input.context.dataDir, "decision-log");
|
|
2693
|
+
const store = new DecisionStore(dir);
|
|
2694
|
+
const path = store.pathFor(date, slug);
|
|
2695
|
+
if (existsSync(path)) {
|
|
2696
|
+
throw new Error(`Refusing to overwrite existing entry: ${path}`);
|
|
2697
|
+
}
|
|
2698
|
+
const body = renderTemplate({ date, slug, title });
|
|
2699
|
+
await writeFile5(path, body, "utf8");
|
|
2700
|
+
return { path, date, slug };
|
|
2701
|
+
}
|
|
2702
|
+
};
|
|
2703
|
+
function extractTitle2(rest, slug) {
|
|
2704
|
+
const trimmed = rest.trim();
|
|
2705
|
+
if (trimmed.startsWith(slug)) {
|
|
2706
|
+
return trimmed.slice(slug.length).trim();
|
|
2707
|
+
}
|
|
2708
|
+
return trimmed;
|
|
2709
|
+
}
|
|
2710
|
+
function todayIso() {
|
|
2711
|
+
const d2 = /* @__PURE__ */ new Date();
|
|
2712
|
+
const y2 = d2.getFullYear();
|
|
2713
|
+
const m2 = String(d2.getMonth() + 1).padStart(2, "0");
|
|
2714
|
+
const day = String(d2.getDate()).padStart(2, "0");
|
|
2715
|
+
return `${y2}-${m2}-${day}`;
|
|
2716
|
+
}
|
|
2717
|
+
|
|
2718
|
+
// ../plugins/session-rituals/dist/commands/reindex.js
|
|
2719
|
+
import { existsSync as existsSync2 } from "fs";
|
|
2720
|
+
import { readFile as readFile13, writeFile as writeFile6 } from "fs/promises";
|
|
2721
|
+
import { join as join15 } from "path";
|
|
2722
|
+
var TARGETS = [
|
|
2723
|
+
{
|
|
2724
|
+
dir: "_memory",
|
|
2725
|
+
title: "Memory",
|
|
2726
|
+
description: "\uC138\uC158 \uAC04 \uACF5\uC720\uB418\uB294 \uC601\uC18D \uBA54\uBAA8\uB9AC \uD56D\uBAA9\uB4E4. MEMORY.md\uB294 \uBCF8 \uB514\uB809\uD1A0\uB9AC\uC758 \uC6D0\uBCF8 \uC778\uB371\uC2A4\uC774\uBA70, \uBCF8 _INDEX.md\uB294 \uC0AC\uB78C\xB7Obsidian \uCE5C\uD654 \uC591\uC2DD\uC758 \uD30C\uC0DD\uBB3C\uC785\uB2C8\uB2E4.",
|
|
2727
|
+
privacy: "internal",
|
|
2728
|
+
recursive: false,
|
|
2729
|
+
skipPrefixes: [],
|
|
2730
|
+
skipFilenames: ["MEMORY.md"]
|
|
2731
|
+
},
|
|
2732
|
+
{
|
|
2733
|
+
dir: "til",
|
|
2734
|
+
title: "TIL",
|
|
2735
|
+
description: "\uB0A0\uC9DC\uBCC4 \uC791\uC5C5 \uAE30\uB85D. `YYYY/MM/YYYY-MM-DD-keyword.md` \uAD6C\uC870.",
|
|
2736
|
+
privacy: "internal",
|
|
2737
|
+
recursive: true,
|
|
2738
|
+
skipPrefixes: [],
|
|
2739
|
+
skipFilenames: []
|
|
2740
|
+
},
|
|
2741
|
+
{
|
|
2742
|
+
dir: "decision-log",
|
|
2743
|
+
title: "Decision Log",
|
|
2744
|
+
description: "\uAC1C\uC778 \uC758\uC0AC\uACB0\uC815 \uAE30\uB85D \u2014 \uC65C \uADF8\uAC78 \uACE8\uB790\uB294\uC9C0\uB97C \uB0A8\uAE41\uB2C8\uB2E4.",
|
|
2745
|
+
privacy: "personal",
|
|
2746
|
+
recursive: false,
|
|
2747
|
+
skipPrefixes: ["_TEMPLATE"],
|
|
2748
|
+
skipFilenames: []
|
|
2749
|
+
},
|
|
2750
|
+
{
|
|
2751
|
+
dir: "runbooks",
|
|
2752
|
+
title: "Runbooks",
|
|
2753
|
+
description: "\uC7A5\uC560 \uB300\uC751\xB7\uC815\uAE30 \uC815\uBE44 \uC808\uCC28. `last_tested`\uB85C \uAC31\uC2E0 \uAE30\uD55C \uCD94\uC801.",
|
|
2754
|
+
privacy: "internal",
|
|
2755
|
+
recursive: false,
|
|
2756
|
+
skipPrefixes: [],
|
|
2757
|
+
skipFilenames: []
|
|
2758
|
+
},
|
|
2759
|
+
{
|
|
2760
|
+
dir: "hubs",
|
|
2761
|
+
title: "Hubs",
|
|
2762
|
+
description: "\uC8FC\uC81C\uBCC4 \uC9C4\uC785\uC810 \u2014 \uAD00\uB828 \uC790\uB8CC\uB97C \uD55C \uACF3\uC5D0\uC11C \uBB36\uB294 \uC778\uB371\uC2A4 \uD398\uC774\uC9C0 \uBAA8\uC74C.",
|
|
2763
|
+
privacy: "internal",
|
|
2764
|
+
recursive: false,
|
|
2765
|
+
skipPrefixes: [],
|
|
2766
|
+
skipFilenames: []
|
|
2767
|
+
},
|
|
2768
|
+
{
|
|
2769
|
+
dir: "projects",
|
|
2770
|
+
title: "Projects",
|
|
2771
|
+
description: "\uC9C4\uD589 \uC911\xB7\uC644\uB8CC \uD504\uB85C\uC81D\uD2B8 \uBAA8\uC74C (Work\xB7Home). \uBCF8 _INDEX\uB294 \uD3C9\uD0C4 \uBAA9\uB85D\uC774\uBA70, \uD558\uC704 \uD504\uB85C\uC81D\uD2B8 \uD3F4\uB354\uBCC4 _INDEX\uAC00 \uB354 \uC720\uC6A9\uD560 \uC218 \uC788\uC74C (\uB2E4\uC74C \uC0AC\uC774\uD074 \uAC80\uD1A0).",
|
|
2772
|
+
privacy: "internal",
|
|
2773
|
+
recursive: true,
|
|
2774
|
+
skipPrefixes: [],
|
|
2775
|
+
skipFilenames: []
|
|
2776
|
+
},
|
|
2777
|
+
{
|
|
2778
|
+
dir: "reference",
|
|
2779
|
+
title: "Reference",
|
|
2780
|
+
description: "AI \uADDC\uCE59\xB7\uAE30\uC220 \uCE58\uD2B8\uC2DC\uD2B8\xB7\uC7A5\uBE44\xB7\uC2A4\uD0AC \uB4F1 \uB808\uD37C\uB7F0\uC2A4 \uC790\uB8CC (AI-Rules\xB7Games\xB7Gear\xB7Infra\xB7Org\xB7Skills\xB7Tech).",
|
|
2781
|
+
privacy: "internal",
|
|
2782
|
+
recursive: true,
|
|
2783
|
+
skipPrefixes: [],
|
|
2784
|
+
skipFilenames: []
|
|
2785
|
+
},
|
|
2786
|
+
{
|
|
2787
|
+
dir: "reports",
|
|
2788
|
+
title: "Reports",
|
|
2789
|
+
description: "\uC815\uAE30 \uAC74\uAC15\uAC80\uC9C4 \uB9AC\uD3EC\uD2B8 (Service-Health\xB7Homelab-Health). \uC2DC\uC810 \uC2A4\uB0C5\uC0F7 \uB204\uC801.",
|
|
2790
|
+
privacy: "internal",
|
|
2791
|
+
recursive: true,
|
|
2792
|
+
skipPrefixes: [],
|
|
2793
|
+
skipFilenames: []
|
|
2794
|
+
},
|
|
2795
|
+
{
|
|
2796
|
+
dir: "inbox",
|
|
2797
|
+
title: "Inbox",
|
|
2798
|
+
description: "\uBBF8\uBD84\uB958 \uC784\uC2DC \uBA54\uBAA8\xB7\uC544\uC774\uB514\uC5B4\xB7\uBC31\uB85C\uADF8. \uC815\uC2DD \uBD84\uB958 \uC2DC \uD574\uB2F9 \uCE74\uD14C\uACE0\uB9AC\uB85C \uC774\uB3D9.",
|
|
2799
|
+
privacy: "internal",
|
|
2800
|
+
recursive: true,
|
|
2801
|
+
skipPrefixes: [],
|
|
2802
|
+
skipFilenames: []
|
|
2803
|
+
},
|
|
2804
|
+
{
|
|
2805
|
+
dir: "_templates",
|
|
2806
|
+
title: "Templates",
|
|
2807
|
+
description: "\uBCF4\uACE0\uC6A9\xB7\uACF5\uC720\uC6A9 \uC790\uB8CC \uD15C\uD50C\uB9BF \uBAA8\uC74C (Sharing \uB4F1).",
|
|
2808
|
+
privacy: "internal",
|
|
2809
|
+
recursive: true,
|
|
2810
|
+
skipPrefixes: [],
|
|
2811
|
+
skipFilenames: []
|
|
2812
|
+
}
|
|
2813
|
+
];
|
|
2814
|
+
var reindexCommand = {
|
|
2815
|
+
name: "reindex",
|
|
2816
|
+
description: "Regenerate _INDEX.md for one or all data directories (memory, til, decision-log).",
|
|
2817
|
+
args: [
|
|
2818
|
+
{
|
|
2819
|
+
name: "dir",
|
|
2820
|
+
description: "Optional directory name. Omit to reindex all targets."
|
|
2821
|
+
}
|
|
2822
|
+
],
|
|
2823
|
+
handler: async (input) => {
|
|
2824
|
+
const requested = input.args.dir;
|
|
2825
|
+
const targets = requested ? TARGETS.filter((t) => t.dir === requested) : TARGETS;
|
|
2826
|
+
if (requested && targets.length === 0) {
|
|
2827
|
+
throw new Error(`Unknown reindex target: "${requested}". Known: ${TARGETS.map((t) => t.dir).join(", ")}`);
|
|
2828
|
+
}
|
|
2829
|
+
const results = [];
|
|
2830
|
+
for (const t of targets) {
|
|
2831
|
+
const dir = join15(input.context.dataDir, t.dir);
|
|
2832
|
+
if (!existsSync2(dir)) {
|
|
2833
|
+
results.push({ dir: t.dir, status: "missing", entries: 0, bytes: 0 });
|
|
2834
|
+
continue;
|
|
2835
|
+
}
|
|
2836
|
+
const entries = await scanDirectory(dir, {
|
|
2837
|
+
recursive: t.recursive,
|
|
2838
|
+
skipPrefixes: t.skipPrefixes,
|
|
2839
|
+
skipFilenames: t.skipFilenames
|
|
2840
|
+
});
|
|
2841
|
+
const body = renderIndex({
|
|
2842
|
+
title: t.title,
|
|
2843
|
+
description: t.description,
|
|
2844
|
+
entries,
|
|
2845
|
+
privacy: t.privacy
|
|
2846
|
+
});
|
|
2847
|
+
const target = join15(dir, "_INDEX.md");
|
|
2848
|
+
let existing;
|
|
2849
|
+
try {
|
|
2850
|
+
existing = await readFile13(target, "utf8");
|
|
2851
|
+
} catch {
|
|
2852
|
+
existing = void 0;
|
|
2853
|
+
}
|
|
2854
|
+
if (existing === body) {
|
|
2855
|
+
results.push({
|
|
2856
|
+
dir: t.dir,
|
|
2857
|
+
status: "unchanged",
|
|
2858
|
+
entries: entries.length,
|
|
2859
|
+
bytes: body.length
|
|
2860
|
+
});
|
|
2861
|
+
continue;
|
|
2862
|
+
}
|
|
2863
|
+
await writeFile6(target, body, "utf8");
|
|
2864
|
+
results.push({
|
|
2865
|
+
dir: t.dir,
|
|
2866
|
+
status: "written",
|
|
2867
|
+
entries: entries.length,
|
|
2868
|
+
bytes: body.length
|
|
2869
|
+
});
|
|
2870
|
+
}
|
|
2871
|
+
return results;
|
|
2872
|
+
}
|
|
2873
|
+
};
|
|
2874
|
+
|
|
2875
|
+
// ../plugins/session-rituals/dist/commands/session-start.js
|
|
2876
|
+
import { existsSync as existsSync3 } from "fs";
|
|
2877
|
+
import { readdir as readdir12 } from "fs/promises";
|
|
2878
|
+
import { join as join16 } from "path";
|
|
2879
|
+
var COUNTED_DIRS = ["_memory", "til", "decision-log"];
|
|
2880
|
+
var sessionStartCommand = {
|
|
2881
|
+
name: "session-start",
|
|
2882
|
+
description: "Emit a start-of-session report (time + data directory counts).",
|
|
2883
|
+
handler: async (input) => {
|
|
2884
|
+
const { dataDir, repoRoot } = input.context;
|
|
2885
|
+
const counts = {};
|
|
2886
|
+
const missing = [];
|
|
2887
|
+
for (const name of COUNTED_DIRS) {
|
|
2888
|
+
const dir = join16(dataDir, name);
|
|
2889
|
+
if (!existsSync3(dir)) {
|
|
2890
|
+
missing.push(name);
|
|
2891
|
+
counts[name] = 0;
|
|
2892
|
+
continue;
|
|
2893
|
+
}
|
|
2894
|
+
counts[name] = await countMarkdown(dir, name === "til");
|
|
2895
|
+
}
|
|
2896
|
+
return {
|
|
2897
|
+
time: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2898
|
+
repoRoot,
|
|
2899
|
+
dataDir,
|
|
2900
|
+
counts,
|
|
2901
|
+
missing
|
|
2902
|
+
};
|
|
2903
|
+
}
|
|
2904
|
+
};
|
|
2905
|
+
async function countMarkdown(dir, recursive) {
|
|
2906
|
+
let total = 0;
|
|
2907
|
+
const entries = await readdir12(dir, { withFileTypes: true });
|
|
2908
|
+
for (const e of entries) {
|
|
2909
|
+
if (e.isFile()) {
|
|
2910
|
+
if (!e.name.endsWith(".md"))
|
|
2911
|
+
continue;
|
|
2912
|
+
if (e.name === "README.md" || e.name === "_INDEX.md" || e.name === "MEMORY.md") {
|
|
2913
|
+
continue;
|
|
2914
|
+
}
|
|
2915
|
+
if (e.name.startsWith("_TEMPLATE"))
|
|
2916
|
+
continue;
|
|
2917
|
+
total++;
|
|
2918
|
+
} else if (e.isDirectory() && recursive) {
|
|
2919
|
+
if (e.name.startsWith(".") || e.name.startsWith("_"))
|
|
2920
|
+
continue;
|
|
2921
|
+
total += await countMarkdown(join16(dir, e.name), recursive);
|
|
2922
|
+
}
|
|
2923
|
+
}
|
|
2924
|
+
return total;
|
|
2925
|
+
}
|
|
2926
|
+
|
|
2927
|
+
// ../plugins/session-rituals/dist/commands/til.js
|
|
2928
|
+
var tilCommand = {
|
|
2929
|
+
name: "til",
|
|
2930
|
+
description: "Append a section to today's TIL entry.",
|
|
2931
|
+
args: [
|
|
2932
|
+
{
|
|
2933
|
+
name: "section",
|
|
2934
|
+
description: "Title for the new `## ` section (rest of the input).",
|
|
2935
|
+
required: true
|
|
2936
|
+
}
|
|
2937
|
+
],
|
|
2938
|
+
handler: async (input) => {
|
|
2939
|
+
const sectionTitle = input.rest.trim();
|
|
2940
|
+
if (!sectionTitle) {
|
|
2941
|
+
throw new Error("`/til` requires a section title.");
|
|
2942
|
+
}
|
|
2943
|
+
const date = todayIso2();
|
|
2944
|
+
const store = new TilStore(`${input.context.dataDir}/til`);
|
|
2945
|
+
const todayEntry = await store.get(date);
|
|
2946
|
+
if (!todayEntry) {
|
|
2947
|
+
throw new Error(`No TIL entry exists for ${date}. Create one first; this command only appends sections.`);
|
|
2948
|
+
}
|
|
2949
|
+
await appendSection(todayEntry, sectionTitle, "");
|
|
2950
|
+
return {
|
|
2951
|
+
path: todayEntry.path,
|
|
2952
|
+
date: todayEntry.date,
|
|
2953
|
+
keyword: todayEntry.keyword,
|
|
2954
|
+
sectionTitle
|
|
2955
|
+
};
|
|
2956
|
+
}
|
|
2957
|
+
};
|
|
2958
|
+
function todayIso2() {
|
|
2959
|
+
const d2 = /* @__PURE__ */ new Date();
|
|
2960
|
+
const y2 = d2.getFullYear();
|
|
2961
|
+
const m2 = String(d2.getMonth() + 1).padStart(2, "0");
|
|
2962
|
+
const day = String(d2.getDate()).padStart(2, "0");
|
|
2963
|
+
return `${y2}-${m2}-${day}`;
|
|
2964
|
+
}
|
|
2965
|
+
|
|
2966
|
+
// ../plugins/session-rituals/dist/commands/vortex.js
|
|
2967
|
+
import { existsSync as existsSync4 } from "fs";
|
|
2968
|
+
import { mkdir as mkdir2, writeFile as writeFile7 } from "fs/promises";
|
|
2969
|
+
import { join as join17 } from "path";
|
|
2970
|
+
var PLANNED_SUBS = ["status", "import", "doctor"];
|
|
2971
|
+
var vortexCommand = {
|
|
2972
|
+
name: "vortex",
|
|
2973
|
+
description: "VortEX root command. Subcommands: init | status | import | doctor | help.",
|
|
2974
|
+
args: [
|
|
2975
|
+
{
|
|
2976
|
+
name: "sub",
|
|
2977
|
+
description: "Subcommand (init|status|import|doctor|help).",
|
|
2978
|
+
required: false
|
|
2979
|
+
}
|
|
2980
|
+
],
|
|
2981
|
+
handler: async (input) => {
|
|
2982
|
+
const tokens = tokenize(input.rest);
|
|
2983
|
+
const sub = tokens[0] ?? "help";
|
|
2984
|
+
const restAfterSub = tokens.slice(1);
|
|
2985
|
+
if (sub === "init")
|
|
2986
|
+
return runInit(input, restAfterSub);
|
|
2987
|
+
if (sub === "help" || sub === "")
|
|
2988
|
+
return runHelp();
|
|
2989
|
+
if (PLANNED_SUBS.includes(sub)) {
|
|
2990
|
+
return {
|
|
2991
|
+
subcommand: sub,
|
|
2992
|
+
status: "not-implemented",
|
|
2993
|
+
message: `\`/vortex ${sub}\` is reserved but not yet implemented. Planned in a future phase. Run \`/vortex help\` for available subcommands.`
|
|
2994
|
+
};
|
|
2995
|
+
}
|
|
2996
|
+
return {
|
|
2997
|
+
subcommand: "unknown",
|
|
2998
|
+
status: "not-implemented",
|
|
2999
|
+
message: `Unknown subcommand "${sub}". Run \`/vortex help\` for the list.`
|
|
3000
|
+
};
|
|
3001
|
+
}
|
|
3002
|
+
};
|
|
3003
|
+
function runHelp() {
|
|
3004
|
+
return {
|
|
3005
|
+
subcommand: "help",
|
|
3006
|
+
status: "ok",
|
|
3007
|
+
subcommands: [
|
|
3008
|
+
{
|
|
3009
|
+
name: "init",
|
|
3010
|
+
description: "First-time setup wizard. Creates user profile memory, first TIL, first topic hub.",
|
|
3011
|
+
state: "active"
|
|
3012
|
+
},
|
|
3013
|
+
{
|
|
3014
|
+
name: "status",
|
|
3015
|
+
description: "Show instance state (memory count, latest TIL, missing skeletons).",
|
|
3016
|
+
state: "planned"
|
|
3017
|
+
},
|
|
3018
|
+
{
|
|
3019
|
+
name: "import",
|
|
3020
|
+
description: "Bring an existing folder into data/imported/ for gradual sorting.",
|
|
3021
|
+
state: "planned"
|
|
3022
|
+
},
|
|
3023
|
+
{
|
|
3024
|
+
name: "doctor",
|
|
3025
|
+
description: "Diagnose common setup issues (missing modules, broken links).",
|
|
3026
|
+
state: "planned"
|
|
3027
|
+
},
|
|
3028
|
+
{ name: "help", description: "Show this list.", state: "active" }
|
|
3029
|
+
]
|
|
3030
|
+
};
|
|
3031
|
+
}
|
|
3032
|
+
async function runInit(input, tokens) {
|
|
3033
|
+
const args = parseInitArgs(tokens);
|
|
3034
|
+
const { dataDir } = input.context;
|
|
3035
|
+
const requiredDirs = ["_memory", "til", "decision-log", "hubs", "inbox"];
|
|
3036
|
+
for (const d2 of requiredDirs) {
|
|
3037
|
+
const p = join17(dataDir, d2);
|
|
3038
|
+
if (!existsSync4(p))
|
|
3039
|
+
await mkdir2(p, { recursive: true });
|
|
3040
|
+
}
|
|
3041
|
+
const profilePath = join17(dataDir, "_memory", "user_profile.md");
|
|
3042
|
+
if (existsSync4(profilePath) && !args.force) {
|
|
3043
|
+
return {
|
|
3044
|
+
subcommand: "init",
|
|
3045
|
+
status: "already-initialized",
|
|
3046
|
+
created: [],
|
|
3047
|
+
nextActions: [
|
|
3048
|
+
`VortEX instance is already initialized (${profilePath} exists).`,
|
|
3049
|
+
"To re-run, pass `--force` (existing user_profile / first TIL / first hub will be overwritten).",
|
|
3050
|
+
"To check current state, try `/session-start`."
|
|
3051
|
+
]
|
|
3052
|
+
};
|
|
3053
|
+
}
|
|
3054
|
+
const missing = [];
|
|
3055
|
+
if (!args.name) {
|
|
3056
|
+
missing.push({
|
|
3057
|
+
name: "name",
|
|
3058
|
+
prompt: 'What name or handle should VortEX use for you? (e.g. "Alex" or "team-lead")'
|
|
3059
|
+
});
|
|
3060
|
+
}
|
|
3061
|
+
if (!args.role) {
|
|
3062
|
+
missing.push({
|
|
3063
|
+
name: "role",
|
|
3064
|
+
prompt: 'What is your main role in one word? (e.g. "engineer", "researcher", "writer")'
|
|
3065
|
+
});
|
|
3066
|
+
}
|
|
3067
|
+
if (!args.task) {
|
|
3068
|
+
missing.push({
|
|
3069
|
+
name: "task",
|
|
3070
|
+
prompt: "What is one thing you're working on right now? (one sentence \u2014 this becomes your first TIL seed)"
|
|
3071
|
+
});
|
|
3072
|
+
}
|
|
3073
|
+
if (missing.length > 0) {
|
|
3074
|
+
return {
|
|
3075
|
+
subcommand: "init",
|
|
3076
|
+
status: "needs-input",
|
|
3077
|
+
created: [],
|
|
3078
|
+
missingInputs: missing,
|
|
3079
|
+
nextActions: [
|
|
3080
|
+
"Ask the user the prompts in `missingInputs`, then re-run with the answers:",
|
|
3081
|
+
' /vortex init --name "<name>" --role "<role>" --task "<task>"',
|
|
3082
|
+
"Optional: append `--force` to overwrite an already-initialized instance."
|
|
3083
|
+
]
|
|
3084
|
+
};
|
|
3085
|
+
}
|
|
3086
|
+
const today2 = todayIso3();
|
|
3087
|
+
const created = [];
|
|
3088
|
+
await writeFile7(profilePath, renderUserProfile(args.name, args.role, args.task, today2), "utf8");
|
|
3089
|
+
created.push(profilePath);
|
|
3090
|
+
const [year, month] = today2.split("-");
|
|
3091
|
+
const tilDir = join17(dataDir, "til", year, month);
|
|
3092
|
+
await mkdir2(tilDir, { recursive: true });
|
|
3093
|
+
const tilPath = join17(tilDir, `${today2}-vortex-init.md`);
|
|
3094
|
+
await writeFile7(tilPath, renderFirstTil(args.name, args.role, args.task, today2), "utf8");
|
|
3095
|
+
created.push(tilPath);
|
|
3096
|
+
const hubSlug = slugify(args.role);
|
|
3097
|
+
const hubPath = join17(dataDir, "hubs", `_HUB-${hubSlug}.md`);
|
|
3098
|
+
await writeFile7(hubPath, renderFirstHub(args.role, today2), "utf8");
|
|
3099
|
+
created.push(hubPath);
|
|
3100
|
+
return {
|
|
3101
|
+
subcommand: "init",
|
|
3102
|
+
status: "completed",
|
|
3103
|
+
created,
|
|
3104
|
+
nextActions: [
|
|
3105
|
+
`Done. Created ${created.length} files.`,
|
|
3106
|
+
"Next 3 things you can try right now:",
|
|
3107
|
+
" /til <one-line update> \u2014 append a section to today's TIL",
|
|
3108
|
+
" /decision <slug> <title> \u2014 record a decision",
|
|
3109
|
+
" /session-start \u2014 daily start-of-session report",
|
|
3110
|
+
`Open ${tilPath} to see your first TIL \u2014 it already names "${args.task}".`
|
|
3111
|
+
]
|
|
3112
|
+
};
|
|
3113
|
+
}
|
|
3114
|
+
function parseInitArgs(tokens) {
|
|
3115
|
+
const args = {};
|
|
3116
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
3117
|
+
const t = tokens[i];
|
|
3118
|
+
if (t === "--force") {
|
|
3119
|
+
args.force = true;
|
|
3120
|
+
continue;
|
|
3121
|
+
}
|
|
3122
|
+
if (t === "--name" && i + 1 < tokens.length) {
|
|
3123
|
+
args.name = tokens[++i];
|
|
3124
|
+
continue;
|
|
3125
|
+
}
|
|
3126
|
+
if (t === "--role" && i + 1 < tokens.length) {
|
|
3127
|
+
args.role = tokens[++i];
|
|
3128
|
+
continue;
|
|
3129
|
+
}
|
|
3130
|
+
if (t === "--task" && i + 1 < tokens.length) {
|
|
3131
|
+
args.task = tokens[++i];
|
|
3132
|
+
continue;
|
|
3133
|
+
}
|
|
3134
|
+
}
|
|
3135
|
+
return args;
|
|
3136
|
+
}
|
|
3137
|
+
function tokenize(s) {
|
|
3138
|
+
const out = [];
|
|
3139
|
+
let i = 0;
|
|
3140
|
+
while (i < s.length) {
|
|
3141
|
+
while (i < s.length && /\s/.test(s[i]))
|
|
3142
|
+
i++;
|
|
3143
|
+
if (i >= s.length)
|
|
3144
|
+
break;
|
|
3145
|
+
const ch = s[i];
|
|
3146
|
+
if (ch === '"' || ch === "'") {
|
|
3147
|
+
const quote = ch;
|
|
3148
|
+
i++;
|
|
3149
|
+
let buf = "";
|
|
3150
|
+
while (i < s.length && s[i] !== quote) {
|
|
3151
|
+
buf += s[i++];
|
|
3152
|
+
}
|
|
3153
|
+
if (i < s.length)
|
|
3154
|
+
i++;
|
|
3155
|
+
out.push(buf);
|
|
3156
|
+
} else {
|
|
3157
|
+
let buf = "";
|
|
3158
|
+
while (i < s.length && !/\s/.test(s[i])) {
|
|
3159
|
+
buf += s[i++];
|
|
3160
|
+
}
|
|
3161
|
+
out.push(buf);
|
|
3162
|
+
}
|
|
3163
|
+
}
|
|
3164
|
+
return out;
|
|
3165
|
+
}
|
|
3166
|
+
function renderUserProfile(name, role, task, date) {
|
|
3167
|
+
return `---
|
|
3168
|
+
name: user-profile
|
|
3169
|
+
description: Operator profile captured by /vortex init.
|
|
3170
|
+
type: user
|
|
3171
|
+
created: ${date}
|
|
3172
|
+
updated: ${date}
|
|
3173
|
+
---
|
|
3174
|
+
|
|
3175
|
+
# User Profile
|
|
3176
|
+
|
|
3177
|
+
- **Name/handle**: ${name}
|
|
3178
|
+
- **Role**: ${role}
|
|
3179
|
+
- **Initial focus**: ${task}
|
|
3180
|
+
|
|
3181
|
+
This memory was created by \`/vortex init\` on ${date}. Edit freely as your role evolves.
|
|
3182
|
+
|
|
3183
|
+
Linked: [[_HUB-${slugify(role)}]] \u2014 primary topic hub.
|
|
3184
|
+
`;
|
|
3185
|
+
}
|
|
3186
|
+
function renderFirstTil(name, role, task, date) {
|
|
3187
|
+
return `---
|
|
3188
|
+
type: til
|
|
3189
|
+
status: active
|
|
3190
|
+
created: ${date}
|
|
3191
|
+
updated: ${date}
|
|
3192
|
+
tags: [til, onboarding]
|
|
3193
|
+
---
|
|
3194
|
+
|
|
3195
|
+
# ${date} \u2014 VortEX \uC2DC\uC791
|
|
3196
|
+
|
|
3197
|
+
> First TIL, created by \`/vortex init\`. ${name} (${role}). Today's focus: ${task}
|
|
3198
|
+
|
|
3199
|
+
## What I'm working on
|
|
3200
|
+
|
|
3201
|
+
${task}
|
|
3202
|
+
|
|
3203
|
+
## Notes
|
|
3204
|
+
|
|
3205
|
+
(append more with \`/til <section-title>\`)
|
|
3206
|
+
|
|
3207
|
+
## Next
|
|
3208
|
+
|
|
3209
|
+
- [ ] Try \`/decision <slug> <title>\` for your first decision record
|
|
3210
|
+
- [ ] Add a memory by editing \`data/_memory/user_profile.md\` or creating new ones
|
|
3211
|
+
- [ ] Run \`/session-start\` tomorrow to see your accumulated state
|
|
3212
|
+
`;
|
|
3213
|
+
}
|
|
3214
|
+
function renderFirstHub(role, date) {
|
|
3215
|
+
return `---
|
|
3216
|
+
type: hub
|
|
3217
|
+
status: active
|
|
3218
|
+
privacy: internal
|
|
3219
|
+
created: ${date}
|
|
3220
|
+
updated: ${date}
|
|
3221
|
+
tags: [hub, ${slugify(role)}]
|
|
3222
|
+
---
|
|
3223
|
+
|
|
3224
|
+
# ${role} Hub
|
|
3225
|
+
|
|
3226
|
+
> Topic hub for everything related to ${role}. Auto-created by \`/vortex init\`. Edit freely.
|
|
3227
|
+
|
|
3228
|
+
## Active TILs
|
|
3229
|
+
|
|
3230
|
+
- (link your ${role}-related TILs here as you accumulate them)
|
|
3231
|
+
|
|
3232
|
+
## Decisions
|
|
3233
|
+
|
|
3234
|
+
- (link Decision Log entries here)
|
|
3235
|
+
|
|
3236
|
+
## Memories
|
|
3237
|
+
|
|
3238
|
+
- (link \`_memory/*.md\` entries here)
|
|
3239
|
+
|
|
3240
|
+
## External references
|
|
3241
|
+
|
|
3242
|
+
- (links, dashboards, repos, etc.)
|
|
3243
|
+
`;
|
|
3244
|
+
}
|
|
3245
|
+
function slugify(s) {
|
|
3246
|
+
return s.toLowerCase().replace(/[^a-z0-9가-힣]+/g, "-").replace(/^-+|-+$/g, "");
|
|
3247
|
+
}
|
|
3248
|
+
function todayIso3() {
|
|
3249
|
+
const d2 = /* @__PURE__ */ new Date();
|
|
3250
|
+
const y2 = d2.getFullYear();
|
|
3251
|
+
const m2 = String(d2.getMonth() + 1).padStart(2, "0");
|
|
3252
|
+
const day = String(d2.getDate()).padStart(2, "0");
|
|
3253
|
+
return `${y2}-${m2}-${day}`;
|
|
3254
|
+
}
|
|
3255
|
+
|
|
3256
|
+
// ../plugins/session-rituals/dist/registry.js
|
|
3257
|
+
function createRitualRegistry() {
|
|
3258
|
+
const registry = new CommandRegistry();
|
|
3259
|
+
registry.register(sessionStartCommand);
|
|
3260
|
+
registry.register(reindexCommand);
|
|
3261
|
+
registry.register(decisionCommand);
|
|
3262
|
+
registry.register(tilCommand);
|
|
3263
|
+
registry.register(vortexCommand);
|
|
3264
|
+
return registry;
|
|
3265
|
+
}
|
|
3266
|
+
export {
|
|
3267
|
+
dist_exports5 as aiCodingPitfalls,
|
|
3268
|
+
dist_exports as core,
|
|
3269
|
+
dist_exports4 as dataLint,
|
|
3270
|
+
dist_exports9 as decisionLog,
|
|
3271
|
+
dist_exports10 as indexGenerator,
|
|
3272
|
+
dist_exports12 as linkRewriter,
|
|
3273
|
+
dist_exports3 as memorySystem,
|
|
3274
|
+
dist_exports7 as reportGenerator,
|
|
3275
|
+
dist_exports11 as runbooks,
|
|
3276
|
+
dist_exports13 as sessionRituals,
|
|
3277
|
+
dist_exports2 as slashCommands,
|
|
3278
|
+
dist_exports8 as til,
|
|
3279
|
+
dist_exports6 as toolRules
|
|
21
3280
|
};
|
|
22
3281
|
//# sourceMappingURL=index.js.map
|