@veolab/discoverylab 1.3.3 → 1.4.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.
Files changed (37) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/dist/chunk-34KRJWZL.js +477 -0
  4. package/dist/chunk-4VNS5WPM.js +42 -0
  5. package/dist/{chunk-FIL7IWEL.js → chunk-DGXAP477.js} +1 -1
  6. package/dist/{chunk-HGWEHWKJ.js → chunk-DKAX5RCX.js} +1 -1
  7. package/dist/{chunk-7EDIUVIO.js → chunk-EU63HPKT.js} +1 -1
  8. package/dist/chunk-QMUEC6B5.js +288 -0
  9. package/dist/{chunk-FNUN7EPB.js → chunk-RCY26WEK.js} +2 -2
  10. package/dist/{chunk-ZLHIHMSL.js → chunk-SWZIBO2R.js} +1 -1
  11. package/dist/chunk-VYYAP5G5.js +265 -0
  12. package/dist/{chunk-VVIOB362.js → chunk-XAMA3JJG.js} +18 -1
  13. package/dist/{chunk-LXSWDEXV.js → chunk-XWBFSSNB.js} +10224 -389
  14. package/dist/{chunk-AHVBE25Y.js → chunk-YNLUOZSZ.js} +274 -667
  15. package/dist/cli.js +33 -31
  16. package/dist/{db-6WLEVKUV.js → db-745LC5YC.js} +2 -2
  17. package/dist/document-AE4XI2CP.js +104 -0
  18. package/dist/{esvp-KVOWYW6G.js → esvp-4LIAU76K.js} +3 -3
  19. package/dist/{esvp-mobile-GZ5EMYPG.js → esvp-mobile-FKFHDS5Q.js} +4 -4
  20. package/dist/frames-RCNLSDD6.js +24 -0
  21. package/dist/{gridCompositor-M3K3LCLZ.js → gridCompositor-VUWBZXYL.js} +262 -3
  22. package/dist/index.d.ts +32 -0
  23. package/dist/index.html +1197 -9
  24. package/dist/index.js +15 -10
  25. package/dist/notion-api-OXSWOJPZ.js +190 -0
  26. package/dist/{ocr-QDYNCSPE.js → ocr-FXRLEP66.js} +1 -1
  27. package/dist/{playwright-VZ7PXDC5.js → playwright-GYKUH34L.js} +3 -3
  28. package/dist/renderer-D22GCMMD.js +17 -0
  29. package/dist/{server-6N3KIEGP.js → server-NTT2XGCC.js} +1 -1
  30. package/dist/server-TKYRIYJ6.js +24 -0
  31. package/dist/{setup-2SQC5UHJ.js → setup-O6WQQAGP.js} +3 -3
  32. package/dist/templates/bundle/bundle.js +4 -2
  33. package/dist/{tools-YGM5HRIB.js → tools-FVVWKEGC.js} +15 -7
  34. package/package.json +2 -2
  35. package/skills/knowledge-brain/SKILL.md +64 -0
  36. package/dist/chunk-MLKGABMK.js +0 -9
  37. package/dist/server-T5X6GGOO.js +0 -22
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  startServer,
4
4
  stopServer
5
- } from "./chunk-LXSWDEXV.js";
5
+ } from "./chunk-XWBFSSNB.js";
6
6
  import {
7
7
  analyzeTools,
8
8
  canvasTools,
@@ -10,21 +10,25 @@ import {
10
10
  esvpTools,
11
11
  exportTools,
12
12
  integrationTools,
13
+ knowledgeTools,
13
14
  projectTools,
14
15
  taskHubTools,
15
16
  templateTools,
16
17
  testingTools,
17
18
  uiTools
18
- } from "./chunk-AHVBE25Y.js";
19
+ } from "./chunk-YNLUOZSZ.js";
20
+ import "./chunk-QMUEC6B5.js";
19
21
  import {
20
22
  setupTools
21
- } from "./chunk-FNUN7EPB.js";
23
+ } from "./chunk-RCY26WEK.js";
22
24
  import {
23
25
  mcpServer
24
26
  } from "./chunk-XKX6NBHF.js";
