@vitest-agent/sdk 2.0.16 → 2.1.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 +23 -6
- package/index.d.ts +77 -1
- package/index.js +3 -2
- package/layers/DataStoreLive.js +6 -3
- package/package.json +1 -1
- package/schemas/AgentReport.js +9 -1
- package/schemas/RenderState.js +11 -1
- package/schemas/RunEvent.js +9 -1
- package/testing.d.ts +8 -0
- package/utils/build-report.js +34 -8
- package/utils/coerce-error-text.js +60 -0
- package/utils/failure-signature.js +1 -0
- package/utils/format-fatal-error.js +14 -2
package/errors/DataStoreError.js
CHANGED
|
@@ -35,18 +35,35 @@ const extractSqlReason = (e) => {
|
|
|
35
35
|
while (node && typeof node === "object" && !seen.has(node)) {
|
|
36
36
|
seen.add(node);
|
|
37
37
|
const n = node;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
let msg;
|
|
39
|
+
let cause;
|
|
40
|
+
try {
|
|
41
|
+
msg = n.message;
|
|
42
|
+
} catch {
|
|
43
|
+
msg = void 0;
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
cause = n.cause;
|
|
47
|
+
} catch {
|
|
48
|
+
cause = void 0;
|
|
49
|
+
}
|
|
50
|
+
if (typeof msg === "string" && msg.length > 0) best = msg;
|
|
51
|
+
if (typeof cause === "string") {
|
|
52
|
+
if (cause.length > 0) best = cause;
|
|
41
53
|
break;
|
|
42
54
|
}
|
|
43
|
-
node =
|
|
55
|
+
node = cause;
|
|
44
56
|
}
|
|
45
57
|
if (best !== void 0) return best;
|
|
46
58
|
if (e && typeof e === "object") try {
|
|
47
|
-
|
|
59
|
+
const json = JSON.stringify(e);
|
|
60
|
+
if (json !== void 0) return json;
|
|
48
61
|
} catch {}
|
|
49
|
-
|
|
62
|
+
try {
|
|
63
|
+
return String(e);
|
|
64
|
+
} catch {
|
|
65
|
+
return "<unserializable error>";
|
|
66
|
+
}
|
|
50
67
|
};
|
|
51
68
|
|
|
52
69
|
//#endregion
|
package/index.d.ts
CHANGED
|
@@ -375,6 +375,16 @@ declare const RenderState: Schema.Struct<{
|
|
|
375
375
|
readonly detail: Schema.String;
|
|
376
376
|
readonly targetTool: Schema.optional<Schema.String>;
|
|
377
377
|
}>>;
|
|
378
|
+
/**
|
|
379
|
+
* Count of every collected module, passing modules included. Folded
|
|
380
|
+
* from `RunFinished.collectedModules`. Renderers prefer this over
|
|
381
|
+
* `moduleOrder.length` for "N modules all-passed" copy — a report
|
|
382
|
+
* replay only queues failing modules, so `moduleOrder` alone
|
|
383
|
+
* undercounts a green run to zero (issue #204). Optional — a run
|
|
384
|
+
* that never carried the field (older replay data, hand-built
|
|
385
|
+
* fixtures) falls back to `moduleOrder.length`.
|
|
386
|
+
*/
|
|
387
|
+
readonly collectedModules: Schema.optional<Schema.Number>;
|
|
378
388
|
}>;
|
|
379
389
|
/** @public */
|
|
380
390
|
type RenderState = typeof RenderState.Type;
|
|
@@ -519,6 +529,14 @@ declare const ReportSummary: Schema.Struct<{
|
|
|
519
529
|
readonly failed: Schema.Number;
|
|
520
530
|
readonly skipped: Schema.Number;
|
|
521
531
|
readonly duration: Schema.Number;
|
|
532
|
+
/**
|
|
533
|
+
* Count of every collected module, passing modules included.
|
|
534
|
+
* `AgentReport.failed` only carries failing modules, so a green run
|
|
535
|
+
* has no other way to know how many files actually ran — without
|
|
536
|
+
* this a fully-passing replay reads as "0 modules all-passed"
|
|
537
|
+
* (issue #204). Optional to keep existing fixtures/reports valid.
|
|
538
|
+
*/
|
|
539
|
+
readonly modules: Schema.optional<Schema.Number>;
|
|
522
540
|
}>;
|
|
523
541
|
/** @public */
|
|
524
542
|
type ReportSummary = typeof ReportSummary.Type;
|
|
@@ -603,6 +621,14 @@ declare const AgentReport: Schema.Struct<{
|
|
|
603
621
|
readonly failed: Schema.Number;
|
|
604
622
|
readonly skipped: Schema.Number;
|
|
605
623
|
readonly duration: Schema.Number;
|
|
624
|
+
/**
|
|
625
|
+
* Count of every collected module, passing modules included.
|
|
626
|
+
* `AgentReport.failed` only carries failing modules, so a green run
|
|
627
|
+
* has no other way to know how many files actually ran — without
|
|
628
|
+
* this a fully-passing replay reads as "0 modules all-passed"
|
|
629
|
+
* (issue #204). Optional to keep existing fixtures/reports valid.
|
|
630
|
+
*/
|
|
631
|
+
readonly modules: Schema.optional<Schema.Number>;
|
|
606
632
|
}>;
|
|
607
633
|
readonly failed: Schema.$Array<Schema.Struct<{
|
|
608
634
|
readonly file: Schema.String;
|
|
@@ -1090,6 +1116,14 @@ declare const RunEvent: Schema.Union<readonly [Schema.TaggedStruct<"RunStarted",
|
|
|
1090
1116
|
readonly skipCount: Schema.Number;
|
|
1091
1117
|
readonly durationMs: Schema.Number;
|
|
1092
1118
|
readonly timeoutCount: Schema.optional<Schema.Number>;
|
|
1119
|
+
/**
|
|
1120
|
+
* Count of every collected module, passing modules included.
|
|
1121
|
+
* Carries `AgentReport.summary.modules` (or the live module
|
|
1122
|
+
* count) into the event stream so the reducer can fold the
|
|
1123
|
+
* true count into `RenderState` even when `moduleOrder` only
|
|
1124
|
+
* tracks failing modules (report replay). See issue #204.
|
|
1125
|
+
*/
|
|
1126
|
+
readonly collectedModules: Schema.optional<Schema.Number>;
|
|
1093
1127
|
}>]>;
|
|
1094
1128
|
/** @public */
|
|
1095
1129
|
type RunEvent = typeof RunEvent.Type;
|
|
@@ -4457,6 +4491,12 @@ interface VitestTestSuite {
|
|
|
4457
4491
|
line: number;
|
|
4458
4492
|
column: number;
|
|
4459
4493
|
};
|
|
4494
|
+
/**
|
|
4495
|
+
* Errors attached to the suite entity itself — a `beforeAll`/`afterAll`
|
|
4496
|
+
* hook throw lands here, not on any individual `TestCase`. Optional
|
|
4497
|
+
* because older duck-typed callers may not supply it.
|
|
4498
|
+
*/
|
|
4499
|
+
errors?(): Array<VitestModuleError>;
|
|
4460
4500
|
}
|
|
4461
4501
|
/**
|
|
4462
4502
|
* Duck-typed Vitest TestModule from the Reporter v2 API.
|
|
@@ -4564,6 +4604,42 @@ declare function classifyTest(current: "passed" | "failed", priorRuns: ReadonlyA
|
|
|
4564
4604
|
state: string;
|
|
4565
4605
|
}>): TestClassification;
|
|
4566
4606
|
//#endregion
|
|
4607
|
+
//#region src/utils/coerce-error-text.d.ts
|
|
4608
|
+
/**
|
|
4609
|
+
* Coerce an unknown error-field value (message, name, diff, stack, ...) into a
|
|
4610
|
+
* string that is safe to bind to a SQLite TEXT column or render to a terminal.
|
|
4611
|
+
*
|
|
4612
|
+
* Vitest failure values are typed as strings but are whatever the test threw:
|
|
4613
|
+
* `Effect.flip` on an unexpectedly-succeeding effect puts arbitrary success
|
|
4614
|
+
* values (routinely plain objects) into the error channel, and Effect's
|
|
4615
|
+
* `ConfigError.message` is a getter that throws when its cause lacks
|
|
4616
|
+
* `toString`. Every access here is exception-safe.
|
|
4617
|
+
*
|
|
4618
|
+
* - `undefined` / `null` → `undefined` (caller decides null vs sentinel)
|
|
4619
|
+
* - string → unchanged
|
|
4620
|
+
* - other primitives → `String(value)`
|
|
4621
|
+
* - objects → `JSON.stringify`, falling back to `String(value)`, falling back
|
|
4622
|
+
* to `"<unserializable>"` when both throw
|
|
4623
|
+
*
|
|
4624
|
+
* @public
|
|
4625
|
+
*/
|
|
4626
|
+
declare const coerceErrorText: (value: unknown) => string | undefined;
|
|
4627
|
+
/**
|
|
4628
|
+
* Read a named field off an unknown error-like value and coerce it with
|
|
4629
|
+
* {@link coerceErrorText}, guarding the property access itself. A live getter
|
|
4630
|
+
* that throws (Effect's `ConfigError.message` when its cause lacks
|
|
4631
|
+
* `toString`) throws at the read site — `coerceErrorText(e.message)` never
|
|
4632
|
+
* reaches the helper's own exception handling. Route every read of an
|
|
4633
|
+
* untrusted error object's field through this helper instead.
|
|
4634
|
+
*
|
|
4635
|
+
* - `null` / non-object sources → `undefined`
|
|
4636
|
+
* - a getter that throws → `"<unreadable field>"`
|
|
4637
|
+
* - otherwise → `coerceErrorText(value)`
|
|
4638
|
+
*
|
|
4639
|
+
* @public
|
|
4640
|
+
*/
|
|
4641
|
+
declare const coerceErrorField: (source: unknown, key: string) => string | undefined;
|
|
4642
|
+
//#endregion
|
|
4567
4643
|
//#region src/utils/compress-lines.d.ts
|
|
4568
4644
|
/**
|
|
4569
4645
|
* Compress an array of line numbers into a compact range string.
|
|
@@ -5205,5 +5281,5 @@ declare function validateCoverageTargetsShape(input: unknown): CoverageTargetsSh
|
|
|
5205
5281
|
*/
|
|
5206
5282
|
declare const CURRENT_SDK_VERSION: string;
|
|
5207
5283
|
//#endregion
|
|
5208
|
-
export { AcceptanceMetrics, ActionSeverity, ActorType, Agent, AgentConsoleMode, AgentContext, AgentId, AgentNotFoundError, AgentPluginOptions, AgentReport, AgentReporterOptions, AgentTreeNode, AnsiOptions, ArtifactKind, AssembledHistoryRecord, AssociateRunSessionInput, BehaviorAbandonedEvent, BehaviorAddedEvent, BehaviorCompletedEvent, BehaviorDetail, BehaviorNotFoundError, BehaviorRow, BehaviorScopedEventType, BehaviorScopedEventTypes, BehaviorStartedEvent, BehaviorStatus, BehaviorsReadyEvent, BlockedEvent, CURRENT_SDK_VERSION, CacheManifest, CacheManifestEntry, CandidateContext, CellOptions, ChangeKind, ChannelEvent, ChatId, CiConsoleMode, CitedArtifact, CitedArtifactRow, CommitChangesEntry, ConfigLive, ConsoleFormatOptions, ConsoleLeakEntry, ConsoleLeakFile, ConsoleLeakTask, ConsoleLeaks, ConsoleLogLevel, ConsoleMode, ConsoleOutputMode, ConsoleOutputs, ConversationId, ConversationNotFoundError, CoverageBaselines, FileCoverageReport as CoverageFile, FileCoverageReport, CoverageGap, CoverageInput, CoverageLevel, CoverageLevelName, CoverageMetric, CoverageRenderState, CoverageReport, CoverageTargets, CoverageTargetsMetrics, CoverageTargetsShapeError, CoverageTargetsShapeInfo, CoverageTargetsShapeResult, CoverageTargetsShapeWarning, CoverageTotals, CreateBehaviorInput, CreateGoalInput, CurrentTddPhase, DATABASE_FILENAME, DataReader, DataReaderLive, DataStore, DataStoreError, DataStoreLive, DenialReason, DetailLevel, DetailResolver, DetailResolverLive, DiscoveryError, DiscoveryRegistry, DiscoveryRegistryLive, DispatchInputs, EndTddTaskInput, Environment, EnvironmentDetector, EnvironmentDetectorLive, EnvironmentDetectorTest, Executor, ExecutorResolver, ExecutorResolverLive, FailureRecord, FailureSignatureDetail, FailureSignatureInput, FailureSignatureWriteInput, FileCoverageInput, FileEditPayload, FileSystemAdapter, FlakyTest, FormatSelector, FormatSelectorLive, type FormatTriageOptions, type FormatWrapupOptions, Formatter, FormatterContext, FunctionBoundary, GfmFormatter, GitCommandError, GoalAbandonedEvent, GoalAddedEvent, GoalCompletedEvent, GoalDetail, GoalNotFoundError, GoalRow, GoalStartedEvent, GoalStatus, GoalsReadyEvent, HistoryRecord, HistoryRow, HistoryTracker, HistoryTrackerLive, HistoryTrackerTest, HistoryTrackerTestState, HookFirePayload, HookStatus, HookType, HostKind, HostMetadataParseError, HostMetadataResult, HumanConsoleMode, HypothesisDetail, HypothesisInput, HypothesisPayload, IDEMPOTENCY_ROOT_SENTINEL, IdempotencyHit, IdempotencyInput, IdempotentResponseInput, IllegalStatusTransitionEntity, IllegalStatusTransitionError, JsonFormatter, KnownProject, KnownProjectInput, LoggerLive, ManifestRow, MapSessionInput, MapSessionOutput, MarkdownFormatter, MetricThresholds, ModuleInput, ModuleListEntry, ModuleRecord, ModuleReport, NoteInput, NotePayload, NoteRow, Osc8Options, OutputFormat, OutputPipelineLive, OutputRenderer, OutputRendererLive, PackageManager, PathResolutionError, PathResolutionLive, PatternThresholds, PerClientSessionMapReader, PerClientSessionMapReaderLive, PerClientSessionMapWriter, PerClientSessionMapWriterLive, PersistentFailure, Phase, PhaseTransitionContext, PhaseTransitionEvent, PhaseTransitionResult, ProbeMissError, ProjectDiscovery, ProjectDiscoveryLive, ProjectDiscoveryTest, ProjectIdentity, ProjectIdentityCandidate, ProjectIdentityCandidates, ProjectIdentityLive, ProjectIdentityNotResolvableError, ProjectIdentitySource, ProjectIdentityTest, ProjectKey, ProjectRunSummary, ProjectSummary, RegisterAgentInput, RegisterAgentResult, RegistrationConflictError, Remediation, RenderState, RenderTotals, RenderedOutput, ReportError, ReportSummary, ReporterKit, ReporterRenderInput, ResolveDataPathOptions, ResolveProjectIdentityOptions, ResolvedIdentity, ResolvedReporterConfig, ResolvedThresholds, RunChangedFile, RunContext, RunContext$, RunContextLive, RunContextService, RunContextTest, RunEvent, RunEventByTag, RunHealth, RunInvocationMethod, RunOutcome, RunShape, SessionCompleteEvent, SessionContextRow, SessionDetail, SessionInput, SessionNotFoundError, SessionOutcome, SettingsInput, SettingsListEntry, SettingsRow, SidecarTimeoutError, SilentFormatter, StackFrameInput, SuggestedActionRecord, SuiteInput, SuiteListEntry, TagCountEntry, TagInventoryRow, TddArtifactDetail, TddArtifactRow, TddPhaseDetail, TddTaskAlreadyEndedError, TddTaskDetail, TddTaskEndOutcome, TddTaskId, TddTaskInput, TddTaskNotFoundError, TddTaskSummary, TerminalFormatter, TestCaseInput, TestClassification, TestError, TestErrorInput, TestFileEntry, TestHistory, TestListEntry, TestOutcome, TestRecord, TestReport, TestRun, TestRunInput, TestRunReason, TestState, ToolCallPayload, ToolResultPayload, Transport, TrendEntry, TrendRecord, TrendSummary, TurnInput, TurnPayload, TurnSearchOptions, TurnSummary, UpdateBehaviorInput, UpdateGoalInput, UserPromptPayload, ValidateHypothesisInput, VitestAgentConfig, VitestAgentConfigFile, VitestAgentConfigFileService, VitestAgentReporter, VitestAgentReporterFactory, VitestModuleDiagnostic, VitestModuleError, VitestParsedStack, VitestTestCase, VitestTestDiagnostic, VitestTestError, VitestTestModule, VitestTestResult, VitestTestSuite, type WrapupKind, WriteCommitInput, WriteRunChangedFilesInput, WriteTddArtifactInput, WriteTddPhaseInput, WriteTddPhaseOutput, _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 };
|
|
5284
|
+
export { AcceptanceMetrics, ActionSeverity, ActorType, Agent, AgentConsoleMode, AgentContext, AgentId, AgentNotFoundError, AgentPluginOptions, AgentReport, AgentReporterOptions, AgentTreeNode, AnsiOptions, ArtifactKind, AssembledHistoryRecord, AssociateRunSessionInput, BehaviorAbandonedEvent, BehaviorAddedEvent, BehaviorCompletedEvent, BehaviorDetail, BehaviorNotFoundError, BehaviorRow, BehaviorScopedEventType, BehaviorScopedEventTypes, BehaviorStartedEvent, BehaviorStatus, BehaviorsReadyEvent, BlockedEvent, CURRENT_SDK_VERSION, CacheManifest, CacheManifestEntry, CandidateContext, CellOptions, ChangeKind, ChannelEvent, ChatId, CiConsoleMode, CitedArtifact, CitedArtifactRow, CommitChangesEntry, ConfigLive, ConsoleFormatOptions, ConsoleLeakEntry, ConsoleLeakFile, ConsoleLeakTask, ConsoleLeaks, ConsoleLogLevel, ConsoleMode, ConsoleOutputMode, ConsoleOutputs, ConversationId, ConversationNotFoundError, CoverageBaselines, FileCoverageReport as CoverageFile, FileCoverageReport, CoverageGap, CoverageInput, CoverageLevel, CoverageLevelName, CoverageMetric, CoverageRenderState, CoverageReport, CoverageTargets, CoverageTargetsMetrics, CoverageTargetsShapeError, CoverageTargetsShapeInfo, CoverageTargetsShapeResult, CoverageTargetsShapeWarning, CoverageTotals, CreateBehaviorInput, CreateGoalInput, CurrentTddPhase, DATABASE_FILENAME, DataReader, DataReaderLive, DataStore, DataStoreError, DataStoreLive, DenialReason, DetailLevel, DetailResolver, DetailResolverLive, DiscoveryError, DiscoveryRegistry, DiscoveryRegistryLive, DispatchInputs, EndTddTaskInput, Environment, EnvironmentDetector, EnvironmentDetectorLive, EnvironmentDetectorTest, Executor, ExecutorResolver, ExecutorResolverLive, FailureRecord, FailureSignatureDetail, FailureSignatureInput, FailureSignatureWriteInput, FileCoverageInput, FileEditPayload, FileSystemAdapter, FlakyTest, FormatSelector, FormatSelectorLive, type FormatTriageOptions, type FormatWrapupOptions, Formatter, FormatterContext, FunctionBoundary, GfmFormatter, GitCommandError, GoalAbandonedEvent, GoalAddedEvent, GoalCompletedEvent, GoalDetail, GoalNotFoundError, GoalRow, GoalStartedEvent, GoalStatus, GoalsReadyEvent, HistoryRecord, HistoryRow, HistoryTracker, HistoryTrackerLive, HistoryTrackerTest, HistoryTrackerTestState, HookFirePayload, HookStatus, HookType, HostKind, HostMetadataParseError, HostMetadataResult, HumanConsoleMode, HypothesisDetail, HypothesisInput, HypothesisPayload, IDEMPOTENCY_ROOT_SENTINEL, IdempotencyHit, IdempotencyInput, IdempotentResponseInput, IllegalStatusTransitionEntity, IllegalStatusTransitionError, JsonFormatter, KnownProject, KnownProjectInput, LoggerLive, ManifestRow, MapSessionInput, MapSessionOutput, MarkdownFormatter, MetricThresholds, ModuleInput, ModuleListEntry, ModuleRecord, ModuleReport, NoteInput, NotePayload, NoteRow, Osc8Options, OutputFormat, OutputPipelineLive, OutputRenderer, OutputRendererLive, PackageManager, PathResolutionError, PathResolutionLive, PatternThresholds, PerClientSessionMapReader, PerClientSessionMapReaderLive, PerClientSessionMapWriter, PerClientSessionMapWriterLive, PersistentFailure, Phase, PhaseTransitionContext, PhaseTransitionEvent, PhaseTransitionResult, ProbeMissError, ProjectDiscovery, ProjectDiscoveryLive, ProjectDiscoveryTest, ProjectIdentity, ProjectIdentityCandidate, ProjectIdentityCandidates, ProjectIdentityLive, ProjectIdentityNotResolvableError, ProjectIdentitySource, ProjectIdentityTest, ProjectKey, ProjectRunSummary, ProjectSummary, RegisterAgentInput, RegisterAgentResult, RegistrationConflictError, Remediation, RenderState, RenderTotals, RenderedOutput, ReportError, ReportSummary, ReporterKit, ReporterRenderInput, ResolveDataPathOptions, ResolveProjectIdentityOptions, ResolvedIdentity, ResolvedReporterConfig, ResolvedThresholds, RunChangedFile, RunContext, RunContext$, RunContextLive, RunContextService, RunContextTest, RunEvent, RunEventByTag, RunHealth, RunInvocationMethod, RunOutcome, RunShape, SessionCompleteEvent, SessionContextRow, SessionDetail, SessionInput, SessionNotFoundError, SessionOutcome, SettingsInput, SettingsListEntry, SettingsRow, SidecarTimeoutError, SilentFormatter, StackFrameInput, SuggestedActionRecord, SuiteInput, SuiteListEntry, TagCountEntry, TagInventoryRow, TddArtifactDetail, TddArtifactRow, TddPhaseDetail, TddTaskAlreadyEndedError, TddTaskDetail, TddTaskEndOutcome, TddTaskId, TddTaskInput, TddTaskNotFoundError, TddTaskSummary, TerminalFormatter, TestCaseInput, TestClassification, TestError, TestErrorInput, TestFileEntry, TestHistory, TestListEntry, TestOutcome, TestRecord, TestReport, TestRun, TestRunInput, TestRunReason, TestState, ToolCallPayload, ToolResultPayload, Transport, TrendEntry, TrendRecord, TrendSummary, TurnInput, TurnPayload, TurnSearchOptions, TurnSummary, UpdateBehaviorInput, UpdateGoalInput, UserPromptPayload, ValidateHypothesisInput, VitestAgentConfig, VitestAgentConfigFile, VitestAgentConfigFileService, VitestAgentReporter, VitestAgentReporterFactory, VitestModuleDiagnostic, VitestModuleError, VitestParsedStack, VitestTestCase, VitestTestDiagnostic, VitestTestError, VitestTestModule, VitestTestResult, VitestTestSuite, type WrapupKind, WriteCommitInput, WriteRunChangedFilesInput, WriteTddArtifactInput, WriteTddPhaseInput, WriteTddPhaseOutput, _resetMigrationCacheForTesting, ansi, assembleHistoryRecord, assembleManifest, buildAgentReport, buildConsoleLeaks, buildEnvPrefix, canonicalizeGitUrl, ciAnnotationsFormatter, classifyTest, coerceErrorField, coerceErrorText, 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 };
|
|
5209
5285
|
//# sourceMappingURL=index.d.ts.map
|
package/index.js
CHANGED
|
@@ -25,6 +25,7 @@ import { DataReaderLive } from "./layers/DataReaderLive.js";
|
|
|
25
25
|
import { ActorType, AgentId, ChatId, ConversationId, HostKind, ProjectKey, TddTaskId } from "./schemas/Identity.js";
|
|
26
26
|
import { Agent, IdempotencyHit } from "./schemas/Agent.js";
|
|
27
27
|
import { DataStore } from "./services/DataStore.js";
|
|
28
|
+
import { coerceErrorField, coerceErrorText } from "./utils/coerce-error-text.js";
|
|
28
29
|
import { DataStoreLive } from "./layers/DataStoreLive.js";
|
|
29
30
|
import { DetailResolver } from "./services/DetailResolver.js";
|
|
30
31
|
import { DetailResolverLive } from "./layers/DetailResolverLive.js";
|
|
@@ -115,7 +116,7 @@ import { requiredArtifactForTransition, transitionEnforcesBehaviorMatch, validat
|
|
|
115
116
|
* substituted yet. Exported for version introspection by downstream tooling.
|
|
116
117
|
* @public
|
|
117
118
|
*/
|
|
118
|
-
const CURRENT_SDK_VERSION = "2.0
|
|
119
|
+
const CURRENT_SDK_VERSION = "2.1.0";
|
|
119
120
|
|
|
120
121
|
//#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, 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 };
|
|
122
|
+
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, coerceErrorField, coerceErrorText, 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/DataStoreLive.js
CHANGED
|
@@ -3,6 +3,7 @@ import { DataStoreError, extractSqlReason } from "../errors/DataStoreError.js";
|
|
|
3
3
|
import { BehaviorNotFoundError, GoalNotFoundError, IllegalStatusTransitionError, TddTaskAlreadyEndedError, TddTaskNotFoundError } from "../errors/TddErrors.js";
|
|
4
4
|
import { Agent, IdempotencyHit } from "../schemas/Agent.js";
|
|
5
5
|
import { DataStore } from "../services/DataStore.js";
|
|
6
|
+
import { coerceErrorText } from "../utils/coerce-error-text.js";
|
|
6
7
|
import { Effect, Layer, Option } from "effect";
|
|
7
8
|
import { SqlClient } from "effect/unstable/sql/SqlClient";
|
|
8
9
|
import { randomUUID } from "node:crypto";
|
|
@@ -134,16 +135,18 @@ const DataStoreLive = Layer.effect(DataStore, Effect.gen(function* () {
|
|
|
134
135
|
count: errors.length
|
|
135
136
|
}));
|
|
136
137
|
for (const err of errors) {
|
|
137
|
-
|
|
138
|
+
const message = coerceErrorText(err.message) ?? "<missing message>";
|
|
139
|
+
yield* sql`INSERT INTO test_errors (run_id, test_case_id, test_suite_id, module_id, scope, name, message, diff, actual, expected, stack, cause_error_id, signature_hash, ordinal) VALUES (${runId}, ${err.testCaseId ?? null}, ${err.testSuiteId ?? null}, ${err.moduleId ?? null}, ${err.scope}, ${coerceErrorText(err.name) ?? null}, ${message}, ${coerceErrorText(err.diff) ?? null}, ${coerceErrorText(err.actual) ?? null}, ${coerceErrorText(err.expected) ?? null}, ${coerceErrorText(err.stack) ?? null}, ${err.causeErrorId ?? null}, ${err.signatureHash ?? null}, ${err.ordinal ?? 0})`;
|
|
140
|
+
const stackText = coerceErrorText(err.stack);
|
|
138
141
|
if (err.frames && err.frames.length > 0) {
|
|
139
142
|
const errorId = (yield* sql`SELECT last_insert_rowid() as id`)[0].id;
|
|
140
143
|
for (const frame of err.frames) {
|
|
141
144
|
const fileId = yield* ensureFile(frame.filePath);
|
|
142
145
|
yield* sql`INSERT INTO stack_frames (error_id, ordinal, method, file_id, line, col, source_mapped_line, function_boundary_line) VALUES (${errorId}, ${frame.ordinal}, ${frame.method}, ${fileId}, ${frame.line}, ${frame.col}, ${frame.sourceMappedLine ?? null}, ${frame.functionBoundaryLine ?? null})`;
|
|
143
146
|
}
|
|
144
|
-
} else if (
|
|
147
|
+
} else if (stackText) {
|
|
145
148
|
const errorId = (yield* sql`SELECT last_insert_rowid() as id`)[0].id;
|
|
146
|
-
const frames = [...
|
|
149
|
+
const frames = [...stackText.matchAll(/at\s+(?:(.+?)\s+)?\(?(.+?):(\d+):(\d+)\)?/g)];
|
|
147
150
|
for (let frameOrdinal = 0; frameOrdinal < frames.length; frameOrdinal++) {
|
|
148
151
|
const m = frames[frameOrdinal];
|
|
149
152
|
const method = m[1] ?? null;
|
package/package.json
CHANGED
package/schemas/AgentReport.js
CHANGED
|
@@ -13,7 +13,15 @@ const ReportSummary = Schema.Struct({
|
|
|
13
13
|
passed: Schema.Number,
|
|
14
14
|
failed: Schema.Number,
|
|
15
15
|
skipped: Schema.Number,
|
|
16
|
-
duration: Schema.Number
|
|
16
|
+
duration: Schema.Number,
|
|
17
|
+
/**
|
|
18
|
+
* Count of every collected module, passing modules included.
|
|
19
|
+
* `AgentReport.failed` only carries failing modules, so a green run
|
|
20
|
+
* has no other way to know how many files actually ran — without
|
|
21
|
+
* this a fully-passing replay reads as "0 modules all-passed"
|
|
22
|
+
* (issue #204). Optional to keep existing fixtures/reports valid.
|
|
23
|
+
*/
|
|
24
|
+
modules: Schema.optional(Schema.Number)
|
|
17
25
|
}).annotate({ identifier: "ReportSummary" });
|
|
18
26
|
/**
|
|
19
27
|
* An individual test case result.
|
package/schemas/RenderState.js
CHANGED
|
@@ -135,7 +135,17 @@ const RenderState = Schema.Struct({
|
|
|
135
135
|
runCount: Schema.Number
|
|
136
136
|
})),
|
|
137
137
|
failures: Schema.Array(FailureRecord),
|
|
138
|
-
suggestedActions: Schema.Array(SuggestedActionRecord)
|
|
138
|
+
suggestedActions: Schema.Array(SuggestedActionRecord),
|
|
139
|
+
/**
|
|
140
|
+
* Count of every collected module, passing modules included. Folded
|
|
141
|
+
* from `RunFinished.collectedModules`. Renderers prefer this over
|
|
142
|
+
* `moduleOrder.length` for "N modules all-passed" copy — a report
|
|
143
|
+
* replay only queues failing modules, so `moduleOrder` alone
|
|
144
|
+
* undercounts a green run to zero (issue #204). Optional — a run
|
|
145
|
+
* that never carried the field (older replay data, hand-built
|
|
146
|
+
* fixtures) falls back to `moduleOrder.length`.
|
|
147
|
+
*/
|
|
148
|
+
collectedModules: Schema.optional(Schema.Number)
|
|
139
149
|
}).annotate({ identifier: "RenderState" });
|
|
140
150
|
/**
|
|
141
151
|
* Initial state — what the reducer returns when no events have been
|
package/schemas/RunEvent.js
CHANGED
|
@@ -194,7 +194,15 @@ const RunEvent = Schema.Union([
|
|
|
194
194
|
failCount: Schema.Number,
|
|
195
195
|
skipCount: Schema.Number,
|
|
196
196
|
durationMs: Schema.Number,
|
|
197
|
-
timeoutCount: Schema.optional(Schema.Number)
|
|
197
|
+
timeoutCount: Schema.optional(Schema.Number),
|
|
198
|
+
/**
|
|
199
|
+
* Count of every collected module, passing modules included.
|
|
200
|
+
* Carries `AgentReport.summary.modules` (or the live module
|
|
201
|
+
* count) into the event stream so the reducer can fold the
|
|
202
|
+
* true count into `RenderState` even when `moduleOrder` only
|
|
203
|
+
* tracks failing modules (report replay). See issue #204.
|
|
204
|
+
*/
|
|
205
|
+
collectedModules: Schema.optional(Schema.Number)
|
|
198
206
|
})
|
|
199
207
|
]).annotate({ identifier: "RunEvent" });
|
|
200
208
|
|
package/testing.d.ts
CHANGED
|
@@ -36,6 +36,14 @@ declare const AgentReport: Schema.Struct<{
|
|
|
36
36
|
readonly failed: Schema.Number;
|
|
37
37
|
readonly skipped: Schema.Number;
|
|
38
38
|
readonly duration: Schema.Number;
|
|
39
|
+
/**
|
|
40
|
+
* Count of every collected module, passing modules included.
|
|
41
|
+
* `AgentReport.failed` only carries failing modules, so a green run
|
|
42
|
+
* has no other way to know how many files actually ran — without
|
|
43
|
+
* this a fully-passing replay reads as "0 modules all-passed"
|
|
44
|
+
* (issue #204). Optional to keep existing fixtures/reports valid.
|
|
45
|
+
*/
|
|
46
|
+
readonly modules: Schema.optional<Schema.Number>;
|
|
39
47
|
}>;
|
|
40
48
|
readonly failed: Schema.$Array<Schema.Struct<{
|
|
41
49
|
readonly file: Schema.String;
|
package/utils/build-report.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { coerceErrorField } from "./coerce-error-text.js";
|
|
2
|
+
|
|
1
3
|
//#region src/utils/build-report.ts
|
|
2
4
|
/**
|
|
3
5
|
* Format a single Vitest stack frame: strings pass through; ParsedStack
|
|
@@ -18,10 +20,23 @@ function formatStackFrame(frame) {
|
|
|
18
20
|
function mapErrors(errors) {
|
|
19
21
|
if (!errors || errors.length === 0) return void 0;
|
|
20
22
|
return errors.map((e) => {
|
|
23
|
+
const diffText = coerceErrorField(e, "diff");
|
|
24
|
+
let stacks;
|
|
25
|
+
try {
|
|
26
|
+
stacks = e.stacks;
|
|
27
|
+
} catch {
|
|
28
|
+
stacks = void 0;
|
|
29
|
+
}
|
|
30
|
+
let stackText;
|
|
31
|
+
try {
|
|
32
|
+
stackText = stacks && stacks.length > 0 ? stacks.map(formatStackFrame).join("\n") : void 0;
|
|
33
|
+
} catch {
|
|
34
|
+
stackText = void 0;
|
|
35
|
+
}
|
|
21
36
|
return {
|
|
22
|
-
message: e
|
|
23
|
-
...
|
|
24
|
-
...
|
|
37
|
+
message: coerceErrorField(e, "message") ?? "<missing message>",
|
|
38
|
+
...diffText !== void 0 ? { diff: diffText } : {},
|
|
39
|
+
...stackText !== void 0 ? { stack: stackText } : {}
|
|
25
40
|
};
|
|
26
41
|
});
|
|
27
42
|
}
|
|
@@ -68,6 +83,13 @@ function buildAgentReport(testModules, unhandledErrors, reason, options, project
|
|
|
68
83
|
totalDuration += moduleDuration;
|
|
69
84
|
const moduleState = normalizeState(testModule.state());
|
|
70
85
|
const moduleErrors = mapErrors(testModule.errors());
|
|
86
|
+
const suiteErrors = [];
|
|
87
|
+
let anySuiteFailed = false;
|
|
88
|
+
for (const suite of testModule.children.allSuites()) {
|
|
89
|
+
if (normalizeState(suite.state()) === "failed") anySuiteFailed = true;
|
|
90
|
+
const mapped = mapErrors(suite.errors?.());
|
|
91
|
+
if (mapped) suiteErrors.push(...mapped);
|
|
92
|
+
}
|
|
71
93
|
const allTests = [...testModule.children.allTests()];
|
|
72
94
|
const testReports = [];
|
|
73
95
|
let moduleHasFailure = false;
|
|
@@ -96,29 +118,33 @@ function buildAgentReport(testModules, unhandledErrors, reason, options, project
|
|
|
96
118
|
testReports.push(testReport);
|
|
97
119
|
}
|
|
98
120
|
}
|
|
99
|
-
|
|
121
|
+
const combinedErrors = [...moduleErrors ?? [], ...suiteErrors];
|
|
122
|
+
const moduleLevelFailure = moduleState === "failed" || anySuiteFailed || combinedErrors.length > 0;
|
|
123
|
+
if (moduleHasFailure || moduleLevelFailure) {
|
|
100
124
|
failedFiles.push(testModule.relativeModuleId);
|
|
101
125
|
const moduleReport = {
|
|
102
126
|
file: testModule.relativeModuleId,
|
|
103
|
-
state: moduleState,
|
|
127
|
+
state: moduleLevelFailure ? "failed" : moduleState,
|
|
104
128
|
duration: moduleDuration,
|
|
105
129
|
tests: testReports,
|
|
106
|
-
...
|
|
130
|
+
...combinedErrors.length > 0 ? { errors: combinedErrors } : {}
|
|
107
131
|
};
|
|
108
132
|
failedModules.push(moduleReport);
|
|
109
133
|
}
|
|
110
134
|
}
|
|
111
135
|
const mappedUnhandled = mapErrors(unhandledErrors) ?? [];
|
|
136
|
+
const effectiveReason = reason === "passed" && (failedFiles.length > 0 || mappedUnhandled.length > 0) ? "failed" : reason;
|
|
112
137
|
return {
|
|
113
138
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
114
139
|
...projectName != null ? { project: projectName } : {},
|
|
115
|
-
reason,
|
|
140
|
+
reason: effectiveReason,
|
|
116
141
|
summary: {
|
|
117
142
|
total: totalCount,
|
|
118
143
|
passed: passedCount,
|
|
119
144
|
failed: failedCount,
|
|
120
145
|
skipped: skippedCount,
|
|
121
|
-
duration: totalDuration
|
|
146
|
+
duration: totalDuration,
|
|
147
|
+
modules: testModules.length
|
|
122
148
|
},
|
|
123
149
|
failed: failedModules,
|
|
124
150
|
unhandledErrors: mappedUnhandled,
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
//#region src/utils/coerce-error-text.ts
|
|
2
|
+
/**
|
|
3
|
+
* Coerce an unknown error-field value (message, name, diff, stack, ...) into a
|
|
4
|
+
* string that is safe to bind to a SQLite TEXT column or render to a terminal.
|
|
5
|
+
*
|
|
6
|
+
* Vitest failure values are typed as strings but are whatever the test threw:
|
|
7
|
+
* `Effect.flip` on an unexpectedly-succeeding effect puts arbitrary success
|
|
8
|
+
* values (routinely plain objects) into the error channel, and Effect's
|
|
9
|
+
* `ConfigError.message` is a getter that throws when its cause lacks
|
|
10
|
+
* `toString`. Every access here is exception-safe.
|
|
11
|
+
*
|
|
12
|
+
* - `undefined` / `null` → `undefined` (caller decides null vs sentinel)
|
|
13
|
+
* - string → unchanged
|
|
14
|
+
* - other primitives → `String(value)`
|
|
15
|
+
* - objects → `JSON.stringify`, falling back to `String(value)`, falling back
|
|
16
|
+
* to `"<unserializable>"` when both throw
|
|
17
|
+
*
|
|
18
|
+
* @public
|
|
19
|
+
*/
|
|
20
|
+
const coerceErrorText = (value) => {
|
|
21
|
+
if (value === void 0 || value === null) return void 0;
|
|
22
|
+
if (typeof value === "string") return value;
|
|
23
|
+
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") return String(value);
|
|
24
|
+
try {
|
|
25
|
+
return JSON.stringify(value) ?? "<unserializable>";
|
|
26
|
+
} catch {
|
|
27
|
+
try {
|
|
28
|
+
return String(value);
|
|
29
|
+
} catch {
|
|
30
|
+
return "<unserializable>";
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Read a named field off an unknown error-like value and coerce it with
|
|
36
|
+
* {@link coerceErrorText}, guarding the property access itself. A live getter
|
|
37
|
+
* that throws (Effect's `ConfigError.message` when its cause lacks
|
|
38
|
+
* `toString`) throws at the read site — `coerceErrorText(e.message)` never
|
|
39
|
+
* reaches the helper's own exception handling. Route every read of an
|
|
40
|
+
* untrusted error object's field through this helper instead.
|
|
41
|
+
*
|
|
42
|
+
* - `null` / non-object sources → `undefined`
|
|
43
|
+
* - a getter that throws → `"<unreadable field>"`
|
|
44
|
+
* - otherwise → `coerceErrorText(value)`
|
|
45
|
+
*
|
|
46
|
+
* @public
|
|
47
|
+
*/
|
|
48
|
+
const coerceErrorField = (source, key) => {
|
|
49
|
+
if (source === null || typeof source !== "object" && typeof source !== "function") return void 0;
|
|
50
|
+
let value;
|
|
51
|
+
try {
|
|
52
|
+
value = source[key];
|
|
53
|
+
} catch {
|
|
54
|
+
return "<unreadable field>";
|
|
55
|
+
}
|
|
56
|
+
return coerceErrorText(value);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
//#endregion
|
|
60
|
+
export { coerceErrorField, coerceErrorText };
|
|
@@ -15,6 +15,7 @@ const typeTagOf = (literal) => {
|
|
|
15
15
|
};
|
|
16
16
|
/** @public */
|
|
17
17
|
const normalizeAssertionShape = (message) => {
|
|
18
|
+
if (typeof message !== "string") return "";
|
|
18
19
|
const match = message.match(ASSERTION_REGEX);
|
|
19
20
|
if (match === null) return null;
|
|
20
21
|
const matcher = match[1];
|
|
@@ -21,11 +21,23 @@ function formatFatalError(err) {
|
|
|
21
21
|
const cause = err[FIBER_FAILURE_CAUSE_KEY];
|
|
22
22
|
if (Cause.isCause(cause)) detail = Cause.pretty(cause);
|
|
23
23
|
else detail = String(err);
|
|
24
|
-
} else if (err instanceof Error)
|
|
24
|
+
} else if (err instanceof Error) try {
|
|
25
|
+
detail = err.stack ?? err.message;
|
|
26
|
+
} catch {
|
|
27
|
+
let ctorName = "Error";
|
|
28
|
+
try {
|
|
29
|
+
ctorName = err.constructor?.name ?? "Error";
|
|
30
|
+
} catch {}
|
|
31
|
+
detail = `<unserializable ${ctorName}>`;
|
|
32
|
+
}
|
|
25
33
|
else if (err !== null && typeof err === "object") try {
|
|
26
34
|
detail = JSON.stringify(err, null, 2);
|
|
27
35
|
} catch {
|
|
28
|
-
|
|
36
|
+
try {
|
|
37
|
+
detail = String(err);
|
|
38
|
+
} catch {
|
|
39
|
+
detail = "<unserializable error>";
|
|
40
|
+
}
|
|
29
41
|
}
|
|
30
42
|
else detail = String(err);
|
|
31
43
|
return `${detail}\nPlease report at ${ISSUE_URL}`;
|