substrate-ai 0.19.46 → 0.19.48
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/dist/cli/index.js +141 -13
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -16,7 +16,7 @@ import { dirname, join, resolve } from "path";
|
|
|
16
16
|
import { access, mkdir, readFile, writeFile } from "fs/promises";
|
|
17
17
|
import yaml from "js-yaml";
|
|
18
18
|
import { existsSync, readFileSync } from "node:fs";
|
|
19
|
-
import { spawn } from "node:child_process";
|
|
19
|
+
import { execFile, spawn } from "node:child_process";
|
|
20
20
|
import * as path$3 from "node:path";
|
|
21
21
|
import * as path$2 from "node:path";
|
|
22
22
|
import * as path$1 from "node:path";
|
|
@@ -1182,6 +1182,17 @@ const PartialSubstrateConfigSchema = z.object({
|
|
|
1182
1182
|
|
|
1183
1183
|
//#endregion
|
|
1184
1184
|
//#region src/modules/project-profile/detect.ts
|
|
1185
|
+
function execFileAsync(cmd, args, opts) {
|
|
1186
|
+
return new Promise((resolve$2, reject) => {
|
|
1187
|
+
execFile(cmd, args, {
|
|
1188
|
+
...opts,
|
|
1189
|
+
timeout: 5e3
|
|
1190
|
+
}, (err, stdout) => {
|
|
1191
|
+
if (err) reject(err);
|
|
1192
|
+
else resolve$2(stdout);
|
|
1193
|
+
});
|
|
1194
|
+
});
|
|
1195
|
+
}
|
|
1185
1196
|
/**
|
|
1186
1197
|
* Ordered array of build system markers. Detection checks them in priority
|
|
1187
1198
|
* order — the first matching marker wins at the single-project level.
|
|
@@ -1282,6 +1293,101 @@ async function detectNodeBuildTool(dir) {
|
|
|
1282
1293
|
installCommand: "npm install <package>"
|
|
1283
1294
|
};
|
|
1284
1295
|
}
|
|
1296
|
+
const TASK_RUNNER_MARKERS = [
|
|
1297
|
+
{
|
|
1298
|
+
file: "justfile",
|
|
1299
|
+
runner: "just",
|
|
1300
|
+
listCommand: ["just", "--list"]
|
|
1301
|
+
},
|
|
1302
|
+
{
|
|
1303
|
+
file: "Justfile",
|
|
1304
|
+
runner: "just",
|
|
1305
|
+
listCommand: ["just", "--list"]
|
|
1306
|
+
},
|
|
1307
|
+
{
|
|
1308
|
+
file: "Makefile",
|
|
1309
|
+
runner: "make",
|
|
1310
|
+
listCommand: []
|
|
1311
|
+
},
|
|
1312
|
+
{
|
|
1313
|
+
file: "Taskfile.yml",
|
|
1314
|
+
runner: "task",
|
|
1315
|
+
listCommand: ["task", "--list"]
|
|
1316
|
+
}
|
|
1317
|
+
];
|
|
1318
|
+
/** Known build-related target names, in preference order. */
|
|
1319
|
+
const BUILD_TARGETS = [
|
|
1320
|
+
"build-skip-tests",
|
|
1321
|
+
"build-no-tests",
|
|
1322
|
+
"compile",
|
|
1323
|
+
"build"
|
|
1324
|
+
];
|
|
1325
|
+
/** Known unit-test target names, in preference order. */
|
|
1326
|
+
const TEST_TARGETS = [
|
|
1327
|
+
"test-unit",
|
|
1328
|
+
"test-fast",
|
|
1329
|
+
"test"
|
|
1330
|
+
];
|
|
1331
|
+
/**
|
|
1332
|
+
* Detect a task runner (justfile, Makefile, Taskfile.yml) in the given directory
|
|
1333
|
+
* and extract build/test command overrides from its available targets.
|
|
1334
|
+
*
|
|
1335
|
+
* Returns overrides for buildCommand and testCommand, or null if no task runner found.
|
|
1336
|
+
*/
|
|
1337
|
+
async function detectTaskRunner(dir) {
|
|
1338
|
+
for (const marker of TASK_RUNNER_MARKERS) {
|
|
1339
|
+
if (!await fileExists(path$1.join(dir, marker.file))) continue;
|
|
1340
|
+
if (marker.runner === "just") return detectJustTargets(dir, marker.file);
|
|
1341
|
+
if (marker.runner === "make") return detectMakeTargets(dir);
|
|
1342
|
+
return { runner: "task" };
|
|
1343
|
+
}
|
|
1344
|
+
return null;
|
|
1345
|
+
}
|
|
1346
|
+
async function detectJustTargets(dir, _filename) {
|
|
1347
|
+
const result = { runner: "just" };
|
|
1348
|
+
try {
|
|
1349
|
+
const stdout = await execFileAsync("just", ["--summary"], { cwd: dir });
|
|
1350
|
+
const recipes = stdout.trim().split(/\s+/);
|
|
1351
|
+
for (const target of BUILD_TARGETS) if (recipes.includes(target)) {
|
|
1352
|
+
result.buildCommand = `just ${target}`;
|
|
1353
|
+
break;
|
|
1354
|
+
}
|
|
1355
|
+
for (const target of TEST_TARGETS) if (recipes.includes(target)) {
|
|
1356
|
+
result.testCommand = `just ${target}`;
|
|
1357
|
+
break;
|
|
1358
|
+
}
|
|
1359
|
+
} catch {
|
|
1360
|
+
try {
|
|
1361
|
+
const content = await fs.readFile(path$1.join(dir, _filename), "utf-8");
|
|
1362
|
+
const recipes = content.split("\n").map((line) => line.match(/^([a-zA-Z_][\w-]*)(?:\s+[^:]*)?:/)).filter((m) => m !== null).map((m) => m[1]);
|
|
1363
|
+
for (const target of BUILD_TARGETS) if (recipes.includes(target)) {
|
|
1364
|
+
result.buildCommand = `just ${target}`;
|
|
1365
|
+
break;
|
|
1366
|
+
}
|
|
1367
|
+
for (const target of TEST_TARGETS) if (recipes.includes(target)) {
|
|
1368
|
+
result.testCommand = `just ${target}`;
|
|
1369
|
+
break;
|
|
1370
|
+
}
|
|
1371
|
+
} catch {}
|
|
1372
|
+
}
|
|
1373
|
+
return result;
|
|
1374
|
+
}
|
|
1375
|
+
async function detectMakeTargets(dir) {
|
|
1376
|
+
const result = { runner: "make" };
|
|
1377
|
+
try {
|
|
1378
|
+
const content = await fs.readFile(path$1.join(dir, "Makefile"), "utf-8");
|
|
1379
|
+
const targets = content.split("\n").map((line) => line.match(/^([a-zA-Z_][\w-]*):/)).filter((m) => m !== null).map((m) => m[1]);
|
|
1380
|
+
for (const target of BUILD_TARGETS) if (targets.includes(target)) {
|
|
1381
|
+
result.buildCommand = `make ${target}`;
|
|
1382
|
+
break;
|
|
1383
|
+
}
|
|
1384
|
+
for (const target of TEST_TARGETS) if (targets.includes(target)) {
|
|
1385
|
+
result.testCommand = `make ${target}`;
|
|
1386
|
+
break;
|
|
1387
|
+
}
|
|
1388
|
+
} catch {}
|
|
1389
|
+
return result;
|
|
1390
|
+
}
|
|
1285
1391
|
/**
|
|
1286
1392
|
* Detects the language and build tool for a single project directory.
|
|
1287
1393
|
*
|
|
@@ -1293,12 +1399,13 @@ async function detectNodeBuildTool(dir) {
|
|
|
1293
1399
|
* @returns A `PackageEntry` describing the detected stack.
|
|
1294
1400
|
*/
|
|
1295
1401
|
async function detectSingleProjectStack(dir) {
|
|
1402
|
+
let baseEntry;
|
|
1296
1403
|
for (const marker of STACK_MARKERS) {
|
|
1297
1404
|
const markerPath = path$1.join(dir, marker.file);
|
|
1298
1405
|
if (!await fileExists(markerPath)) continue;
|
|
1299
1406
|
if (marker.file === "package.json") {
|
|
1300
1407
|
const nodeInfo = await detectNodeBuildTool(dir);
|
|
1301
|
-
|
|
1408
|
+
baseEntry = {
|
|
1302
1409
|
path: dir,
|
|
1303
1410
|
language: "typescript",
|
|
1304
1411
|
buildTool: nodeInfo.buildTool,
|
|
@@ -1306,20 +1413,24 @@ async function detectSingleProjectStack(dir) {
|
|
|
1306
1413
|
testCommand: nodeInfo.testCommand,
|
|
1307
1414
|
installCommand: nodeInfo.installCommand
|
|
1308
1415
|
};
|
|
1416
|
+
break;
|
|
1309
1417
|
}
|
|
1310
1418
|
if (marker.file === "pyproject.toml") {
|
|
1311
1419
|
const hasPoetry = await fileExists(path$1.join(dir, "poetry.lock"));
|
|
1312
|
-
if (hasPoetry)
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1420
|
+
if (hasPoetry) {
|
|
1421
|
+
baseEntry = {
|
|
1422
|
+
path: dir,
|
|
1423
|
+
language: "python",
|
|
1424
|
+
buildTool: "poetry",
|
|
1425
|
+
buildCommand: "poetry build",
|
|
1426
|
+
testCommand: "poetry run pytest",
|
|
1427
|
+
installCommand: "poetry add <package>"
|
|
1428
|
+
};
|
|
1429
|
+
break;
|
|
1430
|
+
}
|
|
1320
1431
|
const hasVenv = await fileExists(path$1.join(dir, ".venv", "bin", "activate"));
|
|
1321
1432
|
const venvPrefix = hasVenv ? "source .venv/bin/activate && " : "";
|
|
1322
|
-
|
|
1433
|
+
baseEntry = {
|
|
1323
1434
|
path: dir,
|
|
1324
1435
|
language: "python",
|
|
1325
1436
|
buildTool: "pip",
|
|
@@ -1327,8 +1438,9 @@ async function detectSingleProjectStack(dir) {
|
|
|
1327
1438
|
testCommand: `${venvPrefix}pytest`,
|
|
1328
1439
|
installCommand: `${venvPrefix}pip install <package>`
|
|
1329
1440
|
};
|
|
1441
|
+
break;
|
|
1330
1442
|
}
|
|
1331
|
-
|
|
1443
|
+
baseEntry = {
|
|
1332
1444
|
path: dir,
|
|
1333
1445
|
language: marker.language,
|
|
1334
1446
|
buildTool: marker.buildTool,
|
|
@@ -1336,8 +1448,9 @@ async function detectSingleProjectStack(dir) {
|
|
|
1336
1448
|
testCommand: marker.testCommand,
|
|
1337
1449
|
installCommand: marker.installCommand
|
|
1338
1450
|
};
|
|
1451
|
+
break;
|
|
1339
1452
|
}
|
|
1340
|
-
|
|
1453
|
+
if (!baseEntry) baseEntry = {
|
|
1341
1454
|
path: dir,
|
|
1342
1455
|
language: "typescript",
|
|
1343
1456
|
buildTool: "npm",
|
|
@@ -1345,6 +1458,21 @@ async function detectSingleProjectStack(dir) {
|
|
|
1345
1458
|
testCommand: "npm test",
|
|
1346
1459
|
installCommand: "npm install <package>"
|
|
1347
1460
|
};
|
|
1461
|
+
return applyTaskRunnerOverlay(dir, baseEntry);
|
|
1462
|
+
}
|
|
1463
|
+
/**
|
|
1464
|
+
* Apply task runner overlay to a detected PackageEntry.
|
|
1465
|
+
* If a justfile/Makefile/Taskfile.yml exists with matching targets,
|
|
1466
|
+
* override the buildCommand and testCommand with task runner commands.
|
|
1467
|
+
*/
|
|
1468
|
+
async function applyTaskRunnerOverlay(dir, entry) {
|
|
1469
|
+
const runner = await detectTaskRunner(dir);
|
|
1470
|
+
if (!runner) return entry;
|
|
1471
|
+
return {
|
|
1472
|
+
...entry,
|
|
1473
|
+
...runner.buildCommand && { buildCommand: runner.buildCommand },
|
|
1474
|
+
...runner.testCommand && { testCommand: runner.testCommand }
|
|
1475
|
+
};
|
|
1348
1476
|
}
|
|
1349
1477
|
/**
|
|
1350
1478
|
* Detects if the project root is a Turborepo monorepo.
|