@opencraw/studio 0.0.6 → 0.0.7
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/dist/index.esm.js +536 -103
- package/dist/src/explain-why/index.d.ts +5 -0
- package/dist/src/explain-why/item-hint.algorithm.d.ts +13 -0
- package/dist/src/explain-why/why-sentence.mapper.d.ts +48 -0
- package/dist/src/explain-why/why.use-case.d.ts +26 -0
- package/dist/src/index.d.ts +4 -3
- package/dist/src/sample-run/index.d.ts +3 -1
- package/dist/src/sample-run/last-run.store.d.ts +17 -0
- package/dist/src/sample-run/run-sample.use-case.d.ts +12 -6
- package/dist/src/sample-run/sample-run-record.contract.d.ts +30 -1
- package/dist/src/studio-api/command.contract.d.ts +59 -0
- package/dist/src/studio-api/event.contract.d.ts +41 -1
- package/dist/src/studio-api/index.d.ts +6 -4
- package/dist/src/studio-api/why-view.contract.d.ts +16 -0
- package/dist/src/studio-server/explain-why.handler.d.ts +14 -0
- package/dist/src/studio-server/workspace.store.d.ts +4 -3
- package/dist/ui/assets/index-DV8i4Zza.js +13 -0
- package/dist/ui/index.html +1 -1
- package/package.json +2 -2
- package/dist/ui/assets/index-BfbrsfCv.js +0 -13
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { explainWhy } from './why.use-case.js';
|
|
2
|
+
export { buildWhySentence } from './why-sentence.mapper.js';
|
|
3
|
+
export type { WhyFacts, WhyStepFact } from './why-sentence.mapper.js';
|
|
4
|
+
export { hintFor } from './item-hint.algorithm.js';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A best-effort hint about what a missing value's bound id actually held in
|
|
3
|
+
* the scope snapshot: the keys of an object, or the length of a list — the
|
|
4
|
+
* fallback when there is no per-item DOM snapshot to compare a selector
|
|
5
|
+
* against (see `why-sentence.mapper.ts`'s doc comment for why the richer,
|
|
6
|
+
* "the item has `.price_new`" hint is out of this phase's scope).
|
|
7
|
+
*
|
|
8
|
+
* @param scope - The record's scope snapshot (`SampleRunRecord.scope`/`SampleRunRejected.scope`).
|
|
9
|
+
* @param boundId - The leading id the rule's `from` reads.
|
|
10
|
+
* @returns A short clause (no leading punctuation), or `undefined` when the id is not in scope or nothing useful can be said about it.
|
|
11
|
+
*/
|
|
12
|
+
export declare function hintFor(scope: Record<string, unknown> | undefined, boundId: string | undefined): string | undefined;
|
|
13
|
+
//# sourceMappingURL=item-hint.algorithm.d.ts.map
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { FieldTrace } from '@opencraw/core';
|
|
2
|
+
/** One step of the recipe that may have bound the missing value's source id, and how it went over the whole sample run (`sample-run`'s `SampleStepSummary`). */
|
|
3
|
+
export interface WhyStepFact {
|
|
4
|
+
path: string;
|
|
5
|
+
stepType: string;
|
|
6
|
+
stepId?: string;
|
|
7
|
+
outcome: 'ran' | 'skipped' | 'retried' | 'not-found';
|
|
8
|
+
error?: string;
|
|
9
|
+
}
|
|
10
|
+
/** Everything `buildWhySentence` needs to explain one missing or rejected value; gathered by `why.use-case.ts` from the last sample run's kept trace, scope and step summary. */
|
|
11
|
+
export interface WhyFacts {
|
|
12
|
+
field: string;
|
|
13
|
+
outcome: 'missing' | 'rejected';
|
|
14
|
+
/** The engine's own rejection reason (`record:reject`'s `reason`), for a rejected record. */
|
|
15
|
+
reason?: string;
|
|
16
|
+
/** The resolved missing-value policy (`nullable`, `default`, `null`, `fail`, `skip-record`), when the field could be found in the output recipe. */
|
|
17
|
+
policy?: string;
|
|
18
|
+
/** The field's mapping trace, when the record itself was emitted (a `missing` outcome only — a rejected record never reached `data`). */
|
|
19
|
+
trace?: FieldTrace;
|
|
20
|
+
/** The leading id the rule's `from` reads (`item` of `item.description`), when the rule could be found. */
|
|
21
|
+
boundId?: string;
|
|
22
|
+
/** The step that binds `boundId`, when one was found in the recipe. */
|
|
23
|
+
step?: WhyStepFact;
|
|
24
|
+
/** A best-effort hint about what the bound value actually held (phase 2's item snapshot gives a richer one for a CSS pick; this is the scope-only fallback — see this module's doc comment). */
|
|
25
|
+
hint?: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Builds the Why? tab's sentence (studio plan §4.4, issue #92) from the
|
|
29
|
+
* facts `why.use-case.ts` gathers: the value the mapping read (and each
|
|
30
|
+
* transform's effect on it), the step that bound its source id and whether
|
|
31
|
+
* it ran, was skipped, or bound nothing this recipe knows of, the
|
|
32
|
+
* missing-value policy that applied, and a hint about what was actually
|
|
33
|
+
* there instead.
|
|
34
|
+
*
|
|
35
|
+
* This is the scope-snapshot-only half of the design: phase 2's per-item DOM
|
|
36
|
+
* snapshot (the CSS-selector "the item has `.price_new`" hint the issue's
|
|
37
|
+
* example shows) is not wired in here — `sample-run` keeps the mapping's
|
|
38
|
+
* scope snapshot (bound ids and their values), not a per-`forEach`-item DOM
|
|
39
|
+
* capture, and building that link is a bigger integration than this phase's
|
|
40
|
+
* budget covers (see this package's `page-snapshot` slice, which captures a
|
|
41
|
+
* step's page for the content pane, not per-iteration). `hint`, when given,
|
|
42
|
+
* is instead built from the scope snapshot itself (`item-hint.algorithm.ts`).
|
|
43
|
+
*
|
|
44
|
+
* @param facts - What is known about the value.
|
|
45
|
+
* @returns One sentence, always ending in a period.
|
|
46
|
+
*/
|
|
47
|
+
export declare function buildWhySentence(facts: WhyFacts): string;
|
|
48
|
+
//# sourceMappingURL=why-sentence.mapper.d.ts.map
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { InputRecipe, OutputRecipe } from '@opencraw/core';
|
|
2
|
+
import type { LastRunCache } from '../sample-run/index.js';
|
|
3
|
+
import type { WhyTarget, WhyView } from '../studio-api/index.js';
|
|
4
|
+
/**
|
|
5
|
+
* Explains one missing or rejected value from a recipe's last sample run
|
|
6
|
+
* (issue #92's Why? tab, studio plan §4.4): the mapping trace and scope
|
|
7
|
+
* snapshot `run-sample` kept, the recipe's own rule and field for the
|
|
8
|
+
* missing-value policy, and the step that bound the value's source id — did
|
|
9
|
+
* it run, was it skipped, or does no step in this recipe bind it at all.
|
|
10
|
+
*
|
|
11
|
+
* @param folder - The workspace folder (to re-read the recipe pair: the last
|
|
12
|
+
* run only kept the run's own data, not the recipe text, and a save may
|
|
13
|
+
* have happened since).
|
|
14
|
+
* @param cache - The server's last-run cache (`sample-run`'s `LastRunCache`).
|
|
15
|
+
* @param loadPair - Loads the input/output recipe pair; injected so this
|
|
16
|
+
* stays testable without a real workspace folder (`sample-run`'s
|
|
17
|
+
* `loadRecipePair` in production).
|
|
18
|
+
* @param target - What was clicked.
|
|
19
|
+
* @returns The explanation.
|
|
20
|
+
* @throws Error when no sample run has finished for this recipe yet, or the target does not name a real record/field.
|
|
21
|
+
*/
|
|
22
|
+
export declare function explainWhy(folder: string, cache: LastRunCache, loadPair: (folder: string, recipeId: string) => Promise<{
|
|
23
|
+
input: InputRecipe;
|
|
24
|
+
output: OutputRecipe;
|
|
25
|
+
}>, target: WhyTarget): Promise<WhyView>;
|
|
26
|
+
//# sourceMappingURL=why.use-case.d.ts.map
|
package/dist/src/index.d.ts
CHANGED
|
@@ -3,8 +3,9 @@ export { startStudioServer } from './studio-server/index.js';
|
|
|
3
3
|
export type { StudioServer, StudioServerOptions } from './studio-server/index.js';
|
|
4
4
|
export { openWorkspace, saveRecipe } from './recipe-workspace/index.js';
|
|
5
5
|
export { runSample, loadRecipePair } from './sample-run/index.js';
|
|
6
|
-
export type { RecipePair, SampleRunCallbacks, SampleRunHandle, SampleRunRecord, SampleRunResult, SampleStoppedBy } from './sample-run/index.js';
|
|
6
|
+
export type { RecipePair, SampleRunCallbacks, SampleRunHandle, SampleRunRecord, SampleRunRejected, SampleRunResult, SampleStepSummary, SampleStoppedBy } from './sample-run/index.js';
|
|
7
7
|
export { fetchStartPage } from './page-snapshot/index.js';
|
|
8
|
-
export {
|
|
9
|
-
export
|
|
8
|
+
export type { WhyFacts, WhyStepFact } from './explain-why/index.js';
|
|
9
|
+
export { sampleBudgetSchema, openWorkspaceCommandSchema, runSampleCommandSchema, stopRunCommandSchema, saveRecipeCommandSchema, fetchStartPageCommandSchema, saveOutlineCommandSchema, takeSnapshotCommandSchema, verifySelectorCommandSchema, inferSelectorCommandSchema, missingWhyTargetSchema, rejectedWhyTargetSchema, whyTargetSchema, explainWhyCommandSchema, studioCommandSchema, stoppedBySchema, fieldTraceSchema, traceLineEventSchema, recordEventSchema, recordRejectedEventSchema, runFinishedEventSchema, workspaceChangedEventSchema, studioEventSchema, recipeIssueSchema, recipeListingSchema, workspaceViewSchema, sampleRunRecordSchema, sampleRunViewSchema, startPageViewSchema, snapshotViewSchema, verifySelectorViewSchema, fieldPickSchema, inferSelectorViewSchema, sentencePartSchema, outlineCardSchema, outlineBracketSchema, outlineNodeSchema, outlineViewSchema, whyViewSchema, } from './studio-api/index.js';
|
|
10
|
+
export type { SampleBudget, OpenWorkspaceCommand, RunSampleCommand, StopRunCommand, SaveRecipeCommand, FetchStartPageCommand, SaveOutlineCommand, TakeSnapshotCommand, VerifySelectorCommand, InferSelectorCommand, MissingWhyTarget, RejectedWhyTarget, WhyTarget, ExplainWhyCommand, StudioCommand, StoppedBy, FieldTraceView, TraceLineEvent, RecordEvent, RecordRejectedEvent, RunFinishedEvent, WorkspaceChangedEvent, StudioEvent, RecipeIssue, RecipeListing, WorkspaceView, SampleRunView, StartPageView, SnapshotView, VerifySelectorView, FieldPick, InferSelectorView, SentencePart, OutlineCard, OutlineBracket, OutlineNode, OutlineView, WhyView, } from './studio-api/index.js';
|
|
10
11
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -2,5 +2,7 @@ export { loadRecipePair } from './load-recipe-pair.use-case.js';
|
|
|
2
2
|
export type { RecipePair } from './load-recipe-pair.use-case.js';
|
|
3
3
|
export { runSample } from './run-sample.use-case.js';
|
|
4
4
|
export type { SampleRunCallbacks, SampleRunHandle } from './run-sample.use-case.js';
|
|
5
|
-
export type { SampleRunRecord, SampleRunResult, SampleStoppedBy } from './sample-run-record.contract.js';
|
|
5
|
+
export type { SampleRunRecord, SampleRunRejected, SampleRunResult, SampleStepSummary, SampleStoppedBy } from './sample-run-record.contract.js';
|
|
6
|
+
export { createLastRunCache, lastRunOf, recordLastRun } from './last-run.store.js';
|
|
7
|
+
export type { LastRunCache, LastRunEntry } from './last-run.store.js';
|
|
6
8
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { SampleRunResult } from './sample-run-record.contract.js';
|
|
2
|
+
/** The last completed sample run of one input recipe: its records, rejections, mapping traces and step summary, kept for `explain-why` (issue #92) so a Why? click needs no second run. */
|
|
3
|
+
export interface LastRunEntry {
|
|
4
|
+
recipeId: string;
|
|
5
|
+
result: SampleRunResult;
|
|
6
|
+
}
|
|
7
|
+
/** One server's worth of last-run entries, by recipe id: a run replaces the previous one for the same recipe. */
|
|
8
|
+
export interface LastRunCache {
|
|
9
|
+
entries: Map<string, LastRunEntry>;
|
|
10
|
+
}
|
|
11
|
+
/** @returns A fresh, empty cache. */
|
|
12
|
+
export declare function createLastRunCache(): LastRunCache;
|
|
13
|
+
/** Records a finished sample run, replacing whatever this recipe's cache entry held before. */
|
|
14
|
+
export declare function recordLastRun(cache: LastRunCache, recipeId: string, result: SampleRunResult): void;
|
|
15
|
+
/** @returns The recipe's last completed sample run, or `undefined` when none has finished yet. */
|
|
16
|
+
export declare function lastRunOf(cache: LastRunCache, recipeId: string): LastRunEntry | undefined;
|
|
17
|
+
//# sourceMappingURL=last-run.store.d.ts.map
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import type { BrowserSessionConfig } from '@opencraw/core';
|
|
2
2
|
import type { SampleBudget } from '../studio-api/index.js';
|
|
3
|
-
import type { SampleRunRecord, SampleRunResult } from './sample-run-record.contract.js';
|
|
3
|
+
import type { SampleRunRecord, SampleRunRejected, SampleRunResult } from './sample-run-record.contract.js';
|
|
4
4
|
/** Where trace lines and records go as a sample run proceeds. */
|
|
5
5
|
export interface SampleRunCallbacks {
|
|
6
6
|
onTraceLine: (line: string) => void;
|
|
7
7
|
onRecord: (record: SampleRunRecord) => void;
|
|
8
|
+
/** A record was rejected (a field's `skip-record` missing/coercion policy); optional, most callers only need the final `rejectedRecords` list. */
|
|
9
|
+
onRejected?: (rejected: SampleRunRejected) => void;
|
|
8
10
|
}
|
|
9
11
|
/** A sample run in progress. */
|
|
10
12
|
export interface SampleRunHandle {
|
|
@@ -14,11 +16,15 @@ export interface SampleRunHandle {
|
|
|
14
16
|
}
|
|
15
17
|
/**
|
|
16
18
|
* Runs one input recipe of a workspace folder as a sample: `debug: true` (so
|
|
17
|
-
* each `record:emit` carries its
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* `
|
|
19
|
+
* each `record:emit` carries its scope snapshot and mapping trace, and each
|
|
20
|
+
* `record:reject` its scope), an in-memory sink, and `budget` as the
|
|
21
|
+
* crawler's `sample` (`@opencraw/core`'s `CrawlOptions.sample`, #89). Every
|
|
22
|
+
* engine event becomes a trace line with the same `traceLine` formatter the
|
|
23
|
+
* cli's `--trace` uses; every emitted record reaches `callbacks.onRecord` as
|
|
24
|
+
* it happens, not only in the final result. Step events (`step:start`,
|
|
25
|
+
* `step:skip`, `step:retry`) are aggregated by path into `result.steps`, so
|
|
26
|
+
* `explain-why` (#92) can later say whether the step that bound a mapping's
|
|
27
|
+
* source id ran, was skipped, or retried — without a second run.
|
|
22
28
|
*
|
|
23
29
|
* @param folder - The workspace folder the recipe lives in.
|
|
24
30
|
* @param recipeId - The input recipe to run.
|
|
@@ -1,10 +1,37 @@
|
|
|
1
|
-
|
|
1
|
+
import type { MappingTrace } from '@opencraw/core';
|
|
2
|
+
/**
|
|
3
|
+
* One record streamed or kept from a sample run. `scope` (the snapshot it
|
|
4
|
+
* was mapped from) and `mapping` (each field's source value and its value
|
|
5
|
+
* after every transform, `@opencraw/core`'s `record:emit.mapping`, core
|
|
6
|
+
* since 0.1.12) are always present: `runSample` runs with `debug: true`.
|
|
7
|
+
* Kept per record (studio plan §4.2/§4.4, issue #92) so the Record tab can
|
|
8
|
+
* show a transform chain's real values and the Why? tab can explain a
|
|
9
|
+
* missing one, without a second run.
|
|
10
|
+
*/
|
|
2
11
|
export interface SampleRunRecord {
|
|
3
12
|
key: string | null;
|
|
4
13
|
data: Record<string, unknown>;
|
|
14
|
+
scope?: Record<string, unknown>;
|
|
15
|
+
mapping?: MappingTrace;
|
|
16
|
+
}
|
|
17
|
+
/** One record a sample run rejected (`RecordRejectedError`, a field's `skip-record` policy), kept for the Why? tab. */
|
|
18
|
+
export interface SampleRunRejected {
|
|
19
|
+
field: string;
|
|
20
|
+
reason: string;
|
|
21
|
+
url: string;
|
|
22
|
+
scope?: Record<string, unknown>;
|
|
5
23
|
}
|
|
6
24
|
/** A sample run's stopping reason: mirrors `@opencraw/core`'s `RecipeReport.stoppedBy`. */
|
|
7
25
|
export type SampleStoppedBy = 'sample-maxRecords' | 'sample-maxPages' | 'sample-maxMs';
|
|
26
|
+
/** One outcome of a step during a sample run, aggregated over every time its path ran: whether it ever ran cleanly, was skipped, or retried, kept for the Why? tab (issue #92) — which step bound a mapping's source id, and whether it found nothing. */
|
|
27
|
+
export interface SampleStepSummary {
|
|
28
|
+
path: string;
|
|
29
|
+
stepType: string;
|
|
30
|
+
stepId?: string;
|
|
31
|
+
as?: string;
|
|
32
|
+
outcome: 'ran' | 'skipped' | 'retried';
|
|
33
|
+
error?: string;
|
|
34
|
+
}
|
|
8
35
|
/** What a sample run finished with. */
|
|
9
36
|
export interface SampleRunResult {
|
|
10
37
|
recipeId: string;
|
|
@@ -15,5 +42,7 @@ export interface SampleRunResult {
|
|
|
15
42
|
error?: string;
|
|
16
43
|
stoppedBy?: SampleStoppedBy;
|
|
17
44
|
records: SampleRunRecord[];
|
|
45
|
+
rejectedRecords: SampleRunRejected[];
|
|
46
|
+
steps: SampleStepSummary[];
|
|
18
47
|
}
|
|
19
48
|
//# sourceMappingURL=sample-run-record.contract.d.ts.map
|
|
@@ -77,6 +77,49 @@ export declare const inferSelectorCommandSchema: z.ZodObject<{
|
|
|
77
77
|
path: z.ZodString;
|
|
78
78
|
nodeIds: z.ZodUnion<readonly [z.ZodTuple<[z.ZodString], null>, z.ZodTuple<[z.ZodString, z.ZodString], null>]>;
|
|
79
79
|
}, z.core.$strip>;
|
|
80
|
+
/** A missing value in an emitted record, by its position in the last sample run's records (the order they streamed in, matching the UI's own `records` list). */
|
|
81
|
+
export declare const missingWhyTargetSchema: z.ZodObject<{
|
|
82
|
+
kind: z.ZodLiteral<"missing">;
|
|
83
|
+
recipeId: z.ZodString;
|
|
84
|
+
recordIndex: z.ZodInt;
|
|
85
|
+
field: z.ZodString;
|
|
86
|
+
}, z.core.$strip>;
|
|
87
|
+
/** A rejected record, by its position in the last sample run's `rejectedRecords`. */
|
|
88
|
+
export declare const rejectedWhyTargetSchema: z.ZodObject<{
|
|
89
|
+
kind: z.ZodLiteral<"rejected">;
|
|
90
|
+
recipeId: z.ZodString;
|
|
91
|
+
rejectedIndex: z.ZodInt;
|
|
92
|
+
}, z.core.$strip>;
|
|
93
|
+
export declare const whyTargetSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
94
|
+
kind: z.ZodLiteral<"missing">;
|
|
95
|
+
recipeId: z.ZodString;
|
|
96
|
+
recordIndex: z.ZodInt;
|
|
97
|
+
field: z.ZodString;
|
|
98
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
99
|
+
kind: z.ZodLiteral<"rejected">;
|
|
100
|
+
recipeId: z.ZodString;
|
|
101
|
+
rejectedIndex: z.ZodInt;
|
|
102
|
+
}, z.core.$strip>], "kind">;
|
|
103
|
+
/**
|
|
104
|
+
* Explains one missing or rejected value from the recipe's last sample run
|
|
105
|
+
* (`explain-why.use-case.ts`, issue #92's Why? tab): the mapping trace and
|
|
106
|
+
* scope snapshot `run-sample` already kept, the step that bound the value's
|
|
107
|
+
* source id and whether it ran, was skipped or found nothing, and the
|
|
108
|
+
* missing-value policy that applied.
|
|
109
|
+
*/
|
|
110
|
+
export declare const explainWhyCommandSchema: z.ZodObject<{
|
|
111
|
+
type: z.ZodLiteral<"explain-why">;
|
|
112
|
+
target: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
113
|
+
kind: z.ZodLiteral<"missing">;
|
|
114
|
+
recipeId: z.ZodString;
|
|
115
|
+
recordIndex: z.ZodInt;
|
|
116
|
+
field: z.ZodString;
|
|
117
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
118
|
+
kind: z.ZodLiteral<"rejected">;
|
|
119
|
+
recipeId: z.ZodString;
|
|
120
|
+
rejectedIndex: z.ZodInt;
|
|
121
|
+
}, z.core.$strip>], "kind">;
|
|
122
|
+
}, z.core.$strip>;
|
|
80
123
|
export declare const studioCommandSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
81
124
|
type: z.ZodLiteral<"open-workspace">;
|
|
82
125
|
folder: z.ZodString;
|
|
@@ -115,6 +158,18 @@ export declare const studioCommandSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
115
158
|
recipeId: z.ZodString;
|
|
116
159
|
path: z.ZodString;
|
|
117
160
|
nodeIds: z.ZodUnion<readonly [z.ZodTuple<[z.ZodString], null>, z.ZodTuple<[z.ZodString, z.ZodString], null>]>;
|
|
161
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
162
|
+
type: z.ZodLiteral<"explain-why">;
|
|
163
|
+
target: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
164
|
+
kind: z.ZodLiteral<"missing">;
|
|
165
|
+
recipeId: z.ZodString;
|
|
166
|
+
recordIndex: z.ZodInt;
|
|
167
|
+
field: z.ZodString;
|
|
168
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
169
|
+
kind: z.ZodLiteral<"rejected">;
|
|
170
|
+
recipeId: z.ZodString;
|
|
171
|
+
rejectedIndex: z.ZodInt;
|
|
172
|
+
}, z.core.$strip>], "kind">;
|
|
118
173
|
}, z.core.$strip>], "type">;
|
|
119
174
|
export type SampleBudget = z.infer<typeof sampleBudgetSchema>;
|
|
120
175
|
export type OpenWorkspaceCommand = z.infer<typeof openWorkspaceCommandSchema>;
|
|
@@ -126,6 +181,10 @@ export type SaveOutlineCommand = z.infer<typeof saveOutlineCommandSchema>;
|
|
|
126
181
|
export type TakeSnapshotCommand = z.infer<typeof takeSnapshotCommandSchema>;
|
|
127
182
|
export type VerifySelectorCommand = z.infer<typeof verifySelectorCommandSchema>;
|
|
128
183
|
export type InferSelectorCommand = z.infer<typeof inferSelectorCommandSchema>;
|
|
184
|
+
export type MissingWhyTarget = z.infer<typeof missingWhyTargetSchema>;
|
|
185
|
+
export type RejectedWhyTarget = z.infer<typeof rejectedWhyTargetSchema>;
|
|
186
|
+
export type WhyTarget = z.infer<typeof whyTargetSchema>;
|
|
187
|
+
export type ExplainWhyCommand = z.infer<typeof explainWhyCommandSchema>;
|
|
129
188
|
/** Every command the UI can send the server, over HTTP POST. */
|
|
130
189
|
export type StudioCommand = z.infer<typeof studioCommandSchema>;
|
|
131
190
|
//# sourceMappingURL=command.contract.d.ts.map
|
|
@@ -10,12 +10,36 @@ export declare const traceLineEventSchema: z.ZodObject<{
|
|
|
10
10
|
type: z.ZodLiteral<"trace-line">;
|
|
11
11
|
line: z.ZodString;
|
|
12
12
|
}, z.core.$strip>;
|
|
13
|
-
/** One
|
|
13
|
+
/** One entry of a mapping trace field: what a rule's `from` read, and the value after each transform, in order (`@opencraw/core`'s `FieldTrace`). */
|
|
14
|
+
export declare const fieldTraceSchema: z.ZodObject<{
|
|
15
|
+
from: z.ZodUnknown;
|
|
16
|
+
steps: z.ZodArray<z.ZodObject<{
|
|
17
|
+
op: z.ZodString;
|
|
18
|
+
value: z.ZodUnknown;
|
|
19
|
+
}, z.core.$strip>>;
|
|
20
|
+
}, z.core.$strip>;
|
|
21
|
+
/** One record a sample run emitted: `scope` (what it was mapped from) and `mapping` (each field's trace) ride along, so the Record tab (#92) can show a transform chain's real values without a second round trip. */
|
|
14
22
|
export declare const recordEventSchema: z.ZodObject<{
|
|
15
23
|
type: z.ZodLiteral<"record">;
|
|
16
24
|
recipeId: z.ZodString;
|
|
17
25
|
key: z.ZodNullable<z.ZodString>;
|
|
18
26
|
data: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
27
|
+
scope: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
28
|
+
mapping: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
29
|
+
from: z.ZodUnknown;
|
|
30
|
+
steps: z.ZodArray<z.ZodObject<{
|
|
31
|
+
op: z.ZodString;
|
|
32
|
+
value: z.ZodUnknown;
|
|
33
|
+
}, z.core.$strip>>;
|
|
34
|
+
}, z.core.$strip>>>;
|
|
35
|
+
}, z.core.$strip>;
|
|
36
|
+
/** One record a sample run rejected (a field's `skip-record` policy on a missing or uncoercible value). */
|
|
37
|
+
export declare const recordRejectedEventSchema: z.ZodObject<{
|
|
38
|
+
type: z.ZodLiteral<"record-rejected">;
|
|
39
|
+
recipeId: z.ZodString;
|
|
40
|
+
field: z.ZodString;
|
|
41
|
+
reason: z.ZodString;
|
|
42
|
+
scope: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
19
43
|
}, z.core.$strip>;
|
|
20
44
|
/** A sample run ended: how many records, and why it stopped when it did not finish on its own. */
|
|
21
45
|
export declare const runFinishedEventSchema: z.ZodObject<{
|
|
@@ -44,6 +68,20 @@ export declare const studioEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
44
68
|
recipeId: z.ZodString;
|
|
45
69
|
key: z.ZodNullable<z.ZodString>;
|
|
46
70
|
data: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
71
|
+
scope: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
72
|
+
mapping: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
73
|
+
from: z.ZodUnknown;
|
|
74
|
+
steps: z.ZodArray<z.ZodObject<{
|
|
75
|
+
op: z.ZodString;
|
|
76
|
+
value: z.ZodUnknown;
|
|
77
|
+
}, z.core.$strip>>;
|
|
78
|
+
}, z.core.$strip>>>;
|
|
79
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
80
|
+
type: z.ZodLiteral<"record-rejected">;
|
|
81
|
+
recipeId: z.ZodString;
|
|
82
|
+
field: z.ZodString;
|
|
83
|
+
reason: z.ZodString;
|
|
84
|
+
scope: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
47
85
|
}, z.core.$strip>, z.ZodObject<{
|
|
48
86
|
type: z.ZodLiteral<"run-finished">;
|
|
49
87
|
recipeId: z.ZodString;
|
|
@@ -62,7 +100,9 @@ export declare const studioEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
62
100
|
}, z.core.$strip>], "type">;
|
|
63
101
|
export type StoppedBy = z.infer<typeof stoppedBySchema>;
|
|
64
102
|
export type TraceLineEvent = z.infer<typeof traceLineEventSchema>;
|
|
103
|
+
export type FieldTraceView = z.infer<typeof fieldTraceSchema>;
|
|
65
104
|
export type RecordEvent = z.infer<typeof recordEventSchema>;
|
|
105
|
+
export type RecordRejectedEvent = z.infer<typeof recordRejectedEventSchema>;
|
|
66
106
|
export type RunFinishedEvent = z.infer<typeof runFinishedEventSchema>;
|
|
67
107
|
export type WorkspaceChangedEvent = z.infer<typeof workspaceChangedEventSchema>;
|
|
68
108
|
/** Every event the server pushes to the UI over the WebSocket. */
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
export { sampleBudgetSchema, openWorkspaceCommandSchema, runSampleCommandSchema, stopRunCommandSchema, saveRecipeCommandSchema, fetchStartPageCommandSchema, saveOutlineCommandSchema, takeSnapshotCommandSchema, verifySelectorCommandSchema, inferSelectorCommandSchema, studioCommandSchema } from './command.contract.js';
|
|
2
|
-
export type { SampleBudget, OpenWorkspaceCommand, RunSampleCommand, StopRunCommand, SaveRecipeCommand, FetchStartPageCommand, SaveOutlineCommand, TakeSnapshotCommand, VerifySelectorCommand, InferSelectorCommand, StudioCommand } from './command.contract.js';
|
|
1
|
+
export { sampleBudgetSchema, openWorkspaceCommandSchema, runSampleCommandSchema, stopRunCommandSchema, saveRecipeCommandSchema, fetchStartPageCommandSchema, saveOutlineCommandSchema, takeSnapshotCommandSchema, verifySelectorCommandSchema, inferSelectorCommandSchema, missingWhyTargetSchema, rejectedWhyTargetSchema, whyTargetSchema, explainWhyCommandSchema, studioCommandSchema } from './command.contract.js';
|
|
2
|
+
export type { SampleBudget, OpenWorkspaceCommand, RunSampleCommand, StopRunCommand, SaveRecipeCommand, FetchStartPageCommand, SaveOutlineCommand, TakeSnapshotCommand, VerifySelectorCommand, InferSelectorCommand, MissingWhyTarget, RejectedWhyTarget, WhyTarget, ExplainWhyCommand, StudioCommand } from './command.contract.js';
|
|
3
3
|
export { snapshotViewSchema } from './snapshot-view.contract.js';
|
|
4
4
|
export type { SnapshotView } from './snapshot-view.contract.js';
|
|
5
5
|
export { verifySelectorViewSchema } from './verify-selector-view.contract.js';
|
|
6
6
|
export type { VerifySelectorView } from './verify-selector-view.contract.js';
|
|
7
7
|
export { fieldPickSchema, inferSelectorViewSchema } from './infer-selector-view.contract.js';
|
|
8
8
|
export type { FieldPick, InferSelectorView } from './infer-selector-view.contract.js';
|
|
9
|
-
export { stoppedBySchema, traceLineEventSchema, recordEventSchema, runFinishedEventSchema, workspaceChangedEventSchema, studioEventSchema } from './event.contract.js';
|
|
10
|
-
export type { StoppedBy, TraceLineEvent, RecordEvent, RunFinishedEvent, WorkspaceChangedEvent, StudioEvent } from './event.contract.js';
|
|
9
|
+
export { stoppedBySchema, fieldTraceSchema, traceLineEventSchema, recordEventSchema, recordRejectedEventSchema, runFinishedEventSchema, workspaceChangedEventSchema, studioEventSchema } from './event.contract.js';
|
|
10
|
+
export type { StoppedBy, FieldTraceView, TraceLineEvent, RecordEvent, RecordRejectedEvent, RunFinishedEvent, WorkspaceChangedEvent, StudioEvent } from './event.contract.js';
|
|
11
11
|
export { recipeIssueSchema, recipeListingSchema, workspaceViewSchema } from './workspace-view.contract.js';
|
|
12
12
|
export type { RecipeIssue, RecipeListing, WorkspaceView } from './workspace-view.contract.js';
|
|
13
13
|
export { sampleRunRecordSchema, sampleRunViewSchema } from './sample-run-view.contract.js';
|
|
@@ -16,4 +16,6 @@ export { startPageViewSchema } from './start-page-view.contract.js';
|
|
|
16
16
|
export type { StartPageView } from './start-page-view.contract.js';
|
|
17
17
|
export { sentencePartSchema, outlineCardSchema, outlineBracketSchema, outlineNodeSchema, outlineViewSchema } from './outline-view.contract.js';
|
|
18
18
|
export type { SentencePart, OutlineCard, OutlineBracket, OutlineNode, OutlineView } from './outline-view.contract.js';
|
|
19
|
+
export { whyViewSchema } from './why-view.contract.js';
|
|
20
|
+
export type { WhyView } from './why-view.contract.js';
|
|
19
21
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/** What `explain-why` answers with: the sentence (`why-sentence.mapper.ts`'s `buildWhySentence`), plus the structured facts a click can act on — a link back to the step that bound the value, the policy that applied. */
|
|
3
|
+
export declare const whyViewSchema: z.ZodObject<{
|
|
4
|
+
sentence: z.ZodString;
|
|
5
|
+
field: z.ZodString;
|
|
6
|
+
recipeId: z.ZodString;
|
|
7
|
+
outcome: z.ZodEnum<{
|
|
8
|
+
missing: "missing";
|
|
9
|
+
rejected: "rejected";
|
|
10
|
+
}>;
|
|
11
|
+
stepPath: z.ZodOptional<z.ZodString>;
|
|
12
|
+
policy: z.ZodOptional<z.ZodString>;
|
|
13
|
+
reason: z.ZodOptional<z.ZodString>;
|
|
14
|
+
}, z.core.$strip>;
|
|
15
|
+
export type WhyView = z.infer<typeof whyViewSchema>;
|
|
16
|
+
//# sourceMappingURL=why-view.contract.d.ts.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ExplainWhyCommand, WhyView } from '../studio-api/index.js';
|
|
2
|
+
import type { StudioState } from './workspace.store.js';
|
|
3
|
+
/**
|
|
4
|
+
* Handles `explain-why` (issue #92's Why? tab): builds the sentence for a
|
|
5
|
+
* missing or rejected value from the recipe's last sample run, kept in
|
|
6
|
+
* `state.lastRuns` by `handleRunSample`.
|
|
7
|
+
*
|
|
8
|
+
* @param state - The server state: `folder` must already be set (`open-workspace` first).
|
|
9
|
+
* @param command - The command.
|
|
10
|
+
* @returns The explanation.
|
|
11
|
+
* @throws Error when no workspace is open, no sample run has finished for the target's recipe, or the target does not name a real record/field.
|
|
12
|
+
*/
|
|
13
|
+
export declare function handleExplainWhy(state: StudioState, command: ExplainWhyCommand): Promise<WhyView>;
|
|
14
|
+
//# sourceMappingURL=explain-why.handler.d.ts.map
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import type { BrowserSessionConfig } from '@opencraw/core';
|
|
2
2
|
import type { SnapshotCache } from '../page-snapshot/index.js';
|
|
3
|
-
import type { SampleRunHandle } from '../sample-run/index.js';
|
|
3
|
+
import type { LastRunCache, SampleRunHandle } from '../sample-run/index.js';
|
|
4
4
|
import type { StudioEvent } from '../studio-api/index.js';
|
|
5
5
|
import type { WsConnection } from './websocket.client.js';
|
|
6
|
-
/** The server's mutable state: the opened folder, the run in progress (if any), the connected event sockets, the per-recipe snapshot cache `take-snapshot`/`verify-selector`/`infer-selector` share, and the browser launch settings every web-mode command (`take-snapshot`, `verify-selector`, `run-sample`) shares. */
|
|
6
|
+
/** The server's mutable state: the opened folder, the run in progress (if any), the connected event sockets, the per-recipe snapshot cache `take-snapshot`/`verify-selector`/`infer-selector` share, each recipe's last finished sample run (`explain-why`, issue #92), and the browser launch settings every web-mode command (`take-snapshot`, `verify-selector`, `run-sample`) shares. */
|
|
7
7
|
export interface StudioState {
|
|
8
8
|
folder?: string;
|
|
9
9
|
activeRun?: SampleRunHandle;
|
|
10
10
|
sockets: Set<WsConnection>;
|
|
11
11
|
snapshots: SnapshotCache;
|
|
12
|
+
lastRuns: LastRunCache;
|
|
12
13
|
/** Set once at server start (`StudioServerOptions.browser`); every web-mode command reads it from here rather than each accepting its own. */
|
|
13
14
|
browser?: BrowserSessionConfig;
|
|
14
15
|
}
|
|
15
|
-
/** @returns Fresh state for a new server instance: no workspace open, no run, no sockets, an empty snapshot cache, Playwright's own default browser. */
|
|
16
|
+
/** @returns Fresh state for a new server instance: no workspace open, no run, no sockets, an empty snapshot cache, no last runs, Playwright's own default browser. */
|
|
16
17
|
export declare function createStudioState(): StudioState;
|
|
17
18
|
/**
|
|
18
19
|
* Sends one event to every connected client. A socket that errors while
|