@larkup/cli 0.2.4 → 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.
@@ -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,10 +12,17 @@ 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
25
+ getToolById
19
26
  } from "./chunk-P5JVXA7X.js";
20
27
  import {
21
28
  __require
@@ -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.4",
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,406 +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 install = async (specifier) => {
4908
- const installCmd = `npm install ${specifier} --prefix "${toolsDir}" --save --no-audit --no-fund`;
4909
- onProgress?.(`Running: npm install ${specifier}`);
4910
- const { 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
- };
4920
- try {
4921
- await install(`${packageName}@${version}`);
4922
- } catch (err) {
4923
- const message = err instanceof Error ? err.message : "Install command failed";
4924
- if (!message.includes("ETARGET") && !message.includes("No matching version found")) {
4925
- throw new Error(`Failed to install ${packageName}: ${message}`);
4926
- }
4927
- onProgress?.(
4928
- `Catalog version ${version} is unavailable; installing the latest published version\u2026`
4929
- );
4930
- try {
4931
- await install(`${packageName}@latest`);
4932
- } catch (latestErr) {
4933
- const latestMessage = latestErr instanceof Error ? latestErr.message : "Install command failed";
4934
- throw new Error(`Failed to install ${packageName}: ${latestMessage}`);
4935
- }
4936
- }
4937
- const resolvedPath = path9.join(toolsDir, "node_modules", packageName);
4938
- try {
4939
- await fs8.access(resolvedPath);
4940
- } catch {
4941
- throw new Error(
4942
- `Package ${packageName} was installed but could not be found at ${resolvedPath}`
4943
- );
4944
- }
4945
- const packageJson = JSON.parse(
4946
- await fs8.readFile(path9.join(resolvedPath, "package.json"), "utf8")
4947
- );
4948
- return { resolvedPath, version: packageJson.version ?? version };
4949
- }
4950
- case "serverless": {
4951
- onProgress?.("Serverless environment detected \u2014 queuing for next deploy");
4952
- const pendingPath = path9.join(toolsDir, "pending-tools.json");
4953
- let pending = { tools: [] };
4954
- try {
4955
- const raw = await fs8.readFile(pendingPath, "utf8");
4956
- pending = JSON.parse(raw);
4957
- } catch {
4958
- }
4959
- pending.tools.push({ packageName, version });
4960
- await ensureDir();
4961
- await fs8.writeFile(pendingPath, JSON.stringify(pending, null, 2), "utf8");
4962
- return { resolvedPath: path9.join(toolsDir, "node_modules", packageName), version };
4963
- }
4964
- case "sandbox": {
4965
- onProgress?.("Installing in sandbox environment");
4966
- await ensureToolsPackageJson();
4967
- const installCmd = `npm install ${packageName}@${version} --prefix "${toolsDir}" --save --no-audit --no-fund`;
4968
- await execAsync2(installCmd, { cwd: toolsDir, timeout: 12e4 });
4969
- return { resolvedPath: path9.join(toolsDir, "node_modules", packageName), version };
4970
- }
4971
- default:
4972
- throw new Error(`Unsupported deployment target: ${target}`);
4973
- }
4974
- }
4975
- async function resolveManifest(toolId) {
4976
- const descriptor = await getToolById(toolId);
4977
- if (descriptor) return descriptor;
4978
- throw new Error(`Unknown tool: ${toolId}. Not found in local registry or Hub.`);
4979
- }
4980
- async function isWorkspaceTool(packageName) {
4981
- try {
4982
- const { stdout } = await execAsync2(`pnpm ls -r --depth -1 --json 2>/dev/null || true`, {
4983
- cwd: process.cwd(),
4984
- timeout: 1e4
4985
- });
4986
- const data = JSON.parse(stdout || "[]");
4987
- return Array.isArray(data) && data.some((pkg) => pkg.name === packageName);
4988
- } catch {
4989
- return false;
4990
- }
4991
- }
4992
- async function installTool(toolId, onProgress) {
4993
- const report = (stage, percent, message) => {
4994
- onProgress?.({ toolId, stage, percent, message });
4995
- };
4996
- try {
4997
- report("checking-deps", 5, "Resolving tool manifest\u2026");
4998
- const descriptor = await resolveManifest(toolId);
4999
- if (descriptor.comingSoon) {
5000
- throw new Error(`${descriptor.name} is coming soon.`);
5001
- }
5002
- report("checking-deps", 15, "Checking system dependencies\u2026");
5003
- const missing = await checkSystemDeps(toolId);
5004
- if (missing.length > 0) {
5005
- const msg = `Missing system dependencies: ${missing.join(", ")}. Please install them first.`;
5006
- report("failed", 0, msg);
5007
- throw new Error(msg);
5008
- }
5009
- const isWorkspace = await isWorkspaceTool(descriptor.packageName);
5010
- const target = detectDeploymentTarget();
5011
- let resolvedPath;
5012
- let installedVersion = descriptor.version;
5013
- let source;
5014
- if (isWorkspace) {
5015
- report("downloading", 30, "Resolving workspace package\u2026");
5016
- try {
5017
- const modulePath = __require.resolve(descriptor.packageName, {
5018
- paths: [process.cwd()]
5019
- });
5020
- resolvedPath = path9.dirname(modulePath);
5021
- } catch {
5022
- resolvedPath = path9.join(process.cwd(), "node_modules", descriptor.packageName);
5023
- }
5024
- source = "local";
5025
- report("installing", 60, "Workspace package resolved.");
5026
- } else {
5027
- report("downloading", 30, `Downloading ${descriptor.packageName}@${descriptor.version}\u2026`);
5028
- const installed = await execInstall(
5029
- descriptor.packageName,
5030
- descriptor.version,
5031
- target,
5032
- (msg) => report("downloading", 50, msg)
5033
- );
5034
- resolvedPath = installed.resolvedPath;
5035
- installedVersion = installed.version;
5036
- source = target === "sandbox" ? "sandbox" : "registry";
5037
- report("installing", 70, "Package installed.");
5038
- }
5039
- report("installing", 80, "Registering tool\u2026");
5040
- await ensureDir();
5041
- const manifest = await readManifest();
5042
- const existing = manifest.tools.findIndex((t) => t.id === toolId);
5043
- const entry = {
5044
- id: toolId,
5045
- version: installedVersion,
5046
- installedAt: (/* @__PURE__ */ new Date()).toISOString(),
5047
- packageName: descriptor.packageName,
5048
- resolvedPath,
5049
- source,
5050
- config: buildDefaultConfig(descriptor)
5051
- };
5052
- if (existing >= 0) {
5053
- manifest.tools[existing] = entry;
5054
- } else {
5055
- manifest.tools.push(entry);
5056
- }
5057
- manifest.downloadCounts[toolId] = (manifest.downloadCounts[toolId] ?? 0) + 1;
5058
- await writeManifest(manifest);
5059
- notifyHubInstall(toolId).catch(() => {
5060
- });
5061
- invalidateRegistryCache();
5062
- report("completed", 100, "Installed successfully.");
5063
- } catch (err) {
5064
- const message = err instanceof Error ? err.message : "Installation failed.";
5065
- report("failed", 0, message);
5066
- throw err;
5067
- }
5068
- }
5069
- async function uninstallTool(toolId) {
5070
- const manifest = await readManifest();
5071
- const tool2 = manifest.tools.find((t) => t.id === toolId);
5072
- manifest.tools = manifest.tools.filter((t) => t.id !== toolId);
5073
- await writeManifest(manifest);
5074
- if (tool2?.source === "registry" && tool2.packageName) {
5075
- try {
5076
- const toolsDir = getToolsDir();
5077
- await execAsync2(`npm uninstall ${tool2.packageName} --prefix "${toolsDir}"`, {
5078
- cwd: toolsDir,
5079
- timeout: 3e4
5080
- });
5081
- } catch {
5082
- }
5083
- }
5084
- invalidateRegistryCache();
5085
- }
5086
- async function notifyHubInstall(toolId) {
5087
- const hubUrl = process.env.LARKUP_HUB_URL ?? "https://hub.larkup.de";
5088
- try {
5089
- const controller = new AbortController();
5090
- const timeout = setTimeout(() => controller.abort(), 3e3);
5091
- await fetch(`${hubUrl}/v1/tools/${toolId}/installed`, {
5092
- method: "POST",
5093
- signal: controller.signal,
5094
- headers: { "Content-Type": "application/json" }
5095
- });
5096
- clearTimeout(timeout);
5097
- } catch {
5098
- }
5099
- }
5100
- function buildDefaultConfig(descriptor) {
5101
- const config = {};
5102
- for (const field of descriptor.configSchema ?? []) {
5103
- if (field.defaultValue !== void 0) {
5104
- config[field.key] = field.defaultValue;
5105
- }
5106
- }
5107
- return config;
5108
- }
5109
-
5110
- // ../../packages/marketplace/src/tool-loader.ts
5111
- var moduleCache = /* @__PURE__ */ new Map();
5112
- async function loadTool(toolId) {
5113
- if (moduleCache.has(toolId)) return moduleCache.get(toolId);
5114
- const installed = await getInstalledTool(toolId);
5115
- if (!installed) return null;
5116
- try {
5117
- const importPath = resolveImportPath(installed);
5118
- const mod = await import(
5119
- /* webpackIgnore: true */
5120
- importPath
5121
- );
5122
- moduleCache.set(toolId, mod);
5123
- return mod;
5124
- } catch (err) {
5125
- console.error(`[marketplace] Failed to load tool "${toolId}":`, err);
5126
- return null;
5127
- }
5128
- }
5129
- function resolveImportPath(installed) {
5130
- switch (installed.source) {
5131
- case "local":
5132
- return installed.packageName;
5133
- case "registry":
5134
- case "sandbox":
5135
- return installed.resolvedPath;
5136
- default:
5137
- return installed.packageName;
5138
- }
5139
- }
5140
-
5141
- // ../../packages/marketplace/src/storage-provider.ts
5142
- import { promises as fs9 } from "fs";
5143
- import path10 from "path";
5144
4789
  var LocalStorageProvider = class {
5145
4790
  id = "local";
5146
4791
  name = "Local Storage";
5147
4792
  async mediaDir() {
5148
4793
  const dataDir = await requireDataDir();
5149
- const dir = path10.join(dataDir, "media");
5150
- await fs9.mkdir(dir, { recursive: true });
4794
+ const dir = path9.join(dataDir, "media");
4795
+ await fs8.mkdir(dir, { recursive: true });
5151
4796
  return dir;
5152
4797
  }
5153
4798
  async store(key, data, _mimeType) {
5154
4799
  const dir = await this.mediaDir();
5155
- const filePath = path10.join(dir, key);
5156
- await fs9.mkdir(path10.dirname(filePath), { recursive: true });
5157
- 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);
5158
4803
  return `local://${key}`;
5159
4804
  }
