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,219 @@
|
|
|
1
|
+
// modelroom — frontmatter
|
|
2
|
+
//
|
|
3
|
+
// Frontmatter is the record: a small, flat YAML map at the top of a room doc.
|
|
4
|
+
// The body stays the content. We read only the head of the file (8 KiB) because
|
|
5
|
+
// frontmatter lives there, and fall back to the whole file only when a closing
|
|
6
|
+
// delimiter is missing.
|
|
7
|
+
//
|
|
8
|
+
// The parser is deliberately a subset of YAML: one level, scalars and string
|
|
9
|
+
// lists. Nested maps are reported, not silently accepted — facets are built from
|
|
10
|
+
// this map, so a nested value has nowhere to go.
|
|
11
|
+
import { open, readFile } from 'node:fs/promises';
|
|
12
|
+
export const HEAD_BYTES = 8192;
|
|
13
|
+
const OPEN = /^---[ \t]*\r?\n/;
|
|
14
|
+
const CLOSE = /^(---|\.\.\.)[ \t]*$/m;
|
|
15
|
+
/** Split `text` into raw frontmatter and body. */
|
|
16
|
+
export function splitFrontmatter(text) {
|
|
17
|
+
const src = String(text ?? '').replace(/^\uFEFF/, '');
|
|
18
|
+
if (!OPEN.test(src))
|
|
19
|
+
return { raw: null, body: src, error: null };
|
|
20
|
+
const start = src.indexOf('\n') + 1;
|
|
21
|
+
const rest = src.slice(start);
|
|
22
|
+
const m = CLOSE.exec(rest);
|
|
23
|
+
if (!m)
|
|
24
|
+
return { raw: null, body: src, error: 'unterminated frontmatter' };
|
|
25
|
+
return {
|
|
26
|
+
raw: rest.slice(0, m.index).replace(/\r?\n$/, ''),
|
|
27
|
+
body: rest.slice(m.index + m[0].length).replace(/^\r?\n/, ''),
|
|
28
|
+
error: null,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/** Cut a trailing `# comment` that is outside quotes and preceded by space. */
|
|
32
|
+
function stripComment(line) {
|
|
33
|
+
let quote = null;
|
|
34
|
+
for (let i = 0; i < line.length; i++) {
|
|
35
|
+
const ch = line[i];
|
|
36
|
+
if (quote) {
|
|
37
|
+
if (ch === quote && line[i - 1] !== '\\')
|
|
38
|
+
quote = null;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (ch === '"' || ch === "'") {
|
|
42
|
+
quote = ch;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (ch === '#' && (i === 0 || /\s/.test(line[i - 1]))) {
|
|
46
|
+
return line.slice(0, i).trimEnd();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return line;
|
|
50
|
+
}
|
|
51
|
+
function splitInline(src) {
|
|
52
|
+
const out = [];
|
|
53
|
+
let quote = null;
|
|
54
|
+
let buf = '';
|
|
55
|
+
for (let i = 0; i < src.length; i++) {
|
|
56
|
+
const ch = src[i];
|
|
57
|
+
if (quote) {
|
|
58
|
+
buf += ch;
|
|
59
|
+
if (ch === quote && src[i - 1] !== '\\')
|
|
60
|
+
quote = null;
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (ch === '"' || ch === "'") {
|
|
64
|
+
quote = ch;
|
|
65
|
+
buf += ch;
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
if (ch === ',') {
|
|
69
|
+
out.push(buf);
|
|
70
|
+
buf = '';
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
buf += ch;
|
|
74
|
+
}
|
|
75
|
+
if (buf.trim())
|
|
76
|
+
out.push(buf);
|
|
77
|
+
return out.map((s) => s.trim()).filter((s) => s !== '');
|
|
78
|
+
}
|
|
79
|
+
function unquote(s) {
|
|
80
|
+
if (s.startsWith('"') && s.endsWith('"')) {
|
|
81
|
+
try {
|
|
82
|
+
return JSON.parse(s);
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return s.slice(1, -1);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return s.slice(1, -1).replace(/''/g, "'");
|
|
89
|
+
}
|
|
90
|
+
/** One scalar: quoted string, inline list, boolean, null, number, or string. */
|
|
91
|
+
export function parseScalar(raw) {
|
|
92
|
+
const s = (raw ?? '').trim();
|
|
93
|
+
if (!s)
|
|
94
|
+
return null;
|
|
95
|
+
if (s === '[]')
|
|
96
|
+
return [];
|
|
97
|
+
if (s.startsWith('[') && s.endsWith(']')) {
|
|
98
|
+
return splitInline(s.slice(1, -1)).map(parseScalar);
|
|
99
|
+
}
|
|
100
|
+
if ((s.startsWith('"') && s.endsWith('"')) || (s.startsWith("'") && s.endsWith("'"))) {
|
|
101
|
+
return unquote(s);
|
|
102
|
+
}
|
|
103
|
+
if (s === 'true')
|
|
104
|
+
return true;
|
|
105
|
+
if (s === 'false')
|
|
106
|
+
return false;
|
|
107
|
+
if (s === 'null' || s === '~')
|
|
108
|
+
return null;
|
|
109
|
+
if (/^-?\d+(?:\.\d+)?$/.test(s))
|
|
110
|
+
return Number(s);
|
|
111
|
+
return s;
|
|
112
|
+
}
|
|
113
|
+
/** Parse the flat YAML subset. Returns `{ data, issues }`. */
|
|
114
|
+
export function parseYamlLite(raw) {
|
|
115
|
+
const data = {};
|
|
116
|
+
const issues = [];
|
|
117
|
+
const lines = String(raw ?? '').split(/\r?\n/);
|
|
118
|
+
let pending = null; // `key:` with no value yet — may become a list
|
|
119
|
+
let skipIndent = 0; // > 0 while skipping a nested block
|
|
120
|
+
for (const rawLine of lines) {
|
|
121
|
+
if (!rawLine.trim())
|
|
122
|
+
continue;
|
|
123
|
+
if (/^\s*#/.test(rawLine))
|
|
124
|
+
continue;
|
|
125
|
+
const indent = (rawLine.match(/^\s*/) ?? [''])[0]?.length ?? 0;
|
|
126
|
+
if (skipIndent && indent >= skipIndent)
|
|
127
|
+
continue;
|
|
128
|
+
if (skipIndent && indent < skipIndent)
|
|
129
|
+
skipIndent = 0;
|
|
130
|
+
if (indent > 0) {
|
|
131
|
+
if (pending && /^-\s+/.test(rawLine.trim())) {
|
|
132
|
+
const list = data[pending];
|
|
133
|
+
if (Array.isArray(list))
|
|
134
|
+
list.push(parseScalar(rawLine.trim().replace(/^-\s+/, '')));
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
issues.push({
|
|
138
|
+
code: 'nested',
|
|
139
|
+
key: pending,
|
|
140
|
+
message: 'nested values are not supported — keep frontmatter flat',
|
|
141
|
+
});
|
|
142
|
+
skipIndent = indent;
|
|
143
|
+
pending = null;
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
if (pending) {
|
|
147
|
+
data[pending] = null;
|
|
148
|
+
pending = null;
|
|
149
|
+
}
|
|
150
|
+
const line = stripComment(rawLine.trim());
|
|
151
|
+
if (!line)
|
|
152
|
+
continue;
|
|
153
|
+
const m = /^([^:]+):(.*)$/.exec(line);
|
|
154
|
+
if (!m) {
|
|
155
|
+
issues.push({ code: 'syntax', message: `not a key: value line — ${line}` });
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
const key = m[1].trim();
|
|
159
|
+
const value = m[2].trim();
|
|
160
|
+
if (Object.prototype.hasOwnProperty.call(data, key) || pending === key) {
|
|
161
|
+
issues.push({ code: 'duplicate-key', key, message: `duplicate key: ${key}` });
|
|
162
|
+
}
|
|
163
|
+
if (value === '') {
|
|
164
|
+
pending = key;
|
|
165
|
+
data[key] = [];
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
data[key] = parseScalar(value);
|
|
169
|
+
}
|
|
170
|
+
if (pending) {
|
|
171
|
+
// A key with no items and no following key is an empty value, not an empty list.
|
|
172
|
+
const value = data[pending];
|
|
173
|
+
if (Array.isArray(value) && value.length === 0)
|
|
174
|
+
data[pending] = null;
|
|
175
|
+
}
|
|
176
|
+
return { data, issues };
|
|
177
|
+
}
|
|
178
|
+
/** Parse a whole document: frontmatter + body. */
|
|
179
|
+
export function parseFrontmatter(text) {
|
|
180
|
+
const src = String(text ?? '');
|
|
181
|
+
const { raw, body, error } = splitFrontmatter(src);
|
|
182
|
+
if (error) {
|
|
183
|
+
return {
|
|
184
|
+
hasFrontmatter: true,
|
|
185
|
+
data: {},
|
|
186
|
+
body: src,
|
|
187
|
+
issues: [{ code: 'unterminated', message: error }],
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
if (raw === null)
|
|
191
|
+
return { hasFrontmatter: false, data: {}, body, issues: [] };
|
|
192
|
+
const { data, issues } = parseYamlLite(raw);
|
|
193
|
+
return { hasFrontmatter: true, data, body, issues };
|
|
194
|
+
}
|
|
195
|
+
function needsWholeFile(text) {
|
|
196
|
+
return OPEN.test(text) && !CLOSE.test(text.slice(text.indexOf('\n') + 1));
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Read a doc's frontmatter without reading the whole file.
|
|
200
|
+
* `source` is 'head' when the frontmatter fit in the first `head` bytes.
|
|
201
|
+
*/
|
|
202
|
+
export async function readFrontmatterFile(path, { head = HEAD_BYTES } = {}) {
|
|
203
|
+
let fh;
|
|
204
|
+
try {
|
|
205
|
+
fh = await open(path, 'r');
|
|
206
|
+
const buf = Buffer.alloc(head + 4);
|
|
207
|
+
const { bytesRead } = await fh.read(buf, 0, buf.length, 0);
|
|
208
|
+
const slice = buf.subarray(0, bytesRead).toString('utf8');
|
|
209
|
+
if (needsWholeFile(slice)) {
|
|
210
|
+
return { ...parseFrontmatter(await readFile(path, 'utf8')), source: 'full' };
|
|
211
|
+
}
|
|
212
|
+
return { ...parseFrontmatter(slice), source: 'head' };
|
|
213
|
+
}
|
|
214
|
+
finally {
|
|
215
|
+
if (fh)
|
|
216
|
+
await fh.close().catch(() => { });
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
//# sourceMappingURL=frontmatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../../lib/frontmatter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export type IssueLevel = 'error' | 'warn';
|
|
2
|
+
export interface LintIssue {
|
|
3
|
+
level: IssueLevel;
|
|
4
|
+
room: string;
|
|
5
|
+
file: string | null;
|
|
6
|
+
code: string;
|
|
7
|
+
message: string;
|
|
8
|
+
}
|
|
9
|
+
export interface LintStats {
|
|
10
|
+
rooms: number;
|
|
11
|
+
errors: number;
|
|
12
|
+
warnings: number;
|
|
13
|
+
}
|
|
14
|
+
export interface LintConfig {
|
|
15
|
+
roomsDir: string;
|
|
16
|
+
docs: string[];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Check every room. Returns `{ issues, stats }`.
|
|
20
|
+
* `issues[].level` is 'error' (fixable by an agent) or 'warn' (needs a human).
|
|
21
|
+
*/
|
|
22
|
+
export declare function lintRooms(cfg: LintConfig): Promise<{
|
|
23
|
+
issues: LintIssue[];
|
|
24
|
+
stats: LintStats;
|
|
25
|
+
}>;
|
|
26
|
+
//# sourceMappingURL=lint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../../lib/lint.ts"],"names":[],"mappings":"AAmCA,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,MAAM,CAAC;AAE1C,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,UAAU,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AA4BD;;;GAGG;AACH,wBAAsB,SAAS,CAC7B,GAAG,EAAE,UAAU,GACd,OAAO,CAAC;IAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IAAC,KAAK,EAAE,SAAS,CAAA;CAAE,CAAC,CAyHpD"}
|
package/dist/lib/lint.js
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
// modelroom — the check
|
|
2
|
+
//
|
|
3
|
+
// The check verifies the convention, not the content. It never decides whether a
|
|
4
|
+
// room is good; it decides whether the record can be read. Errors are things an
|
|
5
|
+
// agent can fix without asking; warnings are things a human should look at.
|
|
6
|
+
//
|
|
7
|
+
// Nothing here writes. Deleting and merging stay a human decision.
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
import { readFrontmatterFile } from './frontmatter.js';
|
|
10
|
+
import { listRoomNames } from './rooms.js';
|
|
11
|
+
import { normalize } from './facets.js';
|
|
12
|
+
/** Reserved keys and the shapes they must keep. Everything else is free. */
|
|
13
|
+
const RESERVED_TYPES = {
|
|
14
|
+
id: ['string'],
|
|
15
|
+
title: ['string'],
|
|
16
|
+
summary: ['string'],
|
|
17
|
+
status: ['string'],
|
|
18
|
+
key_points: ['array'],
|
|
19
|
+
tags: ['array'],
|
|
20
|
+
version: ['number', 'string'],
|
|
21
|
+
updated_at: ['string', 'number'],
|
|
22
|
+
deprecated: ['boolean'],
|
|
23
|
+
superseded_by: ['string'],
|
|
24
|
+
};
|
|
25
|
+
/** Keys that mean the same thing. Two of them in one file is a drift signal. */
|
|
26
|
+
const SYNONYMS = {
|
|
27
|
+
summary: ['description', 'abstract', '概要', '要約'],
|
|
28
|
+
tags: ['labels', 'label', 'ラベル', 'タグ'],
|
|
29
|
+
status: ['state', '状態'],
|
|
30
|
+
version: ['revision', '版'],
|
|
31
|
+
};
|
|
32
|
+
const typeOf = (v) => {
|
|
33
|
+
if (Array.isArray(v))
|
|
34
|
+
return 'array';
|
|
35
|
+
if (v === null)
|
|
36
|
+
return 'null';
|
|
37
|
+
return typeof v;
|
|
38
|
+
};
|
|
39
|
+
/** A variant is the same value written two ways (`draft` / `Draft` / `下書き`). */
|
|
40
|
+
function variantGroups(entries) {
|
|
41
|
+
const groups = new Map();
|
|
42
|
+
for (const { room, file, key, value } of entries) {
|
|
43
|
+
const n = normalize(value);
|
|
44
|
+
if (!n)
|
|
45
|
+
continue;
|
|
46
|
+
if (!groups.has(n))
|
|
47
|
+
groups.set(n, []);
|
|
48
|
+
const g = groups.get(n);
|
|
49
|
+
if (!g.some((x) => x.value === String(value)))
|
|
50
|
+
g.push({ room, file, key, value });
|
|
51
|
+
}
|
|
52
|
+
return [...groups.values()].filter((g) => g.length > 1);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Check every room. Returns `{ issues, stats }`.
|
|
56
|
+
* `issues[].level` is 'error' (fixable by an agent) or 'warn' (needs a human).
|
|
57
|
+
*/
|
|
58
|
+
export async function lintRooms(cfg) {
|
|
59
|
+
const names = await listRoomNames(cfg);
|
|
60
|
+
const issues = [];
|
|
61
|
+
const variants = [];
|
|
62
|
+
const seen = new Set(names);
|
|
63
|
+
const add = (level, room, file, code, message) => {
|
|
64
|
+
issues.push({ level, room, file: file || null, code, message });
|
|
65
|
+
};
|
|
66
|
+
for (const room of names) {
|
|
67
|
+
for (const file of cfg.docs) {
|
|
68
|
+
let doc;
|
|
69
|
+
try {
|
|
70
|
+
doc = await readFrontmatterFile(join(cfg.roomsDir, room, file));
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
continue; // a missing doc is reported by `doctor`, not here
|
|
74
|
+
}
|
|
75
|
+
for (const issue of doc.issues) {
|
|
76
|
+
add('error', room, file, issue.code, issue.message);
|
|
77
|
+
}
|
|
78
|
+
const data = doc.data || {};
|
|
79
|
+
for (const [key, value] of Object.entries(data)) {
|
|
80
|
+
const allowed = RESERVED_TYPES[key];
|
|
81
|
+
if (allowed) {
|
|
82
|
+
const t = typeOf(value);
|
|
83
|
+
if (value !== null && !allowed.includes(t)) {
|
|
84
|
+
add('error', room, file, 'reserved-type', `${key} must be ${allowed.join(' or ')}, got ${t}`);
|
|
85
|
+
}
|
|
86
|
+
if (key === 'tags' &&
|
|
87
|
+
Array.isArray(value) &&
|
|
88
|
+
value.some((v) => typeof v === 'object' || Array.isArray(v))) {
|
|
89
|
+
add('error', room, file, 'tags-shape', 'tags must be a flat list of strings');
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
for (const [canonical, aliases] of Object.entries(SYNONYMS)) {
|
|
93
|
+
if (aliases.includes(key) && data[canonical] !== undefined) {
|
|
94
|
+
add('warn', room, file, 'synonym', `${key} duplicates ${canonical} — keep one`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (['status', 'category', 'type'].includes(key) &&
|
|
98
|
+
!Array.isArray(value) &&
|
|
99
|
+
typeof value !== 'object') {
|
|
100
|
+
variants.push({ room, file, key, value });
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (!doc.hasFrontmatter && file === cfg.docs[0]) {
|
|
104
|
+
add('warn', room, file, 'no-frontmatter', 'no frontmatter — add title, summary and tags');
|
|
105
|
+
}
|
|
106
|
+
if (file === cfg.docs[0] && data.title) {
|
|
107
|
+
const h1 = /^#\s+(.+)$/m.exec(doc.body || '');
|
|
108
|
+
if (h1 && normalize(h1[1].trim()) !== normalize(data.title)) {
|
|
109
|
+
add('warn', room, file, 'h1-title', `H1 "${h1[1].trim()}" differs from title "${String(data.title)}"`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
for (const group of variantGroups(variants)) {
|
|
115
|
+
const values = group.map((x) => x.value).join(' / ');
|
|
116
|
+
for (const item of group) {
|
|
117
|
+
add('warn', item.room, item.file, 'variant', `${item.key}: ${values} — same value, different spelling`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
for (const room of names) {
|
|
121
|
+
for (const file of cfg.docs) {
|
|
122
|
+
let doc;
|
|
123
|
+
try {
|
|
124
|
+
doc = await readFrontmatterFile(join(cfg.roomsDir, room, file));
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
const target = doc.data?.superseded_by;
|
|
130
|
+
if (typeof target === 'string' && target && !seen.has(target)) {
|
|
131
|
+
add('warn', room, file, 'superseded-missing', `superseded_by points to a room that does not exist: ${target}`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
const errors = issues.filter((i) => i.level === 'error').length;
|
|
136
|
+
const warnings = issues.filter((i) => i.level === 'warn').length;
|
|
137
|
+
return { issues, stats: { rooms: names.length, errors, warnings } };
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=lint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lint.js","sourceRoot":"","sources":["../../lib/lint.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Config } from './config.ts';
|
|
2
|
+
export interface TokenUsage {
|
|
3
|
+
input: number;
|
|
4
|
+
output: number;
|
|
5
|
+
reasoning: number;
|
|
6
|
+
cacheRead: number;
|
|
7
|
+
cacheWrite: number;
|
|
8
|
+
}
|
|
9
|
+
export interface SessionStats {
|
|
10
|
+
cost: number | null;
|
|
11
|
+
tokens: TokenUsage | null;
|
|
12
|
+
outcome: string | null;
|
|
13
|
+
model: string | null;
|
|
14
|
+
}
|
|
15
|
+
export interface ContextUsage {
|
|
16
|
+
used: number;
|
|
17
|
+
limit: number;
|
|
18
|
+
pct: number;
|
|
19
|
+
}
|
|
20
|
+
export interface TranscriptLine {
|
|
21
|
+
role: 'user' | 'assistant' | 'meta';
|
|
22
|
+
text: string;
|
|
23
|
+
}
|
|
24
|
+
export interface McpServer {
|
|
25
|
+
name: string;
|
|
26
|
+
status: string;
|
|
27
|
+
error: string | null;
|
|
28
|
+
}
|
|
29
|
+
export interface SessionView {
|
|
30
|
+
stats: SessionStats;
|
|
31
|
+
context: ContextUsage | null;
|
|
32
|
+
lines: TranscriptLine[];
|
|
33
|
+
mcp: McpServer[];
|
|
34
|
+
skills: string[];
|
|
35
|
+
workspace: string | null;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Everything the session panel needs for one room session.
|
|
39
|
+
* Returns null when opencode is unreachable, so the caller can say so plainly.
|
|
40
|
+
*/
|
|
41
|
+
export declare function sessionView(cfg: Config, sessionId: string | null): Promise<SessionView | null>;
|
|
42
|
+
//# sourceMappingURL=opencode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opencode.d.ts","sourceRoot":"","sources":["../../lib/opencode.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAQ1C,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;IAC1B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;IACpC,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,YAAY,CAAC;IACpB,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;IAC7B,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,GAAG,EAAE,SAAS,EAAE,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAiLD;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,GAAG,IAAI,GACvB,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAgC7B"}
|