@vitest-agent/cli 3.2.7 → 4.0.1
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/commands/agent.js +2 -2
- package/commands/db.js +16 -36
- package/lib/render-failure.js +59 -0
- package/lib/version-formatter.js +18 -13
- package/main.d.ts +36 -16
- package/main.js +73 -51
- package/package.json +14 -12
- package/version.js +1 -1
package/commands/agent.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { recordCommand } from "./record.js";
|
|
2
2
|
import { triageCommand } from "./triage.js";
|
|
3
3
|
import { wrapupCommand } from "./wrapup.js";
|
|
4
|
+
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
4
5
|
import * as NodeServices from "@effect/platform-node/NodeServices";
|
|
5
6
|
import { SidecarPlatformLive, endAgentEffect, registerAgentEffect, resolveHookPaths, resolveProjectKeyFromCwd } from "@vitest-agent/engine";
|
|
6
|
-
import { classifyTestPath, detectNonDefaultDiscoverStrategy, findOwningWorkspace } from "@vitest-agent/sdk";
|
|
7
7
|
import { Cause, Effect, Option } from "effect";
|
|
8
8
|
import { Argument, Command, Flag } from "effect/cli";
|
|
9
9
|
import { existsSync, readFileSync } from "node:fs";
|
|
10
|
-
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
11
10
|
import { findWorkspaceRootSync, getWorkspacePackagesSync } from "@effected/workspaces";
|
|
12
11
|
import { nodeSyncOps } from "@effected/workspaces/node-sync";
|
|
12
|
+
import { classifyTestPath, detectNonDefaultDiscoverStrategy, findOwningWorkspace } from "@vitest-agent/sdk";
|
|
13
13
|
import { exitCodeForTag, injectEnv } from "@vitest-agent/sdk/dispatch";
|
|
14
14
|
import { resolveSidecarBinaryPath } from "@vitest-agent/sidecar";
|
|
15
15
|
|
package/commands/db.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { formatDbQuery } from "../lib/format-db-query.js";
|
|
2
|
-
import
|
|
2
|
+
import { Cancelled, CliExit, CliInteractive } from "@effected/cli";
|
|
3
3
|
import { DataStore, resolveDataPath } from "@vitest-agent/engine";
|
|
4
|
-
import { Effect, FileSystem } from "effect";
|
|
5
|
-
import { Argument, Command, Flag } from "effect/cli";
|
|
6
|
-
import * as readline from "node:readline";
|
|
4
|
+
import { Console, Effect, FileSystem } from "effect";
|
|
5
|
+
import { Argument, Command, Flag, Prompt } from "effect/cli";
|
|
7
6
|
import { layer } from "@effect/sql-sqlite-node/SqliteClient";
|
|
8
7
|
import { SqlClient } from "effect/sql/SqlClient";
|
|
9
8
|
|
|
@@ -21,37 +20,20 @@ const yesOption = Flag.Boolean("yes").pipe(Flag.withDefault(false), Flag.withDes
|
|
|
21
20
|
const resetCommand = Command.make("reset", { yes: yesOption }, ({ yes }) => Effect.gen(function* () {
|
|
22
21
|
const agentId = process.env.VITEST_AGENT_AGENT_ID;
|
|
23
22
|
if (agentId !== void 0 && agentId.length > 0) {
|
|
24
|
-
yield*
|
|
25
|
-
|
|
26
|
-
process.exit(4);
|
|
27
|
-
});
|
|
28
|
-
return;
|
|
23
|
+
yield* Console.error("db reset is human-only; use db prune or run from a human terminal");
|
|
24
|
+
return yield* CliExit.set(4);
|
|
29
25
|
}
|
|
30
26
|
const dbPath = yield* resolveDataPath(process.env.VITEST_AGENT_PROJECT_DIR ?? process.cwd());
|
|
31
|
-
if (!
|
|
32
|
-
yield*
|
|
33
|
-
|
|
34
|
-
process.exit(5);
|
|
35
|
-
});
|
|
36
|
-
return;
|
|
27
|
+
if (!yes && !(yield* CliInteractive)) {
|
|
28
|
+
yield* Console.error("db reset requires --yes when the run is not interactive (stdout or stdin is not a TTY, or the audience is not human)");
|
|
29
|
+
return yield* CliExit.set(5);
|
|
37
30
|
}
|
|
38
|
-
if (
|
|
39
|
-
if (!(yield*
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
});
|
|
45
|
-
rl.question(`Wipe ${dbPath}? [y/N]: `, (answer) => {
|
|
46
|
-
rl.close();
|
|
47
|
-
resolve(answer === "y" || answer === "Y");
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
}))) {
|
|
51
|
-
yield* Effect.sync(() => {
|
|
52
|
-
process.stdout.write("aborted\n");
|
|
53
|
-
process.exit(0);
|
|
54
|
-
});
|
|
31
|
+
if (!yes) {
|
|
32
|
+
if (!(yield* Prompt.run(Prompt.Confirm({
|
|
33
|
+
message: `Wipe ${dbPath}?`,
|
|
34
|
+
initial: false
|
|
35
|
+
})).pipe(Effect.catchTag("QuitError", () => Effect.fail(Cancelled.make({ reason: "interrupt" })))))) {
|
|
36
|
+
yield* Console.log("aborted");
|
|
55
37
|
return;
|
|
56
38
|
}
|
|
57
39
|
}
|
|
@@ -59,10 +41,8 @@ const resetCommand = Command.make("reset", { yes: yesOption }, ({ yes }) => Effe
|
|
|
59
41
|
yield* fs.remove(dbPath).pipe(Effect.catch(() => Effect.void));
|
|
60
42
|
yield* fs.remove(`${dbPath}-shm`).pipe(Effect.catch(() => Effect.void));
|
|
61
43
|
yield* fs.remove(`${dbPath}-wal`).pipe(Effect.catch(() => Effect.void));
|
|
62
|
-
yield*
|
|
63
|
-
|
|
64
|
-
});
|
|
65
|
-
}).pipe(Effect.provide(NodeServices.layer))).pipe(Command.withDescription("Wipe the database (human-only; blocked in agent contexts)"));
|
|
44
|
+
yield* Console.log(`Deleted database at ${dbPath}`);
|
|
45
|
+
})).pipe(Command.withDescription("Wipe the database (human-only; blocked in agent contexts)"));
|
|
66
46
|
const queryFormatOption = Flag.Literals("format", ["table", "json"]).pipe(Flag.withDefault("table"), Flag.withDescription("Output format for query results"));
|
|
67
47
|
const sqlArg = Argument.String("sql").pipe(Argument.withDescription("Read-only SQL statement to execute against data.db"));
|
|
68
48
|
/**
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Cancelled, Fmt, NotInteractive } from "@effected/cli";
|
|
2
|
+
import { Schema } from "effect";
|
|
3
|
+
|
|
4
|
+
//#region src/lib/render-failure.ts
|
|
5
|
+
/**
|
|
6
|
+
* The one-line name of a typed failure: its `_tag` when it carries one (a
|
|
7
|
+
* `PlatformError`, `SqlError`, `MigrationError`), else its `Error` name.
|
|
8
|
+
*/
|
|
9
|
+
const failureName = (error) => {
|
|
10
|
+
if (typeof error === "object" && error !== null && "_tag" in error && typeof error._tag === "string") return error._tag;
|
|
11
|
+
return error instanceof Error ? error.name : "Error";
|
|
12
|
+
};
|
|
13
|
+
/** Where a defect's report sends the reader: a defect is a bug in this program. */
|
|
14
|
+
const ISSUE_URL = "https://github.com/spencerbeggs/vitest-agent/issues";
|
|
15
|
+
/**
|
|
16
|
+
* Failures the kit renders better than one `<Tag>: <message>` line: its own
|
|
17
|
+
* `Cancelled` / `NotInteractive` fixed lines, and a `SchemaError` as a tree of
|
|
18
|
+
* the rejected values.
|
|
19
|
+
*/
|
|
20
|
+
const isKitRendered = (error) => error instanceof Cancelled || error instanceof NotInteractive || Schema.isSchemaError(error);
|
|
21
|
+
/** One line of text we did not write, made safe to print: controls stripped, line breaks folded to spaces. */
|
|
22
|
+
const oneLine = (text) => Fmt.sanitize(text).replace(/\s*[\r\n]+\s*/g, " ").trim();
|
|
23
|
+
/**
|
|
24
|
+
* One rendering for every failure `CliRuntime.main` reports, its first line
|
|
25
|
+
* led by `vitest-agent: `. The kit says which kind it is
|
|
26
|
+
* (`details.isDefect`, exact: the cause carries no typed failure).
|
|
27
|
+
*
|
|
28
|
+
* - A typed failure from the error channel (a `PlatformError`, `SqlError`,
|
|
29
|
+
* `MigrationError`) is the one line we own: `vitest-agent: <Tag>: <message>`,
|
|
30
|
+
* the message passed through `Fmt.sanitize` (it can carry a path or SQL text).
|
|
31
|
+
* - Everything else is delegated to `details.lines({ status: false })`, the
|
|
32
|
+
* kit's report for this run (its colour, links, and `displayPath`) with the
|
|
33
|
+
* status glyph / `[FAIL]` tag left off, so our prefix replaces the marker
|
|
34
|
+
* rather than doubling it: `Cancelled` / `NotInteractive` keep their fixed
|
|
35
|
+
* line (`vitest-agent: cancelled; nothing written`), a `SchemaError` is a
|
|
36
|
+
* tree, and a defect is its message plus a `stack` of the program's own
|
|
37
|
+
* frames (`node_modules`, Node, and Effect frames hidden and counted), then
|
|
38
|
+
* the issue link.
|
|
39
|
+
*
|
|
40
|
+
* `ShowHelp` and runWith-rendered `UserError`s never reach here (the kit skips
|
|
41
|
+
* them).
|
|
42
|
+
*
|
|
43
|
+
* @internal
|
|
44
|
+
*/
|
|
45
|
+
const renderFailure = (error, details) => {
|
|
46
|
+
if (!details.isDefect && !isKitRendered(error)) {
|
|
47
|
+
const message = oneLine(error instanceof Error ? error.message : typeof error === "string" ? error : "");
|
|
48
|
+
return [`vitest-agent: ${oneLine(failureName(error))}${message ? `: ${message}` : ""}`];
|
|
49
|
+
}
|
|
50
|
+
const [first = failureName(error), ...rest] = details.lines({ status: false });
|
|
51
|
+
return [
|
|
52
|
+
`vitest-agent: ${first}`,
|
|
53
|
+
...rest,
|
|
54
|
+
...details.isDefect ? [`Please report at ${ISSUE_URL}`] : []
|
|
55
|
+
];
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
//#endregion
|
|
59
|
+
export { renderFailure };
|
package/lib/version-formatter.js
CHANGED
|
@@ -1,23 +1,28 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { CurrentDistribution, distributionSuffix } from "@effected/engine";
|
|
3
|
-
import { Effect, Layer } from "effect";
|
|
1
|
+
import { distributionSuffix } from "@effected/engine";
|
|
4
2
|
|
|
5
3
|
//#region src/lib/version-formatter.ts
|
|
6
4
|
/**
|
|
7
|
-
* The
|
|
8
|
-
*
|
|
9
|
-
* unset or empty) with only `formatVersion` overridden, so `--version`
|
|
5
|
+
* The `CliOutput.Formatter` methods `main.ts` replaces through
|
|
6
|
+
* `CliRuntime.main`'s `env.formatter`: only `formatVersion`, so `--version`
|
|
10
7
|
* prints `vitest-agent <cli version>` plus ` via <name> <version>` when a
|
|
11
|
-
* carrier (`@vitest-agent/plugin`'s bin shim)
|
|
12
|
-
* Help and parse-error rendering stay `CliColor`'s own.
|
|
8
|
+
* carrier (`@vitest-agent/plugin`'s bin shim) passed its identity to `main`.
|
|
13
9
|
*
|
|
14
|
-
* `
|
|
15
|
-
*
|
|
16
|
-
*
|
|
10
|
+
* `env.formatter` is the kit's one way to keep a formatter method of our own:
|
|
11
|
+
* `main` installs its coloured default formatter inside the platform, which
|
|
12
|
+
* shadows any formatter the platform sets. Every method left out keeps the
|
|
13
|
+
* kit's coloured default, and `helpOnUsageError: "stderr"` still wraps the
|
|
14
|
+
* result, so usage-error help keeps going to stderr.
|
|
15
|
+
*
|
|
16
|
+
* `distribution` is the same value `main.ts` provides as `CurrentDistribution`;
|
|
17
|
+
* it is known when `main` is called, so it is read here directly rather than
|
|
18
|
+
* from the context when `--version` runs.
|
|
17
19
|
*
|
|
18
20
|
* @internal
|
|
19
21
|
*/
|
|
20
|
-
const
|
|
22
|
+
const carrierVersionFormatter = (distribution) => {
|
|
23
|
+
const suffix = distributionSuffix(distribution);
|
|
24
|
+
return { formatVersion: (name, version) => `${name} ${version}${suffix}` };
|
|
25
|
+
};
|
|
21
26
|
|
|
22
27
|
//#endregion
|
|
23
|
-
export {
|
|
28
|
+
export { carrierVersionFormatter };
|
package/main.d.ts
CHANGED
|
@@ -18,28 +18,48 @@ export interface MainOptions {
|
|
|
18
18
|
* re-exported from `index.ts` — a library consumer's import graph must not
|
|
19
19
|
* pull in the process-owning module.
|
|
20
20
|
*
|
|
21
|
+
* The one `@effected/cli` wiring: the root carries `CliAudience.flags()`
|
|
22
|
+
* (`--audience <human|agent|ci>`, `--human`, `--agent`, `--ci`), runs through
|
|
23
|
+
* `CliAudience.run`, and `CliRuntime.main`'s `env` option builds the
|
|
24
|
+
* `@effected/env` services (`Audience` with the `VITEST_AGENT_AUDIENCE`
|
|
25
|
+
* override, `TerminalEnv`, `CliTheme`, `CliInteractive`, the gated `Terminal`)
|
|
26
|
+
* plus the kit's colour-decided help formatter, inside failure reporting.
|
|
27
|
+
* `env.formatter` replaces only that formatter's `formatVersion`, so
|
|
28
|
+
* `--version` names the carrier (`via @vitest-agent/plugin <version>`) when
|
|
29
|
+
* `options.distribution` is given; the same value is provided as
|
|
30
|
+
* `CurrentDistribution`. An audience flag recomputes `CliInteractive` from the
|
|
31
|
+
* TTY facts, so `--human` in an agent-detected shell (Claude Code's terminal)
|
|
32
|
+
* at a real terminal may prompt.
|
|
33
|
+
*
|
|
21
34
|
* Output routing (hooks parse `agent *` stdout with jq, so stdout carries
|
|
22
35
|
* only what a command writes as its result):
|
|
23
36
|
*
|
|
24
|
-
* -
|
|
25
|
-
* `
|
|
26
|
-
* `VITEST_REPORTER_LOG_LEVEL` is set
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
37
|
+
* - `env.log` makes `CliLog.layer` the one logger set, outermost: a
|
|
38
|
+
* `CliLogger` for ordinary lines and failure reports, plus a diagnostics
|
|
39
|
+
* sink that is silent unless `VITEST_REPORTER_LOG_LEVEL` is set (then
|
|
40
|
+
* NDJSON on stderr for every audience), plus an
|
|
41
|
+
* async NDJSON file when `VITEST_REPORTER_LOG_FILE` is set. The platform
|
|
42
|
+
* therefore installs no logger of its own (`PlatformLive`'s `logger: false`:
|
|
43
|
+
* the engine's `LoggerLive` would otherwise replace this set inside the
|
|
44
|
+
* program). The platform is built under that logger, so what it logs
|
|
45
|
+
* while building (the engine's migration records) reaches the same sink.
|
|
46
|
+
* `format: "auto"`: NDJSON for an agent or a CI, plain lines for a person.
|
|
47
|
+
* `argv` (`process.argv.slice(2)`) lets the build-time records follow the
|
|
48
|
+
* audience flags too, so `--agent` with no agent detected is all NDJSON and
|
|
49
|
+
* `--human` in an agent shell is all plain, migration records included.
|
|
50
|
+
* - Failures render through `renderFailure` on stderr, first line led by
|
|
51
|
+
* `vitest-agent: `. `env.displayPath` shows a defect's stack frames
|
|
52
|
+
* relative to the project directory (absolute when outside it).
|
|
33
53
|
* - An explicit `--help` (or a bare group invocation) prints help on
|
|
34
|
-
* stdout. A usage error (unknown flag, bad value, unknown subcommand
|
|
35
|
-
* prints help AND the parse errors on stderr
|
|
36
|
-
* so stdout stays empty for a jq-piping
|
|
37
|
-
*
|
|
38
|
-
* through `platform` for the kit to reroute it.
|
|
54
|
+
* stdout. A usage error (unknown flag, bad value, unknown subcommand,
|
|
55
|
+
* conflicting audience flags) prints help AND the parse errors on stderr
|
|
56
|
+
* (`helpOnUsageError: "stderr"`), so stdout stays empty for a jq-piping
|
|
57
|
+
* hook.
|
|
39
58
|
*
|
|
40
59
|
* Exit codes are the kit's: `0` success (including bare `--help`), `64` a
|
|
41
|
-
* usage error
|
|
42
|
-
*
|
|
60
|
+
* usage error, `130` a cancelled prompt, `1` any other reported failure.
|
|
61
|
+
* Commands that record their own code through `CliExit` (`db reset`) or
|
|
62
|
+
* `process.exit` with it still exit with it.
|
|
43
63
|
*
|
|
44
64
|
* @public
|
|
45
65
|
*/
|
package/main.js
CHANGED
|
@@ -2,13 +2,14 @@ import { CURRENT_CLI_VERSION } from "./version.js";
|
|
|
2
2
|
import { agentCommand } from "./commands/agent.js";
|
|
3
3
|
import { dbCommand } from "./commands/db.js";
|
|
4
4
|
import { doctorCommand } from "./commands/doctor.js";
|
|
5
|
-
import {
|
|
5
|
+
import { renderFailure } from "./lib/render-failure.js";
|
|
6
|
+
import { carrierVersionFormatter } from "./lib/version-formatter.js";
|
|
7
|
+
import { isAbsolute, relative } from "node:path";
|
|
6
8
|
import * as NodeRuntime from "@effect/platform-node/NodeRuntime";
|
|
7
9
|
import * as NodeServices from "@effect/platform-node/NodeServices";
|
|
8
|
-
import { CliRuntime } from "@effected/cli";
|
|
10
|
+
import { CliAudience, CliRuntime } from "@effected/cli";
|
|
9
11
|
import { CurrentDistribution } from "@effected/engine";
|
|
10
|
-
import { PathResolutionLive, PlatformLive, resolveDataPath,
|
|
11
|
-
import { formatFatalError } from "@vitest-agent/sdk";
|
|
12
|
+
import { PathResolutionLive, PlatformLive, resolveDataPath, resolveProjectDir } from "@vitest-agent/engine";
|
|
12
13
|
import { Effect, Layer, Option } from "effect";
|
|
13
14
|
import { Command } from "effect/cli";
|
|
14
15
|
|
|
@@ -25,81 +26,102 @@ import { Command } from "effect/cli";
|
|
|
25
26
|
*
|
|
26
27
|
* @packageDocumentation
|
|
27
28
|
*/
|
|
28
|
-
|
|
29
|
+
/**
|
|
30
|
+
* The environment variable that overrides the detected audience
|
|
31
|
+
* (`human` | `agent` | `ci`), read by `@effected/env`'s `Audience` through
|
|
32
|
+
* `Config`. The `VITEST_AGENT_` prefix is the family's runtime-override
|
|
33
|
+
* namespace (`VITEST_AGENT_CONSOLE`, `VITEST_AGENT_PROJECT_DIR`,
|
|
34
|
+
* `VITEST_AGENT_CLI_CMD`); the `VITEST_REPORTER_` prefix survives only on the
|
|
35
|
+
* two legacy logging variables.
|
|
36
|
+
*/
|
|
37
|
+
const AUDIENCE_ENV_VAR = "VITEST_AGENT_AUDIENCE";
|
|
38
|
+
const rootCommand = Command.make("vitest-agent").pipe(Command.withSharedFlags(CliAudience.flags()), Command.withSubcommands([
|
|
29
39
|
dbCommand,
|
|
30
40
|
doctorCommand,
|
|
31
41
|
agentCommand
|
|
32
42
|
]));
|
|
33
43
|
/**
|
|
34
|
-
* The one-line name of a typed failure: its `_tag` when it carries one (a
|
|
35
|
-
* `PlatformError`, `SqlError`, `MigrationError`), else its `Error` name.
|
|
36
|
-
*/
|
|
37
|
-
const failureName = (error) => {
|
|
38
|
-
if (typeof error === "object" && error !== null && "_tag" in error && typeof error._tag === "string") return error._tag;
|
|
39
|
-
return error instanceof Error ? error.name : "Error";
|
|
40
|
-
};
|
|
41
|
-
/**
|
|
42
|
-
* One rendering for every failure `CliRuntime.main` reports. The kit says
|
|
43
|
-
* which kind it is (`details.isDefect`, exact: the cause carries no typed
|
|
44
|
-
* failure): a typed failure from the error channel is one line, a defect
|
|
45
|
-
* keeps the issue-report rendering `formatFatalError` gives it. `ShowHelp`
|
|
46
|
-
* and runWith-rendered `UserError`s never reach here (the kit skips them).
|
|
47
|
-
*/
|
|
48
|
-
const renderFailure = (error, details) => {
|
|
49
|
-
if (details.isDefect) return `vitest-agent: ${formatFatalError(error)}`;
|
|
50
|
-
const message = error instanceof Error ? error.message : typeof error === "string" ? error : "";
|
|
51
|
-
return `vitest-agent: ${failureName(error)}${message ? `: ${message}` : ""}`;
|
|
52
|
-
};
|
|
53
|
-
/**
|
|
54
44
|
* Assembles and runs the CLI program, taking over the process. Not
|
|
55
45
|
* re-exported from `index.ts` — a library consumer's import graph must not
|
|
56
46
|
* pull in the process-owning module.
|
|
57
47
|
*
|
|
48
|
+
* The one `@effected/cli` wiring: the root carries `CliAudience.flags()`
|
|
49
|
+
* (`--audience <human|agent|ci>`, `--human`, `--agent`, `--ci`), runs through
|
|
50
|
+
* `CliAudience.run`, and `CliRuntime.main`'s `env` option builds the
|
|
51
|
+
* `@effected/env` services (`Audience` with the `VITEST_AGENT_AUDIENCE`
|
|
52
|
+
* override, `TerminalEnv`, `CliTheme`, `CliInteractive`, the gated `Terminal`)
|
|
53
|
+
* plus the kit's colour-decided help formatter, inside failure reporting.
|
|
54
|
+
* `env.formatter` replaces only that formatter's `formatVersion`, so
|
|
55
|
+
* `--version` names the carrier (`via @vitest-agent/plugin <version>`) when
|
|
56
|
+
* `options.distribution` is given; the same value is provided as
|
|
57
|
+
* `CurrentDistribution`. An audience flag recomputes `CliInteractive` from the
|
|
58
|
+
* TTY facts, so `--human` in an agent-detected shell (Claude Code's terminal)
|
|
59
|
+
* at a real terminal may prompt.
|
|
60
|
+
*
|
|
58
61
|
* Output routing (hooks parse `agent *` stdout with jq, so stdout carries
|
|
59
62
|
* only what a command writes as its result):
|
|
60
63
|
*
|
|
61
|
-
* -
|
|
62
|
-
* `
|
|
63
|
-
* `VITEST_REPORTER_LOG_LEVEL` is set
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
64
|
+
* - `env.log` makes `CliLog.layer` the one logger set, outermost: a
|
|
65
|
+
* `CliLogger` for ordinary lines and failure reports, plus a diagnostics
|
|
66
|
+
* sink that is silent unless `VITEST_REPORTER_LOG_LEVEL` is set (then
|
|
67
|
+
* NDJSON on stderr for every audience), plus an
|
|
68
|
+
* async NDJSON file when `VITEST_REPORTER_LOG_FILE` is set. The platform
|
|
69
|
+
* therefore installs no logger of its own (`PlatformLive`'s `logger: false`:
|
|
70
|
+
* the engine's `LoggerLive` would otherwise replace this set inside the
|
|
71
|
+
* program). The platform is built under that logger, so what it logs
|
|
72
|
+
* while building (the engine's migration records) reaches the same sink.
|
|
73
|
+
* `format: "auto"`: NDJSON for an agent or a CI, plain lines for a person.
|
|
74
|
+
* `argv` (`process.argv.slice(2)`) lets the build-time records follow the
|
|
75
|
+
* audience flags too, so `--agent` with no agent detected is all NDJSON and
|
|
76
|
+
* `--human` in an agent shell is all plain, migration records included.
|
|
77
|
+
* - Failures render through `renderFailure` on stderr, first line led by
|
|
78
|
+
* `vitest-agent: `. `env.displayPath` shows a defect's stack frames
|
|
79
|
+
* relative to the project directory (absolute when outside it).
|
|
70
80
|
* - An explicit `--help` (or a bare group invocation) prints help on
|
|
71
|
-
* stdout. A usage error (unknown flag, bad value, unknown subcommand
|
|
72
|
-
* prints help AND the parse errors on stderr
|
|
73
|
-
* so stdout stays empty for a jq-piping
|
|
74
|
-
*
|
|
75
|
-
* through `platform` for the kit to reroute it.
|
|
81
|
+
* stdout. A usage error (unknown flag, bad value, unknown subcommand,
|
|
82
|
+
* conflicting audience flags) prints help AND the parse errors on stderr
|
|
83
|
+
* (`helpOnUsageError: "stderr"`), so stdout stays empty for a jq-piping
|
|
84
|
+
* hook.
|
|
76
85
|
*
|
|
77
86
|
* Exit codes are the kit's: `0` success (including bare `--help`), `64` a
|
|
78
|
-
* usage error
|
|
79
|
-
*
|
|
87
|
+
* usage error, `130` a cancelled prompt, `1` any other reported failure.
|
|
88
|
+
* Commands that record their own code through `CliExit` (`db reset`) or
|
|
89
|
+
* `process.exit` with it still exit with it.
|
|
80
90
|
*
|
|
81
91
|
* @public
|
|
82
92
|
*/
|
|
83
93
|
const main = (options = {}) => {
|
|
84
94
|
const env = process.env;
|
|
85
|
-
const logLevel = resolveLogLevel(env);
|
|
86
|
-
const logFile = resolveLogFile(env);
|
|
87
95
|
const projectDir = resolveProjectDir({
|
|
88
96
|
env,
|
|
89
97
|
cwd: process.cwd()
|
|
90
98
|
});
|
|
91
|
-
const
|
|
99
|
+
const platform = Layer.unwrap(Effect.map(resolveDataPath(projectDir), (dbPath) => PlatformLive({
|
|
92
100
|
dbPath,
|
|
93
101
|
env,
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const
|
|
98
|
-
|
|
102
|
+
logger: false
|
|
103
|
+
}))).pipe(Layer.provideMerge(PathResolutionLive(projectDir)), Layer.provideMerge(NodeServices.layer));
|
|
104
|
+
const distribution = Option.fromNullishOr(options.distribution);
|
|
105
|
+
const displayPath = (absolute) => {
|
|
106
|
+
const rel = relative(projectDir, absolute);
|
|
107
|
+
return rel === "" || rel.startsWith("..") || isAbsolute(rel) ? absolute : rel;
|
|
108
|
+
};
|
|
109
|
+
const program = CliRuntime.main(CliAudience.run(rootCommand, { version: CURRENT_CLI_VERSION }), {
|
|
99
110
|
platform,
|
|
100
111
|
render: renderFailure,
|
|
101
|
-
helpOnUsageError: "stderr"
|
|
102
|
-
|
|
112
|
+
helpOnUsageError: "stderr",
|
|
113
|
+
env: {
|
|
114
|
+
audienceEnvVar: AUDIENCE_ENV_VAR,
|
|
115
|
+
formatter: carrierVersionFormatter(distribution),
|
|
116
|
+
displayPath,
|
|
117
|
+
log: {
|
|
118
|
+
envVar: "VITEST_REPORTER_LOG_LEVEL",
|
|
119
|
+
format: "auto",
|
|
120
|
+
argv: process.argv.slice(2),
|
|
121
|
+
file: { envVar: "VITEST_REPORTER_LOG_FILE" }
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}).pipe(Effect.provideService(CurrentDistribution, distribution));
|
|
103
125
|
NodeRuntime.runMain(program);
|
|
104
126
|
};
|
|
105
127
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vitest-agent/cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "On-demand CLI for vitest-agent. Reads cached test data and reports status, overview, coverage, history, trends, and cache health.",
|
|
6
6
|
"keywords": [
|
|
@@ -43,17 +43,19 @@
|
|
|
43
43
|
"vitest-agent": "bin/vitest-agent.js"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@effect/platform-node": "4.0.0
|
|
47
|
-
"@effect/sql-sqlite-node": "4.0.0
|
|
48
|
-
"@effected/cli": "^0.
|
|
49
|
-
"@effected/config-file": "^0.
|
|
50
|
-
"@effected/engine": "^0.
|
|
51
|
-
"@effected/
|
|
52
|
-
"@effected/
|
|
53
|
-
"@
|
|
54
|
-
"@
|
|
55
|
-
"@vitest-agent/
|
|
56
|
-
"
|
|
46
|
+
"@effect/platform-node": "^4.0.0",
|
|
47
|
+
"@effect/sql-sqlite-node": "^4.0.0",
|
|
48
|
+
"@effected/cli": "^0.11.0",
|
|
49
|
+
"@effected/config-file": "^0.14.0",
|
|
50
|
+
"@effected/engine": "^0.3.0",
|
|
51
|
+
"@effected/env": "^0.1.0",
|
|
52
|
+
"@effected/glob": "^0.10.0",
|
|
53
|
+
"@effected/walker": "^0.15.0",
|
|
54
|
+
"@effected/workspaces": "^0.31.0",
|
|
55
|
+
"@vitest-agent/engine": "0.5.0",
|
|
56
|
+
"@vitest-agent/sdk": "6.0.0",
|
|
57
|
+
"@vitest-agent/sidecar": "2.2.5",
|
|
58
|
+
"effect": "^4.0.0"
|
|
57
59
|
},
|
|
58
60
|
"engines": {
|
|
59
61
|
"node": ">=24.11.0"
|