@justmpm/ai-tool 0.5.1 → 0.5.4
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 +40 -0
- package/dist/{chunk-A3QVUKVA.js → chunk-PHTWZ2JT.js} +285 -195
- package/dist/cli.js +2 -2
- package/dist/index.d.ts +135 -1
- package/dist/index.js +19 -1
- package/dist/{server-DMLKPY45.js → server-NIEAOPLJ.js} +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -155,6 +155,46 @@ Cria `.analyze/areas.config.json` com:
|
|
|
155
155
|
- Patterns glob para cada area
|
|
156
156
|
- Keywords de deteccao
|
|
157
157
|
- Descricoes manuais de arquivos
|
|
158
|
+
- Padroes de ignore global
|
|
159
|
+
|
|
160
|
+
### Configuracao de Areas
|
|
161
|
+
|
|
162
|
+
O arquivo `.analyze/areas.config.json` suporta:
|
|
163
|
+
|
|
164
|
+
```json
|
|
165
|
+
{
|
|
166
|
+
"$schema": "./areas.schema.json",
|
|
167
|
+
"version": "1.0.0",
|
|
168
|
+
"ignore": [
|
|
169
|
+
"docs/brainstorming/**",
|
|
170
|
+
"functions/lib/**",
|
|
171
|
+
"**/*.test.ts"
|
|
172
|
+
],
|
|
173
|
+
"areas": {
|
|
174
|
+
"auth": {
|
|
175
|
+
"name": "Autenticacao",
|
|
176
|
+
"description": "Sistema de login e sessao",
|
|
177
|
+
"patterns": ["**/auth/**", "**/login/**"],
|
|
178
|
+
"keywords": ["auth", "login", "session"]
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
"descriptions": {
|
|
182
|
+
"src/hooks/useAuth.ts": "Hook principal de autenticacao"
|
|
183
|
+
},
|
|
184
|
+
"settings": {
|
|
185
|
+
"autoDetect": true,
|
|
186
|
+
"inferDescriptions": true
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
| Campo | Descricao |
|
|
192
|
+
|-------|-----------|
|
|
193
|
+
| `ignore` | Padroes glob para ignorar arquivos/pastas globalmente |
|
|
194
|
+
| `areas` | Definicao manual de areas com patterns e keywords |
|
|
195
|
+
| `descriptions` | Descricoes manuais para arquivos especificos |
|
|
196
|
+
| `settings.autoDetect` | Se `false`, usa apenas areas definidas manualmente |
|
|
197
|
+
| `settings.inferDescriptions` | Infere descricoes automaticamente baseado no nome |
|
|
158
198
|
|
|
159
199
|
## Servidor MCP
|
|
160
200
|
|
|
@@ -1079,6 +1079,7 @@ var CONFIG_FILE = "areas.config.json";
|
|
|
1079
1079
|
var DEFAULT_CONFIG = {
|
|
1080
1080
|
$schema: "./areas.schema.json",
|
|
1081
1081
|
version: "1.0.0",
|
|
1082
|
+
ignore: [],
|
|
1082
1083
|
areas: {},
|
|
1083
1084
|
descriptions: {},
|
|
1084
1085
|
settings: {
|
|
@@ -1475,6 +1476,17 @@ var AREA_DESCRIPTIONS = {
|
|
|
1475
1476
|
};
|
|
1476
1477
|
|
|
1477
1478
|
// src/areas/detector.ts
|
|
1479
|
+
function isFileIgnored(filePath, config) {
|
|
1480
|
+
const ignorePatterns = config.ignore || [];
|
|
1481
|
+
if (ignorePatterns.length === 0) return false;
|
|
1482
|
+
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
1483
|
+
for (const pattern of ignorePatterns) {
|
|
1484
|
+
if (minimatch(normalizedPath, pattern, { dot: true })) {
|
|
1485
|
+
return true;
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
return false;
|
|
1489
|
+
}
|
|
1478
1490
|
function detectFileAreas(filePath, config) {
|
|
1479
1491
|
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
1480
1492
|
const matches = [];
|
|
@@ -1722,6 +1734,9 @@ function detectAreasInfo(cwd, filePaths) {
|
|
|
1722
1734
|
const areaSet = /* @__PURE__ */ new Set();
|
|
1723
1735
|
let unmappedCount = 0;
|
|
1724
1736
|
for (const filePath of filePaths) {
|
|
1737
|
+
if (isFileIgnored(filePath, config)) {
|
|
1738
|
+
continue;
|
|
1739
|
+
}
|
|
1725
1740
|
const areas2 = detectFileAreas(filePath, config);
|
|
1726
1741
|
if (areas2.length === 0) {
|
|
1727
1742
|
unmappedCount++;
|
|
@@ -1858,6 +1873,254 @@ ${output}`;
|
|
|
1858
1873
|
|
|
1859
1874
|
// src/commands/impact.ts
|
|
1860
1875
|
import skott2 from "skott";
|
|
1876
|
+
|
|
1877
|
+
// src/utils/similarity.ts
|
|
1878
|
+
function levenshteinDistance(a, b) {
|
|
1879
|
+
const matrix = [];
|
|
1880
|
+
for (let i = 0; i <= b.length; i++) {
|
|
1881
|
+
matrix[i] = [i];
|
|
1882
|
+
}
|
|
1883
|
+
for (let j = 0; j <= a.length; j++) {
|
|
1884
|
+
matrix[0][j] = j;
|
|
1885
|
+
}
|
|
1886
|
+
for (let i = 1; i <= b.length; i++) {
|
|
1887
|
+
for (let j = 1; j <= a.length; j++) {
|
|
1888
|
+
if (b.charAt(i - 1) === a.charAt(j - 1)) {
|
|
1889
|
+
matrix[i][j] = matrix[i - 1][j - 1];
|
|
1890
|
+
} else {
|
|
1891
|
+
matrix[i][j] = Math.min(
|
|
1892
|
+
matrix[i - 1][j - 1] + 1,
|
|
1893
|
+
// substituição
|
|
1894
|
+
matrix[i][j - 1] + 1,
|
|
1895
|
+
// inserção
|
|
1896
|
+
matrix[i - 1][j] + 1
|
|
1897
|
+
// deleção
|
|
1898
|
+
);
|
|
1899
|
+
}
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
return matrix[b.length][a.length];
|
|
1903
|
+
}
|
|
1904
|
+
function findSimilar(target, candidates, options = {}) {
|
|
1905
|
+
const {
|
|
1906
|
+
maxDistance = 3,
|
|
1907
|
+
limit = 5,
|
|
1908
|
+
normalize: normalize2 = true,
|
|
1909
|
+
extractKey = (item) => String(item)
|
|
1910
|
+
} = options;
|
|
1911
|
+
const normalizedTarget = normalize2 ? target.toLowerCase() : target;
|
|
1912
|
+
const scored = candidates.map((item) => {
|
|
1913
|
+
const key = extractKey(item);
|
|
1914
|
+
const normalizedKey = normalize2 ? key.toLowerCase() : key;
|
|
1915
|
+
const keyNoExt = normalizedKey.replace(/\.(tsx?|jsx?|mjs|cjs)$/, "");
|
|
1916
|
+
let score = Infinity;
|
|
1917
|
+
if (normalizedKey.includes(normalizedTarget) || keyNoExt.includes(normalizedTarget)) {
|
|
1918
|
+
score = 0;
|
|
1919
|
+
} else {
|
|
1920
|
+
score = levenshteinDistance(keyNoExt, normalizedTarget);
|
|
1921
|
+
}
|
|
1922
|
+
return { item, score };
|
|
1923
|
+
}).filter(({ score }) => score <= maxDistance).sort((a, b) => a.score - b.score).slice(0, limit);
|
|
1924
|
+
return scored.map(({ item }) => item);
|
|
1925
|
+
}
|
|
1926
|
+
function findBestMatch(target, candidates, extractKey = (item) => String(item)) {
|
|
1927
|
+
const similar = findSimilar(target, candidates, {
|
|
1928
|
+
maxDistance: 2,
|
|
1929
|
+
// Mais restritivo para "você quis dizer"
|
|
1930
|
+
limit: 1,
|
|
1931
|
+
extractKey
|
|
1932
|
+
});
|
|
1933
|
+
return similar.length > 0 ? similar[0] : null;
|
|
1934
|
+
}
|
|
1935
|
+
function extractFileName(filePath) {
|
|
1936
|
+
const fileName = filePath.split("/").pop() || filePath;
|
|
1937
|
+
return fileName.replace(/\.(tsx?|jsx?|mjs|cjs)$/, "");
|
|
1938
|
+
}
|
|
1939
|
+
|
|
1940
|
+
// src/utils/errors.ts
|
|
1941
|
+
var COMMAND_REFERENCE = {
|
|
1942
|
+
map: "Resumo do projeto (sem target)",
|
|
1943
|
+
areas: "Listar todas as \xE1reas (sem target)",
|
|
1944
|
+
area: "Arquivos de uma \xE1rea espec\xEDfica",
|
|
1945
|
+
suggest: "O que ler antes de editar",
|
|
1946
|
+
context: "API/assinaturas de um arquivo",
|
|
1947
|
+
impact: "Quem usa este arquivo",
|
|
1948
|
+
dead: "C\xF3digo morto (sem target)"
|
|
1949
|
+
};
|
|
1950
|
+
function getCommandReferenceSection(excludeCommand) {
|
|
1951
|
+
let out = `
|
|
1952
|
+
\u{1F4CC} Comandos \xFAteis:
|
|
1953
|
+
`;
|
|
1954
|
+
for (const [cmd, desc] of Object.entries(COMMAND_REFERENCE)) {
|
|
1955
|
+
if (cmd !== excludeCommand) {
|
|
1956
|
+
out += ` ai-tool ${cmd.padEnd(10)} ${desc}
|
|
1957
|
+
`;
|
|
1958
|
+
}
|
|
1959
|
+
}
|
|
1960
|
+
return out;
|
|
1961
|
+
}
|
|
1962
|
+
function formatFileNotFound(options) {
|
|
1963
|
+
const { target, allFiles, command } = options;
|
|
1964
|
+
const similarFiles = findSimilar(target, allFiles, {
|
|
1965
|
+
maxDistance: 3,
|
|
1966
|
+
limit: 5,
|
|
1967
|
+
extractKey: extractFileName
|
|
1968
|
+
});
|
|
1969
|
+
const bestMatch = findBestMatch(target, allFiles, extractFileName);
|
|
1970
|
+
let out = `
|
|
1971
|
+
\u274C Arquivo n\xE3o encontrado: "${target}"
|
|
1972
|
+
|
|
1973
|
+
`;
|
|
1974
|
+
out += `\u{1F4CA} Total de arquivos indexados: ${allFiles.length}
|
|
1975
|
+
|
|
1976
|
+
`;
|
|
1977
|
+
if (bestMatch) {
|
|
1978
|
+
out += `\u{1F4A1} Voc\xEA quis dizer?
|
|
1979
|
+
`;
|
|
1980
|
+
out += ` \u2192 ${bestMatch}
|
|
1981
|
+
|
|
1982
|
+
`;
|
|
1983
|
+
}
|
|
1984
|
+
if (similarFiles.length > 1) {
|
|
1985
|
+
out += `\u{1F4DD} Arquivos similares:
|
|
1986
|
+
`;
|
|
1987
|
+
for (const f of similarFiles) {
|
|
1988
|
+
if (f !== bestMatch) {
|
|
1989
|
+
out += ` \u2022 ${f}
|
|
1990
|
+
`;
|
|
1991
|
+
}
|
|
1992
|
+
}
|
|
1993
|
+
out += "\n";
|
|
1994
|
+
}
|
|
1995
|
+
out += `\u{1F4D6} Dicas:
|
|
1996
|
+
`;
|
|
1997
|
+
out += ` \u2022 Use o caminho relativo: src/components/Header.tsx
|
|
1998
|
+
`;
|
|
1999
|
+
out += ` \u2022 Ou apenas o nome do arquivo: Header
|
|
2000
|
+
`;
|
|
2001
|
+
out += ` \u2022 Verifique se o arquivo est\xE1 em uma pasta inclu\xEDda no scan
|
|
2002
|
+
`;
|
|
2003
|
+
if (command) {
|
|
2004
|
+
out += getCommandReferenceSection(command);
|
|
2005
|
+
}
|
|
2006
|
+
return out;
|
|
2007
|
+
}
|
|
2008
|
+
function formatAreaNotFound(options) {
|
|
2009
|
+
const { target, availableAreas } = options;
|
|
2010
|
+
const areaIds = availableAreas.map((a) => a.id);
|
|
2011
|
+
const bestMatchId = findBestMatch(target, areaIds);
|
|
2012
|
+
const similarAreaIds = findSimilar(target, areaIds, {
|
|
2013
|
+
maxDistance: 3,
|
|
2014
|
+
limit: 5
|
|
2015
|
+
});
|
|
2016
|
+
let out = `
|
|
2017
|
+
\u274C \xC1rea n\xE3o encontrada: "${target}"
|
|
2018
|
+
|
|
2019
|
+
`;
|
|
2020
|
+
if (bestMatchId) {
|
|
2021
|
+
out += `\u{1F4A1} Voc\xEA quis dizer?
|
|
2022
|
+
`;
|
|
2023
|
+
out += ` \u2192 ai-tool area ${bestMatchId}
|
|
2024
|
+
|
|
2025
|
+
`;
|
|
2026
|
+
}
|
|
2027
|
+
if (availableAreas.length > 0) {
|
|
2028
|
+
out += `\u{1F4E6} \xC1reas dispon\xEDveis:
|
|
2029
|
+
|
|
2030
|
+
`;
|
|
2031
|
+
if (similarAreaIds.length > 0 && !bestMatchId) {
|
|
2032
|
+
for (const id of similarAreaIds) {
|
|
2033
|
+
const area2 = availableAreas.find((a) => a.id === id);
|
|
2034
|
+
if (area2) {
|
|
2035
|
+
out += ` ${area2.id.padEnd(25)} ${area2.count} arquivos
|
|
2036
|
+
`;
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
out += ` ---
|
|
2040
|
+
`;
|
|
2041
|
+
}
|
|
2042
|
+
const areasToShow = similarAreaIds.length > 0 && !bestMatchId ? availableAreas.filter((a) => !similarAreaIds.includes(a.id)).slice(0, 10) : availableAreas.slice(0, 15);
|
|
2043
|
+
for (const { id, count } of areasToShow) {
|
|
2044
|
+
out += ` ${id.padEnd(25)} ${count} arquivos
|
|
2045
|
+
`;
|
|
2046
|
+
}
|
|
2047
|
+
const totalShown = similarAreaIds.length > 0 && !bestMatchId ? similarAreaIds.length + areasToShow.length : areasToShow.length;
|
|
2048
|
+
if (availableAreas.length > totalShown) {
|
|
2049
|
+
out += ` ... e mais ${availableAreas.length - totalShown}
|
|
2050
|
+
`;
|
|
2051
|
+
}
|
|
2052
|
+
out += `
|
|
2053
|
+
`;
|
|
2054
|
+
}
|
|
2055
|
+
out += `\u{1F4D6} Dicas:
|
|
2056
|
+
`;
|
|
2057
|
+
out += ` \u2022 Use o ID exato da \xE1rea (ex: ai-tool area auth)
|
|
2058
|
+
`;
|
|
2059
|
+
out += ` \u2022 Use 'ai-tool areas' para listar todas as \xE1reas
|
|
2060
|
+
`;
|
|
2061
|
+
out += ` \u2022 IDs s\xE3o case-sensitive (Auth \u2260 auth)
|
|
2062
|
+
`;
|
|
2063
|
+
out += `
|
|
2064
|
+
\u{1F4CC} Comandos relacionados:
|
|
2065
|
+
`;
|
|
2066
|
+
out += ` ai-tool areas Listar todas as \xE1reas
|
|
2067
|
+
`;
|
|
2068
|
+
out += ` ai-tool map Ver estrutura do projeto
|
|
2069
|
+
`;
|
|
2070
|
+
return out;
|
|
2071
|
+
}
|
|
2072
|
+
function formatMissingTarget(command) {
|
|
2073
|
+
let out = `
|
|
2074
|
+
\u274C Erro: par\xE2metro "target" \xE9 OBRIGAT\xD3RIO para o comando "${command}".
|
|
2075
|
+
|
|
2076
|
+
`;
|
|
2077
|
+
out += `\u{1F4DD} Exemplos:
|
|
2078
|
+
`;
|
|
2079
|
+
if (command === "area") {
|
|
2080
|
+
out += ` ai-tool area auth
|
|
2081
|
+
`;
|
|
2082
|
+
out += ` ai-tool area dashboard
|
|
2083
|
+
`;
|
|
2084
|
+
out += ` ai-tool area billing --type=hook
|
|
2085
|
+
|
|
2086
|
+
`;
|
|
2087
|
+
out += `\u{1F4A1} Use 'ai-tool areas' para listar todas as \xE1reas dispon\xEDveis.
|
|
2088
|
+
`;
|
|
2089
|
+
} else {
|
|
2090
|
+
out += ` ai-tool ${command} useAuth
|
|
2091
|
+
`;
|
|
2092
|
+
out += ` ai-tool ${command} Button.tsx
|
|
2093
|
+
`;
|
|
2094
|
+
out += ` ai-tool ${command} src/hooks/useAuth.ts
|
|
2095
|
+
`;
|
|
2096
|
+
}
|
|
2097
|
+
out += getCommandReferenceSection(command);
|
|
2098
|
+
return out;
|
|
2099
|
+
}
|
|
2100
|
+
function formatInvalidCommand(command) {
|
|
2101
|
+
const validCommands = Object.keys(COMMAND_REFERENCE);
|
|
2102
|
+
const bestMatch = findBestMatch(command, validCommands);
|
|
2103
|
+
let out = `
|
|
2104
|
+
\u274C Comando inv\xE1lido: "${command}"
|
|
2105
|
+
|
|
2106
|
+
`;
|
|
2107
|
+
if (bestMatch) {
|
|
2108
|
+
out += `\u{1F4A1} Voc\xEA quis dizer?
|
|
2109
|
+
`;
|
|
2110
|
+
out += ` \u2192 ai-tool ${bestMatch}
|
|
2111
|
+
|
|
2112
|
+
`;
|
|
2113
|
+
}
|
|
2114
|
+
out += `\u{1F4CC} Comandos dispon\xEDveis:
|
|
2115
|
+
`;
|
|
2116
|
+
for (const [cmd, desc] of Object.entries(COMMAND_REFERENCE)) {
|
|
2117
|
+
out += ` ai-tool ${cmd.padEnd(10)} ${desc}
|
|
2118
|
+
`;
|
|
2119
|
+
}
|
|
2120
|
+
return out;
|
|
2121
|
+
}
|
|
2122
|
+
|
|
2123
|
+
// src/commands/impact.ts
|
|
1861
2124
|
async function impact(target, options = {}) {
|
|
1862
2125
|
const cwd = options.cwd || process.cwd();
|
|
1863
2126
|
const format = options.format || "text";
|
|
@@ -2050,37 +2313,7 @@ function findTargetFile(target, allFiles) {
|
|
|
2050
2313
|
return null;
|
|
2051
2314
|
}
|
|
2052
2315
|
function formatNotFound(target, allFiles) {
|
|
2053
|
-
|
|
2054
|
-
const similar = allFiles.filter((f) => {
|
|
2055
|
-
const fileName = f.split("/").pop()?.toLowerCase() || "";
|
|
2056
|
-
const fileNameNoExt = fileName.replace(/\.(tsx?|jsx?|mjs|cjs)$/, "");
|
|
2057
|
-
return fileName.includes(normalizedTarget) || fileNameNoExt.includes(normalizedTarget) || levenshteinDistance(fileNameNoExt, normalizedTarget) <= 3;
|
|
2058
|
-
}).slice(0, 5);
|
|
2059
|
-
let out = `\u274C Arquivo n\xE3o encontrado no \xEDndice: "${target}"
|
|
2060
|
-
|
|
2061
|
-
`;
|
|
2062
|
-
out += `\u{1F4CA} Total de arquivos indexados: ${allFiles.length}
|
|
2063
|
-
|
|
2064
|
-
`;
|
|
2065
|
-
if (similar.length > 0) {
|
|
2066
|
-
out += `\u{1F4DD} Arquivos com nome similar:
|
|
2067
|
-
`;
|
|
2068
|
-
for (const s of similar) {
|
|
2069
|
-
out += ` \u2022 ${s}
|
|
2070
|
-
`;
|
|
2071
|
-
}
|
|
2072
|
-
out += `
|
|
2073
|
-
`;
|
|
2074
|
-
}
|
|
2075
|
-
out += `\u{1F4A1} Dicas:
|
|
2076
|
-
`;
|
|
2077
|
-
out += ` \u2022 Use o caminho relativo: src/components/Header.tsx
|
|
2078
|
-
`;
|
|
2079
|
-
out += ` \u2022 Ou apenas o nome do arquivo: Header
|
|
2080
|
-
`;
|
|
2081
|
-
out += ` \u2022 Verifique se o arquivo est\xE1 em uma pasta inclu\xEDda no scan
|
|
2082
|
-
`;
|
|
2083
|
-
return out;
|
|
2316
|
+
return formatFileNotFound({ target, allFiles, command: "impact" });
|
|
2084
2317
|
}
|
|
2085
2318
|
function toImpactFile(isDirect) {
|
|
2086
2319
|
return (path) => ({
|
|
@@ -2149,29 +2382,6 @@ function generateSuggestions(upstream, downstream, risks) {
|
|
|
2149
2382
|
}
|
|
2150
2383
|
return suggestions;
|
|
2151
2384
|
}
|
|
2152
|
-
function levenshteinDistance(a, b) {
|
|
2153
|
-
const matrix = [];
|
|
2154
|
-
for (let i = 0; i <= b.length; i++) {
|
|
2155
|
-
matrix[i] = [i];
|
|
2156
|
-
}
|
|
2157
|
-
for (let j = 0; j <= a.length; j++) {
|
|
2158
|
-
matrix[0][j] = j;
|
|
2159
|
-
}
|
|
2160
|
-
for (let i = 1; i <= b.length; i++) {
|
|
2161
|
-
for (let j = 1; j <= a.length; j++) {
|
|
2162
|
-
if (b.charAt(i - 1) === a.charAt(j - 1)) {
|
|
2163
|
-
matrix[i][j] = matrix[i - 1][j - 1];
|
|
2164
|
-
} else {
|
|
2165
|
-
matrix[i][j] = Math.min(
|
|
2166
|
-
matrix[i - 1][j - 1] + 1,
|
|
2167
|
-
matrix[i][j - 1] + 1,
|
|
2168
|
-
matrix[i - 1][j] + 1
|
|
2169
|
-
);
|
|
2170
|
-
}
|
|
2171
|
-
}
|
|
2172
|
-
}
|
|
2173
|
-
return matrix[b.length][a.length];
|
|
2174
|
-
}
|
|
2175
2385
|
|
|
2176
2386
|
// src/commands/suggest.ts
|
|
2177
2387
|
import skott3 from "skott";
|
|
@@ -2350,60 +2560,7 @@ function findTargetFile2(target, allFiles) {
|
|
|
2350
2560
|
return null;
|
|
2351
2561
|
}
|
|
2352
2562
|
function formatNotFound2(target, allFiles) {
|
|
2353
|
-
|
|
2354
|
-
const similar = allFiles.filter((f) => {
|
|
2355
|
-
const fileName = f.split("/").pop()?.toLowerCase() || "";
|
|
2356
|
-
const fileNameNoExt = fileName.replace(/\.(tsx?|jsx?|mjs|cjs)$/, "");
|
|
2357
|
-
return fileName.includes(normalizedTarget) || fileNameNoExt.includes(normalizedTarget) || levenshteinDistance2(fileNameNoExt, normalizedTarget) <= 3;
|
|
2358
|
-
}).slice(0, 5);
|
|
2359
|
-
let out = `Arquivo nao encontrado no indice: "${target}"
|
|
2360
|
-
|
|
2361
|
-
`;
|
|
2362
|
-
out += `Total de arquivos indexados: ${allFiles.length}
|
|
2363
|
-
|
|
2364
|
-
`;
|
|
2365
|
-
if (similar.length > 0) {
|
|
2366
|
-
out += `Arquivos com nome similar:
|
|
2367
|
-
`;
|
|
2368
|
-
for (const s of similar) {
|
|
2369
|
-
out += ` - ${s}
|
|
2370
|
-
`;
|
|
2371
|
-
}
|
|
2372
|
-
out += `
|
|
2373
|
-
`;
|
|
2374
|
-
}
|
|
2375
|
-
out += `Dicas:
|
|
2376
|
-
`;
|
|
2377
|
-
out += ` - Use o caminho relativo: src/components/Header.tsx
|
|
2378
|
-
`;
|
|
2379
|
-
out += ` - Ou apenas o nome do arquivo: Header
|
|
2380
|
-
`;
|
|
2381
|
-
out += ` - Verifique se o arquivo esta em uma pasta incluida no scan
|
|
2382
|
-
`;
|
|
2383
|
-
return out;
|
|
2384
|
-
}
|
|
2385
|
-
function levenshteinDistance2(a, b) {
|
|
2386
|
-
const matrix = [];
|
|
2387
|
-
for (let i = 0; i <= b.length; i++) {
|
|
2388
|
-
matrix[i] = [i];
|
|
2389
|
-
}
|
|
2390
|
-
for (let j = 0; j <= a.length; j++) {
|
|
2391
|
-
matrix[0][j] = j;
|
|
2392
|
-
}
|
|
2393
|
-
for (let i = 1; i <= b.length; i++) {
|
|
2394
|
-
for (let j = 1; j <= a.length; j++) {
|
|
2395
|
-
if (b.charAt(i - 1) === a.charAt(j - 1)) {
|
|
2396
|
-
matrix[i][j] = matrix[i - 1][j - 1];
|
|
2397
|
-
} else {
|
|
2398
|
-
matrix[i][j] = Math.min(
|
|
2399
|
-
matrix[i - 1][j - 1] + 1,
|
|
2400
|
-
matrix[i][j - 1] + 1,
|
|
2401
|
-
matrix[i - 1][j] + 1
|
|
2402
|
-
);
|
|
2403
|
-
}
|
|
2404
|
-
}
|
|
2405
|
-
}
|
|
2406
|
-
return matrix[b.length][a.length];
|
|
2563
|
+
return formatFileNotFound({ target, allFiles, command: "suggest" });
|
|
2407
2564
|
}
|
|
2408
2565
|
|
|
2409
2566
|
// src/commands/context.ts
|
|
@@ -2725,61 +2882,8 @@ function shouldIgnore(name) {
|
|
|
2725
2882
|
return ignoredDirs.includes(name) || name.startsWith(".");
|
|
2726
2883
|
}
|
|
2727
2884
|
function formatNotFound3(target, cwd) {
|
|
2728
|
-
const normalizedTarget = target.toLowerCase();
|
|
2729
2885
|
const allFiles = getAllCodeFiles(cwd);
|
|
2730
|
-
|
|
2731
|
-
const fileName = basename(f).toLowerCase();
|
|
2732
|
-
const fileNameNoExt = fileName.replace(/\.(tsx?|jsx?|mjs|cjs)$/, "");
|
|
2733
|
-
return fileName.includes(normalizedTarget) || fileNameNoExt.includes(normalizedTarget) || levenshteinDistance3(fileNameNoExt, normalizedTarget) <= 3;
|
|
2734
|
-
}).slice(0, 5);
|
|
2735
|
-
let out = `Arquivo nao encontrado: "${target}"
|
|
2736
|
-
|
|
2737
|
-
`;
|
|
2738
|
-
out += `Total de arquivos no projeto: ${allFiles.length}
|
|
2739
|
-
|
|
2740
|
-
`;
|
|
2741
|
-
if (similar.length > 0) {
|
|
2742
|
-
out += `Arquivos com nome similar:
|
|
2743
|
-
`;
|
|
2744
|
-
for (const s of similar) {
|
|
2745
|
-
out += ` - ${s}
|
|
2746
|
-
`;
|
|
2747
|
-
}
|
|
2748
|
-
out += `
|
|
2749
|
-
`;
|
|
2750
|
-
}
|
|
2751
|
-
out += `Dicas:
|
|
2752
|
-
`;
|
|
2753
|
-
out += ` - Use o caminho relativo: src/components/Header.tsx
|
|
2754
|
-
`;
|
|
2755
|
-
out += ` - Ou apenas o nome do arquivo: Header
|
|
2756
|
-
`;
|
|
2757
|
-
out += ` - Verifique se o arquivo existe e e um arquivo .ts/.tsx/.js/.jsx
|
|
2758
|
-
`;
|
|
2759
|
-
return out;
|
|
2760
|
-
}
|
|
2761
|
-
function levenshteinDistance3(a, b) {
|
|
2762
|
-
const matrix = [];
|
|
2763
|
-
for (let i = 0; i <= b.length; i++) {
|
|
2764
|
-
matrix[i] = [i];
|
|
2765
|
-
}
|
|
2766
|
-
for (let j = 0; j <= a.length; j++) {
|
|
2767
|
-
matrix[0][j] = j;
|
|
2768
|
-
}
|
|
2769
|
-
for (let i = 1; i <= b.length; i++) {
|
|
2770
|
-
for (let j = 1; j <= a.length; j++) {
|
|
2771
|
-
if (b.charAt(i - 1) === a.charAt(j - 1)) {
|
|
2772
|
-
matrix[i][j] = matrix[i - 1][j - 1];
|
|
2773
|
-
} else {
|
|
2774
|
-
matrix[i][j] = Math.min(
|
|
2775
|
-
matrix[i - 1][j - 1] + 1,
|
|
2776
|
-
matrix[i][j - 1] + 1,
|
|
2777
|
-
matrix[i - 1][j] + 1
|
|
2778
|
-
);
|
|
2779
|
-
}
|
|
2780
|
-
}
|
|
2781
|
-
}
|
|
2782
|
-
return matrix[b.length][a.length];
|
|
2886
|
+
return formatFileNotFound({ target, allFiles, command: "context" });
|
|
2783
2887
|
}
|
|
2784
2888
|
|
|
2785
2889
|
// src/commands/areas.ts
|
|
@@ -2804,9 +2908,10 @@ async function areas(options = {}) {
|
|
|
2804
2908
|
try {
|
|
2805
2909
|
const config = readConfig(cwd);
|
|
2806
2910
|
const allFiles = getAllCodeFiles2(cwd);
|
|
2911
|
+
const filteredFiles = allFiles.filter((filePath) => !isFileIgnored(filePath, config));
|
|
2807
2912
|
const areaMap = /* @__PURE__ */ new Map();
|
|
2808
2913
|
const unmapped = [];
|
|
2809
|
-
for (const filePath of
|
|
2914
|
+
for (const filePath of filteredFiles) {
|
|
2810
2915
|
const category = detectCategory(filePath);
|
|
2811
2916
|
const areas2 = detectFileAreas(filePath, config);
|
|
2812
2917
|
let description = getFileDescription(cwd, filePath);
|
|
@@ -2854,7 +2959,7 @@ async function areas(options = {}) {
|
|
|
2854
2959
|
unmapped,
|
|
2855
2960
|
summary: {
|
|
2856
2961
|
totalAreas: detectedAreas.length,
|
|
2857
|
-
totalFiles:
|
|
2962
|
+
totalFiles: filteredFiles.length,
|
|
2858
2963
|
unmappedCount: unmapped.length
|
|
2859
2964
|
}
|
|
2860
2965
|
};
|
|
@@ -2921,9 +3026,10 @@ async function area(target, options = {}) {
|
|
|
2921
3026
|
try {
|
|
2922
3027
|
const config = readConfig(cwd);
|
|
2923
3028
|
const allFiles = getAllCodeFiles3(cwd);
|
|
3029
|
+
const filteredFiles = allFiles.filter((filePath) => !isFileIgnored(filePath, config));
|
|
2924
3030
|
const areaFiles = [];
|
|
2925
3031
|
const targetLower = target.toLowerCase();
|
|
2926
|
-
for (const filePath of
|
|
3032
|
+
for (const filePath of filteredFiles) {
|
|
2927
3033
|
const fileAreas = detectFileAreas(filePath, config);
|
|
2928
3034
|
const belongsToArea = fileAreas.some(
|
|
2929
3035
|
(a) => a.toLowerCase() === targetLower || a.toLowerCase().includes(targetLower)
|
|
@@ -2945,8 +3051,8 @@ async function area(target, options = {}) {
|
|
|
2945
3051
|
}
|
|
2946
3052
|
}
|
|
2947
3053
|
if (areaFiles.length === 0) {
|
|
2948
|
-
const availableAreas = getAvailableAreas(
|
|
2949
|
-
return
|
|
3054
|
+
const availableAreas = getAvailableAreas(filteredFiles, config);
|
|
3055
|
+
return formatAreaNotFound2(target, availableAreas);
|
|
2950
3056
|
}
|
|
2951
3057
|
const byCategory = {};
|
|
2952
3058
|
const categories = {};
|
|
@@ -2960,7 +3066,7 @@ async function area(target, options = {}) {
|
|
|
2960
3066
|
for (const cat of Object.keys(byCategory)) {
|
|
2961
3067
|
byCategory[cat].sort((a, b) => a.path.localeCompare(b.path));
|
|
2962
3068
|
}
|
|
2963
|
-
const realAreaId = findRealAreaId(target,
|
|
3069
|
+
const realAreaId = findRealAreaId(target, filteredFiles, config);
|
|
2964
3070
|
const detectedArea = {
|
|
2965
3071
|
id: realAreaId || target,
|
|
2966
3072
|
name: getAreaName(realAreaId || target, config),
|
|
@@ -3013,33 +3119,8 @@ function getAvailableAreas(allFiles, config) {
|
|
|
3013
3119
|
}
|
|
3014
3120
|
return [...areaCounts.entries()].map(([id, count]) => ({ id, count })).sort((a, b) => b.count - a.count);
|
|
3015
3121
|
}
|
|
3016
|
-
function
|
|
3017
|
-
|
|
3018
|
-
\u274C \xC1rea n\xE3o encontrada: "${target}"
|
|
3019
|
-
|
|
3020
|
-
`;
|
|
3021
|
-
if (availableAreas.length > 0) {
|
|
3022
|
-
out += `\u{1F4E6} \xC1reas dispon\xEDveis:
|
|
3023
|
-
|
|
3024
|
-
`;
|
|
3025
|
-
for (const { id, count } of availableAreas.slice(0, 15)) {
|
|
3026
|
-
out += ` ${id.padEnd(25)} ${count} arquivos
|
|
3027
|
-
`;
|
|
3028
|
-
}
|
|
3029
|
-
if (availableAreas.length > 15) {
|
|
3030
|
-
out += ` ... e mais ${availableAreas.length - 15}
|
|
3031
|
-
`;
|
|
3032
|
-
}
|
|
3033
|
-
out += `
|
|
3034
|
-
`;
|
|
3035
|
-
}
|
|
3036
|
-
out += `\u{1F4A1} Dicas:
|
|
3037
|
-
`;
|
|
3038
|
-
out += ` - Use o ID exato da \xE1rea (ex: ai-tool area auth)
|
|
3039
|
-
`;
|
|
3040
|
-
out += ` - Use 'ai-tool areas' para listar todas as \xE1reas
|
|
3041
|
-
`;
|
|
3042
|
-
return out;
|
|
3122
|
+
function formatAreaNotFound2(target, availableAreas) {
|
|
3123
|
+
return formatAreaNotFound({ target, availableAreas });
|
|
3043
3124
|
}
|
|
3044
3125
|
function getAllCodeFiles3(dir, files = [], baseDir = dir) {
|
|
3045
3126
|
try {
|
|
@@ -3261,6 +3342,15 @@ export {
|
|
|
3261
3342
|
map,
|
|
3262
3343
|
dead,
|
|
3263
3344
|
deadFix,
|
|
3345
|
+
levenshteinDistance,
|
|
3346
|
+
findSimilar,
|
|
3347
|
+
findBestMatch,
|
|
3348
|
+
extractFileName,
|
|
3349
|
+
COMMAND_REFERENCE,
|
|
3350
|
+
formatFileNotFound,
|
|
3351
|
+
formatAreaNotFound,
|
|
3352
|
+
formatMissingTarget,
|
|
3353
|
+
formatInvalidCommand,
|
|
3264
3354
|
impact,
|
|
3265
3355
|
suggest,
|
|
3266
3356
|
context,
|
package/dist/cli.js
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
impact,
|
|
11
11
|
map,
|
|
12
12
|
suggest
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-PHTWZ2JT.js";
|
|
14
14
|
|
|
15
15
|
// src/cli.ts
|
|
16
16
|
var HELP = `
|
|
@@ -87,7 +87,7 @@ async function main() {
|
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
if (flags.mcp) {
|
|
90
|
-
const { startMcpServer } = await import("./server-
|
|
90
|
+
const { startMcpServer } = await import("./server-NIEAOPLJ.js");
|
|
91
91
|
await startMcpServer();
|
|
92
92
|
return;
|
|
93
93
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -169,6 +169,7 @@ interface AreaConfig {
|
|
|
169
169
|
interface AreasConfigFile {
|
|
170
170
|
$schema?: string;
|
|
171
171
|
version: string;
|
|
172
|
+
ignore?: string[];
|
|
172
173
|
areas: Record<string, AreaConfig>;
|
|
173
174
|
descriptions?: Record<string, string>;
|
|
174
175
|
settings?: {
|
|
@@ -330,6 +331,139 @@ declare function isEntryPoint(filePath: string): boolean;
|
|
|
330
331
|
*/
|
|
331
332
|
declare function isCodeFile(filePath: string): boolean;
|
|
332
333
|
|
|
334
|
+
/**
|
|
335
|
+
* Funções de similaridade de strings
|
|
336
|
+
*
|
|
337
|
+
* Usa algoritmo de Levenshtein para calcular distância entre strings
|
|
338
|
+
* e encontrar candidatos similares para sugestões "você quis dizer?"
|
|
339
|
+
*/
|
|
340
|
+
/**
|
|
341
|
+
* Calcula a distância de Levenshtein entre duas strings
|
|
342
|
+
*
|
|
343
|
+
* A distância representa o número mínimo de operações (inserção, deleção, substituição)
|
|
344
|
+
* necessárias para transformar uma string na outra.
|
|
345
|
+
*
|
|
346
|
+
* @param a - Primeira string
|
|
347
|
+
* @param b - Segunda string
|
|
348
|
+
* @returns Número de edições necessárias
|
|
349
|
+
*
|
|
350
|
+
* @example
|
|
351
|
+
* levenshteinDistance('auth', 'auht') // 2 (troca de posição = 2 substituições)
|
|
352
|
+
* levenshteinDistance('auth', 'auth') // 0 (iguais)
|
|
353
|
+
* levenshteinDistance('auth', 'auths') // 1 (1 inserção)
|
|
354
|
+
*/
|
|
355
|
+
declare function levenshteinDistance(a: string, b: string): number;
|
|
356
|
+
/**
|
|
357
|
+
* Opções para busca de itens similares
|
|
358
|
+
*/
|
|
359
|
+
interface FindSimilarOptions<T> {
|
|
360
|
+
/** Distância máxima de Levenshtein para considerar similar (default: 3) */
|
|
361
|
+
maxDistance?: number;
|
|
362
|
+
/** Número máximo de resultados (default: 5) */
|
|
363
|
+
limit?: number;
|
|
364
|
+
/** Normalizar para lowercase antes de comparar (default: true) */
|
|
365
|
+
normalize?: boolean;
|
|
366
|
+
/** Função para extrair a chave de comparação de cada item */
|
|
367
|
+
extractKey?: (item: T) => string;
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Encontra itens similares a um target
|
|
371
|
+
*
|
|
372
|
+
* Usa Levenshtein distance e match de substring para encontrar candidatos.
|
|
373
|
+
* Substring match tem prioridade (score 0), seguido por Levenshtein.
|
|
374
|
+
*
|
|
375
|
+
* @param target - Termo buscado
|
|
376
|
+
* @param candidates - Lista de candidatos
|
|
377
|
+
* @param options - Configurações opcionais
|
|
378
|
+
* @returns Lista de candidatos similares, ordenados por relevância
|
|
379
|
+
*
|
|
380
|
+
* @example
|
|
381
|
+
* const areas = ['auth', 'dashboard', 'stripe'];
|
|
382
|
+
* findSimilar('auht', areas) // ['auth']
|
|
383
|
+
* findSimilar('dash', areas) // ['dashboard']
|
|
384
|
+
*/
|
|
385
|
+
declare function findSimilar<T>(target: string, candidates: T[], options?: FindSimilarOptions<T>): T[];
|
|
386
|
+
/**
|
|
387
|
+
* Encontra o melhor match para sugestão "você quis dizer?"
|
|
388
|
+
*
|
|
389
|
+
* Mais restritivo que findSimilar (maxDistance: 2) para evitar
|
|
390
|
+
* sugestões incorretas.
|
|
391
|
+
*
|
|
392
|
+
* @param target - Termo buscado
|
|
393
|
+
* @param candidates - Lista de candidatos
|
|
394
|
+
* @param extractKey - Função para extrair chave de comparação
|
|
395
|
+
* @returns Melhor match ou null se não houver sugestão confiável
|
|
396
|
+
*
|
|
397
|
+
* @example
|
|
398
|
+
* findBestMatch('auht', ['auth', 'dashboard']) // 'auth'
|
|
399
|
+
* findBestMatch('xyz', ['auth', 'dashboard']) // null
|
|
400
|
+
*/
|
|
401
|
+
declare function findBestMatch<T>(target: string, candidates: T[], extractKey?: (item: T) => string): T | null;
|
|
402
|
+
/**
|
|
403
|
+
* Extrai nome do arquivo de um caminho (sem extensão)
|
|
404
|
+
*
|
|
405
|
+
* Útil para comparar arquivos ignorando caminho e extensão.
|
|
406
|
+
*
|
|
407
|
+
* @param filePath - Caminho do arquivo
|
|
408
|
+
* @returns Nome do arquivo sem extensão
|
|
409
|
+
*
|
|
410
|
+
* @example
|
|
411
|
+
* extractFileName('src/hooks/useAuth.ts') // 'useAuth'
|
|
412
|
+
* extractFileName('Button.tsx') // 'Button'
|
|
413
|
+
*/
|
|
414
|
+
declare function extractFileName(filePath: string): string;
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Formatadores de mensagens de erro com sugestões inteligentes
|
|
418
|
+
*
|
|
419
|
+
* Todas as funções retornam strings formatadas para exibição,
|
|
420
|
+
* com sugestões "você quis dizer?" e referência de comandos.
|
|
421
|
+
*/
|
|
422
|
+
/**
|
|
423
|
+
* Referência rápida de comandos disponíveis
|
|
424
|
+
*/
|
|
425
|
+
declare const COMMAND_REFERENCE: Record<string, string>;
|
|
426
|
+
interface FormatFileNotFoundOptions {
|
|
427
|
+
/** Termo buscado */
|
|
428
|
+
target: string;
|
|
429
|
+
/** Lista de todos os arquivos disponíveis */
|
|
430
|
+
allFiles: string[];
|
|
431
|
+
/** Comando que gerou o erro (para contexto) */
|
|
432
|
+
command?: string;
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Formata mensagem de arquivo não encontrado
|
|
436
|
+
*
|
|
437
|
+
* Inclui sugestões de arquivos similares e referência de comandos.
|
|
438
|
+
*/
|
|
439
|
+
declare function formatFileNotFound(options: FormatFileNotFoundOptions): string;
|
|
440
|
+
interface AreaInfo {
|
|
441
|
+
/** ID da área */
|
|
442
|
+
id: string;
|
|
443
|
+
/** Número de arquivos na área */
|
|
444
|
+
count: number;
|
|
445
|
+
}
|
|
446
|
+
interface FormatAreaNotFoundOptions {
|
|
447
|
+
/** Termo buscado */
|
|
448
|
+
target: string;
|
|
449
|
+
/** Lista de áreas disponíveis */
|
|
450
|
+
availableAreas: AreaInfo[];
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Formata mensagem de área não encontrada
|
|
454
|
+
*
|
|
455
|
+
* Inclui sugestões de áreas similares usando Levenshtein.
|
|
456
|
+
*/
|
|
457
|
+
declare function formatAreaNotFound(options: FormatAreaNotFoundOptions): string;
|
|
458
|
+
/**
|
|
459
|
+
* Formata mensagem de target obrigatório faltando
|
|
460
|
+
*/
|
|
461
|
+
declare function formatMissingTarget(command: string): string;
|
|
462
|
+
/**
|
|
463
|
+
* Formata mensagem de comando inválido
|
|
464
|
+
*/
|
|
465
|
+
declare function formatInvalidCommand(command: string): string;
|
|
466
|
+
|
|
333
467
|
/**
|
|
334
468
|
* Utilitários para detecção de Firebase Cloud Functions
|
|
335
469
|
*
|
|
@@ -516,4 +650,4 @@ declare const AREA_DESCRIPTIONS: Record<string, string>;
|
|
|
516
650
|
|
|
517
651
|
declare const VERSION: string;
|
|
518
652
|
|
|
519
|
-
export { AREA_DESCRIPTIONS, AREA_NAMES, type AreaConfig, type AreaDetailResult, type AreaFile, type AreaOptions, type AreasConfigFile, type AreasOptions, type AreasResult, type CommandOptions, type ContextOptions, type ContextResult, type DeadFile, type DeadOptions, type DeadResult, type DetectedArea, FOLDER_PATTERNS, type FileCategory, type FileInfo, type FolderStats, type FunctionInfo, type ImpactFile, type ImpactOptions, type ImpactResult, type ImportInfo, KEYWORD_PATTERNS, type MapOptions, type MapResult, type OutputFormat, type ParamInfo, type RiskInfo, type SuggestOptions, type SuggestResult, type Suggestion, type SuggestionPriority, type TypeInfo, type TypeKind, VERSION, area, areas, areasInit, categoryIcons, clearFirebaseCache, configExists, context, dead, deadFix, detectCategory, detectFileAreas, filterCloudFunctionsFalsePositives, getAreaDescription, getAreaName, getCacheDir, getFileDescription, hasFirebaseFunctions, impact, inferFileDescription, invalidateCache, isCacheValid, isCodeFile, isEntryPoint, isExportedCloudFunction, isFirebaseProject, map, readConfig, removeArea, setArea, setFileDescription, suggest, writeConfig };
|
|
653
|
+
export { AREA_DESCRIPTIONS, AREA_NAMES, type AreaConfig, type AreaDetailResult, type AreaFile, type AreaInfo, type AreaOptions, type AreasConfigFile, type AreasOptions, type AreasResult, COMMAND_REFERENCE, type CommandOptions, type ContextOptions, type ContextResult, type DeadFile, type DeadOptions, type DeadResult, type DetectedArea, FOLDER_PATTERNS, type FileCategory, type FileInfo, type FindSimilarOptions, type FolderStats, type FormatAreaNotFoundOptions, type FormatFileNotFoundOptions, type FunctionInfo, type ImpactFile, type ImpactOptions, type ImpactResult, type ImportInfo, KEYWORD_PATTERNS, type MapOptions, type MapResult, type OutputFormat, type ParamInfo, type RiskInfo, type SuggestOptions, type SuggestResult, type Suggestion, type SuggestionPriority, type TypeInfo, type TypeKind, VERSION, area, areas, areasInit, categoryIcons, clearFirebaseCache, configExists, context, dead, deadFix, detectCategory, detectFileAreas, extractFileName, filterCloudFunctionsFalsePositives, findBestMatch, findSimilar, formatAreaNotFound, formatFileNotFound, formatInvalidCommand, formatMissingTarget, getAreaDescription, getAreaName, getCacheDir, getFileDescription, hasFirebaseFunctions, impact, inferFileDescription, invalidateCache, isCacheValid, isCodeFile, isEntryPoint, isExportedCloudFunction, isFirebaseProject, levenshteinDistance, map, readConfig, removeArea, setArea, setFileDescription, suggest, writeConfig };
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AREA_DESCRIPTIONS,
|
|
3
3
|
AREA_NAMES,
|
|
4
|
+
COMMAND_REFERENCE,
|
|
4
5
|
FOLDER_PATTERNS,
|
|
5
6
|
KEYWORD_PATTERNS,
|
|
6
7
|
VERSION,
|
|
@@ -15,7 +16,14 @@ import {
|
|
|
15
16
|
deadFix,
|
|
16
17
|
detectCategory,
|
|
17
18
|
detectFileAreas,
|
|
19
|
+
extractFileName,
|
|
18
20
|
filterCloudFunctionsFalsePositives,
|
|
21
|
+
findBestMatch,
|
|
22
|
+
findSimilar,
|
|
23
|
+
formatAreaNotFound,
|
|
24
|
+
formatFileNotFound,
|
|
25
|
+
formatInvalidCommand,
|
|
26
|
+
formatMissingTarget,
|
|
19
27
|
getAreaDescription,
|
|
20
28
|
getAreaName,
|
|
21
29
|
getCacheDir,
|
|
@@ -29,6 +37,7 @@ import {
|
|
|
29
37
|
isEntryPoint,
|
|
30
38
|
isExportedCloudFunction,
|
|
31
39
|
isFirebaseProject,
|
|
40
|
+
levenshteinDistance,
|
|
32
41
|
map,
|
|
33
42
|
readConfig,
|
|
34
43
|
removeArea,
|
|
@@ -36,10 +45,11 @@ import {
|
|
|
36
45
|
setFileDescription,
|
|
37
46
|
suggest,
|
|
38
47
|
writeConfig
|
|
39
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-PHTWZ2JT.js";
|
|
40
49
|
export {
|
|
41
50
|
AREA_DESCRIPTIONS,
|
|
42
51
|
AREA_NAMES,
|
|
52
|
+
COMMAND_REFERENCE,
|
|
43
53
|
FOLDER_PATTERNS,
|
|
44
54
|
KEYWORD_PATTERNS,
|
|
45
55
|
VERSION,
|
|
@@ -54,7 +64,14 @@ export {
|
|
|
54
64
|
deadFix,
|
|
55
65
|
detectCategory,
|
|
56
66
|
detectFileAreas,
|
|
67
|
+
extractFileName,
|
|
57
68
|
filterCloudFunctionsFalsePositives,
|
|
69
|
+
findBestMatch,
|
|
70
|
+
findSimilar,
|
|
71
|
+
formatAreaNotFound,
|
|
72
|
+
formatFileNotFound,
|
|
73
|
+
formatInvalidCommand,
|
|
74
|
+
formatMissingTarget,
|
|
58
75
|
getAreaDescription,
|
|
59
76
|
getAreaName,
|
|
60
77
|
getCacheDir,
|
|
@@ -68,6 +85,7 @@ export {
|
|
|
68
85
|
isEntryPoint,
|
|
69
86
|
isExportedCloudFunction,
|
|
70
87
|
isFirebaseProject,
|
|
88
|
+
levenshteinDistance,
|
|
71
89
|
map,
|
|
72
90
|
readConfig,
|
|
73
91
|
removeArea,
|
package/package.json
CHANGED