@vitest-agent/cli 4.1.3 → 4.1.4
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 +8 -27
- package/commands/flag-defaults.js +9 -0
- package/commands/record.js +14 -12
- package/lib/format-db-query.js +6 -3
- package/lib/version-formatter.js +9 -14
- package/main.d.ts +4 -3
- package/main.js +10 -15
- package/package.json +11 -11
- package/version.js +1 -1
package/commands/agent.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
+
import { currentCwd } from "./flag-defaults.js";
|
|
1
2
|
import { recordCommand } from "./record.js";
|
|
2
3
|
import { triageCommand } from "./triage.js";
|
|
3
4
|
import { wrapupCommand } from "./wrapup.js";
|
|
4
|
-
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
5
5
|
import * as NodeServices from "@effect/platform-node/NodeServices";
|
|
6
6
|
import { SidecarPlatformLive, endAgentEffect, registerAgentEffect, resolveHookPaths, resolveProjectKeyFromCwd } from "@vitest-agent/engine";
|
|
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";
|
|
10
11
|
import { findWorkspaceRootSync, getWorkspacePackagesSync } from "@effected/workspaces";
|
|
11
12
|
import { nodeSyncOps } from "@effected/workspaces/node-sync";
|
|
12
|
-
import { classifyTestPath, detectNonDefaultDiscoverStrategy, findOwningWorkspace } from "@vitest-agent/sdk";
|
|
13
|
+
import { VITEST_CONFIG_FILES, classifyTestPath, detectNonDefaultDiscoverStrategy, findOwningWorkspace } from "@vitest-agent/sdk";
|
|
13
14
|
import { exitCodeForTag, injectEnv } from "@vitest-agent/sdk/dispatch";
|
|
14
15
|
import { resolveSidecarBinaryPath } from "@vitest-agent/sidecar";
|
|
15
16
|
|
|
@@ -80,7 +81,7 @@ const registerAgentSubcommand = Command.make("register-agent", {
|
|
|
80
81
|
const agentIdOpt = Flag.String("agent-id").pipe(Flag.withDescription("The agent_id (UUID) returned by an earlier register-agent call"));
|
|
81
82
|
const endedAtOpt = Flag.optional(Flag.Int("ended-at"));
|
|
82
83
|
const endHostSessionIdOpt = Flag.optional(Flag.String("host-session-id"));
|
|
83
|
-
const endCwdOpt = Flag.String("cwd").pipe(Flag.withDefault(
|
|
84
|
+
const endCwdOpt = Flag.String("cwd").pipe(Flag.withDefault(currentCwd), Flag.withDescription("Workspace root, used to locate the per-project data.db"));
|
|
84
85
|
const endProjectKeyOverrideOpt = Flag.optional(Flag.String("project-key"));
|
|
85
86
|
const endAgentSubcommand = Command.make("end-agent", {
|
|
86
87
|
agentId: agentIdOpt,
|
|
@@ -103,7 +104,7 @@ const endAgentSubcommand = Command.make("end-agent", {
|
|
|
103
104
|
}).pipe(Effect.provide(sidecar, { local: true }), Effect.catchCause(mapDefectToExit));
|
|
104
105
|
}).pipe(Effect.provide(NodeServices.layer))).pipe(Command.withDescription("Mark an agent (and optionally its session) as ended"));
|
|
105
106
|
const commandOpt = Flag.String("command").pipe(Flag.withDescription("The Bash command to (possibly) rewrite with VITEST_AGENT_* env-prefix"));
|
|
106
|
-
const cwdInjectOpt = Flag.String("cwd").pipe(Flag.withDefault(
|
|
107
|
+
const cwdInjectOpt = Flag.String("cwd").pipe(Flag.withDefault(currentCwd), Flag.withDescription("Working directory; used to find package.json scripts"));
|
|
107
108
|
const injectEnvSubcommand = Command.make("inject-env", {
|
|
108
109
|
command: commandOpt,
|
|
109
110
|
cwd: cwdInjectOpt
|
|
@@ -147,29 +148,9 @@ function crossesNestedPackageBoundary(ownerPath, filePath) {
|
|
|
147
148
|
return false;
|
|
148
149
|
}
|
|
149
150
|
/**
|
|
150
|
-
* Candidate Vitest/Vite config filenames at a workspace root, in the order
|
|
151
|
-
* Vitest itself would prefer them. `vite.config.*` is a fallback for a
|
|
152
|
-
* workspace that configures the plugin through Vite directly rather than a
|
|
153
|
-
* dedicated `vitest.config.*`.
|
|
154
|
-
* @internal
|
|
155
|
-
*/
|
|
156
|
-
const VITEST_CONFIG_CANDIDATES = [
|
|
157
|
-
"vitest.config.ts",
|
|
158
|
-
"vitest.config.mts",
|
|
159
|
-
"vitest.config.js",
|
|
160
|
-
"vitest.config.mjs",
|
|
161
|
-
"vitest.workspace.ts",
|
|
162
|
-
"vitest.workspace.mts",
|
|
163
|
-
"vitest.workspace.js",
|
|
164
|
-
"vitest.workspace.mjs",
|
|
165
|
-
"vite.config.ts",
|
|
166
|
-
"vite.config.mts",
|
|
167
|
-
"vite.config.js",
|
|
168
|
-
"vite.config.mjs"
|
|
169
|
-
];
|
|
170
|
-
/**
|
|
171
151
|
* Reads the first Vitest/Vite config file found at `root`, returning its
|
|
172
|
-
* source text, or `null` when none of
|
|
152
|
+
* source text, or `null` when none of sdk's `VITEST_CONFIG_FILES` (the names
|
|
153
|
+
* Vitest 5 itself loads, in its order) exists
|
|
173
154
|
* or the file that does exist cannot be read.
|
|
174
155
|
*
|
|
175
156
|
* A `null` result is deliberately indistinguishable between "no config file"
|
|
@@ -178,7 +159,7 @@ const VITEST_CONFIG_CANDIDATES = [
|
|
|
178
159
|
* @internal
|
|
179
160
|
*/
|
|
180
161
|
function readWorkspaceVitestConfigSource(root) {
|
|
181
|
-
for (const candidate of
|
|
162
|
+
for (const candidate of VITEST_CONFIG_FILES) {
|
|
182
163
|
const candidatePath = join(root, candidate);
|
|
183
164
|
if (!existsSync(candidatePath)) continue;
|
|
184
165
|
try {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { DateTime, Effect } from "effect";
|
|
2
|
+
|
|
3
|
+
// src/commands/flag-defaults.ts
|
|
4
|
+
/** The current instant as an ISO 8601 string, read from the `Clock` when the flag is absent. */
|
|
5
|
+
const nowIso = Effect.map(DateTime.now, DateTime.formatIso);
|
|
6
|
+
/** The process working directory, read when the flag is absent. */
|
|
7
|
+
const currentCwd = Effect.sync(() => process.cwd());
|
|
8
|
+
|
|
9
|
+
export { currentCwd, nowIso };
|
package/commands/record.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
+
import { nowIso } from "./flag-defaults.js";
|
|
1
2
|
import { ProjectDataLive } from "../layers/project-data.js";
|
|
3
|
+
import { Fmt } from "@effected/cli";
|
|
2
4
|
import { DataReader, DataStore, dispatchRecordTddArtifactEffect, recordRunWorkspaceChangesEffect, recordSessionEnd, recordSessionStart, recordTurnEffect } from "@vitest-agent/engine";
|
|
3
5
|
import { Effect, Option } from "effect";
|
|
4
6
|
import { Argument, Command, Flag } from "effect/cli";
|
|
5
7
|
|
|
6
8
|
// src/commands/record.ts
|
|
7
9
|
const chatId = Flag.String("chat-id").pipe(Flag.withDescription("Host chat id (`session_id` in the Claude Code hook envelope; equivalent in other clients)"));
|
|
8
|
-
const occurredAt = Flag.String("occurred-at").pipe(Flag.withDefault(
|
|
10
|
+
const occurredAt = Flag.String("occurred-at").pipe(Flag.withDefault(nowIso), Flag.withDescription("ISO 8601 timestamp; defaults to now"));
|
|
9
11
|
const payloadArg = Argument.String("payload-json").pipe(Argument.withDescription("Stringified JSON payload (validated against TurnPayload)"));
|
|
10
12
|
const project = Flag.String("project");
|
|
11
13
|
const cwd = Flag.String("cwd");
|
|
@@ -24,14 +26,14 @@ const turnSubcommand = Command.make("turn", {
|
|
|
24
26
|
...project._tag === "Some" && { project: project.value },
|
|
25
27
|
cwd: cwd._tag === "Some" ? cwd.value : process.cwd()
|
|
26
28
|
}).pipe(Effect.flatMap((result) => Effect.sync(() => process.stdout.write(`${JSON.stringify(result)}\n`))), Effect.catch((err) => Effect.sync(() => {
|
|
27
|
-
process.stderr.write(`record turn: ${
|
|
29
|
+
process.stderr.write(`record turn: ${Fmt.describe(err)}\n`);
|
|
28
30
|
process.exit(1);
|
|
29
31
|
})))).pipe(Command.withDescription("Validate a TurnPayload JSON and write a turn row"));
|
|
30
32
|
const agentKind = Flag.Literals("agent-kind", ["main", "subagent"]).pipe(Flag.withDefault("main"));
|
|
31
33
|
const agentType = Flag.optional(Flag.String("agent-type"));
|
|
32
34
|
const parentChatId = Flag.optional(Flag.String("parent-chat-id"));
|
|
33
35
|
const triageWasNonEmpty = Flag.Boolean("triage-was-non-empty").pipe(Flag.withDefault(false));
|
|
34
|
-
const startedAt = Flag.String("started-at").pipe(Flag.withDefault(
|
|
36
|
+
const startedAt = Flag.String("started-at").pipe(Flag.withDefault(nowIso));
|
|
35
37
|
const sessionStartSubcommand = Command.make("session-start", {
|
|
36
38
|
chatId,
|
|
37
39
|
project,
|
|
@@ -51,10 +53,10 @@ const sessionStartSubcommand = Command.make("session-start", {
|
|
|
51
53
|
triageWasNonEmpty: opts.triageWasNonEmpty,
|
|
52
54
|
startedAt: opts.startedAt
|
|
53
55
|
}).pipe(Effect.flatMap((result) => Effect.sync(() => process.stdout.write(`${JSON.stringify(result)}\n`))), Effect.catch((err) => Effect.sync(() => {
|
|
54
|
-
process.stderr.write(`record session-start: ${
|
|
56
|
+
process.stderr.write(`record session-start: ${Fmt.describe(err)}\n`);
|
|
55
57
|
process.exit(1);
|
|
56
58
|
})))).pipe(Command.withDescription("Insert a new sessions row"));
|
|
57
|
-
const endedAt = Flag.String("ended-at").pipe(Flag.withDefault(
|
|
59
|
+
const endedAt = Flag.String("ended-at").pipe(Flag.withDefault(nowIso));
|
|
58
60
|
const endReason = Flag.optional(Flag.String("end-reason"));
|
|
59
61
|
const sessionEndSubcommand = Command.make("session-end", {
|
|
60
62
|
chatId,
|
|
@@ -65,7 +67,7 @@ const sessionEndSubcommand = Command.make("session-end", {
|
|
|
65
67
|
endedAt: opts.endedAt,
|
|
66
68
|
endReason: opts.endReason._tag === "Some" ? opts.endReason.value : null
|
|
67
69
|
}).pipe(Effect.flatMap(() => Effect.sync(() => process.stdout.write(`{"ok":true}\n`))), Effect.catch((err) => Effect.sync(() => {
|
|
68
|
-
process.stderr.write(`record session-end: ${
|
|
70
|
+
process.stderr.write(`record session-end: ${Fmt.describe(err)}\n`);
|
|
69
71
|
process.exit(1);
|
|
70
72
|
})))).pipe(Command.withDescription("Update sessions.ended_at + end_reason"));
|
|
71
73
|
const artifactKindOpt = Flag.Literals("artifact-kind", [
|
|
@@ -81,7 +83,7 @@ const testCaseIdOpt = Flag.optional(Flag.Int("test-case-id"));
|
|
|
81
83
|
const testRunIdOpt = Flag.optional(Flag.Int("test-run-id"));
|
|
82
84
|
const testFirstFailureRunIdOpt = Flag.optional(Flag.Int("test-first-failure-run-id"));
|
|
83
85
|
const diffExcerptOpt = Flag.optional(Flag.String("diff-excerpt"));
|
|
84
|
-
const recordedAtOpt = Flag.String("recorded-at").pipe(Flag.withDefault(
|
|
86
|
+
const recordedAtOpt = Flag.String("recorded-at").pipe(Flag.withDefault(nowIso));
|
|
85
87
|
const chatIdOptional = Flag.optional(Flag.String("chat-id")).pipe(Flag.withDescription("Host chat id; omit when --tdd-task-id is supplied instead"));
|
|
86
88
|
const tddTaskIdOpt = Flag.optional(Flag.Int("tdd-task-id")).pipe(Flag.withDescription("Explicit TDD task id escape hatch (issue #144): bypasses chat-id -> session -> task resolution entirely"));
|
|
87
89
|
const suiteOpt = Flag.Literals("suite", ["vitest", "bats"]).pipe(Flag.withDefault("vitest"), Flag.withDescription("Explicit test-runner marker (issue #363): 'vitest' (default) or 'bats'. Distinguishes a bats run-level artifact (no test_case_id) from a vitest one for the D2 phase-transition validator."));
|
|
@@ -116,7 +118,7 @@ const tddArtifactSubcommand = Command.make("tdd-artifact", {
|
|
|
116
118
|
suite: opts.suite
|
|
117
119
|
});
|
|
118
120
|
}).pipe(Effect.flatMap((result) => Effect.sync(() => process.stdout.write(`${JSON.stringify(result)}\n`))), Effect.catch((err) => Effect.sync(() => {
|
|
119
|
-
process.stderr.write(`record tdd-artifact: ${
|
|
121
|
+
process.stderr.write(`record tdd-artifact: ${Fmt.describe(err)}\n`);
|
|
120
122
|
process.exit(1);
|
|
121
123
|
})))).pipe(Command.withDescription("Record a TDD artifact (D7: CLI-only)"));
|
|
122
124
|
const testCaseTurnsSubcommand = Command.make("test-case-turns", { chatId }, ({ chatId }) => Effect.gen(function* () {
|
|
@@ -129,7 +131,7 @@ const testCaseTurnsSubcommand = Command.make("test-case-turns", { chatId }, ({ c
|
|
|
129
131
|
latestTestCaseId: Option.getOrNull(latestId)
|
|
130
132
|
};
|
|
131
133
|
}).pipe(Effect.flatMap((result) => Effect.sync(() => process.stdout.write(`${JSON.stringify(result)}\n`))), Effect.catch((err) => Effect.sync(() => {
|
|
132
|
-
process.stderr.write(`record test-case-turns: ${
|
|
134
|
+
process.stderr.write(`record test-case-turns: ${Fmt.describe(err)}\n`);
|
|
133
135
|
process.exit(1);
|
|
134
136
|
})))).pipe(Command.withDescription("Backfill test_cases.created_turn_id from file_edits in the current session (BUG-2 fix)"));
|
|
135
137
|
const invocationMethodOpt = Flag.Literals("invocation-method", [
|
|
@@ -146,7 +148,7 @@ const runTriggerSubcommand = Command.make("run-trigger", {
|
|
|
146
148
|
invocationMethod
|
|
147
149
|
});
|
|
148
150
|
}).pipe(Effect.catch((err) => Effect.sync(() => {
|
|
149
|
-
process.stderr.write(`record run-trigger: ${
|
|
151
|
+
process.stderr.write(`record run-trigger: ${Fmt.describe(err)}\n`);
|
|
150
152
|
process.exit(1);
|
|
151
153
|
})))).pipe(Command.withDescription("Associate the latest test run with the current Claude Code session"));
|
|
152
154
|
const shaOpt = Flag.String("sha");
|
|
@@ -169,7 +171,7 @@ const runWorkspaceChangesSubcommand = Command.make("run-workspace-changes", {
|
|
|
169
171
|
}, (opts) => Effect.gen(function* () {
|
|
170
172
|
const parsed = yield* Effect.try({
|
|
171
173
|
try: () => JSON.parse(opts.files),
|
|
172
|
-
catch: (e) => /* @__PURE__ */ new Error(`Invalid files-json: ${
|
|
174
|
+
catch: (e) => /* @__PURE__ */ new Error(`Invalid files-json: ${Fmt.describe(e)}`)
|
|
173
175
|
});
|
|
174
176
|
return yield* recordRunWorkspaceChangesEffect({
|
|
175
177
|
sha: opts.sha,
|
|
@@ -182,7 +184,7 @@ const runWorkspaceChangesSubcommand = Command.make("run-workspace-changes", {
|
|
|
182
184
|
files: parsed
|
|
183
185
|
});
|
|
184
186
|
}).pipe(Effect.flatMap((result) => Effect.sync(() => process.stdout.write(`${JSON.stringify(result)}\n`))), Effect.catch((err) => Effect.sync(() => {
|
|
185
|
-
process.stderr.write(`record run-workspace-changes: ${
|
|
187
|
+
process.stderr.write(`record run-workspace-changes: ${Fmt.describe(err)}\n`);
|
|
186
188
|
process.exit(1);
|
|
187
189
|
})))).pipe(Command.withDescription("Record a commit + its changed files (driven by post-commit hook)"));
|
|
188
190
|
const recordCommand = Command.make("record").pipe(Command.withSubcommands([
|
package/lib/format-db-query.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Fmt } from "@effected/cli";
|
|
2
|
+
|
|
1
3
|
// src/lib/format-db-query.ts
|
|
2
4
|
const renderCell = (value) => {
|
|
3
5
|
if (value === null || value === void 0) return "NULL";
|
|
@@ -8,7 +10,8 @@ const renderCell = (value) => {
|
|
|
8
10
|
* Render query rows as whitespace-padded tabular text or a JSON array.
|
|
9
11
|
*
|
|
10
12
|
* Table format: column headers in the first line, one row per line,
|
|
11
|
-
* each cell padded to its column's widest value
|
|
13
|
+
* each cell padded to its column's widest value, measured in terminal
|
|
14
|
+
* columns (`Fmt.width`: a wide character counts two). An empty result set
|
|
12
15
|
* renders as `(0 rows)`. JSON format emits a single array of row
|
|
13
16
|
* objects keyed by column name; an empty result set is `[]`.
|
|
14
17
|
*/
|
|
@@ -17,8 +20,8 @@ const formatDbQuery = (rows, format) => {
|
|
|
17
20
|
if (rows.length === 0) return "(0 rows)";
|
|
18
21
|
const columns = Object.keys(rows[0]);
|
|
19
22
|
const cells = rows.map((row) => columns.map((col) => renderCell(row[col])));
|
|
20
|
-
const widths = columns.map((col, i) => Math.max(col
|
|
21
|
-
const renderLine = (values) => values.map((value, i) =>
|
|
23
|
+
const widths = columns.map((col, i) => Math.max(Fmt.width(col), ...cells.map((row) => Fmt.width(row[i]))));
|
|
24
|
+
const renderLine = (values) => values.map((value, i) => Fmt.pad(value, widths[i])).join(" ").trimEnd();
|
|
22
25
|
return [renderLine(columns), ...cells.map(renderLine)].join("\n");
|
|
23
26
|
};
|
|
24
27
|
|
package/lib/version-formatter.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { distributionSuffix } from "@effected/engine";
|
|
2
|
-
|
|
3
1
|
// src/lib/version-formatter.ts
|
|
4
2
|
/**
|
|
5
|
-
* The `CliOutput.Formatter`
|
|
3
|
+
* The `CliOutput.Formatter` method `main.ts` replaces through
|
|
6
4
|
* `CliRuntime.main`'s `env.formatter`: only `formatVersion`, so `--version`
|
|
7
|
-
* prints `vitest-agent <cli version>`
|
|
8
|
-
*
|
|
5
|
+
* prints `vitest-agent <cli version>` (core's default formatter writes
|
|
6
|
+
* `<name> v<version>`, and the published output has no `v`).
|
|
7
|
+
*
|
|
8
|
+
* The carrier's ` via <name> <version>` is not added here: `CliRuntime.main`'s
|
|
9
|
+
* `distribution` option wraps whichever `formatVersion` is in effect, this
|
|
10
|
+
* one included, and provides `CurrentDistribution` alongside.
|
|
9
11
|
*
|
|
10
12
|
* `env.formatter` is the kit's one way to keep a formatter method of our own:
|
|
11
13
|
* `main` installs its coloured default formatter inside the platform, which
|
|
@@ -13,15 +15,8 @@ import { distributionSuffix } from "@effected/engine";
|
|
|
13
15
|
* kit's coloured default, and `helpOnUsageError: "stderr"` still wraps the
|
|
14
16
|
* result, so usage-error help keeps going to stderr.
|
|
15
17
|
*
|
|
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.
|
|
19
|
-
*
|
|
20
18
|
* @internal
|
|
21
19
|
*/
|
|
22
|
-
const
|
|
23
|
-
const suffix = distributionSuffix(distribution);
|
|
24
|
-
return { formatVersion: (name, version) => `${name} ${version}${suffix}` };
|
|
25
|
-
};
|
|
20
|
+
const plainVersionFormatter = { formatVersion: (name, version) => `${name} ${version}` };
|
|
26
21
|
|
|
27
|
-
export {
|
|
22
|
+
export { plainVersionFormatter };
|
package/main.d.ts
CHANGED
|
@@ -23,9 +23,10 @@ export interface MainOptions {
|
|
|
23
23
|
* `@effected/env` services (`Audience` with the `VITEST_AGENT_AUDIENCE`
|
|
24
24
|
* override, `TerminalEnv`, `CliTheme`, `CliInteractive`, the gated `Terminal`)
|
|
25
25
|
* plus the kit's colour-decided help formatter, inside failure reporting.
|
|
26
|
-
* `env.formatter` replaces only that formatter's `formatVersion
|
|
27
|
-
*
|
|
28
|
-
* `
|
|
26
|
+
* `env.formatter` replaces only that formatter's `formatVersion` (no `v`
|
|
27
|
+
* before the version), and `CliRuntime.main`'s `distribution` option wraps
|
|
28
|
+
* it, so `--version` names the carrier (`via @vitest-agent/plugin <version>`)
|
|
29
|
+
* when `options.distribution` is given; the kit provides the same value as
|
|
29
30
|
* `CurrentDistribution`. An audience flag recomputes `CliInteractive` from the
|
|
30
31
|
* TTY facts, so `--human` in an agent-detected shell (Claude Code's terminal)
|
|
31
32
|
* at a real terminal may prompt.
|
package/main.js
CHANGED
|
@@ -4,14 +4,12 @@ import { agentCommand } from "./commands/agent.js";
|
|
|
4
4
|
import { dbCommand } from "./commands/db.js";
|
|
5
5
|
import { doctorCommand } from "./commands/doctor.js";
|
|
6
6
|
import { renderFailure } from "./lib/render-failure.js";
|
|
7
|
-
import {
|
|
8
|
-
import { isAbsolute, relative } from "node:path";
|
|
7
|
+
import { plainVersionFormatter } from "./lib/version-formatter.js";
|
|
9
8
|
import * as NodeRuntime from "@effect/platform-node/NodeRuntime";
|
|
10
9
|
import * as NodeServices from "@effect/platform-node/NodeServices";
|
|
11
10
|
import { CliAudience, CliRuntime } from "@effected/cli";
|
|
12
|
-
import { CurrentDistribution } from "@effected/engine";
|
|
13
11
|
import { PathResolutionLive, resolveProjectDir } from "@vitest-agent/engine";
|
|
14
|
-
import {
|
|
12
|
+
import { Layer } from "effect";
|
|
15
13
|
import { Command } from "effect/cli";
|
|
16
14
|
|
|
17
15
|
// src/main.ts
|
|
@@ -52,9 +50,10 @@ const rootCommand = Command.make("vitest-agent").pipe(Command.withSharedFlags(Cl
|
|
|
52
50
|
* `@effected/env` services (`Audience` with the `VITEST_AGENT_AUDIENCE`
|
|
53
51
|
* override, `TerminalEnv`, `CliTheme`, `CliInteractive`, the gated `Terminal`)
|
|
54
52
|
* plus the kit's colour-decided help formatter, inside failure reporting.
|
|
55
|
-
* `env.formatter` replaces only that formatter's `formatVersion
|
|
56
|
-
*
|
|
57
|
-
* `
|
|
53
|
+
* `env.formatter` replaces only that formatter's `formatVersion` (no `v`
|
|
54
|
+
* before the version), and `CliRuntime.main`'s `distribution` option wraps
|
|
55
|
+
* it, so `--version` names the carrier (`via @vitest-agent/plugin <version>`)
|
|
56
|
+
* when `options.distribution` is given; the kit provides the same value as
|
|
58
57
|
* `CurrentDistribution`. An audience flag recomputes `CliInteractive` from the
|
|
59
58
|
* TTY facts, so `--human` in an agent-detected shell (Claude Code's terminal)
|
|
60
59
|
* at a real terminal may prompt.
|
|
@@ -102,19 +101,15 @@ const main = (options = {}) => {
|
|
|
102
101
|
dir: projectDir,
|
|
103
102
|
env
|
|
104
103
|
}), PathResolutionLive(projectDir)).pipe(Layer.provideMerge(NodeServices.layer));
|
|
105
|
-
const distribution = Option.fromNullishOr(options.distribution);
|
|
106
|
-
const displayPath = (absolute) => {
|
|
107
|
-
const rel = relative(projectDir, absolute);
|
|
108
|
-
return rel === "" || rel.startsWith("..") || isAbsolute(rel) ? absolute : rel;
|
|
109
|
-
};
|
|
110
104
|
const program = CliRuntime.main(CliAudience.run(rootCommand, { version: CURRENT_CLI_VERSION }), {
|
|
111
105
|
platform,
|
|
112
106
|
render: renderFailure,
|
|
113
107
|
helpOnUsageError: "stderr",
|
|
108
|
+
...options.distribution !== void 0 ? { distribution: options.distribution } : {},
|
|
114
109
|
env: {
|
|
115
110
|
audienceEnvVar: AUDIENCE_ENV_VAR,
|
|
116
|
-
formatter:
|
|
117
|
-
displayPath,
|
|
111
|
+
formatter: plainVersionFormatter,
|
|
112
|
+
displayPath: { relativeTo: projectDir },
|
|
118
113
|
log: {
|
|
119
114
|
envVar: "VITEST_REPORTER_LOG_LEVEL",
|
|
120
115
|
format: "auto",
|
|
@@ -122,7 +117,7 @@ const main = (options = {}) => {
|
|
|
122
117
|
file: { envVar: "VITEST_REPORTER_LOG_FILE" }
|
|
123
118
|
}
|
|
124
119
|
}
|
|
125
|
-
})
|
|
120
|
+
});
|
|
126
121
|
NodeRuntime.runMain(program);
|
|
127
122
|
};
|
|
128
123
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vitest-agent/cli",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.4",
|
|
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": [
|
|
@@ -45,16 +45,16 @@
|
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"@effect/platform-node": "^4.0.6",
|
|
47
47
|
"@effect/sql-sqlite-node": "^4.0.6",
|
|
48
|
-
"@effected/cli": "^0.
|
|
49
|
-
"@effected/config-file": "^0.
|
|
50
|
-
"@effected/engine": "^0.
|
|
51
|
-
"@effected/env": "^0.
|
|
52
|
-
"@effected/glob": "^0.
|
|
53
|
-
"@effected/walker": "^0.
|
|
54
|
-
"@effected/workspaces": "^0.39.
|
|
55
|
-
"@vitest-agent/engine": "
|
|
56
|
-
"@vitest-agent/sdk": "
|
|
57
|
-
"@vitest-agent/sidecar": "2.2.
|
|
48
|
+
"@effected/cli": "^0.23.0",
|
|
49
|
+
"@effected/config-file": "^0.21.0",
|
|
50
|
+
"@effected/engine": "^0.9.0",
|
|
51
|
+
"@effected/env": "^0.6.0",
|
|
52
|
+
"@effected/glob": "^0.15.0",
|
|
53
|
+
"@effected/walker": "^0.21.0",
|
|
54
|
+
"@effected/workspaces": "^0.39.1",
|
|
55
|
+
"@vitest-agent/engine": "3.0.0",
|
|
56
|
+
"@vitest-agent/sdk": "9.0.0",
|
|
57
|
+
"@vitest-agent/sidecar": "2.2.15",
|
|
58
58
|
"effect": "^4.0.6"
|
|
59
59
|
},
|
|
60
60
|
"engines": {
|