modelroom 0.0.0-stage → 0.0.2
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/CHANGELOG.md +32 -0
- package/LICENSE +21 -0
- package/README.md +149 -2
- package/dist/bin/modelroom.d.ts +3 -0
- package/dist/bin/modelroom.d.ts.map +1 -0
- package/dist/bin/modelroom.js +242 -0
- package/dist/bin/modelroom.js.map +1 -0
- package/dist/lib/agents/index.d.ts +22 -0
- package/dist/lib/agents/index.d.ts.map +1 -0
- package/dist/lib/agents/index.js +68 -0
- package/dist/lib/agents/index.js.map +1 -0
- package/dist/lib/artifact.d.ts +22 -0
- package/dist/lib/artifact.d.ts.map +1 -0
- package/dist/lib/artifact.js +62 -0
- package/dist/lib/artifact.js.map +1 -0
- package/dist/lib/config.d.ts +53 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +92 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/facets.d.ts +62 -0
- package/dist/lib/facets.d.ts.map +1 -0
- package/dist/lib/facets.js +181 -0
- package/dist/lib/facets.js.map +1 -0
- package/dist/lib/frontmatter.d.ts +41 -0
- package/dist/lib/frontmatter.d.ts.map +1 -0
- package/dist/lib/frontmatter.js +219 -0
- package/dist/lib/frontmatter.js.map +1 -0
- package/dist/lib/lint.d.ts +26 -0
- package/dist/lib/lint.d.ts.map +1 -0
- package/dist/lib/lint.js +139 -0
- package/dist/lib/lint.js.map +1 -0
- package/dist/lib/opencode.d.ts +42 -0
- package/dist/lib/opencode.d.ts.map +1 -0
- package/dist/lib/opencode.js +229 -0
- package/dist/lib/opencode.js.map +1 -0
- package/dist/lib/pkg.d.ts +2 -0
- package/dist/lib/pkg.d.ts.map +1 -0
- package/dist/lib/pkg.js +19 -0
- package/dist/lib/pkg.js.map +1 -0
- package/dist/lib/rooms.d.ts +63 -0
- package/dist/lib/rooms.d.ts.map +1 -0
- package/dist/lib/rooms.js +178 -0
- package/dist/lib/rooms.js.map +1 -0
- package/dist/lib/server.d.ts +53 -0
- package/dist/lib/server.d.ts.map +1 -0
- package/dist/lib/server.js +538 -0
- package/dist/lib/server.js.map +1 -0
- package/docs/01_concept.md +69 -0
- package/docs/02-convention.md +109 -0
- package/docs/03-cli.md +103 -0
- package/docs/04-agents.md +88 -0
- package/examples/rooms/sign-in/BEHAVIOUR.md +23 -0
- package/examples/rooms/sign-in/BRIEF.md +15 -0
- package/examples/rooms/sign-in/SPEC.md +14 -0
- package/examples/rooms/sign-in/index.html +56 -0
- package/package.json +83 -4
- package/templates/AGENTS.md +31 -0
- package/templates/modelroom.json +14 -0
- package/templates/room/BEHAVIOUR.md +19 -0
- package/templates/room/BRIEF.md +16 -0
- package/templates/room/SPEC.md +9 -0
- package/templates/room/index.html +53 -0
- package/ui/dashboard.html +332 -0
- package/ui/modelroom.css +2 -0
- package/ui/room.html +466 -0
- package/ui/settings.html +125 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// modelroom — optional artifact rendering (HTML → PNG)
|
|
2
|
+
//
|
|
3
|
+
// Rendering is optional: it needs Playwright with a browser installed. If it is not
|
|
4
|
+
// there, modelroom still works — the room just has no thumbnail.
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { stat } from 'node:fs/promises';
|
|
7
|
+
export async function playwrightAvailable() {
|
|
8
|
+
try {
|
|
9
|
+
await import('playwright');
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export const INSTALL_HINT = 'PNG rendering needs Playwright:\n' +
|
|
17
|
+
' npm install --include=dev playwright && npx playwright install chromium\n' +
|
|
18
|
+
'(modelroom works without it — the room just has no thumbnail.)';
|
|
19
|
+
const WIDTHS = { sp: 390, tablet: 1024, pc: 1280 };
|
|
20
|
+
/**
|
|
21
|
+
* Render `rooms/<room>/<artifact>` to `<artifact>.png` next to it.
|
|
22
|
+
*/
|
|
23
|
+
export async function renderArtifact({ cfg, room, device = 'tablet', scale = 2, }) {
|
|
24
|
+
let chromium;
|
|
25
|
+
try {
|
|
26
|
+
({ chromium } = await import('playwright'));
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return { ok: false, error: INSTALL_HINT };
|
|
30
|
+
}
|
|
31
|
+
const width = WIDTHS[device] ?? 1024;
|
|
32
|
+
const src = join(cfg.roomsDir, room, cfg.artifact);
|
|
33
|
+
const out = src.replace(/\.html?$/i, '.png');
|
|
34
|
+
try {
|
|
35
|
+
await stat(src);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return { ok: false, error: `artifact not found: ${cfg.rooms}/${room}/${cfg.artifact}` };
|
|
39
|
+
}
|
|
40
|
+
const browser = await chromium.launch();
|
|
41
|
+
try {
|
|
42
|
+
const page = await browser.newPage({
|
|
43
|
+
viewport: { width, height: 800 },
|
|
44
|
+
deviceScaleFactor: scale,
|
|
45
|
+
});
|
|
46
|
+
await page.goto('file://' + src, { waitUntil: 'networkidle' });
|
|
47
|
+
await page.evaluate(() => document.fonts?.ready).catch(() => { });
|
|
48
|
+
await page.waitForTimeout(250);
|
|
49
|
+
const height = await page.evaluate(() => Math.ceil(document.body.getBoundingClientRect().height));
|
|
50
|
+
await page.setViewportSize({ width, height });
|
|
51
|
+
await page.waitForTimeout(150);
|
|
52
|
+
await page.screenshot({ path: out, fullPage: true, type: 'png' });
|
|
53
|
+
return { ok: true, png: out, width, height };
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
await browser.close().catch(() => { });
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=artifact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact.js","sourceRoot":"","sources":["../../lib/artifact.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export type AdapterName = 'opencode' | 'command';
|
|
2
|
+
export interface AgentConfig {
|
|
3
|
+
adapter: AdapterName;
|
|
4
|
+
command: string;
|
|
5
|
+
/** e.g. "openrouter/deepseek/deepseek-v4.1-flash" (null = let the agent decide) */
|
|
6
|
+
model: string | null;
|
|
7
|
+
agent: string;
|
|
8
|
+
/** opencode: run with a private server (uses this process's env) */
|
|
9
|
+
standalone: boolean;
|
|
10
|
+
/** command adapter: e.g. ["-p", "{prompt}"] */
|
|
11
|
+
args: string[];
|
|
12
|
+
}
|
|
13
|
+
export interface Config {
|
|
14
|
+
root: string;
|
|
15
|
+
rooms: string;
|
|
16
|
+
artifact: string;
|
|
17
|
+
docs: string[];
|
|
18
|
+
port: number;
|
|
19
|
+
host: string;
|
|
20
|
+
agent: AgentConfig;
|
|
21
|
+
/** Resolved at load time. */
|
|
22
|
+
rootDir: string;
|
|
23
|
+
roomsDir: string;
|
|
24
|
+
configPath: string;
|
|
25
|
+
stateDir: string;
|
|
26
|
+
statePath: string;
|
|
27
|
+
}
|
|
28
|
+
export interface State {
|
|
29
|
+
sessions: Record<string, string>;
|
|
30
|
+
settings: Record<string, unknown>;
|
|
31
|
+
}
|
|
32
|
+
export declare const DEFAULTS: {
|
|
33
|
+
readonly root: '.';
|
|
34
|
+
readonly rooms: 'rooms';
|
|
35
|
+
readonly artifact: 'index.html';
|
|
36
|
+
readonly docs: readonly ['BRIEF.md', 'SPEC.md', 'BEHAVIOUR.md'];
|
|
37
|
+
readonly port: 4321;
|
|
38
|
+
readonly host: '127.0.0.1';
|
|
39
|
+
readonly agent: {
|
|
40
|
+
readonly adapter: 'opencode';
|
|
41
|
+
readonly command: 'opencode';
|
|
42
|
+
readonly model: null;
|
|
43
|
+
readonly agent: 'build';
|
|
44
|
+
readonly standalone: true;
|
|
45
|
+
readonly args: readonly [];
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
export declare function loadConfig(cwd?: string): Promise<Config>;
|
|
49
|
+
export declare function loadState(cfg: Config): Promise<State>;
|
|
50
|
+
export declare function saveState(cfg: Config, state: State): Promise<void>;
|
|
51
|
+
/** Settings the UI may change (whitelist). */
|
|
52
|
+
export declare function applySettings(cfg: Config, patch: Record<string, unknown>): Record<string, unknown>;
|
|
53
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../lib/config.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,SAAS,CAAC;AAEjD,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,WAAW,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,mFAAmF;IACnF,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,UAAU,EAAE,OAAO,CAAC;IACpB,+CAA+C;IAC/C,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,WAAW,CAAC;IACnB,6BAA6B;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,KAAK;IACpB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,eAAO,MAAM,QAAQ;aACnB,IAAI,EAAE,GAAG;aACT,KAAK,EAAE,OAAO;aACd,QAAQ,EAAE,YAAY;aACtB,IAAI,YAAG,UAAU,EAAE,SAAS,EAAE,cAAc;aAC5C,IAAI,EAAE,IAAI;aACV,IAAI,EAAE,WAAW;aACjB,KAAK;iBACH,OAAO,EAAE,UAAU;iBACnB,OAAO,EAAE,UAAU;iBACnB,KAAK;iBACL,KAAK,EAAE,OAAO;iBACd,UAAU;iBACV,IAAI;;CAEE,CAAC;AAIX,wBAAsB,UAAU,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,MAAM,CAAC,CA2B7E;AAED,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAO3D;AAED,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAKxE;AAED,8CAA8C;AAC9C,wBAAgB,aAAa,CAC3B,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAuBzB"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// modelroom — config and state
|
|
2
|
+
//
|
|
3
|
+
// Config (`modelroom.json`) is committed. State (`.modelroom/state.json`) is local:
|
|
4
|
+
// chat sessions per room, and any settings changed from the UI.
|
|
5
|
+
import { readFile, writeFile, mkdir, rename } from 'node:fs/promises';
|
|
6
|
+
import { dirname, join, resolve } from 'node:path';
|
|
7
|
+
export const DEFAULTS = {
|
|
8
|
+
root: '.',
|
|
9
|
+
rooms: 'rooms',
|
|
10
|
+
artifact: 'index.html',
|
|
11
|
+
docs: ['BRIEF.md', 'SPEC.md', 'BEHAVIOUR.md'],
|
|
12
|
+
port: 4321,
|
|
13
|
+
host: '127.0.0.1',
|
|
14
|
+
agent: {
|
|
15
|
+
adapter: 'opencode',
|
|
16
|
+
command: 'opencode',
|
|
17
|
+
model: null,
|
|
18
|
+
agent: 'build',
|
|
19
|
+
standalone: true,
|
|
20
|
+
args: [],
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
export async function loadConfig(cwd = process.cwd()) {
|
|
24
|
+
const path = resolve(cwd, 'modelroom.json');
|
|
25
|
+
let file = {};
|
|
26
|
+
try {
|
|
27
|
+
file = JSON.parse(await readFile(path, 'utf8'));
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
/* no config: defaults */
|
|
31
|
+
}
|
|
32
|
+
const cfg = {
|
|
33
|
+
root: file.root ?? DEFAULTS.root,
|
|
34
|
+
rooms: file.rooms ?? DEFAULTS.rooms,
|
|
35
|
+
artifact: file.artifact ?? DEFAULTS.artifact,
|
|
36
|
+
docs: Array.isArray(file.docs) && file.docs.length ? file.docs : [...DEFAULTS.docs],
|
|
37
|
+
port: file.port ?? DEFAULTS.port,
|
|
38
|
+
host: file.host ?? DEFAULTS.host,
|
|
39
|
+
agent: { ...DEFAULTS.agent, ...file.agent },
|
|
40
|
+
rootDir: '',
|
|
41
|
+
roomsDir: '',
|
|
42
|
+
configPath: path,
|
|
43
|
+
stateDir: '',
|
|
44
|
+
statePath: '',
|
|
45
|
+
};
|
|
46
|
+
cfg.rootDir = resolve(cwd, cfg.root);
|
|
47
|
+
cfg.roomsDir = resolve(cfg.rootDir, cfg.rooms);
|
|
48
|
+
cfg.stateDir = join(cfg.rootDir, '.modelroom');
|
|
49
|
+
cfg.statePath = join(cfg.stateDir, 'state.json');
|
|
50
|
+
return cfg;
|
|
51
|
+
}
|
|
52
|
+
export async function loadState(cfg) {
|
|
53
|
+
try {
|
|
54
|
+
const raw = JSON.parse(await readFile(cfg.statePath, 'utf8'));
|
|
55
|
+
return { sessions: raw.sessions ?? {}, settings: raw.settings ?? {} };
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return { sessions: {}, settings: {} };
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
export async function saveState(cfg, state) {
|
|
62
|
+
await mkdir(dirname(cfg.statePath), { recursive: true });
|
|
63
|
+
const tmp = cfg.statePath + '.tmp';
|
|
64
|
+
await writeFile(tmp, JSON.stringify(state, null, 2) + '\n');
|
|
65
|
+
await rename(tmp, cfg.statePath);
|
|
66
|
+
}
|
|
67
|
+
/** Settings the UI may change (whitelist). */
|
|
68
|
+
export function applySettings(cfg, patch) {
|
|
69
|
+
const applied = {};
|
|
70
|
+
if (typeof patch.model === 'string') {
|
|
71
|
+
cfg.agent.model = patch.model || null;
|
|
72
|
+
applied.model = cfg.agent.model;
|
|
73
|
+
}
|
|
74
|
+
if (typeof patch.agent === 'string' && patch.agent) {
|
|
75
|
+
cfg.agent.agent = patch.agent;
|
|
76
|
+
applied.agent = cfg.agent.agent;
|
|
77
|
+
}
|
|
78
|
+
if (patch.adapter === 'opencode' || patch.adapter === 'command') {
|
|
79
|
+
cfg.agent.adapter = patch.adapter;
|
|
80
|
+
applied.adapter = cfg.agent.adapter;
|
|
81
|
+
}
|
|
82
|
+
if (typeof patch.command === 'string' && patch.command) {
|
|
83
|
+
cfg.agent.command = patch.command;
|
|
84
|
+
applied.command = cfg.agent.command;
|
|
85
|
+
}
|
|
86
|
+
if (typeof patch.standalone === 'boolean') {
|
|
87
|
+
cfg.agent.standalone = patch.standalone;
|
|
88
|
+
applied.standalone = cfg.agent.standalone;
|
|
89
|
+
}
|
|
90
|
+
return applied;
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../lib/config.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,EAAE;AACF,oFAAoF;AACpF,gEAAgE;AAEhE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAqCnD,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,IAAI,EAAE,GAAG;IACT,KAAK,EAAE,OAAO;IACd,QAAQ,EAAE,YAAY;IACtB,IAAI,EAAE,CAAC,UAAU,EAAE,SAAS,EAAE,cAAc,CAAC;IAC7C,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,WAAW;IACjB,KAAK,EAAE;QACL,OAAO,EAAE,UAAU;QACnB,OAAO,EAAE,UAAU;QACnB,KAAK,EAAE,IAAI;QACX,KAAK,EAAE,OAAO;QACd,UAAU,EAAE,IAAI;QAChB,IAAI,EAAE,EAAE;KACT;CACO,CAAC;AAIX,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAG,GAAW,OAAO,CAAC,GAAG,EAAE;IAC1D,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;IAC5C,IAAI,IAAI,GAAe,EAAE,CAAC;IAC1B,IAAI,CAAC;QACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAe,CAAC;IAChE,CAAC;IAAC,MAAM,CAAC;QACP,yBAAyB;IAC3B,CAAC;IACD,MAAM,GAAG,GAAG;QACV,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI;QAChC,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,QAAQ,CAAC,KAAK;QACnC,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,QAAQ;QAC5C,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC;QACnF,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI;QAChC,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI;QAChC,KAAK,EAAE,EAAE,GAAG,QAAQ,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,KAAK,EAAiB;QAC1D,OAAO,EAAE,EAAE;QACX,QAAQ,EAAE,EAAE;QACZ,UAAU,EAAE,IAAI;QAChB,QAAQ,EAAE,EAAE;QACZ,SAAS,EAAE,EAAE;KACG,CAAC;IACnB,GAAG,CAAC,OAAO,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;IACrC,GAAG,CAAC,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;IAC/C,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IAC/C,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IACjD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,GAAW;IACzC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAmB,CAAC;QAChF,OAAO,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,IAAI,EAAE,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,IAAI,EAAE,EAAE,CAAC;IACxE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IACxC,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,GAAW,EAAE,KAAY;IACvD,MAAM,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzD,MAAM,GAAG,GAAG,GAAG,CAAC,SAAS,GAAG,MAAM,CAAC;IACnC,MAAM,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAC5D,MAAM,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;AACnC,CAAC;AAED,8CAA8C;AAC9C,MAAM,UAAU,aAAa,CAC3B,GAAW,EACX,KAA8B;IAE9B,MAAM,OAAO,GAA4B,EAAE,CAAC;IAC5C,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QACpC,GAAG,CAAC,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC;QACtC,OAAO,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC;IAClC,CAAC;IACD,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QACnD,GAAG,CAAC,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;QAC9B,OAAO,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC;IAClC,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,KAAK,UAAU,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QAChE,GAAG,CAAC,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;QAClC,OAAO,CAAC,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC;IACtC,CAAC;IACD,IAAI,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;QACvD,GAAG,CAAC,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;QAClC,OAAO,CAAC,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC;IACtC,CAAC;IACD,IAAI,OAAO,KAAK,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QAC1C,GAAG,CAAC,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;QACxC,OAAO,CAAC,UAAU,GAAG,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC;IAC5C,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { Frontmatter } from './frontmatter.ts';
|
|
2
|
+
/** Keys that are shown on the card, not used as filters. */
|
|
3
|
+
export declare const NOT_FACETS: Set<string>;
|
|
4
|
+
/** How many values before a control stops being useful. */
|
|
5
|
+
export declare const LIMITS: {
|
|
6
|
+
readonly radio: 8;
|
|
7
|
+
readonly select: 300;
|
|
8
|
+
readonly checkboxes: 50;
|
|
9
|
+
};
|
|
10
|
+
export type Control = 'radio' | 'select' | 'checkboxes' | null;
|
|
11
|
+
export interface FacetValue {
|
|
12
|
+
value: string;
|
|
13
|
+
count: number;
|
|
14
|
+
}
|
|
15
|
+
export interface Facet {
|
|
16
|
+
key: string;
|
|
17
|
+
kind: 'string' | 'array';
|
|
18
|
+
control: Exclude<Control, null>;
|
|
19
|
+
values: FacetValue[];
|
|
20
|
+
}
|
|
21
|
+
export declare function controlFor(isArray: boolean, cardinality: number): Control;
|
|
22
|
+
export interface FacetRoom {
|
|
23
|
+
fields?: Frontmatter;
|
|
24
|
+
deprecated?: boolean;
|
|
25
|
+
}
|
|
26
|
+
/** Build filter facets from the rooms' merged frontmatter. */
|
|
27
|
+
export declare function buildFacets(rooms: Array<FacetRoom | null | undefined>): Facet[];
|
|
28
|
+
export declare function normalize(value: unknown): string;
|
|
29
|
+
export type Filters = Record<string, string[] | undefined>;
|
|
30
|
+
/** Keep a room when every chosen facet matches (OR within a facet). */
|
|
31
|
+
export declare function matchesFilters(room: {
|
|
32
|
+
fields?: Frontmatter;
|
|
33
|
+
} | null | undefined, filters?: Filters): boolean;
|
|
34
|
+
/** Markdown markers read as noise in a one-line excerpt. */
|
|
35
|
+
export declare function plainMarkdown(text: unknown): string;
|
|
36
|
+
export interface Snippet {
|
|
37
|
+
line: number;
|
|
38
|
+
text: string;
|
|
39
|
+
}
|
|
40
|
+
/** A short excerpt around the first match, with its line number in the body. */
|
|
41
|
+
export declare function snippet(text: string | null | undefined, tokens: string[] | null | undefined, radius?: number): Snippet | null;
|
|
42
|
+
export interface SearchRoom {
|
|
43
|
+
name: string;
|
|
44
|
+
title: string;
|
|
45
|
+
summary: string | null;
|
|
46
|
+
tags: string[];
|
|
47
|
+
keyPoints: string[];
|
|
48
|
+
bodyText: string;
|
|
49
|
+
}
|
|
50
|
+
export interface SearchHit {
|
|
51
|
+
name: string;
|
|
52
|
+
score: number;
|
|
53
|
+
snippets: Snippet[];
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Full-text search over title, summary, tags, key points and the docs' bodies.
|
|
57
|
+
* Every token must appear somewhere (AND); scoring only decides the order.
|
|
58
|
+
*/
|
|
59
|
+
export declare function searchRooms(rooms: SearchRoom[] | null | undefined, query: string | null | undefined, { limit }?: {
|
|
60
|
+
limit?: number;
|
|
61
|
+
}): SearchHit[];
|
|
62
|
+
//# sourceMappingURL=facets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"facets.d.ts","sourceRoot":"","sources":["../../lib/facets.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAoB,MAAM,kBAAkB,CAAC;AAEtE,4DAA4D;AAC5D,eAAO,MAAM,UAAU,aAQrB,CAAC;AAEH,2DAA2D;AAC3D,eAAO,MAAM,MAAM;aAAK,KAAK,EAAE,CAAC;aAAE,MAAM,EAAE,GAAG;aAAE,UAAU,EAAE,EAAE;CAAW,CAAC;AAEzE,MAAM,MAAM,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,YAAY,GAAG,IAAI,CAAC;AAE/D,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,KAAK;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAChC,MAAM,EAAE,UAAU,EAAE,CAAC;CACtB;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAKzE;AAKD,MAAM,WAAW,SAAS;IACxB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,8DAA8D;AAC9D,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC,SAAS,GAAG,IAAI,GAAG,SAAS,CAAC,GAAG,KAAK,EAAE,CAqC/E;AASD,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEhD;AAED,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;AAE3D,uEAAuE;AACvE,wBAAgB,cAAc,CAC5B,IAAI,EAAE;IAAE,MAAM,CAAC,EAAE,WAAW,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,EACjD,OAAO,GAAE,OAAY,GACpB,OAAO,CAUT;AAED,4DAA4D;AAC5D,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAWnD;AAID,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,gFAAgF;AAChF,wBAAgB,OAAO,CACrB,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC/B,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,GAAG,SAAS,EACnC,MAAM,SAAS,GACd,OAAO,GAAG,IAAI,CAsBhB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAUD;;;GAGG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,UAAU,EAAE,GAAG,IAAI,GAAG,SAAS,EACtC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAChC,EAAE,KAAW,EAAE,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GACvC,SAAS,EAAE,CA6Bb"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
// modelroom — facets and search
|
|
2
|
+
//
|
|
3
|
+
// The dashboard's controls are not configured: they are derived from the records.
|
|
4
|
+
// A string becomes a radio group or a select (unique values, with counts); a list
|
|
5
|
+
// becomes checkboxes. Values are free — a facet shows what exists, it does not
|
|
6
|
+
// decide what is allowed.
|
|
7
|
+
/** Keys that are shown on the card, not used as filters. */
|
|
8
|
+
export const NOT_FACETS = new Set([
|
|
9
|
+
'id',
|
|
10
|
+
'title',
|
|
11
|
+
'summary',
|
|
12
|
+
'key_points',
|
|
13
|
+
'updated_at',
|
|
14
|
+
'superseded_by',
|
|
15
|
+
'deprecated',
|
|
16
|
+
]);
|
|
17
|
+
/** How many values before a control stops being useful. */
|
|
18
|
+
export const LIMITS = { radio: 8, select: 300, checkboxes: 50 };
|
|
19
|
+
export function controlFor(isArray, cardinality) {
|
|
20
|
+
if (isArray)
|
|
21
|
+
return cardinality <= LIMITS.checkboxes ? 'checkboxes' : null;
|
|
22
|
+
if (cardinality <= LIMITS.radio)
|
|
23
|
+
return 'radio';
|
|
24
|
+
if (cardinality <= LIMITS.select)
|
|
25
|
+
return 'select';
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
const cmp = (a, b) => b.count - a.count || String(a.value).localeCompare(String(b.value), 'ja');
|
|
29
|
+
/** Build filter facets from the rooms' merged frontmatter. */
|
|
30
|
+
export function buildFacets(rooms) {
|
|
31
|
+
const values = new Map();
|
|
32
|
+
const arrays = new Map();
|
|
33
|
+
for (const room of rooms) {
|
|
34
|
+
if (!room || room.deprecated)
|
|
35
|
+
continue;
|
|
36
|
+
for (const [key, value] of Object.entries(room.fields ?? {})) {
|
|
37
|
+
if (NOT_FACETS.has(key) || value === null || value === undefined)
|
|
38
|
+
continue;
|
|
39
|
+
const list = Array.isArray(value) ? value : [value];
|
|
40
|
+
if (!list.length)
|
|
41
|
+
continue;
|
|
42
|
+
if (!values.has(key))
|
|
43
|
+
values.set(key, new Map());
|
|
44
|
+
const counts = values.get(key);
|
|
45
|
+
for (const v of list) {
|
|
46
|
+
if (v === null || v === undefined || typeof v === 'object')
|
|
47
|
+
continue;
|
|
48
|
+
const s = String(v);
|
|
49
|
+
counts.set(s, (counts.get(s) ?? 0) + 1);
|
|
50
|
+
}
|
|
51
|
+
if (Array.isArray(value))
|
|
52
|
+
arrays.set(key, true);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const facets = [];
|
|
56
|
+
for (const [key, counts] of values) {
|
|
57
|
+
const entries = [...counts].map(([value, count]) => ({ value, count })).sort(cmp);
|
|
58
|
+
const isArray = Boolean(arrays.get(key));
|
|
59
|
+
const control = controlFor(isArray, entries.length);
|
|
60
|
+
if (!control || entries.length < 2)
|
|
61
|
+
continue;
|
|
62
|
+
facets.push({ key, kind: isArray ? 'array' : 'string', control, values: entries });
|
|
63
|
+
}
|
|
64
|
+
// status first, then tags, then the narrowest facets.
|
|
65
|
+
const rank = (key) => (key === 'status' ? 0 : key === 'tags' ? 1 : 2);
|
|
66
|
+
facets.sort((a, b) => rank(a.key) - rank(b.key) || a.values.length - b.values.length || a.key.localeCompare(b.key));
|
|
67
|
+
return facets;
|
|
68
|
+
}
|
|
69
|
+
/** Stringify only primitives; objects and arrays have no text form. */
|
|
70
|
+
function primitive(value) {
|
|
71
|
+
if (typeof value === 'string')
|
|
72
|
+
return value;
|
|
73
|
+
if (typeof value === 'number' || typeof value === 'boolean')
|
|
74
|
+
return String(value);
|
|
75
|
+
return '';
|
|
76
|
+
}
|
|
77
|
+
export function normalize(value) {
|
|
78
|
+
return primitive(value).normalize('NFKC').toLowerCase();
|
|
79
|
+
}
|
|
80
|
+
/** Keep a room when every chosen facet matches (OR within a facet). */
|
|
81
|
+
export function matchesFilters(room, filters = {}) {
|
|
82
|
+
for (const [key, wanted] of Object.entries(filters)) {
|
|
83
|
+
if (!wanted || !wanted.length)
|
|
84
|
+
continue;
|
|
85
|
+
const raw = room?.fields?.[key];
|
|
86
|
+
const have = (Array.isArray(raw) ? raw : [raw])
|
|
87
|
+
.filter((v) => v !== null && v !== undefined)
|
|
88
|
+
.map((v) => String(v));
|
|
89
|
+
if (!have.some((v) => wanted.includes(v)))
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
/** Markdown markers read as noise in a one-line excerpt. */
|
|
95
|
+
export function plainMarkdown(text) {
|
|
96
|
+
return primitive(text)
|
|
97
|
+
.replace(/```[\s\S]*?```/g, ' ')
|
|
98
|
+
.replace(/!\[[^\]]*\]\([^)]*\)/g, '')
|
|
99
|
+
.replace(/\[([^\]]+)\]\([^)]*\)/g, '$1')
|
|
100
|
+
.replace(/^#{1,6}\s+/gm, '')
|
|
101
|
+
.replace(/^\s*[-*+]\s+/gm, '')
|
|
102
|
+
.replace(/^\s*>\s?/gm, '')
|
|
103
|
+
.replace(/\*\*([^*]+)\*\*/g, '$1')
|
|
104
|
+
.replace(/__([^_]+)__/g, '$1')
|
|
105
|
+
.replace(/`([^`]+)`/g, '$1');
|
|
106
|
+
}
|
|
107
|
+
const RADIUS = 60;
|
|
108
|
+
/** A short excerpt around the first match, with its line number in the body. */
|
|
109
|
+
export function snippet(text, tokens, radius = RADIUS) {
|
|
110
|
+
const src = String(text ?? '');
|
|
111
|
+
if (!src.trim() || !tokens?.length)
|
|
112
|
+
return null;
|
|
113
|
+
const hay = src.toLowerCase();
|
|
114
|
+
let at = -1;
|
|
115
|
+
let len = 0;
|
|
116
|
+
for (const token of tokens) {
|
|
117
|
+
const i = hay.indexOf(String(token).toLowerCase());
|
|
118
|
+
if (i !== -1 && (at === -1 || i < at)) {
|
|
119
|
+
at = i;
|
|
120
|
+
len = String(token).length;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (at === -1)
|
|
124
|
+
return null;
|
|
125
|
+
const start = Math.max(0, at - radius);
|
|
126
|
+
const end = Math.min(src.length, at + len + radius);
|
|
127
|
+
const line = src.slice(0, at).split('\n').length;
|
|
128
|
+
const clean = plainMarkdown(src.slice(start, end)).replace(/\s+/g, ' ').trim();
|
|
129
|
+
return {
|
|
130
|
+
line,
|
|
131
|
+
text: `${start > 0 ? '…' : ''}${clean}${end < src.length ? '…' : ''}`,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
function snippetsFor(room, tokens) {
|
|
135
|
+
for (const source of [room.bodyText, room.summary, room.title]) {
|
|
136
|
+
const hit = snippet(source, tokens);
|
|
137
|
+
if (hit)
|
|
138
|
+
return [hit];
|
|
139
|
+
}
|
|
140
|
+
return [];
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Full-text search over title, summary, tags, key points and the docs' bodies.
|
|
144
|
+
* Every token must appear somewhere (AND); scoring only decides the order.
|
|
145
|
+
*/
|
|
146
|
+
export function searchRooms(rooms, query, { limit = 200 } = {}) {
|
|
147
|
+
const q = String(query ?? '').trim();
|
|
148
|
+
if (!q)
|
|
149
|
+
return [];
|
|
150
|
+
const tokens = normalize(q).split(/\s+/).filter(Boolean);
|
|
151
|
+
if (!tokens.length)
|
|
152
|
+
return [];
|
|
153
|
+
const hits = [];
|
|
154
|
+
for (const room of rooms ?? []) {
|
|
155
|
+
const title = normalize(room.title);
|
|
156
|
+
const summary = normalize(room.summary);
|
|
157
|
+
const tags = normalize((room.tags ?? []).join(' '));
|
|
158
|
+
const points = normalize((room.keyPoints ?? []).join(' '));
|
|
159
|
+
const body = normalize(room.bodyText);
|
|
160
|
+
const all = [title, summary, tags, points, body].join('\n');
|
|
161
|
+
if (!tokens.every((t) => all.includes(t)))
|
|
162
|
+
continue;
|
|
163
|
+
let score = 0;
|
|
164
|
+
for (const t of tokens) {
|
|
165
|
+
if (title.includes(t))
|
|
166
|
+
score += 5;
|
|
167
|
+
if (summary.includes(t))
|
|
168
|
+
score += 3;
|
|
169
|
+
if (tags.includes(t))
|
|
170
|
+
score += 3;
|
|
171
|
+
if (points.includes(t))
|
|
172
|
+
score += 2;
|
|
173
|
+
if (body.includes(t))
|
|
174
|
+
score += 1;
|
|
175
|
+
}
|
|
176
|
+
hits.push({ name: room.name, score, snippets: snippetsFor(room, tokens) });
|
|
177
|
+
}
|
|
178
|
+
hits.sort((a, b) => b.score - a.score || a.name.localeCompare(b.name));
|
|
179
|
+
return hits.slice(0, limit);
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=facets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"facets.js","sourceRoot":"","sources":["../../lib/facets.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export declare const HEAD_BYTES = 8192;
|
|
2
|
+
export type FrontmatterValue = string | number | boolean | null | FrontmatterValue[];
|
|
3
|
+
export type Frontmatter = Record<string, FrontmatterValue>;
|
|
4
|
+
export interface FrontmatterIssue {
|
|
5
|
+
code: string;
|
|
6
|
+
key?: string | null;
|
|
7
|
+
message: string;
|
|
8
|
+
}
|
|
9
|
+
export interface ParsedDocument {
|
|
10
|
+
hasFrontmatter: boolean;
|
|
11
|
+
data: Frontmatter;
|
|
12
|
+
body: string;
|
|
13
|
+
issues: FrontmatterIssue[];
|
|
14
|
+
}
|
|
15
|
+
export interface SplitResult {
|
|
16
|
+
raw: string | null;
|
|
17
|
+
body: string;
|
|
18
|
+
error: string | null;
|
|
19
|
+
}
|
|
20
|
+
/** Split `text` into raw frontmatter and body. */
|
|
21
|
+
export declare function splitFrontmatter(text: string | null | undefined): SplitResult;
|
|
22
|
+
/** One scalar: quoted string, inline list, boolean, null, number, or string. */
|
|
23
|
+
export declare function parseScalar(raw: string | null | undefined): FrontmatterValue;
|
|
24
|
+
/** Parse the flat YAML subset. Returns `{ data, issues }`. */
|
|
25
|
+
export declare function parseYamlLite(raw: string | null | undefined): {
|
|
26
|
+
data: Frontmatter;
|
|
27
|
+
issues: FrontmatterIssue[];
|
|
28
|
+
};
|
|
29
|
+
/** Parse a whole document: frontmatter + body. */
|
|
30
|
+
export declare function parseFrontmatter(text: string | null | undefined): ParsedDocument;
|
|
31
|
+
export interface FrontmatterRead extends ParsedDocument {
|
|
32
|
+
source: 'head' | 'full';
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Read a doc's frontmatter without reading the whole file.
|
|
36
|
+
* `source` is 'head' when the frontmatter fit in the first `head` bytes.
|
|
37
|
+
*/
|
|
38
|
+
export declare function readFrontmatterFile(path: string, { head }?: {
|
|
39
|
+
head?: number;
|
|
40
|
+
}): Promise<FrontmatterRead>;
|
|
41
|
+
//# sourceMappingURL=frontmatter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontmatter.d.ts","sourceRoot":"","sources":["../../lib/frontmatter.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,UAAU,OAAO,CAAC;AAI/B,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,gBAAgB,EAAE,CAAC;AACrF,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;AAE3D,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,cAAc,EAAE,OAAO,CAAC;IACxB,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,gBAAgB,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,kDAAkD;AAClD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,WAAW,CAY7E;AA4DD,gFAAgF;AAChF,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,gBAAgB,CAe5E;AAED,8DAA8D;AAC9D,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG;IAC7D,IAAI,EAAE,WAAW,CAAC;IAClB,MAAM,EAAE,gBAAgB,EAAE,CAAC;CAC5B,CAgEA;AAED,kDAAkD;AAClD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,cAAc,CAchF;AAMD,MAAM,WAAW,eAAgB,SAAQ,cAAc;IACrD,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,MAAM,EACZ,EAAE,IAAiB,EAAE,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAO,GAC5C,OAAO,CAAC,eAAe,CAAC,CAc1B"}
|