@lark-apaas/fullstack-cli 1.1.18 → 1.1.19
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/index.js +313 -33
- package/package.json +1 -1
- package/templates/drizzle.config.ts +55 -0
- package/templates/scripts/dev.sh +5 -1
package/dist/index.js
CHANGED
|
@@ -1960,6 +1960,27 @@ var syncConfig = {
|
|
|
1960
1960
|
type: "remove-line",
|
|
1961
1961
|
to: ".gitignore",
|
|
1962
1962
|
pattern: "package-lock.json"
|
|
1963
|
+
},
|
|
1964
|
+
// 5. 注册 postinstall 脚本,自动恢复 action plugins
|
|
1965
|
+
{
|
|
1966
|
+
type: "add-script",
|
|
1967
|
+
name: "postinstall",
|
|
1968
|
+
command: "fullstack-cli action-plugin init",
|
|
1969
|
+
overwrite: false
|
|
1970
|
+
},
|
|
1971
|
+
// 6. 替换 drizzle.config.ts(仅当文件存在时)
|
|
1972
|
+
{
|
|
1973
|
+
from: "templates/drizzle.config.ts",
|
|
1974
|
+
to: "drizzle.config.ts",
|
|
1975
|
+
type: "file",
|
|
1976
|
+
overwrite: true,
|
|
1977
|
+
onlyIfExists: true
|
|
1978
|
+
},
|
|
1979
|
+
// 7. 确保 .gitignore 包含 .agent/ 目录
|
|
1980
|
+
{
|
|
1981
|
+
type: "add-line",
|
|
1982
|
+
to: ".gitignore",
|
|
1983
|
+
line: ".agent/"
|
|
1963
1984
|
}
|
|
1964
1985
|
],
|
|
1965
1986
|
// 文件权限设置
|
|
@@ -2053,6 +2074,16 @@ async function syncRule(rule, pluginRoot, userProjectRoot) {
|
|
|
2053
2074
|
removeLineFromFile(destPath2, rule.pattern);
|
|
2054
2075
|
return;
|
|
2055
2076
|
}
|
|
2077
|
+
if (rule.type === "add-script") {
|
|
2078
|
+
const packageJsonPath = path4.join(userProjectRoot, "package.json");
|
|
2079
|
+
addScript(packageJsonPath, rule.name, rule.command, rule.overwrite ?? false);
|
|
2080
|
+
return;
|
|
2081
|
+
}
|
|
2082
|
+
if (rule.type === "add-line") {
|
|
2083
|
+
const destPath2 = path4.join(userProjectRoot, rule.to);
|
|
2084
|
+
addLineToFile(destPath2, rule.line);
|
|
2085
|
+
return;
|
|
2086
|
+
}
|
|
2056
2087
|
if (!("from" in rule)) {
|
|
2057
2088
|
return;
|
|
2058
2089
|
}
|
|
@@ -2067,14 +2098,18 @@ async function syncRule(rule, pluginRoot, userProjectRoot) {
|
|
|
2067
2098
|
syncDirectory(srcPath, destPath, rule.overwrite ?? true);
|
|
2068
2099
|
break;
|
|
2069
2100
|
case "file":
|
|
2070
|
-
syncFile(srcPath, destPath, rule.overwrite ?? true);
|
|
2101
|
+
syncFile(srcPath, destPath, rule.overwrite ?? true, rule.onlyIfExists ?? false);
|
|
2071
2102
|
break;
|
|
2072
2103
|
case "append":
|
|
2073
2104
|
appendToFile(srcPath, destPath);
|
|
2074
2105
|
break;
|
|
2075
2106
|
}
|
|
2076
2107
|
}
|
|
2077
|
-
function syncFile(src, dest, overwrite = true) {
|
|
2108
|
+
function syncFile(src, dest, overwrite = true, onlyIfExists = false) {
|
|
2109
|
+
if (onlyIfExists && !fs6.existsSync(dest)) {
|
|
2110
|
+
console.log(`[fullstack-cli] \u25CB ${path4.basename(dest)} (skipped, target not exists)`);
|
|
2111
|
+
return;
|
|
2112
|
+
}
|
|
2078
2113
|
const destDir = path4.dirname(dest);
|
|
2079
2114
|
if (!fs6.existsSync(destDir)) {
|
|
2080
2115
|
fs6.mkdirSync(destDir, { recursive: true });
|
|
@@ -2155,6 +2190,42 @@ function deleteDirectory(dirPath) {
|
|
|
2155
2190
|
console.log(`[fullstack-cli] \u25CB ${path4.basename(dirPath)} (not found)`);
|
|
2156
2191
|
}
|
|
2157
2192
|
}
|
|
2193
|
+
function addScript(packageJsonPath, name, command, overwrite) {
|
|
2194
|
+
if (!fs6.existsSync(packageJsonPath)) {
|
|
2195
|
+
console.log(`[fullstack-cli] \u25CB package.json (not found)`);
|
|
2196
|
+
return;
|
|
2197
|
+
}
|
|
2198
|
+
const content = fs6.readFileSync(packageJsonPath, "utf-8");
|
|
2199
|
+
const pkg2 = JSON.parse(content);
|
|
2200
|
+
if (!pkg2.scripts) {
|
|
2201
|
+
pkg2.scripts = {};
|
|
2202
|
+
}
|
|
2203
|
+
if (pkg2.scripts[name]) {
|
|
2204
|
+
if (!overwrite) {
|
|
2205
|
+
console.log(`[fullstack-cli] \u25CB scripts.${name} (already exists)`);
|
|
2206
|
+
return;
|
|
2207
|
+
}
|
|
2208
|
+
}
|
|
2209
|
+
pkg2.scripts[name] = command;
|
|
2210
|
+
fs6.writeFileSync(packageJsonPath, JSON.stringify(pkg2, null, 2) + "\n");
|
|
2211
|
+
console.log(`[fullstack-cli] \u2713 scripts.${name}`);
|
|
2212
|
+
}
|
|
2213
|
+
function addLineToFile(filePath, line) {
|
|
2214
|
+
const fileName = path4.basename(filePath);
|
|
2215
|
+
if (!fs6.existsSync(filePath)) {
|
|
2216
|
+
console.log(`[fullstack-cli] \u25CB ${fileName} (not found, skipped)`);
|
|
2217
|
+
return;
|
|
2218
|
+
}
|
|
2219
|
+
const content = fs6.readFileSync(filePath, "utf-8");
|
|
2220
|
+
const lines = content.split("\n").map((l) => l.trim());
|
|
2221
|
+
if (lines.includes(line)) {
|
|
2222
|
+
console.log(`[fullstack-cli] \u25CB ${fileName} (line already exists: ${line})`);
|
|
2223
|
+
return;
|
|
2224
|
+
}
|
|
2225
|
+
const appendContent = (content.endsWith("\n") ? "" : "\n") + line + "\n";
|
|
2226
|
+
fs6.appendFileSync(filePath, appendContent);
|
|
2227
|
+
console.log(`[fullstack-cli] \u2713 ${fileName} (added: ${line})`);
|
|
2228
|
+
}
|
|
2158
2229
|
|
|
2159
2230
|
// src/commands/sync/index.ts
|
|
2160
2231
|
var syncCommand = {
|
|
@@ -2438,9 +2509,24 @@ function ensureCacheDir() {
|
|
|
2438
2509
|
function getTempFilePath(pluginKey, version) {
|
|
2439
2510
|
ensureCacheDir();
|
|
2440
2511
|
const safeKey = pluginKey.replace(/[/@]/g, "_");
|
|
2441
|
-
const filename = `${safeKey}
|
|
2512
|
+
const filename = `${safeKey}@${version}.tgz`;
|
|
2442
2513
|
return path6.join(getPluginCacheDir(), filename);
|
|
2443
2514
|
}
|
|
2515
|
+
var MAX_RETRIES = 2;
|
|
2516
|
+
async function withRetry(operation, description, maxRetries = MAX_RETRIES) {
|
|
2517
|
+
let lastError;
|
|
2518
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
2519
|
+
try {
|
|
2520
|
+
return await operation();
|
|
2521
|
+
} catch (error) {
|
|
2522
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
2523
|
+
if (attempt < maxRetries) {
|
|
2524
|
+
console.log(`[action-plugin] ${description} failed, retrying (${attempt + 1}/${maxRetries})...`);
|
|
2525
|
+
}
|
|
2526
|
+
}
|
|
2527
|
+
}
|
|
2528
|
+
throw lastError;
|
|
2529
|
+
}
|
|
2444
2530
|
async function downloadPlugin(pluginKey, requestedVersion) {
|
|
2445
2531
|
console.log(`[action-plugin] Fetching plugin info for ${pluginKey}@${requestedVersion}...`);
|
|
2446
2532
|
const pluginInfo = await getPluginVersion(pluginKey, requestedVersion);
|
|
@@ -2449,10 +2535,16 @@ async function downloadPlugin(pluginKey, requestedVersion) {
|
|
|
2449
2535
|
let tgzBuffer;
|
|
2450
2536
|
if (pluginInfo.downloadApproach === "inner") {
|
|
2451
2537
|
console.log(`[action-plugin] Downloading from inner API...`);
|
|
2452
|
-
tgzBuffer = await
|
|
2538
|
+
tgzBuffer = await withRetry(
|
|
2539
|
+
() => downloadFromInner(pluginKey, pluginInfo.version),
|
|
2540
|
+
"Download"
|
|
2541
|
+
);
|
|
2453
2542
|
} else {
|
|
2454
2543
|
console.log(`[action-plugin] Downloading from public URL...`);
|
|
2455
|
-
tgzBuffer = await
|
|
2544
|
+
tgzBuffer = await withRetry(
|
|
2545
|
+
() => downloadFromPublic(pluginInfo.downloadURL),
|
|
2546
|
+
"Download"
|
|
2547
|
+
);
|
|
2456
2548
|
}
|
|
2457
2549
|
const tgzPath = getTempFilePath(pluginKey, pluginInfo.version);
|
|
2458
2550
|
fs8.writeFileSync(tgzPath, tgzBuffer);
|
|
@@ -2464,25 +2556,99 @@ async function downloadPlugin(pluginKey, requestedVersion) {
|
|
|
2464
2556
|
};
|
|
2465
2557
|
}
|
|
2466
2558
|
function cleanupTempFile(tgzPath) {
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2559
|
+
}
|
|
2560
|
+
function getCachePath(pluginKey, version) {
|
|
2561
|
+
ensureCacheDir();
|
|
2562
|
+
const safeKey = pluginKey.replace(/[/@]/g, "_");
|
|
2563
|
+
const filename = `${safeKey}@${version}.tgz`;
|
|
2564
|
+
return path6.join(getPluginCacheDir(), filename);
|
|
2565
|
+
}
|
|
2566
|
+
function hasCachedPlugin(pluginKey, version) {
|
|
2567
|
+
const cachePath = getCachePath(pluginKey, version);
|
|
2568
|
+
return fs8.existsSync(cachePath);
|
|
2569
|
+
}
|
|
2570
|
+
function listCachedPlugins() {
|
|
2571
|
+
const cacheDir = getPluginCacheDir();
|
|
2572
|
+
if (!fs8.existsSync(cacheDir)) {
|
|
2573
|
+
return [];
|
|
2574
|
+
}
|
|
2575
|
+
const files = fs8.readdirSync(cacheDir);
|
|
2576
|
+
const result = [];
|
|
2577
|
+
for (const file of files) {
|
|
2578
|
+
if (!file.endsWith(".tgz")) continue;
|
|
2579
|
+
const match = file.match(/^(.+)@(.+)\.tgz$/);
|
|
2580
|
+
if (!match) continue;
|
|
2581
|
+
const [, rawName, version] = match;
|
|
2582
|
+
const name = rawName.replace(/^_/, "@").replace(/_/, "/");
|
|
2583
|
+
const filePath = path6.join(cacheDir, file);
|
|
2584
|
+
const stat = fs8.statSync(filePath);
|
|
2585
|
+
result.push({
|
|
2586
|
+
name,
|
|
2587
|
+
version,
|
|
2588
|
+
filePath,
|
|
2589
|
+
size: stat.size,
|
|
2590
|
+
mtime: stat.mtime
|
|
2591
|
+
});
|
|
2592
|
+
}
|
|
2593
|
+
return result;
|
|
2594
|
+
}
|
|
2595
|
+
function cleanAllCache() {
|
|
2596
|
+
const cacheDir = getPluginCacheDir();
|
|
2597
|
+
if (!fs8.existsSync(cacheDir)) {
|
|
2598
|
+
return 0;
|
|
2599
|
+
}
|
|
2600
|
+
const files = fs8.readdirSync(cacheDir);
|
|
2601
|
+
let count = 0;
|
|
2602
|
+
for (const file of files) {
|
|
2603
|
+
if (file.endsWith(".tgz")) {
|
|
2604
|
+
fs8.unlinkSync(path6.join(cacheDir, file));
|
|
2605
|
+
count++;
|
|
2470
2606
|
}
|
|
2471
|
-
} catch {
|
|
2472
2607
|
}
|
|
2608
|
+
return count;
|
|
2609
|
+
}
|
|
2610
|
+
function cleanPluginCache(pluginKey, version) {
|
|
2611
|
+
const cacheDir = getPluginCacheDir();
|
|
2612
|
+
if (!fs8.existsSync(cacheDir)) {
|
|
2613
|
+
return 0;
|
|
2614
|
+
}
|
|
2615
|
+
const safeKey = pluginKey.replace(/[/@]/g, "_");
|
|
2616
|
+
const files = fs8.readdirSync(cacheDir);
|
|
2617
|
+
let count = 0;
|
|
2618
|
+
for (const file of files) {
|
|
2619
|
+
if (version) {
|
|
2620
|
+
if (file === `${safeKey}@${version}.tgz`) {
|
|
2621
|
+
fs8.unlinkSync(path6.join(cacheDir, file));
|
|
2622
|
+
count++;
|
|
2623
|
+
}
|
|
2624
|
+
} else {
|
|
2625
|
+
if (file.startsWith(`${safeKey}@`) && file.endsWith(".tgz")) {
|
|
2626
|
+
fs8.unlinkSync(path6.join(cacheDir, file));
|
|
2627
|
+
count++;
|
|
2628
|
+
}
|
|
2629
|
+
}
|
|
2630
|
+
}
|
|
2631
|
+
return count;
|
|
2473
2632
|
}
|
|
2474
2633
|
|
|
2475
2634
|
// src/commands/action-plugin/init.handler.ts
|
|
2476
2635
|
async function installOneForInit(name, version) {
|
|
2477
|
-
let tgzPath;
|
|
2478
2636
|
try {
|
|
2479
2637
|
const installedVersion = getPackageVersion(name);
|
|
2480
2638
|
if (installedVersion === version) {
|
|
2481
2639
|
return { name, version, success: true, skipped: true };
|
|
2482
2640
|
}
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2641
|
+
let tgzPath;
|
|
2642
|
+
let fromCache = false;
|
|
2643
|
+
if (hasCachedPlugin(name, version)) {
|
|
2644
|
+
console.log(`[action-plugin] \u21BB Restoring ${name}@${version} from cache...`);
|
|
2645
|
+
tgzPath = getCachePath(name, version);
|
|
2646
|
+
fromCache = true;
|
|
2647
|
+
} else {
|
|
2648
|
+
console.log(`[action-plugin] \u2193 Downloading ${name}@${version}...`);
|
|
2649
|
+
const downloadResult = await downloadPlugin(name, version);
|
|
2650
|
+
tgzPath = downloadResult.tgzPath;
|
|
2651
|
+
}
|
|
2486
2652
|
const pluginDir = extractTgzToNodeModules(tgzPath, name);
|
|
2487
2653
|
const pluginPkg = readPluginPackageJson(pluginDir);
|
|
2488
2654
|
if (pluginPkg?.peerDependencies) {
|
|
@@ -2491,16 +2657,13 @@ async function installOneForInit(name, version) {
|
|
|
2491
2657
|
installMissingDeps(missingDeps);
|
|
2492
2658
|
}
|
|
2493
2659
|
}
|
|
2494
|
-
|
|
2660
|
+
const source = fromCache ? "from cache" : "downloaded";
|
|
2661
|
+
console.log(`[action-plugin] \u2713 Installed ${name}@${version} (${source})`);
|
|
2495
2662
|
return { name, version, success: true };
|
|
2496
2663
|
} catch (error) {
|
|
2497
2664
|
const message = error instanceof Error ? error.message : String(error);
|
|
2498
2665
|
console.error(`[action-plugin] \u2717 Failed to install ${name}: ${message}`);
|
|
2499
2666
|
return { name, version, success: false, error: message };
|
|
2500
|
-
} finally {
|
|
2501
|
-
if (tgzPath) {
|
|
2502
|
-
cleanupTempFile(tgzPath);
|
|
2503
|
-
}
|
|
2504
2667
|
}
|
|
2505
2668
|
}
|
|
2506
2669
|
async function init() {
|
|
@@ -2546,7 +2709,6 @@ function syncActionPluginsRecord(name, version) {
|
|
|
2546
2709
|
}
|
|
2547
2710
|
}
|
|
2548
2711
|
async function installOne(nameWithVersion) {
|
|
2549
|
-
let tgzPath;
|
|
2550
2712
|
const { name, version: requestedVersion } = parsePluginName(nameWithVersion);
|
|
2551
2713
|
try {
|
|
2552
2714
|
console.log(`[action-plugin] Installing ${name}@${requestedVersion}...`);
|
|
@@ -2558,17 +2720,28 @@ async function installOne(nameWithVersion) {
|
|
|
2558
2720
|
return { name, version: actualVersion, success: true, skipped: true };
|
|
2559
2721
|
}
|
|
2560
2722
|
}
|
|
2561
|
-
|
|
2723
|
+
let targetVersion = requestedVersion;
|
|
2724
|
+
if (requestedVersion === "latest") {
|
|
2562
2725
|
const latestInfo = await getPluginVersion(name, "latest");
|
|
2563
|
-
|
|
2726
|
+
targetVersion = latestInfo.version;
|
|
2727
|
+
if (actualVersion === targetVersion) {
|
|
2564
2728
|
console.log(`[action-plugin] Plugin ${name} is already up to date (version: ${actualVersion})`);
|
|
2565
2729
|
syncActionPluginsRecord(name, actualVersion);
|
|
2566
2730
|
return { name, version: actualVersion, success: true, skipped: true };
|
|
2567
2731
|
}
|
|
2568
|
-
console.log(`[action-plugin] Found newer version: ${
|
|
2732
|
+
console.log(`[action-plugin] Found newer version: ${targetVersion} (installed: ${actualVersion || "none"})`);
|
|
2733
|
+
}
|
|
2734
|
+
let tgzPath;
|
|
2735
|
+
let fromCache = false;
|
|
2736
|
+
if (hasCachedPlugin(name, targetVersion)) {
|
|
2737
|
+
console.log(`[action-plugin] \u21BB Using cached ${name}@${targetVersion}...`);
|
|
2738
|
+
tgzPath = getCachePath(name, targetVersion);
|
|
2739
|
+
fromCache = true;
|
|
2740
|
+
} else {
|
|
2741
|
+
console.log(`[action-plugin] \u2193 Downloading ${name}@${targetVersion}...`);
|
|
2742
|
+
const downloadResult = await downloadPlugin(name, requestedVersion);
|
|
2743
|
+
tgzPath = downloadResult.tgzPath;
|
|
2569
2744
|
}
|
|
2570
|
-
const downloadResult = await downloadPlugin(name, requestedVersion);
|
|
2571
|
-
tgzPath = downloadResult.tgzPath;
|
|
2572
2745
|
console.log(`[action-plugin] Extracting to node_modules...`);
|
|
2573
2746
|
const pluginDir = extractTgzToNodeModules(tgzPath, name);
|
|
2574
2747
|
const pluginPkg = readPluginPackageJson(pluginDir);
|
|
@@ -2578,20 +2751,17 @@ async function installOne(nameWithVersion) {
|
|
|
2578
2751
|
installMissingDeps(missingDeps);
|
|
2579
2752
|
}
|
|
2580
2753
|
}
|
|
2581
|
-
const installedVersion = getPackageVersion(name) ||
|
|
2754
|
+
const installedVersion = getPackageVersion(name) || targetVersion;
|
|
2582
2755
|
const plugins = readActionPlugins();
|
|
2583
2756
|
plugins[name] = installedVersion;
|
|
2584
2757
|
writeActionPlugins(plugins);
|
|
2585
|
-
|
|
2758
|
+
const source = fromCache ? "from cache" : "downloaded";
|
|
2759
|
+
console.log(`[action-plugin] Successfully installed ${name}@${installedVersion} (${source})`);
|
|
2586
2760
|
return { name, version: installedVersion, success: true };
|
|
2587
2761
|
} catch (error) {
|
|
2588
2762
|
const message = error instanceof Error ? error.message : String(error);
|
|
2589
2763
|
console.error(`[action-plugin] Failed to install ${name}: ${message}`);
|
|
2590
2764
|
return { name, version: requestedVersion, success: false, error: message };
|
|
2591
|
-
} finally {
|
|
2592
|
-
if (tgzPath) {
|
|
2593
|
-
cleanupTempFile(tgzPath);
|
|
2594
|
-
}
|
|
2595
2765
|
}
|
|
2596
2766
|
}
|
|
2597
2767
|
async function install(namesWithVersion) {
|
|
@@ -2745,6 +2915,58 @@ async function list() {
|
|
|
2745
2915
|
}
|
|
2746
2916
|
}
|
|
2747
2917
|
|
|
2918
|
+
// src/commands/action-plugin/cache.handler.ts
|
|
2919
|
+
async function cacheList() {
|
|
2920
|
+
const cached = listCachedPlugins();
|
|
2921
|
+
if (cached.length === 0) {
|
|
2922
|
+
console.log("[action-plugin] No cached plugins found");
|
|
2923
|
+
return;
|
|
2924
|
+
}
|
|
2925
|
+
console.log("[action-plugin] Cached plugins:\n");
|
|
2926
|
+
console.log(" Name Version Size Modified");
|
|
2927
|
+
console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
2928
|
+
let totalSize = 0;
|
|
2929
|
+
for (const plugin of cached) {
|
|
2930
|
+
const name = plugin.name.padEnd(38);
|
|
2931
|
+
const version = plugin.version.padEnd(10);
|
|
2932
|
+
const size = formatSize(plugin.size).padEnd(9);
|
|
2933
|
+
const mtime = plugin.mtime.toISOString().replace("T", " ").slice(0, 19);
|
|
2934
|
+
console.log(` ${name} ${version} ${size} ${mtime}`);
|
|
2935
|
+
totalSize += plugin.size;
|
|
2936
|
+
}
|
|
2937
|
+
console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
2938
|
+
console.log(` Total: ${cached.length} cached file(s), ${formatSize(totalSize)}`);
|
|
2939
|
+
}
|
|
2940
|
+
async function cacheClean(pluginName, version) {
|
|
2941
|
+
let count;
|
|
2942
|
+
if (pluginName) {
|
|
2943
|
+
console.log(`[action-plugin] Cleaning cache for ${pluginName}${version ? `@${version}` : ""}...`);
|
|
2944
|
+
count = cleanPluginCache(pluginName, version);
|
|
2945
|
+
if (count === 0) {
|
|
2946
|
+
console.log(`[action-plugin] No cached files found for ${pluginName}${version ? `@${version}` : ""}`);
|
|
2947
|
+
} else {
|
|
2948
|
+
console.log(`[action-plugin] Cleaned ${count} cached file(s)`);
|
|
2949
|
+
}
|
|
2950
|
+
} else {
|
|
2951
|
+
console.log("[action-plugin] Cleaning all cached plugins...");
|
|
2952
|
+
count = cleanAllCache();
|
|
2953
|
+
if (count === 0) {
|
|
2954
|
+
console.log("[action-plugin] No cached files found");
|
|
2955
|
+
} else {
|
|
2956
|
+
console.log(`[action-plugin] Cleaned ${count} cached file(s)`);
|
|
2957
|
+
}
|
|
2958
|
+
}
|
|
2959
|
+
}
|
|
2960
|
+
function formatSize(bytes) {
|
|
2961
|
+
if (bytes < 1024) {
|
|
2962
|
+
return `${bytes} B`;
|
|
2963
|
+
} else if (bytes < 1024 * 1024) {
|
|
2964
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
2965
|
+
} else {
|
|
2966
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
2967
|
+
}
|
|
2968
|
+
}
|
|
2969
|
+
|
|
2748
2970
|
// src/commands/action-plugin/index.ts
|
|
2749
2971
|
var initCommand = {
|
|
2750
2972
|
name: "init",
|
|
@@ -2795,10 +3017,28 @@ var listCommand = {
|
|
|
2795
3017
|
});
|
|
2796
3018
|
}
|
|
2797
3019
|
};
|
|
3020
|
+
var cacheListCommand = {
|
|
3021
|
+
name: "cache-list",
|
|
3022
|
+
description: "List all cached plugin packages",
|
|
3023
|
+
register(program) {
|
|
3024
|
+
program.command(this.name).description(this.description).action(async () => {
|
|
3025
|
+
await cacheList();
|
|
3026
|
+
});
|
|
3027
|
+
}
|
|
3028
|
+
};
|
|
3029
|
+
var cacheCleanCommand = {
|
|
3030
|
+
name: "cache-clean",
|
|
3031
|
+
description: "Clean cached plugin packages",
|
|
3032
|
+
register(program) {
|
|
3033
|
+
program.command(this.name).description(this.description).argument("[name]", "Plugin name to clean (e.g., @office/feishu-create-group). If not provided, clean all cache.").option("-v, --version <version>", "Specific version to clean").action(async (name, options) => {
|
|
3034
|
+
await cacheClean(name, options.version);
|
|
3035
|
+
});
|
|
3036
|
+
}
|
|
3037
|
+
};
|
|
2798
3038
|
var actionPluginCommandGroup = {
|
|
2799
3039
|
name: "action-plugin",
|
|
2800
3040
|
description: "Manage action plugins",
|
|
2801
|
-
commands: [initCommand, installCommand, updateCommand, removeCommand, listCommand]
|
|
3041
|
+
commands: [initCommand, installCommand, updateCommand, removeCommand, listCommand, cacheListCommand, cacheCleanCommand]
|
|
2802
3042
|
};
|
|
2803
3043
|
|
|
2804
3044
|
// src/commands/capability/utils.ts
|
|
@@ -5125,6 +5365,28 @@ function extractClientStdSegment(lines, maxLines, offset) {
|
|
|
5125
5365
|
};
|
|
5126
5366
|
}
|
|
5127
5367
|
|
|
5368
|
+
// src/commands/read-logs/dev.ts
|
|
5369
|
+
function readDevSegment(filePath, maxLines, offset) {
|
|
5370
|
+
const marker = (line) => {
|
|
5371
|
+
if (!line) return false;
|
|
5372
|
+
if (line.includes("Dev session started")) return true;
|
|
5373
|
+
return false;
|
|
5374
|
+
};
|
|
5375
|
+
const segment = readStdLinesTailFromLastMarkerPaged(filePath, maxLines, offset, marker);
|
|
5376
|
+
return { lines: segment.lines, totalLinesCount: segment.totalLinesCount };
|
|
5377
|
+
}
|
|
5378
|
+
|
|
5379
|
+
// src/commands/read-logs/dev-std.ts
|
|
5380
|
+
function readDevStdSegment(filePath, maxLines, offset) {
|
|
5381
|
+
const marker = (line) => {
|
|
5382
|
+
if (!line) return false;
|
|
5383
|
+
if (line.includes("Dev session started")) return true;
|
|
5384
|
+
return false;
|
|
5385
|
+
};
|
|
5386
|
+
const segment = readStdLinesTailFromLastMarkerPaged(filePath, maxLines, offset, marker);
|
|
5387
|
+
return { lines: segment.lines, totalLinesCount: segment.totalLinesCount };
|
|
5388
|
+
}
|
|
5389
|
+
|
|
5128
5390
|
// src/commands/read-logs/json-lines.ts
|
|
5129
5391
|
import fs20 from "fs";
|
|
5130
5392
|
function normalizePid(value) {
|
|
@@ -5449,7 +5711,7 @@ function readJsonLinesTailByLevel(filePath, maxLines, offset, levels) {
|
|
|
5449
5711
|
}
|
|
5450
5712
|
|
|
5451
5713
|
// src/commands/read-logs/index.ts
|
|
5452
|
-
var LOG_TYPES = ["server", "trace", "server-std", "client-std", "browser"];
|
|
5714
|
+
var LOG_TYPES = ["server", "trace", "server-std", "client-std", "dev", "dev-std", "install-dep-std", "browser"];
|
|
5453
5715
|
function normalizeObjectKey(key) {
|
|
5454
5716
|
return key.toLowerCase().replace(/_/g, "");
|
|
5455
5717
|
}
|
|
@@ -5611,6 +5873,15 @@ async function readLatestLogLinesMeta(options) {
|
|
|
5611
5873
|
if (options.type === "client-std") {
|
|
5612
5874
|
return readClientStdSegment(filePath, maxLines, offset);
|
|
5613
5875
|
}
|
|
5876
|
+
if (options.type === "dev") {
|
|
5877
|
+
return readDevSegment(filePath, maxLines, offset);
|
|
5878
|
+
}
|
|
5879
|
+
if (options.type === "dev-std") {
|
|
5880
|
+
return readDevStdSegment(filePath, maxLines, offset);
|
|
5881
|
+
}
|
|
5882
|
+
if (options.type === "install-dep-std") {
|
|
5883
|
+
return readFileTailNonEmptyLinesWithOffset(filePath, maxLines, offset);
|
|
5884
|
+
}
|
|
5614
5885
|
const traceId = typeof options.traceId === "string" ? options.traceId.trim() : "";
|
|
5615
5886
|
if (traceId) {
|
|
5616
5887
|
return readJsonLinesByTraceId(filePath, traceId, maxLines, offset, levels);
|
|
@@ -5628,7 +5899,7 @@ async function readLatestLogLinesMeta(options) {
|
|
|
5628
5899
|
}
|
|
5629
5900
|
async function readLogsJsonResult(options) {
|
|
5630
5901
|
const { lines, totalLinesCount } = await readLatestLogLinesMeta(options);
|
|
5631
|
-
if (options.type === "server-std" || options.type === "client-std") {
|
|
5902
|
+
if (options.type === "server-std" || options.type === "client-std" || options.type === "dev" || options.type === "dev-std" || options.type === "install-dep-std") {
|
|
5632
5903
|
return {
|
|
5633
5904
|
hasError: hasErrorInStdLines(lines),
|
|
5634
5905
|
totalLinesCount,
|
|
@@ -5672,6 +5943,15 @@ function resolveLogFilePath(logDir, type) {
|
|
|
5672
5943
|
if (type === "client-std") {
|
|
5673
5944
|
return path16.join(base, "client.std.log");
|
|
5674
5945
|
}
|
|
5946
|
+
if (type === "dev") {
|
|
5947
|
+
return path16.join(base, "dev.log");
|
|
5948
|
+
}
|
|
5949
|
+
if (type === "dev-std") {
|
|
5950
|
+
return path16.join(base, "dev.std.log");
|
|
5951
|
+
}
|
|
5952
|
+
if (type === "install-dep-std") {
|
|
5953
|
+
return path16.join(base, "install-dep.std.log");
|
|
5954
|
+
}
|
|
5675
5955
|
if (type === "browser") {
|
|
5676
5956
|
return path16.join(base, "browser.log");
|
|
5677
5957
|
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { defineConfig, Config } from 'drizzle-kit';
|
|
2
|
+
require('dotenv').config();
|
|
3
|
+
|
|
4
|
+
const outputDir = process.env.__DRIZZLE_OUT_DIR__ || './server/database/.introspect';
|
|
5
|
+
const schemaPath = process.env.__DRIZZLE_SCHEMA_PATH__ || './server/database/schema.ts';
|
|
6
|
+
|
|
7
|
+
const parsedUrl = new URL(process.env.SUDA_DATABASE_URL || '');
|
|
8
|
+
|
|
9
|
+
const envSchemaFilter = process.env.DRIZZLE_SCHEMA_FILTER;
|
|
10
|
+
const urlSchemaFilter = parsedUrl.searchParams.get('schema');
|
|
11
|
+
|
|
12
|
+
const schemaFilter = (envSchemaFilter ?? urlSchemaFilter ?? '')
|
|
13
|
+
.split(',')
|
|
14
|
+
.map((s) => s.trim())
|
|
15
|
+
.filter(Boolean);
|
|
16
|
+
|
|
17
|
+
parsedUrl.searchParams.delete('schema'); // 移除schema参数,避免 drizzle-kit 解析错误
|
|
18
|
+
|
|
19
|
+
// 默认排除的系统对象(PostgreSQL 扩展和系统视图)
|
|
20
|
+
// 这些对象在 drizzle-kit introspect 时可能导致无效的 JS 代码生成
|
|
21
|
+
const SYSTEM_OBJECTS_EXCLUSIONS = [
|
|
22
|
+
'!spatial_ref_sys', // PostGIS 空间参考系统表
|
|
23
|
+
'!geography_columns', // PostGIS 地理列视图
|
|
24
|
+
'!geometry_columns', // PostGIS 几何列视图
|
|
25
|
+
'!raster_columns', // PostGIS 栅格列视图
|
|
26
|
+
'!raster_overviews', // PostGIS 栅格概览视图
|
|
27
|
+
'!pg_stat_statements', // pg_stat_statements 扩展
|
|
28
|
+
'!pg_stat_statements_info', // pg_stat_statements 扩展
|
|
29
|
+
'!part_config', // pg_partman 分区配置表
|
|
30
|
+
'!part_config_sub', // pg_partman 子分区配置表
|
|
31
|
+
'!table_privs', // 系统权限视图
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
const envTablesFilter = process.env.DRIZZLE_TABLES_FILTER;
|
|
35
|
+
const userTablesFilter = (envTablesFilter ?? '*')
|
|
36
|
+
.split(',')
|
|
37
|
+
.map((s) => s.trim())
|
|
38
|
+
.filter(Boolean);
|
|
39
|
+
|
|
40
|
+
// 合并用户过滤器和系统对象排除
|
|
41
|
+
// 用户可以通过设置 DRIZZLE_TABLES_FILTER 来覆盖(如果需要包含某些系统对象)
|
|
42
|
+
const tablesFilter = [...userTablesFilter, ...SYSTEM_OBJECTS_EXCLUSIONS];
|
|
43
|
+
|
|
44
|
+
const config:Config = {
|
|
45
|
+
schema: schemaPath,
|
|
46
|
+
out: outputDir,
|
|
47
|
+
tablesFilter,
|
|
48
|
+
schemaFilter,
|
|
49
|
+
dialect: 'postgresql',
|
|
50
|
+
dbCredentials: {
|
|
51
|
+
url: parsedUrl.toString(),
|
|
52
|
+
},
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export default defineConfig(config);
|
package/templates/scripts/dev.sh
CHANGED
|
@@ -21,6 +21,10 @@ CLEANUP_DONE=false
|
|
|
21
21
|
|
|
22
22
|
mkdir -p "${LOG_DIR}"
|
|
23
23
|
|
|
24
|
+
# Redirect all stdout/stderr to both terminal and log file
|
|
25
|
+
DEV_STD_LOG="${LOG_DIR}/dev.std.log"
|
|
26
|
+
exec > >(tee -a "$DEV_STD_LOG") 2>&1
|
|
27
|
+
|
|
24
28
|
# Log event to dev.log with timestamp
|
|
25
29
|
log_event() {
|
|
26
30
|
local level=$1
|
|
@@ -234,7 +238,7 @@ log_event "INFO" "client" "Supervisor started with PID ${CLIENT_PID}"
|
|
|
234
238
|
log_event "INFO" "main" "All processes started, monitoring..."
|
|
235
239
|
echo ""
|
|
236
240
|
echo "📋 Dev processes running. Press Ctrl+C to stop."
|
|
237
|
-
echo "📄 Logs: ${
|
|
241
|
+
echo "📄 Logs: ${DEV_STD_LOG}"
|
|
238
242
|
echo ""
|
|
239
243
|
|
|
240
244
|
# Wait for all background processes
|