5160
4805
  async storeFile(key, sourcePath, _mimeType) {
5161
4806
  const dir = await this.mediaDir();
5162
- const filePath = path10.join(dir, key);
5163
- await fs9.mkdir(path10.dirname(filePath), { recursive: true });
5164
- 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);
5165
4810
  return `local://${key}`;
5166
4811
  }
5167
4812
  async retrieve(uri) {
5168
4813
  const filePath = await this.resolvePath(uri);
5169
4814
  if (!filePath) throw new Error(`Unsupported local storage URI: ${uri}`);
5170
- return fs9.readFile(filePath);
4815
+ return fs8.readFile(filePath);
5171
4816
  }
5172
4817
  async resolvePath(uri) {
5173
4818
  if (!uri.startsWith("local://")) return void 0;
5174
4819
  const key = uri.slice("local://".length);
5175
4820
  const dir = await this.mediaDir();
5176
- const filePath = path10.resolve(dir, key);
5177
- const relative = path10.relative(dir, filePath);
5178
- 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)) {
5179
4824
  throw new Error("Invalid local storage URI");
5180
4825
  }
5181
4826
  return filePath;
@@ -5184,7 +4829,7 @@ var LocalStorageProvider = class {
5184
4829
  const key = uri.replace("local://", "");
5185
4830
  const dir = await this.mediaDir();
5186
4831
  try {
5187
- await fs9.unlink(path10.join(dir, key));
4832
+ await fs8.unlink(path9.join(dir, key));
5188
4833
  } catch {
5189
4834
  }
5190
4835
  }
