@larkup/cli 0.2.3 → 0.2.5

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.
@@ -90,7 +90,7 @@ var FALLBACK_REGISTRY = {
90
90
  name: "Video & Audio",
91
91
  description: "Index video and audio files with transcription and frame analysis.",
92
92
  category: "media",
93
- version: "0.2.0",
93
+ version: "0.2.1",
94
94
  pricing: "free",
95
95
  emoji: "\u{1F3AC}",
96
96
  icon: "Film",
@@ -171,7 +171,7 @@ var FALLBACK_REGISTRY = {
171
171
  name: "Document Editor",
172
172
  description: "AI-powered form filling and document editing with Canvas-style live preview.",
173
173
  category: "utility",
174
- version: "0.2.1",
174
+ version: "0.2.3",
175
175
  pricing: "free",
176
176
  emoji: "\u{1F4DD}",
177
177
  icon: "FileEdit",
@@ -0,0 +1,412 @@
1
+ import {
2
+ getToolById,
3
+ invalidateRegistryCache
4
+ } from "./chunk-P5JVXA7X.js";
5
+ import {
6
+ __require
7
+ } from "./chunk-3RG5ZIWI.js";
8
+
9
+ // ../../packages/marketplace/src/tool-loader.ts
10
+ import { promises as fs2 } from "fs";
11
+ import path2 from "path";
12
+ import { pathToFileURL } from "url";
13
+
14
+ // ../../packages/marketplace/src/tool-installer.ts
15
+ import { promises as fs } from "fs";
16
+ import path from "path";
17
+ import { exec as execCb } from "child_process";
18
+ import { promisify } from "util";
19
+ var execAsync = promisify(execCb);
20
+ function getToolsDir() {
21
+ return path.join(process.cwd(), ".larkup", "tools");
22
+ }
23
+ function getManifestPath() {
24
+ return path.join(getToolsDir(), "installed.json");
25
+ }
26
+ async function ensureDir() {
27
+ await fs.mkdir(getToolsDir(), { recursive: true });
28
+ }
29
+ async function readManifest() {
30
+ try {
31
+ const raw = await fs.readFile(getManifestPath(), "utf8");
32
+ const parsed = JSON.parse(raw);
33
+ if (!parsed.downloadCounts) parsed.downloadCounts = {};
34
+ for (const tool of parsed.tools ?? []) {
35
+ if (tool.packagePath && !tool.packageName) {
36
+ tool.packageName = tool.packagePath;
37
+ delete tool.packagePath;
38
+ }
39
+ if (!tool.source) tool.source = "local";
40
+ if (!tool.resolvedPath) {
41
+ tool.resolvedPath = tool.packageName;
42
+ }
43
+ }
44
+ return parsed;
45
+ } catch {
46
+ return { tools: [], downloadCounts: {}, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
47
+ }
48
+ }
49
+ async function writeManifest(manifest) {
50
+ await ensureDir();
51
+ manifest.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
52
+ await fs.writeFile(getManifestPath(), JSON.stringify(manifest, null, 2), "utf8");
53
+ }
54
+ async function getInstalledTools() {
55
+ const manifest = await readManifest();
56
+ const tools = [...manifest.tools];
57
+ const bundledIds = (process.env.LARKUP_BUNDLED_TOOLS ?? "").split(",").map((id) => id.trim()).filter(Boolean);
58
+ for (const toolId of bundledIds) {
59
+ if (tools.some((tool) => tool.id === toolId)) continue;
60
+ const descriptor = await getToolById(toolId);
61
+ if (!descriptor) continue;
62
+ tools.push({
63
+ id: toolId,
64
+ version: descriptor.version,
65
+ installedAt: "bundled",
66
+ packageName: descriptor.packageName,
67
+ resolvedPath: descriptor.packageName,
68
+ source: "local",
69
+ config: buildDefaultConfig(descriptor)
70
+ });
71
+ }
72
+ return tools;
73
+ }
74
+ async function isToolInstalled(toolId) {
75
+ const tools = await getInstalledTools();
76
+ return tools.some((t) => t.id === toolId);
77
+ }
78
+ async function getInstalledTool(toolId) {
79
+ const tools = await getInstalledTools();
80
+ return tools.find((t) => t.id === toolId);
81
+ }
82
+ async function checkSystemDeps(toolId) {
83
+ const descriptor = await getToolById(toolId);
84
+ if (!descriptor?.systemDeps?.length) return [];
85
+ const target = detectDeploymentTarget();
86
+ const missing = [];
87
+ for (const dep of descriptor.systemDeps) {
88
+ if (target === "docker" && dep === "docker") continue;
89
+ try {
90
+ await execAsync(`which ${dep}`);
91
+ } catch {
92
+ missing.push(dep);
93
+ }
94
+ }
95
+ return missing;
96
+ }
97
+ function detectDeploymentTarget() {
98
+ const explicit = process.env.LARKUP_DEPLOYMENT_TARGET;
99
+ if (explicit && ["local", "docker", "serverless", "sandbox"].includes(explicit)) {
100
+ return explicit;
101
+ }
102
+ if (process.env.VERCEL || process.env.AWS_LAMBDA_FUNCTION_NAME) return "serverless";
103
+ if (process.env.DOCKER_CONTAINER || isDockerEnvironment()) return "docker";
104
+ if (process.env.E2B_SANDBOX_ID || process.env.MODAL_TASK_ID) return "sandbox";
105
+ return "local";
106
+ }
107
+ function isDockerEnvironment() {
108
+ try {
109
+ const fs3 = __require("fs");
110
+ return fs3.existsSync("/.dockerenv");
111
+ } catch {
112
+ return false;
113
+ }
114
+ }
115
+ async function ensureToolsPackageJson() {
116
+ const toolsDir = getToolsDir();
117
+ const pkgPath = path.join(toolsDir, "package.json");
118
+ try {
119
+ await fs.access(pkgPath);
120
+ } catch {
121
+ await ensureDir();
122
+ await fs.writeFile(
123
+ pkgPath,
124
+ JSON.stringify(
125
+ {
126
+ name: "larkup-tools",
127
+ version: "1.0.0",
128
+ private: true,
129
+ description: "Isolated directory for installed Larkup marketplace tools."
130
+ },
131
+ null,
132
+ 2
133
+ ),
134
+ "utf8"
135
+ );
136
+ }
137
+ }
138
+ async function execInstall(packageName, version, target, onProgress) {
139
+ const toolsDir = getToolsDir();
140
+ switch (target) {
141
+ case "local":
142
+ case "docker": {
143
+ await ensureToolsPackageJson();
144
+ const install = async (specifier) => {
145
+ const installCmd = `npm install ${specifier} --prefix "${toolsDir}" --save --no-audit --no-fund`;
146
+ onProgress?.(`Running: npm install ${specifier}`);
147
+ const { stderr } = await execAsync(installCmd, {
148
+ cwd: toolsDir,
149
+ timeout: 12e4,
150
+ // 2 minute timeout
151
+ env: { ...process.env, NODE_ENV: "production" }
152
+ });
153
+ if (stderr && !stderr.includes("npm warn")) {
154
+ console.warn(`[marketplace] Install stderr: ${stderr}`);
155
+ }
156
+ };
157
+ try {
158
+ await install(`${packageName}@${version}`);
159
+ } catch (err) {
160
+ const message = err instanceof Error ? err.message : "Install command failed";
161
+ if (!message.includes("ETARGET") && !message.includes("No matching version found")) {
162
+ throw new Error(`Failed to install ${packageName}: ${message}`);
163
+ }
164
+ onProgress?.(
165
+ `Catalog version ${version} is unavailable; installing the latest published version\u2026`
166
+ );
167
+ try {
168
+ await install(`${packageName}@latest`);
169
+ } catch (latestErr) {
170
+ const latestMessage = latestErr instanceof Error ? latestErr.message : "Install command failed";
171
+ throw new Error(`Failed to install ${packageName}: ${latestMessage}`);
172
+ }
173
+ }
174
+ const resolvedPath = path.join(toolsDir, "node_modules", packageName);
175
+ try {
176
+ await fs.access(resolvedPath);
177
+ } catch {
178
+ throw new Error(
179
+ `Package ${packageName} was installed but could not be found at ${resolvedPath}`
180
+ );
181
+ }
182
+ const packageJson = JSON.parse(
183
+ await fs.readFile(path.join(resolvedPath, "package.json"), "utf8")
184
+ );
185
+ return { resolvedPath, version: packageJson.version ?? version };
186
+ }
187
+ case "serverless": {
188
+ onProgress?.("Serverless environment detected \u2014 queuing for next deploy");
189
+ const pendingPath = path.join(toolsDir, "pending-tools.json");
190
+ let pending = { tools: [] };
191
+ try {
192
+ const raw = await fs.readFile(pendingPath, "utf8");
193
+ pending = JSON.parse(raw);
194
+ } catch {
195
+ }
196
+ pending.tools.push({ packageName, version });
197
+ await ensureDir();
198
+ await fs.writeFile(pendingPath, JSON.stringify(pending, null, 2), "utf8");
199
+ return { resolvedPath: path.join(toolsDir, "node_modules", packageName), version };
200
+ }
201
+ case "sandbox": {
202
+ onProgress?.("Installing in sandbox environment");
203
+ await ensureToolsPackageJson();
204
+ const installCmd = `npm install ${packageName}@${version} --prefix "${toolsDir}" --save --no-audit --no-fund`;
205
+ await execAsync(installCmd, { cwd: toolsDir, timeout: 12e4 });
206
+ return { resolvedPath: path.join(toolsDir, "node_modules", packageName), version };
207
+ }
208
+ default:
209
+ throw new Error(`Unsupported deployment target: ${target}`);
210
+ }
211
+ }
212
+ async function resolveManifest(toolId) {
213
+ const descriptor = await getToolById(toolId);
214
+ if (descriptor) return descriptor;
215
+ throw new Error(`Unknown tool: ${toolId}. Not found in local registry or Hub.`);
216
+ }
217
+ async function isWorkspaceTool(packageName) {
218
+ try {
219
+ const { stdout } = await execAsync(`pnpm ls -r --depth -1 --json 2>/dev/null || true`, {
220
+ cwd: process.cwd(),
221
+ timeout: 1e4
222
+ });
223
+ const data = JSON.parse(stdout || "[]");
224
+ return Array.isArray(data) && data.some((pkg) => pkg.name === packageName);
225
+ } catch {
226
+ return false;
227
+ }
228
+ }
229
+ async function installTool(toolId, onProgress) {
230
+ const report = (stage, percent, message) => {
231
+ onProgress?.({ toolId, stage, percent, message });
232
+ };
233
+ try {
234
+ report("checking-deps", 5, "Resolving tool manifest\u2026");
235
+ const descriptor = await resolveManifest(toolId);
236
+ if (descriptor.comingSoon) {
237
+ throw new Error(`${descriptor.name} is coming soon.`);
238
+ }
239
+ report("checking-deps", 15, "Checking system dependencies\u2026");
240
+ const missing = await checkSystemDeps(toolId);
241
+ if (missing.length > 0) {
242
+ const msg = `Missing system dependencies: ${missing.join(", ")}. Please install them first.`;
243
+ report("failed", 0, msg);
244
+ throw new Error(msg);
245
+ }
246
+ const isWorkspace = await isWorkspaceTool(descriptor.packageName);
247
+ const target = detectDeploymentTarget();
248
+ let resolvedPath;
249
+ let installedVersion = descriptor.version;
250
+ let source;
251
+ if (isWorkspace) {
252
+ report("downloading", 30, "Resolving workspace package\u2026");
253
+ try {
254
+ const modulePath = __require.resolve(descriptor.packageName, {
255
+ paths: [process.cwd()]
256
+ });
257
+ resolvedPath = path.dirname(modulePath);
258
+ } catch {
259
+ resolvedPath = path.join(process.cwd(), "node_modules", descriptor.packageName);
260
+ }
261
+ source = "local";
262
+ report("installing", 60, "Workspace package resolved.");
263
+ } else {
264
+ report("downloading", 30, `Downloading ${descriptor.packageName}@${descriptor.version}\u2026`);
265
+ const installed = await execInstall(
266
+ descriptor.packageName,
267
+ descriptor.version,
268
+ target,
269
+ (msg) => report("downloading", 50, msg)
270
+ );
271
+ resolvedPath = installed.resolvedPath;
272
+ installedVersion = installed.version;
273
+ source = target === "sandbox" ? "sandbox" : "registry";
274
+ report("installing", 70, "Package installed.");
275
+ }
276
+ report("installing", 80, "Registering tool\u2026");
277
+ await ensureDir();
278
+ const manifest = await readManifest();
279
+ const existing = manifest.tools.findIndex((t) => t.id === toolId);
280
+ const entry = {
281
+ id: toolId,
282
+ version: installedVersion,
283
+ installedAt: (/* @__PURE__ */ new Date()).toISOString(),
284
+ packageName: descriptor.packageName,
285
+ resolvedPath,
286
+ source,
287
+ config: buildDefaultConfig(descriptor)
288
+ };
289
+ if (existing >= 0) {
290
+ manifest.tools[existing] = entry;
291
+ } else {
292
+ manifest.tools.push(entry);
293
+ }
294
+ manifest.downloadCounts[toolId] = (manifest.downloadCounts[toolId] ?? 0) + 1;
295
+ await writeManifest(manifest);
296
+ notifyHubInstall(toolId).catch(() => {
297
+ });
298
+ invalidateRegistryCache();
299
+ report("completed", 100, "Installed successfully.");
300
+ } catch (err) {
301
+ const message = err instanceof Error ? err.message : "Installation failed.";
302
+ report("failed", 0, message);
303
+ throw err;
304
+ }
305
+ }
306
+ async function uninstallTool(toolId) {
307
+ const manifest = await readManifest();
308
+ const tool = manifest.tools.find((t) => t.id === toolId);
309
+ manifest.tools = manifest.tools.filter((t) => t.id !== toolId);
310
+ await writeManifest(manifest);
311
+ if (tool?.source === "registry" && tool.packageName) {
312
+ try {
313
+ const toolsDir = getToolsDir();
314
+ await execAsync(`npm uninstall ${tool.packageName} --prefix "${toolsDir}"`, {
315
+ cwd: toolsDir,
316
+ timeout: 3e4
317
+ });
318
+ } catch {
319
+ }
320
+ }
321
+ invalidateRegistryCache();
322
+ const { unloadTool: unloadTool2 } = await import("./tool-loader-B2J2R64F.js");
323
+ unloadTool2(toolId);
324
+ }
325
+ async function notifyHubInstall(toolId) {
326
+ const hubUrl = process.env.LARKUP_HUB_URL ?? "https://hub.larkup.de";
327
+ try {
328
+ const controller = new AbortController();
329
+ const timeout = setTimeout(() => controller.abort(), 3e3);
330
+ await fetch(`${hubUrl}/v1/tools/${toolId}/installed`, {
331
+ method: "POST",
332
+ signal: controller.signal,
333
+ headers: { "Content-Type": "application/json" }
334
+ });
335
+ clearTimeout(timeout);
336
+ } catch {
337
+ }
338
+ }
339
+ function buildDefaultConfig(descriptor) {
340
+ const config = {};
341
+ for (const field of descriptor.configSchema ?? []) {
342
+ if (field.defaultValue !== void 0) {
343
+ config[field.key] = field.defaultValue;
344
+ }
345
+ }
346
+ return config;
347
+ }
348
+
349
+ // ../../packages/marketplace/src/tool-loader.ts
350
+ var moduleCache = /* @__PURE__ */ new Map();
351
+ async function loadTool(toolId) {
352
+ if (moduleCache.has(toolId)) return moduleCache.get(toolId);
353
+ const installed = await getInstalledTool(toolId);
354
+ if (!installed) return null;
355
+ try {
356
+ const importPath = await resolveImportPath(installed);
357
+ const mod = await import(
358
+ /* webpackIgnore: true */
359
+ importPath
360
+ );
361
+ moduleCache.set(toolId, mod);
362
+ return mod;
363
+ } catch (err) {
364
+ console.error(`[marketplace] Failed to load tool "${toolId}":`, err);
365
+ return null;
366
+ }
367
+ }
368
+ async function resolveImportPath(installed) {
369
+ switch (installed.source) {
370
+ case "local":
371
+ return installed.packageName;
372
+ case "registry":
373
+ case "sandbox":
374
+ return resolvePackageEntry(installed.resolvedPath);
375
+ default:
376
+ return installed.packageName;
377
+ }
378
+ }
379
+ async function resolvePackageEntry(packageDir) {
380
+ const manifestPath = path2.join(packageDir, "package.json");
381
+ const manifest = JSON.parse(await fs2.readFile(manifestPath, "utf8"));
382
+ const rootExport = typeof manifest.exports === "object" ? manifest.exports["."] : manifest.exports;
383
+ const entry = (typeof rootExport === "object" ? rootExport.import ?? rootExport.default : rootExport) ?? manifest.main ?? "index.js";
384
+ return pathToFileURL(path2.resolve(packageDir, entry)).href;
385
+ }
386
+ function isToolLoaded(toolId) {
387
+ return moduleCache.has(toolId);
388
+ }
389
+ function unloadTool(toolId) {
390
+ moduleCache.delete(toolId);
391
+ }
392
+ async function hasCapability(capability) {
393
+ const { getToolsWithCapability } = await import("./tool-registry-W3JOGDE3.js");
394
+ const tools = await getToolsWithCapability(capability);
395
+ for (const t of tools) {
396
+ const installed = await getInstalledTool(t.id);
397
+ if (installed) return true;
398
+ }
399
+ return false;
400
+ }
401
+
402
+ export {
403
+ loadTool,
404
+ isToolLoaded,
405
+ unloadTool,
406
+ hasCapability,
407
+ getInstalledTools,
408
+ isToolInstalled,
409
+ getInstalledTool,
410
+ installTool,
411
+ uninstallTool
412
+ };
package/dist/index.js CHANGED
@@ -12,11 +12,18 @@ import {
12
12
  setActiveServer,
13
13
  trackUsageEvent
14
14
  } from "./chunk-ZJLA4SIG.js";
15
+ import {
16
+ getInstalledTool,
17
+ getInstalledTools,
18
+ installTool,
19
+ isToolInstalled,
20
+ loadTool,
21
+ uninstallTool
22
+ } from "./chunk-TH2MPRMA.js";
15
23
  import {
16
24
  getAllTools,
17
- getToolById,
18
- invalidateRegistryCache
19
- } from "./chunk-SWHRNA3E.js";
25
+ getToolById
26
+ } from "./chunk-P5JVXA7X.js";
20
27
  import {
21
28
  __require
22
29
  } from "./chunk-3RG5ZIWI.js";
@@ -27,7 +34,7 @@ import { Command } from "commander";
27
34
  // package.json
28
35
  var package_default = {
29
36
  name: "@larkup/cli",
30
- version: "0.2.3",
37
+ version: "0.2.5",
31
38
  publishConfig: {
32
39
  access: "public"
33
40
  },
@@ -944,12 +951,12 @@ function addChatProviderDependency(dependencies, provider) {
944
951
  }
945
952
 
946
953
  // ../../packages/core/src/generator/generate-server.ts
947
- function lang(path15) {
948
- if (path15.endsWith(".json")) return "json";
949
- if (path15.endsWith(".mjs") || path15.endsWith(".js")) return "javascript";
950
- if (path15.endsWith(".md")) return "markdown";
951
- if (path15.endsWith("Dockerfile")) return "dockerfile";
952
- if (path15.endsWith(".yml") || path15.endsWith(".yaml")) return "yaml";
954
+ function lang(path14) {
955
+ if (path14.endsWith(".json")) return "json";
956
+ if (path14.endsWith(".mjs") || path14.endsWith(".js")) return "javascript";
957
+ if (path14.endsWith(".md")) return "markdown";
958
+ if (path14.endsWith("Dockerfile")) return "dockerfile";
959
+ if (path14.endsWith(".yml") || path14.endsWith(".yaml")) return "yaml";
953
960
  return "text";
954
961
  }
955
962
  function lancedbStore() {
@@ -2266,22 +2273,22 @@ function generateServer(config) {
2266
2273
  { path: "README.md", contents: readme(config, server) }
2267
2274
  ].map((f) => ({ ...f, language: lang(f.path) }));
2268
2275
  try {
2269
- const fs14 = __require("fs");
2270
- const path15 = __require("path");
2271
- const faviconPath = path15.resolve(process.cwd(), "public/favicon2.ico");
2272
- if (fs14.existsSync(faviconPath)) {
2276
+ const fs13 = __require("fs");
2277
+ const path14 = __require("path");
2278
+ const faviconPath = path14.resolve(process.cwd(), "public/favicon2.ico");
2279
+ if (fs13.existsSync(faviconPath)) {
2273
2280
  files.push({
2274
2281
  path: "public/favicon2.ico",
2275
- contents: fs14.readFileSync(faviconPath).toString("base64"),
2282
+ contents: fs13.readFileSync(faviconPath).toString("base64"),
2276
2283
  language: "ico",
2277
2284
  encoding: "base64"
2278
2285
  });
2279
2286
  } else {
2280
- const webFaviconPath = path15.resolve(process.cwd(), "apps/web/public/favicon2.ico");
2281
- if (fs14.existsSync(webFaviconPath)) {
2287
+ const webFaviconPath = path14.resolve(process.cwd(), "apps/web/public/favicon2.ico");
2288
+ if (fs13.existsSync(webFaviconPath)) {
2282
2289
  files.push({
2283
2290
  path: "public/favicon2.ico",
2284
- contents: fs14.readFileSync(webFaviconPath).toString("base64"),
2291
+ contents: fs13.readFileSync(webFaviconPath).toString("base64"),
2285
2292
  language: "ico",
2286
2293
  encoding: "base64"
2287
2294
  });
@@ -2295,12 +2302,12 @@ function generateServer(config) {
2295
2302
  }
2296
2303
 
2297
2304
  // ../../packages/core/src/generator/generate-agent-server.ts
2298
- function lang2(path15) {
2299
- if (path15.endsWith(".json")) return "json";
2300
- if (path15.endsWith(".mjs") || path15.endsWith(".js")) return "javascript";
2301
- if (path15.endsWith(".md")) return "markdown";
2302
- if (path15.endsWith("Dockerfile")) return "dockerfile";
2303
- if (path15.endsWith(".yml") || path15.endsWith(".yaml")) return "yaml";
2305
+ function lang2(path14) {
2306
+ if (path14.endsWith(".json")) return "json";
2307
+ if (path14.endsWith(".mjs") || path14.endsWith(".js")) return "javascript";
2308
+ if (path14.endsWith(".md")) return "markdown";
2309
+ if (path14.endsWith("Dockerfile")) return "dockerfile";
2310
+ if (path14.endsWith(".yml") || path14.endsWith(".yaml")) return "yaml";
2304
2311
  return "text";
2305
2312
  }
2306
2313
  function lancedbStore2() {
@@ -3314,22 +3321,22 @@ function generateAgentServer(config) {
3314
3321
  { path: "README.md", contents: readme2(config, server) }
3315
3322
  ].map((f) => ({ ...f, language: lang2(f.path) }));
3316
3323
  try {
3317
- const fs14 = __require("fs");
3318
- const path15 = __require("path");
3319
- const faviconPath = path15.resolve(process.cwd(), "public/favicon2.ico");
3320
- if (fs14.existsSync(faviconPath)) {
3324
+ const fs13 = __require("fs");
3325
+ const path14 = __require("path");
3326
+ const faviconPath = path14.resolve(process.cwd(), "public/favicon2.ico");
3327
+ if (fs13.existsSync(faviconPath)) {
3321
3328
  files.push({
3322
3329
  path: "public/favicon2.ico",
3323
- contents: fs14.readFileSync(faviconPath).toString("base64"),
3330
+ contents: fs13.readFileSync(faviconPath).toString("base64"),
3324
3331
  language: "ico",
3325
3332
  encoding: "base64"
3326
3333
  });
3327
3334
  } else {
3328
- const webFaviconPath = path15.resolve(process.cwd(), "apps/web/public/favicon2.ico");
3329
- if (fs14.existsSync(webFaviconPath)) {
3335
+ const webFaviconPath = path14.resolve(process.cwd(), "apps/web/public/favicon2.ico");
3336
+ if (fs13.existsSync(webFaviconPath)) {
3330
3337
  files.push({
3331
3338
  path: "public/favicon2.ico",
3332
- contents: fs14.readFileSync(webFaviconPath).toString("base64"),
3339
+ contents: fs13.readFileSync(webFaviconPath).toString("base64"),
3333
3340
  language: "ico",
3334
3341
  encoding: "base64"
3335
3342
  });
@@ -4633,8 +4640,8 @@ async function readTextFiles(files) {
4633
4640
  }
4634
4641
 
4635
4642
  // src/commands/media.ts
4636
- import { promises as fs10 } from "fs";
4637
- import path11 from "path";
4643
+ import { promises as fs9 } from "fs";
4644
+ import path10 from "path";
4638
4645
 
4639
4646
  // ../../packages/core/src/media-store.ts
4640
4647
  import { promises as fs7 } from "fs";
@@ -4776,386 +4783,44 @@ function claimMediaAsset(id) {
4776
4783
  });
4777
4784
  }
4778
4785
 
4779
- // ../../packages/marketplace/src/tool-installer.ts
4786
+ // ../../packages/marketplace/src/storage-provider.ts
4780
4787
  import { promises as fs8 } from "fs";
4781
4788
  import path9 from "path";
4782
- import { exec as execCb } from "child_process";
4783
- import { promisify as promisify2 } from "util";
4784
- var execAsync2 = promisify2(execCb);
4785
- function getToolsDir() {
4786
- return path9.join(process.cwd(), ".larkup", "tools");
4787
- }
4788
- function getManifestPath() {
4789
- return path9.join(getToolsDir(), "installed.json");
4790
- }
4791
- async function ensureDir() {
4792
- await fs8.mkdir(getToolsDir(), { recursive: true });
4793
- }
4794
- async function readManifest() {
4795
- try {
4796
- const raw = await fs8.readFile(getManifestPath(), "utf8");
4797
- const parsed = JSON.parse(raw);
4798
- if (!parsed.downloadCounts) parsed.downloadCounts = {};
4799
- for (const tool2 of parsed.tools ?? []) {
4800
- if (tool2.packagePath && !tool2.packageName) {
4801
- tool2.packageName = tool2.packagePath;
4802
- delete tool2.packagePath;
4803
- }
4804
- if (!tool2.source) tool2.source = "local";
4805
- if (!tool2.resolvedPath) {
4806
- tool2.resolvedPath = tool2.packageName;
4807
- }
4808
- }
4809
- return parsed;
4810
- } catch {
4811
- return { tools: [], downloadCounts: {}, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
4812
- }
4813
- }
4814
- async function writeManifest(manifest) {
4815
- await ensureDir();
4816
- manifest.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
4817
- await fs8.writeFile(getManifestPath(), JSON.stringify(manifest, null, 2), "utf8");
4818
- }
4819
- async function getInstalledTools() {
4820
- const manifest = await readManifest();
4821
- const tools = [...manifest.tools];
4822
- const bundledIds = (process.env.LARKUP_BUNDLED_TOOLS ?? "").split(",").map((id) => id.trim()).filter(Boolean);
4823
- for (const toolId of bundledIds) {
4824
- if (tools.some((tool2) => tool2.id === toolId)) continue;
4825
- const descriptor = await getToolById(toolId);
4826
- if (!descriptor) continue;
4827
- tools.push({
4828
- id: toolId,
4829
- version: descriptor.version,
4830
- installedAt: "bundled",
4831
- packageName: descriptor.packageName,
4832
- resolvedPath: descriptor.packageName,
4833
- source: "local",
4834
- config: buildDefaultConfig(descriptor)
4835
- });
4836
- }
4837
- return tools;
4838
- }
4839
- async function isToolInstalled(toolId) {
4840
- const tools = await getInstalledTools();
4841
- return tools.some((t) => t.id === toolId);
4842
- }
4843
- async function getInstalledTool(toolId) {
4844
- const tools = await getInstalledTools();
4845
- return tools.find((t) => t.id === toolId);
4846
- }
4847
- async function checkSystemDeps(toolId) {
4848
- const descriptor = await getToolById(toolId);
4849
- if (!descriptor?.systemDeps?.length) return [];
4850
- const missing = [];
4851
- for (const dep of descriptor.systemDeps) {
4852
- try {
4853
- await execAsync2(`which ${dep}`);
4854
- } catch {
4855
- missing.push(dep);
4856
- }
4857
- }
4858
- return missing;
4859
- }
4860
- function detectDeploymentTarget() {
4861
- const explicit = process.env.LARKUP_DEPLOYMENT_TARGET;
4862
- if (explicit && ["local", "docker", "serverless", "sandbox"].includes(explicit)) {
4863
- return explicit;
4864
- }
4865
- if (process.env.VERCEL || process.env.AWS_LAMBDA_FUNCTION_NAME) return "serverless";
4866
- if (process.env.DOCKER_CONTAINER || isDockerEnvironment()) return "docker";
4867
- if (process.env.E2B_SANDBOX_ID || process.env.MODAL_TASK_ID) return "sandbox";
4868
- return "local";
4869
- }
4870
- function isDockerEnvironment() {
4871
- try {
4872
- const fs14 = __require("fs");
4873
- return fs14.existsSync("/.dockerenv");
4874
- } catch {
4875
- return false;
4876
- }
4877
- }
4878
- async function ensureToolsPackageJson() {
4879
- const toolsDir = getToolsDir();
4880
- const pkgPath = path9.join(toolsDir, "package.json");
4881
- try {
4882
- await fs8.access(pkgPath);
4883
- } catch {
4884
- await ensureDir();
4885
- await fs8.writeFile(
4886
- pkgPath,
4887
- JSON.stringify(
4888
- {
4889
- name: "larkup-tools",
4890
- version: "1.0.0",
4891
- private: true,
4892
- description: "Isolated directory for installed Larkup marketplace tools."
4893
- },
4894
- null,
4895
- 2
4896
- ),
4897
- "utf8"
4898
- );
4899
- }
4900
- }
4901
- async function execInstall(packageName, version, target, onProgress) {
4902
- const toolsDir = getToolsDir();
4903
- switch (target) {
4904
- case "local":
4905
- case "docker": {
4906
- await ensureToolsPackageJson();
4907
- const installCmd = `npm install ${packageName}@${version} --prefix "${toolsDir}" --save --no-audit --no-fund`;
4908
- onProgress?.(`Running: npm install ${packageName}@${version}`);
4909
- try {
4910
- const { stdout, stderr } = await execAsync2(installCmd, {
4911
- cwd: toolsDir,
4912
- timeout: 12e4,
4913
- // 2 minute timeout
4914
- env: { ...process.env, NODE_ENV: "production" }
4915
- });
4916
- if (stderr && !stderr.includes("npm warn")) {
4917
- console.warn(`[marketplace] Install stderr: ${stderr}`);
4918
- }
4919
- } catch (err) {
4920
- const message = err instanceof Error ? err.message : "Install command failed";
4921
- throw new Error(`Failed to install ${packageName}: ${message}`);
4922
- }
4923
- const resolvedPath = path9.join(toolsDir, "node_modules", packageName);
4924
- try {
4925
- await fs8.access(resolvedPath);
4926
- } catch {
4927
- throw new Error(
4928
- `Package ${packageName} was installed but could not be found at ${resolvedPath}`
4929
- );
4930
- }
4931
- return resolvedPath;
4932
- }
4933
- case "serverless": {
4934
- onProgress?.("Serverless environment detected \u2014 queuing for next deploy");
4935
- const pendingPath = path9.join(toolsDir, "pending-tools.json");
4936
- let pending = { tools: [] };
4937
- try {
4938
- const raw = await fs8.readFile(pendingPath, "utf8");
4939
- pending = JSON.parse(raw);
4940
- } catch {
4941
- }
4942
- pending.tools.push({ packageName, version });
4943
- await ensureDir();
4944
- await fs8.writeFile(pendingPath, JSON.stringify(pending, null, 2), "utf8");
4945
- return path9.join(toolsDir, "node_modules", packageName);
4946
- }
4947
- case "sandbox": {
4948
- onProgress?.("Installing in sandbox environment");
4949
- await ensureToolsPackageJson();
4950
- const installCmd = `npm install ${packageName}@${version} --prefix "${toolsDir}" --save --no-audit --no-fund`;
4951
- await execAsync2(installCmd, { cwd: toolsDir, timeout: 12e4 });
4952
- return path9.join(toolsDir, "node_modules", packageName);
4953
- }
4954
- default:
4955
- throw new Error(`Unsupported deployment target: ${target}`);
4956
- }
4957
- }
4958
- async function resolveManifest(toolId) {
4959
- const descriptor = await getToolById(toolId);
4960
- if (descriptor) return descriptor;
4961
- throw new Error(`Unknown tool: ${toolId}. Not found in local registry or Hub.`);
4962
- }
4963
- async function isWorkspaceTool(packageName) {
4964
- try {
4965
- const { stdout } = await execAsync2(`pnpm ls -r --depth -1 --json 2>/dev/null || true`, {
4966
- cwd: process.cwd(),
4967
- timeout: 1e4
4968
- });
4969
- const data = JSON.parse(stdout || "[]");
4970
- return Array.isArray(data) && data.some((pkg) => pkg.name === packageName);
4971
- } catch {
4972
- return false;
4973
- }
4974
- }
4975
- async function installTool(toolId, onProgress) {
4976
- const report = (stage, percent, message) => {
4977
- onProgress?.({ toolId, stage, percent, message });
4978
- };
4979
- try {
4980
- report("checking-deps", 5, "Resolving tool manifest\u2026");
4981
- const descriptor = await resolveManifest(toolId);
4982
- if (descriptor.comingSoon) {
4983
- throw new Error(`${descriptor.name} is coming soon.`);
4984
- }
4985
- report("checking-deps", 15, "Checking system dependencies\u2026");
4986
- const missing = await checkSystemDeps(toolId);
4987
- if (missing.length > 0) {
4988
- const msg = `Missing system dependencies: ${missing.join(", ")}. Please install them first.`;
4989
- report("failed", 0, msg);
4990
- throw new Error(msg);
4991
- }
4992
- const isWorkspace = await isWorkspaceTool(descriptor.packageName);
4993
- const target = detectDeploymentTarget();
4994
- let resolvedPath;
4995
- let source;
4996
- if (isWorkspace) {
4997
- report("downloading", 30, "Resolving workspace package\u2026");
4998
- try {
4999
- const modulePath = __require.resolve(descriptor.packageName, {
5000
- paths: [process.cwd()]
5001
- });
5002
- resolvedPath = path9.dirname(modulePath);
5003
- } catch {
5004
- resolvedPath = path9.join(process.cwd(), "node_modules", descriptor.packageName);
5005
- }
5006
- source = "local";
5007
- report("installing", 60, "Workspace package resolved.");
5008
- } else {
5009
- report("downloading", 30, `Downloading ${descriptor.packageName}@${descriptor.version}\u2026`);
5010
- resolvedPath = await execInstall(
5011
- descriptor.packageName,
5012
- descriptor.version,
5013
- target,
5014
- (msg) => report("downloading", 50, msg)
5015
- );
5016
- source = target === "sandbox" ? "sandbox" : "registry";
5017
- report("installing", 70, "Package installed.");
5018
- }
5019
- report("installing", 80, "Registering tool\u2026");
5020
- await ensureDir();
5021
- const manifest = await readManifest();
5022
- const existing = manifest.tools.findIndex((t) => t.id === toolId);
5023
- const entry = {
5024
- id: toolId,
5025
- version: descriptor.version,
5026
- installedAt: (/* @__PURE__ */ new Date()).toISOString(),
5027
- packageName: descriptor.packageName,
5028
- resolvedPath,
5029
- source,
5030
- config: buildDefaultConfig(descriptor)
5031
- };
5032
- if (existing >= 0) {
5033
- manifest.tools[existing] = entry;
5034
- } else {
5035
- manifest.tools.push(entry);
5036
- }
5037
- manifest.downloadCounts[toolId] = (manifest.downloadCounts[toolId] ?? 0) + 1;
5038
- await writeManifest(manifest);
5039
- notifyHubInstall(toolId).catch(() => {
5040
- });
5041
- invalidateRegistryCache();
5042
- report("completed", 100, "Installed successfully.");
5043
- } catch (err) {
5044
- const message = err instanceof Error ? err.message : "Installation failed.";
5045
- report("failed", 0, message);
5046
- throw err;
5047
- }
5048
- }
5049
- async function uninstallTool(toolId) {
5050
- const manifest = await readManifest();
5051
- const tool2 = manifest.tools.find((t) => t.id === toolId);
5052
- manifest.tools = manifest.tools.filter((t) => t.id !== toolId);
5053
- await writeManifest(manifest);
5054
- if (tool2?.source === "registry" && tool2.packageName) {
5055
- try {
5056
- const toolsDir = getToolsDir();
5057
- await execAsync2(`npm uninstall ${tool2.packageName} --prefix "${toolsDir}"`, {
5058
- cwd: toolsDir,
5059
- timeout: 3e4
5060
- });
5061
- } catch {
5062
- }
5063
- }
5064
- invalidateRegistryCache();
5065
- }
5066
- async function notifyHubInstall(toolId) {
5067
- const hubUrl = process.env.LARKUP_HUB_URL ?? "https://hub.larkup.de";
5068
- try {
5069
- const controller = new AbortController();
5070
- const timeout = setTimeout(() => controller.abort(), 3e3);
5071
- await fetch(`${hubUrl}/v1/tools/${toolId}/installed`, {
5072
- method: "POST",
5073
- signal: controller.signal,
5074
- headers: { "Content-Type": "application/json" }
5075
- });
5076
- clearTimeout(timeout);
5077
- } catch {
5078
- }
5079
- }
5080
- function buildDefaultConfig(descriptor) {
5081
- const config = {};
5082
- for (const field of descriptor.configSchema ?? []) {
5083
- if (field.defaultValue !== void 0) {
5084
- config[field.key] = field.defaultValue;
5085
- }
5086
- }
5087
- return config;
5088
- }
5089
-
5090
- // ../../packages/marketplace/src/tool-loader.ts
5091
- var moduleCache = /* @__PURE__ */ new Map();
5092
- async function loadTool(toolId) {
5093
- if (moduleCache.has(toolId)) return moduleCache.get(toolId);
5094
- const installed = await getInstalledTool(toolId);
5095
- if (!installed) return null;
5096
- try {
5097
- const importPath = resolveImportPath(installed);
5098
- const mod = await import(
5099
- /* webpackIgnore: true */
5100
- importPath
5101
- );
5102
- moduleCache.set(toolId, mod);
5103
- return mod;
5104
- } catch (err) {
5105
- console.error(`[marketplace] Failed to load tool "${toolId}":`, err);
5106
- return null;
5107
- }
5108
- }
5109
- function resolveImportPath(installed) {
5110
- switch (installed.source) {
5111
- case "local":
5112
- return installed.packageName;
5113
- case "registry":
5114
- case "sandbox":
5115
- return installed.resolvedPath;
5116
- default:
5117
- return installed.packageName;
5118
- }
5119
- }
5120
-
5121
- // ../../packages/marketplace/src/storage-provider.ts
5122
- import { promises as fs9 } from "fs";
5123
- import path10 from "path";
5124
4789
  var LocalStorageProvider = class {
5125
4790
  id = "local";
5126
4791
  name = "Local Storage";
5127
4792
  async mediaDir() {
5128
4793
  const dataDir = await requireDataDir();
5129
- const dir = path10.join(dataDir, "media");
5130
- await fs9.mkdir(dir, { recursive: true });
4794
+ const dir = path9.join(dataDir, "media");
4795
+ await fs8.mkdir(dir, { recursive: true });
5131
4796
  return dir;
5132
4797
  }
5133
4798
  async store(key, data, _mimeType) {
5134
4799
  const dir = await this.mediaDir();
5135
- const filePath = path10.join(dir, key);
5136
- await fs9.mkdir(path10.dirname(filePath), { recursive: true });
5137
- await fs9.writeFile(filePath, data);
4800
+ const filePath = path9.join(dir, key);
4801
+ await fs8.mkdir(path9.dirname(filePath), { recursive: true });
4802
+ await fs8.writeFile(filePath, data);
5138
4803
  return `local://${key}`;
5139
4804
  }
5140
4805
  async storeFile(key, sourcePath, _mimeType) {
5141
4806
  const dir = await this.mediaDir();
5142
- const filePath = path10.join(dir, key);
5143
- await fs9.mkdir(path10.dirname(filePath), { recursive: true });
5144
- await fs9.copyFile(sourcePath, filePath);
4807
+ const filePath = path9.join(dir, key);
4808
+ await fs8.mkdir(path9.dirname(filePath), { recursive: true });
4809
+ await fs8.copyFile(sourcePath, filePath);
5145
4810
  return `local://${key}`;
5146
4811
  }
5147
4812
  async retrieve(uri) {
5148
4813
  const filePath = await this.resolvePath(uri);
5149
4814
  if (!filePath) throw new Error(`Unsupported local storage URI: ${uri}`);
5150
- return fs9.readFile(filePath);
4815
+ return fs8.readFile(filePath);
5151
4816
  }
5152
4817
  async resolvePath(uri) {
5153
4818
  if (!uri.startsWith("local://")) return void 0;
5154
4819
  const key = uri.slice("local://".length);
5155
4820
  const dir = await this.mediaDir();
5156
- const filePath = path10.resolve(dir, key);
5157
- const relative = path10.relative(dir, filePath);
5158
- if (relative.startsWith("..") || path10.isAbsolute(relative)) {
4821
+ const filePath = path9.resolve(dir, key);
4822
+ const relative = path9.relative(dir, filePath);
4823
+ if (relative.startsWith("..") || path9.isAbsolute(relative)) {
5159
4824
  throw new Error("Invalid local storage URI");
5160
4825
  }
5161
4826
  return filePath;
@@ -5164,7 +4829,7 @@ var LocalStorageProvider = class {
5164
4829
  const key = uri.replace("local://", "");
5165
4830
  const dir = await this.mediaDir();
5166
4831
  try {
5167
- await fs9.unlink(path10.join(dir, key));
4832
+ await fs8.unlink(path9.join(dir, key));
5168
4833
  } catch {
5169
4834
  }
5170
4835
  }
@@ -5183,17 +4848,17 @@ async function computeDirStats(dir) {
5183
4848
  async function walk2(d) {
5184
4849
  let entries;
5185
4850
  try {
5186
- entries = await fs9.readdir(d, { withFileTypes: true });
4851
+ entries = await fs8.readdir(d, { withFileTypes: true });
5187
4852
  } catch {
5188
4853
  return;
5189
4854
  }
5190
4855
  for (const entry of entries) {
5191
- const full = path10.join(d, entry.name);
4856
+ const full = path9.join(d, entry.name);
5192
4857
  if (entry.isDirectory()) {
5193
4858
  await walk2(full);
5194
4859
  } else {
5195
4860
  try {
5196
- const stat = await fs9.stat(full);
4861
+ const stat = await fs8.stat(full);
5197
4862
  usedBytes += stat.size;
5198
4863
  fileCount++;
5199
4864
  } catch {
@@ -5250,12 +4915,12 @@ async function processMediaCommand(inputs, options) {
5250
4915
  const assets = await Promise.all(
5251
4916
  mediaFiles.map(async (filePath) => {
5252
4917
  const type = mediaType(filePath);
5253
- const stat = await fs10.stat(filePath);
5254
- const extension = path11.extname(filePath).toLowerCase() || ".bin";
4918
+ const stat = await fs9.stat(filePath);
4919
+ const extension = path10.extname(filePath).toLowerCase() || ".bin";
5255
4920
  const key = `${type}s/${Date.now()}_${Math.random().toString(36).slice(2)}${extension}`;
5256
4921
  const mimeType = MIME_TYPES[extension] || "application/octet-stream";
5257
- const storageUri = storage.storeFile ? await storage.storeFile(key, filePath, mimeType) : await storage.store(key, await fs10.readFile(filePath), mimeType);
5258
- return { type, fileName: path11.basename(filePath), mimeType, storageUri, fileSize: stat.size };
4922
+ const storageUri = storage.storeFile ? await storage.storeFile(key, filePath, mimeType) : await storage.store(key, await fs9.readFile(filePath), mimeType);
4923
+ return { type, fileName: path10.basename(filePath), mimeType, storageUri, fileSize: stat.size };
5259
4924
  })
5260
4925
  );
5261
4926
  const stored = await addMediaAssets(assets);
@@ -5337,7 +5002,7 @@ async function processMediaAsset(asset) {
5337
5002
  if (!tool2.processVideo)
5338
5003
  throw new Error("The installed Video & Audio tool cannot process videos.");
5339
5004
  await update("Extracting video audio", 20);
5340
- const outputDir = await fs10.mkdtemp(path11.join(process.cwd(), ".larkup", "tmp-media-"));
5005
+ const outputDir = await fs9.mkdtemp(path10.join(process.cwd(), ".larkup", "tmp-media-"));
5341
5006
  try {
5342
5007
  const video = await tool2.processVideo(localFile, {
5343
5008
  outputDir,
@@ -5358,7 +5023,7 @@ async function processMediaAsset(asset) {
5358
5023
  dimensions = { width: video.meta.width, height: video.meta.height };
5359
5024
  frameCount = video.frames.length;
5360
5025
  } finally {
5361
- await fs10.rm(outputDir, { recursive: true, force: true }).catch(() => {
5026
+ await fs9.rm(outputDir, { recursive: true, force: true }).catch(() => {
5362
5027
  });
5363
5028
  }
5364
5029
  } else {
@@ -5436,7 +5101,7 @@ async function indexPendingMedia() {
5436
5101
  spinner2.stop(`Indexed ${finalRun.totalChunks} chunks`);
5437
5102
  }
5438
5103
  function mediaType(filePath) {
5439
- const extension = path11.extname(filePath).toLowerCase();
5104
+ const extension = path10.extname(filePath).toLowerCase();
5440
5105
  if ([".png", ".jpg", ".jpeg", ".webp", ".gif"].includes(extension)) return "image";
5441
5106
  if ([".mp4", ".webm", ".mov", ".mkv"].includes(extension)) return "video";
5442
5107
  if ([".mp3", ".m4a", ".wav", ".ogg", ".flac"].includes(extension)) return "audio";
@@ -5523,20 +5188,20 @@ async function indexCommand(inputs, options) {
5523
5188
  }
5524
5189
 
5525
5190
  // src/commands/generate.ts
5526
- import { promises as fs11 } from "fs";
5527
- import path12 from "path";
5191
+ import { promises as fs10 } from "fs";
5192
+ import path11 from "path";
5528
5193
  async function generateCommand(options) {
5529
5194
  await inServerScope(options.server, async () => {
5530
5195
  await requireActive();
5531
5196
  const config = await readConfig();
5532
5197
  if (options.out) {
5533
- const dir = path12.isAbsolute(options.out) ? options.out : path12.join(process.cwd(), options.out);
5198
+ const dir = path11.isAbsolute(options.out) ? options.out : path11.join(process.cwd(), options.out);
5534
5199
  const server2 = generateServer(config);
5535
- await fs11.mkdir(dir, { recursive: true });
5200
+ await fs10.mkdir(dir, { recursive: true });
5536
5201
  for (const f of server2.files) {
5537
- const dest = path12.join(dir, f.path);
5538
- await fs11.mkdir(path12.dirname(dest), { recursive: true });
5539
- await fs11.writeFile(dest, f.contents, "utf8");
5202
+ const dest = path11.join(dir, f.path);
5203
+ await fs10.mkdir(path11.dirname(dest), { recursive: true });
5204
+ await fs10.writeFile(dest, f.contents, "utf8");
5540
5205
  }
5541
5206
  log.success(`Generated ${server2.files.length} files \u2192 ${dir}`);
5542
5207
  } else {
@@ -5884,8 +5549,8 @@ async function marketplaceCommand(action = "list", toolId) {
5884
5549
  }
5885
5550
 
5886
5551
  // src/commands/deploy.ts
5887
- import { promises as fs12 } from "fs";
5888
- import path13 from "path";
5552
+ import { promises as fs11 } from "fs";
5553
+ import path12 from "path";
5889
5554
  async function deployCommand(target, options) {
5890
5555
  await inServerScope(options.server, async () => {
5891
5556
  await requireActive();
@@ -5921,13 +5586,13 @@ async function deployCommand(target, options) {
5921
5586
  });
5922
5587
  }
5923
5588
  async function copyGenerated(source, output) {
5924
- const destination = path13.resolve(output);
5925
- const relative = path13.relative(source, destination);
5926
- if (relative === "" || !relative.startsWith("..") && !path13.isAbsolute(relative)) {
5589
+ const destination = path12.resolve(output);
5590
+ const relative = path12.relative(source, destination);
5591
+ if (relative === "" || !relative.startsWith("..") && !path12.isAbsolute(relative)) {
5927
5592
  throw new Error("Deployment output must be outside the generated server directory.");
5928
5593
  }
5929
- await fs12.mkdir(destination, { recursive: true });
5930
- await fs12.cp(source, destination, { recursive: true, force: true });
5594
+ await fs11.mkdir(destination, { recursive: true });
5595
+ await fs11.cp(source, destination, { recursive: true, force: true });
5931
5596
  return destination;
5932
5597
  }
5933
5598
 
@@ -6012,8 +5677,8 @@ function openCommandForPlatform(url) {
6012
5677
  }
6013
5678
 
6014
5679
  // src/commands/documents.ts
6015
- import { promises as fs13 } from "fs";
6016
- import path14 from "path";
5680
+ import { promises as fs12 } from "fs";
5681
+ import path13 from "path";
6017
5682
 
6018
5683
  // ../../packages/core/src/corpus-retriever.ts
6019
5684
  function applyFilters(docs, filter) {
@@ -6132,10 +5797,10 @@ async function documentsCommand(action = "list", idOrPath, options) {
6132
5797
  }
6133
5798
  if (action === "export") {
6134
5799
  const format = options.format === "jsonl" ? "jsonl" : "csv";
6135
- const output = path14.resolve(options.out || idOrPath || `corpus.${format}`);
5800
+ const output = path13.resolve(options.out || idOrPath || `corpus.${format}`);
6136
5801
  const content = format === "jsonl" ? await exportCorpusAsJSONL(void 0, Number.MAX_SAFE_INTEGER) : await exportCorpusAsCSV(void 0, Number.MAX_SAFE_INTEGER);
6137
- await fs13.mkdir(path14.dirname(output), { recursive: true });
6138
- await fs13.writeFile(output, content, "utf8");
5802
+ await fs12.mkdir(path13.dirname(output), { recursive: true });
5803
+ await fs12.writeFile(output, content, "utf8");
6139
5804
  log.success(`Exported corpus \u2192 ${output}`);
6140
5805
  return;
6141
5806
  }
@@ -6161,7 +5826,7 @@ ${document.content}`);
6161
5826
  return;
6162
5827
  }
6163
5828
  if (action === "update") {
6164
- const content = options.file ? await fs13.readFile(path14.resolve(options.file), "utf8") : options.text;
5829
+ const content = options.file ? await fs12.readFile(path13.resolve(options.file), "utf8") : options.text;
6165
5830
  const updated = await updateDocument(document.id, {
6166
5831
  title: options.title,
6167
5832
  content,
@@ -0,0 +1,14 @@
1
+ import {
2
+ hasCapability,
3
+ isToolLoaded,
4
+ loadTool,
5
+ unloadTool
6
+ } from "./chunk-TH2MPRMA.js";
7
+ import "./chunk-P5JVXA7X.js";
8
+ import "./chunk-3RG5ZIWI.js";
9
+ export {
10
+ hasCapability,
11
+ isToolLoaded,
12
+ loadTool,
13
+ unloadTool
14
+ };
@@ -6,7 +6,7 @@ import {
6
6
  getToolById,
7
7
  getToolsWithCapability,
8
8
  invalidateRegistryCache
9
- } from "./chunk-SWHRNA3E.js";
9
+ } from "./chunk-P5JVXA7X.js";
10
10
  import "./chunk-3RG5ZIWI.js";
11
11
  export {
12
12
  buildRegistry,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@larkup/cli",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -28,9 +28,9 @@
28
28
  "cli-table3": "^0.6.5",
29
29
  "commander": "^15.0.0",
30
30
  "zod": "^4.4.3",
31
+ "@larkup/core": "0.2.2",
31
32
  "@larkup/vector-stores": "0.1.22",
32
- "@larkup/marketplace": "0.1.3",
33
- "@larkup/core": "0.2.2"
33
+ "@larkup/marketplace": "0.1.5"
34
34
  },
35
35
  "devDependencies": {
36
36
  "tsup": "^8.0.0",