ai-spec-dev 0.29.0 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -3
- package/RELEASE_LOG.md +24 -0
- package/core/error-feedback.ts +102 -2
- package/core/frontend-context-loader.ts +117 -20
- package/dist/cli/index.js +113 -9
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +113 -9
- package/dist/cli/index.mjs.map +1 -1
- package/dist/index.js +57 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +57 -8
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/purpose.md +29 -4
package/dist/index.js
CHANGED
|
@@ -4973,6 +4973,41 @@ async function loadDslForSpec(specFilePath) {
|
|
|
4973
4973
|
// core/frontend-context-loader.ts
|
|
4974
4974
|
var fs7 = __toESM(require("fs-extra"));
|
|
4975
4975
|
var path5 = __toESM(require("path"));
|
|
4976
|
+
function parseImportStatements(content) {
|
|
4977
|
+
const stripped = content.replace(/\/\*[\s\S]*?\*\//g, (m) => "\n".repeat(m.split("\n").length - 1));
|
|
4978
|
+
const collapsed = stripped.replace(/import\s*\{[^}]*\}/gs, (m) => m.replace(/\n\s*/g, " "));
|
|
4979
|
+
const results = [];
|
|
4980
|
+
for (const rawLine of collapsed.split("\n")) {
|
|
4981
|
+
const line = rawLine.trim();
|
|
4982
|
+
if (!line) continue;
|
|
4983
|
+
if (/^import\s+type\b/.test(line)) continue;
|
|
4984
|
+
if (!line.startsWith("import")) continue;
|
|
4985
|
+
const match = line.match(/^(import\s+([\s\S]+?)\s+from\s+['"]([^'"]+)['"])/);
|
|
4986
|
+
if (!match) continue;
|
|
4987
|
+
results.push({
|
|
4988
|
+
line: match[1],
|
|
4989
|
+
modulePath: match[3],
|
|
4990
|
+
specifiers: match[2]
|
|
4991
|
+
});
|
|
4992
|
+
}
|
|
4993
|
+
return results;
|
|
4994
|
+
}
|
|
4995
|
+
var HTTP_MODULE_PATTERNS = [
|
|
4996
|
+
// Project path aliases (@/, @@/, ~/, #/) — catches '@/utils/request', '~/lib/http', etc.
|
|
4997
|
+
/^(?:@{1,2}|~|#)[/\\]/,
|
|
4998
|
+
// Well-known HTTP libraries (exact name match)
|
|
4999
|
+
/^(?:axios|ky(?:-universal)?|undici|node-fetch|cross-fetch|got|superagent|alova|openapi-fetch)$/,
|
|
5000
|
+
// Relative imports whose path contains an HTTP-utility keyword
|
|
5001
|
+
/\.{1,2}\/[^'"]*(?:http|request|fetch|client|api)[^'"]*/
|
|
5002
|
+
];
|
|
5003
|
+
function findHttpClientImport(content) {
|
|
5004
|
+
for (const stmt of parseImportStatements(content)) {
|
|
5005
|
+
if (HTTP_MODULE_PATTERNS.some((p) => p.test(stmt.modulePath))) {
|
|
5006
|
+
return stmt.line;
|
|
5007
|
+
}
|
|
5008
|
+
}
|
|
5009
|
+
return void 0;
|
|
5010
|
+
}
|
|
4976
5011
|
var STATE_MANAGEMENT_LIBS = [
|
|
4977
5012
|
"zustand",
|
|
4978
5013
|
"redux",
|
|
@@ -5161,13 +5196,12 @@ ${preview}`);
|
|
|
5161
5196
|
} catch {
|
|
5162
5197
|
}
|
|
5163
5198
|
}
|
|
5164
|
-
const httpImportRegex = /^import(?!\s+type)\s+(?:[\w*]+|\{[^}]+\})\s+from\s+['"]((?:@{1,2}|~|#)[/\\][^'"]+|\.{1,2}\/[^'"]*(?:http|request|fetch|client|api)[^'"]*|axios|ky(?:-universal)?|undici|node-fetch|cross-fetch|got|superagent|alova|openapi-fetch)['"]/im;
|
|
5165
5199
|
for (const relPath of ctx.existingApiFiles.slice(0, 5)) {
|
|
5166
5200
|
try {
|
|
5167
5201
|
const content = await fs7.readFile(path5.join(projectRoot, relPath), "utf-8");
|
|
5168
|
-
const
|
|
5169
|
-
if (
|
|
5170
|
-
ctx.httpClientImport =
|
|
5202
|
+
const found = findHttpClientImport(content);
|
|
5203
|
+
if (found) {
|
|
5204
|
+
ctx.httpClientImport = found;
|
|
5171
5205
|
break;
|
|
5172
5206
|
}
|
|
5173
5207
|
} catch {
|
|
@@ -5297,13 +5331,28 @@ async function extractRouteModuleContext(projectRoot, ctx) {
|
|
|
5297
5331
|
moduleFiles.push(...files);
|
|
5298
5332
|
}
|
|
5299
5333
|
if (moduleFiles.length === 0) return;
|
|
5300
|
-
const
|
|
5334
|
+
const dynamicLayoutRegex = /const\s+Layout\s*=\s*(?:defineAsyncComponent\s*\(\s*)?(?:\(\s*\))?\s*(?:=>|function[^(]*\()\s*(?:[^)]*\))?\s*(?:=>)?\s*import\s*\(\s*['"]([^'"]+)['"]\s*\)/;
|
|
5301
5335
|
for (const relPath of moduleFiles) {
|
|
5302
5336
|
try {
|
|
5303
5337
|
const content = await fs7.readFile(path5.join(projectRoot, relPath), "utf-8");
|
|
5304
|
-
const
|
|
5305
|
-
|
|
5306
|
-
|
|
5338
|
+
const stmts = parseImportStatements(content);
|
|
5339
|
+
const staticLayout = stmts.find(
|
|
5340
|
+
(s) => /\bLayout\b/.test(s.specifiers) && /layout/i.test(s.modulePath)
|
|
5341
|
+
);
|
|
5342
|
+
if (staticLayout) {
|
|
5343
|
+
ctx.layoutImport = staticLayout.line;
|
|
5344
|
+
const preview = content.split("\n").slice(0, 100).join("\n");
|
|
5345
|
+
ctx.routeModuleExample = { path: relPath, content: preview };
|
|
5346
|
+
break;
|
|
5347
|
+
}
|
|
5348
|
+
const singleLine = content.replace(
|
|
5349
|
+
/const\s+Layout\s*=[\s\S]*?import\s*\([^)]+\)/gm,
|
|
5350
|
+
(m) => m.replace(/\n\s*/g, " ")
|
|
5351
|
+
);
|
|
5352
|
+
const dynMatch = singleLine.match(dynamicLayoutRegex);
|
|
5353
|
+
if (dynMatch) {
|
|
5354
|
+
const constMatch = content.match(/^const\s+Layout\s*=.+/m);
|
|
5355
|
+
ctx.layoutImport = constMatch ? constMatch[0].trim() : dynMatch[0].trim();
|
|
5307
5356
|
const preview = content.split("\n").slice(0, 100).join("\n");
|
|
5308
5357
|
ctx.routeModuleExample = { path: relPath, content: preview };
|
|
5309
5358
|
break;
|