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.
Files changed (66) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/LICENSE +21 -0
  3. package/README.md +149 -2
  4. package/dist/bin/modelroom.d.ts +3 -0
  5. package/dist/bin/modelroom.d.ts.map +1 -0
  6. package/dist/bin/modelroom.js +242 -0
  7. package/dist/bin/modelroom.js.map +1 -0
  8. package/dist/lib/agents/index.d.ts +22 -0
  9. package/dist/lib/agents/index.d.ts.map +1 -0
  10. package/dist/lib/agents/index.js +68 -0
  11. package/dist/lib/agents/index.js.map +1 -0
  12. package/dist/lib/artifact.d.ts +22 -0
  13. package/dist/lib/artifact.d.ts.map +1 -0
  14. package/dist/lib/artifact.js +62 -0
  15. package/dist/lib/artifact.js.map +1 -0
  16. package/dist/lib/config.d.ts +53 -0
  17. package/dist/lib/config.d.ts.map +1 -0
  18. package/dist/lib/config.js +92 -0
  19. package/dist/lib/config.js.map +1 -0
  20. package/dist/lib/facets.d.ts +62 -0
  21. package/dist/lib/facets.d.ts.map +1 -0
  22. package/dist/lib/facets.js +181 -0
  23. package/dist/lib/facets.js.map +1 -0
  24. package/dist/lib/frontmatter.d.ts +41 -0
  25. package/dist/lib/frontmatter.d.ts.map +1 -0
  26. package/dist/lib/frontmatter.js +219 -0
  27. package/dist/lib/frontmatter.js.map +1 -0
  28. package/dist/lib/lint.d.ts +26 -0
  29. package/dist/lib/lint.d.ts.map +1 -0
  30. package/dist/lib/lint.js +139 -0
  31. package/dist/lib/lint.js.map +1 -0
  32. package/dist/lib/opencode.d.ts +42 -0
  33. package/dist/lib/opencode.d.ts.map +1 -0
  34. package/dist/lib/opencode.js +229 -0
  35. package/dist/lib/opencode.js.map +1 -0
  36. package/dist/lib/pkg.d.ts +2 -0
  37. package/dist/lib/pkg.d.ts.map +1 -0
  38. package/dist/lib/pkg.js +19 -0
  39. package/dist/lib/pkg.js.map +1 -0
  40. package/dist/lib/rooms.d.ts +63 -0
  41. package/dist/lib/rooms.d.ts.map +1 -0
  42. package/dist/lib/rooms.js +178 -0
  43. package/dist/lib/rooms.js.map +1 -0
  44. package/dist/lib/server.d.ts +53 -0
  45. package/dist/lib/server.d.ts.map +1 -0
  46. package/dist/lib/server.js +538 -0
  47. package/dist/lib/server.js.map +1 -0
  48. package/docs/01_concept.md +69 -0
  49. package/docs/02-convention.md +109 -0
  50. package/docs/03-cli.md +103 -0
  51. package/docs/04-agents.md +88 -0
  52. package/examples/rooms/sign-in/BEHAVIOUR.md +23 -0
  53. package/examples/rooms/sign-in/BRIEF.md +15 -0
  54. package/examples/rooms/sign-in/SPEC.md +14 -0
  55. package/examples/rooms/sign-in/index.html +56 -0
  56. package/package.json +83 -4
  57. package/templates/AGENTS.md +31 -0
  58. package/templates/modelroom.json +14 -0
  59. package/templates/room/BEHAVIOUR.md +19 -0
  60. package/templates/room/BRIEF.md +16 -0
  61. package/templates/room/SPEC.md +9 -0
  62. package/templates/room/index.html +53 -0
  63. package/ui/dashboard.html +332 -0
  64. package/ui/modelroom.css +2 -0
  65. package/ui/room.html +466 -0
  66. package/ui/settings.html +125 -0
