@vitest-agent/cli 1.0.7 → 2.0.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.
@@ -3,10 +3,11 @@ import { CliLive } from "../layers/CliLive.js";
3
3
  import { agentCommand } from "../commands/agent.js";
4
4
  import { dbCommand } from "../commands/db.js";
5
5
  import { doctorCommand } from "../commands/doctor.js";
6
- import { NodeContext, NodeRuntime } from "@effect/platform-node";
6
+ import * as NodeServices from "@effect/platform-node/NodeServices";
7
7
  import { PathResolutionLive, formatFatalError, resolveDataPath, resolveLogFile, resolveLogLevel } from "@vitest-agent/sdk";
8
8
  import { Cause, Console, Effect } from "effect";
9
- import { Command } from "@effect/cli";
9
+ import * as NodeRuntime from "@effect/platform-node/NodeRuntime";
10
+ import { Command } from "effect/unstable/cli";
10
11
 
11
12
  //#region src/bin.ts
12
13
  /**
@@ -19,15 +20,12 @@ const rootCommand = Command.make("vitest-agent").pipe(Command.withSubcommands([
19
20
  doctorCommand,
20
21
  agentCommand
21
22
  ]));
22
- const cli = Command.run(rootCommand, {
23
- name: "vitest-agent",
24
- version: "0.0.0"
25
- });
23
+ const cli = Command.run(rootCommand, { version: "0.0.0" });
26
24
  const logLevel = resolveLogLevel();
27
25
  const logFile = resolveLogFile();
28
26
  const projectDir = process.env.VITEST_AGENT_PROJECT_DIR ?? process.cwd();
29
- const main = resolveDataPath(projectDir).pipe(Effect.flatMap((dbPath) => Effect.suspend(() => cli(process.argv)).pipe(Effect.provide(CliLive(dbPath, logLevel, logFile)))), Effect.provide(PathResolutionLive(projectDir)), Effect.provide(NodeContext.layer), Effect.catchAllCause((cause) => {
30
- if (Cause.defects(cause).length > 0) return Console.error(`vitest-agent: ${formatFatalError(cause)}`).pipe(Effect.andThen(Effect.failCause(cause)));
27
+ const main = resolveDataPath(projectDir).pipe(Effect.flatMap((dbPath) => cli.pipe(Effect.provide(CliLive(dbPath, logLevel, logFile)))), Effect.provide(PathResolutionLive(projectDir)), Effect.provide(NodeServices.layer), Effect.catchCause((cause) => {
28
+ if (cause.reasons.filter(Cause.isDieReason).length > 0) return Console.error(`vitest-agent: ${formatFatalError(cause)}`).pipe(Effect.andThen(Effect.failCause(cause)));
31
29
  return Effect.failCause(cause);
32
30
  }));
33
31
  NodeRuntime.runMain(main);
package/commands/agent.js CHANGED
@@ -5,11 +5,11 @@ import { endAgentEffect } from "../lib/internal-end-agent.js";
5
5
  import { recordCommand } from "./record.js";
6
6
  import { triageCommand } from "./triage.js";
7
7
  import { wrapupCommand } from "./wrapup.js";
8
- import { NodeContext } from "@effect/platform-node";
8
+ import * as NodeServices from "@effect/platform-node/NodeServices";
9
9
  import { resolveProjectKeyFromCwd } from "@vitest-agent/sdk";
10
- import { Cause, Chunk, Effect, Option } from "effect";
10
+ import { Cause, Effect, Option } from "effect";
11
11
  import { join } from "node:path";
12
- import { Command, Options } from "@effect/cli";
12
+ import { Command, Flag } from "effect/unstable/cli";
13
13
  import { exitCodeForTag, injectEnv } from "@vitest-agent/sdk/dispatch";
14
14
  import { resolveSidecarBinaryPath } from "@vitest-agent/sidecar";
15
15
 
@@ -46,26 +46,27 @@ const writeStderrAndExit = (exitCode, tag, message) => Effect.sync(() => {
46
46
  process.exit(exitCode);
47
47
  });
48
48
  const mapDefectToExit = (cause) => {
49
- const failures = Chunk.toReadonlyArray(Cause.failures(cause));
49
+ const failures = cause.reasons.filter(Cause.isFailReason);
50
50
  if (failures.length > 0) {
51
- const tagged = failures[0];
51
+ const error = failures[0].error;
52
+ const tagged = error;
52
53
  const tag = tagged._tag ?? "UnknownError";
53
- const message = tagged.reason ?? tagged.message ?? String(failures[0]);
54
+ const message = tagged.reason ?? tagged.message ?? String(error);
54
55
  const exitCode = exitCodeForTag(tag);
55
56
  return writeStderrAndExit(exitCode, tag, message);
56
57
  }
57
- const defect = Chunk.toReadonlyArray(Cause.defects(cause))[0];
58
+ const defect = cause.reasons.filter(Cause.isDieReason)[0]?.defect;
58
59
  const message = defect instanceof Error ? defect.message : String(defect ?? "unknown defect");
59
60
  return writeStderrAndExit(5, "Defect", message);
60
61
  };
61
- const hostKindOpt = Options.text("host-kind").pipe(Options.withDescription("Host vendor identifier; e.g. 'claude-code', 'cursor', 'goose'"));
62
- const agentTypeOpt = Options.text("agent-type").pipe(Options.withDescription("Agent type, must begin with the host-kind prefix"));
63
- const hostSessionIdOpt = Options.text("host-session-id").pipe(Options.withDescription("Host's native session id (host chat UUID; `session_id` in the CC hook payload)"));
64
- const transcriptPathOpt = Options.text("transcript-path").pipe(Options.withDescription("Path to the host's transcript file (basename UUID is the conversation key)"));
65
- const cwdOpt = Options.text("cwd").pipe(Options.withDescription("Workspace root directory the agent is running in"));
66
- const parentAgentIdOpt = Options.optional(Options.text("parent-agent-id"));
67
- const clientNonceOpt = Options.optional(Options.text("client-nonce"));
68
- const projectKeyOverrideOpt = Options.optional(Options.text("project-key"));
62
+ const hostKindOpt = Flag.string("host-kind").pipe(Flag.withDescription("Host vendor identifier; e.g. 'claude-code', 'cursor', 'goose'"));
63
+ const agentTypeOpt = Flag.string("agent-type").pipe(Flag.withDescription("Agent type, must begin with the host-kind prefix"));
64
+ const hostSessionIdOpt = Flag.string("host-session-id").pipe(Flag.withDescription("Host's native session id (host chat UUID; `session_id` in the CC hook payload)"));
65
+ const transcriptPathOpt = Flag.string("transcript-path").pipe(Flag.withDescription("Path to the host's transcript file (basename UUID is the conversation key)"));
66
+ const cwdOpt = Flag.string("cwd").pipe(Flag.withDescription("Workspace root directory the agent is running in"));
67
+ const parentAgentIdOpt = Flag.optional(Flag.string("parent-agent-id"));
68
+ const clientNonceOpt = Flag.optional(Flag.string("client-nonce"));
69
+ const projectKeyOverrideOpt = Flag.optional(Flag.string("project-key"));
69
70
  const registerAgentSubcommand = Command.make("register-agent", {
70
71
  hostKind: hostKindOpt,
71
72
  agentType: agentTypeOpt,
@@ -81,7 +82,7 @@ const registerAgentSubcommand = Command.make("register-agent", {
81
82
  const registryDbPath = join(resolveRegistryDir(), REGISTRY_DB_FILENAME);
82
83
  const sidecar = SidecarLive({
83
84
  perProjectDbPath,
84
- sessionMapDbPath: yield* resolveSessionMapPath().pipe(Effect.catchAllCause(mapDefectToExit)),
85
+ sessionMapDbPath: yield* resolveSessionMapPath().pipe(Effect.catchCause(mapDefectToExit)),
85
86
  registryDbPath
86
87
  });
87
88
  const result = yield* registerAgentEffect({
@@ -93,7 +94,7 @@ const registerAgentSubcommand = Command.make("register-agent", {
93
94
  projectKey,
94
95
  ...Option.isSome(opts.parentAgentId) && { parentAgentId: opts.parentAgentId.value },
95
96
  ...Option.isSome(opts.clientNonce) && { clientNonce: opts.clientNonce.value }
96
- }).pipe(Effect.provide(sidecar), Effect.catchAllCause(mapDefectToExit));
97
+ }).pipe(Effect.provide(sidecar), Effect.catchCause(mapDefectToExit));
97
98
  yield* writeStdout(JSON.stringify({
98
99
  agentId: result.agentId,
99
100
  conversationId: result.conversationId,
@@ -101,12 +102,12 @@ const registerAgentSubcommand = Command.make("register-agent", {
101
102
  idempotencyKey: result.idempotencyKey,
102
103
  idempotencyHit: result.idempotencyHit
103
104
  }));
104
- }).pipe(Effect.provide(NodeContext.layer))).pipe(Command.withDescription("Register an agent invocation in the per-project store and the per-client session map"));
105
- const agentIdOpt = Options.text("agent-id").pipe(Options.withDescription("The agent_id (UUID) returned by an earlier register-agent call"));
106
- const endedAtOpt = Options.optional(Options.integer("ended-at"));
107
- const endHostSessionIdOpt = Options.optional(Options.text("host-session-id"));
108
- const endCwdOpt = Options.text("cwd").pipe(Options.withDefault(process.cwd()), Options.withDescription("Workspace root, used to locate the per-project data.db"));
109
- const endProjectKeyOverrideOpt = Options.optional(Options.text("project-key"));
105
+ }).pipe(Effect.provide(NodeServices.layer))).pipe(Command.withDescription("Register an agent invocation in the per-project store and the per-client session map"));
106
+ const agentIdOpt = Flag.string("agent-id").pipe(Flag.withDescription("The agent_id (UUID) returned by an earlier register-agent call"));
107
+ const endedAtOpt = Flag.optional(Flag.integer("ended-at"));
108
+ const endHostSessionIdOpt = Flag.optional(Flag.string("host-session-id"));
109
+ const endCwdOpt = Flag.string("cwd").pipe(Flag.withDefault(process.cwd()), Flag.withDescription("Workspace root, used to locate the per-project data.db"));
110
+ const endProjectKeyOverrideOpt = Flag.optional(Flag.string("project-key"));
110
111
  const endAgentSubcommand = Command.make("end-agent", {
111
112
  agentId: agentIdOpt,
112
113
  endedAt: endedAtOpt,
@@ -118,7 +119,7 @@ const endAgentSubcommand = Command.make("end-agent", {
118
119
  const registryDbPath = join(resolveRegistryDir(), REGISTRY_DB_FILENAME);
119
120
  const sidecar = SidecarLive({
120
121
  perProjectDbPath,
121
- sessionMapDbPath: yield* resolveSessionMapPath().pipe(Effect.catchAllCause(mapDefectToExit)),
122
+ sessionMapDbPath: yield* resolveSessionMapPath().pipe(Effect.catchCause(mapDefectToExit)),
122
123
  registryDbPath
123
124
  });
124
125
  const endedAt = Option.isSome(opts.endedAt) ? opts.endedAt.value : Math.floor(Date.now() / 1e3);
@@ -126,10 +127,10 @@ const endAgentSubcommand = Command.make("end-agent", {
126
127
  agentId: opts.agentId,
127
128
  endedAt,
128
129
  ...Option.isSome(opts.hostSessionId) && { hostSessionId: opts.hostSessionId.value }
129
- }).pipe(Effect.provide(sidecar), Effect.catchAllCause(mapDefectToExit));
130
- }).pipe(Effect.provide(NodeContext.layer))).pipe(Command.withDescription("Mark an agent (and optionally its session) as ended"));
131
- const commandOpt = Options.text("command").pipe(Options.withDescription("The Bash command to (possibly) rewrite with VITEST_AGENT_* env-prefix"));
132
- const cwdInjectOpt = Options.text("cwd").pipe(Options.withDefault(process.cwd()), Options.withDescription("Working directory; used to find package.json scripts"));
130
+ }).pipe(Effect.provide(sidecar), Effect.catchCause(mapDefectToExit));
131
+ }).pipe(Effect.provide(NodeServices.layer))).pipe(Command.withDescription("Mark an agent (and optionally its session) as ended"));
132
+ const commandOpt = Flag.string("command").pipe(Flag.withDescription("The Bash command to (possibly) rewrite with VITEST_AGENT_* env-prefix"));
133
+ const cwdInjectOpt = Flag.string("cwd").pipe(Flag.withDefault(process.cwd()), Flag.withDescription("Working directory; used to find package.json scripts"));
133
134
  const injectEnvSubcommand = Command.make("inject-env", {
134
135
  command: commandOpt,
135
136
  cwd: cwdInjectOpt
package/commands/db.js CHANGED
@@ -1,12 +1,11 @@
1
1
  import { formatDbQuery } from "../lib/format-db-query.js";
2
- import { NodeContext } from "@effect/platform-node";
2
+ import * as NodeServices from "@effect/platform-node/NodeServices";
3
3
  import { layer } from "@effect/sql-sqlite-node/SqliteClient";
4
4
  import { DataStore, resolveDataPath } from "@vitest-agent/sdk";
5
- import { Effect } from "effect";
6
- import { Args, Command, Options } from "@effect/cli";
7
- import { SqlClient } from "@effect/sql/SqlClient";
5
+ import { Effect, FileSystem } from "effect";
6
+ import { Argument, Command, Flag } from "effect/unstable/cli";
7
+ import { SqlClient } from "effect/unstable/sql/SqlClient";
8
8
  import * as readline from "node:readline";
9
- import { FileSystem } from "@effect/platform";
10
9
 
11
10
  //#region src/commands/db.ts
12
11
  /**
@@ -18,12 +17,12 @@ const pathCommand = Command.make("path", {}, () => Effect.gen(function* () {
18
17
  const dbPath = yield* resolveDataPath(process.env.VITEST_AGENT_PROJECT_DIR ?? process.cwd());
19
18
  yield* Effect.sync(() => process.stdout.write(`${dbPath}\n`));
20
19
  })).pipe(Command.withDescription("Print the resolved database path"));
21
- const keepRecentOption = Options.withDefault(Options.integer("keep-recent"), 30).pipe(Options.withDescription("Number of most-recent sessions to keep in full"));
20
+ const keepRecentOption = Flag.withDefault(Flag.integer("keep-recent"), 30).pipe(Flag.withDescription("Number of most-recent sessions to keep in full"));
22
21
  const pruneCommand = Command.make("prune", { keepRecent: keepRecentOption }, ({ keepRecent }) => Effect.gen(function* () {
23
22
  const result = yield* (yield* DataStore).pruneSessions(keepRecent);
24
23
  yield* Effect.sync(() => process.stdout.write(`Pruned ${result.prunedTurns} turn row(s) across ${result.affectedSessions} session(s); session rows retained.\n`));
25
24
  })).pipe(Command.withDescription("Drop old sessions' turn history (W1 retention; keeps the last N in full)"));
26
- const yesOption = Options.boolean("yes").pipe(Options.withDefault(false), Options.withDescription("Skip the interactive confirmation prompt"));
25
+ const yesOption = Flag.boolean("yes").pipe(Flag.withDefault(false), Flag.withDescription("Skip the interactive confirmation prompt"));
27
26
  const resetCommand = Command.make("reset", { yes: yesOption }, ({ yes }) => Effect.gen(function* () {
28
27
  const agentId = process.env.VITEST_AGENT_AGENT_ID;
29
28
  if (agentId !== void 0 && agentId.length > 0) {
@@ -62,15 +61,15 @@ const resetCommand = Command.make("reset", { yes: yesOption }, ({ yes }) => Effe
62
61
  }
63
62
  }
64
63
  const fs = yield* FileSystem.FileSystem;
65
- yield* fs.remove(dbPath).pipe(Effect.catchAll(() => Effect.void));
66
- yield* fs.remove(`${dbPath}-shm`).pipe(Effect.catchAll(() => Effect.void));
67
- yield* fs.remove(`${dbPath}-wal`).pipe(Effect.catchAll(() => Effect.void));
64
+ yield* fs.remove(dbPath).pipe(Effect.catch(() => Effect.void));
65
+ yield* fs.remove(`${dbPath}-shm`).pipe(Effect.catch(() => Effect.void));
66
+ yield* fs.remove(`${dbPath}-wal`).pipe(Effect.catch(() => Effect.void));
68
67
  yield* Effect.sync(() => {
69
68
  process.stdout.write(`Deleted database at ${dbPath}\n`);
70
69
  });
71
- }).pipe(Effect.provide(NodeContext.layer))).pipe(Command.withDescription("Wipe the database (human-only; blocked in agent contexts)"));
72
- const queryFormatOption = Options.choice("format", ["table", "json"]).pipe(Options.withDefault("table"), Options.withDescription("Output format for query results"));
73
- const sqlArg = Args.text({ name: "sql" }).pipe(Args.withDescription("Read-only SQL statement to execute against data.db"));
70
+ }).pipe(Effect.provide(NodeServices.layer))).pipe(Command.withDescription("Wipe the database (human-only; blocked in agent contexts)"));
71
+ const queryFormatOption = Flag.choice("format", ["table", "json"]).pipe(Flag.withDefault("table"), Flag.withDescription("Output format for query results"));
72
+ const sqlArg = Argument.string("sql").pipe(Argument.withDescription("Read-only SQL statement to execute against data.db"));
74
73
  /**
75
74
  * Flatten an error and its cause chain into a single message so the
76
75
  * driver's `attempt to write a readonly database` text surfaces to
@@ -78,13 +77,15 @@ const sqlArg = Args.text({ name: "sql" }).pipe(Args.withDescription("Read-only S
78
77
  */
