@vertaaux/cli 0.2.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 +345 -0
- package/dist/auth/ci-token.d.ts +49 -0
- package/dist/auth/ci-token.d.ts.map +1 -0
- package/dist/auth/ci-token.js +83 -0
- package/dist/auth/device-flow.d.ts +66 -0
- package/dist/auth/device-flow.d.ts.map +1 -0
- package/dist/auth/device-flow.js +156 -0
- package/dist/auth/token-store.d.ts +53 -0
- package/dist/auth/token-store.d.ts.map +1 -0
- package/dist/auth/token-store.js +78 -0
- package/dist/baseline/diff.d.ts +57 -0
- package/dist/baseline/diff.d.ts.map +1 -0
- package/dist/baseline/diff.js +152 -0
- package/dist/baseline/hash.d.ts +54 -0
- package/dist/baseline/hash.d.ts.map +1 -0
- package/dist/baseline/hash.js +66 -0
- package/dist/baseline/manager.d.ts +89 -0
- package/dist/baseline/manager.d.ts.map +1 -0
- package/dist/baseline/manager.js +157 -0
- package/dist/cache/index.d.ts +8 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +7 -0
- package/dist/cache/route-cache.d.ts +119 -0
- package/dist/cache/route-cache.d.ts.map +1 -0
- package/dist/cache/route-cache.js +213 -0
- package/dist/ci/changed-routes.d.ts +95 -0
- package/dist/ci/changed-routes.d.ts.map +1 -0
- package/dist/ci/changed-routes.js +304 -0
- package/dist/ci/github-api.d.ts +68 -0
- package/dist/ci/github-api.d.ts.map +1 -0
- package/dist/ci/github-api.js +138 -0
- package/dist/ci/gitlab-api.d.ts +75 -0
- package/dist/ci/gitlab-api.d.ts.map +1 -0
- package/dist/ci/gitlab-api.js +180 -0
- package/dist/ci/index.d.ts +6 -0
- package/dist/ci/index.d.ts.map +1 -0
- package/dist/ci/index.js +4 -0
- package/dist/commands/audit.d.ts +58 -0
- package/dist/commands/audit.d.ts.map +1 -0
- package/dist/commands/audit.js +862 -0
- package/dist/commands/baseline.d.ts +22 -0
- package/dist/commands/baseline.d.ts.map +1 -0
- package/dist/commands/baseline.js +210 -0
- package/dist/commands/comment.d.ts +14 -0
- package/dist/commands/comment.d.ts.map +1 -0
- package/dist/commands/comment.js +363 -0
- package/dist/commands/diff.d.ts +24 -0
- package/dist/commands/diff.d.ts.map +1 -0
- package/dist/commands/diff.js +196 -0
- package/dist/commands/doctor.d.ts +58 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +338 -0
- package/dist/commands/download.d.ts +12 -0
- package/dist/commands/download.d.ts.map +1 -0
- package/dist/commands/download.js +183 -0
- package/dist/commands/explain.d.ts +62 -0
- package/dist/commands/explain.d.ts.map +1 -0
- package/dist/commands/explain.js +302 -0
- package/dist/commands/init.d.ts +12 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +212 -0
- package/dist/commands/login.d.ts +14 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +222 -0
- package/dist/commands/policy.d.ts +13 -0
- package/dist/commands/policy.d.ts.map +1 -0
- package/dist/commands/policy.js +347 -0
- package/dist/commands/upload.d.ts +12 -0
- package/dist/commands/upload.d.ts.map +1 -0
- package/dist/commands/upload.js +158 -0
- package/dist/config/defaults.d.ts +21 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +49 -0
- package/dist/config/loader.d.ts +66 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +167 -0
- package/dist/config/schema.d.ts +55 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +6 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1090 -0
- package/dist/interactive/fix-wizard.d.ts +44 -0
- package/dist/interactive/fix-wizard.d.ts.map +1 -0
- package/dist/interactive/fix-wizard.js +286 -0
- package/dist/interactive/init-wizard.d.ts +32 -0
- package/dist/interactive/init-wizard.d.ts.map +1 -0
- package/dist/interactive/init-wizard.js +193 -0
- package/dist/interactive/prompts.d.ts +62 -0
- package/dist/interactive/prompts.d.ts.map +1 -0
- package/dist/interactive/prompts.js +78 -0
- package/dist/monorepo/detector.d.ts +70 -0
- package/dist/monorepo/detector.d.ts.map +1 -0
- package/dist/monorepo/detector.js +278 -0
- package/dist/monorepo/index.d.ts +9 -0
- package/dist/monorepo/index.d.ts.map +1 -0
- package/dist/monorepo/index.js +8 -0
- package/dist/monorepo/workspace.d.ts +142 -0
- package/dist/monorepo/workspace.d.ts.map +1 -0
- package/dist/monorepo/workspace.js +171 -0
- package/dist/output/envelope.d.ts +21 -0
- package/dist/output/envelope.d.ts.map +1 -0
- package/dist/output/envelope.js +27 -0
- package/dist/output/factory.d.ts +73 -0
- package/dist/output/factory.d.ts.map +1 -0
- package/dist/output/factory.js +60 -0
- package/dist/output/formats.d.ts +11 -0
- package/dist/output/formats.d.ts.map +1 -0
- package/dist/output/formats.js +41 -0
- package/dist/output/html.d.ts +45 -0
- package/dist/output/html.d.ts.map +1 -0
- package/dist/output/html.js +607 -0
- package/dist/output/human.d.ts +41 -0
- package/dist/output/human.d.ts.map +1 -0
- package/dist/output/human.js +274 -0
- package/dist/output/json.d.ts +42 -0
- package/dist/output/json.d.ts.map +1 -0
- package/dist/output/json.js +37 -0
- package/dist/output/junit.d.ts +56 -0
- package/dist/output/junit.d.ts.map +1 -0
- package/dist/output/junit.js +135 -0
- package/dist/output/markdown.d.ts +77 -0
- package/dist/output/markdown.d.ts.map +1 -0
- package/dist/output/markdown.js +411 -0
- package/dist/output/sarif.d.ts +160 -0
- package/dist/output/sarif.d.ts.map +1 -0
- package/dist/output/sarif.js +207 -0
- package/dist/policy/evaluator.d.ts +111 -0
- package/dist/policy/evaluator.d.ts.map +1 -0
- package/dist/policy/evaluator.js +362 -0
- package/dist/policy/index.d.ts +15 -0
- package/dist/policy/index.d.ts.map +1 -0
- package/dist/policy/index.js +11 -0
- package/dist/policy/loader.d.ts +97 -0
- package/dist/policy/loader.d.ts.map +1 -0
- package/dist/policy/loader.js +281 -0
- package/dist/policy/schema.d.ts +297 -0
- package/dist/policy/schema.d.ts.map +1 -0
- package/dist/policy/schema.js +230 -0
- package/dist/quality-gate/evaluator.d.ts +58 -0
- package/dist/quality-gate/evaluator.d.ts.map +1 -0
- package/dist/quality-gate/evaluator.js +274 -0
- package/dist/quality-gate/index.d.ts +10 -0
- package/dist/quality-gate/index.d.ts.map +1 -0
- package/dist/quality-gate/index.js +7 -0
- package/dist/quality-gate/types.d.ts +103 -0
- package/dist/quality-gate/types.d.ts.map +1 -0
- package/dist/quality-gate/types.js +23 -0
- package/dist/templates/azure-devops.d.ts +25 -0
- package/dist/templates/azure-devops.d.ts.map +1 -0
- package/dist/templates/azure-devops.js +109 -0
- package/dist/templates/circleci.d.ts +28 -0
- package/dist/templates/circleci.d.ts.map +1 -0
- package/dist/templates/circleci.js +86 -0
- package/dist/templates/github-actions.d.ts +81 -0
- package/dist/templates/github-actions.d.ts.map +1 -0
- package/dist/templates/github-actions.js +393 -0
- package/dist/templates/gitlab-ci.d.ts +26 -0
- package/dist/templates/gitlab-ci.d.ts.map +1 -0
- package/dist/templates/gitlab-ci.js +70 -0
- package/dist/templates/index.d.ts +72 -0
- package/dist/templates/index.d.ts.map +1 -0
- package/dist/templates/index.js +112 -0
- package/dist/templates/jenkins.d.ts +26 -0
- package/dist/templates/jenkins.d.ts.map +1 -0
- package/dist/templates/jenkins.js +110 -0
- package/dist/ui/banner.d.ts +31 -0
- package/dist/ui/banner.d.ts.map +1 -0
- package/dist/ui/banner.js +84 -0
- package/dist/ui/diagnostics.d.ts +39 -0
- package/dist/ui/diagnostics.d.ts.map +1 -0
- package/dist/ui/diagnostics.js +153 -0
- package/dist/ui/spinner.d.ts +61 -0
- package/dist/ui/spinner.d.ts.map +1 -0
- package/dist/ui/spinner.js +101 -0
- package/dist/ui/table.d.ts +63 -0
- package/dist/ui/table.d.ts.map +1 -0
- package/dist/ui/table.js +236 -0
- package/dist/utils/client.d.ts +82 -0
- package/dist/utils/client.d.ts.map +1 -0
- package/dist/utils/client.js +128 -0
- package/dist/utils/detect-env.d.ts +59 -0
- package/dist/utils/detect-env.d.ts.map +1 -0
- package/dist/utils/detect-env.js +115 -0
- package/dist/utils/exit-codes.d.ts +47 -0
- package/dist/utils/exit-codes.d.ts.map +1 -0
- package/dist/utils/exit-codes.js +61 -0
- package/dist/utils/logger.d.ts +87 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +185 -0
- package/dist/utils/sanitize.d.ts +36 -0
- package/dist/utils/sanitize.d.ts.map +1 -0
- package/dist/utils/sanitize.js +64 -0
- package/dist/utils/validators.d.ts +41 -0
- package/dist/utils/validators.d.ts.map +1 -0
- package/dist/utils/validators.js +123 -0
- package/package.json +63 -0
- package/schemas/vertaaux.config.schema.json +103 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reusable prompt patterns for interactive CLI mode.
|
|
3
|
+
*
|
|
4
|
+
* Wraps @inquirer/prompts with consistent styling.
|
|
5
|
+
* Keyboard navigation is handled natively by @inquirer/prompts:
|
|
6
|
+
* - Arrow keys for navigation
|
|
7
|
+
* - Enter to confirm
|
|
8
|
+
* - Space to select (multi-select)
|
|
9
|
+
*/
|
|
10
|
+
import { select, confirm, input } from "@inquirer/prompts";
|
|
11
|
+
/**
|
|
12
|
+
* Prompt user to select from a list of options.
|
|
13
|
+
*
|
|
14
|
+
* Uses arrow keys for navigation, Enter to confirm.
|
|
15
|
+
*
|
|
16
|
+
* @param message - Prompt message
|
|
17
|
+
* @param choices - List of options
|
|
18
|
+
* @returns Selected value
|
|
19
|
+
*/
|
|
20
|
+
export async function selectAction(message, choices) {
|
|
21
|
+
return select({
|
|
22
|
+
message,
|
|
23
|
+
choices: choices.map((c) => ({
|
|
24
|
+
name: c.name,
|
|
25
|
+
value: c.value,
|
|
26
|
+
description: c.description,
|
|
27
|
+
disabled: c.disabled,
|
|
28
|
+
})),
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Prompt user for yes/no confirmation.
|
|
33
|
+
*
|
|
34
|
+
* @param message - Question to confirm
|
|
35
|
+
* @param defaultValue - Default value if user just presses Enter
|
|
36
|
+
* @returns true for yes, false for no
|
|
37
|
+
*/
|
|
38
|
+
export async function confirmAction(message, defaultValue = true) {
|
|
39
|
+
return confirm({
|
|
40
|
+
message,
|
|
41
|
+
default: defaultValue,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Prompt user for text input.
|
|
46
|
+
*
|
|
47
|
+
* @param message - Prompt message
|
|
48
|
+
* @param defaultValue - Optional default value
|
|
49
|
+
* @param required - Whether input is required (default: false)
|
|
50
|
+
* @returns User input string
|
|
51
|
+
*/
|
|
52
|
+
export async function inputText(message, defaultValue, required = false) {
|
|
53
|
+
return input({
|
|
54
|
+
message,
|
|
55
|
+
default: defaultValue,
|
|
56
|
+
validate: required
|
|
57
|
+
? (value) => (value.trim() ? true : "This field is required")
|
|
58
|
+
: undefined,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Check if running in an interactive TTY environment.
|
|
63
|
+
*
|
|
64
|
+
* @returns true if stdin/stdout are TTY
|
|
65
|
+
*/
|
|
66
|
+
export function isInteractive() {
|
|
67
|
+
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Assert that the environment is interactive, throwing if not.
|
|
71
|
+
*
|
|
72
|
+
* @throws Error if not in interactive TTY mode
|
|
73
|
+
*/
|
|
74
|
+
export function requireInteractive() {
|
|
75
|
+
if (!isInteractive()) {
|
|
76
|
+
throw new Error("Interactive mode requires a terminal. Use --format json in CI or piped environments.");
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Monorepo detection and workspace discovery.
|
|
3
|
+
*
|
|
4
|
+
* Supports:
|
|
5
|
+
* - npm/yarn/pnpm workspaces
|
|
6
|
+
* - Nx monorepos
|
|
7
|
+
* - Turborepo
|
|
8
|
+
* - Lerna
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Monorepo configuration detected from project root.
|
|
12
|
+
*/
|
|
13
|
+
export interface MonorepoConfig {
|
|
14
|
+
/** Type of monorepo detected */
|
|
15
|
+
type: "npm" | "yarn" | "pnpm" | "nx" | "turbo" | "lerna" | "none";
|
|
16
|
+
/** Root directory of the monorepo */
|
|
17
|
+
root: string;
|
|
18
|
+
/** Detected workspaces */
|
|
19
|
+
workspaces: Workspace[];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Individual workspace in a monorepo.
|
|
23
|
+
*/
|
|
24
|
+
export interface Workspace {
|
|
25
|
+
/** Package name from package.json */
|
|
26
|
+
name: string;
|
|
27
|
+
/** Relative path from monorepo root */
|
|
28
|
+
path: string;
|
|
29
|
+
/** Absolute path to package.json */
|
|
30
|
+
packageJson: string;
|
|
31
|
+
/** Scripts defined in package.json */
|
|
32
|
+
scripts?: Record<string, string>;
|
|
33
|
+
/** Detected app type for URL inference */
|
|
34
|
+
appType?: "nextjs" | "remix" | "sveltekit" | "vite" | "cra" | "unknown";
|
|
35
|
+
/** Inferred dev server URL if detectable */
|
|
36
|
+
url?: string;
|
|
37
|
+
/** Inferred dev server port */
|
|
38
|
+
port?: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Package.json structure (partial).
|
|
42
|
+
*/
|
|
43
|
+
interface PackageJson {
|
|
44
|
+
name?: string;
|
|
45
|
+
workspaces?: string[] | {
|
|
46
|
+
packages: string[];
|
|
47
|
+
};
|
|
48
|
+
scripts?: Record<string, string>;
|
|
49
|
+
dependencies?: Record<string, string>;
|
|
50
|
+
devDependencies?: Record<string, string>;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Detect monorepo configuration from project root.
|
|
54
|
+
*
|
|
55
|
+
* @param projectRoot - Root directory to scan (defaults to cwd)
|
|
56
|
+
* @returns MonorepoConfig with detected type and workspaces
|
|
57
|
+
*/
|
|
58
|
+
export declare function detectMonorepo(projectRoot?: string): Promise<MonorepoConfig>;
|
|
59
|
+
/**
|
|
60
|
+
* Get list of auditable apps from monorepo.
|
|
61
|
+
*
|
|
62
|
+
* Filters workspaces to only those that are web apps with dev servers,
|
|
63
|
+
* excluding libraries and tools.
|
|
64
|
+
*
|
|
65
|
+
* @param config - MonorepoConfig from detectMonorepo
|
|
66
|
+
* @returns List of auditable workspaces
|
|
67
|
+
*/
|
|
68
|
+
export declare function getAuditableApps(config: MonorepoConfig): Workspace[];
|
|
69
|
+
export type { PackageJson };
|
|
70
|
+
//# sourceMappingURL=detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detector.d.ts","sourceRoot":"","sources":["../../src/monorepo/detector.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,gCAAgC;IAChC,IAAI,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,CAAC;IAClE,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,0BAA0B;IAC1B,UAAU,EAAE,SAAS,EAAE,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,oCAAoC;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,sCAAsC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,0CAA0C;IAC1C,OAAO,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,WAAW,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,CAAC;IACxE,4CAA4C;IAC5C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,UAAU,WAAW;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG;QAAE,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAC/C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1C;AAuLD;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,cAAc,CAAC,CA+FzB;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,cAAc,GAAG,SAAS,EAAE,CAEpE;AAGD,YAAY,EAAE,WAAW,EAAE,CAAC"}
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Monorepo detection and workspace discovery.
|
|
3
|
+
*
|
|
4
|
+
* Supports:
|
|
5
|
+
* - npm/yarn/pnpm workspaces
|
|
6
|
+
* - Nx monorepos
|
|
7
|
+
* - Turborepo
|
|
8
|
+
* - Lerna
|
|
9
|
+
*/
|
|
10
|
+
import fs from "fs";
|
|
11
|
+
import path from "path";
|
|
12
|
+
/**
|
|
13
|
+
* Expand glob patterns to actual directory paths.
|
|
14
|
+
*/
|
|
15
|
+
function expandGlobPatterns(root, patterns) {
|
|
16
|
+
const results = [];
|
|
17
|
+
for (const pattern of patterns) {
|
|
18
|
+
// Handle simple glob patterns like "packages/*" or "apps/*"
|
|
19
|
+
if (pattern.endsWith("/*")) {
|
|
20
|
+
const basePath = pattern.slice(0, -2);
|
|
21
|
+
const fullBasePath = path.join(root, basePath);
|
|
22
|
+
if (fs.existsSync(fullBasePath)) {
|
|
23
|
+
const entries = fs.readdirSync(fullBasePath, { withFileTypes: true });
|
|
24
|
+
for (const entry of entries) {
|
|
25
|
+
if (entry.isDirectory()) {
|
|
26
|
+
const pkgJsonPath = path.join(fullBasePath, entry.name, "package.json");
|
|
27
|
+
if (fs.existsSync(pkgJsonPath)) {
|
|
28
|
+
results.push(path.join(basePath, entry.name));
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
else if (pattern.includes("**")) {
|
|
35
|
+
// Recursive glob - simplified implementation
|
|
36
|
+
// For "packages/**" pattern, scan all subdirectories
|
|
37
|
+
const basePath = pattern.split("**")[0].replace(/\/$/, "");
|
|
38
|
+
const fullBasePath = path.join(root, basePath);
|
|
39
|
+
if (fs.existsSync(fullBasePath)) {
|
|
40
|
+
const scanDir = (dir, relativePath) => {
|
|
41
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
42
|
+
for (const entry of entries) {
|
|
43
|
+
if (entry.isDirectory()) {
|
|
44
|
+
const entryPath = path.join(dir, entry.name);
|
|
45
|
+
const entryRelative = path.join(relativePath, entry.name);
|
|
46
|
+
const pkgJsonPath = path.join(entryPath, "package.json");
|
|
47
|
+
if (fs.existsSync(pkgJsonPath)) {
|
|
48
|
+
results.push(entryRelative);
|
|
49
|
+
}
|
|
50
|
+
// Continue scanning deeper
|
|
51
|
+
scanDir(entryPath, entryRelative);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
scanDir(fullBasePath, basePath);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
// Exact path
|
|
60
|
+
const fullPath = path.join(root, pattern);
|
|
61
|
+
const pkgJsonPath = path.join(fullPath, "package.json");
|
|
62
|
+
if (fs.existsSync(pkgJsonPath)) {
|
|
63
|
+
results.push(pattern);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return results;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Read and parse package.json file.
|
|
71
|
+
*/
|
|
72
|
+
function readPackageJson(pkgJsonPath) {
|
|
73
|
+
try {
|
|
74
|
+
const content = fs.readFileSync(pkgJsonPath, "utf-8");
|
|
75
|
+
return JSON.parse(content);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Detect app type from package.json dependencies.
|
|
83
|
+
*/
|
|
84
|
+
function detectAppType(pkg) {
|
|
85
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
86
|
+
// Check for Next.js
|
|
87
|
+
if (deps.next) {
|
|
88
|
+
return "nextjs";
|
|
89
|
+
}
|
|
90
|
+
// Check for Remix
|
|
91
|
+
if (deps["@remix-run/react"] || deps["@remix-run/node"]) {
|
|
92
|
+
return "remix";
|
|
93
|
+
}
|
|
94
|
+
// Check for SvelteKit
|
|
95
|
+
if (deps["@sveltejs/kit"]) {
|
|
96
|
+
return "sveltekit";
|
|
97
|
+
}
|
|
98
|
+
// Check for Create React App
|
|
99
|
+
if (deps["react-scripts"]) {
|
|
100
|
+
return "cra";
|
|
101
|
+
}
|
|
102
|
+
// Check for Vite (generic, check last as many frameworks use Vite)
|
|
103
|
+
if (deps.vite) {
|
|
104
|
+
return "vite";
|
|
105
|
+
}
|
|
106
|
+
return "unknown";
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Get default port for app type.
|
|
110
|
+
*/
|
|
111
|
+
function getDefaultPort(appType) {
|
|
112
|
+
switch (appType) {
|
|
113
|
+
case "nextjs":
|
|
114
|
+
return 3000;
|
|
115
|
+
case "remix":
|
|
116
|
+
return 3000;
|
|
117
|
+
case "sveltekit":
|
|
118
|
+
return 5173;
|
|
119
|
+
case "vite":
|
|
120
|
+
return 5173;
|
|
121
|
+
case "cra":
|
|
122
|
+
return 3000;
|
|
123
|
+
default:
|
|
124
|
+
return 3000;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Check if a workspace is an auditable app (has a dev server).
|
|
129
|
+
*/
|
|
130
|
+
function isAuditableApp(workspace) {
|
|
131
|
+
// Check if it has a dev script
|
|
132
|
+
if (workspace.scripts?.dev || workspace.scripts?.start) {
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
// Check if it's a known app type (not a library)
|
|
136
|
+
if (workspace.appType && workspace.appType !== "unknown") {
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Parse pnpm-workspace.yaml content.
|
|
143
|
+
*/
|
|
144
|
+
function parsePnpmWorkspace(content) {
|
|
145
|
+
// Simple YAML parsing for workspace patterns
|
|
146
|
+
const patterns = [];
|
|
147
|
+
const lines = content.split("\n");
|
|
148
|
+
let inPackages = false;
|
|
149
|
+
for (const line of lines) {
|
|
150
|
+
const trimmed = line.trim();
|
|
151
|
+
if (trimmed === "packages:") {
|
|
152
|
+
inPackages = true;
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
if (inPackages) {
|
|
156
|
+
if (trimmed.startsWith("-")) {
|
|
157
|
+
// Extract pattern, removing quotes if present
|
|
158
|
+
let pattern = trimmed.slice(1).trim();
|
|
159
|
+
pattern = pattern.replace(/^['"]|['"]$/g, "");
|
|
160
|
+
if (pattern) {
|
|
161
|
+
patterns.push(pattern);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
else if (trimmed && !trimmed.startsWith("#")) {
|
|
165
|
+
// Non-empty, non-comment line means end of packages section
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return patterns;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Detect monorepo configuration from project root.
|
|
174
|
+
*
|
|
175
|
+
* @param projectRoot - Root directory to scan (defaults to cwd)
|
|
176
|
+
* @returns MonorepoConfig with detected type and workspaces
|
|
177
|
+
*/
|
|
178
|
+
export async function detectMonorepo(projectRoot) {
|
|
179
|
+
const root = projectRoot || process.cwd();
|
|
180
|
+
const rootPkgJsonPath = path.join(root, "package.json");
|
|
181
|
+
const rootPkg = readPackageJson(rootPkgJsonPath);
|
|
182
|
+
let type = "none";
|
|
183
|
+
let workspacePatterns = [];
|
|
184
|
+
// Check for pnpm-workspace.yaml first
|
|
185
|
+
const pnpmWorkspacePath = path.join(root, "pnpm-workspace.yaml");
|
|
186
|
+
if (fs.existsSync(pnpmWorkspacePath)) {
|
|
187
|
+
type = "pnpm";
|
|
188
|
+
const content = fs.readFileSync(pnpmWorkspacePath, "utf-8");
|
|
189
|
+
workspacePatterns = parsePnpmWorkspace(content);
|
|
190
|
+
}
|
|
191
|
+
// Check for nx.json
|
|
192
|
+
else if (fs.existsSync(path.join(root, "nx.json"))) {
|
|
193
|
+
type = "nx";
|
|
194
|
+
// Nx workspaces are typically in packages/ or apps/
|
|
195
|
+
if (rootPkg?.workspaces) {
|
|
196
|
+
workspacePatterns = Array.isArray(rootPkg.workspaces)
|
|
197
|
+
? rootPkg.workspaces
|
|
198
|
+
: rootPkg.workspaces.packages || [];
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
workspacePatterns = ["packages/*", "apps/*", "libs/*"];
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// Check for turbo.json
|
|
205
|
+
else if (fs.existsSync(path.join(root, "turbo.json"))) {
|
|
206
|
+
type = "turbo";
|
|
207
|
+
if (rootPkg?.workspaces) {
|
|
208
|
+
workspacePatterns = Array.isArray(rootPkg.workspaces)
|
|
209
|
+
? rootPkg.workspaces
|
|
210
|
+
: rootPkg.workspaces.packages || [];
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
workspacePatterns = ["packages/*", "apps/*"];
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
// Check for lerna.json
|
|
217
|
+
else if (fs.existsSync(path.join(root, "lerna.json"))) {
|
|
218
|
+
type = "lerna";
|
|
219
|
+
try {
|
|
220
|
+
const lernaConfig = JSON.parse(fs.readFileSync(path.join(root, "lerna.json"), "utf-8"));
|
|
221
|
+
workspacePatterns = lernaConfig.packages || ["packages/*"];
|
|
222
|
+
}
|
|
223
|
+
catch {
|
|
224
|
+
workspacePatterns = ["packages/*"];
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
// Check for npm/yarn workspaces in package.json
|
|
228
|
+
else if (rootPkg?.workspaces) {
|
|
229
|
+
// Determine if yarn or npm based on lock file
|
|
230
|
+
if (fs.existsSync(path.join(root, "yarn.lock"))) {
|
|
231
|
+
type = "yarn";
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
type = "npm";
|
|
235
|
+
}
|
|
236
|
+
workspacePatterns = Array.isArray(rootPkg.workspaces)
|
|
237
|
+
? rootPkg.workspaces
|
|
238
|
+
: rootPkg.workspaces.packages || [];
|
|
239
|
+
}
|
|
240
|
+
// If no monorepo detected, return early
|
|
241
|
+
if (type === "none") {
|
|
242
|
+
return { type, root, workspaces: [] };
|
|
243
|
+
}
|
|
244
|
+
// Expand patterns to actual workspace paths
|
|
245
|
+
const workspacePaths = expandGlobPatterns(root, workspacePatterns);
|
|
246
|
+
// Build workspace objects
|
|
247
|
+
const workspaces = [];
|
|
248
|
+
for (const wsPath of workspacePaths) {
|
|
249
|
+
const pkgJsonPath = path.join(root, wsPath, "package.json");
|
|
250
|
+
const pkg = readPackageJson(pkgJsonPath);
|
|
251
|
+
if (!pkg)
|
|
252
|
+
continue;
|
|
253
|
+
const appType = detectAppType(pkg);
|
|
254
|
+
const port = getDefaultPort(appType);
|
|
255
|
+
workspaces.push({
|
|
256
|
+
name: pkg.name || path.basename(wsPath),
|
|
257
|
+
path: wsPath,
|
|
258
|
+
packageJson: pkgJsonPath,
|
|
259
|
+
scripts: pkg.scripts,
|
|
260
|
+
appType,
|
|
261
|
+
port,
|
|
262
|
+
url: `http://localhost:${port}`,
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
return { type, root, workspaces };
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Get list of auditable apps from monorepo.
|
|
269
|
+
*
|
|
270
|
+
* Filters workspaces to only those that are web apps with dev servers,
|
|
271
|
+
* excluding libraries and tools.
|
|
272
|
+
*
|
|
273
|
+
* @param config - MonorepoConfig from detectMonorepo
|
|
274
|
+
* @returns List of auditable workspaces
|
|
275
|
+
*/
|
|
276
|
+
export function getAuditableApps(config) {
|
|
277
|
+
return config.workspaces.filter(isAuditableApp);
|
|
278
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Monorepo support module.
|
|
3
|
+
*
|
|
4
|
+
* Provides detection, workspace discovery, and orchestration
|
|
5
|
+
* for auditing multi-package repositories.
|
|
6
|
+
*/
|
|
7
|
+
export { detectMonorepo, getAuditableApps, type MonorepoConfig, type Workspace, } from "./detector.js";
|
|
8
|
+
export { auditWorkspace, generateMatrixConfig, aggregateResults, formatAggregatedResults, type WorkspaceAuditOptions, type WorkspaceResult, type AuditResult, type MatrixConfig, type AggregatedResults, } from "./workspace.js";
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/monorepo/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,KAAK,cAAc,EACnB,KAAK,SAAS,GACf,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,gBAAgB,EAChB,uBAAuB,EACvB,KAAK,qBAAqB,EAC1B,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,iBAAiB,GACvB,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Monorepo support module.
|
|
3
|
+
*
|
|
4
|
+
* Provides detection, workspace discovery, and orchestration
|
|
5
|
+
* for auditing multi-package repositories.
|
|
6
|
+
*/
|
|
7
|
+
export { detectMonorepo, getAuditableApps, } from "./detector.js";
|
|
8
|
+
export { auditWorkspace, generateMatrixConfig, aggregateResults, formatAggregatedResults, } from "./workspace.js";
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workspace audit orchestration for monorepos.
|
|
3
|
+
*
|
|
4
|
+
* Handles running audits across multiple workspaces with
|
|
5
|
+
* proper isolation and result aggregation.
|
|
6
|
+
*/
|
|
7
|
+
import type { Workspace } from "./detector.js";
|
|
8
|
+
/**
|
|
9
|
+
* Options for auditing a single workspace.
|
|
10
|
+
*/
|
|
11
|
+
export interface WorkspaceAuditOptions {
|
|
12
|
+
/** Workspace to audit */
|
|
13
|
+
workspace: Workspace;
|
|
14
|
+
/** Override base URL (if not using workspace's inferred URL) */
|
|
15
|
+
baseUrl?: string;
|
|
16
|
+
/** Override port (if not using workspace's inferred port) */
|
|
17
|
+
port?: number;
|
|
18
|
+
/** Command to start the dev server */
|
|
19
|
+
startCommand?: string;
|
|
20
|
+
/** Timeout for server startup in ms */
|
|
21
|
+
startupTimeout?: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Audit result for a single workspace.
|
|
25
|
+
*/
|
|
26
|
+
export interface AuditResult {
|
|
27
|
+
/** Job ID from audit API */
|
|
28
|
+
job_id?: string;
|
|
29
|
+
/** URL that was audited */
|
|
30
|
+
url?: string;
|
|
31
|
+
/** Audit status */
|
|
32
|
+
status?: string;
|
|
33
|
+
/** Issues found */
|
|
34
|
+
issues?: unknown[];
|
|
35
|
+
/** Scores */
|
|
36
|
+
scores?: Record<string, number>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Result of auditing a workspace.
|
|
40
|
+
*/
|
|
41
|
+
export interface WorkspaceResult {
|
|
42
|
+
/** The workspace that was audited */
|
|
43
|
+
workspace: Workspace;
|
|
44
|
+
/** Audit result if successful */
|
|
45
|
+
auditResult: AuditResult | null;
|
|
46
|
+
/** Error if audit failed */
|
|
47
|
+
error?: Error;
|
|
48
|
+
/** Duration of audit in milliseconds */
|
|
49
|
+
duration: number;
|
|
50
|
+
/** Whether cache was used */
|
|
51
|
+
cached?: boolean;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Matrix configuration for CI parallel execution.
|
|
55
|
+
*/
|
|
56
|
+
export interface MatrixConfig {
|
|
57
|
+
include: Array<{
|
|
58
|
+
name: string;
|
|
59
|
+
path: string;
|
|
60
|
+
url?: string;
|
|
61
|
+
port?: number;
|
|
62
|
+
appType?: string;
|
|
63
|
+
}>;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Aggregated results from multiple workspace audits.
|
|
67
|
+
*/
|
|
68
|
+
export interface AggregatedResults {
|
|
69
|
+
/** Total number of workspaces audited */
|
|
70
|
+
totalWorkspaces: number;
|
|
71
|
+
/** Number of successful audits */
|
|
72
|
+
successfulAudits: number;
|
|
73
|
+
/** Number of failed audits */
|
|
74
|
+
failedAudits: number;
|
|
75
|
+
/** Total issues across all workspaces */
|
|
76
|
+
totalIssues: number;
|
|
77
|
+
/** Issues by severity across all workspaces */
|
|
78
|
+
issuesBySeverity: {
|
|
79
|
+
error: number;
|
|
80
|
+
warning: number;
|
|
81
|
+
info: number;
|
|
82
|
+
};
|
|
83
|
+
/** Results per workspace */
|
|
84
|
+
workspaceResults: WorkspaceResult[];
|
|
85
|
+
/** Total duration in milliseconds */
|
|
86
|
+
totalDuration: number;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Audit a single workspace.
|
|
90
|
+
*
|
|
91
|
+
* If URL not provided, uses the workspace's inferred URL.
|
|
92
|
+
* In future versions, this could start the dev server automatically.
|
|
93
|
+
*
|
|
94
|
+
* @param options - Workspace audit options
|
|
95
|
+
* @returns WorkspaceResult with audit outcome
|
|
96
|
+
*/
|
|
97
|
+
export declare function auditWorkspace(options: WorkspaceAuditOptions): Promise<WorkspaceResult>;
|
|
98
|
+
/**
|
|
99
|
+
* Generate matrix configuration for CI parallel execution.
|
|
100
|
+
*
|
|
101
|
+
* This generates a JSON structure suitable for GitHub Actions matrix strategy
|
|
102
|
+
* or similar CI systems that support parallel job execution.
|
|
103
|
+
*
|
|
104
|
+
* @param workspaces - List of workspaces to include in matrix
|
|
105
|
+
* @returns Matrix configuration object
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```yaml
|
|
109
|
+
* # In GitHub Actions:
|
|
110
|
+
* jobs:
|
|
111
|
+
* detect-apps:
|
|
112
|
+
* runs-on: ubuntu-latest
|
|
113
|
+
* outputs:
|
|
114
|
+
* matrix: ${{ steps.detect.outputs.matrix }}
|
|
115
|
+
* steps:
|
|
116
|
+
* - id: detect
|
|
117
|
+
* run: echo "matrix=$(vertaa audit --detect-matrix --json)" >> $GITHUB_OUTPUT
|
|
118
|
+
*
|
|
119
|
+
* audit:
|
|
120
|
+
* needs: detect-apps
|
|
121
|
+
* strategy:
|
|
122
|
+
* matrix: ${{ fromJson(needs.detect-apps.outputs.matrix) }}
|
|
123
|
+
* steps:
|
|
124
|
+
* - run: vertaa audit --workspace ${{ matrix.name }}
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
export declare function generateMatrixConfig(workspaces: Workspace[]): MatrixConfig;
|
|
128
|
+
/**
|
|
129
|
+
* Aggregate results from multiple workspace audits.
|
|
130
|
+
*
|
|
131
|
+
* @param results - Array of workspace results
|
|
132
|
+
* @returns Aggregated results summary
|
|
133
|
+
*/
|
|
134
|
+
export declare function aggregateResults(results: WorkspaceResult[]): AggregatedResults;
|
|
135
|
+
/**
|
|
136
|
+
* Format aggregated results for display.
|
|
137
|
+
*
|
|
138
|
+
* @param aggregated - Aggregated results
|
|
139
|
+
* @returns Formatted string for console output
|
|
140
|
+
*/
|
|
141
|
+
export declare function formatAggregatedResults(aggregated: AggregatedResults): string;
|
|
142
|
+
//# sourceMappingURL=workspace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../src/monorepo/workspace.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,yBAAyB;IACzB,SAAS,EAAE,SAAS,CAAC;IACrB,gEAAgE;IAChE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sCAAsC;IACtC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uCAAuC;IACvC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,4BAA4B;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2BAA2B;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,mBAAmB;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mBAAmB;IACnB,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;IACnB,aAAa;IACb,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,qCAAqC;IACrC,SAAS,EAAE,SAAS,CAAC;IACrB,iCAAiC;IACjC,WAAW,EAAE,WAAW,GAAG,IAAI,CAAC;IAChC,4BAA4B;IAC5B,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,wCAAwC;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,6BAA6B;IAC7B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,KAAK,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC,CAAC;CACJ;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,yCAAyC;IACzC,eAAe,EAAE,MAAM,CAAC;IACxB,kCAAkC;IAClC,gBAAgB,EAAE,MAAM,CAAC;IACzB,8BAA8B;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,yCAAyC;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,+CAA+C;IAC/C,gBAAgB,EAAE;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,4BAA4B;IAC5B,gBAAgB,EAAE,eAAe,EAAE,CAAC;IACpC,qCAAqC;IACrC,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,eAAe,CAAC,CAkC1B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,SAAS,EAAE,GAAG,YAAY,CAU1E;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,eAAe,EAAE,GAAG,iBAAiB,CA6C9E;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,iBAAiB,GAAG,MAAM,CAyC7E"}
|