@cristiancorreau/forge 2.11.0 → 2.12.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/CHANGELOG.md +10 -0
- package/assets/manifest.json +1 -1
- package/dist/cli.js +16 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/audit.d.ts +24 -0
- package/dist/commands/audit.d.ts.map +1 -1
- package/dist/commands/audit.js +29 -7
- package/dist/commands/audit.js.map +1 -1
- package/dist/commands/doctor.d.ts +23 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +79 -0
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/panel.d.ts +2 -0
- package/dist/commands/panel.d.ts.map +1 -0
- package/dist/commands/panel.js +297 -0
- package/dist/commands/panel.js.map +1 -0
- package/dist/lib/panel-data.d.ts +91 -0
- package/dist/lib/panel-data.d.ts.map +1 -0
- package/dist/lib/panel-data.js +243 -0
- package/dist/lib/panel-data.js.map +1 -0
- package/dist/tui/panel.d.ts +2 -0
- package/dist/tui/panel.d.ts.map +1 -0
- package/dist/tui/panel.js +398 -0
- package/dist/tui/panel.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import { join } from 'path';
|
|
2
|
+
import { spawnSync } from 'child_process';
|
|
3
|
+
import * as p from '@clack/prompts';
|
|
4
|
+
import { resolveForgeRoot } from '../lib/paths.js';
|
|
5
|
+
import { findProjectYaml } from '../lib/yaml.js';
|
|
6
|
+
import { runAudit } from './audit.js';
|
|
7
|
+
import { runDoctor } from './doctor.js';
|
|
8
|
+
import { searchSkills, listInstalledHooks, listTemplates, getConfigSummary, } from '../lib/panel-data.js';
|
|
9
|
+
import { bold, dim, green, cyan, gray, yellow, red, icons } from '../ui/colors.js';
|
|
10
|
+
import { box } from '../ui/box.js';
|
|
11
|
+
const HELP = `Usage: forge panel
|
|
12
|
+
|
|
13
|
+
Open the interactive forge panel: an navigable view of the project's
|
|
14
|
+
configuration, monitoring (audit + doctor), skill search, hooks and templates.
|
|
15
|
+
|
|
16
|
+
Runs full-screen under Bun (OpenTUI). On plain Node it falls back to a menu
|
|
17
|
+
that prints each section. With no project.yaml it still works (showing the
|
|
18
|
+
catalog), but it is most useful inside a configured project.
|
|
19
|
+
|
|
20
|
+
Options:
|
|
21
|
+
-h, --help Show this help
|
|
22
|
+
`;
|
|
23
|
+
// OpenTUI panels require Bun runtime.
|
|
24
|
+
const isBun = typeof globalThis.Bun !== 'undefined';
|
|
25
|
+
/** Locate a usable `bun` binary: PATH first, then standard install locations. */
|
|
26
|
+
function findBun() {
|
|
27
|
+
const candidates = [
|
|
28
|
+
'bun',
|
|
29
|
+
join(process.env.HOME ?? '', '.bun', 'bin', 'bun'),
|
|
30
|
+
'/opt/homebrew/bin/bun',
|
|
31
|
+
'/usr/local/bin/bun',
|
|
32
|
+
];
|
|
33
|
+
for (const bin of candidates) {
|
|
34
|
+
try {
|
|
35
|
+
const r = spawnSync(bin, ['--version'], { encoding: 'utf8', timeout: 2000 });
|
|
36
|
+
if (r.status === 0)
|
|
37
|
+
return bin;
|
|
38
|
+
}
|
|
39
|
+
catch { /* try next */ }
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* If running under Node with a TTY, re-launch the CLI under Bun (if available)
|
|
45
|
+
* so the OpenTUI panel can render. Returns false if it couldn't re-launch (the
|
|
46
|
+
* caller then uses the @clack fallback); exits the process if it did.
|
|
47
|
+
*/
|
|
48
|
+
function tryReLaunchWithBun() {
|
|
49
|
+
if (isBun)
|
|
50
|
+
return false;
|
|
51
|
+
if (process.env.FORGE_NO_BUN === '1')
|
|
52
|
+
return false;
|
|
53
|
+
if (process.env.FORGE_BUN_RELAUNCH === '1')
|
|
54
|
+
return false; // already relaunched
|
|
55
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY)
|
|
56
|
+
return false;
|
|
57
|
+
const bun = findBun();
|
|
58
|
+
if (!bun)
|
|
59
|
+
return false;
|
|
60
|
+
const cliPath = new URL('../cli.js', import.meta.url).pathname;
|
|
61
|
+
const result = spawnSync(bun, [cliPath, 'panel'], {
|
|
62
|
+
stdio: 'inherit',
|
|
63
|
+
env: { ...process.env, FORGE_BUN_RELAUNCH: '1' },
|
|
64
|
+
});
|
|
65
|
+
process.exit(result.status ?? 0);
|
|
66
|
+
}
|
|
67
|
+
function forgeRootOrNull() {
|
|
68
|
+
try {
|
|
69
|
+
return resolveForgeRoot();
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// ─── Node fallback (@clack/prompts) ───────────────────────────────────────────
|
|
76
|
+
function printConfigSection(root) {
|
|
77
|
+
const c = getConfigSummary(root);
|
|
78
|
+
if (!c.found) {
|
|
79
|
+
console.log(dim(' No se encontró project.yaml en este directorio.'));
|
|
80
|
+
console.log(dim(' Ejecutá ') + cyan('forge init') + dim(' para configurar el proyecto.'));
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const lines = [];
|
|
84
|
+
lines.push(`${bold('Proyecto')} ${c.name}`);
|
|
85
|
+
lines.push(`${bold('Mode')} ${c.mode} ${bold('Lenguaje')} ${c.language}`);
|
|
86
|
+
if (c.stack.length) {
|
|
87
|
+
lines.push('');
|
|
88
|
+
lines.push(bold('Stack'));
|
|
89
|
+
for (const { key, value } of c.stack)
|
|
90
|
+
lines.push(` ${gray(key.padEnd(16))} ${value}`);
|
|
91
|
+
}
|
|
92
|
+
lines.push('');
|
|
93
|
+
lines.push(bold('Agentes'));
|
|
94
|
+
lines.push(` ${gray('active'.padEnd(16))} ${c.agentsActive.join(', ') || dim('—')}`);
|
|
95
|
+
if (c.agentsSpecialized.length)
|
|
96
|
+
lines.push(` ${gray('specialized'.padEnd(16))} ${c.agentsSpecialized.join(', ')}`);
|
|
97
|
+
if (c.agentsCompliance.length)
|
|
98
|
+
lines.push(` ${gray('compliance'.padEnd(16))} ${c.agentsCompliance.join(', ')}`);
|
|
99
|
+
if (c.profiles.length)
|
|
100
|
+
lines.push(` ${gray('profiles'.padEnd(16))} ${c.profiles.join(', ')}`);
|
|
101
|
+
lines.push('');
|
|
102
|
+
lines.push(`${bold('Skills')} ${c.skills.join(', ') || dim('ninguna')}`);
|
|
103
|
+
lines.push(`${bold('Runtimes')} ${c.runtimes.join(', ') || dim('ninguno')}`);
|
|
104
|
+
if (c.compliance.length)
|
|
105
|
+
lines.push(`${bold('Compliance')} ${c.compliance.join(', ')}`);
|
|
106
|
+
if (c.deploy)
|
|
107
|
+
lines.push(`${bold('Deploy')} ${c.deploy.provider ?? '—'}${c.deploy.url ? ' ' + c.deploy.url : ''}`);
|
|
108
|
+
console.log(box('Configuración', lines));
|
|
109
|
+
console.log(dim(` Fuente: ${c.yamlPath}`));
|
|
110
|
+
}
|
|
111
|
+
function printMonitorSection(root) {
|
|
112
|
+
const a = runAudit(root);
|
|
113
|
+
const d = runDoctor(root);
|
|
114
|
+
const lines = [];
|
|
115
|
+
lines.push(`Audit: ${green(a.summary.ok + ' OK')} · ${cyan(a.summary.info + ' info')} · ` +
|
|
116
|
+
`${yellow(a.summary.warnings + ' warn')} · ${red(a.summary.errors + ' ✗')}`);
|
|
117
|
+
lines.push(`Hooks instalados: ${a.hooksInstalled}`);
|
|
118
|
+
lines.push(`Manifest: ${a.manifestStatus}`);
|
|
119
|
+
lines.push('');
|
|
120
|
+
lines.push(`Node ${d.nodeVersion} · forge root ${d.forgeRootOk ? green('ok') : red('no')} · assets ${d.assetsOk ? green('ok') : red('faltan')}`);
|
|
121
|
+
lines.push(`Runtimes detectados: ${d.runtimesDetected.join(', ') || dim('ninguno')}`);
|
|
122
|
+
lines.push('');
|
|
123
|
+
lines.push(bold('Runtimes'));
|
|
124
|
+
for (const rt of d.runtimes) {
|
|
125
|
+
const mark = rt.installed ? icons.ok : gray('○');
|
|
126
|
+
const tag = rt.active ? cyan(' ● active') : '';
|
|
127
|
+
const ver = rt.installed && rt.version ? dim(' ' + rt.version) : (rt.installed ? '' : dim(' — ausente'));
|
|
128
|
+
lines.push(` ${mark} ${rt.label.padEnd(14)}${ver}${tag}`);
|
|
129
|
+
}
|
|
130
|
+
console.log(box(d.ok && a.summary.errors === 0 ? 'Monitoreo — todo en orden' : 'Monitoreo', lines));
|
|
131
|
+
}
|
|
132
|
+
function printSkillRows(rows) {
|
|
133
|
+
if (rows.length === 0) {
|
|
134
|
+
console.log(dim(' Sin resultados.'));
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const width = Math.max(...rows.map(r => r.command.length));
|
|
138
|
+
for (const r of rows) {
|
|
139
|
+
const mark = r.active ? icons.ok : gray('·');
|
|
140
|
+
console.log(` ${mark} ${cyan(r.command.padEnd(width))} ${gray('[' + r.category + ']')} ${r.purpose}`);
|
|
141
|
+
console.log(` ${' '.repeat(width)} ${dim('trigger: ' + r.trigger)}`);
|
|
142
|
+
}
|
|
143
|
+
const active = rows.filter(r => r.active).length;
|
|
144
|
+
console.log('\n' + dim(` ${rows.length} skill(s) · ${active} activa(s) en project.yaml`));
|
|
145
|
+
}
|
|
146
|
+
async function skillsSearchSection(root) {
|
|
147
|
+
const q = await p.text({
|
|
148
|
+
message: 'Buscar skills (nombre, categoría, comando, trigger) — Enter para ver todas',
|
|
149
|
+
placeholder: 'wiki, deploy, security…',
|
|
150
|
+
});
|
|
151
|
+
if (p.isCancel(q))
|
|
152
|
+
return;
|
|
153
|
+
printSkillRows(searchSkills(String(q ?? ''), root));
|
|
154
|
+
}
|
|
155
|
+
function printHooksSection(root) {
|
|
156
|
+
const hooks = listInstalledHooks(root, forgeRootOrNull());
|
|
157
|
+
if (hooks.length === 0) {
|
|
158
|
+
console.log(dim(' No hay hooks en el registry ni en .claude/hooks/.'));
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
const truncate = (s, n = 90) => (s.length > n ? s.slice(0, n - 1) + '…' : s);
|
|
162
|
+
const lines = [];
|
|
163
|
+
for (const h of hooks) {
|
|
164
|
+
const mark = h.installed ? icons.ok : gray('○');
|
|
165
|
+
const matcher = h.matcher ? ` ${dim('matcher=' + h.matcher)}` : '';
|
|
166
|
+
lines.push(`${mark} ${bold(h.hook.padEnd(22))} ${cyan(h.event)}${matcher} ${gray('[' + h.mode + ']')}`);
|
|
167
|
+
if (h.description)
|
|
168
|
+
lines.push(` ${dim(truncate(h.description))}`);
|
|
169
|
+
}
|
|
170
|
+
console.log(box('Hooks', lines));
|
|
171
|
+
console.log(dim(' ✓ instalado en .claude/hooks/ ○ declarado en el registry pero no instalado'));
|
|
172
|
+
}
|
|
173
|
+
function printTemplatesSection() {
|
|
174
|
+
const templates = listTemplates(forgeRootOrNull());
|
|
175
|
+
if (templates.length === 0) {
|
|
176
|
+
console.log(dim(' No se encontraron templates (forge root ausente).'));
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
const lines = [];
|
|
180
|
+
let lastCat = '';
|
|
181
|
+
for (const t of templates) {
|
|
182
|
+
if (t.category !== lastCat) {
|
|
183
|
+
lines.push(bold(t.category));
|
|
184
|
+
lastCat = t.category;
|
|
185
|
+
}
|
|
186
|
+
lines.push(` ${cyan(t.name.padEnd(26))} ${dim(t.description)}`);
|
|
187
|
+
}
|
|
188
|
+
console.log(box('Templates', lines));
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Non-interactive snapshot: print every section once. Used when there is no TTY
|
|
192
|
+
* (piped/CI) so the panel never crashes and still surfaces useful information.
|
|
193
|
+
*/
|
|
194
|
+
function printStaticSnapshot(root) {
|
|
195
|
+
console.log(cyan(bold('forge panel')) + dim(' — snapshot (sin TTY interactiva)') + '\n');
|
|
196
|
+
printConfigSection(root);
|
|
197
|
+
console.log('');
|
|
198
|
+
printMonitorSection(root);
|
|
199
|
+
console.log('');
|
|
200
|
+
printSkillRows(searchSkills('', root));
|
|
201
|
+
console.log('');
|
|
202
|
+
printHooksSection(root);
|
|
203
|
+
console.log('');
|
|
204
|
+
printTemplatesSection();
|
|
205
|
+
return 0;
|
|
206
|
+
}
|
|
207
|
+
async function runClackFallback(root) {
|
|
208
|
+
// No interactive TTY → print a one-shot snapshot instead of prompting (which
|
|
209
|
+
// would throw ERR_TTY_INIT_FAILED on a /dev/null or piped stdin).
|
|
210
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
211
|
+
return printStaticSnapshot(root);
|
|
212
|
+
}
|
|
213
|
+
p.intro(' forge panel ');
|
|
214
|
+
if (!findProjectYaml(root)) {
|
|
215
|
+
p.note('No hay project.yaml en este directorio. El panel muestra el catálogo\nglobal; ejecutá `forge init` para configurar el proyecto.', 'Aviso');
|
|
216
|
+
}
|
|
217
|
+
// Loop until the user picks Salir.
|
|
218
|
+
for (;;) {
|
|
219
|
+
const choice = await p.select({
|
|
220
|
+
message: '¿Qué querés ver?',
|
|
221
|
+
options: [
|
|
222
|
+
{ value: 'config', label: 'Configuración', hint: 'resumen de project.yaml' },
|
|
223
|
+
{ value: 'monitor', label: 'Monitoreo', hint: 'audit + doctor' },
|
|
224
|
+
{ value: 'skills', label: 'Skills', hint: 'buscar en el catálogo' },
|
|
225
|
+
{ value: 'hooks', label: 'Hooks', hint: 'instalados + registry' },
|
|
226
|
+
{ value: 'templates', label: 'Templates', hint: 'wiki / spec / modes' },
|
|
227
|
+
{ value: 'editor', label: 'Abrir project.yaml en $EDITOR' },
|
|
228
|
+
{ value: 'exit', label: 'Salir' },
|
|
229
|
+
],
|
|
230
|
+
});
|
|
231
|
+
if (p.isCancel(choice) || choice === 'exit')
|
|
232
|
+
break;
|
|
233
|
+
console.log('');
|
|
234
|
+
switch (choice) {
|
|
235
|
+
case 'config':
|
|
236
|
+
printConfigSection(root);
|
|
237
|
+
break;
|
|
238
|
+
case 'monitor':
|
|
239
|
+
printMonitorSection(root);
|
|
240
|
+
break;
|
|
241
|
+
case 'skills':
|
|
242
|
+
await skillsSearchSection(root);
|
|
243
|
+
break;
|
|
244
|
+
case 'hooks':
|
|
245
|
+
printHooksSection(root);
|
|
246
|
+
break;
|
|
247
|
+
case 'templates':
|
|
248
|
+
printTemplatesSection();
|
|
249
|
+
break;
|
|
250
|
+
case 'editor':
|
|
251
|
+
openEditor(root);
|
|
252
|
+
break;
|
|
253
|
+
}
|
|
254
|
+
console.log('');
|
|
255
|
+
}
|
|
256
|
+
p.outro('Listo.');
|
|
257
|
+
return 0;
|
|
258
|
+
}
|
|
259
|
+
function openEditor(root) {
|
|
260
|
+
const yamlPath = findProjectYaml(root);
|
|
261
|
+
if (!yamlPath) {
|
|
262
|
+
console.log(dim(' No hay project.yaml para abrir.'));
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
const editor = process.env.EDITOR || process.env.VISUAL;
|
|
266
|
+
if (!editor) {
|
|
267
|
+
console.log(dim(' $EDITOR no definido. Ruta: ') + yamlPath);
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
spawnSync(editor, [yamlPath], { stdio: 'inherit' });
|
|
271
|
+
}
|
|
272
|
+
// ─── Entry point ──────────────────────────────────────────────────────────────
|
|
273
|
+
export async function panel(args) {
|
|
274
|
+
if (args.includes('-h') || args.includes('--help')) {
|
|
275
|
+
process.stdout.write(HELP);
|
|
276
|
+
return 0;
|
|
277
|
+
}
|
|
278
|
+
const root = process.cwd();
|
|
279
|
+
// Full-screen OpenTUI under Bun.
|
|
280
|
+
if (isBun && process.stdout.isTTY) {
|
|
281
|
+
try {
|
|
282
|
+
const { runPanel } = await import('../tui/panel.js');
|
|
283
|
+
await runPanel(root);
|
|
284
|
+
return 0;
|
|
285
|
+
}
|
|
286
|
+
catch {
|
|
287
|
+
// fall through to the clack fallback
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
// On Node with Bun installed + a TTY, re-launch under Bun for OpenTUI.
|
|
291
|
+
if (!isBun && process.stdout.isTTY) {
|
|
292
|
+
tryReLaunchWithBun(); // exits the process on success
|
|
293
|
+
}
|
|
294
|
+
// Node fallback (no Bun, or not a TTY): @clack menu.
|
|
295
|
+
return runClackFallback(root);
|
|
296
|
+
}
|
|
297
|
+
//# sourceMappingURL=panel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"panel.js","sourceRoot":"","sources":["../../src/commands/panel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC;AACpC,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EACL,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,gBAAgB,GAElE,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACnF,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAEnC,MAAM,IAAI,GAAG;;;;;;;;;;;CAWZ,CAAC;AAEF,sCAAsC;AACtC,MAAM,KAAK,GAAG,OAAQ,UAAkB,CAAC,GAAG,KAAK,WAAW,CAAC;AAE7D,iFAAiF;AACjF,SAAS,OAAO;IACd,MAAM,UAAU,GAAG;QACjB,KAAK;QACL,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC;QAClD,uBAAuB;QACvB,oBAAoB;KACrB,CAAC;IACF,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,SAAS,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;YAC7E,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,GAAG,CAAC;QACjC,CAAC;QAAC,MAAM,CAAC,CAAC,cAAc,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,SAAS,kBAAkB;IACzB,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC;IACxB,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,KAAK,GAAG;QAAE,OAAO,KAAK,CAAC;IACnD,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB,KAAK,GAAG;QAAE,OAAO,KAAK,CAAC,CAAC,qBAAqB;IAC/E,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IAChE,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;IACtB,IAAI,CAAC,GAAG;QAAE,OAAO,KAAK,CAAC;IACvB,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;IAC/D,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE;QAChD,KAAK,EAAE,SAAS;QAChB,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,kBAAkB,EAAE,GAAG,EAAE;KACjD,CAAC,CAAC;IACH,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;AACnC,CAAC;AAED,SAAS,eAAe;IACtB,IAAI,CAAC;QAAC,OAAO,gBAAgB,EAAE,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,IAAI,CAAC;IAAC,CAAC;AAC3D,CAAC;AAED,iFAAiF;AAEjF,SAAS,kBAAkB,CAAC,IAAY;IACtC,MAAM,CAAC,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACjC,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;QACb,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,mDAAmD,CAAC,CAAC,CAAC;QACtE,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,GAAG,CAAC,+BAA+B,CAAC,CAAC,CAAC;QAC3F,OAAO;IACT,CAAC;IACD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC9C,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;IACnF,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QACnB,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;QAC1B,KAAK,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,KAAK;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC;IACzF,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;IAC5B,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACtF,IAAI,CAAC,CAAC,iBAAiB,CAAC,MAAM;QAAE,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACpH,IAAI,CAAC,CAAC,gBAAgB,CAAC,MAAM;QAAE,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjH,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM;QAAE,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/F,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IAC7E,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IAC/E,IAAI,CAAC,CAAC,UAAU,CAAC,MAAM;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACxF,IAAI,CAAC,CAAC,MAAM;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,IAAI,GAAG,GAAG,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACxH,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC,CAAC;IACzC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;AAC9C,CAAC;AAED,SAAS,mBAAmB,CAAC,IAAY;IACvC,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IACzB,MAAM,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC1B,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CACR,UAAU,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,GAAG,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,KAAK;QAC9E,GAAG,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAC5E,CAAC;IACF,KAAK,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,cAAc,EAAE,CAAC,CAAC;IACpD,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,cAAc,EAAE,CAAC,CAAC;IAC5C,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,WAAW,iBAAiB,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACjJ,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IACtF,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;IAC7B,KAAK,MAAM,EAAE,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjD,MAAM,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/C,MAAM,GAAG,GAAG,EAAE,CAAC,SAAS,IAAI,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC;QACzG,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,GAAG,GAAG,GAAG,EAAE,CAAC,CAAC;IAC7D,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,2BAA2B,CAAC,CAAC,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC;AACtG,CAAC;AAED,SAAS,cAAc,CAAC,IAAgB;IACtC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,CAAC;QAAC,OAAO;IAAC,CAAC;IACzE,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IAC3D,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC7C,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,QAAQ,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;QACxG,OAAO,CAAC,GAAG,CAAC,OAAO,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,WAAW,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC3E,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC;IACjD,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,KAAK,IAAI,CAAC,MAAM,eAAe,MAAM,4BAA4B,CAAC,CAAC,CAAC;AAC7F,CAAC;AAED,KAAK,UAAU,mBAAmB,CAAC,IAAY;IAC7C,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC;QACrB,OAAO,EAAE,4EAA4E;QACrF,WAAW,EAAE,yBAAyB;KACvC,CAAC,CAAC;IACH,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;QAAE,OAAO;IAC1B,cAAc,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AACtD,CAAC;AAED,SAAS,iBAAiB,CAAC,IAAY;IACrC,MAAM,KAAK,GAAG,kBAAkB,CAAC,IAAI,EAAE,eAAe,EAAE,CAAC,CAAC;IAC1D,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAC,CAAC;QAAC,OAAO;IAAC,CAAC;IAC5G,MAAM,QAAQ,GAAG,CAAC,CAAS,EAAE,CAAC,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACrF,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,MAAM,IAAI,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAChD,MAAM,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,UAAU,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACnE,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,OAAO,IAAI,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC,CAAC;QACxG,IAAI,CAAC,CAAC,WAAW;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC;IACrE,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;IACjC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,gFAAgF,CAAC,CAAC,CAAC;AACrG,CAAC;AAED,SAAS,qBAAqB;IAC5B,MAAM,SAAS,GAAG,aAAa,CAAC,eAAe,EAAE,CAAC,CAAC;IACnD,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAC,CAAC;QAAC,OAAO;IAAC,CAAC;IAChH,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,OAAO,GAAG,EAAE,CAAC;IACjB,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;QAC1B,IAAI,CAAC,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;YAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;YAAC,OAAO,GAAG,CAAC,CAAC,QAAQ,CAAC;QAAC,CAAC;QACnF,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;IACnE,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC;AACvC,CAAC;AAED;;;GAGG;AACH,SAAS,mBAAmB,CAAC,IAAY;IACvC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,GAAG,GAAG,CAAC,mCAAmC,CAAC,GAAG,IAAI,CAAC,CAAC;IACzF,kBAAkB,CAAC,IAAI,CAAC,CAAC;IACzB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,mBAAmB,CAAC,IAAI,CAAC,CAAC;IAC1B,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,cAAc,CAAC,YAAY,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC;IACvC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,iBAAiB,CAAC,IAAI,CAAC,CAAC;IACxB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,qBAAqB,EAAE,CAAC;IACxB,OAAO,CAAC,CAAC;AACX,CAAC;AAED,KAAK,UAAU,gBAAgB,CAAC,IAAY;IAC1C,6EAA6E;IAC7E,kEAAkE;IAClE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAClD,OAAO,mBAAmB,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;IAED,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;IACzB,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3B,CAAC,CAAC,IAAI,CAAC,iIAAiI,EAAE,OAAO,CAAC,CAAC;IACrJ,CAAC;IAED,mCAAmC;IACnC,SAAS,CAAC;QACR,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,MAAM,CAAC;YAC5B,OAAO,EAAE,kBAAkB;YAC3B,OAAO,EAAE;gBACP,EAAE,KAAK,EAAE,QAAQ,EAAK,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,yBAAyB,EAAE;gBAC/E,EAAE,KAAK,EAAE,SAAS,EAAI,KAAK,EAAE,WAAW,EAAM,IAAI,EAAE,gBAAgB,EAAE;gBACtE,EAAE,KAAK,EAAE,QAAQ,EAAK,KAAK,EAAE,QAAQ,EAAS,IAAI,EAAE,uBAAuB,EAAE;gBAC7E,EAAE,KAAK,EAAE,OAAO,EAAM,KAAK,EAAE,OAAO,EAAU,IAAI,EAAE,uBAAuB,EAAE;gBAC7E,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAM,IAAI,EAAE,qBAAqB,EAAE;gBAC3E,EAAE,KAAK,EAAE,QAAQ,EAAK,KAAK,EAAE,+BAA+B,EAAE;gBAC9D,EAAE,KAAK,EAAE,MAAM,EAAO,KAAK,EAAE,OAAO,EAAE;aACvC;SACF,CAAC,CAAC;QACH,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,KAAK,MAAM;YAAE,MAAM;QAEnD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,QAAQ,MAAM,EAAE,CAAC;YACf,KAAK,QAAQ;gBAAK,kBAAkB,CAAC,IAAI,CAAC,CAAC;gBAAC,MAAM;YAClD,KAAK,SAAS;gBAAI,mBAAmB,CAAC,IAAI,CAAC,CAAC;gBAAC,MAAM;YACnD,KAAK,QAAQ;gBAAK,MAAM,mBAAmB,CAAC,IAAI,CAAC,CAAC;gBAAC,MAAM;YACzD,KAAK,OAAO;gBAAM,iBAAiB,CAAC,IAAI,CAAC,CAAC;gBAAC,MAAM;YACjD,KAAK,WAAW;gBAAE,qBAAqB,EAAE,CAAC;gBAAC,MAAM;YACjD,KAAK,QAAQ;gBAAK,UAAU,CAAC,IAAI,CAAC,CAAC;gBAAC,MAAM;QAC5C,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAClB,CAAC;IAED,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAClB,OAAO,CAAC,CAAC;AACX,CAAC;AAED,SAAS,UAAU,CAAC,IAAY;IAC9B,MAAM,QAAQ,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,CAAC,QAAQ,EAAE,CAAC;QAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC,CAAC;QAAC,OAAO;IAAC,CAAC;IACjF,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;IACxD,IAAI,CAAC,MAAM,EAAE,CAAC;QAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,+BAA+B,CAAC,GAAG,QAAQ,CAAC,CAAC;QAAC,OAAO;IAAC,CAAC;IACtF,SAAS,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;AACtD,CAAC;AAED,iFAAiF;AAEjF,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,IAAc;IACxC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACnD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC3B,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAE3B,iCAAiC;IACjC,IAAI,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAClC,IAAI,CAAC;YACH,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,iBAAiB,CAAC,CAAC;YACrD,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC;YACrB,OAAO,CAAC,CAAC;QACX,CAAC;QAAC,MAAM,CAAC;YACP,qCAAqC;QACvC,CAAC;IACH,CAAC;IAED,uEAAuE;IACvE,IAAI,CAAC,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QACnC,kBAAkB,EAAE,CAAC,CAAC,+BAA+B;IACvD,CAAC;IAED,qDAAqD;IACrD,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC;AAChC,CAAC"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { type SkillInfo } from './catalog.js';
|
|
2
|
+
export interface SkillRow extends SkillInfo {
|
|
3
|
+
active: boolean;
|
|
4
|
+
}
|
|
5
|
+
/** Read the active skill ids from a project.yaml (skills:), normalising slashes. */
|
|
6
|
+
export declare function loadActiveSkillIds(root: string): Set<string>;
|
|
7
|
+
/**
|
|
8
|
+
* Filter the skill catalog by a free-text query. Matches (case-insensitive,
|
|
9
|
+
* substring) against id, command, category, purpose and trigger. An empty query
|
|
10
|
+
* returns the whole catalog. Each row is marked `active` if it is enabled in the
|
|
11
|
+
* given project.yaml (resolved from `root`).
|
|
12
|
+
*/
|
|
13
|
+
export declare function searchSkills(query: string, root?: string): SkillRow[];
|
|
14
|
+
export interface HookEntry {
|
|
15
|
+
/** Hook file name, e.g. pre-edit-check.js. */
|
|
16
|
+
hook: string;
|
|
17
|
+
/** Claude Code lifecycle event (PreToolUse | Stop | SessionStart | …). */
|
|
18
|
+
event: string;
|
|
19
|
+
/** Tool matcher (Edit|Write, Bash, …) — empty when the event has no matcher. */
|
|
20
|
+
matcher: string;
|
|
21
|
+
/** Human description of what the hook does (from the registry). */
|
|
22
|
+
description: string;
|
|
23
|
+
/** Which group the hook belongs to: universal | standard | unknown. */
|
|
24
|
+
mode: 'universal' | 'standard' | 'unknown';
|
|
25
|
+
/** True when the hook file is actually present in .claude/hooks/. */
|
|
26
|
+
installed: boolean;
|
|
27
|
+
}
|
|
28
|
+
interface RegistryHook {
|
|
29
|
+
hook: string;
|
|
30
|
+
event?: string;
|
|
31
|
+
matcher?: string;
|
|
32
|
+
description?: string;
|
|
33
|
+
}
|
|
34
|
+
interface HooksRegistry {
|
|
35
|
+
universal?: RegistryHook[];
|
|
36
|
+
standard?: RegistryHook[];
|
|
37
|
+
}
|
|
38
|
+
/** Parse core/hooks/hooks-registry.yaml from the forge root. Returns {} on error. */
|
|
39
|
+
export declare function loadHooksRegistry(forgeRoot: string): HooksRegistry;
|
|
40
|
+
/**
|
|
41
|
+
* Build the unified hook list: every hook declared in the registry plus any
|
|
42
|
+
* extra hook found on disk in `<projectRoot>/.claude/hooks/` that the registry
|
|
43
|
+
* doesn't know about. Each entry carries its event/matcher/mode and whether it
|
|
44
|
+
* is installed in the project.
|
|
45
|
+
*/
|
|
46
|
+
export declare function listInstalledHooks(projectRoot: string, forgeRoot: string | null): HookEntry[];
|
|
47
|
+
export interface TemplateEntry {
|
|
48
|
+
/** Display name. */
|
|
49
|
+
name: string;
|
|
50
|
+
/** Category bucket: wiki | spec | mode | claude-md. */
|
|
51
|
+
category: 'wiki' | 'spec' | 'mode' | 'claude-md';
|
|
52
|
+
/** Path relative to the forge root. */
|
|
53
|
+
relPath: string;
|
|
54
|
+
/** Short human description. */
|
|
55
|
+
description: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* List the templates bundled with forge: wiki seeds, the spec template, the
|
|
59
|
+
* project.yaml mode templates and the claude-md templates. Paths are relative to
|
|
60
|
+
* `forgeRoot`. Returns [] if `forgeRoot` is null.
|
|
61
|
+
*/
|
|
62
|
+
export declare function listTemplates(forgeRoot: string | null): TemplateEntry[];
|
|
63
|
+
export interface ConfigSummary {
|
|
64
|
+
found: boolean;
|
|
65
|
+
yamlPath: string | null;
|
|
66
|
+
name: string;
|
|
67
|
+
mode: string;
|
|
68
|
+
language: string;
|
|
69
|
+
stack: Array<{
|
|
70
|
+
key: string;
|
|
71
|
+
value: string;
|
|
72
|
+
}>;
|
|
73
|
+
agentsActive: string[];
|
|
74
|
+
agentsSpecialized: string[];
|
|
75
|
+
agentsCompliance: string[];
|
|
76
|
+
profiles: string[];
|
|
77
|
+
skills: string[];
|
|
78
|
+
runtimes: string[];
|
|
79
|
+
compliance: string[];
|
|
80
|
+
deploy: {
|
|
81
|
+
provider?: string;
|
|
82
|
+
url?: string;
|
|
83
|
+
} | null;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Build a structured, view-friendly summary of a project's project.yaml. When no
|
|
87
|
+
* config is found, `found` is false and the rest of the fields are empty.
|
|
88
|
+
*/
|
|
89
|
+
export declare function getConfigSummary(root?: string): ConfigSummary;
|
|
90
|
+
export {};
|
|
91
|
+
//# sourceMappingURL=panel-data.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"panel-data.d.ts","sourceRoot":"","sources":["../../src/lib/panel-data.ts"],"names":[],"mappings":"AAUA,OAAO,EAAU,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAKtD,MAAM,WAAW,QAAS,SAAQ,SAAS;IACzC,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,oFAAoF;AACpF,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAU5D;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE,MAAsB,GAAG,QAAQ,EAAE,CAYpF;AAID,MAAM,WAAW,SAAS;IACxB,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,0EAA0E;IAC1E,KAAK,EAAE,MAAM,CAAC;IACd,gFAAgF;IAChF,OAAO,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,WAAW,EAAE,MAAM,CAAC;IACpB,uEAAuE;IACvE,IAAI,EAAE,WAAW,GAAG,UAAU,GAAG,SAAS,CAAC;IAC3C,qEAAqE;IACrE,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,UAAU,YAAY;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AACD,UAAU,aAAa;IACrB,SAAS,CAAC,EAAE,YAAY,EAAE,CAAC;IAC3B,QAAQ,CAAC,EAAE,YAAY,EAAE,CAAC;CAC3B;AAED,qFAAqF;AACrF,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,CASlE;AAOD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,CAuC7F;AAID,MAAM,WAAW,aAAa;IAC5B,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,WAAW,CAAC;IACjD,uCAAuC;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,+BAA+B;IAC/B,WAAW,EAAE,MAAM,CAAC;CACrB;AAmCD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,aAAa,EAAE,CAiDvE;AAID,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC7C,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CACpD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,GAAE,MAAsB,GAAG,aAAa,CAkD5E"}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Non-interactive data layer for `forge panel`.
|
|
3
|
+
*
|
|
4
|
+
* Every function here is pure-ish (reads the filesystem, never prints, never
|
|
5
|
+
* touches a TTY) so the OpenTUI panel, the @clack fallback and the test suite
|
|
6
|
+
* can all share the same logic. See SPEC-033.
|
|
7
|
+
*/
|
|
8
|
+
import { existsSync, readFileSync, readdirSync, statSync } from 'fs';
|
|
9
|
+
import { join } from 'path';
|
|
10
|
+
import yaml from 'js-yaml';
|
|
11
|
+
import { SKILLS } from './catalog.js';
|
|
12
|
+
import { findProjectYaml, loadProjectYaml } from './yaml.js';
|
|
13
|
+
/** Read the active skill ids from a project.yaml (skills:), normalising slashes. */
|
|
14
|
+
export function loadActiveSkillIds(root) {
|
|
15
|
+
const yamlPath = findProjectYaml(root);
|
|
16
|
+
if (!yamlPath)
|
|
17
|
+
return new Set();
|
|
18
|
+
try {
|
|
19
|
+
const config = loadProjectYaml(yamlPath);
|
|
20
|
+
const raw = Array.isArray(config.skills) ? config.skills : [];
|
|
21
|
+
return new Set(raw.map(s => String(s).replace(/^\//, '')));
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return new Set();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Filter the skill catalog by a free-text query. Matches (case-insensitive,
|
|
29
|
+
* substring) against id, command, category, purpose and trigger. An empty query
|
|
30
|
+
* returns the whole catalog. Each row is marked `active` if it is enabled in the
|
|
31
|
+
* given project.yaml (resolved from `root`).
|
|
32
|
+
*/
|
|
33
|
+
export function searchSkills(query, root = process.cwd()) {
|
|
34
|
+
const activeIds = loadActiveSkillIds(root);
|
|
35
|
+
const q = query.trim().toLowerCase();
|
|
36
|
+
const rows = SKILLS.map(s => ({ ...s, active: activeIds.has(s.id) }));
|
|
37
|
+
if (!q)
|
|
38
|
+
return rows;
|
|
39
|
+
return rows.filter(s => s.id.toLowerCase().includes(q) ||
|
|
40
|
+
s.command.toLowerCase().includes(q) ||
|
|
41
|
+
s.category.toLowerCase().includes(q) ||
|
|
42
|
+
s.purpose.toLowerCase().includes(q) ||
|
|
43
|
+
s.trigger.toLowerCase().includes(q));
|
|
44
|
+
}
|
|
45
|
+
/** Parse core/hooks/hooks-registry.yaml from the forge root. Returns {} on error. */
|
|
46
|
+
export function loadHooksRegistry(forgeRoot) {
|
|
47
|
+
const path = join(forgeRoot, 'core', 'hooks', 'hooks-registry.yaml');
|
|
48
|
+
if (!existsSync(path))
|
|
49
|
+
return {};
|
|
50
|
+
try {
|
|
51
|
+
const data = yaml.load(readFileSync(path, 'utf-8'));
|
|
52
|
+
return data && typeof data === 'object' ? data : {};
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return {};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/** Collapse a multi-line YAML folded description into a single line. */
|
|
59
|
+
function oneLine(s) {
|
|
60
|
+
return (s ?? '').replace(/\s+/g, ' ').trim();
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Build the unified hook list: every hook declared in the registry plus any
|
|
64
|
+
* extra hook found on disk in `<projectRoot>/.claude/hooks/` that the registry
|
|
65
|
+
* doesn't know about. Each entry carries its event/matcher/mode and whether it
|
|
66
|
+
* is installed in the project.
|
|
67
|
+
*/
|
|
68
|
+
export function listInstalledHooks(projectRoot, forgeRoot) {
|
|
69
|
+
const registry = forgeRoot ? loadHooksRegistry(forgeRoot) : {};
|
|
70
|
+
const hooksDir = join(projectRoot, '.claude', 'hooks');
|
|
71
|
+
const onDisk = new Set(existsSync(hooksDir)
|
|
72
|
+
? readdirSync(hooksDir).filter(f => statSync(join(hooksDir, f)).isFile())
|
|
73
|
+
: []);
|
|
74
|
+
const entries = [];
|
|
75
|
+
const seen = new Set();
|
|
76
|
+
const pushGroup = (group, mode) => {
|
|
77
|
+
for (const h of group ?? []) {
|
|
78
|
+
if (!h?.hook)
|
|
79
|
+
continue;
|
|
80
|
+
seen.add(h.hook);
|
|
81
|
+
entries.push({
|
|
82
|
+
hook: h.hook,
|
|
83
|
+
event: h.event ?? '—',
|
|
84
|
+
matcher: h.matcher ?? '',
|
|
85
|
+
description: oneLine(h.description),
|
|
86
|
+
mode,
|
|
87
|
+
installed: onDisk.has(h.hook),
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
pushGroup(registry.universal, 'universal');
|
|
92
|
+
pushGroup(registry.standard, 'standard');
|
|
93
|
+
// Hooks present on disk but not declared in the registry.
|
|
94
|
+
for (const f of [...onDisk].sort()) {
|
|
95
|
+
if (seen.has(f))
|
|
96
|
+
continue;
|
|
97
|
+
entries.push({
|
|
98
|
+
hook: f, event: '—', matcher: '', description: '(no documentado en el registry)',
|
|
99
|
+
mode: 'unknown', installed: true,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
return entries;
|
|
103
|
+
}
|
|
104
|
+
const MODE_DESCRIPTIONS = {
|
|
105
|
+
'startup.yaml.tpl': 'Modo startup — overhead mínimo, equipo pequeño',
|
|
106
|
+
'enterprise.yaml.tpl': 'Modo enterprise — compliance, auditoría, multi-equipo',
|
|
107
|
+
'multi-runtime.yaml.tpl': 'Multi-runtime — un project.yaml para los 4 runtimes',
|
|
108
|
+
'new-stack.yaml.tpl': 'Stack nuevo — plantilla base para empezar de cero',
|
|
109
|
+
};
|
|
110
|
+
const WIKI_DESCRIPTIONS = {
|
|
111
|
+
'index.md': 'Índice raíz del wiki del proyecto',
|
|
112
|
+
'log.md': 'Bitácora de ingestas del wiki',
|
|
113
|
+
'concepts/_template.md': 'Plantilla de nota de concepto',
|
|
114
|
+
'entities/_template.md': 'Plantilla de nota de entidad',
|
|
115
|
+
'sources/_template.md': 'Plantilla de nota de fuente',
|
|
116
|
+
'synthesis/_template.md': 'Plantilla de nota de síntesis',
|
|
117
|
+
};
|
|
118
|
+
const CLAUDE_MD_DESCRIPTIONS = {
|
|
119
|
+
'project.md': 'CLAUDE.md base de un proyecto forge',
|
|
120
|
+
'global.md': 'Instrucciones globales (~/.claude/CLAUDE.md)',
|
|
121
|
+
'architecture.rules': 'Reglas de arquitectura del proyecto',
|
|
122
|
+
};
|
|
123
|
+
/** Recursively collect files under a dir, returning paths relative to `base`. */
|
|
124
|
+
function walkRel(base, dir, acc = []) {
|
|
125
|
+
if (!existsSync(dir))
|
|
126
|
+
return acc;
|
|
127
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
128
|
+
const full = join(dir, entry.name);
|
|
129
|
+
if (entry.isDirectory())
|
|
130
|
+
walkRel(base, full, acc);
|
|
131
|
+
else
|
|
132
|
+
acc.push(full.slice(base.length + 1).split('\\').join('/'));
|
|
133
|
+
}
|
|
134
|
+
return acc;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* List the templates bundled with forge: wiki seeds, the spec template, the
|
|
138
|
+
* project.yaml mode templates and the claude-md templates. Paths are relative to
|
|
139
|
+
* `forgeRoot`. Returns [] if `forgeRoot` is null.
|
|
140
|
+
*/
|
|
141
|
+
export function listTemplates(forgeRoot) {
|
|
142
|
+
if (!forgeRoot)
|
|
143
|
+
return [];
|
|
144
|
+
const out = [];
|
|
145
|
+
// Spec template.
|
|
146
|
+
const specPath = join(forgeRoot, 'core', 'templates', 'spec-template.md');
|
|
147
|
+
if (existsSync(specPath)) {
|
|
148
|
+
out.push({
|
|
149
|
+
name: 'spec-template.md', category: 'spec',
|
|
150
|
+
relPath: 'core/templates/spec-template.md',
|
|
151
|
+
description: 'Plantilla de spec SDD (docs/specs/_template.md)',
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
// Mode templates (templates/modes/*).
|
|
155
|
+
const modesDir = join(forgeRoot, 'templates', 'modes');
|
|
156
|
+
if (existsSync(modesDir)) {
|
|
157
|
+
for (const f of readdirSync(modesDir).sort()) {
|
|
158
|
+
out.push({
|
|
159
|
+
name: f, category: 'mode',
|
|
160
|
+
relPath: `templates/modes/${f}`,
|
|
161
|
+
description: MODE_DESCRIPTIONS[f] ?? 'Plantilla de project.yaml',
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
// Wiki templates (templates/wiki/**).
|
|
166
|
+
const wikiDir = join(forgeRoot, 'templates', 'wiki');
|
|
167
|
+
for (const rel of walkRel(wikiDir, wikiDir).sort()) {
|
|
168
|
+
out.push({
|
|
169
|
+
name: rel, category: 'wiki',
|
|
170
|
+
relPath: `templates/wiki/${rel}`,
|
|
171
|
+
description: WIKI_DESCRIPTIONS[rel] ?? 'Plantilla de página de wiki',
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
// claude-md templates (core/templates/claude-md/*).
|
|
175
|
+
const cmDir = join(forgeRoot, 'core', 'templates', 'claude-md');
|
|
176
|
+
if (existsSync(cmDir)) {
|
|
177
|
+
for (const f of readdirSync(cmDir).sort()) {
|
|
178
|
+
out.push({
|
|
179
|
+
name: f, category: 'claude-md',
|
|
180
|
+
relPath: `core/templates/claude-md/${f}`,
|
|
181
|
+
description: CLAUDE_MD_DESCRIPTIONS[f] ?? 'Plantilla CLAUDE.md',
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return out;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Build a structured, view-friendly summary of a project's project.yaml. When no
|
|
189
|
+
* config is found, `found` is false and the rest of the fields are empty.
|
|
190
|
+
*/
|
|
191
|
+
export function getConfigSummary(root = process.cwd()) {
|
|
192
|
+
const empty = {
|
|
193
|
+
found: false, yamlPath: null, name: '', mode: '', language: '',
|
|
194
|
+
stack: [], agentsActive: [], agentsSpecialized: [], agentsCompliance: [],
|
|
195
|
+
profiles: [], skills: [], runtimes: [], compliance: [], deploy: null,
|
|
196
|
+
};
|
|
197
|
+
const yamlPath = findProjectYaml(root);
|
|
198
|
+
if (!yamlPath)
|
|
199
|
+
return empty;
|
|
200
|
+
let config;
|
|
201
|
+
try {
|
|
202
|
+
config = loadProjectYaml(yamlPath);
|
|
203
|
+
}
|
|
204
|
+
catch {
|
|
205
|
+
return { ...empty, yamlPath };
|
|
206
|
+
}
|
|
207
|
+
const stack = [];
|
|
208
|
+
const s = config.stack ?? {};
|
|
209
|
+
const pushStack = (key, value) => {
|
|
210
|
+
if (value === undefined || value === null)
|
|
211
|
+
return;
|
|
212
|
+
if (Array.isArray(value)) {
|
|
213
|
+
if (value.length)
|
|
214
|
+
stack.push({ key, value: value.join(', ') });
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
stack.push({ key, value: String(value) });
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
pushStack('backend', s.backend);
|
|
221
|
+
pushStack('frontend', s.frontend);
|
|
222
|
+
pushStack('database', s.database);
|
|
223
|
+
pushStack('orm', s.orm);
|
|
224
|
+
pushStack('package_manager', s.package_manager);
|
|
225
|
+
pushStack('testing', s.testing);
|
|
226
|
+
return {
|
|
227
|
+
found: true,
|
|
228
|
+
yamlPath,
|
|
229
|
+
name: config.project?.name ?? '(sin nombre)',
|
|
230
|
+
mode: config.project?.mode ?? '(sin mode)',
|
|
231
|
+
language: config.project?.language ?? '(sin lenguaje)',
|
|
232
|
+
stack,
|
|
233
|
+
agentsActive: config.agents?.active ?? [],
|
|
234
|
+
agentsSpecialized: config.agents?.specialized ?? [],
|
|
235
|
+
agentsCompliance: config.agents?.compliance ?? [],
|
|
236
|
+
profiles: config.agents?.profiles ?? [],
|
|
237
|
+
skills: Array.isArray(config.skills) ? config.skills.map(x => String(x)) : [],
|
|
238
|
+
runtimes: config.runtimes?.active ?? [],
|
|
239
|
+
compliance: config.compliance?.frameworks ?? [],
|
|
240
|
+
deploy: config.deploy ? { provider: config.deploy.provider, url: config.deploy.production_url } : null,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
//# sourceMappingURL=panel-data.js.map
|