@vonneollc/knbase 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 +182 -0
- package/bin/knbase +5 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +143 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/agents-doc.d.ts +6 -0
- package/dist/core/agents-doc.js +50 -0
- package/dist/core/agents-doc.js.map +1 -0
- package/dist/core/config.d.ts +30 -0
- package/dist/core/config.js +89 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/engine.d.ts +101 -0
- package/dist/core/engine.js +350 -0
- package/dist/core/engine.js.map +1 -0
- package/dist/core/files.d.ts +23 -0
- package/dist/core/files.js +66 -0
- package/dist/core/files.js.map +1 -0
- package/dist/core/index-store.d.ts +17 -0
- package/dist/core/index-store.js +97 -0
- package/dist/core/index-store.js.map +1 -0
- package/dist/core/log.d.ts +11 -0
- package/dist/core/log.js +38 -0
- package/dist/core/log.js.map +1 -0
- package/dist/core/mindmap.d.ts +11 -0
- package/dist/core/mindmap.js +71 -0
- package/dist/core/mindmap.js.map +1 -0
- package/dist/core/session.d.ts +15 -0
- package/dist/core/session.js +53 -0
- package/dist/core/session.js.map +1 -0
- package/dist/core/templates.d.ts +16 -0
- package/dist/core/templates.js +163 -0
- package/dist/core/templates.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/server.d.ts +3 -0
- package/dist/mcp/server.js +39 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools.d.ts +2 -0
- package/dist/mcp/tools.js +129 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/types.d.ts +67 -0
- package/dist/types.js +13 -0
- package/dist/types.js.map +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { DEFAULT_CONFIG, ensureDir, isInitialized, loadConfig, paths, resolveProjectRoot, saveConfig, } from "./config.js";
|
|
3
|
+
import { checksum, missingSections, readDoc, writeDoc, } from "./files.js";
|
|
4
|
+
import { currentChecksums, loadIndex, missingFiles, recordWrite, refreshIndex, saveIndex, } from "./index-store.js";
|
|
5
|
+
import { appendLog, hasTaskCompletedSince, readLog } from "./log.js";
|
|
6
|
+
import { renderMindmapDoc, writeMindmap } from "./mindmap.js";
|
|
7
|
+
import { clearSession, contextMatchesDisk, isSessionFresh, loadSession, newSessionId, newTaskId, saveSession, } from "./session.js";
|
|
8
|
+
import { TEMPLATES } from "./templates.js";
|
|
9
|
+
/** Open a project handle (does not create anything). */
|
|
10
|
+
export function openProject(startDir) {
|
|
11
|
+
const root = resolveProjectRoot(startDir);
|
|
12
|
+
const config = loadConfig(root);
|
|
13
|
+
return { root, config, p: paths(root, config) };
|
|
14
|
+
}
|
|
15
|
+
export function isKnownFile(config, key) {
|
|
16
|
+
return config.files.includes(key);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Initialize knbase in a project: create `.knbase/`, write config, scaffold
|
|
20
|
+
* any missing governance docs with templates, build index + mindmap.
|
|
21
|
+
*/
|
|
22
|
+
export function initProject(startDir, docsDir) {
|
|
23
|
+
const root = resolveProjectRoot(startDir);
|
|
24
|
+
const existed = isInitialized(root);
|
|
25
|
+
const config = existed
|
|
26
|
+
? loadConfig(root)
|
|
27
|
+
: { ...DEFAULT_CONFIG, ...(docsDir ? { docsDir } : {}) };
|
|
28
|
+
const p = paths(root, config);
|
|
29
|
+
ensureDir(p.systemDir);
|
|
30
|
+
ensureDir(p.docsDir);
|
|
31
|
+
saveConfig(root, config);
|
|
32
|
+
const scaffolded = [];
|
|
33
|
+
const alreadyPresent = [];
|
|
34
|
+
for (const key of config.files) {
|
|
35
|
+
const docPath = p.docPath(key);
|
|
36
|
+
if (existsSync(docPath)) {
|
|
37
|
+
alreadyPresent.push(key);
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
writeDoc(docPath, TEMPLATES[key].scaffold);
|
|
41
|
+
scaffolded.push(key);
|
|
42
|
+
}
|
|
43
|
+
const index = refreshIndex(p, config);
|
|
44
|
+
saveIndex(p, index);
|
|
45
|
+
writeMindmap(p, config, index);
|
|
46
|
+
appendLog(p, {
|
|
47
|
+
event: "init",
|
|
48
|
+
detail: `Initialized knbase (docsDir=${config.docsDir})`,
|
|
49
|
+
meta: { scaffolded, alreadyPresent },
|
|
50
|
+
});
|
|
51
|
+
return { root, createdConfig: !existed, scaffolded, alreadyPresent };
|
|
52
|
+
}
|
|
53
|
+
function buildCompactContext(p, config, index) {
|
|
54
|
+
const files = config.files.map((key) => {
|
|
55
|
+
const e = index.files[key];
|
|
56
|
+
return {
|
|
57
|
+
key,
|
|
58
|
+
exists: e.exists,
|
|
59
|
+
summary: e.summary || TEMPLATES[key].purpose,
|
|
60
|
+
headings: e.headings,
|
|
61
|
+
bytes: e.bytes,
|
|
62
|
+
updatedAt: e.updatedAt,
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
return {
|
|
66
|
+
currentPhase: extractCurrentPhase(p, config),
|
|
67
|
+
mindmap: renderMindmapDoc(config, index),
|
|
68
|
+
files,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/** Pulls the "Current Phase" section body from phase.md, if present. */
|
|
72
|
+
function extractCurrentPhase(p, config) {
|
|
73
|
+
if (!config.files.includes("phase"))
|
|
74
|
+
return "unknown";
|
|
75
|
+
const doc = readDoc(p.docPath("phase"));
|
|
76
|
+
if (!doc.exists)
|
|
77
|
+
return "unknown";
|
|
78
|
+
const lines = doc.content.split(/\r?\n/);
|
|
79
|
+
const idx = lines.findIndex((l) => /^##\s+Current Phase\s*$/i.test(l));
|
|
80
|
+
if (idx === -1)
|
|
81
|
+
return "unknown";
|
|
82
|
+
const body = [];
|
|
83
|
+
for (let i = idx + 1; i < lines.length; i++) {
|
|
84
|
+
if (/^##\s+/.test(lines[i]))
|
|
85
|
+
break;
|
|
86
|
+
const t = lines[i].trim();
|
|
87
|
+
if (t && !t.startsWith(">") && !t.startsWith("<!--"))
|
|
88
|
+
body.push(t);
|
|
89
|
+
}
|
|
90
|
+
return body.join(" ").trim() || "unspecified";
|
|
91
|
+
}
|
|
92
|
+
const BOOTSTRAP_INSTRUCTIONS = "Governance files are missing or empty. Before doing ANY work you must author them. " +
|
|
93
|
+
"For each file below, call `write_governance_file` with real content covering all required sections, " +
|
|
94
|
+
"derived from the user's request/prompt. Do not begin_task until all files exist.";
|
|
95
|
+
const READY_INSTRUCTIONS = "Context loaded. You now have the mind map, per-file summaries, and current phase. " +
|
|
96
|
+
"Fetch full file contents with `get_context(files=[...], full=true)` ONLY when needed (to save tokens). " +
|
|
97
|
+
"Call `begin_task` before making changes, and `complete_task` after, updating memory.md.";
|
|
98
|
+
export function startSession(project) {
|
|
99
|
+
const { p, config, root } = project;
|
|
100
|
+
ensureDir(p.systemDir);
|
|
101
|
+
// Persist config so MCP-only usage (without `knbase init`) is fully
|
|
102
|
+
// functional for status/guard checks.
|
|
103
|
+
if (!isInitialized(root))
|
|
104
|
+
saveConfig(root, config);
|
|
105
|
+
const index = refreshIndex(p, config);
|
|
106
|
+
saveIndex(p, index);
|
|
107
|
+
const missing = missingFiles(p, config);
|
|
108
|
+
const sessionId = newSessionId();
|
|
109
|
+
if (missing.length > 0) {
|
|
110
|
+
const session = {
|
|
111
|
+
sessionId,
|
|
112
|
+
state: "NEEDS_BOOTSTRAP",
|
|
113
|
+
startedAt: new Date().toISOString(),
|
|
114
|
+
contextChecksums: currentChecksums(p, config),
|
|
115
|
+
activeTask: null,
|
|
116
|
+
};
|
|
117
|
+
saveSession(p, session);
|
|
118
|
+
appendLog(p, {
|
|
119
|
+
sessionId,
|
|
120
|
+
event: "bootstrap_required",
|
|
121
|
+
detail: `Missing governance files: ${missing.join(", ")}`,
|
|
122
|
+
meta: { missing },
|
|
123
|
+
});
|
|
124
|
+
return {
|
|
125
|
+
sessionId,
|
|
126
|
+
state: "NEEDS_BOOTSTRAP",
|
|
127
|
+
needsBootstrap: true,
|
|
128
|
+
missing,
|
|
129
|
+
instructions: BOOTSTRAP_INSTRUCTIONS,
|
|
130
|
+
bootstrapTemplates: missing.map((key) => ({
|
|
131
|
+
key,
|
|
132
|
+
requiredSections: TEMPLATES[key].requiredSections,
|
|
133
|
+
})),
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
const session = {
|
|
137
|
+
sessionId,
|
|
138
|
+
state: "CONTEXT_LOADED",
|
|
139
|
+
startedAt: new Date().toISOString(),
|
|
140
|
+
contextChecksums: currentChecksums(p, config),
|
|
141
|
+
activeTask: null,
|
|
142
|
+
};
|
|
143
|
+
saveSession(p, session);
|
|
144
|
+
appendLog(p, { sessionId, event: "session_start", detail: "Context loaded" });
|
|
145
|
+
return {
|
|
146
|
+
sessionId,
|
|
147
|
+
state: "CONTEXT_LOADED",
|
|
148
|
+
needsBootstrap: false,
|
|
149
|
+
missing: [],
|
|
150
|
+
instructions: READY_INSTRUCTIONS,
|
|
151
|
+
compactContext: buildCompactContext(p, config, index),
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
export function getContext(project, files, full) {
|
|
155
|
+
const { p, config } = project;
|
|
156
|
+
const index = refreshIndex(p, config);
|
|
157
|
+
saveIndex(p, index);
|
|
158
|
+
const result = { compact: buildCompactContext(p, config, index) };
|
|
159
|
+
if (full && files && files.length > 0) {
|
|
160
|
+
result.fullContents = [];
|
|
161
|
+
for (const key of files) {
|
|
162
|
+
if (!isKnownFile(config, key))
|
|
163
|
+
continue;
|
|
164
|
+
result.fullContents.push({ key, content: readDoc(p.docPath(key)).content });
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return result;
|
|
168
|
+
}
|
|
169
|
+
export function writeGovernanceFile(project, key, content, summary) {
|
|
170
|
+
const { p, config } = project;
|
|
171
|
+
if (!isKnownFile(config, key)) {
|
|
172
|
+
throw new Error(`Unknown governance file '${key}'. Valid: ${config.files.join(", ")}`);
|
|
173
|
+
}
|
|
174
|
+
const tpl = TEMPLATES[key];
|
|
175
|
+
const missing = missingSections(content, tpl.requiredSections);
|
|
176
|
+
if (missing.length > 0) {
|
|
177
|
+
return {
|
|
178
|
+
key,
|
|
179
|
+
bytes: 0,
|
|
180
|
+
ok: false,
|
|
181
|
+
missingSections: missing,
|
|
182
|
+
remainingBootstrap: missingFiles(p, config),
|
|
183
|
+
state: loadSession(p)?.state ?? "UNINITIALIZED",
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
writeDoc(p.docPath(key), content);
|
|
187
|
+
const sum = checksum(content.endsWith("\n") ? content : content + "\n");
|
|
188
|
+
const bytes = Buffer.byteLength(content, "utf8");
|
|
189
|
+
const doc = readDoc(p.docPath(key));
|
|
190
|
+
const index = loadIndex(p, config);
|
|
191
|
+
recordWrite(index, key, sum, bytes, doc.headings, summary);
|
|
192
|
+
saveIndex(p, index);
|
|
193
|
+
writeMindmap(p, config, index);
|
|
194
|
+
const session = loadSession(p);
|
|
195
|
+
const remaining = missingFiles(p, config);
|
|
196
|
+
// Once bootstrap is complete, advance the session to CONTEXT_LOADED.
|
|
197
|
+
if (session && session.state === "NEEDS_BOOTSTRAP" && remaining.length === 0) {
|
|
198
|
+
session.state = "CONTEXT_LOADED";
|
|
199
|
+
session.contextChecksums = currentChecksums(p, config);
|
|
200
|
+
saveSession(p, session);
|
|
201
|
+
}
|
|
202
|
+
appendLog(p, {
|
|
203
|
+
sessionId: session?.sessionId,
|
|
204
|
+
event: "file_written",
|
|
205
|
+
detail: `Wrote ${key}.md (${bytes} bytes)`,
|
|
206
|
+
meta: { key, summary },
|
|
207
|
+
});
|
|
208
|
+
return {
|
|
209
|
+
key,
|
|
210
|
+
bytes,
|
|
211
|
+
ok: true,
|
|
212
|
+
missingSections: [],
|
|
213
|
+
remainingBootstrap: remaining,
|
|
214
|
+
state: loadSession(p)?.state ?? "CONTEXT_LOADED",
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
export function beginTask(project, description) {
|
|
218
|
+
const { p, config } = project;
|
|
219
|
+
const session = loadSession(p);
|
|
220
|
+
if (!session || session.state === "UNINITIALIZED") {
|
|
221
|
+
return { ok: false, error: "No active session. Call start_session first." };
|
|
222
|
+
}
|
|
223
|
+
if (session.state === "NEEDS_BOOTSTRAP") {
|
|
224
|
+
return {
|
|
225
|
+
ok: false,
|
|
226
|
+
error: "Governance files are incomplete. Author them via write_governance_file before starting tasks.",
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
if (session.state === "TASK_ACTIVE") {
|
|
230
|
+
return {
|
|
231
|
+
ok: false,
|
|
232
|
+
error: `A task is already active (${session.activeTask?.taskId}). Call complete_task first.`,
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
// Gate: context must reflect what is on disk right now.
|
|
236
|
+
if (!contextMatchesDisk(session, currentChecksums(p, config))) {
|
|
237
|
+
return {
|
|
238
|
+
ok: false,
|
|
239
|
+
error: "Governance files changed since context was loaded. Call start_session/get_context again before starting a task.",
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
const taskId = newTaskId();
|
|
243
|
+
session.state = "TASK_ACTIVE";
|
|
244
|
+
session.activeTask = {
|
|
245
|
+
taskId,
|
|
246
|
+
description,
|
|
247
|
+
startedAt: new Date().toISOString(),
|
|
248
|
+
startChecksums: currentChecksums(p, config),
|
|
249
|
+
};
|
|
250
|
+
saveSession(p, session);
|
|
251
|
+
appendLog(p, {
|
|
252
|
+
sessionId: session.sessionId,
|
|
253
|
+
event: "task_begin",
|
|
254
|
+
detail: description,
|
|
255
|
+
meta: { taskId },
|
|
256
|
+
});
|
|
257
|
+
return {
|
|
258
|
+
ok: true,
|
|
259
|
+
taskId,
|
|
260
|
+
reminder: "When done, call complete_task with a summary and update memory.md (and phase.md if the phase advanced).",
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
export function completeTask(project, taskId, summary) {
|
|
264
|
+
const { p, config } = project;
|
|
265
|
+
const session = loadSession(p);
|
|
266
|
+
if (!session || session.state !== "TASK_ACTIVE" || !session.activeTask) {
|
|
267
|
+
return { ok: false, error: "No active task. Call begin_task first." };
|
|
268
|
+
}
|
|
269
|
+
if (session.activeTask.taskId !== taskId) {
|
|
270
|
+
return {
|
|
271
|
+
ok: false,
|
|
272
|
+
error: `Task id mismatch. Active task is ${session.activeTask.taskId}.`,
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
// Gate: memory.md must have changed since the task began.
|
|
276
|
+
const now = currentChecksums(p, config);
|
|
277
|
+
const start = session.activeTask.startChecksums;
|
|
278
|
+
const changed = config.files.filter((k) => now[k] !== start[k]);
|
|
279
|
+
if (config.files.includes("memory") && now.memory === start.memory) {
|
|
280
|
+
return {
|
|
281
|
+
ok: false,
|
|
282
|
+
error: "memory.md was not updated during this task. Update it via write_governance_file (record the change under 'Recent Changes'), then call complete_task again.",
|
|
283
|
+
updatedFiles: changed,
|
|
284
|
+
state: session.state,
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
session.state = "CONTEXT_LOADED";
|
|
288
|
+
session.activeTask = null;
|
|
289
|
+
session.contextChecksums = now;
|
|
290
|
+
saveSession(p, session);
|
|
291
|
+
const index = refreshIndex(p, config);
|
|
292
|
+
saveIndex(p, index);
|
|
293
|
+
writeMindmap(p, config, index);
|
|
294
|
+
appendLog(p, {
|
|
295
|
+
sessionId: session.sessionId,
|
|
296
|
+
event: "task_complete",
|
|
297
|
+
detail: summary,
|
|
298
|
+
meta: { taskId, updatedFiles: changed },
|
|
299
|
+
});
|
|
300
|
+
return { ok: true, updatedFiles: changed, state: "CONTEXT_LOADED" };
|
|
301
|
+
}
|
|
302
|
+
export function getStatus(project) {
|
|
303
|
+
const { p, config, root } = project;
|
|
304
|
+
const initialized = isInitialized(root);
|
|
305
|
+
const session = loadSession(p);
|
|
306
|
+
return {
|
|
307
|
+
initialized,
|
|
308
|
+
root,
|
|
309
|
+
docsDir: config.docsDir,
|
|
310
|
+
state: session?.state ?? "UNINITIALIZED",
|
|
311
|
+
sessionFresh: isSessionFresh(session, config),
|
|
312
|
+
missing: initialized ? missingFiles(p, config) : [...config.files],
|
|
313
|
+
activeTask: session?.activeTask ?? null,
|
|
314
|
+
recentLog: initialized ? readLog(p, 10) : [],
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Decide whether a gated shell command may run. Requires: initialized project,
|
|
319
|
+
* all governance files present, and a fresh CONTEXT_LOADED/TASK_ACTIVE session
|
|
320
|
+
* whose loaded context still matches disk.
|
|
321
|
+
*/
|
|
322
|
+
export function guardDecision(project) {
|
|
323
|
+
const { p, config, root } = project;
|
|
324
|
+
if (!isInitialized(root)) {
|
|
325
|
+
return { allow: false, reason: "knbase is not initialized. Run `knbase init`." };
|
|
326
|
+
}
|
|
327
|
+
const missing = missingFiles(p, config);
|
|
328
|
+
if (missing.length > 0) {
|
|
329
|
+
return {
|
|
330
|
+
allow: false,
|
|
331
|
+
reason: `Governance files missing/empty: ${missing.join(", ")}. Author them first.`,
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
const session = loadSession(p);
|
|
335
|
+
if (!isSessionFresh(session, config)) {
|
|
336
|
+
return {
|
|
337
|
+
allow: false,
|
|
338
|
+
reason: "No fresh session. Start a session (read context) before acting.",
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
if (!contextMatchesDisk(session, currentChecksums(p, config))) {
|
|
342
|
+
return {
|
|
343
|
+
allow: false,
|
|
344
|
+
reason: "Governance files changed since context load. Re-read context.",
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
return { allow: true, reason: "Context is loaded and current." };
|
|
348
|
+
}
|
|
349
|
+
export { appendLog, clearSession, hasTaskCompletedSince, loadSession, readLog, };
|
|
350
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/core/engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EACL,cAAc,EACd,SAAS,EACT,aAAa,EACb,UAAU,EACV,KAAK,EACL,kBAAkB,EAClB,UAAU,GAEX,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,QAAQ,EACR,eAAe,EACf,OAAO,EACP,QAAQ,GACT,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,gBAAgB,EAChB,SAAS,EACT,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,SAAS,GACV,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,cAAc,EACd,WAAW,EACX,YAAY,EACZ,SAAS,EACT,WAAW,GACZ,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAc3C,wDAAwD;AACxD,MAAM,UAAU,WAAW,CAAC,QAAiB;IAC3C,MAAM,IAAI,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAChC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,MAAoB,EAAE,GAAW;IAC3D,OAAQ,MAAM,CAAC,KAAkB,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;AAClD,CAAC;AAWD;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,QAAiB,EAAE,OAAgB;IAC7D,MAAM,IAAI,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IAC1C,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACpC,MAAM,MAAM,GAAiB,OAAO;QAClC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC;QAClB,CAAC,CAAC,EAAE,GAAG,cAAc,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;IAC3D,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAE9B,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACvB,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IACrB,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAEzB,MAAM,UAAU,GAAwB,EAAE,CAAC;IAC3C,MAAM,cAAc,GAAwB,EAAE,CAAC;IAC/C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YACxB,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACzB,SAAS;QACX,CAAC;QACD,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC;QAC3C,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC;IAED,MAAM,KAAK,GAAG,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IACtC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACpB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;IAC/B,SAAS,CAAC,CAAC,EAAE;QACX,KAAK,EAAE,MAAM;QACb,MAAM,EAAE,+BAA+B,MAAM,CAAC,OAAO,GAAG;QACxD,IAAI,EAAE,EAAE,UAAU,EAAE,cAAc,EAAE;KACrC,CAAC,CAAC;IAEH,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,CAAC;AACvE,CAAC;AA2BD,SAAS,mBAAmB,CAAC,CAAgB,EAAE,MAAoB,EAAE,KAAgB;IACnF,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QACrC,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC3B,OAAO;YACL,GAAG;YACH,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,OAAO,EAAE,CAAC,CAAC,OAAO,IAAI,SAAS,CAAC,GAAG,CAAC,CAAC,OAAO;YAC5C,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,SAAS,EAAE,CAAC,CAAC,SAAS;SACvB,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,OAAO;QACL,YAAY,EAAE,mBAAmB,CAAC,CAAC,EAAE,MAAM,CAAC;QAC5C,OAAO,EAAE,gBAAgB,CAAC,MAAM,EAAE,KAAK,CAAC;QACxC,KAAK;KACN,CAAC;AACJ,CAAC;AAED,wEAAwE;AACxE,SAAS,mBAAmB,CAAC,CAAgB,EAAE,MAAoB;IACjE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC;QAAE,OAAO,SAAS,CAAC;IACtD,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;IACxC,IAAI,CAAC,GAAG,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IAClC,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACzC,MAAM,GAAG,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,0BAA0B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACvE,IAAI,GAAG,KAAK,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IACjC,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,KAAK,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5C,IAAI,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAAE,MAAM;QACnC,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC1B,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC;YAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACrE,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,IAAI,aAAa,CAAC;AAChD,CAAC;AAED,MAAM,sBAAsB,GAC1B,qFAAqF;IACrF,sGAAsG;IACtG,kFAAkF,CAAC;AAErF,MAAM,kBAAkB,GACtB,oFAAoF;IACpF,yGAAyG;IACzG,yFAAyF,CAAC;AAE5F,MAAM,UAAU,YAAY,CAAC,OAAgB;IAC3C,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC;IACpC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACvB,oEAAoE;IACpE,sCAAsC;IACtC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC;QAAE,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACnD,MAAM,KAAK,GAAG,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IACtC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAEpB,MAAM,OAAO,GAAG,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IACxC,MAAM,SAAS,GAAG,YAAY,EAAE,CAAC;IAEjC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,OAAO,GAAgB;YAC3B,SAAS;YACT,KAAK,EAAE,iBAAiB;YACxB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,gBAAgB,EAAE,gBAAgB,CAAC,CAAC,EAAE,MAAM,CAAC;YAC7C,UAAU,EAAE,IAAI;SACjB,CAAC;QACF,WAAW,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;QACxB,SAAS,CAAC,CAAC,EAAE;YACX,SAAS;YACT,KAAK,EAAE,oBAAoB;YAC3B,MAAM,EAAE,6BAA6B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;YACzD,IAAI,EAAE,EAAE,OAAO,EAAE;SAClB,CAAC,CAAC;QACH,OAAO;YACL,SAAS;YACT,KAAK,EAAE,iBAAiB;YACxB,cAAc,EAAE,IAAI;YACpB,OAAO;YACP,YAAY,EAAE,sBAAsB;YACpC,kBAAkB,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;gBACxC,GAAG;gBACH,gBAAgB,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,gBAAgB;aAClD,CAAC,CAAC;SACJ,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAgB;QAC3B,SAAS;QACT,KAAK,EAAE,gBAAgB;QACvB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,gBAAgB,EAAE,gBAAgB,CAAC,CAAC,EAAE,MAAM,CAAC;QAC7C,UAAU,EAAE,IAAI;KACjB,CAAC;IACF,WAAW,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IACxB,SAAS,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAAC;IAE9E,OAAO;QACL,SAAS;QACT,KAAK,EAAE,gBAAgB;QACvB,cAAc,EAAE,KAAK;QACrB,OAAO,EAAE,EAAE;QACX,YAAY,EAAE,kBAAkB;QAChC,cAAc,EAAE,mBAAmB,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC;KACtD,CAAC;AACJ,CAAC;AASD,MAAM,UAAU,UAAU,CACxB,OAAgB,EAChB,KAAgB,EAChB,IAAc;IAEd,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAC9B,MAAM,KAAK,GAAG,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IACtC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACpB,MAAM,MAAM,GAAqB,EAAE,OAAO,EAAE,mBAAmB,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC;IAEpF,IAAI,IAAI,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtC,MAAM,CAAC,YAAY,GAAG,EAAE,CAAC;QACzB,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;YACxB,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,GAAG,CAAC;gBAAE,SAAS;YACxC,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;QAC9E,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAaD,MAAM,UAAU,mBAAmB,CACjC,OAAgB,EAChB,GAAW,EACX,OAAe,EACf,OAAe;IAEf,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAC9B,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CACb,4BAA4B,GAAG,aAAa,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACtE,CAAC;IACJ,CAAC;IACD,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAC3B,MAAM,OAAO,GAAG,eAAe,CAAC,OAAO,EAAE,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAC/D,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO;YACL,GAAG;YACH,KAAK,EAAE,CAAC;YACR,EAAE,EAAE,KAAK;YACT,eAAe,EAAE,OAAO;YACxB,kBAAkB,EAAE,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC;YAC3C,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,eAAe;SAChD,CAAC;IACJ,CAAC;IAED,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC;IAClC,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IACxE,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACjD,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;IAEpC,MAAM,KAAK,GAAG,SAAS,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IACnC,WAAW,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC3D,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACpB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;IAE/B,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;IAC/B,MAAM,SAAS,GAAG,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAC1C,qEAAqE;IACrE,IAAI,OAAO,IAAI,OAAO,CAAC,KAAK,KAAK,iBAAiB,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7E,OAAO,CAAC,KAAK,GAAG,gBAAgB,CAAC;QACjC,OAAO,CAAC,gBAAgB,GAAG,gBAAgB,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QACvD,WAAW,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IAC1B,CAAC;IAED,SAAS,CAAC,CAAC,EAAE;QACX,SAAS,EAAE,OAAO,EAAE,SAAS;QAC7B,KAAK,EAAE,cAAc;QACrB,MAAM,EAAE,SAAS,GAAG,QAAQ,KAAK,SAAS;QAC1C,IAAI,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE;KACvB,CAAC,CAAC;IAEH,OAAO;QACL,GAAG;QACH,KAAK;QACL,EAAE,EAAE,IAAI;QACR,eAAe,EAAE,EAAE;QACnB,kBAAkB,EAAE,SAAS;QAC7B,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,gBAAgB;KACjD,CAAC;AACJ,CAAC;AAWD,MAAM,UAAU,SAAS,CAAC,OAAgB,EAAE,WAAmB;IAC7D,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAC9B,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;IAE/B,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,KAAK,KAAK,eAAe,EAAE,CAAC;QAClD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,8CAA8C,EAAE,CAAC;IAC9E,CAAC;IACD,IAAI,OAAO,CAAC,KAAK,KAAK,iBAAiB,EAAE,CAAC;QACxC,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EACH,+FAA+F;SAClG,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,CAAC,KAAK,KAAK,aAAa,EAAE,CAAC;QACpC,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,6BAA6B,OAAO,CAAC,UAAU,EAAE,MAAM,8BAA8B;SAC7F,CAAC;IACJ,CAAC;IACD,wDAAwD;IACxD,IAAI,CAAC,kBAAkB,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC;QAC9D,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EACH,iHAAiH;SACpH,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,OAAO,CAAC,KAAK,GAAG,aAAa,CAAC;IAC9B,OAAO,CAAC,UAAU,GAAG;QACnB,MAAM;QACN,WAAW;QACX,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,cAAc,EAAE,gBAAgB,CAAC,CAAC,EAAE,MAAM,CAAC;KAC5C,CAAC;IACF,WAAW,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IACxB,SAAS,CAAC,CAAC,EAAE;QACX,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,KAAK,EAAE,YAAY;QACnB,MAAM,EAAE,WAAW;QACnB,IAAI,EAAE,EAAE,MAAM,EAAE;KACjB,CAAC,CAAC;IACH,OAAO;QACL,EAAE,EAAE,IAAI;QACR,MAAM;QACN,QAAQ,EACN,yGAAyG;KAC5G,CAAC;AACJ,CAAC;AASD,MAAM,UAAU,YAAY,CAC1B,OAAgB,EAChB,MAAc,EACd,OAAe;IAEf,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAC9B,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;IAE/B,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,KAAK,KAAK,aAAa,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;QACvE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,wCAAwC,EAAE,CAAC;IACxE,CAAC;IACD,IAAI,OAAO,CAAC,UAAU,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QACzC,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,oCAAoC,OAAO,CAAC,UAAU,CAAC,MAAM,GAAG;SACxE,CAAC;IACJ,CAAC;IAED,0DAA0D;IAC1D,MAAM,GAAG,GAAG,gBAAgB,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IACxC,MAAM,KAAK,GAAG,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC;IAChD,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAEhE,IAAI,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,EAAE,CAAC;QACnE,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EACH,4JAA4J;YAC9J,YAAY,EAAE,OAAO;YACrB,KAAK,EAAE,OAAO,CAAC,KAAK;SACrB,CAAC;IACJ,CAAC;IAED,OAAO,CAAC,KAAK,GAAG,gBAAgB,CAAC;IACjC,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAC1B,OAAO,CAAC,gBAAgB,GAAG,GAAG,CAAC;IAC/B,WAAW,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IAExB,MAAM,KAAK,GAAG,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IACtC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACpB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;IAE/B,SAAS,CAAC,CAAC,EAAE;QACX,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,KAAK,EAAE,eAAe;QACtB,MAAM,EAAE,OAAO;QACf,IAAI,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE;KACxC,CAAC,CAAC;IAEH,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC;AACtE,CAAC;AAeD,MAAM,UAAU,SAAS,CAAC,OAAgB;IACxC,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC;IACpC,MAAM,WAAW,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACxC,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;IAC/B,OAAO;QACL,WAAW;QACX,IAAI;QACJ,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,KAAK,EAAE,OAAO,EAAE,KAAK,IAAI,eAAe;QACxC,YAAY,EAAE,cAAc,CAAC,OAAO,EAAE,MAAM,CAAC;QAC7C,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC;QAClE,UAAU,EAAE,OAAO,EAAE,UAAU,IAAI,IAAI;QACvC,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE;KAC7C,CAAC;AACJ,CAAC;AASD;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,OAAgB;IAC5C,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC;IACpC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,+CAA+C,EAAE,CAAC;IACnF,CAAC;IACD,MAAM,OAAO,GAAG,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IACxC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO;YACL,KAAK,EAAE,KAAK;YACZ,MAAM,EAAE,mCAAmC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,sBAAsB;SACpF,CAAC;IACJ,CAAC;IACD,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;IAC/B,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,CAAC;QACrC,OAAO;YACL,KAAK,EAAE,KAAK;YACZ,MAAM,EAAE,iEAAiE;SAC1E,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,kBAAkB,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC;QAC9D,OAAO;YACL,KAAK,EAAE,KAAK;YACZ,MAAM,EAAE,+DAA+D;SACxE,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,gCAAgC,EAAE,CAAC;AACnE,CAAC;AAED,OAAO,EACL,SAAS,EACT,YAAY,EACZ,qBAAqB,EACrB,WAAW,EACX,OAAO,GACR,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** SHA-256 of a string. */
|
|
2
|
+
export declare function checksum(content: string): string;
|
|
3
|
+
export interface DocFileState {
|
|
4
|
+
exists: boolean;
|
|
5
|
+
content: string;
|
|
6
|
+
checksum: string;
|
|
7
|
+
bytes: number;
|
|
8
|
+
/** True when the file is missing or contains only whitespace/template guidance. */
|
|
9
|
+
isEmpty: boolean;
|
|
10
|
+
headings: string[];
|
|
11
|
+
}
|
|
12
|
+
/** Reads a doc from disk and computes its derived state. */
|
|
13
|
+
export declare function readDoc(absPath: string): DocFileState;
|
|
14
|
+
export declare function writeDoc(absPath: string, content: string): void;
|
|
15
|
+
/** Extract H2 (##) section headings, ignoring the H1 title and deeper levels. */
|
|
16
|
+
export declare function extractHeadings(content: string): string[];
|
|
17
|
+
/**
|
|
18
|
+
* Content is considered a "placeholder" (i.e. not yet authored) when every
|
|
19
|
+
* non-heading, non-comment line is empty or a guidance blockquote (`> ...`).
|
|
20
|
+
*/
|
|
21
|
+
export declare function isPlaceholderContent(content: string): boolean;
|
|
22
|
+
/** Returns the required sections that are missing from the given content. */
|
|
23
|
+
export declare function missingSections(content: string, required: string[]): string[];
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { dirname } from "node:path";
|
|
4
|
+
import { ensureDir } from "./config.js";
|
|
5
|
+
/** SHA-256 of a string. */
|
|
6
|
+
export function checksum(content) {
|
|
7
|
+
return createHash("sha256").update(content, "utf8").digest("hex");
|
|
8
|
+
}
|
|
9
|
+
/** Reads a doc from disk and computes its derived state. */
|
|
10
|
+
export function readDoc(absPath) {
|
|
11
|
+
if (!existsSync(absPath)) {
|
|
12
|
+
return {
|
|
13
|
+
exists: false,
|
|
14
|
+
content: "",
|
|
15
|
+
checksum: "",
|
|
16
|
+
bytes: 0,
|
|
17
|
+
isEmpty: true,
|
|
18
|
+
headings: [],
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
const content = readFileSync(absPath, "utf8");
|
|
22
|
+
return {
|
|
23
|
+
exists: true,
|
|
24
|
+
content,
|
|
25
|
+
checksum: checksum(content),
|
|
26
|
+
bytes: Buffer.byteLength(content, "utf8"),
|
|
27
|
+
isEmpty: isPlaceholderContent(content),
|
|
28
|
+
headings: extractHeadings(content),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
export function writeDoc(absPath, content) {
|
|
32
|
+
ensureDir(dirname(absPath));
|
|
33
|
+
const normalized = content.endsWith("\n") ? content : content + "\n";
|
|
34
|
+
writeFileSync(absPath, normalized, "utf8");
|
|
35
|
+
}
|
|
36
|
+
/** Extract H2 (##) section headings, ignoring the H1 title and deeper levels. */
|
|
37
|
+
export function extractHeadings(content) {
|
|
38
|
+
const out = [];
|
|
39
|
+
for (const line of content.split(/\r?\n/)) {
|
|
40
|
+
const m = /^##\s+(.+?)\s*$/.exec(line);
|
|
41
|
+
if (m)
|
|
42
|
+
out.push(m[1].trim());
|
|
43
|
+
}
|
|
44
|
+
return out;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Content is considered a "placeholder" (i.e. not yet authored) when every
|
|
48
|
+
* non-heading, non-comment line is empty or a guidance blockquote (`> ...`).
|
|
49
|
+
*/
|
|
50
|
+
export function isPlaceholderContent(content) {
|
|
51
|
+
const meaningful = content
|
|
52
|
+
.split(/\r?\n/)
|
|
53
|
+
.map((l) => l.trim())
|
|
54
|
+
.filter((l) => l.length > 0)
|
|
55
|
+
.filter((l) => !l.startsWith("#")) // headings
|
|
56
|
+
.filter((l) => !l.startsWith("<!--")) // html comments
|
|
57
|
+
.filter((l) => !l.startsWith("-->"))
|
|
58
|
+
.filter((l) => !l.startsWith(">")); // guidance blockquotes
|
|
59
|
+
return meaningful.length === 0;
|
|
60
|
+
}
|
|
61
|
+
/** Returns the required sections that are missing from the given content. */
|
|
62
|
+
export function missingSections(content, required) {
|
|
63
|
+
const present = new Set(extractHeadings(content).map((h) => h.toLowerCase()));
|
|
64
|
+
return required.filter((r) => !present.has(r.toLowerCase()));
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/core/files.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { GOVERNANCE_FILES, type KnbaseConfig, type GovernanceFileKey, type IndexData } from "../types.js";
|
|
2
|
+
import { paths, type ResolvedPaths } from "./config.js";
|
|
3
|
+
export declare function loadIndex(p: ResolvedPaths, config: KnbaseConfig): IndexData;
|
|
4
|
+
export declare function saveIndex(p: ResolvedPaths, index: IndexData): void;
|
|
5
|
+
/**
|
|
6
|
+
* Re-scans all governance docs from disk and refreshes their checksum/heading/
|
|
7
|
+
* exists metadata. Preserves agent-supplied summaries unless the file changed
|
|
8
|
+
* and a new summary is provided elsewhere. Returns the refreshed index.
|
|
9
|
+
*/
|
|
10
|
+
export declare function refreshIndex(p: ResolvedPaths, config: KnbaseConfig, existing?: IndexData): IndexData;
|
|
11
|
+
/** Update a single entry after an authored write, recording the agent summary. */
|
|
12
|
+
export declare function recordWrite(index: IndexData, key: GovernanceFileKey, checksum: string, bytes: number, headings: string[], summary: string): void;
|
|
13
|
+
/** Governance keys whose file is missing or still a placeholder. */
|
|
14
|
+
export declare function missingFiles(p: ResolvedPaths, config: KnbaseConfig): GovernanceFileKey[];
|
|
15
|
+
/** Current checksum map keyed by governance file key. */
|
|
16
|
+
export declare function currentChecksums(p: ResolvedPaths, config: KnbaseConfig): Record<string, string>;
|
|
17
|
+
export { GOVERNANCE_FILES, paths };
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { relative } from "node:path";
|
|
3
|
+
import { GOVERNANCE_FILES, } from "../types.js";
|
|
4
|
+
import { ensureDir, paths } from "./config.js";
|
|
5
|
+
import { readDoc } from "./files.js";
|
|
6
|
+
const INDEX_VERSION = 1;
|
|
7
|
+
function emptyEntry(key, path) {
|
|
8
|
+
return {
|
|
9
|
+
key,
|
|
10
|
+
path,
|
|
11
|
+
exists: false,
|
|
12
|
+
checksum: "",
|
|
13
|
+
bytes: 0,
|
|
14
|
+
summary: "",
|
|
15
|
+
headings: [],
|
|
16
|
+
updatedAt: null,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export function loadIndex(p, config) {
|
|
20
|
+
let data = null;
|
|
21
|
+
if (existsSync(p.indexPath)) {
|
|
22
|
+
try {
|
|
23
|
+
data = JSON.parse(readFileSync(p.indexPath, "utf8"));
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
data = null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const files = {};
|
|
30
|
+
for (const key of config.files) {
|
|
31
|
+
const rel = relative(p.root, p.docPath(key));
|
|
32
|
+
files[key] = data?.files?.[key] ?? emptyEntry(key, rel);
|
|
33
|
+
files[key].path = rel;
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
version: INDEX_VERSION,
|
|
37
|
+
updatedAt: data?.updatedAt ?? new Date().toISOString(),
|
|
38
|
+
files,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export function saveIndex(p, index) {
|
|
42
|
+
ensureDir(p.systemDir);
|
|
43
|
+
index.updatedAt = new Date().toISOString();
|
|
44
|
+
writeFileSync(p.indexPath, JSON.stringify(index, null, 2) + "\n", "utf8");
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Re-scans all governance docs from disk and refreshes their checksum/heading/
|
|
48
|
+
* exists metadata. Preserves agent-supplied summaries unless the file changed
|
|
49
|
+
* and a new summary is provided elsewhere. Returns the refreshed index.
|
|
50
|
+
*/
|
|
51
|
+
export function refreshIndex(p, config, existing) {
|
|
52
|
+
const index = existing ?? loadIndex(p, config);
|
|
53
|
+
for (const key of config.files) {
|
|
54
|
+
const state = readDoc(p.docPath(key));
|
|
55
|
+
const entry = index.files[key];
|
|
56
|
+
const changed = entry.checksum !== state.checksum;
|
|
57
|
+
entry.exists = state.exists && !state.isEmpty;
|
|
58
|
+
entry.checksum = state.checksum;
|
|
59
|
+
entry.bytes = state.bytes;
|
|
60
|
+
entry.headings = state.headings;
|
|
61
|
+
if (changed && state.exists) {
|
|
62
|
+
entry.updatedAt = new Date().toISOString();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return index;
|
|
66
|
+
}
|
|
67
|
+
/** Update a single entry after an authored write, recording the agent summary. */
|
|
68
|
+
export function recordWrite(index, key, checksum, bytes, headings, summary) {
|
|
69
|
+
const entry = index.files[key];
|
|
70
|
+
entry.exists = true;
|
|
71
|
+
entry.checksum = checksum;
|
|
72
|
+
entry.bytes = bytes;
|
|
73
|
+
entry.headings = headings;
|
|
74
|
+
if (summary.trim())
|
|
75
|
+
entry.summary = summary.trim();
|
|
76
|
+
entry.updatedAt = new Date().toISOString();
|
|
77
|
+
}
|
|
78
|
+
/** Governance keys whose file is missing or still a placeholder. */
|
|
79
|
+
export function missingFiles(p, config) {
|
|
80
|
+
const out = [];
|
|
81
|
+
for (const key of config.files) {
|
|
82
|
+
const state = readDoc(p.docPath(key));
|
|
83
|
+
if (!state.exists || state.isEmpty)
|
|
84
|
+
out.push(key);
|
|
85
|
+
}
|
|
86
|
+
return out;
|
|
87
|
+
}
|
|
88
|
+
/** Current checksum map keyed by governance file key. */
|
|
89
|
+
export function currentChecksums(p, config) {
|
|
90
|
+
const map = {};
|
|
91
|
+
for (const key of config.files) {
|
|
92
|
+
map[key] = readDoc(p.docPath(key)).checksum;
|
|
93
|
+
}
|
|
94
|
+
return map;
|
|
95
|
+
}
|
|
96
|
+
export { GOVERNANCE_FILES, paths };
|
|
97
|
+
//# sourceMappingURL=index-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-store.js","sourceRoot":"","sources":["../../src/core/index-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ResolvedPaths } from "./config.js";
|
|
2
|
+
import type { LogRecord } from "../types.js";
|
|
3
|
+
/** Append a record to the JSONL activity log. */
|
|
4
|
+
export declare function appendLog(p: ResolvedPaths, record: Omit<LogRecord, "ts">): LogRecord;
|
|
5
|
+
/** Read the most recent `limit` log records (newest last). */
|
|
6
|
+
export declare function readLog(p: ResolvedPaths, limit?: number): LogRecord[];
|
|
7
|
+
/**
|
|
8
|
+
* Whether a task_complete event has been recorded since the given ISO time.
|
|
9
|
+
* Used by the git pre-commit gate to require a memory update per change set.
|
|
10
|
+
*/
|
|
11
|
+
export declare function hasTaskCompletedSince(p: ResolvedPaths, sinceIso: string | null): boolean;
|
package/dist/core/log.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { appendFileSync, existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { ensureDir } from "./config.js";
|
|
3
|
+
/** Append a record to the JSONL activity log. */
|
|
4
|
+
export function appendLog(p, record) {
|
|
5
|
+
ensureDir(p.systemDir);
|
|
6
|
+
const full = { ts: new Date().toISOString(), ...record };
|
|
7
|
+
appendFileSync(p.logPath, JSON.stringify(full) + "\n", "utf8");
|
|
8
|
+
return full;
|
|
9
|
+
}
|
|
10
|
+
/** Read the most recent `limit` log records (newest last). */
|
|
11
|
+
export function readLog(p, limit = 50) {
|
|
12
|
+
if (!existsSync(p.logPath))
|
|
13
|
+
return [];
|
|
14
|
+
const lines = readFileSync(p.logPath, "utf8")
|
|
15
|
+
.split(/\r?\n/)
|
|
16
|
+
.filter((l) => l.trim().length > 0);
|
|
17
|
+
const slice = limit > 0 ? lines.slice(-limit) : lines;
|
|
18
|
+
const out = [];
|
|
19
|
+
for (const line of slice) {
|
|
20
|
+
try {
|
|
21
|
+
out.push(JSON.parse(line));
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
// skip malformed lines
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return out;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Whether a task_complete event has been recorded since the given ISO time.
|
|
31
|
+
* Used by the git pre-commit gate to require a memory update per change set.
|
|
32
|
+
*/
|
|
33
|
+
export function hasTaskCompletedSince(p, sinceIso) {
|
|
34
|
+
const records = readLog(p, 0);
|
|
35
|
+
const since = sinceIso ? Date.parse(sinceIso) : 0;
|
|
36
|
+
return records.some((r) => r.event === "task_complete" && Date.parse(r.ts) >= since);
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=log.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.js","sourceRoot":"","sources":["../../src/core/log.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAIxC,iDAAiD;AACjD,MAAM,UAAU,SAAS,CACvB,CAAgB,EAChB,MAA6B;IAE7B,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACvB,MAAM,IAAI,GAAc,EAAE,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,GAAG,MAAM,EAAE,CAAC;IACpE,cAAc,CAAC,CAAC,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC;IAC/D,OAAO,IAAI,CAAC;AACd,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,OAAO,CAAC,CAAgB,EAAE,KAAK,GAAG,EAAE;IAClD,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC;QAAE,OAAO,EAAE,CAAC;IACtC,MAAM,KAAK,GAAG,YAAY,CAAC,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC;SAC1C,KAAK,CAAC,OAAO,CAAC;SACd,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACtC,MAAM,KAAK,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IACtD,MAAM,GAAG,GAAgB,EAAE,CAAC;IAC5B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAc,CAAC,CAAC;QAC1C,CAAC;QAAC,MAAM,CAAC;YACP,uBAAuB;QACzB,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,CAAgB,EAAE,QAAuB;IAC7E,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC9B,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAClD,OAAO,OAAO,CAAC,IAAI,CACjB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,eAAe,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,KAAK,CAChE,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type ResolvedPaths } from "./config.js";
|
|
2
|
+
import type { KnbaseConfig, IndexData } from "../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Build a deterministic mermaid `mindmap` from the index: root -> one node per
|
|
5
|
+
* governance file (with its one-line summary) -> child nodes per H2 heading.
|
|
6
|
+
* No LLM involved; purely structural, so it is cheap and reproducible.
|
|
7
|
+
*/
|
|
8
|
+
export declare function buildMindmap(config: KnbaseConfig, index: IndexData): string;
|
|
9
|
+
/** Render the full mindmap.md document (fenced mermaid + text summary table). */
|
|
10
|
+
export declare function renderMindmapDoc(config: KnbaseConfig, index: IndexData): string;
|
|
11
|
+
export declare function writeMindmap(p: ResolvedPaths, config: KnbaseConfig, index: IndexData): string;
|