@@ -0,0 +1,229 @@
1
+ // modelroom — reading an opencode session back
2
+ //
3
+ // The room already runs through the configured `command`. When that command is
4
+ // opencode we can also ask its API what happened in the session: cost, tokens,
5
+ // the messages, the model's context window, MCP servers and skills. Everything
6
+ // here is best-effort and opencode-only — any failure returns null/empty and the
7
+ // UI just hides the panel. Nothing here writes.
8
+ import { spawn } from 'node:child_process';
9
+ const MAX_OUTPUT = 8 * 1024 * 1024; // a runaway response must not grow without bound
10
+ const TIMEOUT_MS = 15_000;
11
+ const MAX_TEXT = 4000; // a transcript excerpt, not the whole file
12
+ const MODEL_TTL = 10 * 60_000;
13
+ const EXTRAS_TTL = 60_000;
14
+ const num = (v) => (typeof v === 'number' && Number.isFinite(v) ? v : null);
15
+ const str = (v) => (typeof v === 'string' ? v : null);
16
+ const isRecord = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
17
+ /** The `{ data: … }` envelope opencode puts around most responses. */
18
+ const dataOf = (res) => (isRecord(res) ? res.data : undefined);
19
+ const listOf = (res) => {
20
+ const d = dataOf(res);
21
+ return Array.isArray(d) ? d : [];
22
+ };
23
+ /** One `opencode api GET` call. Never throws; null on any failure. */
24
+ function runApi(cfg, path, standalone) {
25
+ return new Promise((resolve) => {
26
+ let child;
27
+ try {
28
+ const args = standalone ? ['api', '--standalone', 'GET', path] : ['api', 'GET', path];
29
+ child = spawn(cfg.agent.command || 'opencode', args, {
30
+ cwd: cfg.rootDir,
31
+ // `--standalone` shares the data directory but needs no background service.
32
+ stdio: ['ignore', 'pipe', 'pipe'],
33
+ env: { ...process.env, NO_COLOR: '1', FORCE_COLOR: '0' },
34
+ });
35
+ }
36
+ catch {
37
+ resolve(null);
38
+ return;
39
+ }
40
+ let out = '';
41
+ let settled = false;
42
+ const finish = (value) => {
43
+ if (settled)
44
+ return;
45
+ settled = true;
46
+ clearTimeout(timer);
47
+ try {
48
+ child.kill();
49
+ }
50
+ catch {
51
+ /* already gone */
52
+ }
53
+ resolve(value);
54
+ };
55
+ const timer = setTimeout(() => finish(null), TIMEOUT_MS);
56
+ child.stdout?.on('data', (b) => {
57
+ out += String(b);
58
+ if (out.length > MAX_OUTPUT)
59
+ finish(null);
60
+ });
61
+ child.stderr?.on('data', () => { }); // the error text is not useful to us
62
+ child.on('error', () => finish(null));
63
+ child.on('close', (code) => {
64
+ if (code !== 0 || !out.trim())
65
+ return finish(null);
66
+ try {
67
+ finish(JSON.parse(out));
68
+ }
69
+ catch {
70
+ finish(null);
71
+ }
72
+ });
73
+ });
74
+ }
75
+ /**
76
+ * Ask opencode's API. The background service knows the model catalogue, MCP
77
+ * servers and skills; a private (`--standalone`) server shares the data
78
+ * directory but not those. Try the service first, then a private server.
79
+ */
80
+ async function apiGet(cfg, path) {
81
+ return (await runApi(cfg, path, false)) ?? (await runApi(cfg, path, true));
82
+ }
83
+ function toTokens(raw) {
84
+ if (!isRecord(raw))
85
+ return null;
86
+ const cache = isRecord(raw.cache) ? raw.cache : {};
87
+ return {
88
+ input: num(raw.input) ?? 0,
89
+ output: num(raw.output) ?? 0,
90
+ reasoning: num(raw.reasoning) ?? 0,
91
+ cacheRead: num(cache.read) ?? 0,
92
+ cacheWrite: num(cache.write) ?? 0,
93
+ };
94
+ }
95
+ const created = (m) => isRecord(m) && isRecord(m.time) ? (num(m.time.created) ?? 0) : 0;
96
+ const byTime = (a, b) => created(a) - created(b);
97
+ /** The model the last assistant step used, when the session itself has none. */
98
+ function lastModel(messages) {
99
+ for (const raw of [...messages].sort(byTime).toReversed()) {
100
+ if (isRecord(raw) && raw.type === 'assistant' && isRecord(raw.model)) {
101
+ const id = str(raw.model.id);
102
+ if (id)
103
+ return id;
104
+ }
105
+ }
106
+ return null;
107
+ }
108
+ const clip = (text) => text.length > MAX_TEXT ? `${text.slice(0, MAX_TEXT)}…` : text;
109
+ function toLines(messages) {
110
+ const lines = [];
111
+ for (const raw of [...messages].sort(byTime)) {
112
+ if (!isRecord(raw))
113
+ continue;
114
+ if (raw.type === 'user') {
115
+ const text = str(raw.text) ?? '';
116
+ if (text.trim())
117
+ lines.push({ role: 'user', text: clip(text) });
118
+ continue;
119
+ }
120
+ if (raw.type !== 'assistant' || !Array.isArray(raw.content))
121
+ continue;
122
+ for (const rawPart of raw.content) {
123
+ if (!isRecord(rawPart))
124
+ continue;
125
+ if (rawPart.type === 'text' && typeof rawPart.text === 'string' && rawPart.text.trim()) {
126
+ lines.push({ role: 'assistant', text: clip(rawPart.text) });
127
+ }
128
+ else if (rawPart.type === 'tool') {
129
+ const name = str(rawPart.name) ?? 'tool';
130
+ const state = isRecord(rawPart.state) ? rawPart.state : {};
131
+ const status = str(state.status) ?? '';
132
+ lines.push({ role: 'meta', text: `[${name}]${status ? ` ${status}` : ''}` });
133
+ }
134
+ }
135
+ }
136
+ return lines;
137
+ }
138
+ /** The last turn's prompt size is the current context: fresh input + cache reads. */
139
+ function contextUsed(messages) {
140
+ for (const raw of [...messages].sort(byTime).toReversed()) {
141
+ if (!isRecord(raw) || raw.type !== 'assistant')
142
+ continue;
143
+ const tokens = toTokens(raw.tokens);
144
+ if (tokens)
145
+ return tokens.input + tokens.cacheRead;
146
+ }
147
+ return null;
148
+ }
149
+ let modelLimitsCache = null;
150
+ async function modelLimits(cfg) {
151
+ if (modelLimitsCache && Date.now() - modelLimitsCache.at < MODEL_TTL)
152
+ return modelLimitsCache.map;
153
+ const map = new Map();
154
+ for (const raw of listOf(await apiGet(cfg, '/api/model'))) {
155
+ if (!isRecord(raw))
156
+ continue;
157
+ const id = str(raw.id);
158
+ const limit = isRecord(raw.limit) ? num(raw.limit.context) : null;
159
+ if (id && limit)
160
+ map.set(id, limit);
161
+ }
162
+ if (map.size)
163
+ modelLimitsCache = { at: Date.now(), map };
164
+ return map;
165
+ }
166
+ let extrasCache = null;
167
+ async function extras(cfg) {
168
+ if (extrasCache && Date.now() - extrasCache.at < EXTRAS_TTL)
169
+ return extrasCache;
170
+ const [mcpRes, skillRes] = await Promise.all([
171
+ apiGet(cfg, '/api/mcp'),
172
+ apiGet(cfg, '/api/skill'),
173
+ ]);
174
+ const mcp = [];
175
+ for (const raw of listOf(mcpRes)) {
176
+ if (!isRecord(raw))
177
+ continue;
178
+ const status = isRecord(raw.status) ? raw.status : {};
179
+ mcp.push({
180
+ name: str(raw.name) ?? '?',
181
+ status: str(status.status) ?? 'unknown',
182
+ error: str(status.error),
183
+ });
184
+ }
185
+ const skills = [];
186
+ for (const raw of listOf(skillRes)) {
187
+ if (!isRecord(raw))
188
+ continue;
189
+ const name = str(raw.name) ?? str(raw.id);
190
+ if (name)
191
+ skills.push(name);
192
+ }
193
+ extrasCache = { at: Date.now(), mcp, skills };
194
+ return extrasCache;
195
+ }
196
+ /**
197
+ * Everything the session panel needs for one room session.
198
+ * Returns null when opencode is unreachable, so the caller can say so plainly.
199
+ */
200
+ export async function sessionView(cfg, sessionId) {
201
+ if (!sessionId)
202
+ return null;
203
+ const [infoRes, msgRes] = await Promise.all([
204
+ apiGet(cfg, `/api/session/${sessionId}`),
205
+ apiGet(cfg, `/api/session/${sessionId}/message`),
206
+ ]);
207
+ if (!infoRes && !msgRes)
208
+ return null;
209
+ const info = dataOf(infoRes);
210
+ const messages = listOf(msgRes);
211
+ const model = (isRecord(info) && isRecord(info.model) ? str(info.model.id) : null) ?? lastModel(messages);
212
+ const stats = {
213
+ cost: isRecord(info) ? num(info.cost) : null,
214
+ tokens: isRecord(info) ? toTokens(info.tokens) : null,
215
+ outcome: isRecord(info) ? str(info.outcome) : null,
216
+ model,
217
+ };
218
+ let context = null;
219
+ const used = contextUsed(messages);
220
+ if (used !== null && model) {
221
+ const limit = (await modelLimits(cfg)).get(model) ?? null;
222
+ if (limit)
223
+ context = { used, limit, pct: Math.min(100, Math.round((used / limit) * 1000) / 10) };
224
+ }
225
+ const { mcp, skills } = await extras(cfg);
226
+ const workspace = isRecord(info) && isRecord(info.location) ? str(info.location.directory) : null;
227
+ return { stats, context, lines: toLines(messages), mcp, skills, workspace };
228
+ }
229
+ //# sourceMappingURL=opencode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode.js","sourceRoot":"","sources":["../../lib/opencode.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function findPackageRoot(start: string): string;
2
+ //# sourceMappingURL=pkg.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pkg.d.ts","sourceRoot":"","sources":["../../lib/pkg.ts"],"names":[],"mappings":"AAQA,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CASrD"}
@@ -0,0 +1,19 @@
1
+ // modelroom — where the package lives
2
+ //
3
+ // Works from source (`bin/`, `lib/`) and from the published layout (`dist/bin`,
4
+ // `dist/lib`) alike: walk up until the directory that holds package.json.
5
+ import { existsSync } from 'node:fs';
6
+ import { dirname, join } from 'node:path';
7
+ export function findPackageRoot(start) {
8
+ let dir = start;
9
+ for (let i = 0; i < 4; i++) {
10
+ if (existsSync(join(dir, 'package.json')))
11
+ return dir;
12
+ const parent = dirname(dir);
13
+ if (parent === dir)
14
+ break;
15
+ dir = parent;
16
+ }
17
+ return start;
18
+ }
19
+ //# sourceMappingURL=pkg.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pkg.js","sourceRoot":"","sources":["../../lib/pkg.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,EAAE;AACF,gFAAgF;AAChF,0EAA0E;AAE1E,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE1C,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,IAAI,GAAG,GAAG,KAAK,CAAC;IAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;YAAE,OAAO,GAAG,CAAC;QACtD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,MAAM,KAAK,GAAG;YAAE,MAAM;QAC1B,GAAG,GAAG,MAAM,CAAC;IACf,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,63 @@
1
+ import { type Frontmatter, type FrontmatterIssue } from './frontmatter.ts';
2
+ declare const isRoomName: (s: unknown) => s is string;
3
+ export { isRoomName };
4
+ export interface FileInfo {
5
+ name: string;
6
+ exists: boolean;
7
+ size: number;
8
+ mtime: number;
9
+ }
10
+ export interface RoomDoc {
11
+ name: string;
12
+ text: string;
13
+ body: string;
14
+ frontmatter: Frontmatter;
15
+ issues: FrontmatterIssue[];
16
+ hasFrontmatter: boolean;
17
+ mtime: number;
18
+ size: number;
19
+ }
20
+ export interface RoomInfo {
21
+ name: string;
22
+ title: string;
23
+ status: string | null;
24
+ summary: string | null;
25
+ tags: string[];
26
+ keyPoints: string[];
27
+ version: string | number | null;
28
+ deprecated: boolean;
29
+ supersededBy: string | null;
30
+ fields: Frontmatter;
31
+ files: FileInfo[];
32
+ updatedAt: number;
33
+ hasArtifact: boolean;
34
+ hasThumb: boolean;
35
+ artifactUrl: string;
36
+ thumbUrl: string | null;
37
+ behaviourIds: string[];
38
+ bodyText: string;
39
+ }
40
+ export interface RoomsConfig {
41
+ roomsDir: string;
42
+ docs: string[];
43
+ artifact: string;
44
+ rooms: string;
45
+ }
46
+ export declare function clearDocCache(): void;
47
+ export declare function listRoomNames(cfg: {
48
+ roomsDir: string;
49
+ }): Promise<string[]>;
50
+ /** Optional `Status:` line, or frontmatter `status:`, read from the brief. */
51
+ export declare function parseStatus(text: string | null | undefined): string | null;
52
+ /**
53
+ * Merge the docs' frontmatter. Lists are unioned (tags across docs), scalars keep
54
+ * the first value — BRIEF wins, then SPEC, then BEHAVIOUR.
55
+ */
56
+ export declare function mergeFrontmatter(docs: Array<{
57
+ frontmatter?: Frontmatter;
58
+ } | null | undefined>): Frontmatter;
59
+ export declare function roomInfo(cfg: RoomsConfig, name: string): Promise<RoomInfo>;
60
+ /** The room as the browser sees it: no body, no internal cache fields. */
61
+ export declare function publicRoom(room: RoomInfo): Omit<RoomInfo, 'bodyText'>;
62
+ export declare function docInfo(cfg: Pick<RoomsConfig, 'roomsDir' | 'docs'>, name: string): Promise<Record<string, FileInfo>>;
63
+ //# sourceMappingURL=rooms.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rooms.d.ts","sourceRoot":"","sources":["../../lib/rooms.ts"],"names":[],"mappings":"AAWA,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,gBAAgB,EAEtB,MAAM,kBAAkB,CAAC;AAE1B,QAAA,MAAM,UAAU,MAAO,OAAO,KAAG,CAAC,IAAI,MAC4C,CAAC;AAEnF,OAAO,EAAE,UAAU,EAAE,CAAC;AAEtB,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,WAAW,CAAC;IACzB,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC3B,cAAc,EAAE,OAAO,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAChC,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,EAAE,WAAW,CAAC;IACpB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAKD,wBAAgB,aAAa,IAAI,IAAI,CAEpC;AAmCD,wBAAsB,aAAa,CAAC,GAAG,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAUhF;AAWD,8EAA8E;AAC9E,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAS1E;AAeD;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,KAAK,CAAC;IAAE,WAAW,CAAC,EAAE,WAAW,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,CAAC,GAC5D,WAAW,CAab;AAED,wBAAsB,QAAQ,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAiDhF;AAED,0EAA0E;AAC1E,wBAAgB,UAAU,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAGrE;AAED,wBAAsB,OAAO,CAC3B,GAAG,EAAE,IAAI,CAAC,WAAW,EAAE,UAAU,GAAG,MAAM,CAAC,EAC3C,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAKnC"}
@@ -0,0 +1,178 @@
1
+ // modelroom — rooms
2
+ //
3
+ // A room is one screen: `rooms/<name>/` with an artifact and a small set of
4
+ // single-purpose docs. Nothing here decides anything about the application layer.
5
+ //
6
+ // The frontmatter of the docs is the record. The dashboard's list, facets and
7
+ // search are derived from it on every request; nothing is stored separately, so
8
+ // there is no second place to keep in sync.
9
+ import { open, stat, readdir } from 'node:fs/promises';
10
+ import { join } from 'node:path';
11
+ import { parseFrontmatter, } from './frontmatter.js';
12
+ const isRoomName = (s) => typeof s === 'string' && /^[a-z0-9][a-z0-9._-]*$/i.test(s) && !s.startsWith('.');
13
+ export { isRoomName };
14
+ // Parsed docs, keyed by path and invalidated by mtime+size. A change to one file
15
+ // never re-reads the others.
16
+ const docCache = new Map();
17
+ export function clearDocCache() {
18
+ docCache.clear();
19
+ }
20
+ async function readDoc(path) {
21
+ // One handle for stat + read: the cache key and the text always describe the
22
+ // same file, even if the file is replaced while we read it.
23
+ let fh;
24
+ try {
25
+ fh = await open(path, 'r');
26
+ }
27
+ catch {
28
+ return null;
29
+ }
30
+ try {
31
+ const s = await fh.stat();
32
+ const key = `${s.mtimeMs}:${s.size}`;
33
+ const hit = docCache.get(path);
34
+ if (hit && hit.key === key)
35
+ return hit.value;
36
+ const text = await fh.readFile('utf8');
37
+ const parsed = parseFrontmatter(text);
38
+ const value = {
39
+ name: '',
40
+ text,
41
+ body: parsed.body,
42
+ frontmatter: parsed.data,
43
+ issues: parsed.issues,
44
+ hasFrontmatter: parsed.hasFrontmatter,
45
+ mtime: s.mtimeMs,
46
+ size: s.size,
47
+ };
48
+ docCache.set(path, { key, value });
49
+ return value;
50
+ }
51
+ finally {
52
+ await fh.close();
53
+ }
54
+ }
55
+ export async function listRoomNames(cfg) {
56
+ try {
57
+ const entries = await readdir(cfg.roomsDir, { withFileTypes: true });
58
+ return entries
59
+ .filter((e) => e.isDirectory() && isRoomName(e.name))
60
+ .map((e) => e.name)
61
+ .sort();
62
+ }
63
+ catch {
64
+ return [];
65
+ }
66
+ }
67
+ async function fileInfo(path, name) {
68
+ try {
69
+ const s = await stat(path);
70
+ return { name, exists: true, size: s.size, mtime: s.mtimeMs };
71
+ }
72
+ catch {
73
+ return { name, exists: false, size: 0, mtime: 0 };
74
+ }
75
+ }
76
+ /** Optional `Status:` line, or frontmatter `status:`, read from the brief. */
77
+ export function parseStatus(text) {
78
+ if (!text)
79
+ return null;
80
+ const fm = /^\uFEFF?---\r?\n([\s\S]*?)\r?\n---/.exec(text);
81
+ if (fm) {
82
+ const m = /^status\s*:\s*(.+)$/im.exec(fm[1]);
83
+ if (m)
84
+ return m[1].trim().replace(/^["']|["']$/g, '');
85
+ }
86
+ const m = /^\s*status\s*:\s*(.+)$/im.exec(text);
87
+ return m ? m[1].trim() : null;
88
+ }
89
+ function parseTitle(text, fallback) {
90
+ const m = text ? /^#\s+(.+)$/m.exec(text) : null;
91
+ return m ? m[1].trim() : fallback;
92
+ }
93
+ const asStrings = (value) => {
94
+ if (Array.isArray(value)) {
95
+ return value.filter((v) => v !== null && typeof v !== 'object').map(String);
96
+ }
97
+ if (value === null || value === undefined || typeof value === 'object')
98
+ return [];
99
+ return [String(value)];
100
+ };
101
+ /**
102
+ * Merge the docs' frontmatter. Lists are unioned (tags across docs), scalars keep
103
+ * the first value — BRIEF wins, then SPEC, then BEHAVIOUR.
104
+ */
105
+ export function mergeFrontmatter(docs) {
106
+ const out = {};
107
+ for (const doc of docs) {
108
+ for (const [key, value] of Object.entries(doc?.frontmatter ?? {})) {
109
+ if (Array.isArray(value)) {
110
+ const prev = asStrings(out[key]);
111
+ out[key] = [...new Set([...prev, ...asStrings(value)])];
112
+ }
113
+ else if (out[key] === undefined) {
114
+ out[key] = value;
115
+ }
116
+ }
117
+ }
118
+ return out;
119
+ }
120
+ export async function roomInfo(cfg, name) {
121
+ const dir = join(cfg.roomsDir, name);
122
+ const files = [];
123
+ for (const d of cfg.docs)
124
+ files.push(await fileInfo(join(dir, d), d));
125
+ files.push(await fileInfo(join(dir, cfg.artifact), cfg.artifact));
126
+ const png = cfg.artifact.replace(/\.html?$/i, '.png');
127
+ files.push(await fileInfo(join(dir, png), png));
128
+ const docs = [];
129
+ for (const d of cfg.docs) {
130
+ const doc = await readDoc(join(dir, d));
131
+ if (doc)
132
+ docs.push({ ...doc, name: d });
133
+ }
134
+ const brief = docs.find((d) => d.name === cfg.docs[0])?.text ?? null;
135
+ const behaviour = docs.find((d) => d.name === 'BEHAVIOUR.md')?.text ?? null;
136
+ const ids = behaviour
137
+ ? [...behaviour.matchAll(/@([a-z][a-z0-9-]*-\d+)/gi)].map((m) => m[1])
138
+ : [];
139
+ const fields = mergeFrontmatter(docs);
140
+ const title = typeof fields.title === 'string' && fields.title ? fields.title : parseTitle(brief, name);
141
+ const artifact = files.find((f) => f.name === cfg.artifact);
142
+ const thumb = files.find((f) => f.name === png);
143
+ return {
144
+ name,
145
+ title,
146
+ status: typeof fields.status === 'string' ? fields.status : parseStatus(brief),
147
+ summary: typeof fields.summary === 'string' ? fields.summary : null,
148
+ tags: asStrings(fields.tags),
149
+ keyPoints: asStrings(fields.key_points),
150
+ version: typeof fields.version === 'string' || typeof fields.version === 'number'
151
+ ? fields.version
152
+ : null,
153
+ deprecated: fields.deprecated === true,
154
+ supersededBy: typeof fields.superseded_by === 'string' ? fields.superseded_by : null,
155
+ fields,
156
+ files,
157
+ updatedAt: Math.max(0, ...files.map((f) => f.mtime)),
158
+ hasArtifact: Boolean(artifact?.exists),
159
+ hasThumb: Boolean(thumb?.exists),
160
+ artifactUrl: `/files/${cfg.rooms}/${name}/${cfg.artifact}`,
161
+ thumbUrl: thumb?.exists ? `/files/${cfg.rooms}/${name}/${png}` : null,
162
+ behaviourIds: [...new Set(ids)],
163
+ bodyText: docs.map((d) => d.body).join('\n\n'),
164
+ };
165
+ }
166
+ /** The room as the browser sees it: no body, no internal cache fields. */
167
+ export function publicRoom(room) {
168
+ const { bodyText: _bodyText, ...rest } = room;
169
+ return rest;
170
+ }
171
+ export async function docInfo(cfg, name) {
172
+ const dir = join(cfg.roomsDir, name);
173
+ const out = {};
174
+ for (const d of cfg.docs)
175
+ out[d] = await fileInfo(join(dir, d), d);
176
+ return out;
177
+ }
178
+ //# sourceMappingURL=rooms.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rooms.js","sourceRoot":"","sources":["../../lib/rooms.ts"],"names":[],"mappings":"AAAA,oBAAoB;AACpB,EAAE;AACF,4EAA4E;AAC5E,kFAAkF;AAClF,EAAE;AACF,8EAA8E;AAC9E,gFAAgF;AAChF,4CAA4C;AAE5C,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EACL,gBAAgB,GAIjB,MAAM,kBAAkB,CAAC;AAE1B,MAAM,UAAU,GAAG,CAAC,CAAU,EAAe,EAAE,CAC7C,OAAO,CAAC,KAAK,QAAQ,IAAI,yBAAyB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;AAEnF,OAAO,EAAE,UAAU,EAAE,CAAC;AAgDtB,iFAAiF;AACjF,6BAA6B;AAC7B,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA2C,CAAC;AACpE,MAAM,UAAU,aAAa;IAC3B,QAAQ,CAAC,KAAK,EAAE,CAAC;AACnB,CAAC;AAED,KAAK,UAAU,OAAO,CAAC,IAAY;IACjC,6EAA6E;IAC7E,4DAA4D;IAC5D,IAAI,EAAE,CAAC;IACP,IAAI,CAAC;QACH,EAAE,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC;QAC1B,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,GAAG,IAAI,GAAG,CAAC,GAAG,KAAK,GAAG;YAAE,OAAO,GAAG,CAAC,KAAK,CAAC;QAC7C,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACvC,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;QACtC,MAAM,KAAK,GAAY;YACrB,IAAI,EAAE,EAAE;YACR,IAAI;YACJ,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,WAAW,EAAE,MAAM,CAAC,IAAI;YACxB,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,cAAc,EAAE,MAAM,CAAC,cAAc;YACrC,KAAK,EAAE,CAAC,CAAC,OAAO;YAChB,IAAI,EAAE,CAAC,CAAC,IAAI;SACb,CAAC;QACF,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC;QACnC,OAAO,KAAK,CAAC;IACf,CAAC;YAAS,CAAC;QACT,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,GAAyB;IAC3D,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QACrE,OAAO,OAAO;aACX,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,IAAI,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;aACpD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;aAClB,IAAI,EAAE,CAAC;IACZ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,KAAK,UAAU,QAAQ,CAAC,IAAY,EAAE,IAAY;IAChD,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3B,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;IAChE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;IACpD,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,WAAW,CAAC,IAA+B;IACzD,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,MAAM,EAAE,GAAG,oCAAoC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3D,IAAI,EAAE,EAAE,CAAC;QACP,MAAM,CAAC,GAAG,uBAAuB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAW,CAAC,CAAC;QACxD,IAAI,CAAC;YAAE,OAAQ,CAAC,CAAC,CAAC,CAAY,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;IACpE,CAAC;IACD,MAAM,CAAC,GAAG,0BAA0B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChD,OAAO,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,CAAY,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAC5C,CAAC;AAED,SAAS,UAAU,CAAC,IAAmB,EAAE,QAAgB;IACvD,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACjD,OAAO,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,CAAY,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;AAChD,CAAC;AAED,MAAM,SAAS,GAAG,CAAC,KAAmC,EAAY,EAAE;IAClE,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9E,CAAC;IACD,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,EAAE,CAAC;IAClF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;AACzB,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAC9B,IAA6D;IAE7D,MAAM,GAAG,GAAgB,EAAE,CAAC;IAC5B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,WAAW,IAAI,EAAE,CAAC,EAAE,CAAC;YAClE,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;gBACzB,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;gBACjC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,IAAI,EAAE,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YAC1D,CAAC;iBAAM,IAAI,GAAG,CAAC,GAAG,CAAC,KAAK,SAAS,EAAE,CAAC;gBAClC,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;YACnB,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,GAAgB,EAAE,IAAY;IAC3D,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IACrC,MAAM,KAAK,GAAe,EAAE,CAAC;IAC7B,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,IAAI;QAAE,KAAK,CAAC,IAAI,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACtE,KAAK,CAAC,IAAI,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;IAClE,MAAM,GAAG,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IACtD,KAAK,CAAC,IAAI,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IAEhD,MAAM,IAAI,GAAc,EAAE,CAAC;IAC3B,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;QACxC,IAAI,GAAG;YAAE,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;IAC1C,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,IAAI,CAAC;IACrE,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,cAAc,CAAC,EAAE,IAAI,IAAI,IAAI,CAAC;IAC5E,MAAM,GAAG,GAAG,SAAS;QACnB,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,QAAQ,CAAC,0BAA0B,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAW,CAAC;QAChF,CAAC,CAAC,EAAE,CAAC;IAEP,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,KAAK,GACT,OAAO,MAAM,CAAC,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAC5F,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC5D,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC;IAEhD,OAAO;QACL,IAAI;QACJ,KAAK;QACL,MAAM,EAAE,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC;QAC9E,OAAO,EAAE,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI;QACnE,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC;QAC5B,SAAS,EAAE,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC;QACvC,OAAO,EACL,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ;YACtE,CAAC,CAAC,MAAM,CAAC,OAAO;YAChB,CAAC,CAAC,IAAI;QACV,UAAU,EAAE,MAAM,CAAC,UAAU,KAAK,IAAI;QACtC,YAAY,EAAE,OAAO,MAAM,CAAC,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI;QACpF,MAAM;QACN,KAAK;QACL,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACpD,WAAW,EAAE,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC;QACtC,QAAQ,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC;QAChC,WAAW,EAAE,UAAU,GAAG,CAAC,KAAK,IAAI,IAAI,IAAI,GAAG,CAAC,QAAQ,EAAE;QAC1D,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,KAAK,IAAI,IAAI,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI;QACrE,YAAY,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QAC/B,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;KAC/C,CAAC;AACJ,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,UAAU,CAAC,IAAc;IACvC,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC;IAC9C,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,GAA2C,EAC3C,IAAY;IAEZ,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IACrC,MAAM,GAAG,GAA6B,EAAE,CAAC;IACzC,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,IAAI;QAAE,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACnE,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,53 @@
1
+ import { createServer } from 'node:http';
2
+ import { type Config } from './config.ts';
3
+ import { type RoomInfo } from './rooms.ts';
4
+ import { playwrightAvailable } from './artifact.ts';
5
+ export interface ModelroomStatus {
6
+ phase: string;
7
+ message: string;
8
+ since: number;
9
+ lastEvent: {
10
+ file: string;
11
+ at: number;
12
+ } | null;
13
+ log: string[];
14
+ }
15
+ export interface ChatResult {
16
+ started: boolean;
17
+ reason?: string;
18
+ sessionId?: string;
19
+ pid?: number;
20
+ }
21
+ export interface App {
22
+ cfg: Config;
23
+ server: ReturnType<typeof createServer>;
24
+ status: ModelroomStatus;
25
+ startWatching: () => void;
26
+ listen: () => Promise<{
27
+ url: string;
28
+ cfg: Config;
29
+ }>;
30
+ close: () => Promise<void>;
31
+ }
32
+ export interface CreateOptions {
33
+ cwd?: string;
34
+ port?: number | string;
35
+ host?: string;
36
+ }
37
+ export declare function createModelroom(opts?: CreateOptions): Promise<App>;
38
+ export declare function publicConfig(cfg: Config): {
39
+ root: string;
40
+ rooms: string;
41
+ artifact: string;
42
+ docs: string[];
43
+ agent: {
44
+ adapter: import("./config.ts").AdapterName;
45
+ command: string;
46
+ agent: string;
47
+ model: string | null;
48
+ standalone: boolean;
49
+ };
50
+ };
51
+ export { playwrightAvailable };
52
+ export type { RoomInfo };
53
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../lib/server.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,YAAY,EAA6C,MAAM,WAAW,CAAC;AAMpF,OAAO,EAKL,KAAK,MAAM,EAEZ,MAAM,aAAa,CAAC;AACrB,OAAO,EAAmD,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAG5F,OAAO,EAAkB,mBAAmB,EAAqB,MAAM,eAAe,CAAC;AA0BvF,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC/C,GAAG,EAAE,MAAM,EAAE,CAAC;CACf;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,GAAG;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;IACxC,MAAM,EAAE,eAAe,CAAC;IACxB,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,MAAM,EAAE,MAAM,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACpD,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,eAAe,CAAC,IAAI,GAAE,aAAkB,GAAG,OAAO,CAAC,GAAG,CAAC,CAwe5E;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM;IAEpC,IAAI;IACJ,KAAK;IACL,QAAQ;IACR,IAAI;IACJ,KAAK;QACH,OAAO;QACP,OAAO;QACP,KAAK;QACL,KAAK;QACL,UAAU;;EAGf;AAED,OAAO,EAAE,mBAAmB,EAAE,CAAC;AAC/B,YAAY,EAAE,QAAQ,EAAE,CAAC"}