@reliverse/dler 2.2.5 → 2.2.10
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 +14 -14
- package/dist/cli.js +1 -1
- package/dist/cmds/biome/cmd.js +58 -0
- package/dist/cmds/biome/impl.d.ts +26 -0
- package/dist/cmds/biome/impl.js +272 -0
- package/dist/cmds/build/cmd.js +18 -10
- package/dist/cmds/clean/cmd.js +6 -6
- package/dist/cmds/clean/impl.js +16 -12
- package/dist/cmds/clean/presets.js +2 -2
- package/dist/cmds/publish/cmd.js +7 -7
- package/dist/cmds/senv/cmd.js +13 -15
- package/dist/cmds/tsc/cache.js +1 -1
- package/dist/cmds/tsc/cmd.js +11 -8
- package/dist/cmds/tsc/impl.js +132 -17
- package/dist/cmds/update/cmd.js +11 -10
- package/dist/cmds/update/impl.d.ts +4 -4
- package/dist/cmds/update/impl.js +10 -11
- package/dist/cmds/update/utils.d.ts +23 -4
- package/dist/cmds/update/utils.js +22 -16
- package/package.json +16 -13
- package/dist/cmds/perf/analysis/bundle.d.ts +0 -20
- package/dist/cmds/perf/analysis/bundle.js +0 -225
- package/dist/cmds/perf/analysis/filesystem.d.ts +0 -27
- package/dist/cmds/perf/analysis/filesystem.js +0 -245
- package/dist/cmds/perf/analysis/monorepo.d.ts +0 -30
- package/dist/cmds/perf/analysis/monorepo.js +0 -345
- package/dist/cmds/perf/benchmarks/command.d.ts +0 -21
- package/dist/cmds/perf/benchmarks/command.js +0 -162
- package/dist/cmds/perf/benchmarks/memory.d.ts +0 -41
- package/dist/cmds/perf/benchmarks/memory.js +0 -169
- package/dist/cmds/perf/benchmarks/runner.d.ts +0 -22
- package/dist/cmds/perf/benchmarks/runner.js +0 -157
- package/dist/cmds/perf/cmd.js +0 -240
- package/dist/cmds/perf/impl.d.ts +0 -24
- package/dist/cmds/perf/impl.js +0 -297
- package/dist/cmds/perf/reporters/console.d.ts +0 -12
- package/dist/cmds/perf/reporters/console.js +0 -257
- package/dist/cmds/perf/reporters/html.d.ts +0 -27
- package/dist/cmds/perf/reporters/html.js +0 -881
- package/dist/cmds/perf/reporters/json.d.ts +0 -9
- package/dist/cmds/perf/reporters/json.js +0 -32
- package/dist/cmds/perf/types.d.ts +0 -184
- package/dist/cmds/perf/types.js +0 -0
- package/dist/cmds/perf/utils/cache.d.ts +0 -23
- package/dist/cmds/perf/utils/cache.js +0 -172
- package/dist/cmds/perf/utils/formatter.d.ts +0 -17
- package/dist/cmds/perf/utils/formatter.js +0 -134
- package/dist/cmds/perf/utils/stats.d.ts +0 -15
- package/dist/cmds/perf/utils/stats.js +0 -101
- package/dist/cmds/port/cmd.d.ts +0 -2
- package/dist/cmds/port/cmd.js +0 -58
- package/dist/cmds/port/impl.d.ts +0 -5
- package/dist/cmds/port/impl.js +0 -280
- package/dist/cmds/shell/cmd.d.ts +0 -2
- package/dist/cmds/shell/cmd.js +0 -46
- /package/dist/cmds/{perf → biome}/cmd.d.ts +0 -0
|
@@ -1,345 +0,0 @@
|
|
|
1
|
-
import { existsSync } from "node:fs";
|
|
2
|
-
import { join, resolve } from "node:path";
|
|
3
|
-
import { logger } from "@reliverse/dler-logger";
|
|
4
|
-
import { createIgnoreFilter } from "@reliverse/dler-matcher";
|
|
5
|
-
import {
|
|
6
|
-
getWorkspacePatterns,
|
|
7
|
-
hasWorkspaces,
|
|
8
|
-
readPackageJSON
|
|
9
|
-
} from "@reliverse/dler-pkg-tsc";
|
|
10
|
-
export class MonorepoAnalyzer {
|
|
11
|
-
options;
|
|
12
|
-
packages = [];
|
|
13
|
-
dependencyGraph = {
|
|
14
|
-
nodes: [],
|
|
15
|
-
edges: [],
|
|
16
|
-
levels: []
|
|
17
|
-
};
|
|
18
|
-
constructor(options) {
|
|
19
|
-
this.options = options;
|
|
20
|
-
}
|
|
21
|
-
async analyze() {
|
|
22
|
-
const startTime = Date.now();
|
|
23
|
-
const { cwd, verbose } = this.options;
|
|
24
|
-
if (verbose) {
|
|
25
|
-
logger.info("\u{1F50D} Analyzing monorepo structure...");
|
|
26
|
-
}
|
|
27
|
-
const monorepoRoot = await this.findMonorepoRoot(cwd);
|
|
28
|
-
if (!monorepoRoot) {
|
|
29
|
-
const currentDir = cwd || process.cwd();
|
|
30
|
-
const singlePkg = await this.discoverSinglePackage(currentDir);
|
|
31
|
-
if (singlePkg) {
|
|
32
|
-
this.packages = [singlePkg];
|
|
33
|
-
if (verbose) {
|
|
34
|
-
logger.info(` Single package root: ${currentDir}`);
|
|
35
|
-
logger.info(" Found 1 package");
|
|
36
|
-
}
|
|
37
|
-
} else {
|
|
38
|
-
throw new Error(
|
|
39
|
-
'No monorepo or valid package found. Ensure package.json has "workspaces" field or contains a valid "name" field.'
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
} else {
|
|
43
|
-
if (verbose) {
|
|
44
|
-
logger.info(` Monorepo root: ${monorepoRoot}`);
|
|
45
|
-
}
|
|
46
|
-
this.packages = await this.discoverPackages(monorepoRoot);
|
|
47
|
-
}
|
|
48
|
-
if (verbose) {
|
|
49
|
-
logger.info(` Found ${this.packages.length} packages`);
|
|
50
|
-
}
|
|
51
|
-
this.dependencyGraph = await this.buildDependencyGraph();
|
|
52
|
-
const circularDependencies = this.findCircularDependencies();
|
|
53
|
-
const buildOrder = this.calculateBuildOrder();
|
|
54
|
-
const criticalPath = this.findCriticalPath();
|
|
55
|
-
const bottlenecks = this.identifyBottlenecks();
|
|
56
|
-
const suggestedConcurrency = this.suggestOptimalConcurrency();
|
|
57
|
-
const analysisTime = Date.now() - startTime;
|
|
58
|
-
if (verbose) {
|
|
59
|
-
logger.info(` Analysis completed in ${analysisTime}ms`);
|
|
60
|
-
}
|
|
61
|
-
return {
|
|
62
|
-
packages: this.packages,
|
|
63
|
-
dependencies: this.dependencyGraph,
|
|
64
|
-
circularDependencies,
|
|
65
|
-
criticalPath,
|
|
66
|
-
buildOrder,
|
|
67
|
-
bottlenecks,
|
|
68
|
-
suggestedConcurrency,
|
|
69
|
-
analysisTime
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
async findMonorepoRoot(startDir) {
|
|
73
|
-
let currentDir = resolve(startDir ?? process.cwd());
|
|
74
|
-
while (currentDir !== "/") {
|
|
75
|
-
const pkgPath = join(currentDir, "package.json");
|
|
76
|
-
if (existsSync(pkgPath)) {
|
|
77
|
-
const pkg = await readPackageJSON(currentDir);
|
|
78
|
-
if (pkg && hasWorkspaces(pkg)) {
|
|
79
|
-
return currentDir;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
const parentDir = resolve(currentDir, "..");
|
|
83
|
-
if (parentDir === currentDir) break;
|
|
84
|
-
currentDir = parentDir;
|
|
85
|
-
}
|
|
86
|
-
return null;
|
|
87
|
-
}
|
|
88
|
-
async discoverPackages(monorepoRoot) {
|
|
89
|
-
const rootPkg = await readPackageJSON(monorepoRoot);
|
|
90
|
-
if (!rootPkg) {
|
|
91
|
-
throw new Error("Could not read root package.json");
|
|
92
|
-
}
|
|
93
|
-
const patterns = getWorkspacePatterns(rootPkg);
|
|
94
|
-
if (!patterns.length) {
|
|
95
|
-
throw new Error("No workspace patterns found in package.json");
|
|
96
|
-
}
|
|
97
|
-
const packages = [];
|
|
98
|
-
const seenPaths = /* @__PURE__ */ new Set();
|
|
99
|
-
for (const pattern of patterns) {
|
|
100
|
-
const glob = new Bun.Glob(pattern);
|
|
101
|
-
const matches = glob.scanSync({ cwd: monorepoRoot, onlyFiles: false });
|
|
102
|
-
for (const match of matches) {
|
|
103
|
-
const packagePath = resolve(monorepoRoot, match);
|
|
104
|
-
if (seenPaths.has(packagePath)) continue;
|
|
105
|
-
seenPaths.add(packagePath);
|
|
106
|
-
const pkgInfo = await this.resolvePackageInfo(packagePath);
|
|
107
|
-
if (pkgInfo) {
|
|
108
|
-
packages.push(pkgInfo);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
const filteredPackages = packages.filter((pkg) => {
|
|
113
|
-
const normalizedPkgPath = resolve(pkg.path);
|
|
114
|
-
const normalizedRootPath = resolve(monorepoRoot);
|
|
115
|
-
return normalizedPkgPath !== normalizedRootPath;
|
|
116
|
-
});
|
|
117
|
-
if (this.options.ignore) {
|
|
118
|
-
const ignoreFilter = createIgnoreFilter(this.options.ignore);
|
|
119
|
-
return ignoreFilter(filteredPackages);
|
|
120
|
-
}
|
|
121
|
-
return filteredPackages;
|
|
122
|
-
}
|
|
123
|
-
async discoverSinglePackage(packagePath) {
|
|
124
|
-
try {
|
|
125
|
-
const pkg = await readPackageJSON(packagePath);
|
|
126
|
-
if (!pkg || !pkg.name) return null;
|
|
127
|
-
const dependencies = [
|
|
128
|
-
...Object.keys(pkg.dependencies ?? {}),
|
|
129
|
-
...this.options.includeDevDependencies ? Object.keys(pkg.devDependencies ?? {}) : [],
|
|
130
|
-
...Object.keys(pkg.peerDependencies ?? {})
|
|
131
|
-
];
|
|
132
|
-
return {
|
|
133
|
-
name: pkg.name,
|
|
134
|
-
path: packagePath,
|
|
135
|
-
dependencies,
|
|
136
|
-
dependents: [],
|
|
137
|
-
// Will be filled later
|
|
138
|
-
buildTime: 0,
|
|
139
|
-
size: 0
|
|
140
|
-
};
|
|
141
|
-
} catch {
|
|
142
|
-
return null;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
async resolvePackageInfo(packagePath) {
|
|
146
|
-
const pkgJsonPath = join(packagePath, "package.json");
|
|
147
|
-
if (!existsSync(pkgJsonPath)) return null;
|
|
148
|
-
try {
|
|
149
|
-
const pkg = await readPackageJSON(packagePath);
|
|
150
|
-
if (!pkg?.name) return null;
|
|
151
|
-
const dependencies = [
|
|
152
|
-
...Object.keys(pkg.dependencies ?? {}),
|
|
153
|
-
...this.options.includeDevDependencies ? Object.keys(pkg.devDependencies ?? {}) : [],
|
|
154
|
-
...Object.keys(pkg.peerDependencies ?? {})
|
|
155
|
-
];
|
|
156
|
-
return {
|
|
157
|
-
name: pkg.name,
|
|
158
|
-
path: packagePath,
|
|
159
|
-
dependencies,
|
|
160
|
-
dependents: [],
|
|
161
|
-
// Will be filled later
|
|
162
|
-
buildTime: 0,
|
|
163
|
-
// Would need to measure actual build time
|
|
164
|
-
size: 0
|
|
165
|
-
// Would need to calculate package size
|
|
166
|
-
};
|
|
167
|
-
} catch {
|
|
168
|
-
return null;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
async buildDependencyGraph() {
|
|
172
|
-
const nodes = this.packages.map((pkg) => pkg.name);
|
|
173
|
-
const edges = [];
|
|
174
|
-
for (const pkg of this.packages) {
|
|
175
|
-
for (const dep of pkg.dependencies) {
|
|
176
|
-
const depPkg = this.packages.find((p) => p.name === dep);
|
|
177
|
-
if (depPkg) {
|
|
178
|
-
edges.push({
|
|
179
|
-
from: pkg.name,
|
|
180
|
-
to: dep,
|
|
181
|
-
type: "dependency"
|
|
182
|
-
});
|
|
183
|
-
depPkg.dependents.push(pkg.name);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
const levels = this.calculateLevels(nodes, edges);
|
|
188
|
-
return {
|
|
189
|
-
nodes,
|
|
190
|
-
edges,
|
|
191
|
-
levels
|
|
192
|
-
};
|
|
193
|
-
}
|
|
194
|
-
calculateLevels(nodes, edges) {
|
|
195
|
-
const inDegree = /* @__PURE__ */ new Map();
|
|
196
|
-
const graph = /* @__PURE__ */ new Map();
|
|
197
|
-
for (const node of nodes) {
|
|
198
|
-
inDegree.set(node, 0);
|
|
199
|
-
graph.set(node, []);
|
|
200
|
-
}
|
|
201
|
-
for (const edge of edges) {
|
|
202
|
-
const current = inDegree.get(edge.to) ?? 0;
|
|
203
|
-
inDegree.set(edge.to, current + 1);
|
|
204
|
-
const neighbors = graph.get(edge.from) ?? [];
|
|
205
|
-
neighbors.push(edge.to);
|
|
206
|
-
graph.set(edge.from, neighbors);
|
|
207
|
-
}
|
|
208
|
-
const levels = [];
|
|
209
|
-
const queue = [];
|
|
210
|
-
for (const [node, degree] of inDegree) {
|
|
211
|
-
if (degree === 0) {
|
|
212
|
-
queue.push(node);
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
while (queue.length > 0) {
|
|
216
|
-
const currentLevel = [];
|
|
217
|
-
const nextQueue = [];
|
|
218
|
-
for (const node of queue) {
|
|
219
|
-
currentLevel.push(node);
|
|
220
|
-
const neighbors = graph.get(node) ?? [];
|
|
221
|
-
for (const neighbor of neighbors) {
|
|
222
|
-
const degree = inDegree.get(neighbor) ?? 0;
|
|
223
|
-
inDegree.set(neighbor, degree - 1);
|
|
224
|
-
if (degree - 1 === 0) {
|
|
225
|
-
nextQueue.push(neighbor);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
levels.push(currentLevel);
|
|
230
|
-
queue.length = 0;
|
|
231
|
-
queue.push(...nextQueue);
|
|
232
|
-
}
|
|
233
|
-
return levels;
|
|
234
|
-
}
|
|
235
|
-
findCircularDependencies() {
|
|
236
|
-
const circular = [];
|
|
237
|
-
const visited = /* @__PURE__ */ new Set();
|
|
238
|
-
const recursionStack = /* @__PURE__ */ new Set();
|
|
239
|
-
for (const pkg of this.packages) {
|
|
240
|
-
if (!visited.has(pkg.name)) {
|
|
241
|
-
const cycle = this.detectCycle(pkg.name, visited, recursionStack, []);
|
|
242
|
-
if (cycle.length > 0) {
|
|
243
|
-
circular.push({
|
|
244
|
-
packages: cycle,
|
|
245
|
-
cycle,
|
|
246
|
-
severity: this.calculateCycleSeverity(cycle)
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
return circular;
|
|
252
|
-
}
|
|
253
|
-
detectCycle(node, visited, recursionStack, path) {
|
|
254
|
-
visited.add(node);
|
|
255
|
-
recursionStack.add(node);
|
|
256
|
-
path.push(node);
|
|
257
|
-
const pkg = this.packages.find((p) => p.name === node);
|
|
258
|
-
if (pkg) {
|
|
259
|
-
for (const dep of pkg.dependencies) {
|
|
260
|
-
const depPkg = this.packages.find((p) => p.name === dep);
|
|
261
|
-
if (depPkg) {
|
|
262
|
-
if (!visited.has(dep)) {
|
|
263
|
-
const cycle = this.detectCycle(dep, visited, recursionStack, [
|
|
264
|
-
...path
|
|
265
|
-
]);
|
|
266
|
-
if (cycle.length > 0) {
|
|
267
|
-
return cycle;
|
|
268
|
-
}
|
|
269
|
-
} else if (recursionStack.has(dep)) {
|
|
270
|
-
const cycleStart = path.indexOf(dep);
|
|
271
|
-
return path.slice(cycleStart);
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
recursionStack.delete(node);
|
|
277
|
-
return [];
|
|
278
|
-
}
|
|
279
|
-
calculateCycleSeverity(cycle) {
|
|
280
|
-
if (cycle.length <= 2) return "low";
|
|
281
|
-
if (cycle.length <= 4) return "medium";
|
|
282
|
-
return "high";
|
|
283
|
-
}
|
|
284
|
-
calculateBuildOrder() {
|
|
285
|
-
const order = [];
|
|
286
|
-
for (const level of this.dependencyGraph.levels) {
|
|
287
|
-
order.push(...level);
|
|
288
|
-
}
|
|
289
|
-
return order;
|
|
290
|
-
}
|
|
291
|
-
findCriticalPath() {
|
|
292
|
-
const dependentCounts = /* @__PURE__ */ new Map();
|
|
293
|
-
for (const pkg of this.packages) {
|
|
294
|
-
dependentCounts.set(pkg.name, pkg.dependents.length);
|
|
295
|
-
}
|
|
296
|
-
return Array.from(dependentCounts.entries()).sort(([, a], [, b]) => b - a).map(([name]) => name);
|
|
297
|
-
}
|
|
298
|
-
identifyBottlenecks() {
|
|
299
|
-
const bottlenecks = [];
|
|
300
|
-
for (const pkg of this.packages) {
|
|
301
|
-
if (pkg.dependencies.length > 10) {
|
|
302
|
-
bottlenecks.push({
|
|
303
|
-
package: pkg.name,
|
|
304
|
-
type: "many-dependencies",
|
|
305
|
-
impact: pkg.dependencies.length,
|
|
306
|
-
suggestion: `Consider splitting ${pkg.name} - it has ${pkg.dependencies.length} dependencies`
|
|
307
|
-
});
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
const circularDeps = this.findCircularDependencies();
|
|
311
|
-
for (const circular of circularDeps) {
|
|
312
|
-
bottlenecks.push({
|
|
313
|
-
package: circular.packages[0],
|
|
314
|
-
type: "circular-dependency",
|
|
315
|
-
impact: circular.packages.length,
|
|
316
|
-
suggestion: `Resolve circular dependency: ${circular.cycle.join(" \u2192 ")}`
|
|
317
|
-
});
|
|
318
|
-
}
|
|
319
|
-
for (const pkg of this.packages) {
|
|
320
|
-
if (pkg.dependents.length > 5) {
|
|
321
|
-
bottlenecks.push({
|
|
322
|
-
package: pkg.name,
|
|
323
|
-
type: "slow-build",
|
|
324
|
-
impact: pkg.dependents.length,
|
|
325
|
-
suggestion: `Optimize ${pkg.name} - it blocks ${pkg.dependents.length} other packages`
|
|
326
|
-
});
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
return bottlenecks.sort((a, b) => b.impact - a.impact);
|
|
330
|
-
}
|
|
331
|
-
suggestOptimalConcurrency() {
|
|
332
|
-
const maxLevel = this.dependencyGraph.levels.length;
|
|
333
|
-
const avgLevelSize = this.packages.length / maxLevel;
|
|
334
|
-
const cpuCores = require("node:os").cpus().length;
|
|
335
|
-
const suggested = Math.min(Math.ceil(avgLevelSize), cpuCores);
|
|
336
|
-
return Math.max(1, suggested);
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
export const analyzeMonorepo = async (options) => {
|
|
340
|
-
const analyzer = new MonorepoAnalyzer(options);
|
|
341
|
-
return analyzer.analyze();
|
|
342
|
-
};
|
|
343
|
-
export const createMonorepoAnalyzer = (options) => {
|
|
344
|
-
return new MonorepoAnalyzer(options);
|
|
345
|
-
};
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { Measurement, MemoryUsage } from "../types.js";
|
|
2
|
-
export interface CommandExecutionOptions {
|
|
3
|
-
cwd?: string;
|
|
4
|
-
timeout?: number;
|
|
5
|
-
env?: Record<string, string>;
|
|
6
|
-
}
|
|
7
|
-
export interface CommandResult {
|
|
8
|
-
success: boolean;
|
|
9
|
-
duration: number;
|
|
10
|
-
memory: MemoryUsage;
|
|
11
|
-
stdout: string;
|
|
12
|
-
stderr: string;
|
|
13
|
-
error?: string;
|
|
14
|
-
exitCode: number;
|
|
15
|
-
}
|
|
16
|
-
export declare const executeCommand: (command: string, options?: CommandExecutionOptions) => Promise<CommandResult>;
|
|
17
|
-
export declare const executeCommandWithMemoryTracking: (command: string, options?: CommandExecutionOptions) => Promise<Measurement>;
|
|
18
|
-
export declare const isDlerCommand: (command: string) => boolean;
|
|
19
|
-
export declare const isBunCommand: (command: string) => boolean;
|
|
20
|
-
export declare const isNodeCommand: (command: string) => boolean;
|
|
21
|
-
export declare const getCommandType: (command: string) => "dler" | "bun" | "node" | "external";
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
import { existsSync } from "node:fs";
|
|
2
|
-
import { resolve } from "node:path";
|
|
3
|
-
import { lookpath } from "lookpath";
|
|
4
|
-
export const executeCommand = async (command, options = {}) => {
|
|
5
|
-
const startTime = process.hrtime.bigint();
|
|
6
|
-
try {
|
|
7
|
-
const [cmd, ...args] = parseCommand(command);
|
|
8
|
-
if (!cmd) {
|
|
9
|
-
throw new Error("Command is empty");
|
|
10
|
-
}
|
|
11
|
-
const commandPath = await findCommand(cmd);
|
|
12
|
-
if (!commandPath) {
|
|
13
|
-
throw new Error(`Command not found: ${cmd}`);
|
|
14
|
-
}
|
|
15
|
-
const proc = Bun.spawn([commandPath, ...args], {
|
|
16
|
-
cwd: options.cwd ?? process.cwd(),
|
|
17
|
-
env: { ...process.env, ...options.env },
|
|
18
|
-
stdout: "pipe",
|
|
19
|
-
stderr: "pipe"
|
|
20
|
-
});
|
|
21
|
-
let timeoutId;
|
|
22
|
-
if (options.timeout) {
|
|
23
|
-
timeoutId = setTimeout(() => {
|
|
24
|
-
proc.kill();
|
|
25
|
-
}, options.timeout);
|
|
26
|
-
}
|
|
27
|
-
const [stdout, stderr] = await Promise.all([
|
|
28
|
-
new Response(proc.stdout).text(),
|
|
29
|
-
new Response(proc.stderr).text()
|
|
30
|
-
]);
|
|
31
|
-
const exitCode = await proc.exited;
|
|
32
|
-
const endTime = process.hrtime.bigint();
|
|
33
|
-
const endMemory = process.memoryUsage();
|
|
34
|
-
if (timeoutId) {
|
|
35
|
-
clearTimeout(timeoutId);
|
|
36
|
-
}
|
|
37
|
-
const duration = Number(endTime - startTime) / 1e6;
|
|
38
|
-
return {
|
|
39
|
-
success: exitCode === 0,
|
|
40
|
-
duration,
|
|
41
|
-
memory: {
|
|
42
|
-
rss: endMemory.rss,
|
|
43
|
-
heapTotal: endMemory.heapTotal,
|
|
44
|
-
heapUsed: endMemory.heapUsed,
|
|
45
|
-
external: endMemory.external,
|
|
46
|
-
arrayBuffers: endMemory.arrayBuffers
|
|
47
|
-
},
|
|
48
|
-
stdout,
|
|
49
|
-
stderr,
|
|
50
|
-
exitCode
|
|
51
|
-
};
|
|
52
|
-
} catch (error) {
|
|
53
|
-
const endTime = process.hrtime.bigint();
|
|
54
|
-
const endMemory = process.memoryUsage();
|
|
55
|
-
const duration = Number(endTime - startTime) / 1e6;
|
|
56
|
-
return {
|
|
57
|
-
success: false,
|
|
58
|
-
duration,
|
|
59
|
-
memory: {
|
|
60
|
-
rss: endMemory.rss,
|
|
61
|
-
heapTotal: endMemory.heapTotal,
|
|
62
|
-
heapUsed: endMemory.heapUsed,
|
|
63
|
-
external: endMemory.external,
|
|
64
|
-
arrayBuffers: endMemory.arrayBuffers
|
|
65
|
-
},
|
|
66
|
-
stdout: "",
|
|
67
|
-
stderr: "",
|
|
68
|
-
error: error instanceof Error ? error.message : String(error),
|
|
69
|
-
exitCode: 1
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
|
-
export const executeCommandWithMemoryTracking = async (command, options = {}) => {
|
|
74
|
-
const result = await executeCommand(command, options);
|
|
75
|
-
const endMemory = process.memoryUsage();
|
|
76
|
-
return {
|
|
77
|
-
run: 0,
|
|
78
|
-
// Will be set by the runner
|
|
79
|
-
duration: result.duration,
|
|
80
|
-
memory: {
|
|
81
|
-
rss: endMemory.rss,
|
|
82
|
-
heapTotal: endMemory.heapTotal,
|
|
83
|
-
heapUsed: endMemory.heapUsed,
|
|
84
|
-
external: endMemory.external,
|
|
85
|
-
arrayBuffers: endMemory.arrayBuffers
|
|
86
|
-
},
|
|
87
|
-
success: result.success,
|
|
88
|
-
error: result.error,
|
|
89
|
-
stdout: result.stdout,
|
|
90
|
-
stderr: result.stderr
|
|
91
|
-
};
|
|
92
|
-
};
|
|
93
|
-
const parseCommand = (command) => {
|
|
94
|
-
const parts = [];
|
|
95
|
-
let current = "";
|
|
96
|
-
let inQuotes = false;
|
|
97
|
-
let quoteChar = "";
|
|
98
|
-
for (let i = 0; i < command.length; i++) {
|
|
99
|
-
const char = command[i];
|
|
100
|
-
if (char === '"' || char === "'") {
|
|
101
|
-
if (!inQuotes) {
|
|
102
|
-
inQuotes = true;
|
|
103
|
-
quoteChar = char;
|
|
104
|
-
} else if (char === quoteChar) {
|
|
105
|
-
inQuotes = false;
|
|
106
|
-
quoteChar = "";
|
|
107
|
-
} else {
|
|
108
|
-
current += char;
|
|
109
|
-
}
|
|
110
|
-
} else if (char === " " && !inQuotes) {
|
|
111
|
-
if (current.trim()) {
|
|
112
|
-
parts.push(current.trim());
|
|
113
|
-
current = "";
|
|
114
|
-
}
|
|
115
|
-
} else {
|
|
116
|
-
current += char;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
if (current.trim()) {
|
|
120
|
-
parts.push(current.trim());
|
|
121
|
-
}
|
|
122
|
-
return parts;
|
|
123
|
-
};
|
|
124
|
-
const findCommand = async (cmd) => {
|
|
125
|
-
if (!cmd) {
|
|
126
|
-
return null;
|
|
127
|
-
}
|
|
128
|
-
if (cmd === "dler") {
|
|
129
|
-
return "bun";
|
|
130
|
-
}
|
|
131
|
-
if (cmd === "bun") {
|
|
132
|
-
return "bun";
|
|
133
|
-
}
|
|
134
|
-
if (cmd === "node") {
|
|
135
|
-
return "node";
|
|
136
|
-
}
|
|
137
|
-
if (cmd.includes("/") || cmd.includes("\\")) {
|
|
138
|
-
const fullPath = resolve(cmd);
|
|
139
|
-
return existsSync(fullPath) ? fullPath : null;
|
|
140
|
-
}
|
|
141
|
-
try {
|
|
142
|
-
const path = await lookpath(cmd);
|
|
143
|
-
return path ?? null;
|
|
144
|
-
} catch {
|
|
145
|
-
return null;
|
|
146
|
-
}
|
|
147
|
-
};
|
|
148
|
-
export const isDlerCommand = (command) => {
|
|
149
|
-
return command.startsWith("dler ") || command === "dler";
|
|
150
|
-
};
|
|
151
|
-
export const isBunCommand = (command) => {
|
|
152
|
-
return command.startsWith("bun ") || command === "bun";
|
|
153
|
-
};
|
|
154
|
-
export const isNodeCommand = (command) => {
|
|
155
|
-
return command.startsWith("node ") || command === "node";
|
|
156
|
-
};
|
|
157
|
-
export const getCommandType = (command) => {
|
|
158
|
-
if (isDlerCommand(command)) return "dler";
|
|
159
|
-
if (isBunCommand(command)) return "bun";
|
|
160
|
-
if (isNodeCommand(command)) return "node";
|
|
161
|
-
return "external";
|
|
162
|
-
};
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import type { MemoryUsage } from "../types.js";
|
|
2
|
-
export interface MemoryProfile {
|
|
3
|
-
timestamp: number;
|
|
4
|
-
memory: MemoryUsage;
|
|
5
|
-
label?: string;
|
|
6
|
-
}
|
|
7
|
-
export interface MemorySnapshot {
|
|
8
|
-
before: MemoryUsage;
|
|
9
|
-
after: MemoryUsage;
|
|
10
|
-
peak: MemoryUsage;
|
|
11
|
-
growth: number;
|
|
12
|
-
duration: number;
|
|
13
|
-
}
|
|
14
|
-
export declare class MemoryProfiler {
|
|
15
|
-
private snapshots;
|
|
16
|
-
private startMemory;
|
|
17
|
-
private peakMemory;
|
|
18
|
-
start(label?: string): void;
|
|
19
|
-
snapshot(label?: string): void;
|
|
20
|
-
stop(): MemorySnapshot | null;
|
|
21
|
-
getSnapshots(): MemoryProfile[];
|
|
22
|
-
getMemoryGrowth(): number;
|
|
23
|
-
getPeakMemory(): MemoryUsage | null;
|
|
24
|
-
getAverageMemory(): MemoryUsage | null;
|
|
25
|
-
}
|
|
26
|
-
export declare const createMemoryProfiler: () => MemoryProfiler;
|
|
27
|
-
export declare const measureMemoryUsage: (fn: () => void | Promise<void>) => Promise<MemorySnapshot>;
|
|
28
|
-
export declare const getCurrentMemoryUsage: () => MemoryUsage;
|
|
29
|
-
export declare const getMemoryInfo: () => {
|
|
30
|
-
total: number;
|
|
31
|
-
free: number;
|
|
32
|
-
used: number;
|
|
33
|
-
percentage: number;
|
|
34
|
-
};
|
|
35
|
-
export declare const formatMemoryUsage: (usage: MemoryUsage) => string;
|
|
36
|
-
export declare const detectMemoryLeaks: (snapshots: MemoryProfile[]) => {
|
|
37
|
-
hasLeak: boolean;
|
|
38
|
-
severity: "low" | "medium" | "high";
|
|
39
|
-
growthRate: number;
|
|
40
|
-
suggestion: string;
|
|
41
|
-
};
|