bmad-studio 0.2.0 → 1.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 +163 -17
- package/package.json +12 -3
- package/packages/client/dist/assets/index-81ZKe-R8.css +1 -0
- package/packages/client/dist/assets/index-DyjtzhqN.js +641 -0
- package/packages/client/dist/index.html +2 -2
- package/packages/server/dist/app.d.ts +2 -1
- package/packages/server/dist/app.d.ts.map +1 -1
- package/packages/server/dist/app.js +68 -3
- package/packages/server/dist/app.js.map +1 -1
- package/packages/server/dist/core/file-store.d.ts +8 -1
- package/packages/server/dist/core/file-store.d.ts.map +1 -1
- package/packages/server/dist/core/file-store.js +26 -3
- package/packages/server/dist/core/file-store.js.map +1 -1
- package/packages/server/dist/core/ide-skill-generator.d.ts +58 -0
- package/packages/server/dist/core/ide-skill-generator.d.ts.map +1 -0
- package/packages/server/dist/core/ide-skill-generator.js +270 -0
- package/packages/server/dist/core/ide-skill-generator.js.map +1 -0
- package/packages/server/dist/core/ide-skill-generator.test.d.ts +2 -0
- package/packages/server/dist/core/ide-skill-generator.test.d.ts.map +1 -0
- package/packages/server/dist/core/ide-skill-generator.test.js +257 -0
- package/packages/server/dist/core/ide-skill-generator.test.js.map +1 -0
- package/packages/server/dist/core/module-installer.d.ts +165 -0
- package/packages/server/dist/core/module-installer.d.ts.map +1 -0
- package/packages/server/dist/core/module-installer.js +445 -0
- package/packages/server/dist/core/module-installer.js.map +1 -0
- package/packages/server/dist/core/module-installer.test.d.ts +2 -0
- package/packages/server/dist/core/module-installer.test.d.ts.map +1 -0
- package/packages/server/dist/core/module-installer.test.js +509 -0
- package/packages/server/dist/core/module-installer.test.js.map +1 -0
- package/packages/server/dist/core/module-registry.d.ts +5 -0
- package/packages/server/dist/core/module-registry.d.ts.map +1 -0
- package/packages/server/dist/core/module-registry.js +109 -0
- package/packages/server/dist/core/module-registry.js.map +1 -0
- package/packages/server/dist/core/module-registry.test.d.ts +2 -0
- package/packages/server/dist/core/module-registry.test.d.ts.map +1 -0
- package/packages/server/dist/core/module-registry.test.js +280 -0
- package/packages/server/dist/core/module-registry.test.js.map +1 -0
- package/packages/server/dist/core/write-service.d.ts +20 -0
- package/packages/server/dist/core/write-service.d.ts.map +1 -1
- package/packages/server/dist/core/write-service.js +113 -1
- package/packages/server/dist/core/write-service.js.map +1 -1
- package/packages/server/dist/core/write-service.test.js +93 -6
- package/packages/server/dist/core/write-service.test.js.map +1 -1
- package/packages/server/dist/index.js +85 -1
- package/packages/server/dist/index.js.map +1 -1
- package/packages/server/dist/parsers/module-yaml-parser.d.ts +16 -0
- package/packages/server/dist/parsers/module-yaml-parser.d.ts.map +1 -0
- package/packages/server/dist/parsers/module-yaml-parser.js +62 -0
- package/packages/server/dist/parsers/module-yaml-parser.js.map +1 -0
- package/packages/server/dist/parsers/module-yaml-parser.test.d.ts +2 -0
- package/packages/server/dist/parsers/module-yaml-parser.test.d.ts.map +1 -0
- package/packages/server/dist/parsers/module-yaml-parser.test.js +156 -0
- package/packages/server/dist/parsers/module-yaml-parser.test.js.map +1 -0
- package/packages/server/dist/parsers/skill-parser.d.ts.map +1 -1
- package/packages/server/dist/parsers/skill-parser.js +41 -4
- package/packages/server/dist/parsers/skill-parser.js.map +1 -1
- package/packages/server/dist/parsers/skill-parser.test.js +4 -3
- package/packages/server/dist/parsers/skill-parser.test.js.map +1 -1
- package/packages/server/dist/plugins/agents-plugin.d.ts.map +1 -1
- package/packages/server/dist/plugins/agents-plugin.js +60 -1
- package/packages/server/dist/plugins/agents-plugin.js.map +1 -1
- package/packages/server/dist/plugins/commands-plugin.d.ts.map +1 -1
- package/packages/server/dist/plugins/commands-plugin.js +37 -10
- package/packages/server/dist/plugins/commands-plugin.js.map +1 -1
- package/packages/server/dist/plugins/datasources-plugin.d.ts.map +1 -1
- package/packages/server/dist/plugins/datasources-plugin.js +101 -0
- package/packages/server/dist/plugins/datasources-plugin.js.map +1 -1
- package/packages/server/dist/plugins/modules-plugin.d.ts.map +1 -1
- package/packages/server/dist/plugins/modules-plugin.js +905 -100
- package/packages/server/dist/plugins/modules-plugin.js.map +1 -1
- package/packages/server/dist/plugins/modules-plugin.test.js +1894 -3
- package/packages/server/dist/plugins/modules-plugin.test.js.map +1 -1
- package/packages/server/dist/plugins/outputs-plugin.d.ts.map +1 -1
- package/packages/server/dist/plugins/outputs-plugin.js +111 -0
- package/packages/server/dist/plugins/outputs-plugin.js.map +1 -1
- package/packages/server/dist/plugins/overview-plugin.d.ts.map +1 -1
- package/packages/server/dist/plugins/overview-plugin.js +35 -2
- package/packages/server/dist/plugins/overview-plugin.js.map +1 -1
- package/packages/server/dist/plugins/search-plugin.d.ts.map +1 -1
- package/packages/server/dist/plugins/search-plugin.js +19 -2
- package/packages/server/dist/plugins/search-plugin.js.map +1 -1
- package/packages/server/dist/plugins/settings-plugin.d.ts.map +1 -1
- package/packages/server/dist/plugins/settings-plugin.js +38 -1
- package/packages/server/dist/plugins/settings-plugin.js.map +1 -1
- package/packages/server/dist/plugins/settings-plugin.test.js +72 -0
- package/packages/server/dist/plugins/settings-plugin.test.js.map +1 -1
- package/packages/server/dist/plugins/teams-plugin.d.ts.map +1 -1
- package/packages/server/dist/plugins/teams-plugin.js +6 -6
- package/packages/server/dist/plugins/teams-plugin.js.map +1 -1
- package/packages/server/dist/plugins/teams-plugin.test.js +43 -0
- package/packages/server/dist/plugins/teams-plugin.test.js.map +1 -1
- package/packages/server/dist/plugins/workflows-plugin.d.ts.map +1 -1
- package/packages/server/dist/plugins/workflows-plugin.js +14 -6
- package/packages/server/dist/plugins/workflows-plugin.js.map +1 -1
- package/packages/shared/src/config.ts +26 -0
- package/packages/shared/src/events.ts +7 -0
- package/packages/shared/src/index.ts +13 -0
- package/packages/shared/src/modules.ts +42 -0
- package/packages/shared/src/registry.ts +26 -0
- package/packages/shared/src/types.test.ts +37 -1
- package/packages/shared/src/workflows.ts +27 -0
- package/packages/client/dist/assets/index-5nXyrx_3.css +0 -1
- package/packages/client/dist/assets/index-DxN3uabX.js +0 -521
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { extractZipUpload, parseGithubSource, readOutputFolder, runVariableSubstitution, validateVariables, } from './module-installer.js';
|
|
6
|
+
// Minimal FileStore stub for substitution tests — we don't care about the watcher
|
|
7
|
+
// feedback hooks during tests, just the studioDir.
|
|
8
|
+
function makeStubFileStore(studioDir) {
|
|
9
|
+
return {
|
|
10
|
+
studioDir,
|
|
11
|
+
markPendingWrite: () => { },
|
|
12
|
+
clearPendingWrite: () => { },
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
describe('parseGithubSource', () => {
|
|
17
|
+
// ─── shorthand owner/repo forms ─────────────────────────────────────────────
|
|
18
|
+
it('parses bare owner/repo', () => {
|
|
19
|
+
expect(parseGithubSource('owner/repo')).toEqual({
|
|
20
|
+
owner: 'owner',
|
|
21
|
+
repo: 'repo',
|
|
22
|
+
subpath: null,
|
|
23
|
+
branch: null,
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
it('parses owner/repo/subpath', () => {
|
|
27
|
+
expect(parseGithubSource('owner/repo/subpath')).toEqual({
|
|
28
|
+
owner: 'owner',
|
|
29
|
+
repo: 'repo',
|
|
30
|
+
subpath: 'subpath',
|
|
31
|
+
branch: null,
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
it('parses owner/repo with nested subpath', () => {
|
|
35
|
+
expect(parseGithubSource('owner/repo/nested/deep/subpath')).toEqual({
|
|
36
|
+
owner: 'owner',
|
|
37
|
+
repo: 'repo',
|
|
38
|
+
subpath: 'nested/deep/subpath',
|
|
39
|
+
branch: null,
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
it('parses owner/repo@branch', () => {
|
|
43
|
+
expect(parseGithubSource('owner/repo@dev')).toEqual({
|
|
44
|
+
owner: 'owner',
|
|
45
|
+
repo: 'repo',
|
|
46
|
+
subpath: null,
|
|
47
|
+
branch: 'dev',
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
it('parses owner/repo/subpath@branch', () => {
|
|
51
|
+
expect(parseGithubSource('owner/repo/subpath@dev')).toEqual({
|
|
52
|
+
owner: 'owner',
|
|
53
|
+
repo: 'repo',
|
|
54
|
+
subpath: 'subpath',
|
|
55
|
+
branch: 'dev',
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
it('parses owner/repo/nested/subpath@feature-branch', () => {
|
|
59
|
+
expect(parseGithubSource('owner/repo/nested/subpath@feature-branch')).toEqual({
|
|
60
|
+
owner: 'owner',
|
|
61
|
+
repo: 'repo',
|
|
62
|
+
subpath: 'nested/subpath',
|
|
63
|
+
branch: 'feature-branch',
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
// ─── full URL forms ─────────────────────────────────────────────────────────
|
|
67
|
+
it('parses https://github.com/owner/repo', () => {
|
|
68
|
+
expect(parseGithubSource('https://github.com/owner/repo')).toEqual({
|
|
69
|
+
owner: 'owner',
|
|
70
|
+
repo: 'repo',
|
|
71
|
+
subpath: null,
|
|
72
|
+
branch: null,
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
it('parses https://github.com/owner/repo/tree/branch', () => {
|
|
76
|
+
expect(parseGithubSource('https://github.com/owner/repo/tree/feature-branch')).toEqual({
|
|
77
|
+
owner: 'owner',
|
|
78
|
+
repo: 'repo',
|
|
79
|
+
subpath: null,
|
|
80
|
+
branch: 'feature-branch',
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
it('parses https://github.com/owner/repo/tree/main/modules/foo', () => {
|
|
84
|
+
expect(parseGithubSource('https://github.com/owner/repo/tree/main/modules/foo')).toEqual({
|
|
85
|
+
owner: 'owner',
|
|
86
|
+
repo: 'repo',
|
|
87
|
+
subpath: 'modules/foo',
|
|
88
|
+
branch: 'main',
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
it('parses http:// (not just https://) URLs', () => {
|
|
92
|
+
expect(parseGithubSource('http://github.com/owner/repo')).toEqual({
|
|
93
|
+
owner: 'owner',
|
|
94
|
+
repo: 'repo',
|
|
95
|
+
subpath: null,
|
|
96
|
+
branch: null,
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
it('parses URLs with trailing slash', () => {
|
|
100
|
+
expect(parseGithubSource('https://github.com/owner/repo/')).toEqual({
|
|
101
|
+
owner: 'owner',
|
|
102
|
+
repo: 'repo',
|
|
103
|
+
subpath: null,
|
|
104
|
+
branch: null,
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
// ─── invalid input ──────────────────────────────────────────────────────────
|
|
108
|
+
it('throws on a single segment with no slash', () => {
|
|
109
|
+
expect(() => parseGithubSource('just-one-segment')).toThrow(/Invalid GitHub source/);
|
|
110
|
+
});
|
|
111
|
+
it('throws on an empty string', () => {
|
|
112
|
+
expect(() => parseGithubSource('')).toThrow(/Invalid GitHub source/);
|
|
113
|
+
});
|
|
114
|
+
it('throws on whitespace only', () => {
|
|
115
|
+
expect(() => parseGithubSource(' ')).toThrow(/Invalid GitHub source/);
|
|
116
|
+
});
|
|
117
|
+
// ─── edge cases ─────────────────────────────────────────────────────────────
|
|
118
|
+
it('trims leading/trailing whitespace', () => {
|
|
119
|
+
expect(parseGithubSource(' owner/repo ')).toEqual({
|
|
120
|
+
owner: 'owner',
|
|
121
|
+
repo: 'repo',
|
|
122
|
+
subpath: null,
|
|
123
|
+
branch: null,
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
128
|
+
// extractZipUpload — Story 15.4
|
|
129
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
130
|
+
/**
|
|
131
|
+
* Build a zip in memory using adm-zip directly. Used for test fixtures.
|
|
132
|
+
*
|
|
133
|
+
* Note: this test imports adm-zip eagerly via top-level await, which is fine
|
|
134
|
+
* in test code — the TD-5 dynamic-import constraint applies only to the production
|
|
135
|
+
* `extractZipUpload` function, not its tests.
|
|
136
|
+
*/
|
|
137
|
+
async function buildZip(contents) {
|
|
138
|
+
const AdmZip = (await import('adm-zip')).default;
|
|
139
|
+
const zip = new AdmZip();
|
|
140
|
+
for (const { entryName, data } of contents) {
|
|
141
|
+
const buf = typeof data === 'string' ? Buffer.from(data) : data;
|
|
142
|
+
zip.addFile(entryName, buf);
|
|
143
|
+
}
|
|
144
|
+
return zip.toBuffer();
|
|
145
|
+
}
|
|
146
|
+
describe('extractZipUpload', () => {
|
|
147
|
+
let tmpDirsCreatedBefore;
|
|
148
|
+
beforeEach(() => {
|
|
149
|
+
// Snapshot the count of bmad-zip-* dirs in os.tmpdir() so each test can verify cleanup.
|
|
150
|
+
tmpDirsCreatedBefore = fs
|
|
151
|
+
.readdirSync(os.tmpdir())
|
|
152
|
+
.filter((n) => n.startsWith('bmad-zip-')).length;
|
|
153
|
+
});
|
|
154
|
+
afterEach(() => {
|
|
155
|
+
// Best-effort cleanup of any leaked test dirs (the production code should clean up,
|
|
156
|
+
// but if a test fails mid-flow we don't want pollution to bleed into the next test).
|
|
157
|
+
for (const name of fs.readdirSync(os.tmpdir())) {
|
|
158
|
+
if (name.startsWith('bmad-zip-')) {
|
|
159
|
+
try {
|
|
160
|
+
fs.rmSync(path.join(os.tmpdir(), name), { recursive: true, force: true });
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
/* ignore */
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
// ─── AC-15.4.3 (wrapper dir) ───
|
|
169
|
+
it('navigates into a single wrapper directory at the zip root', async () => {
|
|
170
|
+
const zipBytes = await buildZip([
|
|
171
|
+
{ entryName: 'my-module/agents/test.md', data: '---\nname: test\n---\n# Test\n' },
|
|
172
|
+
{ entryName: 'my-module/module.yaml', data: 'code: my-module\nversion: "1.0.0"\n' },
|
|
173
|
+
]);
|
|
174
|
+
const { extractedRoot, tmpDir } = await extractZipUpload(zipBytes);
|
|
175
|
+
try {
|
|
176
|
+
// The wrapper dir was navigated into — extractedRoot should end with my-module
|
|
177
|
+
expect(path.basename(extractedRoot)).toBe('my-module');
|
|
178
|
+
// The agent file should exist at the wrapper-relative path
|
|
179
|
+
expect(fs.existsSync(path.join(extractedRoot, 'agents', 'test.md'))).toBe(true);
|
|
180
|
+
}
|
|
181
|
+
finally {
|
|
182
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
// ─── AC-15.4.3 (no wrapper dir) ───
|
|
186
|
+
it('returns extractDir directly when there is no wrapper dir', async () => {
|
|
187
|
+
const zipBytes = await buildZip([
|
|
188
|
+
{ entryName: 'agents/test.md', data: '---\nname: test\n---\n# Test\n' },
|
|
189
|
+
{ entryName: 'module.yaml', data: 'code: flat-module\n' },
|
|
190
|
+
]);
|
|
191
|
+
const { extractedRoot, tmpDir } = await extractZipUpload(zipBytes);
|
|
192
|
+
try {
|
|
193
|
+
// No wrapper dir — extractedRoot should be the extract dir itself, not a child
|
|
194
|
+
expect(path.basename(extractedRoot)).toBe('extracted');
|
|
195
|
+
expect(fs.existsSync(path.join(extractedRoot, 'agents', 'test.md'))).toBe(true);
|
|
196
|
+
expect(fs.existsSync(path.join(extractedRoot, 'module.yaml'))).toBe(true);
|
|
197
|
+
}
|
|
198
|
+
finally {
|
|
199
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
// ─── AC-15.4.6 (success cleanup — caller responsible) ───
|
|
203
|
+
it('caller can clean up tmpDir after successful extraction', async () => {
|
|
204
|
+
const zipBytes = await buildZip([
|
|
205
|
+
{ entryName: 'agents/test.md', data: '# Test\n' },
|
|
206
|
+
{ entryName: 'module.yaml', data: 'code: cleanup-test\n' },
|
|
207
|
+
]);
|
|
208
|
+
const { tmpDir } = await extractZipUpload(zipBytes);
|
|
209
|
+
expect(fs.existsSync(tmpDir)).toBe(true);
|
|
210
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
211
|
+
expect(fs.existsSync(tmpDir)).toBe(false);
|
|
212
|
+
// After cleanup, the count of bmad-zip-* dirs should be back to baseline.
|
|
213
|
+
const after = fs.readdirSync(os.tmpdir()).filter((n) => n.startsWith('bmad-zip-')).length;
|
|
214
|
+
expect(after).toBeLessThanOrEqual(tmpDirsCreatedBefore);
|
|
215
|
+
});
|
|
216
|
+
// ─── AC-15.4.6 (failure cleanup — internal) ───
|
|
217
|
+
it('cleans up tmpDir on extraction failure (malformed zip)', async () => {
|
|
218
|
+
// A buffer that is definitely not a valid zip
|
|
219
|
+
const badZipBytes = Buffer.from('this is not a zip file at all');
|
|
220
|
+
let threw = false;
|
|
221
|
+
try {
|
|
222
|
+
await extractZipUpload(badZipBytes);
|
|
223
|
+
}
|
|
224
|
+
catch (err) {
|
|
225
|
+
threw = true;
|
|
226
|
+
expect(err).toBeInstanceOf(Error);
|
|
227
|
+
expect(err.message).toContain('Failed to extract zip');
|
|
228
|
+
}
|
|
229
|
+
expect(threw).toBe(true);
|
|
230
|
+
// The function should have cleaned up its own tmpDir on the throw path.
|
|
231
|
+
const after = fs.readdirSync(os.tmpdir()).filter((n) => n.startsWith('bmad-zip-')).length;
|
|
232
|
+
expect(after).toBeLessThanOrEqual(tmpDirsCreatedBefore);
|
|
233
|
+
});
|
|
234
|
+
// ─── AC-15.4.7 (zip-slip mitigation) ───
|
|
235
|
+
it('rejects zip entries that try to escape the extraction root', async () => {
|
|
236
|
+
// Build a malicious zip with an entry whose name traverses outside extractDir.
|
|
237
|
+
//
|
|
238
|
+
// Gotcha: adm-zip's `addFile('../escape.txt', ...)` SANITIZES the entry name and
|
|
239
|
+
// strips the leading `../`, so the obvious approach doesn't work. To inject a real
|
|
240
|
+
// traversal we add the file with a normal name, then mutate the entry's `entryName`
|
|
241
|
+
// property AFTER addFile but BEFORE toBuffer(). This bypasses adm-zip's input
|
|
242
|
+
// sanitization and writes the traversal verbatim into the zip's central directory.
|
|
243
|
+
const AdmZip = (await import('adm-zip')).default;
|
|
244
|
+
const evilZip = new AdmZip();
|
|
245
|
+
evilZip.addFile('escape.txt', Buffer.from('PWNED'));
|
|
246
|
+
evilZip.addFile('agents/test.md', Buffer.from('# Test\n'));
|
|
247
|
+
const escapeEntry = evilZip.getEntries().find((e) => e.entryName === 'escape.txt');
|
|
248
|
+
if (!escapeEntry)
|
|
249
|
+
throw new Error('test setup failed: could not find escape.txt entry');
|
|
250
|
+
escapeEntry.entryName = '../escape.txt';
|
|
251
|
+
const maliciousZipBytes = evilZip.toBuffer();
|
|
252
|
+
let threw = false;
|
|
253
|
+
let errMsg = '';
|
|
254
|
+
try {
|
|
255
|
+
await extractZipUpload(maliciousZipBytes);
|
|
256
|
+
}
|
|
257
|
+
catch (err) {
|
|
258
|
+
threw = true;
|
|
259
|
+
errMsg = err.message;
|
|
260
|
+
}
|
|
261
|
+
expect(threw).toBe(true);
|
|
262
|
+
expect(errMsg).toContain('attempts to write outside');
|
|
263
|
+
expect(errMsg).toContain('../escape.txt');
|
|
264
|
+
// Verify NO escape.txt file landed anywhere in os.tmpdir() — the validation
|
|
265
|
+
// happened BEFORE extractAllTo was called.
|
|
266
|
+
const tmpEntries = fs.readdirSync(os.tmpdir());
|
|
267
|
+
for (const name of tmpEntries) {
|
|
268
|
+
if (name === 'escape.txt') {
|
|
269
|
+
throw new Error('escape.txt landed in os.tmpdir() — zip-slip mitigation failed!');
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
// Also walk any leaked bmad-zip-* dirs to make sure escape.txt isn't inside them
|
|
273
|
+
for (const name of tmpEntries) {
|
|
274
|
+
if (name.startsWith('bmad-zip-')) {
|
|
275
|
+
const dir = path.join(os.tmpdir(), name);
|
|
276
|
+
// Recursive walk
|
|
277
|
+
const walk = (d) => {
|
|
278
|
+
for (const entry of fs.readdirSync(d, { withFileTypes: true })) {
|
|
279
|
+
if (entry.name === 'escape.txt') {
|
|
280
|
+
throw new Error(`escape.txt found inside ${d} — zip-slip mitigation failed!`);
|
|
281
|
+
}
|
|
282
|
+
if (entry.isDirectory())
|
|
283
|
+
walk(path.join(d, entry.name));
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
try {
|
|
287
|
+
walk(dir);
|
|
288
|
+
}
|
|
289
|
+
catch (e) {
|
|
290
|
+
if (e.message.includes('zip-slip'))
|
|
291
|
+
throw e;
|
|
292
|
+
/* ignore other walk errors */
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
// Also verify the tmp dir was cleaned up on the throw path
|
|
297
|
+
const after = fs.readdirSync(os.tmpdir()).filter((n) => n.startsWith('bmad-zip-')).length;
|
|
298
|
+
expect(after).toBeLessThanOrEqual(tmpDirsCreatedBefore);
|
|
299
|
+
});
|
|
300
|
+
// ─── AC-15.4.5 (dynamic import — source check) ───
|
|
301
|
+
it('AC-15.4.5: adm-zip is dynamically imported, not statically imported', () => {
|
|
302
|
+
// Read the production source and verify it does NOT have a top-level adm-zip import.
|
|
303
|
+
const sourcePath = path.resolve(process.cwd(), 'packages/server/src/core/module-installer.ts');
|
|
304
|
+
const source = fs.readFileSync(sourcePath, 'utf-8');
|
|
305
|
+
// No top-level static import of adm-zip
|
|
306
|
+
expect(source).not.toMatch(/^import .* from ['"]adm-zip['"]/m);
|
|
307
|
+
expect(source).not.toMatch(/^import\s+AdmZip\s+from/m);
|
|
308
|
+
// But it DOES use the dynamic form somewhere
|
|
309
|
+
expect(source).toMatch(/await import\(['"]adm-zip['"]\)/);
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
313
|
+
// validateVariables — Story 15.5
|
|
314
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
315
|
+
describe('validateVariables', () => {
|
|
316
|
+
it('accepts an empty record', () => {
|
|
317
|
+
expect(validateVariables({})).toEqual({ ok: true });
|
|
318
|
+
});
|
|
319
|
+
it('accepts alphanumeric values', () => {
|
|
320
|
+
expect(validateVariables({ name: 'AcmeProject', version: '123' })).toEqual({ ok: true });
|
|
321
|
+
});
|
|
322
|
+
it('accepts the AC-15.5.9 example: my-project_v1.0/aem', () => {
|
|
323
|
+
expect(validateVariables({ project: 'my-project_v1.0/aem' })).toEqual({ ok: true });
|
|
324
|
+
});
|
|
325
|
+
it('accepts values with paths and colons', () => {
|
|
326
|
+
expect(validateVariables({ url: 'localhost:4040/api' })).toEqual({ ok: true });
|
|
327
|
+
});
|
|
328
|
+
it('accepts an empty string value', () => {
|
|
329
|
+
expect(validateVariables({ optional: '' })).toEqual({ ok: true });
|
|
330
|
+
});
|
|
331
|
+
it('accepts whitespace and Unicode letters', () => {
|
|
332
|
+
expect(validateVariables({ name: 'Renée Müller' })).toEqual({ ok: true });
|
|
333
|
+
});
|
|
334
|
+
it('rejects values with YAML-breaking characters (#)', () => {
|
|
335
|
+
const result = validateVariables({ bad: '# injection' });
|
|
336
|
+
expect(result.ok).toBe(false);
|
|
337
|
+
if (result.ok)
|
|
338
|
+
return;
|
|
339
|
+
expect(result.error).toContain('"bad"');
|
|
340
|
+
expect(result.error).toContain('# injection');
|
|
341
|
+
});
|
|
342
|
+
it('rejects values with newlines', () => {
|
|
343
|
+
const result = validateVariables({ multiline: 'line1\nline2' });
|
|
344
|
+
expect(result.ok).toBe(false);
|
|
345
|
+
if (result.ok)
|
|
346
|
+
return;
|
|
347
|
+
expect(result.error).toContain('"multiline"');
|
|
348
|
+
});
|
|
349
|
+
it('rejects values with double quotes', () => {
|
|
350
|
+
const result = validateVariables({ quoted: 'has "quotes"' });
|
|
351
|
+
expect(result.ok).toBe(false);
|
|
352
|
+
});
|
|
353
|
+
it('rejects on the FIRST violation (does not enumerate all)', () => {
|
|
354
|
+
const result = validateVariables({ first: '# bad', second: '" bad' });
|
|
355
|
+
expect(result.ok).toBe(false);
|
|
356
|
+
if (result.ok)
|
|
357
|
+
return;
|
|
358
|
+
expect(result.error).toContain('"first"');
|
|
359
|
+
expect(result.error).not.toContain('"second"');
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
363
|
+
// readOutputFolder — Story 15.5
|
|
364
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
365
|
+
describe('readOutputFolder', () => {
|
|
366
|
+
let tmpDir;
|
|
367
|
+
beforeEach(() => {
|
|
368
|
+
tmpDir = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), 'read-output-folder-')));
|
|
369
|
+
});
|
|
370
|
+
afterEach(() => {
|
|
371
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
372
|
+
});
|
|
373
|
+
it('returns the default when no config.yaml exists', () => {
|
|
374
|
+
expect(readOutputFolder(tmpDir)).toBe(path.join(tmpDir, '_bmad-output'));
|
|
375
|
+
});
|
|
376
|
+
it('returns the substituted output_folder when config.yaml declares it', () => {
|
|
377
|
+
const configDir = path.join(tmpDir, '_bmad', '_config');
|
|
378
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
379
|
+
fs.writeFileSync(path.join(configDir, 'config.yaml'), 'output_folder: "{project-root}/custom-out"\n');
|
|
380
|
+
expect(readOutputFolder(tmpDir)).toBe(path.join(tmpDir, 'custom-out'));
|
|
381
|
+
});
|
|
382
|
+
it('returns the default when config.yaml exists but has no output_folder field', () => {
|
|
383
|
+
const configDir = path.join(tmpDir, '_bmad', '_config');
|
|
384
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
385
|
+
fs.writeFileSync(path.join(configDir, 'config.yaml'), 'project_name: foo\n');
|
|
386
|
+
expect(readOutputFolder(tmpDir)).toBe(path.join(tmpDir, '_bmad-output'));
|
|
387
|
+
});
|
|
388
|
+
it('returns the default when config.yaml is malformed', () => {
|
|
389
|
+
const configDir = path.join(tmpDir, '_bmad', '_config');
|
|
390
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
391
|
+
fs.writeFileSync(path.join(configDir, 'config.yaml'), 'output_folder: [unclosed\n');
|
|
392
|
+
expect(readOutputFolder(tmpDir)).toBe(path.join(tmpDir, '_bmad-output'));
|
|
393
|
+
});
|
|
394
|
+
});
|
|
395
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
396
|
+
// runVariableSubstitution — Story 15.5
|
|
397
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
398
|
+
describe('runVariableSubstitution', () => {
|
|
399
|
+
let tmpDir;
|
|
400
|
+
let studioDir;
|
|
401
|
+
let destDir;
|
|
402
|
+
let fileStore;
|
|
403
|
+
beforeEach(() => {
|
|
404
|
+
tmpDir = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), 'run-var-sub-')));
|
|
405
|
+
studioDir = path.join(tmpDir, '.bmad-studio');
|
|
406
|
+
fs.mkdirSync(studioDir, { recursive: true });
|
|
407
|
+
destDir = path.join(tmpDir, 'module-dest');
|
|
408
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
409
|
+
fileStore = makeStubFileStore(studioDir);
|
|
410
|
+
});
|
|
411
|
+
afterEach(() => {
|
|
412
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
413
|
+
});
|
|
414
|
+
function ctx(overrides = {}) {
|
|
415
|
+
return {
|
|
416
|
+
moduleCode: overrides.moduleCode ?? 'test-mod',
|
|
417
|
+
projectRoot: tmpDir,
|
|
418
|
+
outputFolder: path.join(tmpDir, '_bmad-output'),
|
|
419
|
+
variables: overrides.variables ?? {},
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
it('AC-15.5.1: substitutes {{var}} in a .md file', () => {
|
|
423
|
+
fs.mkdirSync(path.join(destDir, 'agents'), { recursive: true });
|
|
424
|
+
const file = path.join(destDir, 'agents', 'a.md');
|
|
425
|
+
fs.writeFileSync(file, 'Hello {{name}}\n');
|
|
426
|
+
const result = runVariableSubstitution(destDir, ctx({ variables: { name: 'World' } }), studioDir, fileStore);
|
|
427
|
+
expect(result.ok).toBe(true);
|
|
428
|
+
if (!result.ok)
|
|
429
|
+
return;
|
|
430
|
+
expect(result.filesPatched).toBe(1);
|
|
431
|
+
expect(fs.readFileSync(file, 'utf-8')).toBe('Hello World\n');
|
|
432
|
+
});
|
|
433
|
+
it('AC-15.5.2: substitutes {project-root} in a .yaml file', () => {
|
|
434
|
+
const file = path.join(destDir, 'config.yaml');
|
|
435
|
+
fs.writeFileSync(file, 'root: {project-root}\n');
|
|
436
|
+
const result = runVariableSubstitution(destDir, ctx(), studioDir, fileStore);
|
|
437
|
+
expect(result.ok).toBe(true);
|
|
438
|
+
expect(fs.readFileSync(file, 'utf-8')).toBe(`root: ${tmpDir}\n`);
|
|
439
|
+
});
|
|
440
|
+
it('AC-15.5.3: substitutes {module-code} in a .csv file', () => {
|
|
441
|
+
const file = path.join(destDir, 'manifest.csv');
|
|
442
|
+
fs.writeFileSync(file, 'name,code\nfoo,{module-code}\n');
|
|
443
|
+
const result = runVariableSubstitution(destDir, ctx({ moduleCode: 'dept-aem' }), studioDir, fileStore);
|
|
444
|
+
expect(result.ok).toBe(true);
|
|
445
|
+
expect(fs.readFileSync(file, 'utf-8')).toBe('name,code\nfoo,dept-aem\n');
|
|
446
|
+
});
|
|
447
|
+
it('substitutes {output_folder} in a .txt file', () => {
|
|
448
|
+
const file = path.join(destDir, 'notes.txt');
|
|
449
|
+
fs.writeFileSync(file, 'output goes to {output_folder}\n');
|
|
450
|
+
const result = runVariableSubstitution(destDir, ctx(), studioDir, fileStore);
|
|
451
|
+
expect(result.ok).toBe(true);
|
|
452
|
+
expect(fs.readFileSync(file, 'utf-8')).toBe(`output goes to ${path.join(tmpDir, '_bmad-output')}\n`);
|
|
453
|
+
});
|
|
454
|
+
it('AC-15.5.4: leaves a .png file untouched (extension not in allowlist)', () => {
|
|
455
|
+
const file = path.join(destDir, 'logo.png');
|
|
456
|
+
// PNG-ish bytes (not actually a valid png, but the function should not even read it)
|
|
457
|
+
const original = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
|
|
458
|
+
fs.writeFileSync(file, original);
|
|
459
|
+
const result = runVariableSubstitution(destDir, ctx(), studioDir, fileStore);
|
|
460
|
+
expect(result.ok).toBe(true);
|
|
461
|
+
if (!result.ok)
|
|
462
|
+
return;
|
|
463
|
+
expect(result.filesPatched).toBe(0);
|
|
464
|
+
const after = fs.readFileSync(file);
|
|
465
|
+
expect(Buffer.compare(after, original)).toBe(0);
|
|
466
|
+
});
|
|
467
|
+
it('AC-15.5.5: leaves a .md file with no placeholders untouched (filesPatched = 0)', () => {
|
|
468
|
+
const file = path.join(destDir, 'readme.md');
|
|
469
|
+
const original = '# Just a README\n\nNo placeholders here.\n';
|
|
470
|
+
fs.writeFileSync(file, original);
|
|
471
|
+
const mtimeBefore = fs.statSync(file).mtimeMs;
|
|
472
|
+
const result = runVariableSubstitution(destDir, ctx(), studioDir, fileStore);
|
|
473
|
+
expect(result.ok).toBe(true);
|
|
474
|
+
if (!result.ok)
|
|
475
|
+
return;
|
|
476
|
+
expect(result.filesPatched).toBe(0);
|
|
477
|
+
// The file should not have been re-written
|
|
478
|
+
const mtimeAfter = fs.statSync(file).mtimeMs;
|
|
479
|
+
expect(mtimeAfter).toBe(mtimeBefore);
|
|
480
|
+
});
|
|
481
|
+
it('walks nested directories recursively', () => {
|
|
482
|
+
fs.mkdirSync(path.join(destDir, 'agents'), { recursive: true });
|
|
483
|
+
fs.mkdirSync(path.join(destDir, 'workflows', 'create'), { recursive: true });
|
|
484
|
+
fs.writeFileSync(path.join(destDir, 'agents', 'a.md'), 'a={{x}}\n');
|
|
485
|
+
fs.writeFileSync(path.join(destDir, 'workflows', 'create', 'workflow.md'), 'b={{x}}\n');
|
|
486
|
+
fs.writeFileSync(path.join(destDir, 'noplace.md'), 'no placeholders\n');
|
|
487
|
+
const result = runVariableSubstitution(destDir, ctx({ variables: { x: 'OK' } }), studioDir, fileStore);
|
|
488
|
+
expect(result.ok).toBe(true);
|
|
489
|
+
if (!result.ok)
|
|
490
|
+
return;
|
|
491
|
+
expect(result.filesPatched).toBe(2);
|
|
492
|
+
expect(fs.readFileSync(path.join(destDir, 'agents', 'a.md'), 'utf-8')).toBe('a=OK\n');
|
|
493
|
+
expect(fs.readFileSync(path.join(destDir, 'workflows', 'create', 'workflow.md'), 'utf-8')).toBe('b=OK\n');
|
|
494
|
+
// The no-placeholder file is unchanged
|
|
495
|
+
expect(fs.readFileSync(path.join(destDir, 'noplace.md'), 'utf-8')).toBe('no placeholders\n');
|
|
496
|
+
});
|
|
497
|
+
it('returns the correct filesPatched count for mixed-result walks', () => {
|
|
498
|
+
fs.writeFileSync(path.join(destDir, 'a.md'), 'a={{x}}\n');
|
|
499
|
+
fs.writeFileSync(path.join(destDir, 'b.md'), 'b={{x}}\n');
|
|
500
|
+
fs.writeFileSync(path.join(destDir, 'c.md'), 'c=plain\n'); // no placeholder
|
|
501
|
+
fs.writeFileSync(path.join(destDir, 'd.png'), Buffer.from([0x89, 0x50])); // skipped extension
|
|
502
|
+
const result = runVariableSubstitution(destDir, ctx({ variables: { x: 'X' } }), studioDir, fileStore);
|
|
503
|
+
expect(result.ok).toBe(true);
|
|
504
|
+
if (!result.ok)
|
|
505
|
+
return;
|
|
506
|
+
expect(result.filesPatched).toBe(2);
|
|
507
|
+
});
|
|
508
|
+
});
|
|
509
|
+
//# sourceMappingURL=module-installer.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module-installer.test.js","sourceRoot":"","sources":["../../src/core/module-installer.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AACpE,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,IAAI,MAAM,WAAW,CAAA;AAG5B,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,uBAAuB,EACvB,iBAAiB,GAClB,MAAM,uBAAuB,CAAA;AAE9B,kFAAkF;AAClF,mDAAmD;AACnD,SAAS,iBAAiB,CAAC,SAAiB;IAC1C,OAAO;QACL,SAAS;QACT,gBAAgB,EAAE,GAAG,EAAE,GAAE,CAAC;QAC1B,iBAAiB,EAAE,GAAG,EAAE,GAAE,CAAC;QAC3B,8DAA8D;KAC3C,CAAA;AACvB,CAAC;AAED,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,+EAA+E;IAE/E,EAAE,CAAC,wBAAwB,EAAE,GAAG,EAAE;QAChC,MAAM,CAAC,iBAAiB,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC;YAC9C,KAAK,EAAE,OAAO;YACd,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,IAAI;YACb,MAAM,EAAE,IAAI;SACb,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACnC,MAAM,CAAC,iBAAiB,CAAC,oBAAoB,CAAC,CAAC,CAAC,OAAO,CAAC;YACtD,KAAK,EAAE,OAAO;YACd,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,SAAS;YAClB,MAAM,EAAE,IAAI;SACb,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,CAAC,iBAAiB,CAAC,gCAAgC,CAAC,CAAC,CAAC,OAAO,CAAC;YAClE,KAAK,EAAE,OAAO;YACd,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,qBAAqB;YAC9B,MAAM,EAAE,IAAI;SACb,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;QAClC,MAAM,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,CAAC,CAAC,OAAO,CAAC;YAClD,KAAK,EAAE,OAAO;YACd,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,IAAI;YACb,MAAM,EAAE,KAAK;SACd,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,MAAM,CAAC,iBAAiB,CAAC,wBAAwB,CAAC,CAAC,CAAC,OAAO,CAAC;YAC1D,KAAK,EAAE,OAAO;YACd,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,SAAS;YAClB,MAAM,EAAE,KAAK;SACd,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,MAAM,CAAC,iBAAiB,CAAC,0CAA0C,CAAC,CAAC,CAAC,OAAO,CAAC;YAC5E,KAAK,EAAE,OAAO;YACd,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,gBAAgB;YACzB,MAAM,EAAE,gBAAgB;SACzB,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,+EAA+E;IAE/E,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,CAAC,iBAAiB,CAAC,+BAA+B,CAAC,CAAC,CAAC,OAAO,CAAC;YACjE,KAAK,EAAE,OAAO;YACd,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,IAAI;YACb,MAAM,EAAE,IAAI;SACb,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,CAAC,iBAAiB,CAAC,mDAAmD,CAAC,CAAC,CAAC,OAAO,CAAC;YACrF,KAAK,EAAE,OAAO;YACd,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,IAAI;YACb,MAAM,EAAE,gBAAgB;SACzB,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,CAAC,iBAAiB,CAAC,qDAAqD,CAAC,CAAC,CAAC,OAAO,CAAC;YACvF,KAAK,EAAE,OAAO;YACd,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,aAAa;YACtB,MAAM,EAAE,MAAM;SACf,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,CAAC,iBAAiB,CAAC,8BAA8B,CAAC,CAAC,CAAC,OAAO,CAAC;YAChE,KAAK,EAAE,OAAO;YACd,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,IAAI;YACb,MAAM,EAAE,IAAI;SACb,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,MAAM,CAAC,iBAAiB,CAAC,gCAAgC,CAAC,CAAC,CAAC,OAAO,CAAC;YAClE,KAAK,EAAE,OAAO;YACd,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,IAAI;YACb,MAAM,EAAE,IAAI;SACb,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,+EAA+E;IAE/E,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,MAAM,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,kBAAkB,CAAC,CAAC,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAA;IACtF,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACnC,MAAM,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAA;IACtE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACnC,MAAM,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAA;IACzE,CAAC,CAAC,CAAA;IAEF,+EAA+E;IAE/E,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,MAAM,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,CAAC,CAAC,OAAO,CAAC;YAClD,KAAK,EAAE,OAAO;YACd,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,IAAI;YACb,MAAM,EAAE,IAAI;SACb,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,gFAAgF;AAChF,gCAAgC;AAChC,gFAAgF;AAEhF;;;;;;GAMG;AACH,KAAK,UAAU,QAAQ,CACrB,QAA6D;IAE7D,MAAM,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAA;IAChD,MAAM,GAAG,GAAG,IAAI,MAAM,EAAE,CAAA;IACxB,KAAK,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,QAAQ,EAAE,CAAC;QAC3C,MAAM,GAAG,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;QAC/D,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAA;IAC7B,CAAC;IACD,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAA;AACvB,CAAC;AAED,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,IAAI,oBAA4B,CAAA;IAEhC,UAAU,CAAC,GAAG,EAAE;QACd,wFAAwF;QACxF,oBAAoB,GAAG,EAAE;aACtB,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC;aACxB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAA;IACpD,CAAC,CAAC,CAAA;IAEF,SAAS,CAAC,GAAG,EAAE;QACb,oFAAoF;QACpF,qFAAqF;QACrF,KAAK,MAAM,IAAI,IAAI,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC;YAC/C,IAAI,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;gBACjC,IAAI,CAAC;oBACH,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;gBAC3E,CAAC;gBAAC,MAAM,CAAC;oBACP,YAAY;gBACd,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,kCAAkC;IAClC,EAAE,CAAC,2DAA2D,EAAE,KAAK,IAAI,EAAE;QACzE,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC;YAC9B,EAAE,SAAS,EAAE,0BAA0B,EAAE,IAAI,EAAE,gCAAgC,EAAE;YACjF,EAAE,SAAS,EAAE,uBAAuB,EAAE,IAAI,EAAE,qCAAqC,EAAE;SACpF,CAAC,CAAA;QAEF,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,MAAM,gBAAgB,CAAC,QAAQ,CAAC,CAAA;QAClE,IAAI,CAAC;YACH,+EAA+E;YAC/E,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;YACtD,2DAA2D;YAC3D,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACjF,CAAC;gBAAS,CAAC;YACT,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;QACrD,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,qCAAqC;IACrC,EAAE,CAAC,0DAA0D,EAAE,KAAK,IAAI,EAAE;QACxE,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC;YAC9B,EAAE,SAAS,EAAE,gBAAgB,EAAE,IAAI,EAAE,gCAAgC,EAAE;YACvE,EAAE,SAAS,EAAE,aAAa,EAAE,IAAI,EAAE,qBAAqB,EAAE;SAC1D,CAAC,CAAA;QAEF,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,MAAM,gBAAgB,CAAC,QAAQ,CAAC,CAAA;QAClE,IAAI,CAAC;YACH,+EAA+E;YAC/E,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;YACtD,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAC/E,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC3E,CAAC;gBAAS,CAAC;YACT,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;QACrD,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,2DAA2D;IAC3D,EAAE,CAAC,wDAAwD,EAAE,KAAK,IAAI,EAAE;QACtE,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC;YAC9B,EAAE,SAAS,EAAE,gBAAgB,EAAE,IAAI,EAAE,UAAU,EAAE;YACjD,EAAE,SAAS,EAAE,aAAa,EAAE,IAAI,EAAE,sBAAsB,EAAE;SAC3D,CAAC,CAAA;QAEF,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,gBAAgB,CAAC,QAAQ,CAAC,CAAA;QACnD,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACxC,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;QACnD,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAEzC,0EAA0E;QAC1E,MAAM,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAA;QACzF,MAAM,CAAC,KAAK,CAAC,CAAC,mBAAmB,CAAC,oBAAoB,CAAC,CAAA;IACzD,CAAC,CAAC,CAAA;IAEF,iDAAiD;IACjD,EAAE,CAAC,wDAAwD,EAAE,KAAK,IAAI,EAAE;QACtE,8CAA8C;QAC9C,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAA;QAEhE,IAAI,KAAK,GAAG,KAAK,CAAA;QACjB,IAAI,CAAC;YACH,MAAM,gBAAgB,CAAC,WAAW,CAAC,CAAA;QACrC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,KAAK,GAAG,IAAI,CAAA;YACZ,MAAM,CAAC,GAAG,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,CAAA;YACjC,MAAM,CAAE,GAAa,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,uBAAuB,CAAC,CAAA;QACnE,CAAC;QACD,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAExB,wEAAwE;QACxE,MAAM,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAA;QACzF,MAAM,CAAC,KAAK,CAAC,CAAC,mBAAmB,CAAC,oBAAoB,CAAC,CAAA;IACzD,CAAC,CAAC,CAAA;IAEF,0CAA0C;IAC1C,EAAE,CAAC,4DAA4D,EAAE,KAAK,IAAI,EAAE;QAC1E,+EAA+E;QAC/E,EAAE;QACF,iFAAiF;QACjF,mFAAmF;QACnF,oFAAoF;QACpF,8EAA8E;QAC9E,mFAAmF;QACnF,MAAM,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAA;QAChD,MAAM,OAAO,GAAG,IAAI,MAAM,EAAE,CAAA;QAC5B,OAAO,CAAC,OAAO,CAAC,YAAY,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAA;QACnD,OAAO,CAAC,OAAO,CAAC,gBAAgB,EAAE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAA;QAC1D,MAAM,WAAW,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,YAAY,CAAC,CAAA;QAClF,IAAI,CAAC,WAAW;YAAE,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAA;QACvF,WAAW,CAAC,SAAS,GAAG,eAAe,CAAA;QACvC,MAAM,iBAAiB,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAA;QAE5C,IAAI,KAAK,GAAG,KAAK,CAAA;QACjB,IAAI,MAAM,GAAG,EAAE,CAAA;QACf,IAAI,CAAC;YACH,MAAM,gBAAgB,CAAC,iBAAiB,CAAC,CAAA;QAC3C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,KAAK,GAAG,IAAI,CAAA;YACZ,MAAM,GAAI,GAAa,CAAC,OAAO,CAAA;QACjC,CAAC;QACD,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACxB,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,2BAA2B,CAAC,CAAA;QACrD,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAA;QAEzC,4EAA4E;QAC5E,2CAA2C;QAC3C,MAAM,UAAU,GAAG,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAA;QAC9C,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;YAC9B,IAAI,IAAI,KAAK,YAAY,EAAE,CAAC;gBAC1B,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAA;YACnF,CAAC;QACH,CAAC;QACD,iFAAiF;QACjF,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;YAC9B,IAAI,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;gBACjC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,CAAA;gBACxC,iBAAiB;gBACjB,MAAM,IAAI,GAAG,CAAC,CAAS,EAAE,EAAE;oBACzB,KAAK,MAAM,KAAK,IAAI,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;wBAC/D,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;4BAChC,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,gCAAgC,CAAC,CAAA;wBAC/E,CAAC;wBACD,IAAI,KAAK,CAAC,WAAW,EAAE;4BAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAA;oBACzD,CAAC;gBACH,CAAC,CAAA;gBACD,IAAI,CAAC;oBACH,IAAI,CAAC,GAAG,CAAC,CAAA;gBACX,CAAC;gBAAC,OAAO,CAAC,EAAE,CAAC;oBACX,IAAK,CAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;wBAAE,MAAM,CAAC,CAAA;oBACtD,8BAA8B;gBAChC,CAAC;YACH,CAAC;QACH,CAAC;QAED,2DAA2D;QAC3D,MAAM,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAA;QACzF,MAAM,CAAC,KAAK,CAAC,CAAC,mBAAmB,CAAC,oBAAoB,CAAC,CAAA;IACzD,CAAC,CAAC,CAAA;IAEF,oDAAoD;IACpD,EAAE,CAAC,qEAAqE,EAAE,GAAG,EAAE;QAC7E,qFAAqF;QACrF,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAC7B,OAAO,CAAC,GAAG,EAAE,EACb,8CAA8C,CAC/C,CAAA;QACD,MAAM,MAAM,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAA;QAEnD,wCAAwC;QACxC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,kCAAkC,CAAC,CAAA;QAC9D,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,0BAA0B,CAAC,CAAA;QAEtD,6CAA6C;QAC7C,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,iCAAiC,CAAC,CAAA;IAC3D,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,gFAAgF;AAChF,iCAAiC;AACjC,gFAAgF;AAEhF,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,yBAAyB,EAAE,GAAG,EAAE;QACjC,MAAM,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAA;IACrD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;QACrC,MAAM,CAAC,iBAAiB,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAA;IAC1F,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC5D,MAAM,CAAC,iBAAiB,CAAC,EAAE,OAAO,EAAE,qBAAqB,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAA;IACrF,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,CAAC,iBAAiB,CAAC,EAAE,GAAG,EAAE,oBAAoB,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAA;IAChF,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,CAAC,iBAAiB,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAA;IACnE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,MAAM,CAAC,iBAAiB,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAA;IAC3E,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,MAAM,GAAG,iBAAiB,CAAC,EAAE,GAAG,EAAE,aAAa,EAAE,CAAC,CAAA;QACxD,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAC7B,IAAI,MAAM,CAAC,EAAE;YAAE,OAAM;QACrB,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA;QACvC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAA;IAC/C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,MAAM,GAAG,iBAAiB,CAAC,EAAE,SAAS,EAAE,cAAc,EAAE,CAAC,CAAA;QAC/D,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAC7B,IAAI,MAAM,CAAC,EAAE;YAAE,OAAM;QACrB,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAA;IAC/C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,MAAM,MAAM,GAAG,iBAAiB,CAAC,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC,CAAA;QAC5D,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAC/B,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;QACjE,MAAM,MAAM,GAAG,iBAAiB,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAA;QACrE,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAC7B,IAAI,MAAM,CAAC,EAAE;YAAE,OAAM;QACrB,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAA;QACzC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,CAAA;IAChD,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,gFAAgF;AAChF,gCAAgC;AAChC,gFAAgF;AAEhF,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,IAAI,MAAc,CAAA;IAElB,UAAU,CAAC,GAAG,EAAE;QACd,MAAM,GAAG,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,qBAAqB,CAAC,CAAC,CAAC,CAAA;IACzF,CAAC,CAAC,CAAA;IAEF,SAAS,CAAC,GAAG,EAAE;QACb,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;IACrD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,MAAM,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAA;IAC1E,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,oEAAoE,EAAE,GAAG,EAAE;QAC5E,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,CAAC,CAAA;QACvD,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAC5C,EAAE,CAAC,aAAa,CACd,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,EACnC,8CAA8C,CAC/C,CAAA;QACD,MAAM,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAA;IACxE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,4EAA4E,EAAE,GAAG,EAAE;QACpF,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,CAAC,CAAA;QACvD,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAC5C,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,EAAE,qBAAqB,CAAC,CAAA;QAC5E,MAAM,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAA;IAC1E,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAC3D,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,CAAC,CAAA;QACvD,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAC5C,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,EAAE,4BAA4B,CAAC,CAAA;QACnF,MAAM,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAA;IAC1E,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,gFAAgF;AAChF,uCAAuC;AACvC,gFAAgF;AAEhF,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACvC,IAAI,MAAc,CAAA;IAClB,IAAI,SAAiB,CAAA;IACrB,IAAI,OAAe,CAAA;IACnB,IAAI,SAAoB,CAAA;IAExB,UAAU,CAAC,GAAG,EAAE;QACd,MAAM,GAAG,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,cAAc,CAAC,CAAC,CAAC,CAAA;QAChF,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC,CAAA;QAC7C,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAC5C,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA;QAC1C,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAC1C,SAAS,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAA;IAC1C,CAAC,CAAC,CAAA;IAEF,SAAS,CAAC,GAAG,EAAE;QACb,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;IACrD,CAAC,CAAC,CAAA;IAEF,SAAS,GAAG,CAAC,YAAgF,EAAE;QAC7F,OAAO;YACL,UAAU,EAAE,SAAS,CAAC,UAAU,IAAI,UAAU;YAC9C,WAAW,EAAE,MAAM;YACnB,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC;YAC/C,SAAS,EAAE,SAAS,CAAC,SAAS,IAAI,EAAE;SACrC,CAAA;IACH,CAAC;IAED,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAC/D,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAA;QACjD,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAA;QAE1C,MAAM,MAAM,GAAG,uBAAuB,CACpC,OAAO,EACP,GAAG,CAAC,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,EACrC,SAAS,EACT,SAAS,CACV,CAAA;QAED,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC5B,IAAI,CAAC,MAAM,CAAC,EAAE;YAAE,OAAM;QACtB,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACnC,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAA;IAC9D,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;QAC/D,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,CAAA;QAC9C,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,wBAAwB,CAAC,CAAA;QAEhD,MAAM,MAAM,GAAG,uBAAuB,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,CAAA;QAC5E,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC5B,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,MAAM,IAAI,CAAC,CAAA;IAClE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,CAAA;QAC/C,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,gCAAgC,CAAC,CAAA;QAExD,MAAM,MAAM,GAAG,uBAAuB,CACpC,OAAO,EACP,GAAG,CAAC,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC,EAC/B,SAAS,EACT,SAAS,CACV,CAAA;QACD,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC5B,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAA;IAC1E,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAA;QAC5C,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,kCAAkC,CAAC,CAAA;QAE1D,MAAM,MAAM,GAAG,uBAAuB,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,CAAA;QAC5E,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC5B,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CACzC,kBAAkB,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC,IAAI,CACxD,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,sEAAsE,EAAE,GAAG,EAAE;QAC9E,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,CAAA;QAC3C,qFAAqF;QACrF,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAA;QAC9E,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;QAEhC,MAAM,MAAM,GAAG,uBAAuB,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,CAAA;QAC5E,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC5B,IAAI,CAAC,MAAM,CAAC,EAAE;YAAE,OAAM;QACtB,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QAEnC,MAAM,KAAK,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAA;QACnC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,gFAAgF,EAAE,GAAG,EAAE;QACxF,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAA;QAC5C,MAAM,QAAQ,GAAG,4CAA4C,CAAA;QAC7D,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;QAChC,MAAM,WAAW,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,CAAA;QAE7C,MAAM,MAAM,GAAG,uBAAuB,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,CAAA;QAC5E,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC5B,IAAI,CAAC,MAAM,CAAC,EAAE;YAAE,OAAM;QACtB,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QAEnC,2CAA2C;QAC3C,MAAM,UAAU,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,CAAA;QAC5C,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;IACtC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAC/D,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAE5E,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,WAAW,CAAC,CAAA;QACnE,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,aAAa,CAAC,EAAE,WAAW,CAAC,CAAA;QACvF,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,EAAE,mBAAmB,CAAC,CAAA;QAEvE,MAAM,MAAM,GAAG,uBAAuB,CACpC,OAAO,EACP,GAAG,CAAC,EAAE,SAAS,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,EAC/B,SAAS,EACT,SAAS,CACV,CAAA;QACD,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC5B,IAAI,CAAC,MAAM,CAAC,EAAE;YAAE,OAAM;QACtB,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QAEnC,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QACrF,MAAM,CACJ,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,aAAa,CAAC,EAAE,OAAO,CAAC,CACnF,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QAChB,uCAAuC;QACvC,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAA;IAC9F,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,+DAA+D,EAAE,GAAG,EAAE;QACvE,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,WAAW,CAAC,CAAA;QACzD,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,WAAW,CAAC,CAAA;QACzD,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,WAAW,CAAC,CAAA,CAAC,iBAAiB;QAC3E,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAA,CAAC,oBAAoB;QAE7F,MAAM,MAAM,GAAG,uBAAuB,CACpC,OAAO,EACP,GAAG,CAAC,EAAE,SAAS,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,EAC9B,SAAS,EACT,SAAS,CACV,CAAA;QACD,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC5B,IAAI,CAAC,MAAM,CAAC,EAAE;YAAE,OAAM;QACtB,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACrC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { RegistryIndex } from '@bmad-studio/shared';
|
|
2
|
+
export declare function readCachedRegistryIndex(studioDir: string, owner: string, repo: string): RegistryIndex | null;
|
|
3
|
+
export declare function isRegistryCacheStale(index: RegistryIndex): boolean;
|
|
4
|
+
export declare function fetchAndCacheRegistryIndex(studioDir: string, repoString: string, branch: string): Promise<RegistryIndex>;
|
|
5
|
+
//# sourceMappingURL=module-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module-registry.d.ts","sourceRoot":"","sources":["../../src/core/module-registry.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,aAAa,EAAuB,MAAM,qBAAqB,CAAA;AAQ7E,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,GACX,aAAa,GAAG,IAAI,CAQtB;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAGlE;AAED,wBAAsB,0BAA0B,CAC9C,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,aAAa,CAAC,CA4FxB"}
|