@veolab/discoverylab 1.4.4 → 1.6.3
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +70 -211
- package/dist/{chunk-HB3YPWF3.js → chunk-5AISGCS4.js} +166 -8
- package/dist/{chunk-CUBQRT5L.js → chunk-HFN6BTVO.js} +110 -1
- package/dist/{chunk-2UUMLAVR.js → chunk-IVX2OSOJ.js} +251 -1
- package/dist/cli.js +158 -27
- package/dist/export/infographic-template.html +254 -0
- package/dist/import-W2JEW254.js +180 -0
- package/dist/index.html +420 -9
- package/dist/index.js +4 -4
- package/dist/infographic-GQAHEOAA.js +183 -0
- package/dist/{server-QFNKZCOJ.js → server-W3JQ5RG7.js} +1 -1
- package/dist/{setup-6JJYKKBS.js → setup-F7MGEFIM.js} +4 -1
- package/dist/{tools-Q7OZO732.js → tools-VYFNRUS4.js} +5 -3
- package/doc/esvp-protocol.md +116 -0
- package/package.json +3 -3
- package/skills/knowledge-brain/SKILL.md +44 -43
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"name": "discoverylab",
|
|
13
13
|
"source": ".",
|
|
14
14
|
"description": "AI-powered app testing & marketing asset generator. Record mobile/web apps, run automated tests with Maestro & Playwright, and generate professional screenshots, GIFs, and test reports.",
|
|
15
|
-
"version": "1.
|
|
15
|
+
"version": "1.6.3",
|
|
16
16
|
"author": {
|
|
17
17
|
"name": "Anderson Melo"
|
|
18
18
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "discoverylab",
|
|
3
3
|
"description": "AI-powered app testing & marketing asset generator. Record mobile/web apps, run automated tests with Maestro & Playwright, and generate professional screenshots, GIFs, and test reports.",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.6.3",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Anderson Melo",
|
|
7
7
|
"email": "anderson.90@gmail.com"
|
package/README.md
CHANGED
|
@@ -7,271 +7,130 @@
|
|
|
7
7
|
|
|
8
8
|

|
|
9
9
|
[](https://www.npmjs.com/package/@veolab/discoverylab)
|
|
10
|
+
[](https://www.npmjs.com/package/@veolab/discoverylab)
|
|
11
|
+
[](https://github.com/veolab/applab-discovery/stargazers)
|
|
10
12
|
[](https://opensource.org/licenses/MIT)
|
|
11
13
|
|
|
12
|
-
> AI-powered app testing &
|
|
14
|
+
> AI-powered app testing, documentation & knowledge base. A plugin for Claude Code and Claude Desktop.
|
|
13
15
|
|
|
14
16
|

|
|
15
17
|
|
|
16
|
-
##
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install -g @veolab/discoverylab
|
|
22
|
+
discoverylab install # auto-detects Claude Code + Claude Desktop
|
|
23
|
+
discoverylab serve # opens web UI at localhost:3847
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
`applab` works as an alias for `discoverylab`.
|
|
27
|
+
|
|
28
|
+
## What It Does
|
|
29
|
+
|
|
30
|
+
Record app flows. AI analyzes every screen. Ask Claude about any flow in natural language.
|
|
17
31
|
|
|
18
32
|
```mermaid
|
|
19
33
|
flowchart LR
|
|
20
|
-
subgraph
|
|
34
|
+
subgraph Capture
|
|
21
35
|
A[Mobile App] --> R[Record]
|
|
22
36
|
B[Web App] --> R
|
|
23
37
|
C[Video File] --> U[Upload]
|
|
24
38
|
end
|
|
25
39
|
|
|
26
|
-
subgraph
|
|
40
|
+
subgraph Analyze
|
|
27
41
|
R --> P[Process]
|
|
28
42
|
U --> P
|
|
29
43
|
P --> AI[AI Analysis]
|
|
30
|
-
AI -->
|
|
44
|
+
AI --> K[Knowledge Base]
|
|
31
45
|
end
|
|
32
46
|
|
|
33
|
-
subgraph
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
47
|
+
subgraph Use
|
|
48
|
+
K --> Q[Ask Claude]
|
|
49
|
+
K --> E[Export Assets]
|
|
50
|
+
K --> S[Share .applab]
|
|
37
51
|
end
|
|
38
52
|
```
|
|
39
53
|
|
|
40
|
-
## Quick Start
|
|
41
|
-
|
|
42
|
-
```bash
|
|
43
|
-
npm install -g @veolab/discoverylab
|
|
44
|
-
discoverylab install # configures Claude Code MCP
|
|
45
|
-
discoverylab serve # opens web UI
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
`applab serve` works as an alias — both `discoverylab` and `applab` are interchangeable.
|
|
49
|
-
`serve` and `server` are also interchangeable.
|
|
50
|
-
|
|
51
54
|
## Features
|
|
52
55
|
|
|
53
56
|
| Feature | Description |
|
|
54
57
|
|---------|-------------|
|
|
55
58
|
| **Screen Capture** | Record iOS/Android emulators or web apps |
|
|
59
|
+
| **AI Analysis** | OCR, feature detection, smart summaries (Anthropic, OpenAI, Ollama, Claude CLI) |
|
|
60
|
+
| **Knowledge Brain** | Ask Claude about any captured flow — visual answers with interactive infographics |
|
|
61
|
+
| **Interactive Visualizations** | Flow Diagram, Device Showcase, Metrics Dashboard, App Flow Map |
|
|
62
|
+
| **Grid Assets** | Infographic grids with AI annotations, step badges, flow arrows |
|
|
63
|
+
| **Export** | PNG, GIF, MP4, HTML infographic, .applab bundle |
|
|
64
|
+
| **Document Composer** | Build rich Notion pages with preview before export |
|
|
56
65
|
| **Maestro Testing** | Automated mobile app testing with screenshots |
|
|
57
66
|
| **Playwright Testing** | Web testing using your installed Chrome |
|
|
58
|
-
| **AI Analysis** | OCR, feature detection, smart summaries |
|
|
59
|
-
| **Export** | PNG, GIF, MP4 with professional quality |
|
|
60
67
|
| **Task Hub** | Jira, Notion, Figma, GitHub integration |
|
|
61
|
-
| **ESVP
|
|
68
|
+
| **ESVP Protocol** | Mobile sessions, replay, and network traces ([docs](doc/esvp-protocol.md)) |
|
|
69
|
+
| **Share** | Export .applab bundles → import on another machine with full context |
|
|
70
|
+
|
|
71
|
+
## Claude Integration
|
|
62
72
|
|
|
63
|
-
|
|
73
|
+
### Claude Code (CLI)
|
|
64
74
|
|
|
65
|
-
|
|
75
|
+
Skills available after install:
|
|
66
76
|
|
|
67
77
|
```
|
|
68
78
|
/discoverylab:open-ui → Open web interface
|
|
69
79
|
/discoverylab:quick-capture → Capture emulator screen
|
|
70
80
|
/discoverylab:mobile-test → Mobile testing with Maestro
|
|
71
81
|
/discoverylab:web-test → Web testing with Playwright
|
|
82
|
+
/discoverylab:generate-assets → Create marketing assets
|
|
72
83
|
```
|
|
73
84
|
|
|
74
|
-
|
|
85
|
+
### Claude Desktop
|
|
75
86
|
|
|
76
|
-
|
|
77
|
-
- FFmpeg (for video/GIF export)
|
|
78
|
-
- Maestro CLI (optional)
|
|
79
|
-
- Playwright (optional)
|
|
80
|
-
|
|
81
|
-
## Platform Support
|
|
87
|
+
Ask in natural language — Claude opens interactive visuals automatically:
|
|
82
88
|
|
|
83
|
-
| | macOS | Windows | Linux |
|
|
84
|
-
|---|:---:|:---:|:---:|
|
|
85
|
-
| Web UI | ✓ | ✓ | ✓ |
|
|
86
|
-
| iOS Capture | ✓ | — | — |
|
|
87
|
-
| Android Capture | ✓ | ✓ | ✓ |
|
|
88
|
-
| Web Recording | ✓ | ✓ | ✓ |
|
|
89
|
-
| Apple Vision OCR | ✓ | — | — |
|
|
90
|
-
|
|
91
|
-
## ESVP Integration
|
|
92
|
-
|
|
93
|
-
AppLab Discovery can act as an open-source client for a self-hosted ESVP control-plane. This integration is intentionally thin: it only calls the public HTTP contract and does not embed any private Entropy Lab runtime code.
|
|
94
|
-
|
|
95
|
-
Default behavior:
|
|
96
|
-
|
|
97
|
-
- if `ESVP_BASE_URL` is set, DiscoveryLab uses a remote/shared ESVP server
|
|
98
|
-
- if `ESVP_BASE_URL` is not set, DiscoveryLab tries to boot an embedded local OSS runtime (`esvp-local`)
|
|
99
|
-
|
|
100
|
-
For development, until `@entropylab/esvp-local` is published, point the local runtime module explicitly:
|
|
101
|
-
|
|
102
|
-
```bash
|
|
103
|
-
export DISCOVERYLAB_ESVP_LOCAL_MODULE=/absolute/path/to/esvp-server-reference/server.js
|
|
104
89
|
```
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
```bash
|
|
109
|
-
export ESVP_BASE_URL=http://your-esvp-host:8787
|
|
90
|
+
"how does the login flow work?" → opens infographic canvas
|
|
91
|
+
"what screens do we have captured?" → lists all projects
|
|
92
|
+
"show me the onboarding" → visual flow map
|
|
110
93
|
```
|
|
111
94
|
|
|
112
|
-
|
|
95
|
+
### MCP Tools
|
|
113
96
|
|
|
114
|
-
```bash
|
|
115
|
-
npm run build:host-runtime
|
|
116
97
|
```
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
- `DISCOVERYLAB_TEMPLATE_SOURCE_DIR` if set
|
|
123
|
-
- otherwise `~/.discoverylab/templates`
|
|
124
|
-
|
|
125
|
-
into `dist/templates`, so npm packages and fresh installs keep the template toggle icons and Remotion renders working without a second manual copy step.
|
|
126
|
-
|
|
127
|
-
For a local distributable package that already contains the bundled runtime for the current host, run:
|
|
128
|
-
|
|
129
|
-
```bash
|
|
130
|
-
npm run pack:local
|
|
98
|
+
dlab.knowledge.open → visual infographic of a flow (HTML canvas)
|
|
99
|
+
dlab.knowledge.search → text search across all projects
|
|
100
|
+
dlab.knowledge.summary → overview of all captured knowledge
|
|
101
|
+
dlab.export.infographic → export self-contained HTML file
|
|
102
|
+
dlab.project.import → import shared .applab bundle
|
|
131
103
|
```
|
|
132
104
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
Development vs packaged usage:
|
|
136
|
-
|
|
137
|
-
- local development can use `bun run dev`; when a bundled runtime is not present, App Lab falls back to `cargo run` if Rust is installed
|
|
138
|
-
- packaged/npm releases should be built with `npm run pack:local` or `npm publish`, which require the host runtime and embed it so end users only need `discoverylab serve` or `discoverylab server`
|
|
139
|
-
- the bundled runtime is currently host-target specific, so cross-platform distribution still needs a build matrix that produces binaries for each target you want to ship
|
|
140
|
-
- because App Lab is open source, the bundled runtime is intentionally limited to the local proxy/capture commodity path; it does not embed private Entropy Lab managed-proxy or protocol internals
|
|
141
|
-
|
|
142
|
-
Available MCP tools:
|
|
143
|
-
|
|
144
|
-
- `dlab.esvp.status`
|
|
145
|
-
- `dlab.esvp.devices`
|
|
146
|
-
- `dlab.esvp.sessions.list`
|
|
147
|
-
- `dlab.esvp.session.create`
|
|
148
|
-
- `dlab.esvp.session.get`
|
|
149
|
-
- `dlab.esvp.session.inspect`
|
|
150
|
-
- `dlab.esvp.session.transcript`
|
|
151
|
-
- `dlab.esvp.session.artifacts.list`
|
|
152
|
-
- `dlab.esvp.session.artifact.get`
|
|
153
|
-
- `dlab.esvp.session.actions`
|
|
154
|
-
- `dlab.esvp.session.checkpoint`
|
|
155
|
-
- `dlab.esvp.session.finish`
|
|
156
|
-
- `dlab.esvp.replay.run`
|
|
157
|
-
- `dlab.esvp.replay.validate`
|
|
158
|
-
- `dlab.esvp.session.network`
|
|
159
|
-
- `dlab.esvp.network.configure`
|
|
160
|
-
- `dlab.esvp.network.trace.attach`
|
|
161
|
-
- `dlab.project.esvp.current`
|
|
162
|
-
- `dlab.project.esvp.validate`
|
|
163
|
-
- `dlab.project.esvp.replay`
|
|
164
|
-
- `dlab.project.esvp.sync_network`
|
|
165
|
-
- `dlab.project.esvp.app_trace_bootstrap`
|
|
166
|
-
|
|
167
|
-
CLI surface:
|
|
168
|
-
|
|
169
|
-
- `discoverylab esvp status`
|
|
170
|
-
- `discoverylab esvp devices`
|
|
171
|
-
- `discoverylab esvp sessions`
|
|
172
|
-
- `discoverylab esvp create`
|
|
173
|
-
- `discoverylab esvp get <sessionId>`
|
|
174
|
-
- `discoverylab esvp inspect <sessionId>`
|
|
175
|
-
- `discoverylab esvp transcript <sessionId>`
|
|
176
|
-
- `discoverylab esvp artifacts <sessionId>`
|
|
177
|
-
- `discoverylab esvp artifact <sessionId> <artifactPath>`
|
|
178
|
-
- `discoverylab esvp actions <sessionId>`
|
|
179
|
-
- `discoverylab esvp checkpoint <sessionId>`
|
|
180
|
-
- `discoverylab esvp finish <sessionId>`
|
|
181
|
-
- `discoverylab esvp replay-run <sessionId>`
|
|
182
|
-
- `discoverylab esvp replay-validate <sessionId>`
|
|
183
|
-
- `discoverylab esvp replay-consistency <sessionId>`
|
|
184
|
-
- `discoverylab esvp network <sessionId>`
|
|
185
|
-
- `discoverylab esvp network-configure <sessionId>`
|
|
186
|
-
- `discoverylab esvp network-clear <sessionId>`
|
|
187
|
-
- `discoverylab esvp trace-attach <sessionId>`
|
|
188
|
-
|
|
189
|
-
Mobile recording bridge:
|
|
105
|
+
## CLI Commands
|
|
190
106
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
- iOS recordings validate through `maestro-ios`
|
|
200
|
-
- `POST /api/testing/mobile/recordings/:id/esvp/validate` also accepts an optional `network` payload. If present, App Lab asks ESVP to configure the session before replaying the flow.
|
|
201
|
-
- App Lab local now prefers `network.mode=external-proxy`.
|
|
202
|
-
- In `external-proxy` mode, the proxy belongs to the App Lab client and App Lab only uses ESVP to persist `network_profile` / `network_trace`.
|
|
203
|
-
- If `network.mode` is omitted, App Lab defaults to `external-proxy`. `managed-proxy` remains available only when explicitly requested.
|
|
204
|
-
- If `external-proxy` is selected without an explicit `proxy.host` / `proxy.port`, App Lab now auto-starts a local HTTP proxy for the ESVP session and attaches the resulting `network_trace` when the session stops.
|
|
205
|
-
- Practical host rules for local proxying:
|
|
206
|
-
- iOS Simulator can use `127.0.0.1` when the proxy runs on the same macOS host.
|
|
207
|
-
- Android Emulator should use `10.0.2.2` to reach a proxy on the host.
|
|
208
|
-
- Physical Android devices need a host/LAN IP, not `127.0.0.1`.
|
|
209
|
-
- Optional env vars for the client-owned proxy:
|
|
210
|
-
- `DISCOVERYLAB_NETWORK_PROXY_PORT`
|
|
211
|
-
- `DISCOVERYLAB_NETWORK_PROXY_HOST`
|
|
212
|
-
- `DISCOVERYLAB_NETWORK_PROXY_BIND_HOST`
|
|
213
|
-
- `DISCOVERYLAB_NETWORK_PROXY_PROTOCOL`
|
|
214
|
-
- `DISCOVERYLAB_NETWORK_PROXY_BYPASS`
|
|
215
|
-
- `DISCOVERYLAB_NETWORK_PROXY_MAX_DURATION_MS`
|
|
216
|
-
- Host compatibility for local proxying:
|
|
217
|
-
- macOS host + iOS Simulator: supported. This is the only local iOS path, because Simulator / `maestro-ios` / `ios-sim` are macOS-only.
|
|
218
|
-
- macOS host + Android Emulator / physical Android: supported, as long as `adb` is installed and the device is reachable.
|
|
219
|
-
- Linux host + Android Emulator / physical Android: supported, as long as `adb` is installed and the device is reachable.
|
|
220
|
-
- Android local proxying is not tied to macOS. The local proxy is a Node.js HTTP proxy and the ESVP `adb` executor applies the proxy through ADB.
|
|
221
|
-
- Android prerequisites:
|
|
222
|
-
- `adb` must be installed and available on `PATH` before starting App Lab / ESVP flows.
|
|
223
|
-
- Android Emulator should use `10.0.2.2` to reach the host proxy.
|
|
224
|
-
- Physical Android devices must use a host/LAN IP reachable from the device.
|
|
225
|
-
- `DISCOVERYLAB_NETWORK_PROXY_BIND_HOST` can be used when the proxy must listen on a LAN-facing interface instead of loopback.
|
|
226
|
-
- Safety defaults for the local proxy:
|
|
227
|
-
- App Lab now auto-finalizes App-owned local proxies after `15m` by default to avoid leaving the host/device pointed at a stale proxy.
|
|
228
|
-
- Auto-finalization clears ESVP network state, stops the local proxy, attaches the captured `network_trace`, and finishes the session.
|
|
229
|
-
- App Lab Settings now expose an emergency lock for App-owned proxy autostart. Enabling it immediately finalizes active App-owned proxies and blocks new auto-started local proxies until you unlock it.
|
|
230
|
-
- App Lab Settings also expose a `Disable Active Proxy Now` panic button that forces cleanup without changing the lock state.
|
|
231
|
-
- Server shutdown always attempts the same cleanup path, so App-owned proxies are finalized automatically when the App Lab server exits normally.
|
|
232
|
-
- Set `DISCOVERYLAB_NETWORK_PROXY_MAX_DURATION_MS=0` only if you explicitly want to disable this guardrail.
|
|
233
|
-
- Current limitation:
|
|
234
|
-
- Automatic local proxying covers HTTP proxy setup and trace attach only. Advanced fault injection still requires explicit `managed-proxy`.
|
|
235
|
-
- `managed-proxy` is still useful for public-runtime validation and fault-injection experiments.
|
|
236
|
-
|
|
237
|
-
Example request body for ESVP-backed validation with external proxy:
|
|
238
|
-
|
|
239
|
-
```json
|
|
240
|
-
{
|
|
241
|
-
"network": {
|
|
242
|
-
"mode": "external-proxy",
|
|
243
|
-
"profile": "applab-standard-capture",
|
|
244
|
-
"proxy": {
|
|
245
|
-
"host": "10.0.2.2",
|
|
246
|
-
"port": 8080
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
}
|
|
107
|
+
```bash
|
|
108
|
+
discoverylab serve # start web UI
|
|
109
|
+
discoverylab install # auto-detect + configure MCP
|
|
110
|
+
discoverylab install --target desktop # Claude Desktop only
|
|
111
|
+
discoverylab export <project-id> --format infographic --open
|
|
112
|
+
discoverylab import <file.applab> # import shared project
|
|
113
|
+
discoverylab setup # check dependencies
|
|
114
|
+
discoverylab info # version info
|
|
250
115
|
```
|
|
251
116
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
- `Check my ESVP control-plane health`
|
|
255
|
-
- `Create an ios-sim ESVP session and take a screenshot`
|
|
256
|
-
- `Create a maestro-ios ESVP session and replay this iOS recording with an external proxy`
|
|
257
|
-
- `Configure a proxy on this ESVP session and attach the HTTP trace from ./trace.json`
|
|
258
|
-
- `Replay the failing Android session on the current emulator`
|
|
259
|
-
|
|
260
|
-
Programmatic usage:
|
|
117
|
+
## Requirements
|
|
261
118
|
|
|
262
|
-
|
|
263
|
-
|
|
119
|
+
- Node.js 20+
|
|
120
|
+
- FFmpeg (for video/GIF export)
|
|
121
|
+
- Maestro CLI (optional, for mobile testing)
|
|
122
|
+
- Playwright (optional, for web testing)
|
|
264
123
|
|
|
265
|
-
|
|
266
|
-
executor: 'ios-sim',
|
|
267
|
-
meta: { source: 'demo' },
|
|
268
|
-
});
|
|
124
|
+
## Platform Support
|
|
269
125
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
126
|
+
| | macOS | Windows | Linux |
|
|
127
|
+
|---|:---:|:---:|:---:|
|
|
128
|
+
| Web UI | ✓ | ✓ | ✓ |
|
|
129
|
+
| iOS Capture | ✓ | — | — |
|
|
130
|
+
| Android Capture | ✓ | ✓ | ✓ |
|
|
131
|
+
| Web Recording | ✓ | ✓ | ✓ |
|
|
132
|
+
| Apple Vision OCR | ✓ | — | — |
|
|
133
|
+
| Claude Desktop | ✓ | ✓ | — |
|
|
275
134
|
|
|
276
135
|
## License
|
|
277
136
|
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import {
|
|
2
|
+
checkNotionAuth,
|
|
3
|
+
createNotionPage,
|
|
4
|
+
loginToNotion,
|
|
5
|
+
quickExportToNotion
|
|
6
|
+
} from "./chunk-34GGYFXX.js";
|
|
1
7
|
import {
|
|
2
8
|
detectKeyFrames,
|
|
3
9
|
extractFrames,
|
|
@@ -10,12 +16,6 @@ import {
|
|
|
10
16
|
createJsonResult,
|
|
11
17
|
createTextResult
|
|
12
18
|
} from "./chunk-XKX6NBHF.js";
|
|
13
|
-
import {
|
|
14
|
-
checkNotionAuth,
|
|
15
|
-
createNotionPage,
|
|
16
|
-
loginToNotion,
|
|
17
|
-
quickExportToNotion
|
|
18
|
-
} from "./chunk-34GGYFXX.js";
|
|
19
19
|
import {
|
|
20
20
|
getAvailableTemplates,
|
|
21
21
|
isTemplatesInstalled
|
|
@@ -3776,6 +3776,93 @@ var exportSequenceTool = {
|
|
|
3776
3776
|
}, null, 2));
|
|
3777
3777
|
}
|
|
3778
3778
|
};
|
|
3779
|
+
var exportInfographicTool = {
|
|
3780
|
+
name: "dlab.export.infographic",
|
|
3781
|
+
description: "Export a DiscoveryLab project as an interactive HTML infographic. Generates a self-contained offline HTML file with animated frame player, hotspots, annotations, and baseline status.",
|
|
3782
|
+
inputSchema: z6.object({
|
|
3783
|
+
projectId: z6.string().describe("Project ID"),
|
|
3784
|
+
open: z6.boolean().optional().describe("Open in browser after export"),
|
|
3785
|
+
outputPath: z6.string().optional().describe("Custom output directory")
|
|
3786
|
+
}),
|
|
3787
|
+
handler: async (params) => {
|
|
3788
|
+
try {
|
|
3789
|
+
const { projects: projectsTable, frames: framesTable, FRAMES_DIR, PROJECTS_DIR: PROJECTS_DIR3 } = await import("./db-5ECN3O7F.js");
|
|
3790
|
+
const { eq: eq4 } = await import("drizzle-orm");
|
|
3791
|
+
const { collectFrameImages, buildInfographicData, generateInfographicHtml } = await import("./infographic-GQAHEOAA.js");
|
|
3792
|
+
const db = getDatabase();
|
|
3793
|
+
const [project] = await db.select().from(projectsTable).where(eq4(projectsTable.id, params.projectId)).limit(1);
|
|
3794
|
+
if (!project) return createErrorResult(`Project not found: ${params.projectId}`);
|
|
3795
|
+
const dbFrames = await db.select().from(framesTable).where(eq4(framesTable.projectId, project.id)).orderBy(framesTable.frameNumber).limit(20);
|
|
3796
|
+
let frameFiles;
|
|
3797
|
+
let frameOcr;
|
|
3798
|
+
if (dbFrames.length > 0) {
|
|
3799
|
+
frameFiles = dbFrames.map((f) => f.imagePath);
|
|
3800
|
+
frameOcr = dbFrames;
|
|
3801
|
+
} else {
|
|
3802
|
+
frameFiles = collectFrameImages(
|
|
3803
|
+
path5.join(FRAMES_DIR, project.id),
|
|
3804
|
+
project.videoPath,
|
|
3805
|
+
PROJECTS_DIR3,
|
|
3806
|
+
project.id
|
|
3807
|
+
);
|
|
3808
|
+
frameOcr = frameFiles.map(() => ({ ocrText: null }));
|
|
3809
|
+
}
|
|
3810
|
+
if (frameFiles.length === 0) {
|
|
3811
|
+
return createErrorResult("No frames found. Run analyzer first.");
|
|
3812
|
+
}
|
|
3813
|
+
const data = buildInfographicData(project, frameFiles, frameOcr);
|
|
3814
|
+
const slug = (project.marketingTitle || project.name || project.id).toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 40);
|
|
3815
|
+
const outputFilePath = params.outputPath ? path5.join(params.outputPath, `${slug}-infographic.html`) : path5.join(EXPORTS_DIR, `${slug}-infographic.html`);
|
|
3816
|
+
const result = generateInfographicHtml(data, outputFilePath);
|
|
3817
|
+
if (!result.success) {
|
|
3818
|
+
return createErrorResult(`Export failed: ${result.error}`);
|
|
3819
|
+
}
|
|
3820
|
+
if (params.open) {
|
|
3821
|
+
const { exec: exec5 } = await import("child_process");
|
|
3822
|
+
exec5(`open "${result.outputPath}"`);
|
|
3823
|
+
}
|
|
3824
|
+
const sizeKb = ((result.size || 0) / 1024).toFixed(1);
|
|
3825
|
+
return createTextResult(`Infographic exported!
|
|
3826
|
+
|
|
3827
|
+
Path: ${result.outputPath}
|
|
3828
|
+
Size: ${sizeKb}KB
|
|
3829
|
+
Frames: ${result.frameCount}
|
|
3830
|
+
|
|
3831
|
+
Open in any browser to view.`);
|
|
3832
|
+
} catch (error) {
|
|
3833
|
+
return createErrorResult(`Export failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
3834
|
+
}
|
|
3835
|
+
}
|
|
3836
|
+
};
|
|
3837
|
+
var importProjectTool = {
|
|
3838
|
+
name: "dlab.project.import",
|
|
3839
|
+
description: "Import a shared .applab project bundle file. Use this when someone shares a .applab file with you.",
|
|
3840
|
+
inputSchema: z6.object({
|
|
3841
|
+
filePath: z6.string().describe("Path to the .applab file")
|
|
3842
|
+
}),
|
|
3843
|
+
handler: async (params) => {
|
|
3844
|
+
try {
|
|
3845
|
+
const { projects: projectsTable, frames: framesTable, DATA_DIR: DATA_DIR2, FRAMES_DIR, PROJECTS_DIR: PROJECTS_DIR3 } = await import("./db-5ECN3O7F.js");
|
|
3846
|
+
const { importApplabBundle } = await import("./import-W2JEW254.js");
|
|
3847
|
+
const db = getDatabase();
|
|
3848
|
+
const result = await importApplabBundle(params.filePath, db, { projects: projectsTable, frames: framesTable }, {
|
|
3849
|
+
dataDir: DATA_DIR2,
|
|
3850
|
+
framesDir: FRAMES_DIR,
|
|
3851
|
+
projectsDir: PROJECTS_DIR3
|
|
3852
|
+
});
|
|
3853
|
+
if (!result.success) return createErrorResult(`Import failed: ${result.error}`);
|
|
3854
|
+
return createTextResult(`Project imported!
|
|
3855
|
+
|
|
3856
|
+
Name: ${result.projectName}
|
|
3857
|
+
ID: ${result.projectId}
|
|
3858
|
+
Frames: ${result.frameCount}
|
|
3859
|
+
|
|
3860
|
+
Use dlab.knowledge.search to query this project.`);
|
|
3861
|
+
} catch (error) {
|
|
3862
|
+
return createErrorResult(`Import failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
3863
|
+
}
|
|
3864
|
+
}
|
|
3865
|
+
};
|
|
3779
3866
|
var exportTools = [
|
|
3780
3867
|
exportVideoTool,
|
|
3781
3868
|
exportGifTool,
|
|
@@ -3788,7 +3875,9 @@ var exportTools = [
|
|
|
3788
3875
|
exportInfoTool,
|
|
3789
3876
|
exportClipboardTool,
|
|
3790
3877
|
exportRevealTool,
|
|
3791
|
-
exportSequenceTool
|
|
3878
|
+
exportSequenceTool,
|
|
3879
|
+
exportInfographicTool,
|
|
3880
|
+
importProjectTool
|
|
3792
3881
|
];
|
|
3793
3882
|
|
|
3794
3883
|
// src/mcp/tools/testing.ts
|
|
@@ -6997,9 +7086,78 @@ Use \`dlab.knowledge.search\` with a query to find specific flows or screens.`;
|
|
|
6997
7086
|
}
|
|
6998
7087
|
}
|
|
6999
7088
|
};
|
|
7089
|
+
var knowledgeOpenTool = {
|
|
7090
|
+
name: "dlab.knowledge.open",
|
|
7091
|
+
description: `Open an interactive visual infographic of an app flow. Returns self-contained HTML that Claude Desktop renders as a canvas/artifact. Use this when the user wants to SEE a flow visually, not just read about it. The HTML includes animated frame player, annotations, and navigation.`,
|
|
7092
|
+
inputSchema: z12.object({
|
|
7093
|
+
query: z12.string().optional().describe('Search query to find the project (e.g. "login flow", "onboarding")'),
|
|
7094
|
+
projectId: z12.string().optional().describe("Direct project ID if known")
|
|
7095
|
+
}),
|
|
7096
|
+
handler: async (params) => {
|
|
7097
|
+
try {
|
|
7098
|
+
const db = getDatabase();
|
|
7099
|
+
let project = null;
|
|
7100
|
+
if (params.projectId) {
|
|
7101
|
+
const { eq: eq5 } = await import("drizzle-orm");
|
|
7102
|
+
const [p] = await db.select().from(projects).where(eq5(projects.id, params.projectId)).limit(1);
|
|
7103
|
+
project = p;
|
|
7104
|
+
} else if (params.query) {
|
|
7105
|
+
const allProjects = await db.select().from(projects).orderBy(desc2(projects.updatedAt));
|
|
7106
|
+
const query = params.query.toLowerCase();
|
|
7107
|
+
const queryTerms = query.split(/\s+/).filter((t) => t.length > 1);
|
|
7108
|
+
let bestScore = 0;
|
|
7109
|
+
for (const p of allProjects) {
|
|
7110
|
+
let score = 0;
|
|
7111
|
+
const fields = [p.name, p.marketingTitle, p.aiSummary, p.ocrText, p.tags, p.linkedTicket].filter(Boolean);
|
|
7112
|
+
for (const field of fields) {
|
|
7113
|
+
const text = field.toLowerCase();
|
|
7114
|
+
for (const term of queryTerms) {
|
|
7115
|
+
if (text.includes(term)) score += 1;
|
|
7116
|
+
}
|
|
7117
|
+
if (text.includes(query)) score += 3;
|
|
7118
|
+
}
|
|
7119
|
+
if (score > bestScore) {
|
|
7120
|
+
bestScore = score;
|
|
7121
|
+
project = p;
|
|
7122
|
+
}
|
|
7123
|
+
}
|
|
7124
|
+
}
|
|
7125
|
+
if (!project) {
|
|
7126
|
+
return createErrorResult(`No project found${params.query ? ` for "${params.query}"` : ""}. Use dlab.knowledge.summary to see available projects.`);
|
|
7127
|
+
}
|
|
7128
|
+
const { eq: eq4 } = await import("drizzle-orm");
|
|
7129
|
+
const { FRAMES_DIR, PROJECTS_DIR: PROJECTS_DIR3 } = await import("./db-5ECN3O7F.js");
|
|
7130
|
+
const { join: join12 } = await import("path");
|
|
7131
|
+
const dbFrames = await db.select().from(frames).where(eq4(frames.projectId, project.id)).orderBy(frames.frameNumber).limit(15);
|
|
7132
|
+
let frameFiles;
|
|
7133
|
+
let frameOcr;
|
|
7134
|
+
if (dbFrames.length > 0) {
|
|
7135
|
+
frameFiles = dbFrames.map((f) => f.imagePath);
|
|
7136
|
+
frameOcr = dbFrames;
|
|
7137
|
+
} else {
|
|
7138
|
+
const { collectFrameImages } = await import("./infographic-GQAHEOAA.js");
|
|
7139
|
+
frameFiles = collectFrameImages(join12(FRAMES_DIR, project.id), project.videoPath, PROJECTS_DIR3, project.id);
|
|
7140
|
+
frameOcr = frameFiles.map(() => ({ ocrText: null }));
|
|
7141
|
+
}
|
|
7142
|
+
if (frameFiles.length === 0) {
|
|
7143
|
+
return createTextResult(`Project "${project.marketingTitle || project.name}" has no frames. Run the analyzer first, then try again.`);
|
|
7144
|
+
}
|
|
7145
|
+
const { buildInfographicData, generateInfographicHtmlString } = await import("./infographic-GQAHEOAA.js");
|
|
7146
|
+
const data = buildInfographicData(project, frameFiles, frameOcr);
|
|
7147
|
+
const html = generateInfographicHtmlString(data);
|
|
7148
|
+
if (!html) {
|
|
7149
|
+
return createErrorResult("Failed to generate infographic HTML (template not found)");
|
|
7150
|
+
}
|
|
7151
|
+
return createTextResult(html);
|
|
7152
|
+
} catch (error) {
|
|
7153
|
+
return createErrorResult(`Failed to open flow: ${error instanceof Error ? error.message : String(error)}`);
|
|
7154
|
+
}
|
|
7155
|
+
}
|
|
7156
|
+
};
|
|
7000
7157
|
var knowledgeTools = [
|
|
7001
7158
|
knowledgeSearchTool,
|
|
7002
|
-
knowledgeSummaryTool
|
|
7159
|
+
knowledgeSummaryTool,
|
|
7160
|
+
knowledgeOpenTool
|
|
7003
7161
|
];
|
|
7004
7162
|
|
|
7005
7163
|
export {
|