@vitest-agent/sdk 1.3.3 → 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.
- package/errors/DataStoreError.js +22 -13
- package/index.d.ts +1032 -1101
- package/index.js +3 -3
- package/layers/ConfigLive.js +8 -9
- package/layers/DataReaderLive.js +2 -2
- package/layers/DataStoreLive.js +2 -2
- package/layers/DiscoveryRegistryLive.js +1 -1
- package/layers/LoggerLive.js +24 -24
- package/layers/PathResolutionLive.js +18 -17
- package/layers/PerClientSessionMapLive.js +1 -1
- package/layers/ProjectDiscoveryLive.js +1 -2
- package/layers/ProjectIdentityLive.js +16 -12
- package/layers/RunContextLive.js +20 -20
- package/migrations/0001_initial.js +1 -1
- package/migrations/registry_0001_initial.js +1 -1
- package/migrations/session_map_0001_initial.js +1 -1
- package/package.json +18 -18
- package/schemas/AgentReport.js +6 -9
- package/schemas/Baselines.js +3 -3
- package/schemas/CacheManifest.js +2 -2
- package/schemas/ChannelEvent.js +30 -3
- package/schemas/Common.js +76 -14
- package/schemas/ConsoleLeaks.js +2 -2
- package/schemas/Coverage.js +8 -8
- package/schemas/CoverageTargets.js +16 -10
- package/schemas/History.js +4 -4
- package/schemas/Identity.js +19 -7
- package/schemas/Options.js +3 -3
- package/schemas/RenderState.js +26 -19
- package/schemas/RunEvent.js +154 -115
- package/schemas/Tdd.js +16 -6
- package/schemas/Thresholds.js +6 -6
- package/schemas/Transport.js +1 -1
- package/schemas/Trends.js +7 -3
- package/schemas/turns/FileEditPayload.js +5 -1
- package/schemas/turns/HookFirePayload.js +15 -1
- package/schemas/turns/index.js +9 -1
- package/services/Config.js +3 -3
- package/services/DataReader.js +1 -1
- package/services/DataStore.js +1 -1
- package/services/DetailResolver.js +1 -1
- package/services/DiscoveryRegistry.js +1 -1
- package/services/EnvironmentDetector.js +1 -1
- package/services/ExecutorResolver.js +1 -1
- package/services/FormatSelector.js +1 -1
- package/services/HistoryTracker.js +1 -1
- package/services/OutputRenderer.js +1 -1
- package/services/PerClientSessionMap.js +2 -2
- package/services/ProjectDiscovery.js +1 -1
- package/services/ProjectIdentity.js +1 -1
- package/services/RunContext.js +1 -1
- package/testing/layers.js +2 -2
- package/testing.d.ts +312 -332
- package/tsdoc-metadata.json +1 -1
- package/utils/build-report.js +16 -1
- package/utils/ensure-migrated.js +3 -3
- package/utils/resolve-data-path.js +3 -3
- package/utils/resolve-workspace-key.js +11 -6
package/index.js
CHANGED
|
@@ -89,7 +89,7 @@ import { UserPromptPayload } from "./schemas/turns/UserPromptPayload.js";
|
|
|
89
89
|
import { TurnPayload } from "./schemas/turns/index.js";
|
|
90
90
|
import { IDEMPOTENCY_ROOT_SENTINEL, deriveIdempotencyKey } from "./services/idempotency.js";
|
|
91
91
|
import { assembleHistoryRecord, assembleManifest } from "./sql/assemblers.js";
|
|
92
|
-
import { buildAgentReport } from "./utils/build-report.js";
|
|
92
|
+
import { buildAgentReport, countSuiteFailures } from "./utils/build-report.js";
|
|
93
93
|
import { computeTrend, getRecentDirection, hashTargets } from "./utils/compute-trend.js";
|
|
94
94
|
import { buildConsoleLeaks, collectConsoleLeakEntries } from "./utils/console-leaks.js";
|
|
95
95
|
import { detectPackageManager, getRunCommand } from "./utils/detect-pm.js";
|
|
@@ -115,7 +115,7 @@ import { requiredArtifactForTransition, transitionEnforcesBehaviorMatch, validat
|
|
|
115
115
|
* substituted yet. Exported for version introspection by downstream tooling.
|
|
116
116
|
* @public
|
|
117
117
|
*/
|
|
118
|
-
const CURRENT_SDK_VERSION = "
|
|
118
|
+
const CURRENT_SDK_VERSION = "2.0.0";
|
|
119
119
|
|
|
120
120
|
//#endregion
|
|
121
|
-
export { ActionSeverity, ActorType, Agent, AgentConsoleMode, AgentContext, AgentId, AgentNotFoundError, AgentPluginOptions, AgentReport, AgentReporterOptions, BehaviorAbandonedEvent, BehaviorAddedEvent, BehaviorCompletedEvent, BehaviorDetail, BehaviorNotFoundError, BehaviorRow, BehaviorScopedEventTypes, BehaviorStartedEvent, BehaviorStatus, BehaviorsReadyEvent, BlockedEvent, CURRENT_SDK_VERSION, CacheManifest, CacheManifestEntry, ChannelEvent, ChatId, CiConsoleMode, ConfigLive, ConsoleLeakFile, ConsoleLeaks, ConsoleLogLevel, ConsoleMode, ConsoleOutputMode, ConsoleOutputs, ConversationId, ConversationNotFoundError, CoverageBaselines, FileCoverageReport as CoverageFile, CoverageGap, CoverageLevel, CoverageMetric, CoverageRenderState, CoverageReport, CoverageTargets, CoverageTargetsMetrics, CoverageTotals, DATABASE_FILENAME, DataReader, DataReaderLive, DataStore, DataStoreError, DataStoreLive, DetailLevel, DetailResolver, DetailResolverLive, DiscoveryError, DiscoveryRegistry, DiscoveryRegistryLive, Environment, EnvironmentDetector, EnvironmentDetectorLive, EnvironmentDetectorTest, Executor, ExecutorResolver, ExecutorResolverLive, FailureRecord, FileCoverageReport, FileEditPayload, FormatSelector, FormatSelectorLive, GfmFormatter, GitCommandError, GoalAbandonedEvent, GoalAddedEvent, GoalCompletedEvent, GoalDetail, GoalNotFoundError, GoalRow, GoalStartedEvent, GoalStatus, GoalsReadyEvent, HistoryRecord, HistoryTracker, HistoryTrackerLive, HistoryTrackerTest, HookFirePayload, HookStatus, HookType, HostKind, HostMetadataParseError, HumanConsoleMode, HypothesisPayload, IDEMPOTENCY_ROOT_SENTINEL, IdempotencyHit, IllegalStatusTransitionError, JsonFormatter, LoggerLive, MarkdownFormatter, MetricThresholds, ModuleRecord, ModuleReport, NotePayload, OutputFormat, OutputPipelineLive, OutputRenderer, OutputRendererLive, PackageManager, PathResolutionError, PathResolutionLive, PatternThresholds, PerClientSessionMapReader, PerClientSessionMapReaderLive, PerClientSessionMapWriter, PerClientSessionMapWriterLive, PhaseTransitionEvent, ProbeMissError, ProjectDiscovery, ProjectDiscoveryLive, ProjectDiscoveryTest, ProjectIdentity, ProjectIdentityLive, ProjectIdentityNotResolvableError, ProjectIdentityTest, ProjectKey, RegistrationConflictError, RenderState, RenderTotals, ReportError, ReportSummary, ResolvedThresholds, RunContext, RunContext$, RunContextLive, RunContextService, RunContextTest, RunEvent, SessionCompleteEvent, SessionNotFoundError, SessionOutcome, SidecarTimeoutError, SilentFormatter, SuggestedActionRecord, TagCountEntry, TddTaskAlreadyEndedError, TddTaskId, TddTaskNotFoundError, TerminalFormatter, TestClassification, TestHistory, TestRecord, TestReport, TestRun, TestRunReason, TestState, ToolCallPayload, ToolResultPayload, Transport, TrendEntry, TrendRecord, TurnPayload, UserPromptPayload, VitestAgentConfig, VitestAgentConfigFile, _resetMigrationCacheForTesting, ansi, assembleHistoryRecord, assembleManifest, buildAgentReport, buildConsoleLeaks, buildEnvPrefix, canonicalizeGitUrl, ciAnnotationsFormatter, classifyTest, collectConsoleLeakEntries, compressLines, computeFailureSignature, computeTrend, deriveIdempotencyKey, detectPackageManager, detectVitestScripts, determineTier, ensureMigrated, extractSqlReason, findFunctionBoundary, formatConsoleMarkdown, formatFatalError, formatGfm, formatTriageEffect, formatWrapupEffect, getRecentDirection, getRunCommand, getWorstMetric, gitUrlToProjectKey, hashTargets, historyKey, initialRenderState, isTimeoutError, isVitestInvocation, migration as migration0001, normalizeAssertionShape, normalizeWorkspaceKey, osc8, probeHostMetadataFromEnv, migration$1 as registryMigration0001, relativePath, requiredArtifactForTransition, resolveCoverageInput, resolveDataPath, resolveLogFile, resolveLogLevel, resolveProjectIdentityFromCandidates, resolveProjectKeyFromCwd, resolveWorkspaceKey, rewriteBashCommand, safeFilename, migration$2 as sessionMapMigration0001, stripAnsi, transitionEnforcesBehaviorMatch, validateCoverageConfig, validateCoverageTargetsShape, validatePhaseTransition };
|
|
121
|
+
export { ActionSeverity, ActorType, Agent, AgentConsoleMode, AgentContext, AgentId, AgentNotFoundError, AgentPluginOptions, AgentReport, AgentReporterOptions, BehaviorAbandonedEvent, BehaviorAddedEvent, BehaviorCompletedEvent, BehaviorDetail, BehaviorNotFoundError, BehaviorRow, BehaviorScopedEventTypes, BehaviorStartedEvent, BehaviorStatus, BehaviorsReadyEvent, BlockedEvent, CURRENT_SDK_VERSION, CacheManifest, CacheManifestEntry, ChannelEvent, ChatId, CiConsoleMode, ConfigLive, ConsoleLeakFile, ConsoleLeaks, ConsoleLogLevel, ConsoleMode, ConsoleOutputMode, ConsoleOutputs, ConversationId, ConversationNotFoundError, CoverageBaselines, FileCoverageReport as CoverageFile, CoverageGap, CoverageLevel, CoverageMetric, CoverageRenderState, CoverageReport, CoverageTargets, CoverageTargetsMetrics, CoverageTotals, DATABASE_FILENAME, DataReader, DataReaderLive, DataStore, DataStoreError, DataStoreLive, DetailLevel, DetailResolver, DetailResolverLive, DiscoveryError, DiscoveryRegistry, DiscoveryRegistryLive, Environment, EnvironmentDetector, EnvironmentDetectorLive, EnvironmentDetectorTest, Executor, ExecutorResolver, ExecutorResolverLive, FailureRecord, FileCoverageReport, FileEditPayload, FormatSelector, FormatSelectorLive, GfmFormatter, GitCommandError, GoalAbandonedEvent, GoalAddedEvent, GoalCompletedEvent, GoalDetail, GoalNotFoundError, GoalRow, GoalStartedEvent, GoalStatus, GoalsReadyEvent, HistoryRecord, HistoryTracker, HistoryTrackerLive, HistoryTrackerTest, HookFirePayload, HookStatus, HookType, HostKind, HostMetadataParseError, HumanConsoleMode, HypothesisPayload, IDEMPOTENCY_ROOT_SENTINEL, IdempotencyHit, IllegalStatusTransitionError, JsonFormatter, LoggerLive, MarkdownFormatter, MetricThresholds, ModuleRecord, ModuleReport, NotePayload, OutputFormat, OutputPipelineLive, OutputRenderer, OutputRendererLive, PackageManager, PathResolutionError, PathResolutionLive, PatternThresholds, PerClientSessionMapReader, PerClientSessionMapReaderLive, PerClientSessionMapWriter, PerClientSessionMapWriterLive, PhaseTransitionEvent, ProbeMissError, ProjectDiscovery, ProjectDiscoveryLive, ProjectDiscoveryTest, ProjectIdentity, ProjectIdentityLive, ProjectIdentityNotResolvableError, ProjectIdentityTest, ProjectKey, RegistrationConflictError, RenderState, RenderTotals, ReportError, ReportSummary, ResolvedThresholds, RunContext, RunContext$, RunContextLive, RunContextService, RunContextTest, RunEvent, SessionCompleteEvent, SessionNotFoundError, SessionOutcome, SidecarTimeoutError, SilentFormatter, SuggestedActionRecord, TagCountEntry, TddTaskAlreadyEndedError, TddTaskId, TddTaskNotFoundError, TerminalFormatter, TestClassification, TestHistory, TestRecord, TestReport, TestRun, TestRunReason, TestState, ToolCallPayload, ToolResultPayload, Transport, TrendEntry, TrendRecord, TurnPayload, UserPromptPayload, VitestAgentConfig, VitestAgentConfigFile, _resetMigrationCacheForTesting, ansi, assembleHistoryRecord, assembleManifest, buildAgentReport, buildConsoleLeaks, buildEnvPrefix, canonicalizeGitUrl, ciAnnotationsFormatter, classifyTest, collectConsoleLeakEntries, compressLines, computeFailureSignature, computeTrend, countSuiteFailures, deriveIdempotencyKey, detectPackageManager, detectVitestScripts, determineTier, ensureMigrated, extractSqlReason, findFunctionBoundary, formatConsoleMarkdown, formatFatalError, formatGfm, formatTriageEffect, formatWrapupEffect, getRecentDirection, getRunCommand, getWorstMetric, gitUrlToProjectKey, hashTargets, historyKey, initialRenderState, isTimeoutError, isVitestInvocation, migration as migration0001, normalizeAssertionShape, normalizeWorkspaceKey, osc8, probeHostMetadataFromEnv, migration$1 as registryMigration0001, relativePath, requiredArtifactForTransition, resolveCoverageInput, resolveDataPath, resolveLogFile, resolveLogLevel, resolveProjectIdentityFromCandidates, resolveProjectKeyFromCwd, resolveWorkspaceKey, rewriteBashCommand, safeFilename, migration$2 as sessionMapMigration0001, stripAnsi, transitionEnforcesBehaviorMatch, validateCoverageConfig, validateCoverageTargetsShape, validatePhaseTransition };
|
package/layers/ConfigLive.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { VitestAgentConfig } from "../schemas/Config.js";
|
|
2
2
|
import { VitestAgentConfigFile } from "../services/Config.js";
|
|
3
|
-
import { ConfigFile,
|
|
3
|
+
import { ConfigFile, ConfigResolver, MergeStrategy, TomlCodec } from "@effected/config-file";
|
|
4
4
|
|
|
5
5
|
//#region src/layers/ConfigLive.ts
|
|
6
6
|
const CONFIG_FILENAME = "vitest-agent.config.toml";
|
|
@@ -13,8 +13,8 @@ const CONFIG_FILENAME = "vitest-agent.config.toml";
|
|
|
13
13
|
* 2. The git repository root (when `projectDir` is inside a git repo).
|
|
14
14
|
* 3. Walking upward from `projectDir`.
|
|
15
15
|
*
|
|
16
|
-
* The first found file wins (`
|
|
17
|
-
* downstream callers use `loadOrDefault(new VitestAgentConfig({}))`
|
|
16
|
+
* The first found file wins (`MergeStrategy.firstMatch()`). If no file is
|
|
17
|
+
* present, downstream callers use `loadOrDefault(new VitestAgentConfig({}))`
|
|
18
18
|
* to get an empty config.
|
|
19
19
|
*
|
|
20
20
|
* @param projectDir - Absolute path inside the user's workspace. Resolvers
|
|
@@ -22,21 +22,20 @@ const CONFIG_FILENAME = "vitest-agent.config.toml";
|
|
|
22
22
|
* sees the right config even when invoked from elsewhere.
|
|
23
23
|
* @public
|
|
24
24
|
*/
|
|
25
|
-
const ConfigLive = (projectDir) => ConfigFile.
|
|
26
|
-
tag: VitestAgentConfigFile,
|
|
25
|
+
const ConfigLive = (projectDir) => ConfigFile.layer(VitestAgentConfigFile, {
|
|
27
26
|
schema: VitestAgentConfig,
|
|
28
27
|
codec: TomlCodec,
|
|
29
|
-
strategy:
|
|
28
|
+
strategy: MergeStrategy.firstMatch(),
|
|
30
29
|
resolvers: [
|
|
31
|
-
|
|
30
|
+
ConfigResolver.workspaceRoot({
|
|
32
31
|
filename: CONFIG_FILENAME,
|
|
33
32
|
cwd: projectDir
|
|
34
33
|
}),
|
|
35
|
-
|
|
34
|
+
ConfigResolver.gitRoot({
|
|
36
35
|
filename: CONFIG_FILENAME,
|
|
37
36
|
cwd: projectDir
|
|
38
37
|
}),
|
|
39
|
-
|
|
38
|
+
ConfigResolver.upwardWalk({
|
|
40
39
|
filename: CONFIG_FILENAME,
|
|
41
40
|
cwd: projectDir
|
|
42
41
|
})
|
package/layers/DataReaderLive.js
CHANGED
|
@@ -2,7 +2,7 @@ import { DataStoreError, extractSqlReason } from "../errors/DataStoreError.js";
|
|
|
2
2
|
import { DataReader } from "../services/DataReader.js";
|
|
3
3
|
import { historyKey } from "../services/HistoryTracker.js";
|
|
4
4
|
import { Effect, Layer, Option } from "effect";
|
|
5
|
-
import { SqlClient } from "
|
|
5
|
+
import { SqlClient } from "effect/unstable/sql/SqlClient";
|
|
6
6
|
|
|
7
7
|
//#region src/layers/DataReaderLive.ts
|
|
8
8
|
/** @public */
|
|
@@ -598,7 +598,7 @@ const DataReaderLive = Layer.effect(DataReader, Effect.gen(function* () {
|
|
|
598
598
|
) t2 ON t1.project = t2.project
|
|
599
599
|
AND t1.timestamp = t2.max_ts`;
|
|
600
600
|
if (rows.length === 0) return Option.none();
|
|
601
|
-
const dbPath = (yield* sql`PRAGMA database_list`.pipe(Effect.
|
|
601
|
+
const dbPath = (yield* sql`PRAGMA database_list`.pipe(Effect.catch(() => Effect.succeed([])))).find((d) => d.name === "main")?.file ?? "";
|
|
602
602
|
const projects = rows.map((r) => ({
|
|
603
603
|
project: r.project,
|
|
604
604
|
reportFile: dbPath,
|
package/layers/DataStoreLive.js
CHANGED
|
@@ -4,7 +4,7 @@ import { BehaviorNotFoundError, GoalNotFoundError, IllegalStatusTransitionError,
|
|
|
4
4
|
import { Agent, IdempotencyHit } from "../schemas/Agent.js";
|
|
5
5
|
import { DataStore } from "../services/DataStore.js";
|
|
6
6
|
import { Effect, Layer, Option } from "effect";
|
|
7
|
-
import { SqlClient } from "
|
|
7
|
+
import { SqlClient } from "effect/unstable/sql/SqlClient";
|
|
8
8
|
import { randomUUID } from "node:crypto";
|
|
9
9
|
|
|
10
10
|
//#region src/layers/DataStoreLive.ts
|
|
@@ -36,7 +36,7 @@ const boolToInt = (v) => v === void 0 ? null : v ? 1 : 0;
|
|
|
36
36
|
/** @public */
|
|
37
37
|
const DataStoreLive = Layer.effect(DataStore, Effect.gen(function* () {
|
|
38
38
|
const sql = yield* SqlClient;
|
|
39
|
-
yield* sql`PRAGMA foreign_keys=ON`.pipe(Effect.
|
|
39
|
+
yield* sql`PRAGMA foreign_keys=ON`.pipe(Effect.catch(() => Effect.void));
|
|
40
40
|
const ensureFile = (filePath) => Effect.gen(function* () {
|
|
41
41
|
yield* Effect.logDebug("ensureFile").pipe(Effect.annotateLogs({ filePath }));
|
|
42
42
|
yield* sql`INSERT OR IGNORE INTO files (path) VALUES (${filePath})`;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { DataStoreError, extractSqlReason } from "../errors/DataStoreError.js";
|
|
2
2
|
import { DiscoveryRegistry } from "../services/DiscoveryRegistry.js";
|
|
3
3
|
import { Effect, Layer } from "effect";
|
|
4
|
-
import { SqlClient } from "
|
|
4
|
+
import { SqlClient } from "effect/unstable/sql/SqlClient";
|
|
5
5
|
|
|
6
6
|
//#region src/layers/DiscoveryRegistryLive.ts
|
|
7
7
|
const TABLE = "known_projects";
|
package/layers/LoggerLive.js
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
import { Layer, LogLevel, Logger } from "effect";
|
|
1
|
+
import { Layer, LogLevel, Logger, References } from "effect";
|
|
2
2
|
import { appendFileSync } from "node:fs";
|
|
3
3
|
|
|
4
4
|
//#region src/layers/LoggerLive.ts
|
|
5
5
|
/**
|
|
6
6
|
* Create a structured JSON (NDJSON) logger layer for stderr.
|
|
7
7
|
*
|
|
8
|
-
* When level is undefined or
|
|
9
|
-
* When logFile is set, composes with a file logger
|
|
10
|
-
* Uses Logger.
|
|
8
|
+
* When level is undefined or `"None"`, installs an empty logger set (silent).
|
|
9
|
+
* When logFile is set, composes the stderr logger with a file logger.
|
|
10
|
+
* Uses `Logger.formatJson` / `Logger.formatStructured` for machine-readable
|
|
11
|
+
* output.
|
|
11
12
|
* @public
|
|
12
13
|
*/
|
|
13
14
|
const LoggerLive = (level, logFile) => {
|
|
14
|
-
if (!level || level
|
|
15
|
-
const stderrLogger = Logger.
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
...Object.fromEntries(annotations)
|
|
23
|
-
});
|
|
24
|
-
try {
|
|
25
|
-
appendFileSync(logFile, `${entry}\n`);
|
|
26
|
-
} catch {}
|
|
15
|
+
if (!level || level === "None") return Logger.layer([]);
|
|
16
|
+
const stderrLogger = Logger.formatJson.pipe(Logger.withConsoleError);
|
|
17
|
+
const fileLogger = logFile ? Logger.formatStructured.pipe(Logger.map((entry) => {
|
|
18
|
+
const line = JSON.stringify({
|
|
19
|
+
timestamp: entry.timestamp,
|
|
20
|
+
level: entry.level,
|
|
21
|
+
message: entry.message,
|
|
22
|
+
...entry.annotations
|
|
27
23
|
});
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
24
|
+
try {
|
|
25
|
+
appendFileSync(logFile, `${line}\n`);
|
|
26
|
+
} catch {}
|
|
27
|
+
return line;
|
|
28
|
+
})) : void 0;
|
|
29
|
+
const loggers = fileLogger ? [stderrLogger, fileLogger] : [stderrLogger];
|
|
30
|
+
return Layer.merge(Logger.layer(loggers), Layer.succeed(References.MinimumLogLevel, level));
|
|
31
31
|
};
|
|
32
32
|
/**
|
|
33
33
|
* Resolve log level from option or environment variable.
|
|
@@ -35,22 +35,22 @@ const LoggerLive = (level, logFile) => {
|
|
|
35
35
|
* @public
|
|
36
36
|
*/
|
|
37
37
|
const LEVEL_ALIASES = {
|
|
38
|
-
warn: "
|
|
38
|
+
warn: "Warn",
|
|
39
|
+
warning: "Warn",
|
|
39
40
|
error: "Error",
|
|
40
41
|
info: "Info",
|
|
41
42
|
debug: "Debug",
|
|
42
43
|
trace: "Trace",
|
|
43
44
|
fatal: "Fatal",
|
|
44
45
|
all: "All",
|
|
45
|
-
none: "None"
|
|
46
|
-
warning: "Warning"
|
|
46
|
+
none: "None"
|
|
47
47
|
};
|
|
48
48
|
/** @public */
|
|
49
49
|
function resolveLogLevel(option) {
|
|
50
50
|
const raw = option ?? process.env.VITEST_REPORTER_LOG_LEVEL;
|
|
51
51
|
if (!raw) return void 0;
|
|
52
52
|
const normalized = LEVEL_ALIASES[raw.toLowerCase()] ?? `${raw.charAt(0).toUpperCase()}${raw.slice(1).toLowerCase()}`;
|
|
53
|
-
return LogLevel.
|
|
53
|
+
return LogLevel.values.includes(normalized) ? normalized : void 0;
|
|
54
54
|
}
|
|
55
55
|
/**
|
|
56
56
|
* Resolve log file from option or environment variable.
|
|
@@ -1,36 +1,37 @@
|
|
|
1
1
|
import { ConfigLive } from "./ConfigLive.js";
|
|
2
2
|
import { Layer } from "effect";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { WorkspaceDiscovery, WorkspaceRoot } from "@effected/workspaces";
|
|
4
|
+
import { AppDirs, Xdg } from "@effected/xdg";
|
|
5
5
|
|
|
6
6
|
//#region src/layers/PathResolutionLive.ts
|
|
7
|
-
const APP_NAMESPACE = "vitest-agent";
|
|
8
7
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* parses the entire lockfile). We only call `WorkspaceDiscovery.listPackages`
|
|
14
|
-
* to read the root `package.json`'s `name` — `WorkspaceRoot` is the only
|
|
15
|
-
* upstream dependency `WorkspaceDiscoveryLive` actually needs. Skipping
|
|
16
|
-
* the rest avoids the lockfile-read cost on every reporter init, which
|
|
17
|
-
* otherwise fires once per Vitest project (5+ reads on monorepos).
|
|
8
|
+
* `AppDirs` over the ambient `Xdg` environment, bound to a `const` so the
|
|
9
|
+
* layer memoizes by reference (calling `AppDirs.layer(...)` inline at two
|
|
10
|
+
* provide sites would resolve two independent services). Requires
|
|
11
|
+
* `FileSystem` + `Path` at the edge.
|
|
18
12
|
*/
|
|
19
|
-
const
|
|
13
|
+
const AppDirsLive = AppDirs.layer({ namespace: "vitest-agent" }).pipe(Layer.provide(Xdg.layer));
|
|
20
14
|
/**
|
|
21
15
|
* Composite layer providing every service `resolveDataPath` requires:
|
|
22
16
|
* `AppDirs` (XDG path resolution), `VitestAgentConfigFile` (TOML
|
|
23
|
-
* config loader), `WorkspaceDiscovery`
|
|
17
|
+
* config loader), and `WorkspaceDiscovery` / `WorkspaceRoot` (workspace name
|
|
24
18
|
* lookup).
|
|
25
19
|
*
|
|
26
20
|
* Callers still need to provide `FileSystem` and `Path` from
|
|
27
|
-
* `@effect/platform-node`'s `
|
|
21
|
+
* `@effect/platform-node`'s `NodeServices.layer` (or the equivalent on Bun).
|
|
22
|
+
*
|
|
23
|
+
* `WorkspaceDiscovery` is anchored at `projectDir`: on v4,
|
|
24
|
+
* `@effected/workspaces` resolves the workspace root from the layer's `cwd`
|
|
25
|
+
* rather than a per-call path, so the `cwd` is pinned here.
|
|
28
26
|
*
|
|
29
27
|
* @param projectDir - Absolute path inside the user's workspace, used to
|
|
30
|
-
* anchor the config file resolvers.
|
|
28
|
+
* anchor the config file resolvers and workspace discovery.
|
|
31
29
|
* @public
|
|
32
30
|
*/
|
|
33
|
-
const PathResolutionLive = (projectDir) =>
|
|
31
|
+
const PathResolutionLive = (projectDir) => {
|
|
32
|
+
const WorkspaceMinimalLive = WorkspaceDiscovery.layer({ cwd: projectDir }).pipe(Layer.provide(WorkspaceRoot.layer));
|
|
33
|
+
return Layer.mergeAll(AppDirsLive, ConfigLive(projectDir), WorkspaceMinimalLive);
|
|
34
|
+
};
|
|
34
35
|
|
|
35
36
|
//#endregion
|
|
36
37
|
export { PathResolutionLive };
|
|
@@ -2,7 +2,7 @@ import { DataStoreError, extractSqlReason } from "../errors/DataStoreError.js";
|
|
|
2
2
|
import { PerClientSessionMapReader, PerClientSessionMapWriter } from "../services/PerClientSessionMap.js";
|
|
3
3
|
import { Effect, Layer, Option } from "effect";
|
|
4
4
|
import { basename } from "node:path";
|
|
5
|
-
import { SqlClient } from "
|
|
5
|
+
import { SqlClient } from "effect/unstable/sql/SqlClient";
|
|
6
6
|
import { randomUUID } from "node:crypto";
|
|
7
7
|
|
|
8
8
|
//#region src/layers/PerClientSessionMapLive.ts
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { DiscoveryError } from "../errors/DiscoveryError.js";
|
|
2
2
|
import { ProjectDiscovery } from "../services/ProjectDiscovery.js";
|
|
3
|
-
import { Effect, Layer } from "effect";
|
|
4
|
-
import { FileSystem } from "@effect/platform";
|
|
3
|
+
import { Effect, FileSystem, Layer } from "effect";
|
|
5
4
|
|
|
6
5
|
//#region src/layers/ProjectDiscoveryLive.ts
|
|
7
6
|
const TEST_FILE_PATTERN = /\.(test|spec)\.(ts|tsx)$/;
|
|
@@ -2,17 +2,21 @@ import { ProjectIdentityNotResolvableError } from "../errors/ProjectIdentityErro
|
|
|
2
2
|
import { VitestAgentConfig } from "../schemas/Config.js";
|
|
3
3
|
import { VitestAgentConfigFile } from "../services/Config.js";
|
|
4
4
|
import { ProjectIdentity, resolveProjectIdentityFromCandidates } from "../services/ProjectIdentity.js";
|
|
5
|
-
import { Effect, Layer, Option } from "effect";
|
|
6
|
-
import { WorkspaceDiscovery } from "workspaces
|
|
7
|
-
import {
|
|
5
|
+
import { Effect, FileSystem, Layer, Option } from "effect";
|
|
6
|
+
import { WorkspaceDiscovery } from "@effected/workspaces";
|
|
7
|
+
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";
|
|
8
8
|
|
|
9
9
|
//#region src/layers/ProjectIdentityLive.ts
|
|
10
|
-
const readGitRemote = (cwd) =>
|
|
11
|
-
const trimmed =
|
|
10
|
+
const readGitRemote = (cwd) => Effect.gen(function* () {
|
|
11
|
+
const trimmed = (yield* (yield* ChildProcessSpawner.ChildProcessSpawner).string(ChildProcess.make("git", [
|
|
12
|
+
"config",
|
|
13
|
+
"--get",
|
|
14
|
+
"remote.origin.url"
|
|
15
|
+
]).pipe(ChildProcess.setCwd(cwd)))).trim();
|
|
12
16
|
return trimmed.length > 0 ? Option.some(trimmed) : Option.none();
|
|
13
|
-
})
|
|
17
|
+
}).pipe(Effect.catch(() => Effect.succeed(Option.none())));
|
|
14
18
|
const readPackageRepoUrl = (packageJsonPath) => Effect.gen(function* () {
|
|
15
|
-
const raw = yield* (yield* FileSystem.FileSystem).readFileString(packageJsonPath).pipe(Effect.
|
|
19
|
+
const raw = yield* (yield* FileSystem.FileSystem).readFileString(packageJsonPath).pipe(Effect.catch(() => Effect.succeed("")));
|
|
16
20
|
if (raw.length === 0) return Option.none();
|
|
17
21
|
try {
|
|
18
22
|
const repo = JSON.parse(raw).repository;
|
|
@@ -25,9 +29,9 @@ const readPackageRepoUrl = (packageJsonPath) => Effect.gen(function* () {
|
|
|
25
29
|
return Option.none();
|
|
26
30
|
});
|
|
27
31
|
const collectCandidates = (workspaceRoot, options) => Effect.gen(function* () {
|
|
28
|
-
const tomlConfig = yield* (yield* VitestAgentConfigFile).loadOrDefault(new VitestAgentConfig({})).pipe(Effect.
|
|
32
|
+
const tomlConfig = yield* (yield* VitestAgentConfigFile).loadOrDefault(new VitestAgentConfig({})).pipe(Effect.catch(() => Effect.succeed(new VitestAgentConfig({}))));
|
|
29
33
|
const gitRemote = yield* readGitRemote(workspaceRoot);
|
|
30
|
-
const root = (yield* (yield* WorkspaceDiscovery).listPackages(
|
|
34
|
+
const root = (yield* (yield* WorkspaceDiscovery).listPackages().pipe(Effect.catch(() => Effect.succeed([])))).find((pkg) => pkg.isRootWorkspace);
|
|
31
35
|
const packageJsonRepoUrl = root ? yield* readPackageRepoUrl(root.packageJsonPath) : Option.none();
|
|
32
36
|
const candidates = {};
|
|
33
37
|
if (options.projectId !== void 0) candidates.explicit = options.projectId;
|
|
@@ -65,15 +69,15 @@ const candidatesToTriedList = (candidates) => [
|
|
|
65
69
|
* Live layer that wires the resolver into real I/O. Requires
|
|
66
70
|
* `FileSystem`, `CommandExecutor`, `WorkspaceDiscovery`, and
|
|
67
71
|
* `VitestAgentConfigFile`. The platform context comes from
|
|
68
|
-
* `
|
|
72
|
+
* `NodeServices.layer` at the entry point.
|
|
69
73
|
* @public
|
|
70
74
|
*/
|
|
71
75
|
const ProjectIdentityLive = Layer.effect(ProjectIdentity, Effect.gen(function* () {
|
|
72
76
|
const fs = yield* FileSystem.FileSystem;
|
|
73
77
|
const discovery = yield* WorkspaceDiscovery;
|
|
74
78
|
const configFile = yield* VitestAgentConfigFile;
|
|
75
|
-
const
|
|
76
|
-
return { resolve: (workspaceRoot, options = {}) => collectCandidates(workspaceRoot, options).pipe(Effect.provideService(FileSystem.FileSystem, fs), Effect.provideService(WorkspaceDiscovery, discovery), Effect.provideService(VitestAgentConfigFile, configFile), Effect.provideService(
|
|
79
|
+
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
|
|
80
|
+
return { resolve: (workspaceRoot, options = {}) => collectCandidates(workspaceRoot, options).pipe(Effect.provideService(FileSystem.FileSystem, fs), Effect.provideService(WorkspaceDiscovery, discovery), Effect.provideService(VitestAgentConfigFile, configFile), Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner), Effect.flatMap((candidates) => {
|
|
77
81
|
const result = resolveProjectIdentityFromCandidates(candidates);
|
|
78
82
|
if (result === null) return Effect.fail(new ProjectIdentityNotResolvableError({ tried: candidatesToTriedList(candidates) }));
|
|
79
83
|
return Effect.succeed(result);
|
package/layers/RunContextLive.js
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
import { AgentContext, RunContext, RunContextService } from "../services/RunContext.js";
|
|
2
2
|
import { probeHostMetadataFromEnv } from "../utils/probe-host-metadata.js";
|
|
3
3
|
import { Effect, Layer, Option } from "effect";
|
|
4
|
-
import {
|
|
4
|
+
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";
|
|
5
5
|
|
|
6
6
|
//#region src/layers/RunContextLive.ts
|
|
7
|
-
const runGit = (cwd, args) =>
|
|
7
|
+
const runGit = (spawner, cwd, args) => spawner.string(ChildProcess.make("git", args).pipe(ChildProcess.setCwd(cwd))).pipe(Effect.map((output) => {
|
|
8
8
|
const trimmed = output.trim();
|
|
9
9
|
return trimmed.length > 0 ? Option.some(trimmed) : Option.none();
|
|
10
|
-
}), Effect.
|
|
11
|
-
const captureRunContextEffect = (cwd,
|
|
12
|
-
const branch = yield* runGit(cwd, [
|
|
10
|
+
}), Effect.catch(() => Effect.succeed(Option.none())));
|
|
11
|
+
const captureRunContextEffect = (cwd, spawner, env) => Effect.gen(function* () {
|
|
12
|
+
const branch = yield* runGit(spawner, cwd, [
|
|
13
13
|
"rev-parse",
|
|
14
14
|
"--abbrev-ref",
|
|
15
15
|
"HEAD"
|
|
16
16
|
]);
|
|
17
|
-
const sha = yield* runGit(cwd, ["rev-parse", "HEAD"]);
|
|
18
|
-
const dirtyOut = yield* runGit(cwd, ["status", "--porcelain"]);
|
|
19
|
-
const upstream = yield* runGit(cwd, [
|
|
17
|
+
const sha = yield* runGit(spawner, cwd, ["rev-parse", "HEAD"]);
|
|
18
|
+
const dirtyOut = yield* runGit(spawner, cwd, ["status", "--porcelain"]);
|
|
19
|
+
const upstream = yield* runGit(spawner, cwd, [
|
|
20
20
|
"rev-parse",
|
|
21
21
|
"--abbrev-ref",
|
|
22
22
|
"@{upstream}"
|
|
23
23
|
]);
|
|
24
|
-
const worktree = yield* runGit(cwd, ["rev-parse", "--show-toplevel"]);
|
|
24
|
+
const worktree = yield* runGit(spawner, cwd, ["rev-parse", "--show-toplevel"]);
|
|
25
25
|
const dirtyValue = Option.match(dirtyOut, {
|
|
26
26
|
onNone: () => null,
|
|
27
27
|
onSome: (out) => out.length > 0
|
|
@@ -37,34 +37,34 @@ const captureRunContextEffect = (cwd, executor, env) => Effect.gen(function* ()
|
|
|
37
37
|
hostValue: host.value,
|
|
38
38
|
hostMetadata: host.metadata
|
|
39
39
|
});
|
|
40
|
-
})
|
|
41
|
-
const captureAgentContextEffect = (cwd,
|
|
42
|
-
const branch = yield* runGit(cwd, [
|
|
40
|
+
});
|
|
41
|
+
const captureAgentContextEffect = (cwd, spawner) => Effect.gen(function* () {
|
|
42
|
+
const branch = yield* runGit(spawner, cwd, [
|
|
43
43
|
"rev-parse",
|
|
44
44
|
"--abbrev-ref",
|
|
45
45
|
"HEAD"
|
|
46
46
|
]);
|
|
47
|
-
const sha = yield* runGit(cwd, ["rev-parse", "HEAD"]);
|
|
48
|
-
const worktree = yield* runGit(cwd, ["rev-parse", "--show-toplevel"]);
|
|
47
|
+
const sha = yield* runGit(spawner, cwd, ["rev-parse", "HEAD"]);
|
|
48
|
+
const worktree = yield* runGit(spawner, cwd, ["rev-parse", "--show-toplevel"]);
|
|
49
49
|
return new AgentContext({
|
|
50
50
|
startGitBranch: Option.getOrNull(branch),
|
|
51
51
|
startGitCommitSha: Option.getOrNull(sha),
|
|
52
52
|
startWorktreeDir: Option.getOrNull(worktree)
|
|
53
53
|
});
|
|
54
|
-
})
|
|
54
|
+
});
|
|
55
55
|
/**
|
|
56
|
-
* Live layer. Requires `
|
|
57
|
-
* `
|
|
56
|
+
* Live layer. Requires `ChildProcessSpawner` (provided by
|
|
57
|
+
* `NodeServices.layer` at the entry point). Reads `process.env`
|
|
58
58
|
* directly for host-metadata probes — the env walk is pure but the
|
|
59
59
|
* env source is process-global, captured once when the layer
|
|
60
60
|
* constructs.
|
|
61
61
|
* @public
|
|
62
62
|
*/
|
|
63
63
|
const RunContextLive = Layer.effect(RunContextService, Effect.gen(function* () {
|
|
64
|
-
const
|
|
64
|
+
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
|
|
65
65
|
return {
|
|
66
|
-
captureRunContext: (cwd) => captureRunContextEffect(cwd,
|
|
67
|
-
captureAgentContext: (cwd) => captureAgentContextEffect(cwd,
|
|
66
|
+
captureRunContext: (cwd) => captureRunContextEffect(cwd, spawner, process.env),
|
|
67
|
+
captureAgentContext: (cwd) => captureAgentContextEffect(cwd, spawner)
|
|
68
68
|
};
|
|
69
69
|
}));
|
|
70
70
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vitest-agent/sdk",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Shared Effect Schema, SQLite migrations, data layer, services, formatters, and utilities for vitest-agent packages.",
|
|
6
6
|
"keywords": [
|
|
@@ -29,36 +29,36 @@
|
|
|
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
|
"./dispatch": {
|
|
35
36
|
"types": "./dispatch.d.ts",
|
|
36
|
-
"import": "./dispatch.js"
|
|
37
|
+
"import": "./dispatch.js",
|
|
38
|
+
"default": "./dispatch.js"
|
|
37
39
|
},
|
|
38
40
|
"./testing": {
|
|
39
41
|
"types": "./testing.d.ts",
|
|
40
|
-
"import": "./testing.js"
|
|
42
|
+
"import": "./testing.js",
|
|
43
|
+
"default": "./testing.js"
|
|
41
44
|
},
|
|
42
45
|
"./package.json": "./package.json"
|
|
43
46
|
},
|
|
44
47
|
"dependencies": {
|
|
45
|
-
"@effect/
|
|
46
|
-
"@effect/
|
|
47
|
-
"@
|
|
48
|
-
"@
|
|
49
|
-
"@
|
|
50
|
-
"@
|
|
51
|
-
"@
|
|
52
|
-
"@
|
|
53
|
-
"@
|
|
48
|
+
"@effect/platform-node": "4.0.0-beta.98",
|
|
49
|
+
"@effect/sql-sqlite-node": "4.0.0-beta.98",
|
|
50
|
+
"@effected/config-file": "^0.1.2",
|
|
51
|
+
"@effected/jsonc": "^0.2.0",
|
|
52
|
+
"@effected/toml": "^0.1.0",
|
|
53
|
+
"@effected/walker": "^0.2.1",
|
|
54
|
+
"@effected/workspaces": "^0.3.1",
|
|
55
|
+
"@effected/xdg": "^0.1.2",
|
|
56
|
+
"@effected/yaml": "^0.3.0",
|
|
54
57
|
"acorn": "^8.17.0",
|
|
55
58
|
"acorn-typescript": "^1.4.13",
|
|
56
59
|
"ajv": "^8.20.0",
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"std-env": "^4.2.0",
|
|
60
|
-
"workspaces-effect": "^2.0.3",
|
|
61
|
-
"xdg-effect": "^2.1.1"
|
|
60
|
+
"effect": "4.0.0-beta.98",
|
|
61
|
+
"std-env": "^4.2.0"
|
|
62
62
|
},
|
|
63
63
|
"engines": {
|
|
64
64
|
"node": ">=24.11.0"
|
package/schemas/AgentReport.js
CHANGED
|
@@ -14,7 +14,7 @@ const ReportSummary = Schema.Struct({
|
|
|
14
14
|
failed: Schema.Number,
|
|
15
15
|
skipped: Schema.Number,
|
|
16
16
|
duration: Schema.Number
|
|
17
|
-
}).
|
|
17
|
+
}).annotate({ identifier: "ReportSummary" });
|
|
18
18
|
/**
|
|
19
19
|
* An individual test case result.
|
|
20
20
|
* @public
|
|
@@ -28,7 +28,7 @@ const TestReport = Schema.Struct({
|
|
|
28
28
|
slow: Schema.optional(Schema.Boolean),
|
|
29
29
|
errors: Schema.optional(Schema.Array(ReportError)),
|
|
30
30
|
classification: Schema.optional(TestClassification)
|
|
31
|
-
}).
|
|
31
|
+
}).annotate({ identifier: "TestReport" });
|
|
32
32
|
/**
|
|
33
33
|
* A test module (file) and its contained test cases.
|
|
34
34
|
* @public
|
|
@@ -39,7 +39,7 @@ const ModuleReport = Schema.Struct({
|
|
|
39
39
|
duration: Schema.optional(Schema.Number),
|
|
40
40
|
errors: Schema.optional(Schema.Array(ReportError)),
|
|
41
41
|
tests: Schema.Array(TestReport)
|
|
42
|
-
}).
|
|
42
|
+
}).annotate({ identifier: "ModuleReport" });
|
|
43
43
|
/**
|
|
44
44
|
* Per-tag pass/fail/skip aggregates for a single project run.
|
|
45
45
|
* @public
|
|
@@ -48,7 +48,7 @@ const TagCountEntry = Schema.Struct({
|
|
|
48
48
|
passed: Schema.optional(Schema.Number),
|
|
49
49
|
failed: Schema.optional(Schema.Number),
|
|
50
50
|
skipped: Schema.optional(Schema.Number)
|
|
51
|
-
}).
|
|
51
|
+
}).annotate({ identifier: "TagCountEntry" });
|
|
52
52
|
/**
|
|
53
53
|
* Complete per-project test report written to disk as JSON.
|
|
54
54
|
* @public
|
|
@@ -62,12 +62,9 @@ const AgentReport = Schema.Struct({
|
|
|
62
62
|
unhandledErrors: Schema.Array(ReportError),
|
|
63
63
|
failedFiles: Schema.Array(Schema.String),
|
|
64
64
|
coverage: Schema.optional(CoverageReport),
|
|
65
|
-
tagCounts: Schema.optional(Schema.Record(
|
|
66
|
-
key: Schema.String,
|
|
67
|
-
value: TagCountEntry
|
|
68
|
-
})),
|
|
65
|
+
tagCounts: Schema.optional(Schema.Record(Schema.String, TagCountEntry)),
|
|
69
66
|
consoleLeaks: Schema.optional(ConsoleLeaks)
|
|
70
|
-
}).
|
|
67
|
+
}).annotate({ identifier: "AgentReport" });
|
|
71
68
|
|
|
72
69
|
//#endregion
|
|
73
70
|
export { AgentReport, ModuleReport, ReportSummary, TagCountEntry, TestReport };
|
package/schemas/Baselines.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { MetricThresholds, PatternThresholds } from "./Thresholds.js";
|
|
2
|
-
import { Schema } from "effect";
|
|
2
|
+
import { Effect, Schema } from "effect";
|
|
3
3
|
|
|
4
4
|
//#region src/schemas/Baselines.ts
|
|
5
5
|
/**
|
|
@@ -9,8 +9,8 @@ import { Schema } from "effect";
|
|
|
9
9
|
const CoverageBaselines = Schema.Struct({
|
|
10
10
|
updatedAt: Schema.String,
|
|
11
11
|
global: MetricThresholds,
|
|
12
|
-
patterns: Schema.
|
|
13
|
-
}).
|
|
12
|
+
patterns: Schema.Array(PatternThresholds).pipe(Schema.withDecodingDefaultKey(Effect.succeed([])))
|
|
13
|
+
}).annotate({ identifier: "CoverageBaselines" });
|
|
14
14
|
|
|
15
15
|
//#endregion
|
|
16
16
|
export { CoverageBaselines };
|
package/schemas/CacheManifest.js
CHANGED
|
@@ -12,7 +12,7 @@ const CacheManifestEntry = Schema.Struct({
|
|
|
12
12
|
historyFile: Schema.optional(Schema.String),
|
|
13
13
|
lastRun: Schema.NullOr(Schema.String),
|
|
14
14
|
lastResult: Schema.NullOr(TestRunReason)
|
|
15
|
-
}).
|
|
15
|
+
}).annotate({ identifier: "CacheManifestEntry" });
|
|
16
16
|
/**
|
|
17
17
|
* Root manifest file that indexes all project reports.
|
|
18
18
|
* @public
|
|
@@ -21,7 +21,7 @@ const CacheManifest = Schema.Struct({
|
|
|
21
21
|
updatedAt: Schema.String,
|
|
22
22
|
cacheDir: Schema.String,
|
|
23
23
|
projects: Schema.Array(CacheManifestEntry)
|
|
24
|
-
}).
|
|
24
|
+
}).annotate({ identifier: "CacheManifest" });
|
|
25
25
|
|
|
26
26
|
//#endregion
|
|
27
27
|
export { CacheManifest, CacheManifestEntry };
|