@neetru/cli 2.21.0 → 2.24.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 +66 -0
- package/README.md +17 -0
- package/dist/commands/code.js +239 -34
- package/dist/commands/code.js.map +1 -1
- package/dist/commands/dev-context.d.ts +28 -0
- package/dist/commands/dev-context.js +211 -0
- package/dist/commands/dev-context.js.map +1 -0
- package/dist/commands/dev-up.d.ts +2 -0
- package/dist/commands/dev-up.js +122 -18
- package/dist/commands/dev-up.js.map +1 -1
- package/dist/commands/dev.d.ts +3 -0
- package/dist/commands/dev.js +101 -25
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/env.d.ts +1 -1
- package/dist/commands/env.js +17 -10
- package/dist/commands/env.js.map +1 -1
- package/dist/index.js +58 -3
- package/dist/index.js.map +1 -1
- package/dist/lib/code-agent-budget.d.ts +67 -0
- package/dist/lib/code-agent-budget.js +80 -0
- package/dist/lib/code-agent-budget.js.map +1 -0
- package/dist/lib/code-agent-files.d.ts +1 -0
- package/dist/lib/code-agent-files.js +30 -9
- package/dist/lib/code-agent-files.js.map +1 -1
- package/dist/lib/code-agent-protocol.d.ts +5 -0
- package/dist/lib/code-agent-protocol.js +10 -5
- package/dist/lib/code-agent-protocol.js.map +1 -1
- package/dist/lib/code-agent-session.d.ts +1 -1
- package/dist/lib/code-agent-session.js +16 -1
- package/dist/lib/code-agent-session.js.map +1 -1
- package/dist/lib/code-agent-tools.js +40 -10
- package/dist/lib/code-agent-tools.js.map +1 -1
- package/dist/lib/code-agent-tui.d.ts +34 -0
- package/dist/lib/code-agent-tui.js +120 -6
- package/dist/lib/code-agent-tui.js.map +1 -1
- package/dist/lib/code-agent-types.d.ts +19 -1
- package/dist/lib/code-agent-ui.d.ts +7 -0
- package/dist/lib/code-agent-ui.js +44 -30
- package/dist/lib/code-agent-ui.js.map +1 -1
- package/dist/lib/code-agent-web-tools.js +141 -35
- package/dist/lib/code-agent-web-tools.js.map +1 -1
- package/dist/lib/code-agent-write-tools.d.ts +5 -0
- package/dist/lib/code-agent-write-tools.js +141 -0
- package/dist/lib/code-agent-write-tools.js.map +1 -0
- package/dist/lib/dev-local-context.d.ts +29 -0
- package/dist/lib/dev-local-context.js +114 -0
- package/dist/lib/dev-local-context.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ferramentas deterministicas de escrita do `neetru code` — write_file,
|
|
3
|
+
* append_file, replace_in_file (2026-07-13). Existem pra tirar do
|
|
4
|
+
* NEETRU_PATCH (unified diff cru gerado pelo modelo, so validado por `git
|
|
5
|
+
* apply --check`, sem reparo de hunk/CRLF/newline) o papel de UNICO caminho
|
|
6
|
+
* de escrita — achado em uso real (transcript colado pelo usuario: o modelo
|
|
7
|
+
* ficava preso reescrevendo o mesmo diff quebrado, esgotando o orcamento de
|
|
8
|
+
* turnos inteiro sem nunca conseguir mudar o arquivo) + diagnostico
|
|
9
|
+
* confirmado por revisao de codigo (Codex). NEETRU_PATCH continua existindo
|
|
10
|
+
* pra mudancas que precisam de diff multi-arquivo/multi-hunk num so turno;
|
|
11
|
+
* estas 3 ferramentas viram o caminho PRINCIPAL pra criar/editar UM arquivo.
|
|
12
|
+
*
|
|
13
|
+
* Nivel de cautela: local e reversivel (git mostra a mudanca depois, `git
|
|
14
|
+
* checkout`/`git restore` desfaz) — mesmo tier de git_commit/git_branch:
|
|
15
|
+
* `--yes`/`/yes` dispensa a pergunta, senao confirma mostrando o preview.
|
|
16
|
+
* Path sempre resolvido via `resolveInside` (contencao + symlink real path,
|
|
17
|
+
* mesma guarda de read_file); escrita em arquivo de segredo (.env/chave)
|
|
18
|
+
* bloqueada, espelhando o bloqueio de leitura.
|
|
19
|
+
*/
|
|
20
|
+
import fs from 'node:fs';
|
|
21
|
+
import path from 'node:path';
|
|
22
|
+
import { clipToolOutput, isSecretPath, resolveInside } from './code-agent-files.js';
|
|
23
|
+
const MAX_WRITE_CONTENT_CHARS = 200_000;
|
|
24
|
+
const PREVIEW_MAX_LINES = 12;
|
|
25
|
+
const PREVIEW_MAX_CHARS = 600;
|
|
26
|
+
function asString(value) {
|
|
27
|
+
return typeof value === 'string' ? value : undefined;
|
|
28
|
+
}
|
|
29
|
+
function relativeOf(rootDir, fullPath) {
|
|
30
|
+
return path.relative(path.resolve(rootDir), fullPath).replace(/\\/g, '/');
|
|
31
|
+
}
|
|
32
|
+
/** Resolve+valida o path (contencao/symlink/segredo) — lanca em qualquer problema; `runCodeTool` converte pra `ERRO: ...`. */
|
|
33
|
+
function guardPath(rootDir, inputPath) {
|
|
34
|
+
if (typeof inputPath !== 'string' || !inputPath.trim()) {
|
|
35
|
+
throw new Error('exige path string nao vazio.');
|
|
36
|
+
}
|
|
37
|
+
const full = resolveInside(rootDir, inputPath.trim());
|
|
38
|
+
const relative = relativeOf(rootDir, full);
|
|
39
|
+
if (isSecretPath(relative)) {
|
|
40
|
+
throw new Error(`escrita bloqueada: "${relative}" parece arquivo de segredo (.env/chave/credencial).`);
|
|
41
|
+
}
|
|
42
|
+
return { full, relative };
|
|
43
|
+
}
|
|
44
|
+
// Mesma lista de code-agent-git-tools.ts: ESC/CR no conteudo (que pode vir
|
|
45
|
+
// "repetido" de um arquivo lido — prompt injection) nao pode reescrever
|
|
46
|
+
// visualmente o preview de confirmacao.
|
|
47
|
+
function sanitizeForPreview(value) {
|
|
48
|
+
return value.replace(/[\x00-\x08\x0B-\x1F\x7F-\x9F]/g, '');
|
|
49
|
+
}
|
|
50
|
+
function previewSnippet(content) {
|
|
51
|
+
const clipped = content.length > PREVIEW_MAX_CHARS ? `${content.slice(0, PREVIEW_MAX_CHARS)}…` : content;
|
|
52
|
+
const lines = sanitizeForPreview(clipped).split(/\r?\n/);
|
|
53
|
+
const shown = lines.slice(0, PREVIEW_MAX_LINES).map((l) => ` ${l}`);
|
|
54
|
+
if (lines.length > PREVIEW_MAX_LINES)
|
|
55
|
+
shown.push(` ... mais ${lines.length - PREVIEW_MAX_LINES} linha(s)`);
|
|
56
|
+
return shown.join('\n');
|
|
57
|
+
}
|
|
58
|
+
function assertContentSize(tool, content) {
|
|
59
|
+
if (content.length > MAX_WRITE_CONTENT_CHARS) {
|
|
60
|
+
throw new Error(`${tool}: content maior que ${MAX_WRITE_CONTENT_CHARS} chars — quebre em partes menores.`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
export async function writeFileTool(rootDir, request, ctx) {
|
|
64
|
+
const guard = guardPath(rootDir, request.path);
|
|
65
|
+
const content = asString(request.content);
|
|
66
|
+
if (content === undefined)
|
|
67
|
+
return 'ERRO: write_file exige content string.';
|
|
68
|
+
assertContentSize('write_file', content);
|
|
69
|
+
const exists = fs.existsSync(guard.full);
|
|
70
|
+
const before = exists ? fs.statSync(guard.full).size : null;
|
|
71
|
+
const action = exists
|
|
72
|
+
? `sobrescrever arquivo existente (${before} -> ${content.length} chars)`
|
|
73
|
+
: 'criar arquivo novo';
|
|
74
|
+
const preview = [
|
|
75
|
+
`write_file ${guard.relative}`,
|
|
76
|
+
` acao: ${action}`,
|
|
77
|
+
' conteudo:',
|
|
78
|
+
previewSnippet(content),
|
|
79
|
+
].join('\n');
|
|
80
|
+
const approved = ctx.settings.yes || (await ctx.confirm(`${preview}\n\nEscrever este arquivo? [y/N] `));
|
|
81
|
+
if (!approved)
|
|
82
|
+
return 'ERRO: escrita cancelada pelo usuario.';
|
|
83
|
+
fs.mkdirSync(path.dirname(guard.full), { recursive: true });
|
|
84
|
+
fs.writeFileSync(guard.full, content, 'utf8');
|
|
85
|
+
return clipToolOutput('write_file', `OK: ${exists ? 'sobrescrito' : 'criado'} ${guard.relative} (${content.length} chars).`);
|
|
86
|
+
}
|
|
87
|
+
export async function appendFileTool(rootDir, request, ctx) {
|
|
88
|
+
const guard = guardPath(rootDir, request.path);
|
|
89
|
+
const content = asString(request.content);
|
|
90
|
+
if (content === undefined)
|
|
91
|
+
return 'ERRO: append_file exige content string.';
|
|
92
|
+
assertContentSize('append_file', content);
|
|
93
|
+
const preview = [
|
|
94
|
+
`append_file ${guard.relative}`,
|
|
95
|
+
' conteudo a adicionar no final:',
|
|
96
|
+
previewSnippet(content),
|
|
97
|
+
].join('\n');
|
|
98
|
+
const approved = ctx.settings.yes || (await ctx.confirm(`${preview}\n\nAdicionar ao final do arquivo? [y/N] `));
|
|
99
|
+
if (!approved)
|
|
100
|
+
return 'ERRO: escrita cancelada pelo usuario.';
|
|
101
|
+
fs.mkdirSync(path.dirname(guard.full), { recursive: true });
|
|
102
|
+
fs.appendFileSync(guard.full, content, 'utf8');
|
|
103
|
+
return clipToolOutput('append_file', `OK: adicionado ao final de ${guard.relative} (+${content.length} chars).`);
|
|
104
|
+
}
|
|
105
|
+
export async function replaceInFileTool(rootDir, request, ctx) {
|
|
106
|
+
const guard = guardPath(rootDir, request.path);
|
|
107
|
+
const oldString = asString(request.old_string);
|
|
108
|
+
const newString = asString(request.new_string);
|
|
109
|
+
if (!oldString)
|
|
110
|
+
return 'ERRO: replace_in_file exige old_string string nao vazio.';
|
|
111
|
+
if (newString === undefined)
|
|
112
|
+
return 'ERRO: replace_in_file exige new_string string.';
|
|
113
|
+
if (!fs.existsSync(guard.full))
|
|
114
|
+
return `ERRO: replace_in_file arquivo nao existe: ${guard.relative}`;
|
|
115
|
+
const before = fs.readFileSync(guard.full, 'utf8');
|
|
116
|
+
const occurrences = before.split(oldString).length - 1;
|
|
117
|
+
if (occurrences === 0) {
|
|
118
|
+
return `ERRO: old_string nao encontrado em ${guard.relative}. Releia o arquivo antes de tentar de novo.`;
|
|
119
|
+
}
|
|
120
|
+
const replaceAll = request.replace_all === true;
|
|
121
|
+
if (occurrences > 1 && !replaceAll) {
|
|
122
|
+
return (`ERRO: old_string aparece ${occurrences}x em ${guard.relative} — inclua mais contexto pra ficar unico, ` +
|
|
123
|
+
'ou use "replace_all":true de proposito.');
|
|
124
|
+
}
|
|
125
|
+
const after = replaceAll ? before.split(oldString).join(newString) : before.replace(oldString, newString);
|
|
126
|
+
assertContentSize('replace_in_file', after);
|
|
127
|
+
const preview = [
|
|
128
|
+
`replace_in_file ${guard.relative}`,
|
|
129
|
+
` ocorrencias: ${occurrences}${replaceAll ? ' (todas)' : ''}`,
|
|
130
|
+
' de:',
|
|
131
|
+
previewSnippet(oldString),
|
|
132
|
+
' para:',
|
|
133
|
+
previewSnippet(newString),
|
|
134
|
+
].join('\n');
|
|
135
|
+
const approved = ctx.settings.yes || (await ctx.confirm(`${preview}\n\nAplicar esta substituicao? [y/N] `));
|
|
136
|
+
if (!approved)
|
|
137
|
+
return 'ERRO: substituicao cancelada pelo usuario.';
|
|
138
|
+
fs.writeFileSync(guard.full, after, 'utf8');
|
|
139
|
+
return clipToolOutput('replace_in_file', `OK: ${occurrences} ocorrencia(s) substituida(s) em ${guard.relative}.`);
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=code-agent-write-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-agent-write-tools.js","sourceRoot":"","sources":["../../src/lib/code-agent-write-tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export type DevContextMode = 'core-product' | 'prototype';
|
|
2
|
+
export interface LocalProductConfig {
|
|
3
|
+
slug?: string;
|
|
4
|
+
productId?: string;
|
|
5
|
+
tenantId?: string;
|
|
6
|
+
runtime?: string;
|
|
7
|
+
name?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface DevLocalContext {
|
|
10
|
+
version: 1;
|
|
11
|
+
mode: DevContextMode;
|
|
12
|
+
productSlug?: string;
|
|
13
|
+
productId?: string;
|
|
14
|
+
workspaceId?: string;
|
|
15
|
+
environmentId?: string;
|
|
16
|
+
corePath?: string;
|
|
17
|
+
emulatorOnly?: string;
|
|
18
|
+
source?: 'manual' | 'core' | 'inferred';
|
|
19
|
+
updatedAt: string;
|
|
20
|
+
}
|
|
21
|
+
export declare const DEV_CONTEXT_REL = ".neetru/dev.json";
|
|
22
|
+
export declare function devContextPath(cwd?: string): string;
|
|
23
|
+
export declare function loadLocalProductConfig(cwd?: string): LocalProductConfig | null;
|
|
24
|
+
export declare function normalizeDevContext(raw: unknown): DevLocalContext | null;
|
|
25
|
+
export declare function loadDevContext(cwd?: string): DevLocalContext | null;
|
|
26
|
+
export declare function saveDevContext(cwd: string, context: Omit<DevLocalContext, 'version' | 'updatedAt'> & Partial<Pick<DevLocalContext, 'updatedAt'>>): DevLocalContext;
|
|
27
|
+
export declare function inferDevContext(cwd?: string): DevLocalContext | null;
|
|
28
|
+
export declare function resolveDevContext(cwd?: string): DevLocalContext | null;
|
|
29
|
+
export declare function describeDevContext(context: DevLocalContext | null): string;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
export const DEV_CONTEXT_REL = '.neetru/dev.json';
|
|
4
|
+
function isObject(value) {
|
|
5
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
6
|
+
}
|
|
7
|
+
function stringField(value) {
|
|
8
|
+
return typeof value === 'string' && value.trim() ? value.trim() : undefined;
|
|
9
|
+
}
|
|
10
|
+
export function devContextPath(cwd = process.cwd()) {
|
|
11
|
+
return path.join(cwd, DEV_CONTEXT_REL);
|
|
12
|
+
}
|
|
13
|
+
export function loadLocalProductConfig(cwd = process.cwd()) {
|
|
14
|
+
for (const filename of ['neetru.config.json', '.neetru.json']) {
|
|
15
|
+
const filePath = path.join(cwd, filename);
|
|
16
|
+
if (!fs.existsSync(filePath))
|
|
17
|
+
continue;
|
|
18
|
+
try {
|
|
19
|
+
const parsed = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
20
|
+
if (!isObject(parsed))
|
|
21
|
+
return null;
|
|
22
|
+
return {
|
|
23
|
+
slug: stringField(parsed.slug),
|
|
24
|
+
productId: stringField(parsed.productId),
|
|
25
|
+
tenantId: stringField(parsed.tenantId),
|
|
26
|
+
runtime: stringField(parsed.runtime),
|
|
27
|
+
name: stringField(parsed.name),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
export function normalizeDevContext(raw) {
|
|
37
|
+
if (!isObject(raw))
|
|
38
|
+
return null;
|
|
39
|
+
const mode = raw.mode === 'core-product' || raw.mode === 'prototype' ? raw.mode : undefined;
|
|
40
|
+
if (!mode)
|
|
41
|
+
return null;
|
|
42
|
+
return {
|
|
43
|
+
version: 1,
|
|
44
|
+
mode,
|
|
45
|
+
productSlug: stringField(raw.productSlug),
|
|
46
|
+
productId: stringField(raw.productId),
|
|
47
|
+
workspaceId: stringField(raw.workspaceId),
|
|
48
|
+
environmentId: stringField(raw.environmentId),
|
|
49
|
+
corePath: stringField(raw.corePath),
|
|
50
|
+
emulatorOnly: stringField(raw.emulatorOnly),
|
|
51
|
+
source: raw.source === 'manual' || raw.source === 'core' || raw.source === 'inferred'
|
|
52
|
+
? raw.source
|
|
53
|
+
: undefined,
|
|
54
|
+
updatedAt: stringField(raw.updatedAt) ?? new Date().toISOString(),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
export function loadDevContext(cwd = process.cwd()) {
|
|
58
|
+
const filePath = devContextPath(cwd);
|
|
59
|
+
if (!fs.existsSync(filePath))
|
|
60
|
+
return null;
|
|
61
|
+
try {
|
|
62
|
+
return normalizeDevContext(JSON.parse(fs.readFileSync(filePath, 'utf8')));
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
export function saveDevContext(cwd, context) {
|
|
69
|
+
const full = {
|
|
70
|
+
version: 1,
|
|
71
|
+
...context,
|
|
72
|
+
updatedAt: context.updatedAt ?? new Date().toISOString(),
|
|
73
|
+
};
|
|
74
|
+
const filePath = devContextPath(cwd);
|
|
75
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
76
|
+
fs.writeFileSync(filePath, JSON.stringify(full, null, 2) + '\n', 'utf8');
|
|
77
|
+
return full;
|
|
78
|
+
}
|
|
79
|
+
export function inferDevContext(cwd = process.cwd()) {
|
|
80
|
+
const local = loadLocalProductConfig(cwd);
|
|
81
|
+
if (!local?.slug && !local?.productId)
|
|
82
|
+
return null;
|
|
83
|
+
return {
|
|
84
|
+
version: 1,
|
|
85
|
+
mode: local.productId ? 'core-product' : 'prototype',
|
|
86
|
+
productSlug: local.slug,
|
|
87
|
+
productId: local.productId,
|
|
88
|
+
workspaceId: local.tenantId,
|
|
89
|
+
source: 'inferred',
|
|
90
|
+
updatedAt: new Date().toISOString(),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
export function resolveDevContext(cwd = process.cwd()) {
|
|
94
|
+
const saved = loadDevContext(cwd);
|
|
95
|
+
const inferred = inferDevContext(cwd);
|
|
96
|
+
if (!saved)
|
|
97
|
+
return inferred;
|
|
98
|
+
return {
|
|
99
|
+
...saved,
|
|
100
|
+
productSlug: saved.productSlug ?? inferred?.productSlug,
|
|
101
|
+
productId: saved.productId ?? inferred?.productId,
|
|
102
|
+
workspaceId: saved.workspaceId ?? inferred?.workspaceId,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
export function describeDevContext(context) {
|
|
106
|
+
if (!context)
|
|
107
|
+
return 'sem contexto dev-local';
|
|
108
|
+
const product = context.productSlug ?? context.productId ?? 'sem produto';
|
|
109
|
+
const mode = context.mode === 'prototype' ? 'protótipo local' : 'produto Core';
|
|
110
|
+
const env = context.environmentId ? ` · env=${context.environmentId}` : '';
|
|
111
|
+
const workspace = context.workspaceId ? ` · workspace=${context.workspaceId}` : '';
|
|
112
|
+
return `${mode}: ${product}${env}${workspace}`;
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=dev-local-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev-local-context.js","sourceRoot":"","sources":["../../src/lib/dev-local-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAyBlC,MAAM,CAAC,MAAM,eAAe,GAAG,kBAAkB,CAAC;AAElD,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,WAAW,CAAC,KAAc;IACjC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAc,OAAO,CAAC,GAAG,EAAE;IACxD,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,MAAc,OAAO,CAAC,GAAG,EAAE;IAChE,KAAK,MAAM,QAAQ,IAAI,CAAC,oBAAoB,EAAE,cAAc,CAAC,EAAE,CAAC;QAC9D,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QAC1C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;YAAE,SAAS;QACvC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAY,CAAC;YACxE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;gBAAE,OAAO,IAAI,CAAC;YACnC,OAAO;gBACL,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC;gBAC9B,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC;gBACxC,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC;gBACtC,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC;gBACpC,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC;aAC/B,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,GAAY;IAC9C,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAChC,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,KAAK,cAAc,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;IAC5F,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,OAAO;QACL,OAAO,EAAE,CAAC;QACV,IAAI;QACJ,WAAW,EAAE,WAAW,CAAC,GAAG,CAAC,WAAW,CAAC;QACzC,SAAS,EAAE,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC;QACrC,WAAW,EAAE,WAAW,CAAC,GAAG,CAAC,WAAW,CAAC;QACzC,aAAa,EAAE,WAAW,CAAC,GAAG,CAAC,aAAa,CAAC;QAC7C,QAAQ,EAAE,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC;QACnC,YAAY,EAAE,WAAW,CAAC,GAAG,CAAC,YAAY,CAAC;QAC3C,MAAM,EAAE,GAAG,CAAC,MAAM,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,GAAG,CAAC,MAAM,KAAK,UAAU;YACnF,CAAC,CAAC,GAAG,CAAC,MAAM;YACZ,CAAC,CAAC,SAAS;QACb,SAAS,EAAE,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KAClE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAc,OAAO,CAAC,GAAG,EAAE;IACxD,MAAM,QAAQ,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;IACrC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1C,IAAI,CAAC;QACH,OAAO,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IAC5E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,GAAW,EACX,OAAqG;IAErG,MAAM,IAAI,GAAoB;QAC5B,OAAO,EAAE,CAAC;QACV,GAAG,OAAO;QACV,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACzD,CAAC;IACF,MAAM,QAAQ,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;IACrC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1D,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC;IACzE,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAc,OAAO,CAAC,GAAG,EAAE;IACzD,MAAM,KAAK,GAAG,sBAAsB,CAAC,GAAG,CAAC,CAAC;IAC1C,IAAI,CAAC,KAAK,EAAE,IAAI,IAAI,CAAC,KAAK,EAAE,SAAS;QAAE,OAAO,IAAI,CAAC;IACnD,OAAO;QACL,OAAO,EAAE,CAAC;QACV,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,WAAW;QACpD,WAAW,EAAE,KAAK,CAAC,IAAI;QACvB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,WAAW,EAAE,KAAK,CAAC,QAAQ;QAC3B,MAAM,EAAE,UAAU;QAClB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAAc,OAAO,CAAC,GAAG,EAAE;IAC3D,MAAM,KAAK,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;IAClC,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;IACtC,IAAI,CAAC,KAAK;QAAE,OAAO,QAAQ,CAAC;IAC5B,OAAO;QACL,GAAG,KAAK;QACR,WAAW,EAAE,KAAK,CAAC,WAAW,IAAI,QAAQ,EAAE,WAAW;QACvD,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,QAAQ,EAAE,SAAS;QACjD,WAAW,EAAE,KAAK,CAAC,WAAW,IAAI,QAAQ,EAAE,WAAW;KACxD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,OAA+B;IAChE,IAAI,CAAC,OAAO;QAAE,OAAO,wBAAwB,CAAC;IAC9C,MAAM,OAAO,GAAG,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,SAAS,IAAI,aAAa,CAAC;IAC1E,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,cAAc,CAAC;IAC/E,MAAM,GAAG,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,UAAU,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3E,MAAM,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,gBAAgB,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACnF,OAAO,GAAG,IAAI,KAAK,OAAO,GAAG,GAAG,GAAG,SAAS,EAAE,CAAC;AACjD,CAAC"}
|
package/package.json
CHANGED