@opencraw/studio 0.0.4 → 0.0.6

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.
Files changed (40) hide show
  1. package/bin/opencraw-studio.mjs +0 -0
  2. package/dist/index.esm.js +1219 -12
  3. package/dist/src/index.d.ts +2 -2
  4. package/dist/src/page-snapshot/hidden-marks.algorithm.d.ts +23 -0
  5. package/dist/src/page-snapshot/index.d.ts +7 -0
  6. package/dist/src/page-snapshot/rewrite-document.mapper.d.ts +27 -0
  7. package/dist/src/page-snapshot/snapshot.store.d.ts +14 -0
  8. package/dist/src/page-snapshot/take-snapshot.use-case.d.ts +34 -0
  9. package/dist/src/sample-run/run-sample.use-case.d.ts +3 -1
  10. package/dist/src/scope-outline/card-sentence.mapper.d.ts +18 -0
  11. package/dist/src/scope-outline/index.d.ts +8 -0
  12. package/dist/src/scope-outline/outline-to-recipe.mapper.d.ts +17 -0
  13. package/dist/src/scope-outline/outline.model.d.ts +57 -0
  14. package/dist/src/scope-outline/recipe-to-outline.mapper.d.ts +14 -0
  15. package/dist/src/scope-outline/scope-at-path.algorithm.d.ts +19 -0
  16. package/dist/src/selector-inference/class-token.policy.d.ts +35 -0
  17. package/dist/src/selector-inference/dom-path.model.d.ts +73 -0
  18. package/dist/src/selector-inference/index.d.ts +12 -0
  19. package/dist/src/selector-inference/list-inference.algorithm.d.ts +43 -0
  20. package/dist/src/selector-inference/selector-candidates.algorithm.d.ts +22 -0
  21. package/dist/src/selector-inference/selector-ranking.policy.d.ts +27 -0
  22. package/dist/src/selector-inference/shadow-dom.error.d.ts +11 -0
  23. package/dist/src/selector-inference/take-kind.policy.d.ts +12 -0
  24. package/dist/src/studio-api/command.contract.d.ts +64 -0
  25. package/dist/src/studio-api/index.d.ts +10 -2
  26. package/dist/src/studio-api/infer-selector-view.contract.d.ts +68 -0
  27. package/dist/src/studio-api/outline-view.contract.d.ts +37 -0
  28. package/dist/src/studio-api/snapshot-view.contract.d.ts +9 -0
  29. package/dist/src/studio-api/verify-selector-view.contract.d.ts +18 -0
  30. package/dist/src/studio-api/workspace-view.contract.d.ts +4 -2
  31. package/dist/src/studio-server/infer-selector.handler.d.ts +18 -0
  32. package/dist/src/studio-server/save-outline.handler.d.ts +18 -0
  33. package/dist/src/studio-server/studio-http.use-case.d.ts +3 -0
  34. package/dist/src/studio-server/take-snapshot.handler.d.ts +16 -0
  35. package/dist/src/studio-server/verify-selector.handler.d.ts +18 -0
  36. package/dist/src/studio-server/workspace.store.d.ts +7 -2
  37. package/dist/ui/assets/index-BfbrsfCv.js +13 -0
  38. package/dist/ui/index.html +1 -1
  39. package/package.json +5 -3
  40. package/dist/ui/assets/index-CO3pSJhQ.js +0 -12
@@ -1,5 +1,11 @@
1
- export { sampleBudgetSchema, openWorkspaceCommandSchema, runSampleCommandSchema, stopRunCommandSchema, saveRecipeCommandSchema, fetchStartPageCommandSchema, studioCommandSchema } from './command.contract.js';
2
- export type { SampleBudget, OpenWorkspaceCommand, RunSampleCommand, StopRunCommand, SaveRecipeCommand, FetchStartPageCommand, StudioCommand } from './command.contract.js';
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';
3
+ export { snapshotViewSchema } from './snapshot-view.contract.js';
4
+ export type { SnapshotView } from './snapshot-view.contract.js';
5
+ export { verifySelectorViewSchema } from './verify-selector-view.contract.js';
6
+ export type { VerifySelectorView } from './verify-selector-view.contract.js';
7
+ export { fieldPickSchema, inferSelectorViewSchema } from './infer-selector-view.contract.js';
8
+ export type { FieldPick, InferSelectorView } from './infer-selector-view.contract.js';
3
9
  export { stoppedBySchema, traceLineEventSchema, recordEventSchema, runFinishedEventSchema, workspaceChangedEventSchema, studioEventSchema } from './event.contract.js';