25
- import "./chunk-HGWEHWKJ.js";
26
- import "./chunk-FIL7IWEL.js";
27
- import "./chunk-ZLHIHMSL.js";
27
+ import "./chunk-34KRJWZL.js";
28
+ import "./chunk-VYYAP5G5.js";
29
+ import "./chunk-DKAX5RCX.js";
30
+ import "./chunk-DGXAP477.js";
31
+ import "./chunk-SWZIBO2R.js";
28
32
  import "./chunk-LB3RNE3O.js";
29
33
  import {
30
34
  attachESVPNetworkTrace,
@@ -50,7 +54,7 @@ import {
50
54
  runESVPActions,
51
55
  runESVPPreflight,
52
56
  validateESVPReplay
53
- } from "./chunk-7EDIUVIO.js";
57
+ } from "./chunk-EU63HPKT.js";
54
58
  import "./chunk-6EGBXRDK.js";
55
59
  import "./chunk-SLNJEF32.js";
56
60
  import {
@@ -63,9 +67,9 @@ import {
63
67
  projects,
64
68
  settings,
65
69
  testVariables
66
- } from "./chunk-VVIOB362.js";
70
+ } from "./chunk-XAMA3JJG.js";
67
71
  import "./chunk-XFVDP332.js";
68
- import "./chunk-MLKGABMK.js";
72
+ import "./chunk-4VNS5WPM.js";
69
73
 
70
74
  // src/core/protocol/types.ts
71
75
  function isWSRequest(msg) {
@@ -846,7 +850,8 @@ async function main() {
846
850
  ...integrationTools,
847
851
  ...taskHubTools,
848
852
  ...esvpTools,
849
- ...templateTools
853
+ ...templateTools,
854
+ ...knowledgeTools
850
855
  ]);
851
856
  await mcpServer.runStdio();