@@ -5203,17 +4848,17 @@ async function computeDirStats(dir) {
5203
4848
  async function walk2(d) {
5204
4849
  let entries;
5205
4850
  try {
5206
- entries = await fs9.readdir(d, { withFileTypes: true });
4851
+ entries = await fs8.readdir(d, { withFileTypes: true });
5207
4852
  } catch {
5208
4853
  return;
5209
4854
  }
5210
4855
  for (const entry of entries) {
5211
- const full = path10.join(d, entry.name);
4856
+ const full = path9.join(d, entry.name);
5212
4857
  if (entry.isDirectory()) {
5213
4858
  await walk2(full);
5214
4859
  } else {
5215
4860
  try {
5216
- const stat = await fs9.stat(full);
4861
+ const stat = await fs8.stat(full);
5217
4862
  usedBytes += stat.size;
5218
4863
  fileCount++;
5219
4864
  } catch {
@@ -5270,12 +4915,12 @@ async function processMediaCommand(inputs, options) {
5270
4915
  const assets = await Promise.all(
5271
4916
  mediaFiles.map(async (filePath) => {
5272
4917
  const type = mediaType(filePath);
5273
- const stat = await fs10.stat(filePath);
5274
- const extension = path11.extname(filePath).toLowerCase() || ".bin";
4918
+ const stat = await fs9.stat(filePath);
4919
+ const extension = path10.extname(filePath).toLowerCase() || ".bin";
5275
4920
  const key = `${type}s/${Date.now()}_${Math.random().toString(36).slice(2)}${extension}`;
5276
4921
  const mimeType = MIME_TYPES[extension] || "application/octet-stream";
5277
- const storageUri = storage.storeFile ? await storage.storeFile(key, filePath, mimeType) : await storage.store(key, await fs10.readFile(filePath), mimeType);
5278
- 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 };
5279
4924
  })
5280
4925
  );
5281
4926
  const stored = await addMediaAssets(assets);
@@ -5357,7 +5002,7 @@ async function processMediaAsset(asset) {
5357
5002
  if (!tool2.processVideo)
5358
5003
  throw new Error("The installed Video & Audio tool cannot process videos.");
5359
5004
  await update("Extracting video audio", 20);
5360
- 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-"));
5361
5006
  try {
5362
5007
  const video = await tool2.processVideo(localFile, {
5363
5008
  outputDir,
@@ -5378,7 +5023,7 @@ async function processMediaAsset(asset) {
5378
5023
  dimensions = { width: video.meta.width, height: video.meta.height };
5379
5024
  frameCount = video.frames.length;
5380
5025
  } finally {
5381
- await fs10.rm(outputDir, { recursive: true, force: true }).catch(() => {
5026
+ await fs9.rm(outputDir, { recursive: true, force: true }).catch(() => {
5382
5027
  });
5383
5028
  }
5384
5029
  } else {
@@ -5456,7 +5101,7 @@ async function indexPendingMedia() {
5456
5101
  spinner2.stop(`Indexed ${finalRun.totalChunks} chunks`);
5457
5102
  }
5458
5103
  function mediaType(filePath) {
5459
- const extension = path11.extname(filePath).toLowerCase();
5104
+ const extension = path10.extname(filePath).toLowerCase();
5460
5105
  if ([".png", ".jpg", ".jpeg", ".webp", ".gif"].includes(extension)) return "image";
5461
5106
  if ([".mp4", ".webm", ".mov", ".mkv"].includes(extension)) return "video";
5462
5107
  if ([".mp3", ".m4a", ".wav", ".ogg", ".flac"].includes(extension)) return "audio";
@@ -5543,20 +5188,20 @@ async function indexCommand(inputs, options) {
5543
5188
  }
5544
5189
 
5545
5190
  // src/commands/generate.ts
5546
- import { promises as fs11 } from "fs";
5547
- import path12 from "path";
5191
+ import { promises as fs10 } from "fs";
5192
+ import path11 from "path";
5548
5193
  async function generateCommand(options) {
5549
5194
  await inServerScope(options.server, async () => {
5550
5195
  await requireActive();
5551
5196
  const config = await readConfig();
5552
5197
  if (options.out) {
5553
- 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);
5554
5199
  const server2 = generateServer(config);
5555
- await fs11.mkdir(dir, { recursive: true });
5200
+ await fs10.mkdir(dir, { recursive: true });
5556
5201
  for (const f of server2.files) {
5557
- const dest = path12.join(dir, f.path);
5558
- await fs11.mkdir(path12.dirname(dest), { recursive: true });
5559
- 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");
5560
5205
  }
5561
5206
  log.success(`Generated ${server2.files.length} files \u2192 ${dir}`);
5562
5207
  } else {
@@ -5904,8 +5549,8 @@ async function marketplaceCommand(action = "list", toolId) {
5904
5549
  }
5905
5550
 
5906
5551
  // src/commands/deploy.ts
5907
- import { promises as fs12 } from "fs";
5908
- import path13 from "path";
5552
+ import { promises as fs11 } from "fs";
5553
+ import path12 from "path";
5909
5554
  async function deployCommand(target, options) {
5910
5555
  await inServerScope(options.server, async () => {
5911
5556
  await requireActive();
@@ -5941,13 +5586,13 @@ async function deployCommand(target, options) {
5941
5586
  });
5942
5587
  }
5943
5588
  async function copyGenerated(source, output) {
5944
- const destination = path13.resolve(output);
5945
- const relative = path13.relative(source, destination);
5946
- 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)) {
5947
5592
  throw new Error("Deployment output must be outside the generated server directory.");
5948
5593
  }
5949
- await fs12.mkdir(destination, { recursive: true });
5950
- 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 });
5951
5596
  return destination;
5952
5597
  }
5953
5598
 
@@ -6032,8 +5677,8 @@ function openCommandForPlatform(url) {
6032
5677
  }
6033
5678
 
6034
5679
  // src/commands/documents.ts
6035
- import { promises as fs13 } from "fs";
6036
- import path14 from "path";
5680
+ import { promises as fs12 } from "fs";
5681
+ import path13 from "path";
6037
5682
 
6038
5683
  // ../../packages/core/src/corpus-retriever.ts
6039
5684
  function applyFilters(docs, filter) {
@@ -6152,10 +5797,10 @@ async function documentsCommand(action = "list", idOrPath, options) {
6152
5797
  }
6153
5798
  if (action === "export") {
6154
5799
  const format = options.format === "jsonl" ? "jsonl" : "csv";
6155
- const output = path14.resolve(options.out || idOrPath || `corpus.${format}`);
5800
+ const output = path13.resolve(options.out || idOrPath || `corpus.${format}`);
6156
5801
  const content = format === "jsonl" ? await exportCorpusAsJSONL(void 0, Number.MAX_SAFE_INTEGER) : await exportCorpusAsCSV(void 0, Number.MAX_SAFE_INTEGER);
6157
- await fs13.mkdir(path14.dirname(output), { recursive: true });
6158
- await fs13.writeFile(output, content, "utf8");
5802
+ await fs12.mkdir(path13.dirname(output), { recursive: true });
5803
+ await fs12.writeFile(output, content, "utf8");
6159
5804
  log.success(`Exported corpus \u2192 ${output}`);
6160
5805
  return;
6161
5806
  }
@@ -6181,7 +5826,7 @@ ${document.content}`);
6181
5826
  return;
6182
5827
  }
6183
5828
  if (action === "update") {
6184
- 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;
6185
5830
  const updated = await updateDocument(document.id, {
6186
5831
  title: options.title,
6187
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
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@larkup/cli",
3
- "version": "0.2.4",
3
+ "version": "0.2.5",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -29,8 +29,8 @@
29
29
  "commander": "^15.0.0",
30
30
  "zod": "^4.4.3",
31
31
  "@larkup/core": "0.2.2",
32
- "@larkup/marketplace": "0.1.4",
33
- "@larkup/vector-stores": "0.1.22"
32
+ "@larkup/vector-stores": "0.1.22",
33
+ "@larkup/marketplace": "0.1.5"
34
34
  },
35
35
  "devDependencies": {
36
36
  "tsup": "^8.0.0",