4
10
  export type { StoppedBy, TraceLineEvent, RecordEvent, RunFinishedEvent, WorkspaceChangedEvent, StudioEvent } from './event.contract.js';
5
11
  export { recipeIssueSchema, recipeListingSchema, workspaceViewSchema } from './workspace-view.contract.js';
@@ -8,4 +14,6 @@ export { sampleRunRecordSchema, sampleRunViewSchema } from './sample-run-view.co
8
14
  export type { SampleRunRecord, SampleRunView } from './sample-run-view.contract.js';
9
15
  export { startPageViewSchema } from './start-page-view.contract.js';
10
16
  export type { StartPageView } from './start-page-view.contract.js';
17
+ export { sentencePartSchema, outlineCardSchema, outlineBracketSchema, outlineNodeSchema, outlineViewSchema } from './outline-view.contract.js';
18
+ export type { SentencePart, OutlineCard, OutlineBracket, OutlineNode, OutlineView } from './outline-view.contract.js';
11
19
  //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,68 @@
1
+ import { z } from 'zod';
2
+ /** One clicked node's field: the best selector found for it, verified against the snapshot. */
3
+ export declare const fieldPickSchema: z.ZodObject<{
4
+ selector: z.ZodString;
5
+ tier: z.ZodEnum<{
6
+ id: "id";
7
+ "data-attr": "data-attr";
8
+ class: "class";
9
+ structure: "structure";
10
+ position: "position";
11
+ }>;
12
+ take: z.ZodString;
13
+ matches: z.ZodNumber;
14
+ }, z.core.$strip>;
15
+ /**
16
+ * What `infer-selector` answers with (issue #91, studio plan §3.2):
17
+ * `"field"` for one clicked node — a `Read` card's shape; `"list"` for two
18
+ * similar nodes — the safe `extract`(items)+`forEach`(field) shape, item and
19
+ * field each verified separately; `"unsupported"` when the two picks are not
20
+ * a coherent list (different branches, the same node twice, or shadow DOM),
21
+ * with a message the card can show as-is.
22
+ */
23
+ export declare const inferSelectorViewSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
24
+ kind: z.ZodLiteral<"field">;
25
+ field: z.ZodObject<{
26
+ selector: z.ZodString;
27
+ tier: z.ZodEnum<{
28
+ id: "id";
29
+ "data-attr": "data-attr";
30
+ class: "class";
31
+ structure: "structure";
32
+ position: "position";
33
+ }>;
34
+ take: z.ZodString;
35
+ matches: z.ZodNumber;
36
+ }, z.core.$strip>;
37
+ }, z.core.$strip>, z.ZodObject<{
38
+ kind: z.ZodLiteral<"list">;
39
+ item: z.ZodObject<{
40
+ selector: z.ZodString;
41
+ tier: z.ZodEnum<{
42
+ id: "id";
43
+ "data-attr": "data-attr";
44
+ class: "class";
45
+ structure: "structure";
46
+ position: "position";
47
+ }>;
48
+ matches: z.ZodNumber;
49
+ }, z.core.$strip>;
50
+ field: z.ZodObject<{
51
+ selector: z.ZodString;
52
+ tier: z.ZodEnum<{
53
+ id: "id";
54
+ "data-attr": "data-attr";
55
+ class: "class";
56
+ structure: "structure";
57
+ position: "position";
58
+ }>;
59
+ take: z.ZodString;
60
+ matches: z.ZodNumber;
61
+ }, z.core.$strip>;
62
+ }, z.core.$strip>, z.ZodObject<{
63
+ kind: z.ZodLiteral<"unsupported">;
64
+ reason: z.ZodString;
65
+ }, z.core.$strip>], "kind">;
66
+ export type FieldPick = z.infer<typeof fieldPickSchema>;
67
+ export type InferSelectorView = z.infer<typeof inferSelectorViewSchema>;
68
+ //# sourceMappingURL=infer-selector-view.contract.d.ts.map
@@ -0,0 +1,37 @@
1
+ import { z } from 'zod';
2
+ /** One piece of a card's sentence: plain wording, a bound id (a "pill"), or a literal shown as code. Mirrors `scope-outline/outline.model.ts`'s `SentencePart`: the wire shape for the UI. */
3
+ export interface SentencePart {
4
+ kind: 'word' | 'pill' | 'code';
5
+ text: string;
6
+ }
7
+ interface OutlineNodeBase {
8
+ path: string;
9
+ stepType: string;
10
+ sentence: SentencePart[];
11
+ step: Record<string, unknown>;
12
+ }
13
+ /** A leaf step, read as a sentence (or, when `custom`, not read as one: the UI shows `step`'s raw JSON instead). */
14
+ export interface OutlineCard extends OutlineNodeBase {
15
+ kind: 'card';
16
+ custom: boolean;
17
+ }
18
+ /** A container step (`forEach`, `paginate`, `if`), its body nested one level in. */
19
+ export interface OutlineBracket extends OutlineNodeBase {
20
+ kind: 'bracket';
21
+ stepType: 'forEach' | 'paginate' | 'if';
22
+ children: OutlineNode[];
23
+ elseChildren?: OutlineNode[];
24
+ }
25
+ export type OutlineNode = OutlineCard | OutlineBracket;
26
+ /** The outline the UI renders and edits: the recipe's other keys untouched, plus its steps as a tree. */
27
+ export interface OutlineView {
28
+ recipe: Record<string, unknown>;
29
+ steps: OutlineNode[];
30
+ }
31
+ export declare const sentencePartSchema: z.ZodType<SentencePart>;
32
+ export declare const outlineCardSchema: z.ZodType<OutlineCard>;
33
+ export declare const outlineBracketSchema: z.ZodType<OutlineBracket>;
34
+ export declare const outlineNodeSchema: z.ZodType<OutlineNode>;
35
+ export declare const outlineViewSchema: z.ZodType<OutlineView>;
36
+ export {};
37
+ //# sourceMappingURL=outline-view.contract.d.ts.map
@@ -0,0 +1,9 @@
1
+ import { z } from 'zod';
2
+ /** What `take-snapshot` answers with: the rewritten document ready for the content pane's sandboxed iframe (studio plan §3.1, issue #91). */
3
+ export declare const snapshotViewSchema: z.ZodObject<{
4
+ html: z.ZodString;
5
+ nodeCount: z.ZodNumber;
6
+ baseUrl: z.ZodString;
7
+ }, z.core.$strip>;
8
+ export type SnapshotView = z.infer<typeof snapshotViewSchema>;
9
+ //# sourceMappingURL=snapshot-view.contract.d.ts.map
@@ -0,0 +1,18 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * What `verify-selector` answers with: the match count against the snapshot
4
+ * and, when the live page could be reached, against it too (issue #91's
5
+ * "flag a selector that matches the snapshot but not the live page").
6
+ * `liveChecked` is `false` when the live page could not be fetched (offline,
7
+ * blocked by `allowedHosts`, a transient error) — the card shows the
8
+ * snapshot count alone rather than a misleading "0 on the live page".
9
+ */
10
+ export declare const verifySelectorViewSchema: z.ZodObject<{
11
+ selector: z.ZodString;
12
+ snapshotMatches: z.ZodNumber;
13
+ liveChecked: z.ZodBoolean;
14
+ liveMatches: z.ZodOptional<z.ZodNumber>;
15
+ liveError: z.ZodOptional<z.ZodString>;
16
+ }, z.core.$strip>;
17
+ export type VerifySelectorView = z.infer<typeof verifySelectorViewSchema>;
18
+ //# sourceMappingURL=verify-selector-view.contract.d.ts.map
@@ -12,9 +12,9 @@ export declare const recipeIssueSchema: z.ZodObject<{
12
12
  export declare const recipeListingSchema: z.ZodObject<{
13
13
  file: z.ZodString;
14
14
  kind: z.ZodEnum<{
15
- unknown: "unknown";
16
15
  input: "input";
17
16
  output: "output";
17
+ unknown: "unknown";
18
18
  }>;
19
19
  id: z.ZodOptional<z.ZodString>;
20
20
  issues: z.ZodArray<z.ZodObject<{
@@ -26,6 +26,7 @@ export declare const recipeListingSchema: z.ZodObject<{
26
26
  }>;
27
27
  }, z.core.$strip>>;
28
28
  text: z.ZodString;
29
+ outline: z.ZodOptional<z.ZodType<import("./outline-view.contract").OutlineView, unknown, z.core.$ZodTypeInternals<import("./outline-view.contract").OutlineView, unknown>>>;
29
30
  }, z.core.$strip>;
30
31
  /** What `open-workspace` answers with: every recipe file directly inside the folder. */
31
32
  export declare const workspaceViewSchema: z.ZodObject<{
@@ -33,9 +34,9 @@ export declare const workspaceViewSchema: z.ZodObject<{
33
34
  recipes: z.ZodArray<z.ZodObject<{
34
35
  file: z.ZodString;
35
36
  kind: z.ZodEnum<{
36
- unknown: "unknown";
37
37
  input: "input";
38
38
  output: "output";
39
+ unknown: "unknown";
39
40
  }>;
40
41
  id: z.ZodOptional<z.ZodString>;
41
42
  issues: z.ZodArray<z.ZodObject<{
@@ -47,6 +48,7 @@ export declare const workspaceViewSchema: z.ZodObject<{
47
48
  }>;
48
49
  }, z.core.$strip>>;
49
50
  text: z.ZodString;
51
+ outline: z.ZodOptional<z.ZodType<import("./outline-view.contract").OutlineView, unknown, z.core.$ZodTypeInternals<import("./outline-view.contract").OutlineView, unknown>>>;
50
52
  }, z.core.$strip>>;
51
53
  }, z.core.$strip>;
52
54
  export type RecipeIssue = z.infer<typeof recipeIssueSchema>;
@@ -0,0 +1,18 @@
1
+ import type { InferSelectorCommand, InferSelectorView } from '../studio-api/index.js';
2
+ import type { StudioState } from './workspace.store.js';
3
+ /**
4
+ * Handles `infer-selector`: turns one or two picked nodes (their
5
+ * `data-oc-node` ids, off the cached snapshot) into a verified selector —
6
+ * one id for a `Read` card's field, two for the safe item+field list shape
7
+ * `selector-inference`'s `inferList` builds by construction (issue #91,
8
+ * studio plan §3.2). All the actual candidate/ranking/list-inference work
9
+ * is `selector-inference`'s (pure); this handler only locates the clicked
10
+ * nodes in the cached document and calls into it.
11
+ *
12
+ * @param state - The server state.
13
+ * @param command - The command; `command.path` must already have a cached snapshot (call `take-snapshot` first).
14
+ * @returns A field pick, a list pick, or `"unsupported"` with why.
15
+ * @throws Error when no workspace is open, or `command.path` has no cached snapshot yet.
16
+ */
17
+ export declare function handleInferSelector(state: StudioState, command: InferSelectorCommand): InferSelectorView;
18
+ //# sourceMappingURL=infer-selector.handler.d.ts.map
@@ -0,0 +1,18 @@
1
+ import type { SaveOutlineCommand } from '../studio-api/index.js';
2
+ import type { StudioState } from './workspace.store.js';
3
+ /**
4
+ * Handles `save-outline`: the Steps tab's edits, as the outline it holds
5
+ * locally, converted back to the recipe's JSON (`scope-outline`'s
6
+ * `outlineToRecipe`, so the conversion runs here rather than in the
7
+ * browser) and written the same way `save-recipe` writes the JSON tab's
8
+ * edits. Every connected client, including the sender, is told the
9
+ * workspace changed, so both tabs re-fetch it and stay in sync.
10
+ *
11
+ * @param state - The server state holding the connected sockets.
12
+ * @param command - The command: the file path and the edited outline.
13
+ * @returns `{ saved: true }` once the write has completed.
14
+ */
15
+ export declare function handleSaveOutline(state: StudioState, command: SaveOutlineCommand): Promise<{
16
+ saved: true;
17
+ }>;
18
+ //# sourceMappingURL=save-outline.handler.d.ts.map
@@ -1,3 +1,4 @@
1
+ import type { BrowserSessionConfig } from '@opencraw/core';
1
2
  export interface StudioServerOptions {
2
3
  /** Where the built UI lives; default: `dist/ui` next to the running server code. */
3
4
  uiRoot?: string;
@@ -11,6 +12,8 @@ export interface StudioServerOptions {
11
12
  * the folder reaches it through the URL's `folder` query param).
12
13
  */
13
14
  initialFolder?: string;
15
+ /** Browser launch settings every web-mode command shares (`take-snapshot`, `verify-selector`, `run-sample`); an executable path override (e.g. `OPENCRAW_CHROMIUM`, read by the caller — the server itself has no opinion on env vars) for a sandbox with no full Playwright install. Default: Playwright's own bundled browser. */
16
+ browser?: BrowserSessionConfig;
14
17
  }
15
18
  /** The running server: its URL (token included, ready to open), the token alone, and how to stop it. */
16
19
  export interface StudioServer {
@@ -0,0 +1,16 @@
1
+ import type { SnapshotView, TakeSnapshotCommand } from '../studio-api/index.js';
2
+ import type { StudioState } from './workspace.store.js';
3
+ /**
4
+ * Handles `take-snapshot`: loads the named input recipe, captures its
5
+ * snapshot at `command.path` (only `"start"` is captured for now — see
6
+ * `page-snapshot`'s `take-snapshot.use-case.ts`), and caches it so a later
7
+ * `verify-selector`/`infer-selector` against the same recipe and path, or
8
+ * the UI reselecting the same step, does not recapture it.
9
+ *
10
+ * @param state - The server state: `folder` must already be set.
11
+ * @param command - The command.
12
+ * @returns The rewritten snapshot.
13
+ * @throws Error when no workspace is open, or the recipe cannot be found or loaded.
14
+ */
15
+ export declare function handleTakeSnapshot(state: StudioState, command: TakeSnapshotCommand): Promise<SnapshotView>;
16
+ //# sourceMappingURL=take-snapshot.handler.d.ts.map
@@ -0,0 +1,18 @@
1
+ import type { VerifySelectorCommand, VerifySelectorView } from '../studio-api/index.js';
2
+ import type { StudioState } from './workspace.store.js';
3
+ /**
4
+ * Handles `verify-selector`: runs a candidate through the engine's own
5
+ * selection (`@opencraw/core`'s `countMatches`) against the cached
6
+ * snapshot, and, best-effort, against the live page too — issue #91's "flag
7
+ * a selector that matches the snapshot but not the live page". The live
8
+ * page is fetched raw (`page-snapshot`'s `fetchStartPage`, the same reach
9
+ * `take-snapshot` has: only `"start"` today), not through the rewritten
10
+ * snapshot, so its match count is the site's own, not the studio's.
11
+ *
12
+ * @param state - The server state.
13
+ * @param command - The command; `command.path` must already have a cached snapshot (call `take-snapshot` first).
14
+ * @returns The match counts.
15
+ * @throws Error when no workspace is open, the recipe cannot be found, or `command.path` has no cached snapshot yet.
16
+ */
17
+ export declare function handleVerifySelector(state: StudioState, command: VerifySelectorCommand): Promise<VerifySelectorView>;
18
+ //# sourceMappingURL=verify-selector.handler.d.ts.map
@@ -1,13 +1,18 @@
1
+ import type { BrowserSessionConfig } from '@opencraw/core';
2
+ import type { SnapshotCache } from '../page-snapshot/index.js';
1
3
  import type { SampleRunHandle } from '../sample-run/index.js';
2
4
  import type { StudioEvent } from '../studio-api/index.js';
3
5
  import type { WsConnection } from './websocket.client.js';
4
- /** The server's mutable state: the opened folder, the run in progress (if any), and the connected event sockets. */
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. */
5
7
  export interface StudioState {
6
8
  folder?: string;
7
9
  activeRun?: SampleRunHandle;
8
10
  sockets: Set<WsConnection>;
11
+ snapshots: SnapshotCache;
12
+ /** Set once at server start (`StudioServerOptions.browser`); every web-mode command reads it from here rather than each accepting its own. */
13
+ browser?: BrowserSessionConfig;
9
14
  }
10
- /** @returns Fresh state for a new server instance: no workspace open, no run, no sockets. */
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. */
11
16
  export declare function createStudioState(): StudioState;
12
17
  /**
13
18
  * Sends one event to every connected client. A socket that errors while