@beignet/cli 0.0.50 → 0.0.52
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/CHANGELOG.md +32 -0
- package/README.md +64 -22
- package/dist/analysis/layers.d.ts.map +1 -1
- package/dist/analysis/layers.js +4 -2
- package/dist/analysis/layers.js.map +1 -1
- package/dist/analysis/port-wiring.d.ts.map +1 -1
- package/dist/analysis/port-wiring.js +2 -1
- package/dist/analysis/port-wiring.js.map +1 -1
- package/dist/analysis/source-files.d.ts +15 -0
- package/dist/analysis/source-files.d.ts.map +1 -0
- package/dist/analysis/source-files.js +52 -0
- package/dist/analysis/source-files.js.map +1 -0
- package/dist/analysis/workspace.d.ts.map +1 -1
- package/dist/analysis/workspace.js +21 -25
- package/dist/analysis/workspace.js.map +1 -1
- package/dist/app-map-changes.d.ts.map +1 -1
- package/dist/app-map-changes.js +5 -7
- package/dist/app-map-changes.js.map +1 -1
- package/dist/app-map.d.ts.map +1 -1
- package/dist/app-map.js +33 -30
- package/dist/app-map.js.map +1 -1
- package/dist/check.d.ts +12 -0
- package/dist/check.d.ts.map +1 -1
- package/dist/check.js +92 -25
- package/dist/check.js.map +1 -1
- package/dist/git-changes.d.ts +17 -1
- package/dist/git-changes.d.ts.map +1 -1
- package/dist/git-changes.js +118 -84
- package/dist/git-changes.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +35 -6
- package/dist/index.js.map +1 -1
- package/dist/inspect.d.ts.map +1 -1
- package/dist/inspect.js +436 -112
- package/dist/inspect.js.map +1 -1
- package/dist/lint.d.ts.map +1 -1
- package/dist/lint.js +3 -6
- package/dist/lint.js.map +1 -1
- package/dist/make.d.ts.map +1 -1
- package/dist/make.js +0 -2
- package/dist/make.js.map +1 -1
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +23 -5
- package/dist/mcp.js.map +1 -1
- package/dist/operational-process.d.ts +1 -0
- package/dist/operational-process.d.ts.map +1 -1
- package/dist/operational-process.js.map +1 -1
- package/dist/operational-runner.js +1 -0
- package/dist/operational-runner.js.map +1 -1
- package/dist/outbox.d.ts +1 -0
- package/dist/outbox.d.ts.map +1 -1
- package/dist/outbox.js +58 -12
- package/dist/outbox.js.map +1 -1
- package/dist/templates/agents.d.ts.map +1 -1
- package/dist/templates/agents.js +43 -15
- package/dist/templates/agents.js.map +1 -1
- package/dist/templates/base.js +5 -5
- package/dist/templates/db/mysql.d.ts.map +1 -1
- package/dist/templates/db/mysql.js +51 -22
- package/dist/templates/db/mysql.js.map +1 -1
- package/dist/templates/db/postgres.d.ts.map +1 -1
- package/dist/templates/db/postgres.js +60 -20
- package/dist/templates/db/postgres.js.map +1 -1
- package/dist/templates/db/sqlite.d.ts.map +1 -1
- package/dist/templates/db/sqlite.js +51 -23
- package/dist/templates/db/sqlite.js.map +1 -1
- package/dist/templates/shadcn.js +1 -1
- package/dist/templates/shadcn.js.map +1 -1
- package/dist/templates/shared.js +4 -4
- package/dist/templates/shared.js.map +1 -1
- package/dist/templates/testing.d.ts.map +1 -1
- package/dist/templates/testing.js +7 -19
- package/dist/templates/testing.js.map +1 -1
- package/dist/test-discovery.d.ts +9 -0
- package/dist/test-discovery.d.ts.map +1 -0
- package/dist/test-discovery.js +40 -0
- package/dist/test-discovery.js.map +1 -0
- package/package.json +7 -5
- package/skills/app-structure/SKILL.md +37 -10
- package/src/analysis/layers.ts +4 -2
- package/src/analysis/port-wiring.ts +2 -1
- package/src/analysis/source-files.ts +61 -0
- package/src/analysis/workspace.ts +27 -31
- package/src/app-map-changes.ts +10 -8
- package/src/app-map.ts +43 -32
- package/src/check.ts +115 -25
- package/src/git-changes.ts +218 -86
- package/src/index.ts +53 -8
- package/src/inspect.ts +627 -146
- package/src/lint.ts +6 -5
- package/src/make.ts +0 -2
- package/src/mcp.ts +34 -11
- package/src/operational-process.ts +1 -0
- package/src/operational-runner.ts +1 -0
- package/src/outbox.ts +63 -12
- package/src/templates/agents.ts +43 -15
- package/src/templates/base.ts +5 -5
- package/src/templates/db/mysql.ts +51 -22
- package/src/templates/db/postgres.ts +60 -20
- package/src/templates/db/sqlite.ts +51 -23
- package/src/templates/shadcn.ts +1 -1
- package/src/templates/shared.ts +4 -4
- package/src/templates/testing.ts +12 -19
- package/src/test-discovery.ts +53 -0
package/src/app-map.ts
CHANGED
|
@@ -6,6 +6,10 @@ import {
|
|
|
6
6
|
isImportedContractDeclaration,
|
|
7
7
|
} from "./analysis/contract-factories.js";
|
|
8
8
|
import { analyzePortWiring } from "./analysis/port-wiring.js";
|
|
9
|
+
import {
|
|
10
|
+
isAnalysisSourceFile,
|
|
11
|
+
stripSourceFileExtension,
|
|
12
|
+
} from "./analysis/source-files.js";
|
|
9
13
|
import {
|
|
10
14
|
createSourceIndex,
|
|
11
15
|
exportedVariableDeclarations,
|
|
@@ -29,6 +33,11 @@ import {
|
|
|
29
33
|
} from "./inspect.js";
|
|
30
34
|
import { type LintDiagnostic, lintApp } from "./lint.js";
|
|
31
35
|
import { auditProviders } from "./provider-audit.js";
|
|
36
|
+
import {
|
|
37
|
+
appTestRoots,
|
|
38
|
+
isAppTestFile,
|
|
39
|
+
isWithinAppTestRoots,
|
|
40
|
+
} from "./test-discovery.js";
|
|
32
41
|
|
|
33
42
|
export type { AppMapNodeKind } from "./app-map-schema.js";
|
|
34
43
|
export { appMapNodeKinds } from "./app-map-schema.js";
|
|
@@ -208,6 +217,7 @@ export async function mapApp(
|
|
|
208
217
|
const registries: RegistryRecord[] = [];
|
|
209
218
|
const featuresPath = directoryPath(workspace.config.paths.features);
|
|
210
219
|
const featureNames = discoverFeatureNames(workspace, featuresPath);
|
|
220
|
+
const testRoots = appTestRoots(workspace.config.paths);
|
|
211
221
|
|
|
212
222
|
const addNode = (node: AppMapNode) => {
|
|
213
223
|
const existing = nodes.get(node.id);
|
|
@@ -241,17 +251,23 @@ export async function mapApp(
|
|
|
241
251
|
status: "declared",
|
|
242
252
|
details: roles,
|
|
243
253
|
});
|
|
254
|
+
}
|
|
244
255
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
256
|
+
for (const file of workspace.files.filter(
|
|
257
|
+
(candidate) =>
|
|
258
|
+
isAppTestFile(candidate) && isWithinAppTestRoots(candidate, testRoots),
|
|
259
|
+
)) {
|
|
260
|
+
const id = `test:${file}`;
|
|
261
|
+
const feature = featureForFile(file, featuresPath);
|
|
262
|
+
addNode({
|
|
263
|
+
id,
|
|
264
|
+
kind: "test",
|
|
265
|
+
name: path.posix.basename(file),
|
|
266
|
+
...(feature ? { feature } : {}),
|
|
267
|
+
source: { file },
|
|
268
|
+
status: "declared",
|
|
269
|
+
});
|
|
270
|
+
if (feature) {
|
|
255
271
|
addEdge(exactEdge("contains-test", featureId(feature), id, file));
|
|
256
272
|
}
|
|
257
273
|
}
|
|
@@ -345,7 +361,7 @@ export async function mapApp(
|
|
|
345
361
|
details: { type: "server" },
|
|
346
362
|
});
|
|
347
363
|
}
|
|
348
|
-
const sourceFiles = workspace.files.filter(
|
|
364
|
+
const sourceFiles = workspace.files.filter(isAnalysisSourceFile);
|
|
349
365
|
for (const file of sourceFiles) {
|
|
350
366
|
const sourceFile = await workspace.readSourceFile(file);
|
|
351
367
|
for (const { exportName, declaration } of exportedVariableDeclarations(
|
|
@@ -918,7 +934,8 @@ async function addRouteGroups(args: {
|
|
|
918
934
|
const routeFiles = args.workspace.files.filter(
|
|
919
935
|
(file) =>
|
|
920
936
|
featureForFile(file, args.featuresPath) !== undefined &&
|
|
921
|
-
file
|
|
937
|
+
isAnalysisSourceFile(file) &&
|
|
938
|
+
stripSourceFileExtension(file).endsWith("/routes"),
|
|
922
939
|
);
|
|
923
940
|
|
|
924
941
|
for (const file of routeFiles) {
|
|
@@ -1192,8 +1209,8 @@ async function addOutboxDeliveryGraph(args: {
|
|
|
1192
1209
|
]);
|
|
1193
1210
|
for (const file of args.workspace.files) {
|
|
1194
1211
|
if (
|
|
1195
|
-
!
|
|
1196
|
-
|
|
1212
|
+
!isAnalysisSourceFile(file) ||
|
|
1213
|
+
isAppTestFile(file) ||
|
|
1197
1214
|
![...runtimeDirectories].some(
|
|
1198
1215
|
(directory) =>
|
|
1199
1216
|
directory === "." ||
|
|
@@ -1276,9 +1293,10 @@ function isProviderLifecycleSource(
|
|
|
1276
1293
|
file: string,
|
|
1277
1294
|
sourceFile: ts.SourceFile,
|
|
1278
1295
|
): boolean {
|
|
1296
|
+
const sourcePath = stripSourceFileExtension(file);
|
|
1279
1297
|
if (
|
|
1280
|
-
/(^|\/)provider(s)
|
|
1281
|
-
/(^|\/)[^/]*provider[^/]
|
|
1298
|
+
/(^|\/)provider(s)?$/.test(sourcePath) ||
|
|
1299
|
+
/(^|\/)[^/]*provider[^/]*$/.test(sourcePath) ||
|
|
1282
1300
|
/(^|\/)providers?\//.test(file)
|
|
1283
1301
|
) {
|
|
1284
1302
|
return true;
|
|
@@ -1390,7 +1408,7 @@ async function addTables(args: {
|
|
|
1390
1408
|
const schemaPrefix = `${infraDir}/db/schema/`;
|
|
1391
1409
|
const files = args.workspace.files.filter(
|
|
1392
1410
|
(file) =>
|
|
1393
|
-
|
|
1411
|
+
isAnalysisSourceFile(file) &&
|
|
1394
1412
|
(file.startsWith(schemaPrefix) ||
|
|
1395
1413
|
schemaSources.some((source) =>
|
|
1396
1414
|
file.startsWith(staticPathPrefix(source)),
|
|
@@ -1447,7 +1465,7 @@ async function addFeatureDependencies(args: {
|
|
|
1447
1465
|
}
|
|
1448
1466
|
>();
|
|
1449
1467
|
|
|
1450
|
-
for (const file of args.workspace.files.filter(
|
|
1468
|
+
for (const file of args.workspace.files.filter(isAnalysisSourceFile)) {
|
|
1451
1469
|
const from = featureForFile(file, args.featuresPath);
|
|
1452
1470
|
if (!from || !args.featureNames.has(from)) continue;
|
|
1453
1471
|
for (const reference of await localImportReferences(args.workspace, file)) {
|
|
@@ -1496,7 +1514,7 @@ async function addUnresolvedLocalImports(args: {
|
|
|
1496
1514
|
workspace: AnalysisWorkspace;
|
|
1497
1515
|
unresolved: AppMapUnresolvedReference[];
|
|
1498
1516
|
}): Promise<void> {
|
|
1499
|
-
for (const file of args.workspace.files.filter(
|
|
1517
|
+
for (const file of args.workspace.files.filter(isAnalysisSourceFile)) {
|
|
1500
1518
|
for (const reference of await localImportReferences(args.workspace, file)) {
|
|
1501
1519
|
if (reference.resolvedFile) continue;
|
|
1502
1520
|
args.unresolved.push({
|
|
@@ -1556,15 +1574,16 @@ function appMapContractSourceFiles(workspace: AnalysisWorkspace): string[] {
|
|
|
1556
1574
|
contractsPath === directoryPath(workspace.config.paths.features);
|
|
1557
1575
|
|
|
1558
1576
|
return workspace.files.filter((file) => {
|
|
1559
|
-
if (!file
|
|
1577
|
+
if (!isAnalysisSourceFile(file) || isAppTestFile(file)) return false;
|
|
1578
|
+
const sourcePath = stripSourceFileExtension(file);
|
|
1560
1579
|
if (featureOwned) {
|
|
1561
1580
|
const prefix = `${contractsPath}/`;
|
|
1562
1581
|
if (!file.startsWith(prefix)) return false;
|
|
1563
|
-
const parts =
|
|
1564
|
-
return parts.length === 2 && parts[1] === "contracts
|
|
1582
|
+
const parts = sourcePath.slice(prefix.length).split("/");
|
|
1583
|
+
return parts.length === 2 && parts[1] === "contracts";
|
|
1565
1584
|
}
|
|
1566
1585
|
return (
|
|
1567
|
-
|
|
1586
|
+
sourcePath === contractsPath || sourcePath.startsWith(`${contractsPath}/`)
|
|
1568
1587
|
);
|
|
1569
1588
|
});
|
|
1570
1589
|
}
|
|
@@ -1824,7 +1843,7 @@ function summarizeFeatureFiles(files: string[]): Record<string, number> {
|
|
|
1824
1843
|
client: files.filter((file) => file.includes("/client/")).length,
|
|
1825
1844
|
components: files.filter((file) => file.includes("/components/")).length,
|
|
1826
1845
|
domain: files.filter((file) => file.includes("/domain/")).length,
|
|
1827
|
-
tests: files.filter(
|
|
1846
|
+
tests: files.filter(isAppTestFile).length,
|
|
1828
1847
|
};
|
|
1829
1848
|
}
|
|
1830
1849
|
|
|
@@ -2017,14 +2036,6 @@ function sourceNodeEdge(
|
|
|
2017
2036
|
};
|
|
2018
2037
|
}
|
|
2019
2038
|
|
|
2020
|
-
function isTestFile(file: string): boolean {
|
|
2021
|
-
return /\.(test|spec)\.(ts|tsx|mts|cts)$/.test(file);
|
|
2022
|
-
}
|
|
2023
|
-
|
|
2024
|
-
function isTypeScriptSource(file: string): boolean {
|
|
2025
|
-
return /\.(ts|tsx|mts|cts)$/.test(file) && !file.endsWith(".d.ts");
|
|
2026
|
-
}
|
|
2027
|
-
|
|
2028
2039
|
function staticPathPrefix(pattern: string): string {
|
|
2029
2040
|
const wildcard = pattern.search(/[?*[{]/);
|
|
2030
2041
|
return wildcard === -1 ? pattern : pattern.slice(0, wildcard);
|
package/src/check.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
import { readdir, readFile, stat } from "node:fs/promises";
|
|
1
|
+
import { readdir, readFile, realpath, stat } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { createPainter } from "./ansi.js";
|
|
4
4
|
import { detectPackageManager, spawnCommand } from "./db.js";
|
|
5
|
+
import {
|
|
6
|
+
type GitSourceSnapshot,
|
|
7
|
+
readGitSourceSnapshot,
|
|
8
|
+
} from "./git-changes.js";
|
|
5
9
|
import {
|
|
6
10
|
applyDoctorFixes,
|
|
7
11
|
formatDoctor,
|
|
@@ -33,6 +37,14 @@ export type CheckAppResult = {
|
|
|
33
37
|
ok: boolean;
|
|
34
38
|
fixes: InspectFix[];
|
|
35
39
|
steps: CheckStep[];
|
|
40
|
+
provenance: CheckProvenance;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/** Source-state evidence captured around one complete check run. */
|
|
44
|
+
export type CheckProvenance = {
|
|
45
|
+
status: "current" | "stale" | "unavailable";
|
|
46
|
+
start: GitSourceSnapshot;
|
|
47
|
+
end: GitSourceSnapshot;
|
|
36
48
|
};
|
|
37
49
|
|
|
38
50
|
export type CheckAppOptions = {
|
|
@@ -74,19 +86,34 @@ const defaultMaxOutputBytes = 64 * 1024;
|
|
|
74
86
|
export async function checkApp(
|
|
75
87
|
options: CheckAppOptions = {},
|
|
76
88
|
): Promise<CheckAppResult> {
|
|
77
|
-
|
|
78
|
-
const
|
|
79
|
-
|
|
89
|
+
options.signal?.throwIfAborted();
|
|
90
|
+
const targetDir = await resolveCheckTargetDir(options.cwd ?? process.cwd());
|
|
91
|
+
options.signal?.throwIfAborted();
|
|
92
|
+
// Validate the app root before fixes may write; reload execution metadata
|
|
93
|
+
// after the provenance baseline so the selected scripts are covered by it.
|
|
94
|
+
await readAppPackageScripts(targetDir);
|
|
95
|
+
options.signal?.throwIfAborted();
|
|
96
|
+
const fixes = options.fix
|
|
97
|
+
? await applyDoctorFixes({ cwd: targetDir, strict: true })
|
|
98
|
+
: [];
|
|
99
|
+
options.signal?.throwIfAborted();
|
|
80
100
|
const steps: CheckStep[] = [];
|
|
81
101
|
const record = (step: CheckStep): void => {
|
|
82
102
|
steps.push(step);
|
|
83
103
|
options.onStep?.(step);
|
|
84
104
|
};
|
|
85
105
|
|
|
106
|
+
const start = await readGitSourceSnapshot({
|
|
107
|
+
cwd: targetDir,
|
|
108
|
+
signal: options.signal,
|
|
109
|
+
});
|
|
110
|
+
options.signal?.throwIfAborted();
|
|
111
|
+
const scripts = await readAppPackageScripts(targetDir);
|
|
112
|
+
const runner = await detectPackageManager(targetDir);
|
|
86
113
|
options.signal?.throwIfAborted();
|
|
87
114
|
record(await lintStep(targetDir, options));
|
|
88
115
|
options.signal?.throwIfAborted();
|
|
89
|
-
const
|
|
116
|
+
const doctorStep = await runDoctorStep(targetDir, options, fixes);
|
|
90
117
|
record(doctorStep);
|
|
91
118
|
|
|
92
119
|
if (options.preflight || options.preflightConnect) {
|
|
@@ -105,16 +132,38 @@ export async function checkApp(
|
|
|
105
132
|
record(await scriptStep(targetDir, runner, script, scripts, options));
|
|
106
133
|
}
|
|
107
134
|
|
|
135
|
+
options.signal?.throwIfAborted();
|
|
136
|
+
const end = await readGitSourceSnapshot({
|
|
137
|
+
cwd: targetDir,
|
|
138
|
+
signal: options.signal,
|
|
139
|
+
});
|
|
140
|
+
options.signal?.throwIfAborted();
|
|
141
|
+
const provenance = checkProvenance(start, end);
|
|
142
|
+
|
|
108
143
|
return {
|
|
109
144
|
schemaVersion: 1,
|
|
110
145
|
targetDir,
|
|
111
146
|
runner,
|
|
112
|
-
ok:
|
|
147
|
+
ok:
|
|
148
|
+
steps.every((step) => step.status !== "failed") &&
|
|
149
|
+
provenance.status !== "stale",
|
|
113
150
|
fixes,
|
|
114
151
|
steps,
|
|
152
|
+
provenance,
|
|
115
153
|
};
|
|
116
154
|
}
|
|
117
155
|
|
|
156
|
+
async function resolveCheckTargetDir(cwd: string): Promise<string> {
|
|
157
|
+
const targetDir = path.resolve(cwd);
|
|
158
|
+
try {
|
|
159
|
+
return await realpath(targetDir);
|
|
160
|
+
} catch (error) {
|
|
161
|
+
const code = (error as NodeJS.ErrnoException).code;
|
|
162
|
+
if (code === "ENOENT" || code === "ENOTDIR") return targetDir;
|
|
163
|
+
throw error;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
118
167
|
/**
|
|
119
168
|
* Format a completed step as a single status line, with the failing step's
|
|
120
169
|
* output indented underneath.
|
|
@@ -161,9 +210,35 @@ export function formatCheckSummary(
|
|
|
161
210
|
const parts = [`${counts.passed} passed`];
|
|
162
211
|
if (counts.failed > 0) parts.push(paint(`${counts.failed} failed`, "red"));
|
|
163
212
|
if (counts.skipped > 0) parts.push(`${counts.skipped} skipped`);
|
|
213
|
+
if (result.provenance.status === "stale") {
|
|
214
|
+
parts.push(paint("source state stale", "red"));
|
|
215
|
+
}
|
|
164
216
|
return parts.join(", ");
|
|
165
217
|
}
|
|
166
218
|
|
|
219
|
+
/** Format the source state captured before and after validation. */
|
|
220
|
+
export function formatCheckProvenance(
|
|
221
|
+
result: CheckAppResult,
|
|
222
|
+
options: { color?: boolean } = {},
|
|
223
|
+
): string {
|
|
224
|
+
const paint = createPainter(options.color);
|
|
225
|
+
const { provenance } = result;
|
|
226
|
+
if (provenance.status === "unavailable") {
|
|
227
|
+
return `${paint("-", "cyan")} Source provenance unavailable (not a Git worktree)`;
|
|
228
|
+
}
|
|
229
|
+
if (provenance.status === "stale") {
|
|
230
|
+
return `${paint("✗", "red")} Source state changed while checks were running; rerun beignet check`;
|
|
231
|
+
}
|
|
232
|
+
const snapshot = provenance.end;
|
|
233
|
+
if (snapshot.kind !== "git") {
|
|
234
|
+
throw new Error("Current check provenance must contain a Git snapshot.");
|
|
235
|
+
}
|
|
236
|
+
const head = snapshot.comparison.head
|
|
237
|
+
? `HEAD ${snapshot.comparison.head.slice(0, 8)}`
|
|
238
|
+
: "unborn Git repository";
|
|
239
|
+
return `${paint("✓", "green")} Source state current (${head}, ${shortHash(snapshot.repositoryChangeHash)})`;
|
|
240
|
+
}
|
|
241
|
+
|
|
167
242
|
/**
|
|
168
243
|
* Format a full result at once (JSON-free callers and tests).
|
|
169
244
|
*/
|
|
@@ -172,6 +247,7 @@ export function formatCheck(
|
|
|
172
247
|
options: { color?: boolean } = {},
|
|
173
248
|
): string {
|
|
174
249
|
const lines = result.steps.map((step) => formatCheckStep(step, options));
|
|
250
|
+
lines.push(formatCheckProvenance(result, options));
|
|
175
251
|
return `${lines.join("\n")}\n\n${formatCheckSummary(result, options)}`;
|
|
176
252
|
}
|
|
177
253
|
|
|
@@ -195,11 +271,9 @@ async function lintStep(
|
|
|
195
271
|
async function runDoctorStep(
|
|
196
272
|
targetDir: string,
|
|
197
273
|
options: CheckAppOptions,
|
|
198
|
-
|
|
274
|
+
fixes: InspectFix[],
|
|
275
|
+
): Promise<CheckStep> {
|
|
199
276
|
const startedAt = Date.now();
|
|
200
|
-
const fixes = options.fix
|
|
201
|
-
? await applyDoctorFixes({ cwd: targetDir, strict: true })
|
|
202
|
-
: [];
|
|
203
277
|
const result = await inspectApp({ cwd: targetDir, strict: true });
|
|
204
278
|
result.fixes = fixes;
|
|
205
279
|
const failed = result.diagnostics.some(
|
|
@@ -208,24 +282,40 @@ async function runDoctorStep(
|
|
|
208
282
|
);
|
|
209
283
|
|
|
210
284
|
return {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
durationMs: Date.now() - startedAt,
|
|
224
|
-
},
|
|
225
|
-
fixes,
|
|
285
|
+
name: "beignet doctor --strict",
|
|
286
|
+
command: "beignet doctor --strict",
|
|
287
|
+
status: failed ? "failed" : "passed",
|
|
288
|
+
...(fixes.length > 0
|
|
289
|
+
? {
|
|
290
|
+
detail: `${fixes.length} ${fixes.length === 1 ? "fix" : "fixes"} applied`,
|
|
291
|
+
}
|
|
292
|
+
: {}),
|
|
293
|
+
...(failed
|
|
294
|
+
? { output: formatDoctor(result, { color: options.color }) }
|
|
295
|
+
: {}),
|
|
296
|
+
durationMs: Date.now() - startedAt,
|
|
226
297
|
};
|
|
227
298
|
}
|
|
228
299
|
|
|
300
|
+
function checkProvenance(
|
|
301
|
+
start: GitSourceSnapshot,
|
|
302
|
+
end: GitSourceSnapshot,
|
|
303
|
+
): CheckProvenance {
|
|
304
|
+
if (start.kind === "unavailable" && end.kind === "unavailable") {
|
|
305
|
+
return { status: "unavailable", start, end };
|
|
306
|
+
}
|
|
307
|
+
const current =
|
|
308
|
+
start.kind === "git" &&
|
|
309
|
+
end.kind === "git" &&
|
|
310
|
+
start.repositoryRoot === end.repositoryRoot &&
|
|
311
|
+
start.repositoryChangeHash === end.repositoryChangeHash;
|
|
312
|
+
return { status: current ? "current" : "stale", start, end };
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
function shortHash(hash: string): string {
|
|
316
|
+
return `${hash.slice(0, 15)}…`;
|
|
317
|
+
}
|
|
318
|
+
|
|
229
319
|
async function scriptStep(
|
|
230
320
|
targetDir: string,
|
|
231
321
|
runner: string,
|