assertloom 0.0.0-stage → 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/LICENSE +21 -0
- package/README.md +393 -2
- package/dist/ai/anthropic.d.ts +11 -0
- package/dist/ai/anthropic.js +68 -0
- package/dist/ai/anthropic.js.map +1 -0
- package/dist/ai/index.d.ts +12 -0
- package/dist/ai/index.js +23 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/ai/openai.d.ts +9 -0
- package/dist/ai/openai.js +57 -0
- package/dist/ai/openai.js.map +1 -0
- package/dist/ai/openaiCompatible.d.ts +13 -0
- package/dist/ai/openaiCompatible.js +62 -0
- package/dist/ai/openaiCompatible.js.map +1 -0
- package/dist/ai/pricing.d.ts +38 -0
- package/dist/ai/pricing.js +105 -0
- package/dist/ai/pricing.js.map +1 -0
- package/dist/ai/prompts.d.ts +27 -0
- package/dist/ai/prompts.js +89 -0
- package/dist/ai/prompts.js.map +1 -0
- package/dist/ai/provider.d.ts +26 -0
- package/dist/ai/provider.js +4 -0
- package/dist/ai/provider.js.map +1 -0
- package/dist/ai/redact.d.ts +5 -0
- package/dist/ai/redact.js +31 -0
- package/dist/ai/redact.js.map +1 -0
- package/dist/analyzer/dependencies.d.ts +16 -0
- package/dist/analyzer/dependencies.js +168 -0
- package/dist/analyzer/dependencies.js.map +1 -0
- package/dist/analyzer/format.d.ts +3 -0
- package/dist/analyzer/format.js +14 -0
- package/dist/analyzer/format.js.map +1 -0
- package/dist/analyzer/functions.d.ts +4 -0
- package/dist/analyzer/functions.js +324 -0
- package/dist/analyzer/functions.js.map +1 -0
- package/dist/analyzer/index.d.ts +5 -0
- package/dist/analyzer/index.js +29 -0
- package/dist/analyzer/index.js.map +1 -0
- package/dist/analyzer/parser.d.ts +11 -0
- package/dist/analyzer/parser.js +38 -0
- package/dist/analyzer/parser.js.map +1 -0
- package/dist/analyzer/usage.d.ts +16 -0
- package/dist/analyzer/usage.js +159 -0
- package/dist/analyzer/usage.js.map +1 -0
- package/dist/ci/report.d.ts +88 -0
- package/dist/ci/report.js +139 -0
- package/dist/ci/report.js.map +1 -0
- package/dist/ci/run.d.ts +70 -0
- package/dist/ci/run.js +198 -0
- package/dist/ci/run.js.map +1 -0
- package/dist/ci/select.d.ts +58 -0
- package/dist/ci/select.js +238 -0
- package/dist/ci/select.js.map +1 -0
- package/dist/cli/commands/analyze.d.ts +2 -0
- package/dist/cli/commands/analyze.js +49 -0
- package/dist/cli/commands/analyze.js.map +1 -0
- package/dist/cli/commands/ci.d.ts +37 -0
- package/dist/cli/commands/ci.js +258 -0
- package/dist/cli/commands/ci.js.map +1 -0
- package/dist/cli/commands/generate.d.ts +3 -0
- package/dist/cli/commands/generate.js +201 -0
- package/dist/cli/commands/generate.js.map +1 -0
- package/dist/cli/commands/run.d.ts +4 -0
- package/dist/cli/commands/run.js +53 -0
- package/dist/cli/commands/run.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +16 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/program.d.ts +2 -0
- package/dist/cli/program.js +20 -0
- package/dist/cli/program.js.map +1 -0
- package/dist/cli/report.d.ts +3 -0
- package/dist/cli/report.js +36 -0
- package/dist/cli/report.js.map +1 -0
- package/dist/cli/validateFile.d.ts +5 -0
- package/dist/cli/validateFile.js +43 -0
- package/dist/cli/validateFile.js.map +1 -0
- package/dist/errors.d.ts +4 -0
- package/dist/errors.js +8 -0
- package/dist/errors.js.map +1 -0
- package/dist/generator/diff.d.ts +5 -0
- package/dist/generator/diff.js +56 -0
- package/dist/generator/diff.js.map +1 -0
- package/dist/generator/importPlan.d.ts +15 -0
- package/dist/generator/importPlan.js +62 -0
- package/dist/generator/importPlan.js.map +1 -0
- package/dist/generator/index.d.ts +5 -0
- package/dist/generator/index.js +6 -0
- package/dist/generator/index.js.map +1 -0
- package/dist/generator/mocks.d.ts +48 -0
- package/dist/generator/mocks.js +356 -0
- package/dist/generator/mocks.js.map +1 -0
- package/dist/generator/schema.d.ts +40 -0
- package/dist/generator/schema.js +15 -0
- package/dist/generator/schema.js.map +1 -0
- package/dist/generator/testGenerator.d.ts +36 -0
- package/dist/generator/testGenerator.js +85 -0
- package/dist/generator/testGenerator.js.map +1 -0
- package/dist/generator/testWriter.d.ts +22 -0
- package/dist/generator/testWriter.js +93 -0
- package/dist/generator/testWriter.js.map +1 -0
- package/dist/generator/validate.d.ts +31 -0
- package/dist/generator/validate.js +180 -0
- package/dist/generator/validate.js.map +1 -0
- package/dist/repair/classifyFailure.d.ts +11 -0
- package/dist/repair/classifyFailure.js +26 -0
- package/dist/repair/classifyFailure.js.map +1 -0
- package/dist/repair/index.d.ts +2 -0
- package/dist/repair/index.js +3 -0
- package/dist/repair/index.js.map +1 -0
- package/dist/repair/repairLoop.d.ts +74 -0
- package/dist/repair/repairLoop.js +219 -0
- package/dist/repair/repairLoop.js.map +1 -0
- package/dist/repair/schema.d.ts +17 -0
- package/dist/repair/schema.js +14 -0
- package/dist/repair/schema.js.map +1 -0
- package/dist/runner/coverage.d.ts +5 -0
- package/dist/runner/coverage.js +42 -0
- package/dist/runner/coverage.js.map +1 -0
- package/dist/runner/index.d.ts +5 -0
- package/dist/runner/index.js +5 -0
- package/dist/runner/index.js.map +1 -0
- package/dist/runner/jestConfig.d.ts +11 -0
- package/dist/runner/jestConfig.js +103 -0
- package/dist/runner/jestConfig.js.map +1 -0
- package/dist/runner/jestRunner.d.ts +17 -0
- package/dist/runner/jestRunner.js +154 -0
- package/dist/runner/jestRunner.js.map +1 -0
- package/dist/runner/networkGuard.d.ts +4 -0
- package/dist/runner/networkGuard.js +55 -0
- package/dist/runner/networkGuard.js.map +1 -0
- package/dist/runner/project.d.ts +30 -0
- package/dist/runner/project.js +86 -0
- package/dist/runner/project.js.map +1 -0
- package/dist/runner/results.d.ts +32 -0
- package/dist/runner/results.js +58 -0
- package/dist/runner/results.js.map +1 -0
- package/dist/runner/types.d.ts +39 -0
- package/dist/runner/types.js +2 -0
- package/dist/runner/types.js.map +1 -0
- package/dist/runner/vitest.d.ts +24 -0
- package/dist/runner/vitest.js +105 -0
- package/dist/runner/vitest.js.map +1 -0
- package/dist/types/index.d.ts +96 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +67 -4
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { appendFile, mkdir, readdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { Option } from "commander";
|
|
5
|
+
import { createProvider, PROVIDERS } from "../../ai/index.js";
|
|
6
|
+
import { Budget } from "../../ai/pricing.js";
|
|
7
|
+
import { UserError } from "../../errors.js";
|
|
8
|
+
import { MAX_REPAIR_ATTEMPTS } from "../../repair/index.js";
|
|
9
|
+
import { cell, computeTotals, createRedactor, evaluatePolicy, FAIL_ON, renderSummary } from "../../ci/report.js";
|
|
10
|
+
import { runFiles } from "../../ci/run.js";
|
|
11
|
+
import { changedFiles, classify, explicitFiles, repositoryRoot, splitLines, splitList } from "../../ci/select.js";
|
|
12
|
+
const { version } = JSON.parse(readFileSync(new URL("../../../package.json", import.meta.url), "utf8"));
|
|
13
|
+
/** Environment variables that hold provider credentials. Their values are redacted from everything Assertloom writes. */
|
|
14
|
+
export const CREDENTIAL_ENV = ["OPENAI_API_KEY", "ANTHROPIC_API_KEY", "ASSERTLOOM_API_KEY"];
|
|
15
|
+
export const DEFAULT_CI_MAX_FILES = 10;
|
|
16
|
+
export const DEFAULT_CI_MAX_COST_USD = 1;
|
|
17
|
+
const MAX_TIMEOUT_SECONDS = 3600;
|
|
18
|
+
/** Commander passes "" for inputs the action leaves empty; treat them as unset. */
|
|
19
|
+
const given = (value) => (value === undefined || value.trim() === "" ? undefined : value.trim());
|
|
20
|
+
function wholeNumber(value, name, min, max) {
|
|
21
|
+
const n = Number(value);
|
|
22
|
+
if (!Number.isInteger(n) || n < min || n > max)
|
|
23
|
+
throw new UserError(`${name} must be a whole number from ${min} to ${max}.`);
|
|
24
|
+
return n;
|
|
25
|
+
}
|
|
26
|
+
function noNewlines(value, name) {
|
|
27
|
+
if (/[\r\n\0]/.test(value))
|
|
28
|
+
throw new UserError(`${name} must not contain line breaks.`);
|
|
29
|
+
return value;
|
|
30
|
+
}
|
|
31
|
+
/** Only an empty directory or one holding a previous Assertloom report is reused, so nothing else is ever deleted. */
|
|
32
|
+
async function prepareOutDir(outDir) {
|
|
33
|
+
const entries = await readdir(outDir).catch(() => undefined);
|
|
34
|
+
if (entries && entries.length && !entries.includes("report.json")) {
|
|
35
|
+
throw new UserError(`${outDir} exists and is not an Assertloom report directory. Choose an empty or new directory with --out.`);
|
|
36
|
+
}
|
|
37
|
+
for (const name of ["tests", "report.json", "summary.md"])
|
|
38
|
+
await rm(path.join(outDir, name), { recursive: true, force: true });
|
|
39
|
+
await mkdir(path.join(outDir, "tests"), { recursive: true });
|
|
40
|
+
}
|
|
41
|
+
export async function runCi(options, deps) {
|
|
42
|
+
const log = deps.log;
|
|
43
|
+
const cwd = path.resolve(given(options.workingDirectory) ?? ".");
|
|
44
|
+
const failOn = (given(options.failOn) ?? "errors");
|
|
45
|
+
if (!FAIL_ON.includes(failOn))
|
|
46
|
+
throw new UserError(`--fail-on must be one of: ${FAIL_ON.join(", ")}.`);
|
|
47
|
+
const maxFiles = wholeNumber(given(options.maxFiles) ?? String(DEFAULT_CI_MAX_FILES), "--max-files", 1, 1000);
|
|
48
|
+
const maxAttempts = wholeNumber(given(options.maxAttempts) ?? String(MAX_REPAIR_ATTEMPTS), "--max-attempts", 0, MAX_REPAIR_ATTEMPTS);
|
|
49
|
+
const timeoutSeconds = wholeNumber(given(options.timeout) ?? "120", "--timeout", 1, MAX_TIMEOUT_SECONDS);
|
|
50
|
+
const maxCost = Number(given(options.maxCost) ?? DEFAULT_CI_MAX_COST_USD);
|
|
51
|
+
if (!Number.isFinite(maxCost) || maxCost <= 0)
|
|
52
|
+
throw new UserError("--max-cost must be a positive number of US dollars.");
|
|
53
|
+
const maxTokensInput = given(options.maxTokens);
|
|
54
|
+
const maxTokens = maxTokensInput === undefined ? undefined : wholeNumber(maxTokensInput, "--max-tokens", 1, 100_000_000);
|
|
55
|
+
const outDir = path.resolve(cwd, noNewlines(given(options.out) ?? "assertloom-report", "--out"));
|
|
56
|
+
const redact = createRedactor(CREDENTIAL_ENV.map((name) => process.env[name]));
|
|
57
|
+
const base = given(options.base);
|
|
58
|
+
const fileInput = splitLines(options.files);
|
|
59
|
+
if (!base && fileInput.length === 0) {
|
|
60
|
+
throw new UserError("Nothing to select: pass --base (the pull request's base commit) or --files. In GitHub Actions, run on pull_request or set the `files` input.");
|
|
61
|
+
}
|
|
62
|
+
await prepareOutDir(outDir);
|
|
63
|
+
const report = {
|
|
64
|
+
schemaVersion: 1,
|
|
65
|
+
assertloom: version,
|
|
66
|
+
startedAt: new Date().toISOString(),
|
|
67
|
+
finishedAt: "",
|
|
68
|
+
mode: fileInput.length ? "files" : "pull-request",
|
|
69
|
+
...(fileInput.length ? {} : { base, head: given(options.head) ?? "HEAD" }),
|
|
70
|
+
provider: options.provider,
|
|
71
|
+
model: given(options.model) ?? "",
|
|
72
|
+
limits: { maxFiles, maxCostUsd: maxCost, maxTokens: maxTokens ?? null, maxAttempts, timeoutSeconds },
|
|
73
|
+
budget: { exhausted: false, costKnown: false, spentUsd: null, tokens: { input: 0, output: 0 } },
|
|
74
|
+
totals: computeTotals([]),
|
|
75
|
+
policy: { failOn, failed: false, reasons: [] },
|
|
76
|
+
files: [],
|
|
77
|
+
};
|
|
78
|
+
let budget;
|
|
79
|
+
const write = async (files) => {
|
|
80
|
+
report.files = files;
|
|
81
|
+
report.totals = computeTotals(files);
|
|
82
|
+
if (budget) {
|
|
83
|
+
report.budget = {
|
|
84
|
+
...report.budget,
|
|
85
|
+
costKnown: budget.priced,
|
|
86
|
+
spentUsd: budget.spentUsd ?? null,
|
|
87
|
+
tokens: { input: budget.usage.inputTokens, output: budget.usage.outputTokens },
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
report.finishedAt = new Date().toISOString();
|
|
91
|
+
await writeFile(path.join(outDir, "report.json"), redact(JSON.stringify(report, null, 2)) + "\n");
|
|
92
|
+
await writeFile(path.join(outDir, "summary.md"), redact(renderSummary(report)));
|
|
93
|
+
};
|
|
94
|
+
let candidates = [];
|
|
95
|
+
try {
|
|
96
|
+
const root = await repositoryRoot(cwd);
|
|
97
|
+
const files = fileInput.length ? explicitFiles(fileInput, root, cwd) : await changedFiles({ cwd: root, base: base, head: given(options.head) });
|
|
98
|
+
candidates = await classify(files, {
|
|
99
|
+
root,
|
|
100
|
+
include: splitList(options.include),
|
|
101
|
+
exclude: splitList(options.exclude),
|
|
102
|
+
useDefaultExcludes: options.defaultExcludes,
|
|
103
|
+
});
|
|
104
|
+
const eligible = candidates.filter((c) => !c.skip);
|
|
105
|
+
log(`Selected ${eligible.length} of ${candidates.length} changed files${eligible.length > maxFiles ? ` (processing at most ${maxFiles})` : ""}.`);
|
|
106
|
+
if (options.dryRun || eligible.length === 0) {
|
|
107
|
+
if (eligible.length === 0)
|
|
108
|
+
log("No eligible JavaScript or TypeScript source files changed.");
|
|
109
|
+
const files = candidates.map((c) => skippedReport(c, "dry-run"));
|
|
110
|
+
await write(files);
|
|
111
|
+
return finish(report, failOn, files, write, redact);
|
|
112
|
+
}
|
|
113
|
+
const provider = deps.createProvider(options.provider, { model: given(options.model), baseUrl: given(options.baseUrl) });
|
|
114
|
+
report.model = provider.model;
|
|
115
|
+
budget = new Budget(provider.model, maxCost, maxTokens);
|
|
116
|
+
if (!budget.priced && maxTokens === undefined) {
|
|
117
|
+
throw new UserError(`${provider.model} has no known price, so a dollar limit cannot be enforced. Set a shared token limit with --max-tokens.`);
|
|
118
|
+
}
|
|
119
|
+
log(`Using ${provider.name} (${provider.model}); shared limit ${budget.describeLimit()}.`);
|
|
120
|
+
const result = await runFiles({
|
|
121
|
+
root,
|
|
122
|
+
candidates,
|
|
123
|
+
provider,
|
|
124
|
+
budget,
|
|
125
|
+
maxFiles,
|
|
126
|
+
maxAttempts,
|
|
127
|
+
timeoutMs: timeoutSeconds * 1000,
|
|
128
|
+
testsDir: path.join(outDir, "tests"),
|
|
129
|
+
onProgress: write,
|
|
130
|
+
runTests: deps.runTests,
|
|
131
|
+
log: (line) => log(redact(line)),
|
|
132
|
+
});
|
|
133
|
+
report.budget.exhausted = result.budgetExhausted;
|
|
134
|
+
await write(result.files);
|
|
135
|
+
return finish(report, failOn, result.files, write, redact);
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
139
|
+
const hint = /_API_KEY is not set/.test(message) && process.env.GITHUB_ACTIONS ? " In the GitHub Action, pass the key from a secret with the `api-key` input." : "";
|
|
140
|
+
report.error = redact(message + hint);
|
|
141
|
+
await write(report.files.length ? report.files : candidates.map((c) => skippedReport(c, "not-processed")));
|
|
142
|
+
throw error instanceof UserError ? new UserError(report.error) : error;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/** A file that was not processed: skipped by selection, or eligible but not reached (`reason`). */
|
|
146
|
+
function skippedReport(c, reason) {
|
|
147
|
+
return {
|
|
148
|
+
path: c.path,
|
|
149
|
+
...(c.from ? { from: c.from } : {}),
|
|
150
|
+
change: c.status,
|
|
151
|
+
status: "skipped",
|
|
152
|
+
...(c.skip
|
|
153
|
+
? { skipReason: c.skip.reason, detail: c.skip.detail }
|
|
154
|
+
: { skipReason: reason, detail: reason === "dry-run" ? "eligible; dry run, not processed" : "eligible; not processed because the run stopped" }),
|
|
155
|
+
generated: 0,
|
|
156
|
+
accepted: 0,
|
|
157
|
+
rejected: 0,
|
|
158
|
+
repaired: 0,
|
|
159
|
+
flaggedAsSourceBugs: 0,
|
|
160
|
+
removed: 0,
|
|
161
|
+
gaveUp: 0,
|
|
162
|
+
repairRounds: 0,
|
|
163
|
+
regressions: 0,
|
|
164
|
+
durationMs: 0,
|
|
165
|
+
usage: { inputTokens: 0, outputTokens: 0 },
|
|
166
|
+
costUsd: null,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
async function finish(report, failOn, files, write, redact) {
|
|
170
|
+
report.policy = { failOn, ...evaluatePolicy(failOn, files) };
|
|
171
|
+
await write(files);
|
|
172
|
+
// Callers get the same redacted content that was written to disk.
|
|
173
|
+
return JSON.parse(redact(JSON.stringify(report)));
|
|
174
|
+
}
|
|
175
|
+
/** Writes `key=value` pairs for GitHub Actions step outputs. Values never contain line breaks. */
|
|
176
|
+
async function writeGithubOutputs(file, report, outDir) {
|
|
177
|
+
const t = report.totals;
|
|
178
|
+
const outputs = {
|
|
179
|
+
"report-dir": outDir,
|
|
180
|
+
"report-path": path.join(outDir, "report.json"),
|
|
181
|
+
"summary-path": path.join(outDir, "summary.md"),
|
|
182
|
+
"files-selected": String(t.files.selected),
|
|
183
|
+
"files-processed": String(t.files.processed),
|
|
184
|
+
"files-skipped": String(t.files.skipped),
|
|
185
|
+
"files-failed": String(t.files.failed),
|
|
186
|
+
"tests-final-passed": String(t.tests.final.passed),
|
|
187
|
+
"tests-final-failed": String(t.tests.final.failed),
|
|
188
|
+
"budget-exhausted": String(report.budget.exhausted),
|
|
189
|
+
result: report.error ? "error" : report.policy.failed ? "failed" : "passed",
|
|
190
|
+
};
|
|
191
|
+
const lines = Object.entries(outputs)
|
|
192
|
+
.filter(([, v]) => !/[\r\n]/.test(v))
|
|
193
|
+
.map(([k, v]) => `${k}=${v}\n`);
|
|
194
|
+
await appendFile(file, lines.join(""));
|
|
195
|
+
}
|
|
196
|
+
export function registerCiCommand(program, deps = {}) {
|
|
197
|
+
program
|
|
198
|
+
.command("ci")
|
|
199
|
+
.description("Generate, run, and repair tests for JavaScript/TypeScript files changed in a pull request; write a report and test previews")
|
|
200
|
+
.option("--base <commit>", "base commit of the pull request; files changed on --head since it are selected")
|
|
201
|
+
.option("--head <commit>", "head commit (default: HEAD)")
|
|
202
|
+
.option("--files <list>", "newline-separated files to process instead of a diff (for manual runs)")
|
|
203
|
+
.option("--include <globs>", "only consider files matching these globs (newline- or comma-separated)")
|
|
204
|
+
.option("--exclude <globs>", "skip files matching these globs, in addition to the defaults")
|
|
205
|
+
.option("--no-default-excludes", "do not skip tests, node_modules, build output, declarations, and generated files by default")
|
|
206
|
+
.option("--max-files <n>", "process at most this many files", String(DEFAULT_CI_MAX_FILES))
|
|
207
|
+
.option("--max-cost <usd>", "spending limit in US dollars for the whole run, shared by all files and repair rounds", String(DEFAULT_CI_MAX_COST_USD))
|
|
208
|
+
.option("--max-tokens <n>", "shared token limit for models without a known price (required for them)")
|
|
209
|
+
.option("--max-attempts <n>", `repair rounds per file, 0-${MAX_REPAIR_ATTEMPTS}`, String(MAX_REPAIR_ATTEMPTS))
|
|
210
|
+
.option("--timeout <seconds>", "time limit for each test run", "120")
|
|
211
|
+
.option("--out <dir>", "directory for report.json, summary.md, and tests/", "assertloom-report")
|
|
212
|
+
.addOption(new Option("--fail-on <policy>", "exit non-zero on: never, errors (files that could not be processed), or tests (also any test not passing)").default("errors"))
|
|
213
|
+
.addOption(new Option("--provider <name>", "LLM provider").choices(PROVIDERS).default("openai"))
|
|
214
|
+
.option("--model <model>", "model name (default: $ASSERTLOOM_MODEL or the provider default)")
|
|
215
|
+
.option("--base-url <url>", "server URL for --provider openai-compatible (default: $ASSERTLOOM_BASE_URL)")
|
|
216
|
+
.option("--working-directory <dir>", "directory inside the repository to run in (default: current directory)")
|
|
217
|
+
.option("--dry-run", "select files and write the report without calling a model or running tests")
|
|
218
|
+
.option("--github-summary <file>", "append the Markdown summary to this file ($GITHUB_STEP_SUMMARY)")
|
|
219
|
+
.option("--github-output <file>", "append step outputs to this file ($GITHUB_OUTPUT)")
|
|
220
|
+
.action(async (options) => {
|
|
221
|
+
const full = { createProvider, log: (line) => console.log(line), ...deps };
|
|
222
|
+
const outDir = path.resolve(given(options.workingDirectory) ?? ".", given(options.out) ?? "assertloom-report");
|
|
223
|
+
let report;
|
|
224
|
+
let failure;
|
|
225
|
+
try {
|
|
226
|
+
report = await runCi(options, full);
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
failure = createRedactor(CREDENTIAL_ENV.map((name) => process.env[name]))(error instanceof Error ? error.message : String(error));
|
|
230
|
+
throw error;
|
|
231
|
+
}
|
|
232
|
+
finally {
|
|
233
|
+
const summary = await readFile(path.join(outDir, "summary.md"), "utf8").catch(() => undefined);
|
|
234
|
+
if (given(options.githubSummary)) {
|
|
235
|
+
// A configuration error stops the run before any report exists; still say why in the job summary.
|
|
236
|
+
const text = summary ?? `## Assertloom\n\n**Could not run:** ${cell(failure ?? "unknown error")}\n`;
|
|
237
|
+
await appendFile(options.githubSummary, text + "\n");
|
|
238
|
+
}
|
|
239
|
+
if (given(options.githubOutput)) {
|
|
240
|
+
if (report)
|
|
241
|
+
await writeGithubOutputs(options.githubOutput, report, outDir);
|
|
242
|
+
// Partial results may exist even after an error; expose them so they are uploaded.
|
|
243
|
+
else
|
|
244
|
+
await appendFile(options.githubOutput, `result=error\n${summary !== undefined && !/[\r\n]/.test(outDir) ? `report-dir=${outDir}\n` : ""}`);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
const t = report.totals;
|
|
248
|
+
console.log(`\n${t.files.processed} processed, ${t.files.skipped} skipped, ${t.files.failed} failed. ` +
|
|
249
|
+
`Final tests: ${t.tests.final.passed} passed, ${t.tests.final.failed} failed, ${t.tests.final.skipped} skipped.`);
|
|
250
|
+
console.log(`Report: ${path.join(outDir, "report.json")}`);
|
|
251
|
+
if (report.policy.failed) {
|
|
252
|
+
for (const reason of report.policy.reasons)
|
|
253
|
+
console.error(`✗ ${reason} (--fail-on ${report.policy.failOn})`);
|
|
254
|
+
process.exitCode = 1;
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
//# sourceMappingURL=ci.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ci.js","sourceRoot":"","sources":["../../../src/cli/commands/ci.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { Option } from "commander";
|
|
4
|
+
import { createProvider, PROVIDERS } from "../../ai/index.js";
|
|
5
|
+
import { Budget, estimateCost, formatUsd } from "../../ai/pricing.js";
|
|
6
|
+
import { UserError } from "../../errors.js";
|
|
7
|
+
import { generateTests, testPathFor, TestFileExistsError, writeTestFile } from "../../generator/index.js";
|
|
8
|
+
import { MAX_REPAIR_ATTEMPTS, repairTests, summarize } from "../../repair/index.js";
|
|
9
|
+
import { runJest } from "../../runner/index.js";
|
|
10
|
+
import { formatCoverage, printRunResult } from "../report.js";
|
|
11
|
+
import { validateSourceFile } from "../validateFile.js";
|
|
12
|
+
export const DEFAULT_MAX_COST_USD = 1;
|
|
13
|
+
function tokens(usage, model) {
|
|
14
|
+
const cost = estimateCost(model, usage);
|
|
15
|
+
return `${usage.inputTokens.toLocaleString()} in / ${usage.outputTokens.toLocaleString()} out${cost === undefined ? "" : `, ≈${formatUsd(cost)}`}`;
|
|
16
|
+
}
|
|
17
|
+
const collect = (value, previous) => [...previous, value];
|
|
18
|
+
function printMocks(result) {
|
|
19
|
+
const { mocked, real, globals } = result.mocks;
|
|
20
|
+
const names = [...mocked.map((m) => m.source), ...globals.map((g) => `global ${g}`)];
|
|
21
|
+
if (names.length)
|
|
22
|
+
console.log(`✓ Mocked ${names.length} ${names.length === 1 ? "dependency" : "dependencies"}: ${names.join(", ")}`);
|
|
23
|
+
for (const m of mocked)
|
|
24
|
+
console.log(` - ${m.source}: ${m.reason}${m.virtual ? " (virtual mock)" : ""}`);
|
|
25
|
+
if (real.length)
|
|
26
|
+
console.log(` Kept real: ${real.map((r) => `${r.source} (${r.reason})`).join(", ")}`);
|
|
27
|
+
}
|
|
28
|
+
function relative(file) {
|
|
29
|
+
return path.relative(process.cwd(), file) || file;
|
|
30
|
+
}
|
|
31
|
+
/** Prints what changes in an existing test file before it is overwritten. Previews are scratch files. */
|
|
32
|
+
function showDiff(file) {
|
|
33
|
+
if (file.includes(".test.preview."))
|
|
34
|
+
return undefined;
|
|
35
|
+
return (diff) => {
|
|
36
|
+
console.log(`\nOverwriting ${relative(file)}. Changes:`);
|
|
37
|
+
for (const line of diff)
|
|
38
|
+
console.log(` ${line}`);
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const STOP_MESSAGES = {
|
|
42
|
+
"all-passing": "all tests pass",
|
|
43
|
+
"max-attempts": "reached the repair limit",
|
|
44
|
+
regressed: "a repair broke passing tests and was reverted",
|
|
45
|
+
"no-valid-repairs": "the model proposed no usable repairs",
|
|
46
|
+
unrepairable: "the remaining failures cannot be fixed by editing tests",
|
|
47
|
+
budget: "another repair round could exceed the spending limit",
|
|
48
|
+
};
|
|
49
|
+
function printRepair(repair, model) {
|
|
50
|
+
for (const attempt of repair.attempts) {
|
|
51
|
+
const counts = ["fix", "skip", "remove"]
|
|
52
|
+
.map((action) => [action, attempt.changes.filter((c) => c.action === action).length])
|
|
53
|
+
.filter(([, n]) => n > 0)
|
|
54
|
+
.map(([action, n]) => `${n} ${action === "fix" ? "fixed" : action === "skip" ? "flagged as source bugs" : "removed"}`);
|
|
55
|
+
const after = attempt.after ? ` → ${attempt.after.passed} passed, ${attempt.after.failed} failed` : "";
|
|
56
|
+
console.log(`${attempt.regressed ? "!" : "✓"} Repair attempt ${attempt.attempt}: ${counts.join(", ") || "no changes"}${after}`);
|
|
57
|
+
for (const change of attempt.changes)
|
|
58
|
+
console.log(` - ${change.action} ${change.functionName} › "${change.name}": ${change.reason}`);
|
|
59
|
+
for (const invalid of attempt.invalid)
|
|
60
|
+
console.log(` ! ignored repair for ${invalid.functionName} › "${invalid.name}": ${invalid.reason}`);
|
|
61
|
+
if (attempt.regressed)
|
|
62
|
+
console.log(" ! This attempt broke passing tests; it was reverted.");
|
|
63
|
+
}
|
|
64
|
+
for (const change of repair.gaveUp)
|
|
65
|
+
console.log(` - skipped ${change.functionName} › "${change.name}": ${change.reason}`);
|
|
66
|
+
const { final } = repair;
|
|
67
|
+
const total = final.passed + final.failed + final.skipped;
|
|
68
|
+
const skipped = final.skipped ? `, ${final.skipped} skipped` : "";
|
|
69
|
+
console.log(`✓ Final result: ${final.passed}/${total} passing${skipped} (${STOP_MESSAGES[repair.stopReason]})`);
|
|
70
|
+
if (final.coverage)
|
|
71
|
+
console.log(`✓ Coverage: ${formatCoverage(final.coverage)}`);
|
|
72
|
+
console.log(` Repair tokens: ${tokens(repair.usage, model)}`);
|
|
73
|
+
if (!repair.sourceUnchanged)
|
|
74
|
+
console.error("✗ A test run modified the source file. Assertloom restored the original contents.");
|
|
75
|
+
}
|
|
76
|
+
function buildReport(file, generation, run, repair, budget) {
|
|
77
|
+
return {
|
|
78
|
+
file,
|
|
79
|
+
model: generation.model,
|
|
80
|
+
mocks: { mocked: generation.mocks.mocked, real: generation.mocks.real, globals: generation.mocks.globals },
|
|
81
|
+
generated: generation.suites.reduce((n, s) => n + s.cases.length, 0),
|
|
82
|
+
rejected: generation.rejected,
|
|
83
|
+
initial: repair?.initial ?? summarize(run),
|
|
84
|
+
attempts: repair?.attempts ?? [],
|
|
85
|
+
gaveUp: repair?.gaveUp ?? [],
|
|
86
|
+
final: summarize(run),
|
|
87
|
+
stopReason: repair?.stopReason ?? (run.status === "passed" ? "all-passing" : "not-repaired"),
|
|
88
|
+
sourceUnchanged: repair?.sourceUnchanged ?? true,
|
|
89
|
+
usage: {
|
|
90
|
+
generation: generation.usage,
|
|
91
|
+
repair: repair?.usage ?? { inputTokens: 0, outputTokens: 0 },
|
|
92
|
+
},
|
|
93
|
+
costUsd: budget.spentUsd ?? null,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
export function registerGenerateCommand(program) {
|
|
97
|
+
program
|
|
98
|
+
.command("generate")
|
|
99
|
+
.description("Generate Jest tests for a source file, run them, and keep them if they pass")
|
|
100
|
+
.argument("<file>", "path to a JavaScript or TypeScript source file")
|
|
101
|
+
.addOption(new Option("--provider <name>", "LLM provider").choices(PROVIDERS).default("openai"))
|
|
102
|
+
.option("--model <model>", "model name (default: $ASSERTLOOM_MODEL or the provider default)")
|
|
103
|
+
.option("--base-url <url>", "server URL for --provider openai-compatible (default: $ASSERTLOOM_BASE_URL)")
|
|
104
|
+
.option("--out <path>", "where to write the tests (default: <file>.test.preview.<ext>, promoted to <file>.test.<ext> when all pass)")
|
|
105
|
+
.option("--dry-run", "print the generated tests instead of writing or running them")
|
|
106
|
+
.option("--no-run", "write the preview file without running it")
|
|
107
|
+
.option("--no-repair", "do not try to repair failing tests")
|
|
108
|
+
.option("--max-attempts <n>", `repair rounds, 0-${MAX_REPAIR_ATTEMPTS}`, String(MAX_REPAIR_ATTEMPTS))
|
|
109
|
+
.option("--report <file>", "write before/after results of every run and repair round as JSON")
|
|
110
|
+
.option("--mock <module>", "mock this import even if Assertloom would keep it real (repeatable)", collect, [])
|
|
111
|
+
.option("--keep-real <module>", "do not mock this import (repeatable)", collect, [])
|
|
112
|
+
.option("--allow-network", "let generated tests open network connections (blocked by default)")
|
|
113
|
+
.option("--max-cost <usd>", "stop before model calls could push spending past this many US dollars", String(DEFAULT_MAX_COST_USD))
|
|
114
|
+
.option("--force", "overwrite an existing test file that Assertloom did not generate")
|
|
115
|
+
.action(async (file, options) => {
|
|
116
|
+
const maxAttempts = Number(options.maxAttempts);
|
|
117
|
+
if (!Number.isInteger(maxAttempts) || maxAttempts < 0 || maxAttempts > MAX_REPAIR_ATTEMPTS) {
|
|
118
|
+
throw new UserError(`--max-attempts must be a whole number from 0 to ${MAX_REPAIR_ATTEMPTS}.`);
|
|
119
|
+
}
|
|
120
|
+
const maxCost = Number(options.maxCost);
|
|
121
|
+
if (!Number.isFinite(maxCost) || maxCost <= 0)
|
|
122
|
+
throw new UserError("--max-cost must be a positive number of US dollars.");
|
|
123
|
+
const source = await validateSourceFile(file);
|
|
124
|
+
const provider = createProvider(options.provider, { model: options.model, baseUrl: options.baseUrl });
|
|
125
|
+
const budget = new Budget(provider.model, maxCost);
|
|
126
|
+
const testPath = options.out ? path.resolve(options.out) : undefined;
|
|
127
|
+
const allowNetwork = !!options.allowNetwork;
|
|
128
|
+
console.log(`Generating tests for ${source.inputPath} with ${provider.name} (${provider.model})...`);
|
|
129
|
+
const result = await generateTests({ source, provider, testPath, mock: options.mock, keepReal: options.keepReal, budget });
|
|
130
|
+
const exported = result.analysis.functions.filter((f) => f.exported).length;
|
|
131
|
+
const caseCount = result.suites.reduce((n, s) => n + s.cases.length, 0);
|
|
132
|
+
const byCategory = (category) => result.suites.reduce((n, s) => n + s.cases.filter((c) => c.category === category).length, 0);
|
|
133
|
+
console.log(`✓ Analyzed ${exported} exported functions (${result.suites.length} tested)`);
|
|
134
|
+
printMocks(result);
|
|
135
|
+
if (result.redactions)
|
|
136
|
+
console.log(`✓ Redacted ${result.redactions} likely secrets before sending`);
|
|
137
|
+
console.log(`✓ Generated ${caseCount} test cases (${byCategory("normal")} normal, ${byCategory("edge")} edge, ${byCategory("error")} error)`);
|
|
138
|
+
for (const r of result.rejected)
|
|
139
|
+
console.log(` ! rejected ${r.functionName} › "${r.name}": ${r.reason}`);
|
|
140
|
+
console.log(` Tokens: ${tokens(result.usage, result.model)} (${result.model})`);
|
|
141
|
+
if (options.dryRun) {
|
|
142
|
+
console.log(`\n${result.content}`);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
await writeTestFile(result.testPath, result.content, options.force, showDiff(result.testPath));
|
|
146
|
+
if (!options.run) {
|
|
147
|
+
console.log(`\nTests saved to ${relative(result.testPath)} (not run)`);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
let run = await runJest({ testPath: result.testPath, sourcePath: source.absolutePath, allowNetwork });
|
|
151
|
+
printRunResult(run);
|
|
152
|
+
let content = result.content;
|
|
153
|
+
let repair;
|
|
154
|
+
if (run.status === "failed" && options.repair) {
|
|
155
|
+
repair = await repairTests({
|
|
156
|
+
provider,
|
|
157
|
+
analysis: result.analysis,
|
|
158
|
+
promptSource: result.promptSource,
|
|
159
|
+
sourcePath: source.absolutePath,
|
|
160
|
+
testPath: result.testPath,
|
|
161
|
+
extension: source.extension,
|
|
162
|
+
preamble: result.preamble,
|
|
163
|
+
mockSummary: result.mocks.summary,
|
|
164
|
+
suites: result.suites,
|
|
165
|
+
initialRun: run,
|
|
166
|
+
maxAttempts,
|
|
167
|
+
allowNetwork,
|
|
168
|
+
budget,
|
|
169
|
+
});
|
|
170
|
+
printRepair(repair, result.model);
|
|
171
|
+
run = repair.run;
|
|
172
|
+
content = repair.content;
|
|
173
|
+
}
|
|
174
|
+
if (options.report) {
|
|
175
|
+
await writeFile(options.report, JSON.stringify(buildReport(source.inputPath, result, run, repair, budget), null, 2));
|
|
176
|
+
console.log(` Report written to ${relative(path.resolve(options.report))}`);
|
|
177
|
+
}
|
|
178
|
+
if (run.status !== "passed") {
|
|
179
|
+
console.log(`\nTests kept in ${relative(result.testPath)} for review.`);
|
|
180
|
+
process.exitCode = 1;
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (testPath) {
|
|
184
|
+
console.log(`\nTests saved to ${relative(result.testPath)}`);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
const finalPath = testPathFor(source.absolutePath);
|
|
188
|
+
try {
|
|
189
|
+
await writeTestFile(finalPath, content, options.force, showDiff(finalPath));
|
|
190
|
+
await rm(result.testPath);
|
|
191
|
+
console.log(`\nTests saved to ${relative(finalPath)}`);
|
|
192
|
+
}
|
|
193
|
+
catch (error) {
|
|
194
|
+
if (!(error instanceof TestFileExistsError))
|
|
195
|
+
throw error;
|
|
196
|
+
console.log(`\n${relative(finalPath)} already exists and was not generated by Assertloom.`);
|
|
197
|
+
console.log(`Passing tests kept in ${relative(result.testPath)}; rerun with --force to replace the existing file.`);
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=generate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate.js","sourceRoot":"","sources":["../../../src/cli/commands/generate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { stat } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { FileValidationError, validateSourceFile } from "../validateFile.js";
|
|
4
|
+
import { runJest } from "../../runner/index.js";
|
|
5
|
+
import { printRunResult } from "../report.js";
|
|
6
|
+
/** Node timers overflow above 2^31 - 1 ms and fire immediately. */
|
|
7
|
+
const MAX_TIMEOUT_SECONDS = 2_147_483;
|
|
8
|
+
/** `math.test.preview.ts` / `math.test.ts` / `math.spec.ts` → `math.ts`. */
|
|
9
|
+
export function inferSourcePath(testPath) {
|
|
10
|
+
const inferred = testPath.replace(/\.(test|spec)(\.preview)?(?=\.[cm]?[jt]sx?$)/, "");
|
|
11
|
+
return inferred === testPath ? undefined : inferred;
|
|
12
|
+
}
|
|
13
|
+
export function registerRunCommand(program) {
|
|
14
|
+
program
|
|
15
|
+
.command("run")
|
|
16
|
+
.description("Run a test file with Jest and report results and coverage of its source file")
|
|
17
|
+
.argument("<testFile>", "test file to run, such as math.test.preview.ts")
|
|
18
|
+
.option("--source <file>", "source file to measure coverage for (default: inferred from the test file name)")
|
|
19
|
+
.option("--timeout <seconds>", "kill Jest if it runs longer than this", "120")
|
|
20
|
+
.option("--json", "print the full result as JSON")
|
|
21
|
+
.option("--allow-network", "let the tests open network connections (blocked by default)")
|
|
22
|
+
.action(async (testFile, options) => {
|
|
23
|
+
const testPath = path.resolve(testFile);
|
|
24
|
+
try {
|
|
25
|
+
if (!(await stat(testPath)).isFile())
|
|
26
|
+
throw new Error();
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
throw new FileValidationError(`Test file not found: ${testFile}`);
|
|
30
|
+
}
|
|
31
|
+
const sourceArg = options.source ?? inferSourcePath(testFile);
|
|
32
|
+
if (!sourceArg)
|
|
33
|
+
throw new FileValidationError(`Cannot infer the source file from ${testFile}; pass --source.`);
|
|
34
|
+
const source = await validateSourceFile(sourceArg);
|
|
35
|
+
const timeoutSeconds = Number(options.timeout);
|
|
36
|
+
if (!Number.isFinite(timeoutSeconds) || timeoutSeconds <= 0 || timeoutSeconds > MAX_TIMEOUT_SECONDS) {
|
|
37
|
+
throw new FileValidationError(`--timeout must be a positive number of seconds, at most ${MAX_TIMEOUT_SECONDS}.`);
|
|
38
|
+
}
|
|
39
|
+
const result = await runJest({
|
|
40
|
+
testPath,
|
|
41
|
+
sourcePath: source.absolutePath,
|
|
42
|
+
timeoutMs: timeoutSeconds * 1000,
|
|
43
|
+
allowNetwork: !!options.allowNetwork,
|
|
44
|
+
});
|
|
45
|
+
if (options.json)
|
|
46
|
+
console.log(JSON.stringify(result, null, 2));
|
|
47
|
+
else
|
|
48
|
+
printRunResult(result);
|
|
49
|
+
if (result.status !== "passed")
|
|
50
|
+
process.exitCode = 1;
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../../src/cli/commands/run.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,mEAAmE;AACnE,MAAM,mBAAmB,GAAG,SAAS,CAAC;AAStC,4EAA4E;AAC5E,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,8CAA8C,EAAE,EAAE,CAAC,CAAC;IACtF,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,OAAgB;IACjD,OAAO;SACJ,OAAO,CAAC,KAAK,CAAC;SACd,WAAW,CAAC,8EAA8E,CAAC;SAC3F,QAAQ,CAAC,YAAY,EAAE,gDAAgD,CAAC;SACxE,MAAM,CAAC,iBAAiB,EAAE,iFAAiF,CAAC;SAC5G,MAAM,CAAC,qBAAqB,EAAE,uCAAuC,EAAE,KAAK,CAAC;SAC7E,MAAM,CAAC,QAAQ,EAAE,+BAA+B,CAAC;SACjD,MAAM,CAAC,iBAAiB,EAAE,6DAA6D,CAAC;SACxF,MAAM,CAAC,KAAK,EAAE,QAAgB,EAAE,OAA0B,EAAE,EAAE;QAC7D,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACxC,IAAI,CAAC;YACH,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE;gBAAE,MAAM,IAAI,KAAK,EAAE,CAAC;QAC1D,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,mBAAmB,CAAC,wBAAwB,QAAQ,EAAE,CAAC,CAAC;QACpE,CAAC;QAED,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,IAAI,eAAe,CAAC,QAAQ,CAAC,CAAC;QAC9D,IAAI,CAAC,SAAS;YAAE,MAAM,IAAI,mBAAmB,CAAC,qCAAqC,QAAQ,kBAAkB,CAAC,CAAC;QAC/G,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,SAAS,CAAC,CAAC;QAEnD,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAC/C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,cAAc,IAAI,CAAC,IAAI,cAAc,GAAG,mBAAmB,EAAE,CAAC;YACpG,MAAM,IAAI,mBAAmB,CAAC,2DAA2D,mBAAmB,GAAG,CAAC,CAAC;QACnH,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC;YAC3B,QAAQ;YACR,UAAU,EAAE,MAAM,CAAC,YAAY;YAC/B,SAAS,EAAE,cAAc,GAAG,IAAI;YAChC,YAAY,EAAE,CAAC,CAAC,OAAO,CAAC,YAAY;SACrC,CAAC,CAAC;QAEH,IAAI,OAAO,CAAC,IAAI;YAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;;YAC1D,cAAc,CAAC,MAAM,CAAC,CAAC;QAE5B,IAAI,MAAM,CAAC,MAAM,KAAK,QAAQ;YAAE,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { UserError } from "../errors.js";
|
|
3
|
+
import { createProgram } from "./program.js";
|
|
4
|
+
try {
|
|
5
|
+
await createProgram().parseAsync(process.argv);
|
|
6
|
+
}
|
|
7
|
+
catch (error) {
|
|
8
|
+
if (error instanceof UserError) {
|
|
9
|
+
console.error(`✗ ${error.message}`);
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
console.error(error);
|
|
13
|
+
}
|
|
14
|
+
process.exitCode = 1;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,IAAI,CAAC;IACH,MAAM,aAAa,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AACjD,CAAC;AAAC,OAAO,KAAK,EAAE,CAAC;IACf,IAAI,KAAK,YAAY,SAAS,EAAE,CAAC;QAC/B,OAAO,CAAC,KAAK,CAAC,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IACtC,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;IACD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { registerAnalyzeCommand } from "./commands/analyze.js";
|
|
4
|
+
import { registerCiCommand } from "./commands/ci.js";
|
|
5
|
+
import { registerGenerateCommand } from "./commands/generate.js";
|
|
6
|
+
import { registerRunCommand } from "./commands/run.js";
|
|
7
|
+
const { version } = JSON.parse(readFileSync(new URL("../../package.json", import.meta.url), "utf8"));
|
|
8
|
+
export function createProgram() {
|
|
9
|
+
const program = new Command()
|
|
10
|
+
.name("assertloom")
|
|
11
|
+
.description("Assertloom: AI-generated Jest tests that are executed, verified, and repaired.")
|
|
12
|
+
.version(version)
|
|
13
|
+
.showHelpAfterError();
|
|
14
|
+
registerAnalyzeCommand(program);
|
|
15
|
+
registerGenerateCommand(program);
|
|
16
|
+
registerRunCommand(program);
|
|
17
|
+
registerCiCommand(program);
|
|
18
|
+
return program;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=program.js.map
|