852
857
  } catch (error) {
@@ -0,0 +1,190 @@
1
+ import "./chunk-4VNS5WPM.js";
2
+
3
+ // src/core/export/adapters/notion-api.ts
4
+ function richText(text) {
5
+ const chunks = [];
6
+ for (let i = 0; i < text.length; i += 2e3) {
7
+ chunks.push({ type: "text", text: { content: text.slice(i, i + 2e3) } });
8
+ }
9
+ return chunks.length ? chunks : [{ type: "text", text: { content: "" } }];
10
+ }
11
+ function linkRichText(label, url) {
12
+ return { type: "text", text: { content: label, link: { url } } };
13
+ }
14
+ function sectionToNotionBlocks(section) {
15
+ switch (section.type) {
16
+ case "heading":
17
+ const headingType = section.level === 1 ? "heading_1" : section.level === 2 ? "heading_2" : "heading_3";
18
+ return [{ object: "block", type: headingType, [headingType]: { rich_text: richText(section.text) } }];
19
+ case "paragraph":
20
+ return [{ object: "block", type: "paragraph", paragraph: { rich_text: richText(section.text) } }];
21
+ case "divider":
22
+ return [{ object: "block", type: "divider", divider: {} }];
23
+ case "callout":
24
+ return [{
25
+ object: "block",
26
+ type: "callout",
27
+ callout: {
28
+ rich_text: richText(section.text),
29
+ color: (section.color || "purple") + "_background",
30
+ icon: { type: "emoji", emoji: "\u{1F4F1}" }
31
+ }
32
+ }];
33
+ case "links": {
34
+ return section.items.map((link) => ({
35
+ object: "block",
36
+ type: "bulleted_list_item",
37
+ bulleted_list_item: {
38
+ rich_text: [linkRichText(`${link.label}`, link.url)]
39
+ }
40
+ }));
41
+ }
42
+ case "image-gallery": {
43
+ const selectedImages = section.images.filter((img) => img.selected !== false);
44
+ return selectedImages.map((img, i) => ({
45
+ object: "block",
46
+ type: "paragraph",
47
+ paragraph: {
48
+ rich_text: richText(`[Image: ${img.caption || `Screen ${i + 1}`}]`)
49
+ },
50
+ _fileUpload: { path: img.path, type: "image" }
51
+ }));
52
+ }
53
+ case "image":
54
+ return [{
55
+ object: "block",
56
+ type: "paragraph",
57
+ paragraph: { rich_text: richText(`[Image: ${section.caption || "image"}]`) },
58
+ _fileUpload: { path: section.path, type: "image" }
59
+ }];
60
+ case "video":
61
+ return [{
62
+ object: "block",
63
+ type: "paragraph",
64
+ paragraph: { rich_text: richText("[Video]") },
65
+ _fileUpload: { path: section.path, type: "video" }
66
+ }];
67
+ case "gif":
68
+ return [{
69
+ object: "block",
70
+ type: "paragraph",
71
+ paragraph: { rich_text: richText(`[Interactive: ${section.caption || section.templateId || "animation"}]`) },
72
+ _fileUpload: { path: section.path, type: "image" }
73
+ }];
74
+ case "grid":
75
+ return [{
76
+ object: "block",
77
+ type: "paragraph",
78
+ paragraph: { rich_text: richText("[Grid composition]") },
79
+ _fileUpload: { path: section.path, type: "image" }
80
+ }];
81
+ case "markdown": {
82
+ const blocks = [];
83
+ if (section.collapsible && section.label) {
84
+ const lines = section.content.split("\n").filter((l) => l.trim());
85
+ const children = lines.slice(0, 20).map((line) => {
86
+ if (line.startsWith("## ")) {
87
+ return { object: "block", type: "heading_3", heading_3: { rich_text: richText(line.replace(/^##\s+/, "")) } };
88
+ }
89
+ if (line.startsWith("- ")) {
90
+ return { object: "block", type: "bulleted_list_item", bulleted_list_item: { rich_text: richText(line.replace(/^-\s+/, "")) } };
91
+ }
92
+ return { object: "block", type: "paragraph", paragraph: { rich_text: richText(line) } };
93
+ });
94
+ blocks.push({
95
+ object: "block",
96
+ type: "toggle",
97
+ toggle: {
98
+ rich_text: richText(section.label),
99
+ children: children.slice(0, 100)
100
+ // Notion limit
101
+ }
102
+ });
103
+ } else {
104
+ const lines = section.content.split("\n").filter((l) => l.trim());
105
+ for (const line of lines.slice(0, 50)) {
106
+ if (line.startsWith("## ")) {
107
+ blocks.push({ object: "block", type: "heading_2", heading_2: { rich_text: richText(line.replace(/^##\s+/, "")) } });
108
+ } else if (line.startsWith("### ")) {
109
+ blocks.push({ object: "block", type: "heading_3", heading_3: { rich_text: richText(line.replace(/^###\s+/, "")) } });
110
+ } else if (line.startsWith("- ")) {
111
+ blocks.push({ object: "block", type: "bulleted_list_item", bulleted_list_item: { rich_text: richText(line.replace(/^-\s+/, "")) } });
112
+ } else {
113
+ blocks.push({ object: "block", type: "paragraph", paragraph: { rich_text: richText(line) } });
114
+ }
115
+ }
116
+ }
117
+ return blocks;
118
+ }
119
+ default:
120
+ return [];
121
+ }
122
+ }
123
+ async function createNotionPageViaApi(document, config) {
124
+ try {
125
+ const allBlocks = [];
126
+ const fileUploads = [];
127
+ for (const section of document.sections) {
128
+ const blocks = sectionToNotionBlocks(section);
129
+ for (const block of blocks) {
130
+ const idx = allBlocks.length;
131
+ if (block._fileUpload) {
132
+ fileUploads.push({ blockIndex: idx, ...block._fileUpload });
133
+ delete block._fileUpload;
134
+ }
135
+ allBlocks.push(block);
136
+ }
137
+ }
138
+ const firstBatch = allBlocks.slice(0, 100);
139
+ const createResponse = await fetch("https://api.notion.com/v1/pages", {
140
+ method: "POST",
141
+ headers: {
142
+ "Authorization": `Bearer ${config.token}`,
143
+ "Notion-Version": "2022-06-28",
144
+ "Content-Type": "application/json"
145
+ },
146
+ body: JSON.stringify({
147
+ parent: { page_id: config.parentPageId },
148
+ properties: {
149
+ title: {
150
+ title: [{ type: "text", text: { content: document.title } }]
151
+ }
152
+ },
153
+ children: firstBatch
154
+ })
155
+ });
156
+ if (!createResponse.ok) {
157
+ const err = await createResponse.text();
158
+ return { success: false, error: `Notion API error (${createResponse.status}): ${err.slice(0, 300)}` };
159
+ }
160
+ const pageData = await createResponse.json();
161
+ if (allBlocks.length > 100) {
162
+ for (let i = 100; i < allBlocks.length; i += 100) {
163
+ const batch = allBlocks.slice(i, i + 100);
164
+ await fetch(`https://api.notion.com/v1/blocks/${pageData.id}/children`, {
165
+ method: "PATCH",
166
+ headers: {
167
+ "Authorization": `Bearer ${config.token}`,
168
+ "Notion-Version": "2022-06-28",
169
+ "Content-Type": "application/json"
170
+ },
171
+ body: JSON.stringify({ children: batch })
172
+ });
173
+ }
174
+ }
175
+ return {
176
+ success: true,
177
+ pageId: pageData.id,
178
+ pageUrl: pageData.url,
179
+ _fileUploads: fileUploads
180
+ };
181
+ } catch (error) {
182
+ return {
183
+ success: false,
184
+ error: error instanceof Error ? error.message : String(error)
185
+ };
186
+ }
187
+ }
188
+ export {
189
+ createNotionPageViaApi
190
+ };
@@ -8,7 +8,7 @@ import {
8
8
  recognizeTextWithTesseract,
9
9
  recognizeTextWithVision
10
10
  } from "./chunk-XFVDP332.js";
11
- import "./chunk-MLKGABMK.js";
11
+ import "./chunk-4VNS5WPM.js";
12
12
  export {
13
13
  analyzeText,
14
14
  checkTesseractAvailable,
@@ -15,10 +15,10 @@ import {
15
15
  savePlaywrightScript,
16
16
  showPlaywrightReport,
17
17
  startPlaywrightCodegen
18
- } from "./chunk-FIL7IWEL.js";
18
+ } from "./chunk-DGXAP477.js";
19
19
  import "./chunk-SLNJEF32.js";
20
- import "./chunk-VVIOB362.js";
21
- import "./chunk-MLKGABMK.js";
20
+ import "./chunk-XAMA3JJG.js";
21
+ import "./chunk-4VNS5WPM.js";
22
22
  export {
23
23
  BrowserDevices,
24
24
  PlaywrightActions,
@@ -0,0 +1,17 @@
1
+ import {
2
+ cleanupRenderJobs,
3
+ getCachedRender,
4
+ getProjectRenderJobs,
5
+ getRenderJob,
6
+ startRender
7
+ } from "./chunk-VYYAP5G5.js";
8
+ import "./chunk-DKAX5RCX.js";
9
+ import "./chunk-XAMA3JJG.js";
10
+ import "./chunk-4VNS5WPM.js";
11
+ export {
12
+ cleanupRenderJobs,
13
+ getCachedRender,
14
+ getProjectRenderJobs,
15
+ getRenderJob,
16
+ startRender
17
+ };
@@ -6,7 +6,7 @@ import {
6
6
  mcpServer
7
7
  } from "./chunk-XKX6NBHF.js";
8
8
  import "./chunk-6EGBXRDK.js";
9
- import "./chunk-MLKGABMK.js";
9
+ import "./chunk-4VNS5WPM.js";
10
10
  export {
11
11
  MCPServer,
12
12
  createErrorResult,
@@ -0,0 +1,24 @@
1
+ import {
2
+ app,
3
+ getServerPort,
4
+ startServer,
5
+ stopServer
6
+ } from "./chunk-XWBFSSNB.js";
7
+ import "./chunk-34KRJWZL.js";
8
+ import "./chunk-VYYAP5G5.js";
9
+ import "./chunk-DKAX5RCX.js";
10
+ import "./chunk-DGXAP477.js";
11
+ import "./chunk-SWZIBO2R.js";
12
+ import "./chunk-LB3RNE3O.js";
13
+ import "./chunk-EU63HPKT.js";
14
+ import "./chunk-6EGBXRDK.js";
15
+ import "./chunk-SLNJEF32.js";
16
+ import "./chunk-XAMA3JJG.js";
17
+ import "./chunk-XFVDP332.js";
18
+ import "./chunk-4VNS5WPM.js";
19
+ export {
20
+ app,
21
+ getServerPort,
22
+ startServer,
23
+ stopServer
24
+ };
@@ -4,11 +4,11 @@ import {
4
4
  setupInstallTool,
5
5
  setupStatusTool,
6
6
  setupTools
7
- } from "./chunk-FNUN7EPB.js";
7
+ } from "./chunk-RCY26WEK.js";
8
8
  import "./chunk-XKX6NBHF.js";
9
9
  import "./chunk-6EGBXRDK.js";
10
- import "./chunk-VVIOB362.js";
11
- import "./chunk-MLKGABMK.js";
10
+ import "./chunk-XAMA3JJG.js";
11
+ import "./chunk-4VNS5WPM.js";
12
12
  export {
13
13
  setupCheckTool,
14
14
  setupInitTool,
@@ -6553,7 +6553,8 @@ const Studio = ({
6553
6553
  style: {
6554
6554
  width: "100%",
6555
6555
  height: "100%",
6556
- objectFit: "cover"
6556
+ objectFit: platform === "web" ? "contain" : "cover",
6557
+ backgroundColor: platform === "web" ? "#0F0F1A" : undefined
6557
6558
  }
6558
6559
  }
6559
6560
  ) })
@@ -7569,7 +7570,8 @@ const Showcase = ({
7569
7570
  style: {
7570
7571
  width: "100%",
7571
7572
  height: "100%",
7572
- objectFit: "cover"
7573
+ objectFit: platform === "web" ? "contain" : "cover",
7574
+ backgroundColor: platform === "web" ? "#0F0F1A" : undefined
7573
7575
  }
7574
7576
  }
7575
7577
  ) })
@@ -57,6 +57,9 @@ import {
57
57
  jiraLoginTool,
58
58
  jiraQuickExportTool,
59
59
  jiraStatusTool,
60
+ knowledgeSearchTool,
61
+ knowledgeSummaryTool,
62
+ knowledgeTools,
60
63
  listEmulatorsTool,
61
64
  maestroGenerateTool,
62
65
  maestroRunTool,
@@ -104,23 +107,25 @@ import {
104
107
  uiStatusTool,
105
108
  uiTools,
106
109
  videoInfoTool
107
- } from "./chunk-AHVBE25Y.js";
110
+ } from "./chunk-YNLUOZSZ.js";
111
+ import "./chunk-QMUEC6B5.js";
108
112
  import {
109
113
  setupCheckTool,
110
114
  setupInitTool,
111
115
  setupStatusTool,
112
116
  setupTools
113
- } from "./chunk-FNUN7EPB.js";
117
+ } from "./chunk-RCY26WEK.js";
114
118
  import "./chunk-XKX6NBHF.js";
115
- import "./chunk-HGWEHWKJ.js";
116
- import "./chunk-FIL7IWEL.js";
119
+ import "./chunk-34KRJWZL.js";
120
+ import "./chunk-DKAX5RCX.js";
121
+ import "./chunk-DGXAP477.js";
117
122
  import "./chunk-LB3RNE3O.js";
118
- import "./chunk-7EDIUVIO.js";
123
+ import "./chunk-EU63HPKT.js";
119
124
  import "./chunk-6EGBXRDK.js";
120
125
  import "./chunk-SLNJEF32.js";
121
- import "./chunk-VVIOB362.js";
126
+ import "./chunk-XAMA3JJG.js";
122
127
  import "./chunk-XFVDP332.js";
123
- import "./chunk-MLKGABMK.js";
128
+ import "./chunk-4VNS5WPM.js";
124
129
  export {
125
130
  analyzeScreenshotTool,
126
131
  analyzeTools,
@@ -180,6 +185,9 @@ export {
180
185
  jiraLoginTool,
181
186
  jiraQuickExportTool,
182
187
  jiraStatusTool,
188
+ knowledgeSearchTool,
189
+ knowledgeSummaryTool,
190
+ knowledgeTools,
183
191
  listEmulatorsTool,
184
192
  maestroGenerateTool,
185
193
  maestroRunTool,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@veolab/discoverylab",
3
- "version": "1.3.3",
3
+ "version": "1.4.0",
4
4
  "description": "AI-powered app testing & evidence generator - Claude Code Plugin",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -68,7 +68,7 @@
68
68
  "claude-plugin": {
69
69
  "name": "DiscoveryLab",
70
70
  "description": "AI-powered app testing & evidence generator",
71
- "version": "1.3.3",
71
+ "version": "1.4.0",
72
72
  "tools": [
73
73
  "dlab.capture.screen",
74
74
  "dlab.capture.emulator",
@@ -0,0 +1,64 @@
1
+ ---
2
+ name: knowledge-brain
3
+ description: Search app knowledge from captured flows - UI, screens, behaviors
4
+ context: fork
5
+ agent: general-purpose
6
+ always: true
7
+ tags:
8
+ - knowledge
9
+ - search
10
+ - context
11
+ - app-flow
12
+ - ui
13
+ - screens
14
+ ---
15
+
16
+ # DiscoveryLab Knowledge Brain
17
+
18
+ When the user asks about app flows, screens, UI elements, or how something works in an app they've captured, use DiscoveryLab's knowledge base to find answers.
19
+
20
+ ## When to Use
21
+
22
+ Use `dlab.knowledge.search` when the user:
23
+ - Asks about a specific app screen ("how does the login work?")
24
+ - Asks about UI elements ("what buttons are on the paywall?")
25
+ - Asks about user flows ("what's the onboarding flow?")
26
+ - References an app by name ("in StyliApp, what does the closet screen show?")
27
+ - Needs context about captured recordings
28
+ - Compares flows or screens
29
+
30
+ ## Tools
31
+
32
+ ### `dlab.knowledge.search`
33
+ Search across all captured projects. Matches against project names, AI analysis, OCR text, tags, and linked tickets.
34
+
35
+ ```
36
+ dlab.knowledge.search { query: "login StyliApp" }
37
+ dlab.knowledge.search { query: "paywall premium" }
38
+ dlab.knowledge.search { query: "onboarding flow" }
39
+ ```
40
+
41
+ Returns: project overview, user flow steps, UI elements found, OCR text sample, and project ID for deeper lookup.
42
+
43
+ ### `dlab.knowledge.summary`
44
+ Get a high-level overview of all captured app knowledge.
45
+
46
+ ```
47
+ dlab.knowledge.summary {}
48
+ ```
49
+
50
+ Returns: all projects grouped by app, with stats (flows count, screens, analysis status).
51
+
52
+ ### `dlab.project.get`
53
+ For full details on a specific project found via search.
54
+
55
+ ```
56
+ dlab.project.get { projectId: "abc123" }
57
+ ```
58
+
59
+ ## Behavior
60
+
61
+ 1. Always search first before saying you don't know about an app flow
62
+ 2. If no match, show available projects so the user knows what's captured
63
+ 3. Use `dlab.project.get` for full details when the search result needs more depth
64
+ 4. Multiple projects may cover the same flow (different versions) - present the most recent first
@@ -1,9 +0,0 @@
1
- var __defProp = Object.defineProperty;
2
- var __export = (target, all) => {
3
- for (var name in all)
4
- __defProp(target, name, { get: all[name], enumerable: true });
5
- };
6
-
7
- export {
8
- __export
9
- };
@@ -1,22 +0,0 @@
1
- import {
2
- app,
3
- getServerPort,
4
- startServer,
5
- stopServer
6
- } from "./chunk-LXSWDEXV.js";
7
- import "./chunk-HGWEHWKJ.js";
8
- import "./chunk-FIL7IWEL.js";
9
- import "./chunk-ZLHIHMSL.js";
10
- import "./chunk-LB3RNE3O.js";
11
- import "./chunk-7EDIUVIO.js";
12
- import "./chunk-6EGBXRDK.js";
13
- import "./chunk-SLNJEF32.js";
14
- import "./chunk-VVIOB362.js";
15
- import "./chunk-XFVDP332.js";
16
- import "./chunk-MLKGABMK.js";
17
- export {
18
- app,
19
- getServerPort,
20
- startServer,
21
- stopServer
22
- };