@larkup/cli 0.2.15 → 0.2.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -40,4 +40,4 @@ larkup media ./demo.mp4
40
40
  - `larkup open [target]` opens the Web UI or API reference.
41
41
  - `larkup update` checks for and installs CLI releases.
42
42
 
43
- Generated servers use `http://localhost:8080` by default. Run `larkup --help` or see the [CLI documentation](https://larkup.de/docs/developer/cli) for all options.
43
+ Generated servers use `http://localhost:8080` by default. Run `larkup --help` or see the [CLI documentation](https://www.larkup.de/docs/developer/cli) for all options.
@@ -90,13 +90,12 @@ 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.1",
93
+ version: "0.3.1",
94
94
  pricing: "free",
95
95
  emoji: "\u{1F3AC}",
96
96
  icon: "Film",
97
97
  packageName: "@larkup/tool-video-audio",
98
98
  installSize: "~15 MB",
99
- systemDeps: ["ffmpeg"],
100
99
  author: "Larkup",
101
100
  capabilities: [
102
101
  "video-indexing",
@@ -136,7 +135,7 @@ var FALLBACK_REGISTRY = {
136
135
  label: "Transcription language",
137
136
  type: "text",
138
137
  defaultValue: "auto",
139
- help: "Use auto to infer Arabic from the media title and use provider detection otherwise. Enter a language code such as ar, ar-EG, en, or de to override it."
138
+ help: "Use auto for provider language detection, or enter a language code such as ar, ar-EG, en, or de to override it."
140
139
  },
141
140
  {
142
141
  key: "audioApiKey",
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  getToolById,
3
3
  invalidateRegistryCache
4
- } from "./chunk-UCYL66UI.js";
4
+ } from "./chunk-7HVIRRTX.js";
5
5
  import {
6
6
  __require
7
7
  } from "./chunk-3RG5ZIWI.js";
@@ -112,10 +112,13 @@ async function tryAutoInstallDep(dep, onProgress) {
112
112
  }
113
113
  }
114
114
  if (!installCmd) return false;
115
- onProgress?.(`Auto-installing ${dep}\u2026`);
115
+ onProgress?.(`Auto-installing ${dep} via "${installCmd}"\u2026`);
116
116
  try {
117
- await execAsync(installCmd, { timeout: 12e4 });
118
- } catch {
117
+ await execAsync(installCmd, { timeout: 3e5 });
118
+ onProgress?.(`${dep} installation command finished.`);
119
+ } catch (err) {
120
+ const message = err instanceof Error ? err.message : String(err);
121
+ onProgress?.(`Auto-install of ${dep} failed: ${message}`);
119
122
  return false;
120
123
  }
121
124
  try {
@@ -411,7 +414,7 @@ async function uninstallTool(toolId) {
411
414
  }
412
415
  }
413
416
  invalidateRegistryCache();
414
- const { unloadTool: unloadTool2 } = await import("./tool-loader-KJILSS2J.js");
417
+ const { unloadTool: unloadTool2 } = await import("./tool-loader-K33ISDZP.js");
415
418
  unloadTool2(toolId);
416
419
  }
