@larkup/cli 0.1.20 → 0.2.1

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.
@@ -0,0 +1,231 @@
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/tool-registry.ts
17
+ var cachedRegistry = null;
18
+ async function discoverLocalManifests() {
19
+ const registry = {};
20
+ const searchPaths = [
21
+ // Monorepo development: packages/tools/*
22
+ path.resolve(process.cwd(), "packages", "tools"),
23
+ // Next.js dev server runs in apps/web
24
+ path.resolve(process.cwd(), "..", "..", "packages", "tools"),
25
+ // Installed tools: .larkup/tools/node_modules/@larkup
26
+ path.resolve(process.cwd(), ".larkup", "tools", "node_modules", "@larkup"),
27
+ path.resolve(process.cwd(), "..", "..", ".larkup", "tools", "node_modules", "@larkup")
28
+ ];
29
+ for (const searchPath of searchPaths) {
30
+ try {
31
+ const entries = await fs.readdir(searchPath, { withFileTypes: true });
32
+ for (const entry of entries) {
33
+ if (!entry.isDirectory()) continue;
34
+ const manifestPath = path.join(searchPath, entry.name, "tool.manifest.json");
35
+ try {
36
+ const raw = await fs.readFile(manifestPath, "utf8");
37
+ const manifest = JSON.parse(raw);
38
+ if (manifest.id) {
39
+ registry[manifest.id] = manifest;
40
+ }
41
+ } catch {
42
+ }
43
+ }
44
+ } catch {
45
+ }
46
+ }
47
+ return registry;
48
+ }
49
+ async function fetchHubCatalog(hubUrl) {
50
+ const baseUrl = hubUrl ?? DEFAULT_HUB_URL;
51
+ try {
52
+ const controller = new AbortController();
53
+ const timeout = setTimeout(() => controller.abort(), 5e3);
54
+ const res = await fetch(`${baseUrl}/v1/tools`, {
55
+ signal: controller.signal,
56
+ headers: { Accept: "application/json" }
57
+ });
58
+ clearTimeout(timeout);
59
+ if (!res.ok) return {};
60
+ const data = await res.json();
61
+ const registry = {};
62
+ for (const tool of data.tools ?? []) {
63
+ if (tool.id) registry[tool.id] = tool;
64
+ }
65
+ return registry;
66
+ } catch {
67
+ return {};
68
+ }
69
+ }
70
+ async function fetchToolFromHub(toolId, hubUrl) {
71
+ const baseUrl = hubUrl ?? DEFAULT_HUB_URL;
72
+ try {
73
+ const controller = new AbortController();
74
+ const timeout = setTimeout(() => controller.abort(), 5e3);
75
+ const res = await fetch(`${baseUrl}/v1/tools/${toolId}`, {
76
+ signal: controller.signal,
77
+ headers: { Accept: "application/json" }
78
+ });
79
+ clearTimeout(timeout);
80
+ if (!res.ok) return null;
81
+ const data = await res.json();
82
+ return data.tool ?? null;
83
+ } catch {
84
+ return null;
85
+ }
86
+ }
87
+ var FALLBACK_REGISTRY = {
88
+ "video-audio": {
89
+ id: "video-audio",
90
+ name: "Video & Audio",
91
+ description: "Index video and audio files with transcription and frame analysis.",
92
+ category: "media",
93
+ version: "0.1.0",
94
+ pricing: "free",
95
+ emoji: "\u{1F3AC}",
96
+ icon: "Film",
97
+ packageName: "@larkup/tool-video-audio",
98
+ installSize: "~15 MB",
99
+ systemDeps: ["ffmpeg"],
100
+ author: "Larkup",
101
+ capabilities: [
102
+ "video-indexing",
103
+ "audio-indexing",
104
+ "transcription",
105
+ "frame-extraction",
106
+ "youtube-import"
107
+ ],
108
+ tags: ["transcription", "ffmpeg", "video", "audio", "whisper"],
109
+ downloads: 0,
110
+ repositoryUrl: "https://github.com/Larkup-AI/larkup-rag",
111
+ license: "Apache-2.0",
112
+ updatedAt: "2026-07-20",
113
+ configSchema: [
114
+ {
115
+ key: "frameInterval",
116
+ label: "Frame extraction interval (seconds)",
117
+ type: "text",
118
+ defaultValue: "10",
119
+ help: "Baseline cadence for duration-aware coverage frames; scene changes and a reserved ending pass are added separately."
120
+ },
121
+ {
122
+ key: "audioProvider",
123
+ label: "Audio Provider",
124
+ type: "select",
125
+ help: "Choose the provider used only for audio and video transcription.",
126
+ options: [
127
+ { label: "OpenAI", value: "openai" },
128
+ { label: "Groq", value: "groq" },
129
+ { label: "Deepgram", value: "deepgram" },
130
+ { label: "ElevenLabs", value: "elevenlabs" },
131
+ { label: "Local Whisper", value: "local" }
132
+ ]
133
+ },
134
+ {
135
+ key: "audioLanguage",
136
+ label: "Transcription language",
137
+ type: "text",
138
+ defaultValue: "auto",
139
+ help: "Use auto to infer Arabic from the media title and use provider detection otherwise. Enter a language code such as ar, ar-EG, en, or de to override it."
140
+ },
141
+ {
142
+ key: "audioApiKey",
143
+ label: "Audio API Key",
144
+ type: "password",
145
+ help: "Required for the selected audio provider and kept separate from the chat model key."
146
+ }
147
+ ]
148
+ },
149
+ "clip-embeddings": {
150
+ id: "clip-embeddings",
151
+ name: "CLIP Image Search",
152
+ description: "Direct image-to-image similarity search using CLIP/SigLIP embeddings.",
153
+ category: "embedding",
154
+ version: "0.1.0",
155
+ pricing: "free",
156
+ emoji: "\u{1F50D}",
157
+ icon: "ScanEye",
158
+ packageName: "@larkup/tool-clip-embeddings",
159
+ installSize: "~200 MB",
160
+ author: "Larkup",
161
+ capabilities: ["clip-embeddings", "image-similarity"],
162
+ tags: ["clip", "siglip", "image-search", "visual-similarity"],
163
+ downloads: 0,
164
+ repositoryUrl: "https://github.com/Larkup-AI/larkup-rag",
165
+ license: "Apache-2.0",
166
+ updatedAt: "2026-07-20",
167
+ comingSoon: true
168
+ },
169
+ "doc-editor": {
170
+ id: "doc-editor",
171
+ name: "Document Editor",
172
+ description: "AI-powered form filling and document editing with Canvas-style live preview.",
173
+ category: "utility",
174
+ version: "0.1.0",
175
+ pricing: "free",
176
+ emoji: "\u{1F4DD}",
177
+ icon: "FileEdit",
178
+ packageName: "@larkup/tool-doc-editor",
179
+ installSize: "~5 MB",
180
+ systemDeps: ["docker"],
181
+ author: "Larkup",
182
+ capabilities: ["document-editing", "form-filling", "document-preview"],
183
+ tags: ["pdf", "docx", "pptx", "form", "canvas", "editor", "fill"],
184
+ downloads: 0,
185
+ repositoryUrl: "https://github.com/Larkup-AI/larkup-rag",
186
+ license: "Apache-2.0",
187
+ updatedAt: "2026-07-20"
188
+ }
189
+ };
190
+ async function buildRegistry(opts) {
191
+ if (cachedRegistry) return cachedRegistry;
192
+ const registry = { ...FALLBACK_REGISTRY };
193
+ const localManifests = await discoverLocalManifests();
194
+ Object.assign(registry, localManifests);
195
+ if (!opts?.skipHub) {
196
+ const hubCatalog = await fetchHubCatalog(opts?.hubUrl);
197
+ Object.assign(registry, hubCatalog);
198
+ }
199
+ cachedRegistry = registry;
200
+ return registry;
201
+ }
202
+ function invalidateRegistryCache() {
203
+ cachedRegistry = null;
204
+ }
205
+ async function getAllTools() {
206
+ const registry = await buildRegistry();
207
+ return Object.values(registry).sort((a, b) => a.name.localeCompare(b.name));
208
+ }
209
+ async function getToolById(id) {
210
+ const registry = await buildRegistry();
211
+ return registry[id];
212
+ }
213
+ async function getToolsWithCapability(capability) {
214
+ const all = await getAllTools();
215
+ return all.filter((t) => t.capabilities.includes(capability));
216
+ }
217
+ async function getAllCategories() {
218
+ const all = await getAllTools();
219
+ const cats = new Set(all.map((t) => t.category));
220
+ return Array.from(cats).sort();
221
+ }
222
+
223
+ export {
224
+ fetchToolFromHub,
225
+ buildRegistry,
226
+ invalidateRegistryCache,
227
+ getAllTools,
228
+ getToolById,
229
+ getToolsWithCapability,
230
+ getAllCategories
231
+ };