@larkup/cli 0.2.28 → 0.2.30
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/{analytics-store-4NYU7DMO.js → analytics-store-5BPWULY4.js} +1 -1
- package/dist/{chunk-V3VNCOZ6.js → chunk-FY7KWENQ.js} +5 -4
- package/dist/{chunk-JZ3UCEGF.js → chunk-T2XKBURE.js} +42 -20
- package/dist/chunk-YUC4VMEE.js +776 -0
- package/dist/index.js +59 -29
- package/dist/{tool-loader-PEQZZWTB.js → tool-loader-2WHU3H77.js} +2 -2
- package/dist/{tool-registry-VJYLRXKJ.js → tool-registry-JS5NUNN6.js} +1 -1
- package/package.json +13 -13
- package/dist/chunk-5UWKP64Q.js +0 -212
|
@@ -0,0 +1,776 @@
|
|
|
1
|
+
// ../../packages/marketplace/src/tool-registry.ts
|
|
2
|
+
import { promises as fs } from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
|
|
5
|
+
// ../../packages/marketplace/src/types.ts
|
|
6
|
+
var DEFAULT_HUB_URL = process.env.LARKUP_HUB_URL ?? "https://hub.larkup.de";
|
|
7
|
+
var STORAGE_WARNING_THRESHOLDS = [
|
|
8
|
+
1 * 1024 * 1024 * 1024,
|
|
9
|
+
// 1 GB
|
|
10
|
+
5 * 1024 * 1024 * 1024,
|
|
11
|
+
// 5 GB
|
|
12
|
+
10 * 1024 * 1024 * 1024
|
|
13
|
+
// 10 GB
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
// ../../packages/marketplace/src/db/builtin-tools.ts
|
|
17
|
+
var BUILTIN_TOOLS = [
|
|
18
|
+
{
|
|
19
|
+
manifestVersion: "3.0",
|
|
20
|
+
kind: "tool",
|
|
21
|
+
id: "video-intelligence",
|
|
22
|
+
name: "Video Intelligence",
|
|
23
|
+
description: "Help your AI understand your videos, so you can ask questions and get answers from the right moments.",
|
|
24
|
+
longDescription: "Turn videos into knowledge your AI can understand. It listens to what is said, reads what appears on screen, and helps you find the moments that matter.",
|
|
25
|
+
category: "media",
|
|
26
|
+
version: "0.2.2",
|
|
27
|
+
pricing: "free",
|
|
28
|
+
emoji: "\u{1F3AC}",
|
|
29
|
+
icon: "Film",
|
|
30
|
+
packageName: "@larkup/tool-video-intelligence",
|
|
31
|
+
installSize: "~120 KB",
|
|
32
|
+
requiresSandbox: false,
|
|
33
|
+
author: "Larkup",
|
|
34
|
+
capabilities: [
|
|
35
|
+
"video-indexing",
|
|
36
|
+
"video-indexing-brief",
|
|
37
|
+
"agentic-video-indexing",
|
|
38
|
+
"cloud-video-runtime",
|
|
39
|
+
"timestamped-transcription",
|
|
40
|
+
"ocr",
|
|
41
|
+
"object-detection",
|
|
42
|
+
"anonymous-object-tracking",
|
|
43
|
+
"usage-metering"
|
|
44
|
+
],
|
|
45
|
+
entrypoints: { server: ".", agent: ".", ui: "./ui" },
|
|
46
|
+
runtime: {
|
|
47
|
+
protocolVersion: "1",
|
|
48
|
+
defaultMode: "managed-cloud",
|
|
49
|
+
healthPath: "/v1/health",
|
|
50
|
+
modes: [
|
|
51
|
+
{
|
|
52
|
+
id: "managed-cloud",
|
|
53
|
+
label: "Larkup Cloud",
|
|
54
|
+
description: "Index with managed private GPU capacity and your Larkup Cloud allowance.",
|
|
55
|
+
requiresGpu: true
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
id: "local",
|
|
59
|
+
label: "Local runtime",
|
|
60
|
+
icon: "/docker.png",
|
|
61
|
+
description: "Run the application locally on your computer.",
|
|
62
|
+
endpointConfigKey: "localRuntimeUrl",
|
|
63
|
+
credentialConfigKey: "localRuntimeApiKey",
|
|
64
|
+
image: "ghcr.io/larkup-ai/video-intelligence:0.1.0",
|
|
65
|
+
composeFile: "compose.yaml",
|
|
66
|
+
setupNotice: "The local application and its models download to this computer. The initial download can be large."
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
id: "custom-remote",
|
|
70
|
+
label: "Custom runtime",
|
|
71
|
+
description: "Connect a compatible Video Intelligence deployment you operate.",
|
|
72
|
+
endpointConfigKey: "customRuntimeUrl",
|
|
73
|
+
credentialConfigKey: "customRuntimeApiKey",
|
|
74
|
+
requiresGpu: true
|
|
75
|
+
}
|
|
76
|
+
]
|
|
77
|
+
},
|
|
78
|
+
billing: {
|
|
79
|
+
model: "hybrid",
|
|
80
|
+
entitlementVersion: "1",
|
|
81
|
+
meters: [
|
|
82
|
+
{ id: "source-minute", unit: "minute", description: "Minutes of source video." },
|
|
83
|
+
{
|
|
84
|
+
id: "thorough-inspection-minute",
|
|
85
|
+
unit: "minute",
|
|
86
|
+
description: "Minutes inspected with Thorough agent coverage."
|
|
87
|
+
},
|
|
88
|
+
{ id: "gpu-second", unit: "second", description: "GPU worker seconds." },
|
|
89
|
+
{ id: "ocr-frame", unit: "frame", description: "Frames processed by OCR." }
|
|
90
|
+
]
|
|
91
|
+
},
|
|
92
|
+
usage: {
|
|
93
|
+
label: "Usage this month",
|
|
94
|
+
visibleWhenRuntimeMode: ["managed-cloud"],
|
|
95
|
+
visualization: { usedKey: "sourceMinutesUsed", limitKey: "sourceMinutesLimit" },
|
|
96
|
+
support: {
|
|
97
|
+
contactLabel: "Request more usage",
|
|
98
|
+
description: "Each installation receives Cloud access automatically. Request more video-processing usage when your allowance is low.",
|
|
99
|
+
userIdConfigKey: "cloudInstallationId"
|
|
100
|
+
},
|
|
101
|
+
fields: [
|
|
102
|
+
{ key: "sourceMinutesUsed", label: "Used", format: "minutes" },
|
|
103
|
+
{ key: "sourceMinutesLimit", label: "Included", format: "minutes" },
|
|
104
|
+
{ key: "activeJobs", label: "Active jobs", format: "number" }
|
|
105
|
+
]
|
|
106
|
+
},
|
|
107
|
+
ui: {
|
|
108
|
+
isolation: "sandboxed-iframe",
|
|
109
|
+
surfaces: [
|
|
110
|
+
{
|
|
111
|
+
id: "video-indexing-brief",
|
|
112
|
+
slot: "data-indexing",
|
|
113
|
+
title: "Let your AI understand this video",
|
|
114
|
+
entrypoint: "./ui",
|
|
115
|
+
appliesTo: ["video"],
|
|
116
|
+
description: "Choose how deeply to analyze it and optionally point it to what matters most.",
|
|
117
|
+
estimate: {
|
|
118
|
+
modeField: "indexingMode",
|
|
119
|
+
variants: [
|
|
120
|
+
{
|
|
121
|
+
value: "fast",
|
|
122
|
+
analyzedFramesPerSourceMinute: 5,
|
|
123
|
+
ocrFramesPerSourceMinute: 3,
|
|
124
|
+
processingSecondsPerSourceMinute: 8,
|
|
125
|
+
maxProcessingSecondsPerSourceMinute: 15,
|
|
126
|
+
fixedOverheadSeconds: 90,
|
|
127
|
+
maxFixedOverheadSeconds: 180,
|
|
128
|
+
creditsPerSourceMinute: 1
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
value: "balanced",
|
|
132
|
+
analyzedFramesPerSourceMinute: 12,
|
|
133
|
+
ocrFramesPerSourceMinute: 8,
|
|
134
|
+
processingSecondsPerSourceMinute: 16,
|
|
135
|
+
maxProcessingSecondsPerSourceMinute: 30,
|
|
136
|
+
fixedOverheadSeconds: 120,
|
|
137
|
+
maxFixedOverheadSeconds: 240,
|
|
138
|
+
creditsPerSourceMinute: 2
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
value: "thorough",
|
|
142
|
+
analyzedFramesPerSourceMinute: 30,
|
|
143
|
+
ocrFramesPerSourceMinute: 20,
|
|
144
|
+
processingSecondsPerSourceMinute: 32,
|
|
145
|
+
maxProcessingSecondsPerSourceMinute: 60,
|
|
146
|
+
fixedOverheadSeconds: 180,
|
|
147
|
+
maxFixedOverheadSeconds: 360,
|
|
148
|
+
creditsPerSourceMinute: 4
|
|
149
|
+
}
|
|
150
|
+
]
|
|
151
|
+
},
|
|
152
|
+
form: {
|
|
153
|
+
submitLabel: "Start indexing",
|
|
154
|
+
fields: [
|
|
155
|
+
{
|
|
156
|
+
key: "goal",
|
|
157
|
+
type: "textarea",
|
|
158
|
+
label: "What should your AI look for? (optional)",
|
|
159
|
+
placeholder: "For example: find the final score, the moment the package is dropped, or every mention of pricing."
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
key: "indexingMode",
|
|
163
|
+
type: "select",
|
|
164
|
+
label: "Coverage",
|
|
165
|
+
defaultValue: "balanced",
|
|
166
|
+
options: [
|
|
167
|
+
{
|
|
168
|
+
label: "Fast",
|
|
169
|
+
value: "fast",
|
|
170
|
+
description: "Sample key frames for a quick overview.",
|
|
171
|
+
setValues: { processingAuthorityConfirmed: false }
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
label: "Balanced",
|
|
175
|
+
value: "balanced",
|
|
176
|
+
description: "Sample visual and OCR evidence across the video.",
|
|
177
|
+
setValues: { processingAuthorityConfirmed: false }
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
label: "Thorough",
|
|
181
|
+
value: "thorough",
|
|
182
|
+
description: "Let the agent inspect denser evidence around subtle or infrequent details.",
|
|
183
|
+
setValues: { processingAuthorityConfirmed: false }
|
|
184
|
+
}
|
|
185
|
+
]
|
|
186
|
+
}
|
|
187
|
+
]
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
id: "video-evidence-result",
|
|
192
|
+
slot: "chat-result",
|
|
193
|
+
title: "Video evidence",
|
|
194
|
+
entrypoint: "./ui"
|
|
195
|
+
}
|
|
196
|
+
]
|
|
197
|
+
},
|
|
198
|
+
tags: ["video", "ocr", "tracking", "local", "gpu", "private", "gdpr"],
|
|
199
|
+
downloads: 0,
|
|
200
|
+
repositoryUrl: "https://github.com/Larkup-AI/larkup",
|
|
201
|
+
license: "Apache-2.0",
|
|
202
|
+
updatedAt: "2026-08-20",
|
|
203
|
+
trustLevel: "elevated",
|
|
204
|
+
permissions: {
|
|
205
|
+
fsRead: true,
|
|
206
|
+
fsWrite: true,
|
|
207
|
+
exec: true,
|
|
208
|
+
httpAllow: ["127.0.0.1", "localhost", "video.larkup.de"]
|
|
209
|
+
},
|
|
210
|
+
configSchema: [
|
|
211
|
+
{
|
|
212
|
+
key: "runtimeMode",
|
|
213
|
+
label: "Runtime",
|
|
214
|
+
type: "select",
|
|
215
|
+
group: "Runtime",
|
|
216
|
+
defaultValue: "managed-cloud",
|
|
217
|
+
help: "Choose managed Larkup Cloud, a local runtime that auto-selects Docker or native, or your compatible deployment.",
|
|
218
|
+
options: [
|
|
219
|
+
{
|
|
220
|
+
label: "Larkup Cloud",
|
|
221
|
+
value: "managed-cloud",
|
|
222
|
+
icon: "/logo.png",
|
|
223
|
+
description: "Managed GPU capacity and automatic device access."
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
label: "Local runtime",
|
|
227
|
+
value: "local",
|
|
228
|
+
icon: "/docker.png",
|
|
229
|
+
description: "Run the application locally on your computer."
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
label: "Custom runtime",
|
|
233
|
+
value: "custom-remote",
|
|
234
|
+
icon: "/icons/cloudflare.png",
|
|
235
|
+
description: "Use your deployment URL and key."
|
|
236
|
+
}
|
|
237
|
+
]
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
key: "localRuntimeUrl",
|
|
241
|
+
label: "Local runtime URL",
|
|
242
|
+
type: "text",
|
|
243
|
+
group: "Local runtime",
|
|
244
|
+
defaultValue: "http://127.0.0.1:8787",
|
|
245
|
+
help: "Use a LAN address to share the runtime with trusted users.",
|
|
246
|
+
verification: {
|
|
247
|
+
endpoint: "/api/tools/video-intelligence/verify",
|
|
248
|
+
method: "POST",
|
|
249
|
+
fields: {
|
|
250
|
+
localRuntimeUrl: "localRuntimeUrl",
|
|
251
|
+
localRuntimeApiKey: "localRuntimeApiKey",
|
|
252
|
+
runtimeMode: "runtimeMode"
|
|
253
|
+
}
|
|
254
|
+
},
|
|
255
|
+
visibleWhen: { field: "runtimeMode", equals: "local" }
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
key: "localRuntimeApiKey",
|
|
259
|
+
label: "Shared local API key",
|
|
260
|
+
type: "password",
|
|
261
|
+
group: "Local runtime",
|
|
262
|
+
help: "Optional bearer key when local runtime authentication is enabled.",
|
|
263
|
+
visibleWhen: { field: "runtimeMode", equals: "local" }
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
key: "videoVisionProvider",
|
|
267
|
+
label: "Vision provider",
|
|
268
|
+
type: "select",
|
|
269
|
+
group: "Video understanding",
|
|
270
|
+
defaultValue: "vercel_ai_gateway",
|
|
271
|
+
defaultFromGlobalConfigKey: "visionProvider",
|
|
272
|
+
help: "Defaults to your saved AI Models vision provider. Choose another provider here only for this tool.",
|
|
273
|
+
options: [
|
|
274
|
+
{
|
|
275
|
+
label: "Use AI Models",
|
|
276
|
+
value: "auto",
|
|
277
|
+
description: "Follow the workspace Vision Model setting."
|
|
278
|
+
},
|
|
279
|
+
{ label: "Google Gemini", value: "google", icon: "/icons/gemini.svg" },
|
|
280
|
+
{
|
|
281
|
+
label: "Vercel AI Gateway",
|
|
282
|
+
value: "vercel_ai_gateway",
|
|
283
|
+
icon: "/icons/vercel.svg"
|
|
284
|
+
},
|
|
285
|
+
{ label: "OpenAI", value: "openai", icon: "/icons/openai.svg" }
|
|
286
|
+
]
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
key: "videoVisionApiKey",
|
|
290
|
+
label: "Vision provider API key",
|
|
291
|
+
type: "password",
|
|
292
|
+
group: "Video understanding",
|
|
293
|
+
help: "Optional tool override. Leave empty to use the matching provider key from AI Models; it is forwarded only for the active job."
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
key: "semanticVisionModel",
|
|
297
|
+
label: "Video vision model",
|
|
298
|
+
type: "select",
|
|
299
|
+
group: "Video understanding",
|
|
300
|
+
defaultValue: "google/gemini-3.6-flash",
|
|
301
|
+
defaultFromGlobalConfigKey: "visionModelId",
|
|
302
|
+
providerField: "videoVisionProvider",
|
|
303
|
+
defaultValueByProvider: {
|
|
304
|
+
auto: "auto",
|
|
305
|
+
google: "google/gemini-3.6-flash",
|
|
306
|
+
vercel_ai_gateway: "google/gemini-3.6-flash",
|
|
307
|
+
openai: "openai/gpt-4o-mini"
|
|
308
|
+
},
|
|
309
|
+
help: "Defaults to the Vision Model in AI Models. Choose another video-capable model to override it only for this tool.",
|
|
310
|
+
verification: {
|
|
311
|
+
endpoint: "/api/tools/video-intelligence/verify",
|
|
312
|
+
method: "POST",
|
|
313
|
+
fields: {
|
|
314
|
+
videoVisionProvider: "videoVisionProvider",
|
|
315
|
+
videoVisionApiKey: "videoVisionApiKey",
|
|
316
|
+
semanticVisionModel: "semanticVisionModel"
|
|
317
|
+
}
|
|
318
|
+
},
|
|
319
|
+
options: [
|
|
320
|
+
{
|
|
321
|
+
label: "Use AI Models",
|
|
322
|
+
value: "auto",
|
|
323
|
+
description: "Follow the workspace Vision Model setting."
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
label: "Gemini 3.6 Flash",
|
|
327
|
+
value: "google/gemini-3.6-flash",
|
|
328
|
+
icon: "/icons/gemini.svg"
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
label: "Gemini 3.5 Flash",
|
|
332
|
+
value: "google/gemini-3.5-flash",
|
|
333
|
+
icon: "/icons/gemini.svg"
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
label: "GPT-4o mini",
|
|
337
|
+
value: "openai/gpt-4o-mini",
|
|
338
|
+
icon: "/icons/openai.svg"
|
|
339
|
+
}
|
|
340
|
+
]
|
|
341
|
+
},
|
|
342
|
+
{
|
|
343
|
+
key: "videoAgentProvider",
|
|
344
|
+
label: "Agent provider",
|
|
345
|
+
type: "select",
|
|
346
|
+
group: "Agent planning",
|
|
347
|
+
defaultValue: "vercel_ai_gateway",
|
|
348
|
+
defaultFromGlobalConfigKey: "chatProvider",
|
|
349
|
+
help: "Defaults to your saved AI Models chat provider. Choose another provider here only for this tool.",
|
|
350
|
+
options: [
|
|
351
|
+
{
|
|
352
|
+
label: "Use AI Models",
|
|
353
|
+
value: "auto",
|
|
354
|
+
description: "Follow the workspace Chat Model setting."
|
|
355
|
+
},
|
|
356
|
+
{ label: "Google Gemini", value: "google", icon: "/icons/gemini.svg" },
|
|
357
|
+
{
|
|
358
|
+
label: "Vercel AI Gateway",
|
|
359
|
+
value: "vercel_ai_gateway",
|
|
360
|
+
icon: "/icons/vercel.svg"
|
|
361
|
+
},
|
|
362
|
+
{ label: "OpenAI", value: "openai", icon: "/icons/openai.svg" },
|
|
363
|
+
{
|
|
364
|
+
label: "DeepSeek",
|
|
365
|
+
value: "deepseek",
|
|
366
|
+
icon: "https://models.dev/logos/deepseek.svg"
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
label: "Anthropic",
|
|
370
|
+
value: "anthropic",
|
|
371
|
+
icon: "https://models.dev/logos/anthropic.svg"
|
|
372
|
+
},
|
|
373
|
+
{
|
|
374
|
+
label: "Mistral",
|
|
375
|
+
value: "mistral",
|
|
376
|
+
icon: "https://models.dev/logos/mistral.svg"
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
label: "Cohere",
|
|
380
|
+
value: "cohere",
|
|
381
|
+
icon: "https://models.dev/logos/cohere.svg"
|
|
382
|
+
}
|
|
383
|
+
]
|
|
384
|
+
},
|
|
385
|
+
{
|
|
386
|
+
key: "videoAgentApiKey",
|
|
387
|
+
label: "Agent provider API key",
|
|
388
|
+
type: "password",
|
|
389
|
+
group: "Agent planning",
|
|
390
|
+
help: "Optional tool override. Leave empty to use the matching chat-provider key from AI Models; it is forwarded only for the active job."
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
key: "agentModel",
|
|
394
|
+
label: "Agent / tool-brain model",
|
|
395
|
+
type: "select",
|
|
396
|
+
group: "Agent planning",
|
|
397
|
+
defaultValue: "openai/gpt-5-mini",
|
|
398
|
+
defaultFromGlobalConfigKey: "chatModelId",
|
|
399
|
+
providerField: "videoAgentProvider",
|
|
400
|
+
defaultValueByProvider: {
|
|
401
|
+
auto: "auto",
|
|
402
|
+
google: "google/gemini-3.5-flash-lite",
|
|
403
|
+
vercel_ai_gateway: "openai/gpt-5-mini",
|
|
404
|
+
openai: "openai/gpt-5-mini",
|
|
405
|
+
deepseek: "deepseek/deepseek-v3.2",
|
|
406
|
+
anthropic: "anthropic/claude-sonnet-4",
|
|
407
|
+
mistral: "mistral/mistral-large-3",
|
|
408
|
+
cohere: "cohere/command-a"
|
|
409
|
+
},
|
|
410
|
+
help: "Defaults to the Chat Model in AI Models. Choose another model to override it only for video planning and synthesis.",
|
|
411
|
+
verification: {
|
|
412
|
+
endpoint: "/api/tools/video-intelligence/verify",
|
|
413
|
+
method: "POST",
|
|
414
|
+
fields: {
|
|
415
|
+
videoAgentProvider: "videoAgentProvider",
|
|
416
|
+
videoAgentApiKey: "videoAgentApiKey",
|
|
417
|
+
agentModel: "agentModel"
|
|
418
|
+
}
|
|
419
|
+
},
|
|
420
|
+
options: [
|
|
421
|
+
{
|
|
422
|
+
label: "Use AI Models",
|
|
423
|
+
value: "auto",
|
|
424
|
+
description: "Follow the workspace Chat Model setting."
|
|
425
|
+
},
|
|
426
|
+
{
|
|
427
|
+
label: "Gemini 3.5 Flash Lite",
|
|
428
|
+
value: "google/gemini-3.5-flash-lite",
|
|
429
|
+
icon: "/icons/gemini.svg"
|
|
430
|
+
},
|
|
431
|
+
{
|
|
432
|
+
label: "Gemini 3.6 Flash",
|
|
433
|
+
value: "google/gemini-3.6-flash",
|
|
434
|
+
icon: "/icons/gemini.svg"
|
|
435
|
+
},
|
|
436
|
+
{ label: "GPT-5 mini", value: "openai/gpt-5-mini", icon: "/icons/openai.svg" },
|
|
437
|
+
{ label: "GPT-5.2", value: "openai/gpt-5.2", icon: "/icons/openai.svg" },
|
|
438
|
+
{
|
|
439
|
+
label: "DeepSeek V3.2",
|
|
440
|
+
value: "deepseek/deepseek-v3.2",
|
|
441
|
+
icon: "https://models.dev/logos/deepseek.svg"
|
|
442
|
+
},
|
|
443
|
+
{
|
|
444
|
+
label: "DeepSeek V4 Pro",
|
|
445
|
+
value: "deepseek/deepseek-v4-pro",
|
|
446
|
+
icon: "https://models.dev/logos/deepseek.svg"
|
|
447
|
+
},
|
|
448
|
+
{
|
|
449
|
+
label: "Claude Sonnet 4",
|
|
450
|
+
value: "anthropic/claude-sonnet-4",
|
|
451
|
+
icon: "https://models.dev/logos/anthropic.svg"
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
label: "Mistral Large 3",
|
|
455
|
+
value: "mistral/mistral-large-3",
|
|
456
|
+
icon: "https://models.dev/logos/mistral.svg"
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
label: "Command A",
|
|
460
|
+
value: "cohere/command-a",
|
|
461
|
+
icon: "https://models.dev/logos/cohere.svg"
|
|
462
|
+
}
|
|
463
|
+
]
|
|
464
|
+
},
|
|
465
|
+
{
|
|
466
|
+
key: "customRuntimeUrl",
|
|
467
|
+
label: "Custom runtime URL",
|
|
468
|
+
type: "text",
|
|
469
|
+
group: "Custom runtime",
|
|
470
|
+
required: true,
|
|
471
|
+
verification: {
|
|
472
|
+
endpoint: "/api/tools/video-intelligence/verify",
|
|
473
|
+
method: "POST",
|
|
474
|
+
fields: {
|
|
475
|
+
customRuntimeUrl: "customRuntimeUrl",
|
|
476
|
+
customRuntimeApiKey: "customRuntimeApiKey",
|
|
477
|
+
runtimeMode: "runtimeMode"
|
|
478
|
+
}
|
|
479
|
+
},
|
|
480
|
+
visibleWhen: { field: "runtimeMode", equals: "custom-remote" }
|
|
481
|
+
},
|
|
482
|
+
{
|
|
483
|
+
key: "customRuntimeApiKey",
|
|
484
|
+
label: "Custom runtime API key",
|
|
485
|
+
type: "password",
|
|
486
|
+
group: "Custom runtime",
|
|
487
|
+
required: true,
|
|
488
|
+
visibleWhen: { field: "runtimeMode", equals: "custom-remote" }
|
|
489
|
+
},
|
|
490
|
+
{
|
|
491
|
+
key: "audioProvider",
|
|
492
|
+
label: "Audio provider",
|
|
493
|
+
type: "select",
|
|
494
|
+
group: "Audio",
|
|
495
|
+
defaultValue: "deepgram",
|
|
496
|
+
help: "Required for every runtime. Transcription is billed directly to your selected provider; Larkup Cloud does not supply audio-model credits.",
|
|
497
|
+
options: [
|
|
498
|
+
{
|
|
499
|
+
label: "OpenAI",
|
|
500
|
+
value: "openai",
|
|
501
|
+
icon: "/icons/openai.svg",
|
|
502
|
+
description: "Use your OpenAI transcription allowance."
|
|
503
|
+
},
|
|
504
|
+
{
|
|
505
|
+
label: "Groq",
|
|
506
|
+
value: "groq",
|
|
507
|
+
icon: "https://models.dev/logos/groq.svg",
|
|
508
|
+
description: "Fast hosted Whisper inference."
|
|
509
|
+
},
|
|
510
|
+
{
|
|
511
|
+
label: "Deepgram",
|
|
512
|
+
value: "deepgram",
|
|
513
|
+
icon: "/icons/deepgram.png",
|
|
514
|
+
description: "Speech-to-text with language features."
|
|
515
|
+
},
|
|
516
|
+
{
|
|
517
|
+
label: "ElevenLabs",
|
|
518
|
+
value: "elevenlabs",
|
|
519
|
+
icon: "/icons/elevenlabs.png",
|
|
520
|
+
description: "Use your ElevenLabs speech-to-text account."
|
|
521
|
+
}
|
|
522
|
+
]
|
|
523
|
+
},
|
|
524
|
+
{
|
|
525
|
+
key: "audioApiKey",
|
|
526
|
+
label: "Audio provider API key",
|
|
527
|
+
type: "password",
|
|
528
|
+
group: "Audio",
|
|
529
|
+
help: "Required. It stays in this installation and is forwarded only for the active video job.",
|
|
530
|
+
verification: {
|
|
531
|
+
endpoint: "/api/tools/video-intelligence/verify",
|
|
532
|
+
method: "POST",
|
|
533
|
+
fields: {
|
|
534
|
+
audioProvider: "audioProvider",
|
|
535
|
+
audioApiKey: "audioApiKey"
|
|
536
|
+
}
|
|
537
|
+
},
|
|
538
|
+
visibleWhen: {
|
|
539
|
+
field: "audioProvider",
|
|
540
|
+
equals: ["openai", "groq", "deepgram", "elevenlabs"]
|
|
541
|
+
}
|
|
542
|
+
},
|
|
543
|
+
{
|
|
544
|
+
key: "cloudAccessKey",
|
|
545
|
+
label: "Larkup Cloud API key",
|
|
546
|
+
type: "password",
|
|
547
|
+
group: "Managed cloud connection",
|
|
548
|
+
help: "Paste the key Larkup provides for managed cloud access. Leave this empty only when automatic project provisioning is enabled.",
|
|
549
|
+
visibleWhen: { field: "runtimeMode", equals: "managed-cloud" }
|
|
550
|
+
},
|
|
551
|
+
{
|
|
552
|
+
key: "defaultIndexingMode",
|
|
553
|
+
label: "Default indexing mode",
|
|
554
|
+
type: "select",
|
|
555
|
+
group: "Indexing",
|
|
556
|
+
defaultValue: "balanced",
|
|
557
|
+
options: [
|
|
558
|
+
{ label: "Fast", value: "fast" },
|
|
559
|
+
{ label: "Balanced", value: "balanced" },
|
|
560
|
+
{ label: "Thorough", value: "thorough" }
|
|
561
|
+
]
|
|
562
|
+
},
|
|
563
|
+
{
|
|
564
|
+
key: "cloudInstallationId",
|
|
565
|
+
label: "Managed cloud installation ID",
|
|
566
|
+
type: "text",
|
|
567
|
+
group: "Managed cloud connection",
|
|
568
|
+
help: "Provisioned automatically for this project.",
|
|
569
|
+
serverManaged: true
|
|
570
|
+
}
|
|
571
|
+
]
|
|
572
|
+
},
|
|
573
|
+
{
|
|
574
|
+
id: "clip-embeddings",
|
|
575
|
+
name: "CLIP Image Search",
|
|
576
|
+
description: "Direct image-to-image similarity search using CLIP/SigLIP embeddings.",
|
|
577
|
+
longDescription: "Enable native visual similarity search by embedding images with CLIP or SigLIP models. Search your image library by uploading a query image or describing what you're looking for. Requires downloading a ~200MB model on first use.",
|
|
578
|
+
category: "embedding",
|
|
579
|
+
version: "0.1.0",
|
|
580
|
+
pricing: "free",
|
|
581
|
+
emoji: "\u{1F50D}",
|
|
582
|
+
icon: "ScanEye",
|
|
583
|
+
packageName: "@larkup/tool-clip-embeddings",
|
|
584
|
+
installSize: "~200 MB",
|
|
585
|
+
author: "Larkup",
|
|
586
|
+
capabilities: ["clip-embeddings", "image-similarity"],
|
|
587
|
+
tags: ["clip", "siglip", "image-search", "visual-similarity"],
|
|
588
|
+
repositoryUrl: "https://github.com/Larkup-AI/larkup",
|
|
589
|
+
license: "Apache-2.0",
|
|
590
|
+
updatedAt: "2026-07-20",
|
|
591
|
+
comingSoon: true
|
|
592
|
+
},
|
|
593
|
+
{
|
|
594
|
+
id: "doc-editor",
|
|
595
|
+
name: "Document Editor",
|
|
596
|
+
description: "AI-powered form filling and document editing with Canvas-style live preview.",
|
|
597
|
+
longDescription: "Open PDF, Word, PowerPoint, and text files in a split-view Canvas. AI fills forms using your knowledge base, edits content on request, and previews changes live. Supports PDF form fields (AcroForm), DOCX paragraphs/tables, PPTX slide text, and plain text editing. Uses pdf-lib (native) for PDF and the Docker sandbox for DOCX/PPTX via python-docx/python-pptx.",
|
|
598
|
+
category: "utility",
|
|
599
|
+
version: "0.2.3",
|
|
600
|
+
pricing: "free",
|
|
601
|
+
emoji: "\u{1F4DD}",
|
|
602
|
+
icon: "FileEdit",
|
|
603
|
+
packageName: "@larkup/tool-doc-editor",
|
|
604
|
+
installSize: "~5 MB",
|
|
605
|
+
systemDeps: ["docker"],
|
|
606
|
+
requiresSandbox: true,
|
|
607
|
+
author: "Larkup",
|
|
608
|
+
capabilities: ["document-editing", "form-filling", "document-preview"],
|
|
609
|
+
tags: ["pdf", "docx", "pptx", "form", "canvas", "editor", "fill"],
|
|
610
|
+
repositoryUrl: "https://github.com/Larkup-AI/larkup",
|
|
611
|
+
license: "Apache-2.0",
|
|
612
|
+
updatedAt: "2026-07-20"
|
|
613
|
+
}
|
|
614
|
+
];
|
|
615
|
+
|
|
616
|
+
// ../../packages/marketplace/src/tool-registry.ts
|
|
617
|
+
var cachedRegistry = null;
|
|
618
|
+
var RETIRED_CATALOG_TOOL_IDS = /* @__PURE__ */ new Set(["video-audio"]);
|
|
619
|
+
function normalizeToolDescriptor(descriptor) {
|
|
620
|
+
return { ...descriptor, requiresSandbox: descriptor.requiresSandbox !== false };
|
|
621
|
+
}
|
|
622
|
+
function compareToolVersions(left, right) {
|
|
623
|
+
const parse = (version) => {
|
|
624
|
+
const [core, suffix = ""] = version.split("-", 2);
|
|
625
|
+
const parts = core.split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
626
|
+
return { parts, stable: suffix.length === 0 };
|
|
627
|
+
};
|
|
628
|
+
const a = parse(left);
|
|
629
|
+
const b = parse(right);
|
|
630
|
+
const length = Math.max(a.parts.length, b.parts.length);
|
|
631
|
+
for (let index = 0; index < length; index += 1) {
|
|
632
|
+
const difference = (a.parts[index] ?? 0) - (b.parts[index] ?? 0);
|
|
633
|
+
if (difference !== 0) return difference;
|
|
634
|
+
}
|
|
635
|
+
if (a.stable === b.stable) return 0;
|
|
636
|
+
return a.stable ? 1 : -1;
|
|
637
|
+
}
|
|
638
|
+
function mergeToolDescriptors(current, incoming) {
|
|
639
|
+
const merged = { ...current };
|
|
640
|
+
for (const [id, descriptor] of Object.entries(incoming)) {
|
|
641
|
+
const existing = merged[id];
|
|
642
|
+
if (!existing || compareToolVersions(descriptor.version, existing.version) >= 0) {
|
|
643
|
+
merged[id] = descriptor;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
return merged;
|
|
647
|
+
}
|
|
648
|
+
async function discoverLocalManifests() {
|
|
649
|
+
const registry = {};
|
|
650
|
+
const persistentDataDir = process.env.LARKUP_DATA_DIR?.trim();
|
|
651
|
+
const searchPaths = [
|
|
652
|
+
// Monorepo development: packages/marketplace-tools/*
|
|
653
|
+
path.resolve(process.cwd(), "packages", "marketplace-tools"),
|
|
654
|
+
// Next.js dev server runs in apps/web
|
|
655
|
+
path.resolve(process.cwd(), "..", "..", "packages", "marketplace-tools"),
|
|
656
|
+
// Installed tools: .larkup/tools/node_modules/@larkup
|
|
657
|
+
...persistentDataDir ? [path.resolve(persistentDataDir, "tools", "node_modules", "@larkup")] : [],
|
|
658
|
+
path.resolve(process.cwd(), ".larkup", "tools", "node_modules", "@larkup"),
|
|
659
|
+
path.resolve(process.cwd(), "..", "..", ".larkup", "tools", "node_modules", "@larkup")
|
|
660
|
+
];
|
|
661
|
+
for (const searchPath of searchPaths) {
|
|
662
|
+
try {
|
|
663
|
+
const entries = await fs.readdir(searchPath, { withFileTypes: true });
|
|
664
|
+
for (const entry of entries) {
|
|
665
|
+
if (!entry.isDirectory()) continue;
|
|
666
|
+
const manifestPath = path.join(searchPath, entry.name, "tool.manifest.json");
|
|
667
|
+
try {
|
|
668
|
+
const raw = await fs.readFile(manifestPath, "utf8");
|
|
669
|
+
const manifest = normalizeToolDescriptor(JSON.parse(raw));
|
|
670
|
+
if (manifest.id && !RETIRED_CATALOG_TOOL_IDS.has(manifest.id)) {
|
|
671
|
+
registry[manifest.id] = manifest;
|
|
672
|
+
}
|
|
673
|
+
} catch {
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
} catch {
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
return registry;
|
|
680
|
+
}
|
|
681
|
+
async function fetchHubCatalog(hubUrl) {
|
|
682
|
+
const baseUrl = hubUrl ?? DEFAULT_HUB_URL;
|
|
683
|
+
try {
|
|
684
|
+
const controller = new AbortController();
|
|
685
|
+
const timeout = setTimeout(() => controller.abort(), 5e3);
|
|
686
|
+
const res = await fetch(`${baseUrl}/v1/tools`, {
|
|
687
|
+
signal: controller.signal,
|
|
688
|
+
headers: { Accept: "application/json" }
|
|
689
|
+
});
|
|
690
|
+
clearTimeout(timeout);
|
|
691
|
+
if (!res.ok) return {};
|
|
692
|
+
const data = await res.json();
|
|
693
|
+
const registry = {};
|
|
694
|
+
for (const tool of data.tools ?? []) {
|
|
695
|
+
if (tool.id && !RETIRED_CATALOG_TOOL_IDS.has(tool.id)) {
|
|
696
|
+
registry[tool.id] = normalizeToolDescriptor(tool);
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
return registry;
|
|
700
|
+
} catch {
|
|
701
|
+
return {};
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
async function fetchToolFromHub(toolId, hubUrl) {
|
|
705
|
+
if (RETIRED_CATALOG_TOOL_IDS.has(toolId)) return null;
|
|
706
|
+
const baseUrl = hubUrl ?? DEFAULT_HUB_URL;
|
|
707
|
+
try {
|
|
708
|
+
const controller = new AbortController();
|
|
709
|
+
const timeout = setTimeout(() => controller.abort(), 5e3);
|
|
710
|
+
const res = await fetch(`${baseUrl}/v1/tools/${toolId}`, {
|
|
711
|
+
signal: controller.signal,
|
|
712
|
+
headers: { Accept: "application/json" }
|
|
713
|
+
});
|
|
714
|
+
clearTimeout(timeout);
|
|
715
|
+
if (!res.ok) return null;
|
|
716
|
+
const data = await res.json();
|
|
717
|
+
return data.tool ?? null;
|
|
718
|
+
} catch {
|
|
719
|
+
return null;
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
var FALLBACK_REGISTRY = Object.fromEntries(
|
|
723
|
+
BUILTIN_TOOLS.map((tool) => {
|
|
724
|
+
const descriptor = normalizeToolDescriptor(tool);
|
|
725
|
+
return [descriptor.id, descriptor];
|
|
726
|
+
})
|
|
727
|
+
);
|
|
728
|
+
async function buildRegistry(opts) {
|
|
729
|
+
if (cachedRegistry) return cachedRegistry;
|
|
730
|
+
let registry = { ...FALLBACK_REGISTRY };
|
|
731
|
+
let hubAvailable = false;
|
|
732
|
+
if (!opts?.skipHub) {
|
|
733
|
+
const hubCatalog = await fetchHubCatalog(opts?.hubUrl);
|
|
734
|
+
if (Object.keys(hubCatalog).length > 0) {
|
|
735
|
+
registry = mergeToolDescriptors(registry, hubCatalog);
|
|
736
|
+
hubAvailable = true;
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
if (!hubAvailable || opts?.preferLocal) {
|
|
740
|
+
const localManifests = await discoverLocalManifests();
|
|
741
|
+
registry = mergeToolDescriptors(registry, localManifests);
|
|
742
|
+
}
|
|
743
|
+
cachedRegistry = registry;
|
|
744
|
+
return registry;
|
|
745
|
+
}
|
|
746
|
+
function invalidateRegistryCache() {
|
|
747
|
+
cachedRegistry = null;
|
|
748
|
+
}
|
|
749
|
+
async function getAllTools() {
|
|
750
|
+
const registry = await buildRegistry();
|
|
751
|
+
return Object.values(registry).sort((a, b) => a.name.localeCompare(b.name));
|
|
752
|
+
}
|
|
753
|
+
async function getToolById(id) {
|
|
754
|
+
const registry = await buildRegistry();
|
|
755
|
+
return registry[id];
|
|
756
|
+
}
|
|
757
|
+
async function getToolsWithCapability(capability) {
|
|
758
|
+
const all = await getAllTools();
|
|
759
|
+
return all.filter((t) => t.capabilities.includes(capability));
|
|
760
|
+
}
|
|
761
|
+
async function getAllCategories() {
|
|
762
|
+
const all = await getAllTools();
|
|
763
|
+
const cats = new Set(all.map((t) => t.category));
|
|
764
|
+
return Array.from(cats).sort();
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
export {
|
|
768
|
+
mergeToolDescriptors,
|
|
769
|
+
fetchToolFromHub,
|
|
770
|
+
buildRegistry,
|
|
771
|
+
invalidateRegistryCache,
|
|
772
|
+
getAllTools,
|
|
773
|
+
getToolById,
|
|
774
|
+
getToolsWithCapability,
|
|
775
|
+
getAllCategories
|
|
776
|
+
};
|