417
420
  async function notifyHubInstall(toolId) {
@@ -482,7 +485,7 @@ function unloadTool(toolId) {
482
485
  moduleCache.delete(toolId);
483
486
  }
484
487
  async function hasCapability(capability) {
485
- const { getToolsWithCapability } = await import("./tool-registry-ED45DB5F.js");
488
+ const { getToolsWithCapability } = await import("./tool-registry-XQVQ6KQF.js");
486
489
  const tools = await getToolsWithCapability(capability);
487
490
  for (const t of tools) {
488
491
  const installed = await getInstalledTool(t.id);
package/dist/index.js CHANGED
@@ -19,11 +19,11 @@ import {
19
19
  isToolInstalled,
20
20
  loadTool,
21
21
  uninstallTool
22
- } from "./chunk-C37WLM2M.js";
22
+ } from "./chunk-STUKQORW.js";
23
23
  import {
24
24
  getAllTools,
25
25
  getToolById
26
- } from "./chunk-UCYL66UI.js";
26
+ } from "./chunk-7HVIRRTX.js";
27
27
  import {
28
28
  __require
29
29
  } from "./chunk-3RG5ZIWI.js";
@@ -34,7 +34,7 @@ import { Command } from "commander";
34
34
  // package.json
35
35
  var package_default = {
36
36
  name: "@larkup/cli",
37
- version: "0.2.15",
37
+ version: "0.2.17",
38
38
  publishConfig: {
39
39
  access: "public"
40
40
  },
@@ -141,7 +141,7 @@ var prompts = {
141
141
  };
142
142
 
143
143
  // src/updater.ts
144
- var VERSION_CHECK_URL = "https://larkup.de/api/version";
144
+ var VERSION_CHECK_URL = "https://www.larkup.de/api/version";
145
145
  function compareVersions(a, b) {
146
146
  const pa = a.replace(/^v/, "").split(".").map(Number);
147
147
  const pb = b.replace(/^v/, "").split(".").map(Number);
@@ -4341,6 +4341,24 @@ async function createAdapter(config, onRateLimit) {
4341
4341
 
4342
4342
  // ../../packages/core/src/indexing/indexer.ts
4343
4343
  var EMBED_BATCH = 64;
4344
+ var MAX_RATE_LIMIT_RETRIES = 5;
4345
+ function isRateLimitError(error) {
4346
+ const candidate = error;
4347
+ const message = String(candidate?.message ?? error ?? "").toLowerCase();
4348
+ return candidate?.status === 429 || candidate?.statusCode === 429 || /\b429\b|rate[ -]?limit|too many requests|resource_exhausted|quota exceeded|quota.*exceed/.test(
4349
+ message
4350
+ );
4351
+ }
4352
+ function rateLimitDelayMs(error, attempt) {
4353
+ const message = String(error?.message ?? error ?? "");
4354
+ const retryMatch = message.match(
4355
+ /(?:retry(?:\s+after|\s+in)?|try again(?:\s+in)?)\s*(\d+(?:\.\d+)?)\s*(?:s|sec(?:ond)?s?)/i
4356
+ );
4357
+ if (retryMatch) {
4358
+ return Math.min(12e4, Math.max(2e3, Math.ceil(Number(retryMatch[1]) * 1e3)));
4359
+ }
4360
+ return Math.min(6e4, 5e3 * 2 ** (attempt - 1));
4361
+ }
4344
4362
  async function createRun(config) {
4345
4363
  const now = (/* @__PURE__ */ new Date()).toISOString();
4346
4364
  const run = {
@@ -4367,7 +4385,7 @@ async function runIndexer(runId, config, previousRun = null) {
4367
4385
  };
4368
4386
  try {
4369
4387
  let docs = await readDocuments();
4370
- if (previousRun && previousRun.status === "completed") {
4388
+ if (previousRun) {
4371
4389
  docs = docs.filter((document) => document.status !== "indexed");
4372
4390
  }
4373
4391
  if (docs.length === 0) {
@@ -4406,6 +4424,12 @@ async function runIndexer(runId, config, previousRun = null) {
4406
4424
  return;
4407
4425
  }
4408
4426
  await patchRun2({ totalChunks: chunks.length, status: "embedding" });
4427
+ const chunksPerDocument = /* @__PURE__ */ new Map();
4428
+ const processedPerDocument = /* @__PURE__ */ new Map();
4429
+ const indexedDocumentIds = /* @__PURE__ */ new Set();
4430
+ for (const chunk of chunks) {
4431
+ chunksPerDocument.set(chunk.documentId, (chunksPerDocument.get(chunk.documentId) ?? 0) + 1);
4432
+ }
4409
4433
  const adapter = await createAdapter(config, async (waitSecs, attempt) => {
4410
4434
  await patchRun2({
4411
4435
  warning: `Sparse model rate-limited \u2014 pausing ${waitSecs}s (retry ${attempt}/${3})\u2026`
@@ -4434,13 +4458,13 @@ async function runIndexer(runId, config, previousRun = null) {
4434
4458
  if (dim) batchDimensions = dim;
4435
4459
  break;
4436
4460
  } catch (err) {
4437
- const is429 = err?.status === 429 || err?.statusCode === 429 || String(err?.message ?? "").includes("429") || String(err?.message ?? "").includes("rate limit") || String(err?.message ?? "").toLowerCase().includes("too many requests");
4438
- if (is429 && attempt <= 3) {
4439
- const waitSecs = attempt * 10;
4461
+ if (isRateLimitError(err) && attempt <= MAX_RATE_LIMIT_RETRIES) {
4462
+ const waitMs = rateLimitDelayMs(err, attempt);
4463
+ const waitSecs = Math.ceil(waitMs / 1e3);
4440
4464
  await patchRun2({
4441
- warning: `Dense model rate-limited \u2014 pausing ${waitSecs}s (retry ${attempt}/${3})\u2026`
4465
+ warning: `Embedding provider quota reached \u2014 pausing ${waitSecs}s (retry ${attempt}/${MAX_RATE_LIMIT_RETRIES})\u2026`
4442
4466
  });
4443
- await new Promise((r) => setTimeout(r, waitSecs * 1e3));
4467
+ await new Promise((r) => setTimeout(r, waitMs));
4444
4468
  currentDelayMs = Math.max(currentDelayMs, 2e3);
4445
4469
  attempt++;
4446
4470
  } else {
@@ -4453,6 +4477,10 @@ async function runIndexer(runId, config, previousRun = null) {
4453
4477
  await adapter.init(dimensions);
4454
4478
  if (!previousRun) {
4455
4479
  await adapter.reset();
4480
+ await updateDocumentsStatus(
4481
+ docs.map((document) => document.id),
4482
+ "unindexed"
4483
+ );
4456
4484
  }
4457
4485
  initialized = true;
4458
4486
  await patchRun2({ dimensions });
@@ -4475,13 +4503,13 @@ async function runIndexer(runId, config, previousRun = null) {
4475
4503
  await adapter.upsert(records);
4476
4504
  break;
4477
4505
  } catch (err) {
4478
- const is429 = err?.status === 429 || err?.statusCode === 429 || String(err?.message ?? "").includes("429") || String(err?.message ?? "").includes("rate limit") || String(err?.message ?? "").toLowerCase().includes("too many requests") || String(err?.message ?? "").includes("RESOURCE_EXHAUSTED");
4479
- if (is429 && upsertAttempt <= 3) {
4480
- const waitSecs = upsertAttempt * 10;
4506
+ if (isRateLimitError(err) && upsertAttempt <= MAX_RATE_LIMIT_RETRIES) {
4507
+ const waitMs = rateLimitDelayMs(err, upsertAttempt);
4508
+ const waitSecs = Math.ceil(waitMs / 1e3);
4481
4509
  await patchRun2({
4482
- warning: `Vector store rate-limited \u2014 pausing ${waitSecs}s (retry ${upsertAttempt}/${3})\u2026`
4510
+ warning: `Vector store rate-limited \u2014 pausing ${waitSecs}s (retry ${upsertAttempt}/${MAX_RATE_LIMIT_RETRIES})\u2026`
4483
4511
  });
4484
- await new Promise((r) => setTimeout(r, waitSecs * 1e3));
4512
+ await new Promise((r) => setTimeout(r, waitMs));
4485
4513
  currentDelayMs = Math.max(currentDelayMs, 2e3);
4486
4514
  upsertAttempt++;
4487
4515
  } else {
@@ -4490,7 +4518,24 @@ async function runIndexer(runId, config, previousRun = null) {
4490
4518
  }
4491
4519
  }
4492
4520
  processed += batch.length;
4493
- await patchRun2({ processedChunks: processed, status: "embedding", warning: void 0 });
4521
+ const completedDocumentIds = [];
4522
+ for (const chunk of batch) {
4523
+ const completed = (processedPerDocument.get(chunk.documentId) ?? 0) + 1;
4524
+ processedPerDocument.set(chunk.documentId, completed);
4525
+ if (completed === chunksPerDocument.get(chunk.documentId) && !indexedDocumentIds.has(chunk.documentId)) {
4526
+ indexedDocumentIds.add(chunk.documentId);
4527
+ completedDocumentIds.push(chunk.documentId);
4528
+ }
4529
+ }
4530
+ if (completedDocumentIds.length > 0) {
4531
+ await updateDocumentsStatus(completedDocumentIds, "indexed");
4532
+ }
4533
+ await patchRun2({
4534
+ processedChunks: processed,
4535
+ indexedDocumentCount: indexedDocumentIds.size,
4536
+ status: "embedding",
4537
+ warning: void 0
4538
+ });
4494
4539
  }
4495
4540
  await patchRun2({
4496
4541
  status: "completed",
@@ -4499,16 +4544,17 @@ async function runIndexer(runId, config, previousRun = null) {
4499
4544
  finishedAt: (/* @__PURE__ */ new Date()).toISOString(),
4500
4545
  durationMs: Date.now() - started
4501
4546
  });
4502
- await updateDocumentsStatus(
4503
- docs.map((d) => d.id),
4504
- "indexed"
4505
- );
4506
4547
  } catch (err) {
4507
- const message = err instanceof Error ? err.message : "Indexing failed unexpectedly.";
4548
+ const rawMessage = err instanceof Error ? err.message : "Indexing failed unexpectedly.";
4549
+ const completed = await readDocuments().then(
4550
+ (documents) => documents.filter((document) => document.status === "indexed").length
4551
+ );
4552
+ const message = isRateLimitError(err) ? `Embedding quota is still unavailable. ${completed} document${completed === 1 ? "" : "s"} remain indexed; retry the unindexed files when your provider quota resets. ${rawMessage}` : rawMessage;
4508
4553
  await patchRun(
4509
4554
  {
4510
4555
  status: "failed",
4511
4556
  error: message,
4557
+ indexedDocumentCount: completed,
4512
4558
  finishedAt: (/* @__PURE__ */ new Date()).toISOString(),
4513
4559
  durationMs: Date.now() - started
4514
4560
  },
@@ -3,8 +3,8 @@ import {
3
3
  isToolLoaded,
4
4
  loadTool,
5
5
  unloadTool
6
- } from "./chunk-C37WLM2M.js";
7
- import "./chunk-UCYL66UI.js";
6
+ } from "./chunk-STUKQORW.js";
7
+ import "./chunk-7HVIRRTX.js";
8
8
  import "./chunk-3RG5ZIWI.js";
9
9
  export {
10
10
  hasCapability,
@@ -6,7 +6,7 @@ import {
6
6
  getToolById,
7
7
  getToolsWithCapability,
8
8
  invalidateRegistryCache
9
- } from "./chunk-UCYL66UI.js";
9
+ } from "./chunk-7HVIRRTX.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.15",
3
+ "version": "0.2.17",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -29,9 +29,9 @@
29
29
  "cli-table3": "^0.6.5",
30
30
  "commander": "^15.0.0",
31
31
  "zod": "^4.4.3",
32
- "@larkup/marketplace": "0.1.15",
33
- "@larkup/core": "0.3.1",
34
- "@larkup/vector-stores": "0.1.24"
32
+ "@larkup/core": "0.3.2",
33
+ "@larkup/vector-stores": "0.1.24",
34
+ "@larkup/marketplace": "0.1.17"
35
35
  },
36
36
  "devDependencies": {
37
37
  "tsup": "^8.0.0",