79
78
  const describeError = (error) => {
80
79
  if (!(error instanceof Error)) return String(error);
81
- const parts = [error.message];
82
- let cause = error.cause;
83
- while (cause instanceof Error && !parts.includes(cause.message)) {
84
- parts.push(cause.message);
85
- cause = cause.cause;
80
+ const parts = [];
81
+ const seen = /* @__PURE__ */ new Set();
82
+ let current = error;
83
+ while (current instanceof Error && !seen.has(current)) {
84
+ seen.add(current);
85
+ if (current.message.length > 0 && !parts.includes(current.message)) parts.push(current.message);
86
+ current = current.cause;
86
87
  }
87
- return parts.filter((part) => part.length > 0).join(": ");
88
+ return parts.join(": ");
88
89
  };
89
90
  const queryCommand = Command.make("query", {
90
91
  sql: sqlArg,
@@ -106,7 +107,7 @@ const queryCommand = Command.make("query", {
106
107
  }).pipe(Effect.provide(layer({
107
108
  filename: dbPath,
108
109
  readonly: true
109
- })), Effect.catchAll((error) => Effect.sync(() => {
110
+ })), Effect.catch((error) => Effect.sync(() => {
110
111
  process.stderr.write(`db query: ${describeError(error)}\n`);
111
112
  process.exit(3);
112
113
  })));
@@ -1,7 +1,7 @@
1
1
  import { formatDoctor } from "../lib/format-doctor.js";
2
2
  import { DataReader, resolveDataPath } from "@vitest-agent/sdk";
3
3
  import { Effect, Option } from "effect";
4
- import { Command, Options } from "@effect/cli";
4
+ import { Command, Flag } from "effect/unstable/cli";
5
5
 
6
6
  //#region src/commands/doctor.ts
7
7
  /**
@@ -9,7 +9,7 @@ import { Command, Options } from "@effect/cli";
9
9
  *
10
10
  * @packageDocumentation
11
11
  */
12
- const formatOption = Options.withDefault(Options.choice("format", ["markdown", "json"]), "markdown");
12
+ const formatOption = Flag.withDefault(Flag.choice("format", ["markdown", "json"]), "markdown");
13
13
  const writeOutput = (results, format) => Effect.sync(() => {
14
14
  if (format === "json") process.stdout.write(`${JSON.stringify(results, null, 2)}\n`);
15
15
  else process.stdout.write(`${formatDoctor(results)}\n`);
@@ -23,7 +23,7 @@ const doctorCommand = Command.make("doctor", { format: formatOption }, ({ format
23
23
  passed: true,
24
24
  detail: `\`${dbPath}\``
25
25
  });
26
- const manifestOpt = yield* reader.getManifest().pipe(Effect.catchAll(() => Effect.succeed(Option.none())));
26
+ const manifestOpt = yield* reader.getManifest().pipe(Effect.catch(() => Effect.succeed(Option.none())));
27
27
  if (Option.isNone(manifestOpt)) {
28
28
  results.push({
29
29
  name: "Manifest",
@@ -44,7 +44,7 @@ const doctorCommand = Command.make("doctor", { format: formatOption }, ({ format
44
44
  const reportIssues = [];
45
45
  for (const entry of manifest.projects) {
46
46
  const project = entry.project;
47
- const reportOpt = yield* reader.getLatestRun(project).pipe(Effect.catchAll(() => Effect.succeed(Option.none())));
47
+ const reportOpt = yield* reader.getLatestRun(project).pipe(Effect.catch(() => Effect.succeed(Option.none())));
48
48
  if (Option.isNone(reportOpt)) reportIssues.push(`\`${entry.project}\` no report data`);
49
49
  else validReports++;
50
50
  }
@@ -68,7 +68,7 @@ const doctorCommand = Command.make("doctor", { format: formatOption }, ({ format
68
68
  if (!(yield* reader.getHistory(project).pipe(Effect.map((h) => ({
69
69
  ok: true,
70
70
  record: h
71
- })), Effect.catchAll(() => Effect.succeed({
71
+ })), Effect.catch(() => Effect.succeed({
72
72
  ok: false,
73
73
  record: null
74
74
  })))).ok) historyIssues.push(`\`${entry.project}\` history read error`);
@@ -4,25 +4,16 @@ import { recordTurnEffect } from "../lib/record-turn.js";
4
4
  import { recordRunWorkspaceChangesEffect } from "../lib/record-workspace-changes.js";
5
5
  import { DataReader, DataStore } from "@vitest-agent/sdk";
6
6
  import { Effect, Option } from "effect";
7
- import { Args, Command, Options } from "@effect/cli";
7
+ import { Argument, Command, Flag } from "effect/unstable/cli";
8
8
 
9
9
  //#region src/commands/record.ts
10
- /**
11
- * CLI record command -- write session/turn data to the database.
12
- *
13
- * Hook scripts in plugin/hooks/ shell out to these subcommands. The
14
- * record-turn and record-session libs (in ../lib) implement the actual
15
- * write effects; commands here are thin \@effect/cli wrappers.
16
- *
17
- * @packageDocumentation
18
- */
19
- const chatId = Options.text("chat-id").pipe(Options.withDescription("Host chat id (`session_id` in the Claude Code hook envelope; equivalent in other clients)"));
20
- const occurredAt = Options.text("occurred-at").pipe(Options.withDefault((/* @__PURE__ */ new Date()).toISOString()), Options.withDescription("ISO 8601 timestamp; defaults to now"));
21
- const payloadArg = Args.text({ name: "payload-json" }).pipe(Args.withDescription("Stringified JSON payload (validated against TurnPayload)"));
22
- const project = Options.text("project");
23
- const cwd = Options.text("cwd");
24
- const projectOptional = Options.optional(Options.text("project"));
25
- const cwdOptional = Options.optional(Options.text("cwd"));
10
+ const chatId = Flag.string("chat-id").pipe(Flag.withDescription("Host chat id (`session_id` in the Claude Code hook envelope; equivalent in other clients)"));
11
+ const occurredAt = Flag.string("occurred-at").pipe(Flag.withDefault((/* @__PURE__ */ new Date()).toISOString()), Flag.withDescription("ISO 8601 timestamp; defaults to now"));
12
+ const payloadArg = Argument.string("payload-json").pipe(Argument.withDescription("Stringified JSON payload (validated against TurnPayload)"));
13
+ const project = Flag.string("project");
14
+ const cwd = Flag.string("cwd");
15
+ const projectOptional = Flag.optional(Flag.string("project"));
16
+ const cwdOptional = Flag.optional(Flag.string("cwd"));
26
17
  const turnSubcommand = Command.make("turn", {
27
18
  chatId,
28
19
  occurredAt,
@@ -35,15 +26,15 @@ const turnSubcommand = Command.make("turn", {
35
26
  occurredAt,
36
27
  ...project._tag === "Some" && { project: project.value },
37
28
  ...cwd._tag === "Some" && { cwd: cwd.value }
38
- }).pipe(Effect.flatMap((result) => Effect.sync(() => process.stdout.write(`${JSON.stringify(result)}\n`))), Effect.catchAll((err) => Effect.sync(() => {
29
+ }).pipe(Effect.flatMap((result) => Effect.sync(() => process.stdout.write(`${JSON.stringify(result)}\n`))), Effect.catch((err) => Effect.sync(() => {
39
30
  process.stderr.write(`record turn: ${err instanceof Error ? err.message : String(err)}\n`);
40
31
  process.exit(1);
41
32
  })))).pipe(Command.withDescription("Validate a TurnPayload JSON and write a turn row"));
42
- const agentKind = Options.choice("agent-kind", ["main", "subagent"]).pipe(Options.withDefault("main"));
43
- const agentType = Options.optional(Options.text("agent-type"));
44
- const parentChatId = Options.optional(Options.text("parent-chat-id"));
45
- const triageWasNonEmpty = Options.boolean("triage-was-non-empty").pipe(Options.withDefault(false));
46
- const startedAt = Options.text("started-at").pipe(Options.withDefault((/* @__PURE__ */ new Date()).toISOString()));
33
+ const agentKind = Flag.choice("agent-kind", ["main", "subagent"]).pipe(Flag.withDefault("main"));
34
+ const agentType = Flag.optional(Flag.string("agent-type"));
35
+ const parentChatId = Flag.optional(Flag.string("parent-chat-id"));
36
+ const triageWasNonEmpty = Flag.boolean("triage-was-non-empty").pipe(Flag.withDefault(false));
37
+ const startedAt = Flag.string("started-at").pipe(Flag.withDefault((/* @__PURE__ */ new Date()).toISOString()));
47
38
  const sessionStartSubcommand = Command.make("session-start", {
48
39
  chatId,
49
40
  project,
@@ -62,12 +53,12 @@ const sessionStartSubcommand = Command.make("session-start", {
62
53
  ...opts.parentChatId._tag === "Some" && { parentChatId: opts.parentChatId.value },
63
54
  triageWasNonEmpty: opts.triageWasNonEmpty,
64
55
  startedAt: opts.startedAt
65
- }).pipe(Effect.flatMap((result) => Effect.sync(() => process.stdout.write(`${JSON.stringify(result)}\n`))), Effect.catchAll((err) => Effect.sync(() => {
56
+ }).pipe(Effect.flatMap((result) => Effect.sync(() => process.stdout.write(`${JSON.stringify(result)}\n`))), Effect.catch((err) => Effect.sync(() => {
66
57
  process.stderr.write(`record session-start: ${err instanceof Error ? err.message : String(err)}\n`);
67
58
  process.exit(1);
68
59
  })))).pipe(Command.withDescription("Insert a new sessions row"));
69
- const endedAt = Options.text("ended-at").pipe(Options.withDefault((/* @__PURE__ */ new Date()).toISOString()));
70
- const endReason = Options.optional(Options.text("end-reason"));
60
+ const endedAt = Flag.string("ended-at").pipe(Flag.withDefault((/* @__PURE__ */ new Date()).toISOString()));
61
+ const endReason = Flag.optional(Flag.string("end-reason"));
71
62
  const sessionEndSubcommand = Command.make("session-end", {
72
63
  chatId,
73
64
  endedAt,
@@ -76,11 +67,11 @@ const sessionEndSubcommand = Command.make("session-end", {
76
67
  chatId: opts.chatId,
77
68
  endedAt: opts.endedAt,
78
69
  endReason: opts.endReason._tag === "Some" ? opts.endReason.value : null
79
- }).pipe(Effect.flatMap(() => Effect.sync(() => process.stdout.write(`{"ok":true}\n`))), Effect.catchAll((err) => Effect.sync(() => {
70
+ }).pipe(Effect.flatMap(() => Effect.sync(() => process.stdout.write(`{"ok":true}\n`))), Effect.catch((err) => Effect.sync(() => {
80
71
  process.stderr.write(`record session-end: ${err instanceof Error ? err.message : String(err)}\n`);
81
72
  process.exit(1);
82
73
  })))).pipe(Command.withDescription("Update sessions.ended_at + end_reason"));
83
- const artifactKindOpt = Options.choice("artifact-kind", [
74
+ const artifactKindOpt = Flag.choice("artifact-kind", [
84
75
  "test_written",
85
76
  "test_failed_run",
86
77
  "code_written",
@@ -88,12 +79,12 @@ const artifactKindOpt = Options.choice("artifact-kind", [
88
79
  "refactor",
89
80
  "test_weakened"
90
81
  ]);
91
- const filePathOpt = Options.optional(Options.text("file-path"));
92
- const testCaseIdOpt = Options.optional(Options.integer("test-case-id"));
93
- const testRunIdOpt = Options.optional(Options.integer("test-run-id"));
94
- const testFirstFailureRunIdOpt = Options.optional(Options.integer("test-first-failure-run-id"));
95
- const diffExcerptOpt = Options.optional(Options.text("diff-excerpt"));
96
- const recordedAtOpt = Options.text("recorded-at").pipe(Options.withDefault((/* @__PURE__ */ new Date()).toISOString()));
82
+ const filePathOpt = Flag.optional(Flag.string("file-path"));
83
+ const testCaseIdOpt = Flag.optional(Flag.integer("test-case-id"));
84
+ const testRunIdOpt = Flag.optional(Flag.integer("test-run-id"));
85
+ const testFirstFailureRunIdOpt = Flag.optional(Flag.integer("test-first-failure-run-id"));
86
+ const diffExcerptOpt = Flag.optional(Flag.string("diff-excerpt"));
87
+ const recordedAtOpt = Flag.string("recorded-at").pipe(Flag.withDefault((/* @__PURE__ */ new Date()).toISOString()));
97
88
  const tddArtifactSubcommand = Command.make("tdd-artifact", {
98
89
  chatId,
99
90
  project: projectOptional,
@@ -120,7 +111,7 @@ const tddArtifactSubcommand = Command.make("tdd-artifact", {
120
111
  ...opts.diffExcerpt._tag === "Some" && { diffExcerpt: opts.diffExcerpt.value },
121
112
  recordedAt: opts.recordedAt
122
113
  });
123
- }).pipe(Effect.flatMap((result) => Effect.sync(() => process.stdout.write(`${JSON.stringify(result)}\n`))), Effect.catchAll((err) => Effect.sync(() => {
114
+ }).pipe(Effect.flatMap((result) => Effect.sync(() => process.stdout.write(`${JSON.stringify(result)}\n`))), Effect.catch((err) => Effect.sync(() => {
124
115
  process.stderr.write(`record tdd-artifact: ${err instanceof Error ? err.message : String(err)}\n`);
125
116
  process.exit(1);
126
117
  })))).pipe(Command.withDescription("Record a TDD artifact (D7: CLI-only)"));
@@ -133,15 +124,15 @@ const testCaseTurnsSubcommand = Command.make("test-case-turns", { chatId }, ({ c
133
124
  updated,
134
125
  latestTestCaseId: Option.getOrNull(latestId)
135
126
  };
136
- }).pipe(Effect.flatMap((result) => Effect.sync(() => process.stdout.write(`${JSON.stringify(result)}\n`))), Effect.catchAll((err) => Effect.sync(() => {
127
+ }).pipe(Effect.flatMap((result) => Effect.sync(() => process.stdout.write(`${JSON.stringify(result)}\n`))), Effect.catch((err) => Effect.sync(() => {
137
128
  process.stderr.write(`record test-case-turns: ${err instanceof Error ? err.message : String(err)}\n`);
138
129
  process.exit(1);
139
130
  })))).pipe(Command.withDescription("Backfill test_cases.created_turn_id from file_edits in the current session (BUG-2 fix)"));
140
- const invocationMethodOpt = Options.choice("invocation-method", [
131
+ const invocationMethodOpt = Flag.choice("invocation-method", [
141
132
  "bash",
142
133
  "mcp",
143
134
  "cli"
144
- ]).pipe(Options.withDescription("How tests were invoked: \"bash\", \"mcp\", or \"cli\""), Options.withDefault("bash"));
135
+ ]).pipe(Flag.withDescription("How tests were invoked: \"bash\", \"mcp\", or \"cli\""), Flag.withDefault("bash"));
145
136
  const runTriggerSubcommand = Command.make("run-trigger", {
146
137
  chatId,
147
138
  invocationMethod: invocationMethodOpt
@@ -150,18 +141,18 @@ const runTriggerSubcommand = Command.make("run-trigger", {
150
141
  chatId,
151
142
  invocationMethod
152
143
  });
153
- }).pipe(Effect.catchAll((err) => Effect.sync(() => {
144
+ }).pipe(Effect.catch((err) => Effect.sync(() => {
154
145
  process.stderr.write(`record run-trigger: ${err instanceof Error ? err.message : String(err)}\n`);
155
146
  process.exit(1);
156
147
  })))).pipe(Command.withDescription("Associate the latest test run with the current Claude Code session"));
157
- const shaOpt = Options.text("sha");
158
- const parentShaOpt = Options.optional(Options.text("parent-sha"));
159
- const messageOpt = Options.optional(Options.text("message"));
160
- const authorOpt = Options.optional(Options.text("author"));
161
- const committedAtOpt = Options.optional(Options.text("committed-at"));
162
- const branchOpt = Options.optional(Options.text("branch"));
163
- const projectOpt = Options.optional(Options.text("project"));
164
- const filesArg = Args.text({ name: "files-json" }).pipe(Args.withDescription("JSON array of {\"filePath\",\"changeKind\"} objects"));
148
+ const shaOpt = Flag.string("sha");
149
+ const parentShaOpt = Flag.optional(Flag.string("parent-sha"));
150
+ const messageOpt = Flag.optional(Flag.string("message"));
151
+ const authorOpt = Flag.optional(Flag.string("author"));
152
+ const committedAtOpt = Flag.optional(Flag.string("committed-at"));
153
+ const branchOpt = Flag.optional(Flag.string("branch"));
154
+ const projectOpt = Flag.optional(Flag.string("project"));
155
+ const filesArg = Argument.string("files-json").pipe(Argument.withDescription("JSON array of {\"filePath\",\"changeKind\"} objects"));
165
156
  const runWorkspaceChangesSubcommand = Command.make("run-workspace-changes", {
166
157
  sha: shaOpt,
167
158
  parentSha: parentShaOpt,
@@ -186,7 +177,7 @@ const runWorkspaceChangesSubcommand = Command.make("run-workspace-changes", {
186
177
  ...opts.project._tag === "Some" && { project: opts.project.value },
187
178
  files: parsed
188
179
  });
189
- }).pipe(Effect.flatMap((result) => Effect.sync(() => process.stdout.write(`${JSON.stringify(result)}\n`))), Effect.catchAll((err) => Effect.sync(() => {
180
+ }).pipe(Effect.flatMap((result) => Effect.sync(() => process.stdout.write(`${JSON.stringify(result)}\n`))), Effect.catch((err) => Effect.sync(() => {
190
181
  process.stderr.write(`record run-workspace-changes: ${err instanceof Error ? err.message : String(err)}\n`);
191
182
  process.exit(1);
192
183
  })))).pipe(Command.withDescription("Record a commit + its changed files (driven by post-commit hook)"));
@@ -1,6 +1,6 @@
1
1
  import { formatTriageEffect } from "@vitest-agent/sdk";
2
2
  import { Effect } from "effect";
3
- import { Command, Options } from "@effect/cli";
3
+ import { Command, Flag } from "effect/unstable/cli";
4
4
 
5
5
  //#region src/commands/triage.ts
6
6
  /**
@@ -12,13 +12,13 @@ import { Command, Options } from "@effect/cli";
12
12
  *
13
13
  * @packageDocumentation
14
14
  */
15
- const formatOption = Options.withDefault(Options.choice("format", [
15
+ const formatOption = Flag.withDefault(Flag.choice("format", [
16
16
  "markdown",
17
17
  "json",
18
18
  "silent"
19
19
  ]), "markdown");
20
- const projectOption = Options.optional(Options.text("project"));
21
- const maxLinesOption = Options.optional(Options.integer("max-lines"));
20
+ const projectOption = Flag.optional(Flag.string("project"));
21
+ const maxLinesOption = Flag.optional(Flag.integer("max-lines"));
22
22
  const triageCommand = Command.make("triage", {
23
23
  format: formatOption,
24
24
  project: projectOption,
@@ -1,6 +1,6 @@
1
1
  import { formatWrapupEffect } from "@vitest-agent/sdk";
2
2
  import { Effect } from "effect";
3
- import { Command, Options } from "@effect/cli";
3
+ import { Command, Flag } from "effect/unstable/cli";
4
4
 
5
5
  //#region src/commands/wrapup.ts
6
6
  /**
@@ -13,17 +13,17 @@ import { Command, Options } from "@effect/cli";
13
13
  *
14
14
  * @packageDocumentation
15
15
  */
16
- const rowIdOption = Options.optional(Options.integer("row-id"));
17
- const chatIdOption = Options.optional(Options.text("chat-id"));
18
- const kindOption = Options.withDefault(Options.choice("kind", [
16
+ const rowIdOption = Flag.optional(Flag.integer("row-id"));
17
+ const chatIdOption = Flag.optional(Flag.string("chat-id"));
18
+ const kindOption = Flag.withDefault(Flag.choice("kind", [
19
19
  "stop",
20
20
  "session_end",
21
21
  "pre_compact",
22
22
  "tdd_handoff",
23
23
  "user_prompt_nudge"
24
24
  ]), "session_end");
25
- const userPromptHintOption = Options.optional(Options.text("user-prompt-hint"));
26
- const formatOption = Options.withDefault(Options.choice("format", ["markdown", "json"]), "markdown");
25
+ const userPromptHintOption = Flag.optional(Flag.string("user-prompt-hint"));
26
+ const formatOption = Flag.withDefault(Flag.choice("format", ["markdown", "json"]), "markdown");
27
27
  const wrapupCommand = Command.make("wrapup", {
28
28
  rowId: rowIdOption,
29
29
  chatId: chatIdOption,
package/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import * as NodeContext from "@effect/platform-node/NodeContext";
1
+ import * as NodeServices from "@effect/platform-node/NodeServices";
2
2
  import * as SqliteMigrator from "@effect/sql-sqlite-node/SqliteMigrator";
3
3
  import { Effect, Layer, LogLevel } from "effect";
4
4
  import { DataReader, DataStore, PerClientSessionMapWriter, ProjectIdentityNotResolvableError } from "@vitest-agent/sdk";
@@ -7,8 +7,8 @@ import { DataReader, DataStore, PerClientSessionMapWriter, ProjectIdentityNotRes
7
7
  * Composition layer for the CLI runtime.
8
8
  *
9
9
  * Wires `DataReader`, `ProjectDiscovery`, `HistoryTracker`,
10
- * `OutputPipeline`, `SqliteClient`, the DB migrator, `NodeContext`,
11
- * `NodeFileSystem`, and `Logger` into a single layer the `vitest-agent`
10
+ * `OutputPipeline`, `SqliteClient`, the DB migrator, the Node platform
11
+ * services, and `Logger` into a single layer the `vitest-agent`
12
12
  * bin provides to `Command.run`.
13
13
  *
14
14
  * @param dbPath - absolute path to the per-project `data.db`
@@ -16,7 +16,7 @@ import { DataReader, DataStore, PerClientSessionMapWriter, ProjectIdentityNotRes
16
16
  * @param logFile - optional path for structured log output
17
17
  * @public
18
18
  */
19
- declare const CliLive: (dbPath: string, logLevel?: LogLevel.LogLevel, logFile?: string) => Layer.Layer<import("@vitest-agent/sdk").DataReader | import("@vitest-agent/sdk").DataStore | import("@vitest-agent/sdk").DetailResolver | import("@vitest-agent/sdk").EnvironmentDetector | import("@vitest-agent/sdk").ExecutorResolver | import("@vitest-agent/sdk").FormatSelector | import("@vitest-agent/sdk").HistoryTracker | import("@vitest-agent/sdk").OutputRenderer | import("@vitest-agent/sdk").ProjectDiscovery | import("@effect/sql/SqlClient").SqlClient | import("@effect/sql-sqlite-node/SqliteClient").SqliteClient | NodeContext.NodeContext, SqliteMigrator.MigrationError | import("@effect/sql/SqlError").SqlError | import("effect/ConfigError").ConfigError, never>;
19
+ declare const CliLive: (dbPath: string, logLevel?: LogLevel.LogLevel, logFile?: string) => Layer.Layer<import("@vitest-agent/sdk").DataReader | import("@vitest-agent/sdk").DataStore | import("@vitest-agent/sdk").DetailResolver | import("@vitest-agent/sdk").EnvironmentDetector | import("@vitest-agent/sdk").ExecutorResolver | import("@vitest-agent/sdk").FormatSelector | import("@vitest-agent/sdk").HistoryTracker | import("@vitest-agent/sdk").OutputRenderer | import("@vitest-agent/sdk").ProjectDiscovery | import("effect/unstable/sql/SqlClient").SqlClient | import("@effect/sql-sqlite-node/SqliteClient").SqliteClient | NodeServices.NodeServices, SqliteMigrator.MigrationError | import("effect/unstable/sql/SqlError").SqlError, never>;
20
20
  //#endregion
21
21
  //#region src/layers/SidecarLive.d.ts
22
22
  /**
@@ -42,7 +42,7 @@ interface SidecarPaths {
42
42
  * @param paths - the three SQLite database paths to open
43
43
  * @public
44
44
  */
45
- declare const SidecarLive: (paths: SidecarPaths) => Layer.Layer<import("@vitest-agent/sdk").DataReader | import("@vitest-agent/sdk").DataStore | import("@vitest-agent/sdk").DiscoveryRegistry | import("@vitest-agent/sdk").PerClientSessionMapReader | import("@vitest-agent/sdk").PerClientSessionMapWriter | import("@vitest-agent/sdk").RunContext$ | NodeContext.NodeContext, SqliteMigrator.MigrationError | import("@effect/sql/SqlError").SqlError | import("effect/ConfigError").ConfigError, never>;
45
+ declare const SidecarLive: (paths: SidecarPaths) => Layer.Layer<import("@vitest-agent/sdk").DataReader | import("@vitest-agent/sdk").DataStore | import("@vitest-agent/sdk").DiscoveryRegistry | import("@vitest-agent/sdk").PerClientSessionMapReader | import("@vitest-agent/sdk").PerClientSessionMapWriter | import("@vitest-agent/sdk").RunContext$ | NodeServices.NodeServices, SqliteMigrator.MigrationError | import("effect/unstable/sql/SqlError").SqlError, never>;
46
46
  //#endregion
47
47
  //#region src/lib/internal-register-agent.d.ts
48
48
  /**
package/index.js CHANGED
@@ -11,7 +11,7 @@ import { DATA_DB_FILENAME, REGISTRY_DB_FILENAME, SESSIONS_DB_FILENAME, resolvePr
11
11
  *
12
12
  * @public
13
13
  */
14
- const CURRENT_CLI_VERSION = "1.0.7";
14
+ const CURRENT_CLI_VERSION = "2.0.0";
15
15
 
16
16
  //#endregion
17
17
  export { CURRENT_CLI_VERSION, CliLive, DATA_DB_FILENAME, REGISTRY_DB_FILENAME, SESSIONS_DB_FILENAME, SidecarLive, registerAgentEffect, resolveProjectDataDir, resolveRegistryDir, resolveSessionMapPath };
package/layers/CliLive.js CHANGED
@@ -1,5 +1,4 @@
1
- import { NodeFileSystem } from "@effect/platform-node";
2
- import * as NodeContext$1 from "@effect/platform-node/NodeContext";
1
+ import * as NodeServices from "@effect/platform-node/NodeServices";
3
2
  import { layer } from "@effect/sql-sqlite-node/SqliteClient";
4
3
  import * as SqliteMigrator from "@effect/sql-sqlite-node/SqliteMigrator";
5
4
  import { DataReaderLive, DataStoreLive, HistoryTrackerLive, LoggerLive, OutputPipelineLive, ProjectDiscoveryLive, migration0001 } from "@vitest-agent/sdk";
@@ -10,8 +9,8 @@ import { Layer } from "effect";
10
9
  * Composition layer for the CLI runtime.
11
10
  *
12
11
  * Wires `DataReader`, `ProjectDiscovery`, `HistoryTracker`,
13
- * `OutputPipeline`, `SqliteClient`, the DB migrator, `NodeContext`,
14
- * `NodeFileSystem`, and `Logger` into a single layer the `vitest-agent`
12
+ * `OutputPipeline`, `SqliteClient`, the DB migrator, the Node platform
13
+ * services, and `Logger` into a single layer the `vitest-agent`
15
14
  * bin provides to `Command.run`.
16
15
  *
17
16
  * @param dbPath - absolute path to the per-project `data.db`
@@ -21,9 +20,9 @@ import { Layer } from "effect";
21
20
  */
22
21
  const CliLive = (dbPath, logLevel, logFile) => {
23
22
  const SqliteLayer = layer({ filename: dbPath });
24
- const PlatformLayer = NodeContext$1.layer;
23
+ const PlatformLayer = NodeServices.layer;
25
24
  const MigratorLayer = SqliteMigrator.layer({ loader: SqliteMigrator.fromRecord({ "0001_initial": migration0001 }) }).pipe(Layer.provide(Layer.merge(SqliteLayer, PlatformLayer)));
26
- return Layer.mergeAll(ProjectDiscoveryLive, HistoryTrackerLive, OutputPipelineLive).pipe(Layer.provideMerge(DataReaderLive), Layer.provideMerge(DataStoreLive), Layer.provideMerge(MigratorLayer), Layer.provideMerge(SqliteLayer), Layer.provideMerge(PlatformLayer), Layer.provideMerge(NodeFileSystem.layer), Layer.provideMerge(LoggerLive(logLevel, logFile)));
25
+ return Layer.mergeAll(ProjectDiscoveryLive, HistoryTrackerLive, OutputPipelineLive).pipe(Layer.provideMerge(DataReaderLive), Layer.provideMerge(DataStoreLive), Layer.provideMerge(MigratorLayer), Layer.provideMerge(SqliteLayer), Layer.provideMerge(PlatformLayer), Layer.provideMerge(LoggerLive(logLevel, logFile)));
27
26
  };
28
27
 
29
28
  //#endregion
@@ -1,5 +1,4 @@
1
- import { NodeFileSystem } from "@effect/platform-node";
2
- import * as NodeContext$1 from "@effect/platform-node/NodeContext";
1
+ import * as NodeServices from "@effect/platform-node/NodeServices";
3
2
  import { layer } from "@effect/sql-sqlite-node/SqliteClient";
4
3
  import * as SqliteMigrator from "@effect/sql-sqlite-node/SqliteMigrator";
5
4
  import { DataReaderLive, DataStoreLive, DiscoveryRegistryLive, LoggerLive, PerClientSessionMapWriterLive, RunContextLive, migration0001, registryMigration0001, sessionMapMigration0001 } from "@vitest-agent/sdk";
@@ -17,7 +16,7 @@ import { Layer } from "effect";
17
16
  * @public
18
17
  */
19
18
  const SidecarLive = (paths) => {
20
- const PlatformLayer = NodeContext$1.layer;
19
+ const PlatformLayer = NodeServices.layer;
21
20
  const ProjectSqliteLayer = layer({ filename: paths.perProjectDbPath });
22
21
  const ProjectMigratorLayer = SqliteMigrator.layer({ loader: SqliteMigrator.fromRecord({ "0001_initial": migration0001 }) }).pipe(Layer.provide(Layer.merge(ProjectSqliteLayer, PlatformLayer)));
23
22
  const ProjectStoreLayer = Layer.mergeAll(DataStoreLive.pipe(Layer.provide(ProjectSqliteLayer)), DataReaderLive.pipe(Layer.provide(ProjectSqliteLayer)), ProjectMigratorLayer);
@@ -27,7 +26,7 @@ const SidecarLive = (paths) => {
27
26
  const RegistrySqliteLayer = layer({ filename: paths.registryDbPath });
28
27
  const RegistryMigratorLayer = SqliteMigrator.layer({ loader: SqliteMigrator.fromRecord({ "0001_initial": registryMigration0001 }) }).pipe(Layer.provide(Layer.merge(RegistrySqliteLayer, PlatformLayer)));
29
28
  const RegistryLayer = Layer.mergeAll(DiscoveryRegistryLive.pipe(Layer.provide(RegistrySqliteLayer)), RegistryMigratorLayer);
30
- return Layer.mergeAll(ProjectStoreLayer, SessionMapLayer, RegistryLayer, RunContextLive).pipe(Layer.provideMerge(PlatformLayer), Layer.provideMerge(NodeFileSystem.layer), Layer.provideMerge(LoggerLive()));
29
+ return Layer.mergeAll(ProjectStoreLayer, SessionMapLayer, RegistryLayer, RunContextLive).pipe(Layer.provideMerge(PlatformLayer), Layer.provideMerge(LoggerLive()));
31
30
  };
32
31
 
33
32
  //#endregion
@@ -13,14 +13,14 @@ const parseAndValidateTurnPayload = (raw) => {
13
13
  error: `Invalid JSON: ${e instanceof Error ? e.message : String(e)}`
14
14
  };
15
15
  }
16
- const decoded = Schema.decodeUnknownEither(TurnPayload)(parsed);
17
- if (decoded._tag === "Left") return {
16
+ const decoded = Schema.decodeUnknownResult(TurnPayload)(parsed);
17
+ if (decoded._tag === "Failure") return {
18
18
  ok: false,
19
- error: `Invalid TurnPayload: ${decoded.left.message}`
19
+ error: `Invalid TurnPayload: ${decoded.failure.message}`
20
20
  };
21
21
  return {
22
22
  ok: true,
23
- payload: decoded.right
23
+ payload: decoded.success
24
24
  };
25
25
  };
26
26
  const recordTurnEffect = (input) => Effect.gen(function* () {
@@ -1,23 +1,9 @@
1
1
  import { DataStore } from "@vitest-agent/sdk";
2
2
  import { Effect } from "effect";
3
- import { SqlClient } from "@effect/sql/SqlClient";
3
+ import { SqlClient } from "effect/unstable/sql/SqlClient";
4
4
 
5
5
  //#region src/lib/record-workspace-changes.ts
6
6
  /**
7
- * Lib function for the `record run-workspace-changes` CLI subcommand.
8
- *
9
- * Driven by the PostToolUse hook on `git commit` / `git push`. Writes a
10
- * commits row (idempotent on sha via ON CONFLICT DO NOTHING in
11
- * DataStore.writeCommit) and zero or more run_changed_files rows.
12
- *
13
- * Optionally associates the changed files with a test_run_id; for the
14
- * commit-side write path we don't have a run, so we associate the files
15
- * with the most-recent test_run for the project (best-effort) or skip
16
- * the file rows entirely if no test_run exists yet.
17
- *
18
- * @packageDocumentation
19
- */
20
- /**
21
7
  * `ProjectRunSummary` doesn't expose `lastRunId`, so we query it directly
22
8
  * via SqlClient. This is the run id of the most-recent test run for a
23
9
  * given project (or any project, when `project` is unspecified). Used
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vitest-agent/cli",
3
- "version": "1.0.7",
3
+ "version": "2.0.0",
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": [
@@ -29,7 +29,8 @@
29
29
  "exports": {
30
30
  ".": {
31
31
  "types": "./index.d.ts",
32
- "import": "./index.js"
32
+ "import": "./index.js",
33
+ "default": "./index.js"
33
34
  },
34
35
  "./package.json": "./package.json"
35
36
  },
@@ -37,21 +38,11 @@
37
38
  "vitest-agent": "bin/vitest-agent.js"
38
39
  },
39
40
  "dependencies": {
40
- "@effect/cli": "^0.75.2",
41
- "@effect/cluster": "^0.59.0",
42
- "@effect/experimental": "^0.60.0",
43
- "@effect/platform": "^0.96.2",
44
- "@effect/platform-node": "^0.107.0",
45
- "@effect/printer": "^0.49.0",
46
- "@effect/printer-ansi": "^0.49.0",
47
- "@effect/rpc": "^0.75.1",
48
- "@effect/sql": "^0.51.1",
49
- "@effect/sql-sqlite-node": "^0.52.0",
50
- "@effect/typeclass": "^0.40.0",
51
- "@effect/workflow": "^0.18.2",
52
- "@vitest-agent/sdk": "1.3.3",
53
- "@vitest-agent/sidecar": "1.0.2",
54
- "effect": "^3.21.4"
41
+ "@effect/platform-node": "4.0.0-beta.98",
42
+ "@effect/sql-sqlite-node": "4.0.0-beta.98",
43
+ "@vitest-agent/sdk": "2.0.0",
44
+ "@vitest-agent/sidecar": "2.0.0",
45
+ "effect": "4.0.0-beta.98"
55
46
  },
56
47
  "engines": {
57
48
  "node": ">=24.11.0"
@@ -5,7 +5,7 @@
5
5
  "toolPackages": [
6
6
  {
7
7
  "packageName": "@microsoft/api-extractor",
8
- "packageVersion": "7.58.9"
8
+ "packageVersion": "7.58.10"
9
9
  }
10
10
  ]
11
11
  }