@larkup/cli 0.2.22 → 0.2.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{analytics-store-JGHJTMOB.js → analytics-store-KI3NXDYV.js} +1 -1
- package/dist/{chroma-NWWTSRG6.js → chroma-BCASZNMJ.js} +0 -1
- package/dist/{chunk-3SJB3BNF.js → chunk-FM6HYXZ5.js} +8 -5
- package/dist/{chunk-42GOKBRL.js → chunk-I6JJWCUQ.js} +14 -14
- package/dist/chunk-L34L3RDQ.js +7066 -0
- package/dist/index.js +743 -74
- package/dist/{lancedb-RUTGJYW7.js → lancedb-UB2EPDCN.js} +0 -1
- package/dist/{pinecone-5SGBRUV3.js → pinecone-OHOY4YYM.js} +0 -1
- package/dist/{tool-loader-5Y7LCHEN.js → tool-loader-KKODIWEV.js} +2 -2
- package/dist/{tool-registry-FW2X3GIT.js → tool-registry-CXCFMOWA.js} +1 -1
- package/package.json +5 -5
- package/dist/chunk-PDVC2XOG.js +0 -8024
package/dist/index.js
CHANGED
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
runWithServer,
|
|
12
12
|
setActiveServer,
|
|
13
13
|
trackUsageEvent
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-L34L3RDQ.js";
|
|
15
15
|
import {
|
|
16
16
|
getInstalledTool,
|
|
17
17
|
getInstalledTools,
|
|
@@ -19,11 +19,11 @@ import {
|
|
|
19
19
|
isToolInstalled,
|
|
20
20
|
loadTool,
|
|
21
21
|
uninstallTool
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-I6JJWCUQ.js";
|
|
23
23
|
import {
|
|
24
24
|
getAllTools,
|
|
25
25
|
getToolById
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-FM6HYXZ5.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.
|
|
37
|
+
version: "0.2.23",
|
|
38
38
|
publishConfig: {
|
|
39
39
|
access: "public"
|
|
40
40
|
},
|
|
@@ -73,8 +73,8 @@ var package_default = {
|
|
|
73
73
|
zod: "^4.4.3"
|
|
74
74
|
},
|
|
75
75
|
devDependencies: {
|
|
76
|
-
tsup: "^8.
|
|
77
|
-
tsx: "^4.
|
|
76
|
+
tsup: "^8.5.1",
|
|
77
|
+
tsx: "^4.23.5",
|
|
78
78
|
typescript: "^6.0.3"
|
|
79
79
|
}
|
|
80
80
|
};
|
|
@@ -960,12 +960,12 @@ function addChatProviderDependency(dependencies, provider) {
|
|
|
960
960
|
}
|
|
961
961
|
|
|
962
962
|
// ../../packages/core/src/generator/generate-server.ts
|
|
963
|
-
function lang(
|
|
964
|
-
if (
|
|
965
|
-
if (
|
|
966
|
-
if (
|
|
967
|
-
if (
|
|
968
|
-
if (
|
|
963
|
+
function lang(path15) {
|
|
964
|
+
if (path15.endsWith(".json")) return "json";
|
|
965
|
+
if (path15.endsWith(".mjs") || path15.endsWith(".js")) return "javascript";
|
|
966
|
+
if (path15.endsWith(".md")) return "markdown";
|
|
967
|
+
if (path15.endsWith("Dockerfile")) return "dockerfile";
|
|
968
|
+
if (path15.endsWith(".yml") || path15.endsWith(".yaml")) return "yaml";
|
|
969
969
|
return "text";
|
|
970
970
|
}
|
|
971
971
|
function lancedbStore() {
|
|
@@ -2282,22 +2282,22 @@ function generateServer(config) {
|
|
|
2282
2282
|
{ path: "README.md", contents: readme(config, server) }
|
|
2283
2283
|
].map((f) => ({ ...f, language: lang(f.path) }));
|
|
2284
2284
|
try {
|
|
2285
|
-
const
|
|
2286
|
-
const
|
|
2287
|
-
const faviconPath =
|
|
2288
|
-
if (
|
|
2285
|
+
const fs14 = __require("fs");
|
|
2286
|
+
const path15 = __require("path");
|
|
2287
|
+
const faviconPath = path15.resolve(process.cwd(), "public/favicon2.ico");
|
|
2288
|
+
if (fs14.existsSync(faviconPath)) {
|
|
2289
2289
|
files.push({
|
|
2290
2290
|
path: "public/favicon2.ico",
|
|
2291
|
-
contents:
|
|
2291
|
+
contents: fs14.readFileSync(faviconPath).toString("base64"),
|
|
2292
2292
|
language: "ico",
|
|
2293
2293
|
encoding: "base64"
|
|
2294
2294
|
});
|
|
2295
2295
|
} else {
|
|
2296
|
-
const webFaviconPath =
|
|
2297
|
-
if (
|
|
2296
|
+
const webFaviconPath = path15.resolve(process.cwd(), "apps/web/public/favicon2.ico");
|
|
2297
|
+
if (fs14.existsSync(webFaviconPath)) {
|
|
2298
2298
|
files.push({
|
|
2299
2299
|
path: "public/favicon2.ico",
|
|
2300
|
-
contents:
|
|
2300
|
+
contents: fs14.readFileSync(webFaviconPath).toString("base64"),
|
|
2301
2301
|
language: "ico",
|
|
2302
2302
|
encoding: "base64"
|
|
2303
2303
|
});
|
|
@@ -2311,12 +2311,12 @@ function generateServer(config) {
|
|
|
2311
2311
|
}
|
|
2312
2312
|
|
|
2313
2313
|
// ../../packages/core/src/generator/generate-agent-server.ts
|
|
2314
|
-
function lang2(
|
|
2315
|
-
if (
|
|
2316
|
-
if (
|
|
2317
|
-
if (
|
|
2318
|
-
if (
|
|
2319
|
-
if (
|
|
2314
|
+
function lang2(path15) {
|
|
2315
|
+
if (path15.endsWith(".json")) return "json";
|
|
2316
|
+
if (path15.endsWith(".mjs") || path15.endsWith(".js")) return "javascript";
|
|
2317
|
+
if (path15.endsWith(".md")) return "markdown";
|
|
2318
|
+
if (path15.endsWith("Dockerfile")) return "dockerfile";
|
|
2319
|
+
if (path15.endsWith(".yml") || path15.endsWith(".yaml")) return "yaml";
|
|
2320
2320
|
return "text";
|
|
2321
2321
|
}
|
|
2322
2322
|
function lancedbStore2() {
|
|
@@ -3330,22 +3330,22 @@ function generateAgentServer(config) {
|
|
|
3330
3330
|
{ path: "README.md", contents: readme2(config, server) }
|
|
3331
3331
|
].map((f) => ({ ...f, language: lang2(f.path) }));
|
|
3332
3332
|
try {
|
|
3333
|
-
const
|
|
3334
|
-
const
|
|
3335
|
-
const faviconPath =
|
|
3336
|
-
if (
|
|
3333
|
+
const fs14 = __require("fs");
|
|
3334
|
+
const path15 = __require("path");
|
|
3335
|
+
const faviconPath = path15.resolve(process.cwd(), "public/favicon2.ico");
|
|
3336
|
+
if (fs14.existsSync(faviconPath)) {
|
|
3337
3337
|
files.push({
|
|
3338
3338
|
path: "public/favicon2.ico",
|
|
3339
|
-
contents:
|
|
3339
|
+
contents: fs14.readFileSync(faviconPath).toString("base64"),
|
|
3340
3340
|
language: "ico",
|
|
3341
3341
|
encoding: "base64"
|
|
3342
3342
|
});
|
|
3343
3343
|
} else {
|
|
3344
|
-
const webFaviconPath =
|
|
3345
|
-
if (
|
|
3344
|
+
const webFaviconPath = path15.resolve(process.cwd(), "apps/web/public/favicon2.ico");
|
|
3345
|
+
if (fs14.existsSync(webFaviconPath)) {
|
|
3346
3346
|
files.push({
|
|
3347
3347
|
path: "public/favicon2.ico",
|
|
3348
|
-
contents:
|
|
3348
|
+
contents: fs14.readFileSync(webFaviconPath).toString("base64"),
|
|
3349
3349
|
language: "ico",
|
|
3350
3350
|
encoding: "base64"
|
|
3351
3351
|
});
|
|
@@ -4042,7 +4042,7 @@ async function addDocCommand(options) {
|
|
|
4042
4042
|
const doc = await addDocument({
|
|
4043
4043
|
title: title ?? "Untitled",
|
|
4044
4044
|
content,
|
|
4045
|
-
source: options.file ? "
|
|
4045
|
+
source: options.file ? "files" : "text",
|
|
4046
4046
|
url: options.url
|
|
4047
4047
|
});
|
|
4048
4048
|
log.success(`Added "${doc.title}" (${doc.charCount.toLocaleString()} chars)`);
|
|
@@ -4251,7 +4251,7 @@ async function embedTexts(config, texts) {
|
|
|
4251
4251
|
values: texts
|
|
4252
4252
|
});
|
|
4253
4253
|
const totalTokens = texts.reduce((acc, t) => acc + Math.ceil(t.length / 4), 0);
|
|
4254
|
-
const { trackUsageEvent: trackUsageEvent2, estimateCost: estimateCost2 } = await import("./analytics-store-
|
|
4254
|
+
const { trackUsageEvent: trackUsageEvent2, estimateCost: estimateCost2 } = await import("./analytics-store-KI3NXDYV.js");
|
|
4255
4255
|
void trackUsageEvent2({
|
|
4256
4256
|
type: "embedding",
|
|
4257
4257
|
embeddingModelId: config.embeddingModelId,
|
|
@@ -4297,7 +4297,7 @@ async function createAdapter(config, onRateLimit) {
|
|
|
4297
4297
|
}
|
|
4298
4298
|
switch (config.vectorStore) {
|
|
4299
4299
|
case "pinecone": {
|
|
4300
|
-
const { PineconeAdapter } = await import("./pinecone-
|
|
4300
|
+
const { PineconeAdapter } = await import("./pinecone-OHOY4YYM.js");
|
|
4301
4301
|
return new PineconeAdapter({
|
|
4302
4302
|
apiKey: overrides.apiKey,
|
|
4303
4303
|
indexName: overrides.indexName,
|
|
@@ -4308,7 +4308,7 @@ async function createAdapter(config, onRateLimit) {
|
|
|
4308
4308
|
});
|
|
4309
4309
|
}
|
|
4310
4310
|
case "chroma": {
|
|
4311
|
-
const { ChromaAdapter } = await import("./chroma-
|
|
4311
|
+
const { ChromaAdapter } = await import("./chroma-BCASZNMJ.js");
|
|
4312
4312
|
return new ChromaAdapter({
|
|
4313
4313
|
mode: overrides.mode,
|
|
4314
4314
|
host: overrides.host,
|
|
@@ -4322,7 +4322,7 @@ async function createAdapter(config, onRateLimit) {
|
|
|
4322
4322
|
}
|
|
4323
4323
|
case "lancedb":
|
|
4324
4324
|
default: {
|
|
4325
|
-
const { LanceDBAdapter } = await import("./lancedb-
|
|
4325
|
+
const { LanceDBAdapter } = await import("./lancedb-UB2EPDCN.js");
|
|
4326
4326
|
return new LanceDBAdapter({
|
|
4327
4327
|
mode: overrides.mode,
|
|
4328
4328
|
dbPath: overrides.dbPath,
|
|
@@ -4708,8 +4708,10 @@ async function readTextFiles(files) {
|
|
|
4708
4708
|
}
|
|
4709
4709
|
|
|
4710
4710
|
// src/commands/media.ts
|
|
4711
|
-
import { promises as
|
|
4712
|
-
import
|
|
4711
|
+
import { promises as fs10 } from "fs";
|
|
4712
|
+
import { createHash, randomUUID as randomUUID9 } from "crypto";
|
|
4713
|
+
import { createReadStream } from "fs";
|
|
4714
|
+
import path11 from "path";
|
|
4713
4715
|
|
|
4714
4716
|
// ../../packages/core/src/media-store.ts
|
|
4715
4717
|
import { promises as fs7 } from "fs";
|
|
@@ -4943,6 +4945,508 @@ function createStorageProvider(_config) {
|
|
|
4943
4945
|
return new LocalStorageProvider();
|
|
4944
4946
|
}
|
|
4945
4947
|
|
|
4948
|
+
// ../../packages/core/src/video-knowledge/revision-store.ts
|
|
4949
|
+
import { randomUUID as randomUUID5 } from "crypto";
|
|
4950
|
+
|
|
4951
|
+
// ../../packages/core/src/video-knowledge/store.ts
|
|
4952
|
+
import { promises as fs9 } from "fs";
|
|
4953
|
+
import path10 from "path";
|
|
4954
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
4955
|
+
var EMPTY_STATE = {
|
|
4956
|
+
schemaVersion: 1,
|
|
4957
|
+
revisions: [],
|
|
4958
|
+
jobs: [],
|
|
4959
|
+
inspectionReservations: [],
|
|
4960
|
+
backgroundRefinements: [],
|
|
4961
|
+
artifactAnalysisCache: [],
|
|
4962
|
+
artifacts: [],
|
|
4963
|
+
evidence: [],
|
|
4964
|
+
observations: [],
|
|
4965
|
+
states: [],
|
|
4966
|
+
transitions: [],
|
|
4967
|
+
events: [],
|
|
4968
|
+
scenes: [],
|
|
4969
|
+
chapters: [],
|
|
4970
|
+
summaries: [],
|
|
4971
|
+
derived: [],
|
|
4972
|
+
conflicts: [],
|
|
4973
|
+
manifests: [],
|
|
4974
|
+
projections: []
|
|
4975
|
+
};
|
|
4976
|
+
var writeChain4 = Promise.resolve();
|
|
4977
|
+
var LOCK_STALE_MS = 5 * 6e4;
|
|
4978
|
+
var LOCK_ATTEMPTS = 500;
|
|
4979
|
+
function cloneEmpty() {
|
|
4980
|
+
return structuredClone(EMPTY_STATE);
|
|
4981
|
+
}
|
|
4982
|
+
async function dataPath(create) {
|
|
4983
|
+
const dir = create ? await requireDataDir() : await getDataDir();
|
|
4984
|
+
return dir ? path10.join(dir, "video-knowledge.json") : null;
|
|
4985
|
+
}
|
|
4986
|
+
function isMissing(error) {
|
|
4987
|
+
return error?.code === "ENOENT";
|
|
4988
|
+
}
|
|
4989
|
+
async function readVideoKnowledgeState() {
|
|
4990
|
+
const file = await dataPath(false);
|
|
4991
|
+
if (!file) return cloneEmpty();
|
|
4992
|
+
try {
|
|
4993
|
+
const parsed = JSON.parse(await fs9.readFile(file, "utf8"));
|
|
4994
|
+
if (parsed.schemaVersion !== 1)
|
|
4995
|
+
throw new Error(`Unsupported video knowledge schema at ${file}.`);
|
|
4996
|
+
return { ...cloneEmpty(), ...parsed };
|
|
4997
|
+
} catch (error) {
|
|
4998
|
+
if (isMissing(error)) return cloneEmpty();
|
|
4999
|
+
throw error;
|
|
5000
|
+
}
|
|
5001
|
+
}
|
|
5002
|
+
async function writeState2(state) {
|
|
5003
|
+
const file = await dataPath(true);
|
|
5004
|
+
if (!file) return;
|
|
5005
|
+
const temp = path10.join(
|
|
5006
|
+
path10.dirname(file),
|
|
5007
|
+
`.${path10.basename(file)}.${process.pid}.${randomUUID4()}.tmp`
|
|
5008
|
+
);
|
|
5009
|
+
try {
|
|
5010
|
+
await fs9.writeFile(temp, JSON.stringify(state, null, 2), "utf8");
|
|
5011
|
+
await fs9.rename(temp, file);
|
|
5012
|
+
} catch (error) {
|
|
5013
|
+
await fs9.unlink(temp).catch(() => {
|
|
5014
|
+
});
|
|
5015
|
+
throw error;
|
|
5016
|
+
}
|
|
5017
|
+
}
|
|
5018
|
+
var delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
5019
|
+
async function acquireStateLock() {
|
|
5020
|
+
const file = await dataPath(true);
|
|
5021
|
+
if (!file) return async () => {
|
|
5022
|
+
};
|
|
5023
|
+
const lock = `${file}.lock`;
|
|
5024
|
+
for (let attempt = 0; attempt < LOCK_ATTEMPTS; attempt++) {
|
|
5025
|
+
try {
|
|
5026
|
+
const handle = await fs9.open(lock, "wx");
|
|
5027
|
+
await handle.writeFile(`${process.pid}:${(/* @__PURE__ */ new Date()).toISOString()}`);
|
|
5028
|
+
return async () => {
|
|
5029
|
+
await handle.close().catch(() => {
|
|
5030
|
+
});
|
|
5031
|
+
await fs9.unlink(lock).catch(() => {
|
|
5032
|
+
});
|
|
5033
|
+
};
|
|
5034
|
+
} catch (error) {
|
|
5035
|
+
if (error.code !== "EEXIST") throw error;
|
|
5036
|
+
try {
|
|
5037
|
+
const stat = await fs9.stat(lock);
|
|
5038
|
+
if (Date.now() - stat.mtimeMs > LOCK_STALE_MS) {
|
|
5039
|
+
await fs9.unlink(lock).catch(() => {
|
|
5040
|
+
});
|
|
5041
|
+
}
|
|
5042
|
+
} catch (statError) {
|
|
5043
|
+
if (!isMissing(statError)) throw statError;
|
|
5044
|
+
}
|
|
5045
|
+
await delay(Math.min(50, 5 + attempt));
|
|
5046
|
+
}
|
|
5047
|
+
}
|
|
5048
|
+
throw new Error(`Timed out waiting for the video knowledge state lock: ${lock}`);
|
|
5049
|
+
}
|
|
5050
|
+
function mutateVideoKnowledgeState(mutate) {
|
|
5051
|
+
const run = writeChain4.then(async () => {
|
|
5052
|
+
const release = await acquireStateLock();
|
|
5053
|
+
try {
|
|
5054
|
+
const state = await readVideoKnowledgeState();
|
|
5055
|
+
const result = await mutate(state);
|
|
5056
|
+
await writeState2(state);
|
|
5057
|
+
return result;
|
|
5058
|
+
} finally {
|
|
5059
|
+
await release();
|
|
5060
|
+
}
|
|
5061
|
+
});
|
|
5062
|
+
writeChain4 = run.catch(() => {
|
|
5063
|
+
});
|
|
5064
|
+
return run;
|
|
5065
|
+
}
|
|
5066
|
+
|
|
5067
|
+
// ../../packages/core/src/video-knowledge/revision-store.ts
|
|
5068
|
+
function createVideoKnowledgeRevision(input) {
|
|
5069
|
+
return mutateVideoKnowledgeState((state) => {
|
|
5070
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
5071
|
+
const revision = {
|
|
5072
|
+
id: randomUUID5(),
|
|
5073
|
+
mediaAssetId: input.mediaAssetId,
|
|
5074
|
+
sourceFingerprint: input.sourceFingerprint,
|
|
5075
|
+
pipelineVersion: input.pipelineVersion,
|
|
5076
|
+
parentRevisionId: input.parentRevisionId,
|
|
5077
|
+
guidance: input.guidance,
|
|
5078
|
+
status: "queued",
|
|
5079
|
+
budget: input.budget,
|
|
5080
|
+
coverage: input.coverage,
|
|
5081
|
+
schemaVersion: 1,
|
|
5082
|
+
createdAt: now
|
|
5083
|
+
};
|
|
5084
|
+
state.revisions.push(revision);
|
|
5085
|
+
return revision;
|
|
5086
|
+
});
|
|
5087
|
+
}
|
|
5088
|
+
|
|
5089
|
+
// ../../packages/core/src/video-knowledge/job-store.ts
|
|
5090
|
+
import { randomUUID as randomUUID6 } from "crypto";
|
|
5091
|
+
function createVideoKnowledgeJob(input) {
|
|
5092
|
+
return mutateVideoKnowledgeState((state) => {
|
|
5093
|
+
const existing = state.jobs.find(
|
|
5094
|
+
(job2) => job2.idempotencyKey === input.idempotencyKey && !["failed", "cancelled", "completed"].includes(job2.status)
|
|
5095
|
+
);
|
|
5096
|
+
if (existing) return existing;
|
|
5097
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
5098
|
+
const job = {
|
|
5099
|
+
id: randomUUID6(),
|
|
5100
|
+
mediaAssetId: input.mediaAssetId,
|
|
5101
|
+
knowledgeRevisionId: input.knowledgeRevisionId,
|
|
5102
|
+
idempotencyKey: input.idempotencyKey,
|
|
5103
|
+
budget: input.budget,
|
|
5104
|
+
status: "queued",
|
|
5105
|
+
attempt: 0,
|
|
5106
|
+
checkpoint: {
|
|
5107
|
+
stage: "queued",
|
|
5108
|
+
completedEvidenceIds: [],
|
|
5109
|
+
completedProjectionIds: [],
|
|
5110
|
+
updatedAt: now
|
|
5111
|
+
},
|
|
5112
|
+
retryHistory: [],
|
|
5113
|
+
createdAt: now,
|
|
5114
|
+
updatedAt: now
|
|
5115
|
+
};
|
|
5116
|
+
state.jobs.push(job);
|
|
5117
|
+
return job;
|
|
5118
|
+
});
|
|
5119
|
+
}
|
|
5120
|
+
function claimVideoKnowledgeJob(id, owner, leaseMs = 6e4) {
|
|
5121
|
+
return mutateVideoKnowledgeState((state) => {
|
|
5122
|
+
const job = state.jobs.find((candidate) => candidate.id === id);
|
|
5123
|
+
if (!job || job.cancellationRequestedAt || ["completed", "failed", "cancelled"].includes(job.status))
|
|
5124
|
+
return void 0;
|
|
5125
|
+
const now = Date.now();
|
|
5126
|
+
if (job.retryAfter && new Date(job.retryAfter).getTime() > now) return void 0;
|
|
5127
|
+
if (job.leaseExpiresAt && new Date(job.leaseExpiresAt).getTime() > now && job.leaseOwner !== owner)
|
|
5128
|
+
return void 0;
|
|
5129
|
+
job.leaseOwner = owner;
|
|
5130
|
+
job.leaseExpiresAt = new Date(now + leaseMs).toISOString();
|
|
5131
|
+
job.heartbeatAt = new Date(now).toISOString();
|
|
5132
|
+
job.status = job.status === "queued" ? "acquiring" : job.status;
|
|
5133
|
+
job.attempt += 1;
|
|
5134
|
+
job.retryAfter = void 0;
|
|
5135
|
+
job.updatedAt = new Date(now).toISOString();
|
|
5136
|
+
return job;
|
|
5137
|
+
});
|
|
5138
|
+
}
|
|
5139
|
+
function checkpointVideoKnowledgeJob(id, owner, stage, checkpoint, leaseMs = 6e4) {
|
|
5140
|
+
return mutateVideoKnowledgeState((state) => {
|
|
5141
|
+
const job = state.jobs.find((candidate) => candidate.id === id);
|
|
5142
|
+
if (!job || job.leaseOwner !== owner || job.cancellationRequestedAt) return void 0;
|
|
5143
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
5144
|
+
job.status = stage;
|
|
5145
|
+
job.checkpoint = { ...job.checkpoint, ...checkpoint, stage, updatedAt: now };
|
|
5146
|
+
job.heartbeatAt = now;
|
|
5147
|
+
job.leaseExpiresAt = new Date(Date.now() + leaseMs).toISOString();
|
|
5148
|
+
job.updatedAt = now;
|
|
5149
|
+
return job;
|
|
5150
|
+
});
|
|
5151
|
+
}
|
|
5152
|
+
function finishVideoKnowledgeJob(id, owner, status, error) {
|
|
5153
|
+
return mutateVideoKnowledgeState((state) => {
|
|
5154
|
+
const job = state.jobs.find((candidate) => candidate.id === id);
|
|
5155
|
+
if (!job || job.leaseOwner && job.leaseOwner !== owner) return void 0;
|
|
5156
|
+
job.status = status;
|
|
5157
|
+
job.error = error;
|
|
5158
|
+
job.leaseOwner = void 0;
|
|
5159
|
+
job.leaseExpiresAt = void 0;
|
|
5160
|
+
job.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
5161
|
+
return job;
|
|
5162
|
+
});
|
|
5163
|
+
}
|
|
5164
|
+
|
|
5165
|
+
// ../../packages/core/src/video-knowledge/knowledge-builder.ts
|
|
5166
|
+
import { randomUUID as randomUUID7 } from "crypto";
|
|
5167
|
+
var uncalibrated = {
|
|
5168
|
+
score: 1,
|
|
5169
|
+
source: "heuristic",
|
|
5170
|
+
calibrationStatus: "uncalibrated",
|
|
5171
|
+
uncertaintyReasons: [
|
|
5172
|
+
"Legacy timeline evidence has not been calibrated against the video evaluation corpus."
|
|
5173
|
+
]
|
|
5174
|
+
};
|
|
5175
|
+
function textFromValue(value) {
|
|
5176
|
+
if (typeof value === "string") return value;
|
|
5177
|
+
if (value && typeof value === "object" && !Array.isArray(value) && typeof value.text === "string") {
|
|
5178
|
+
return value.text;
|
|
5179
|
+
}
|
|
5180
|
+
return JSON.stringify(value);
|
|
5181
|
+
}
|
|
5182
|
+
function isStateValue(value) {
|
|
5183
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
5184
|
+
}
|
|
5185
|
+
function buildVideoKnowledgeFromEvidence(input) {
|
|
5186
|
+
return mutateVideoKnowledgeState((state) => {
|
|
5187
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
5188
|
+
const maxSceneDuration = Math.max(30, input.maximumSceneDurationSecs ?? 300);
|
|
5189
|
+
const accepted = [...input.evidence].filter(
|
|
5190
|
+
(item) => Number.isFinite(item.timeRange.startSecs) && Number.isFinite(item.timeRange.endSecs)
|
|
5191
|
+
).sort(
|
|
5192
|
+
(left, right) => left.timeRange.startSecs - right.timeRange.startSecs || left.timeRange.endSecs - right.timeRange.endSecs
|
|
5193
|
+
);
|
|
5194
|
+
const evidence = accepted.map((item) => {
|
|
5195
|
+
const id = randomUUID7();
|
|
5196
|
+
const lineageId = randomUUID7();
|
|
5197
|
+
state.evidence.push({
|
|
5198
|
+
id,
|
|
5199
|
+
lineageId,
|
|
5200
|
+
mediaAssetId: input.mediaAssetId,
|
|
5201
|
+
knowledgeRevisionId: input.knowledgeRevisionId,
|
|
5202
|
+
modality: item.modality,
|
|
5203
|
+
timeRange: range(
|
|
5204
|
+
item.timeRange.startSecs,
|
|
5205
|
+
item.timeRange.endSecs,
|
|
5206
|
+
item.timeRange.precision
|
|
5207
|
+
),
|
|
5208
|
+
frameArtifactIds: item.frameArtifactIds,
|
|
5209
|
+
payload: item.payload,
|
|
5210
|
+
source: item.source,
|
|
5211
|
+
confidence: item.confidence,
|
|
5212
|
+
schemaVersion: 1,
|
|
5213
|
+
createdAt: now
|
|
5214
|
+
});
|
|
5215
|
+
return { item, id, lineageId };
|
|
5216
|
+
});
|
|
5217
|
+
const observations = [];
|
|
5218
|
+
for (const record of evidence) {
|
|
5219
|
+
const kind = record.item.observation?.kind ?? (record.item.modality === "transcript" ? "speech" : record.item.modality === "ocr" ? "ocr" : record.item.modality === "audio-event" ? "audio-event" : record.item.modality === "computed" ? "computed" : "state");
|
|
5220
|
+
const id = randomUUID7();
|
|
5221
|
+
const lineageId = randomUUID7();
|
|
5222
|
+
state.observations.push({
|
|
5223
|
+
id,
|
|
5224
|
+
lineageId,
|
|
5225
|
+
mediaAssetId: input.mediaAssetId,
|
|
5226
|
+
knowledgeRevisionId: input.knowledgeRevisionId,
|
|
5227
|
+
kind,
|
|
5228
|
+
timeRange: range(
|
|
5229
|
+
record.item.timeRange.startSecs,
|
|
5230
|
+
record.item.timeRange.endSecs,
|
|
5231
|
+
record.item.timeRange.precision
|
|
5232
|
+
),
|
|
5233
|
+
value: record.item.observation?.value ?? record.item.payload,
|
|
5234
|
+
evidenceLineageIds: [record.lineageId],
|
|
5235
|
+
confidence: record.item.observation?.confidence ?? record.item.confidence,
|
|
5236
|
+
schemaVersion: 1,
|
|
5237
|
+
createdAt: now
|
|
5238
|
+
});
|
|
5239
|
+
observations.push({ id, lineageId, evidenceLineageId: record.lineageId, item: record.item });
|
|
5240
|
+
}
|
|
5241
|
+
const previousByProperty = /* @__PURE__ */ new Map();
|
|
5242
|
+
for (const observation of observations) {
|
|
5243
|
+
const value = observation.item.observation?.value ?? observation.item.payload;
|
|
5244
|
+
if (!isStateValue(value)) continue;
|
|
5245
|
+
const subject = typeof value.subject === "string" ? value.subject.trim() : "";
|
|
5246
|
+
const property = typeof value.property === "string" ? value.property.trim() : "";
|
|
5247
|
+
if (!subject || !property || value.value === void 0) continue;
|
|
5248
|
+
const key = `${subject}\0${property}`;
|
|
5249
|
+
const previous = previousByProperty.get(key);
|
|
5250
|
+
const stateId = randomUUID7();
|
|
5251
|
+
const stateLineageId = randomUUID7();
|
|
5252
|
+
state.states.push({
|
|
5253
|
+
id: stateId,
|
|
5254
|
+
lineageId: stateLineageId,
|
|
5255
|
+
mediaAssetId: input.mediaAssetId,
|
|
5256
|
+
knowledgeRevisionId: input.knowledgeRevisionId,
|
|
5257
|
+
subject,
|
|
5258
|
+
property,
|
|
5259
|
+
value: value.value,
|
|
5260
|
+
timeRange: range(
|
|
5261
|
+
observation.item.timeRange.startSecs,
|
|
5262
|
+
observation.item.timeRange.endSecs,
|
|
5263
|
+
observation.item.timeRange.precision
|
|
5264
|
+
),
|
|
5265
|
+
previousStateId: previous?.id,
|
|
5266
|
+
evidenceLineageIds: [observation.evidenceLineageId],
|
|
5267
|
+
confidence: observation.item.observation?.confidence ?? observation.item.confidence,
|
|
5268
|
+
schemaVersion: 1,
|
|
5269
|
+
createdAt: now
|
|
5270
|
+
});
|
|
5271
|
+
const conflictingState = state.states.find(
|
|
5272
|
+
(candidate) => candidate.id !== stateId && candidate.mediaAssetId === input.mediaAssetId && candidate.subject === subject && candidate.property === property && candidate.timeRange.startSecs <= observation.item.timeRange.endSecs && candidate.timeRange.endSecs >= observation.item.timeRange.startSecs && JSON.stringify(candidate.value) !== JSON.stringify(value.value)
|
|
5273
|
+
);
|
|
5274
|
+
if (conflictingState) {
|
|
5275
|
+
const existing = state.conflicts.some(
|
|
5276
|
+
(conflict) => conflict.knowledgeRevisionId === input.knowledgeRevisionId && conflict.evidenceLineageIds.includes(observation.evidenceLineageId) && conflict.evidenceLineageIds.some(
|
|
5277
|
+
(lineageId) => conflictingState.evidenceLineageIds.includes(lineageId)
|
|
5278
|
+
)
|
|
5279
|
+
);
|
|
5280
|
+
if (!existing) {
|
|
5281
|
+
state.conflicts.push({
|
|
5282
|
+
id: randomUUID7(),
|
|
5283
|
+
mediaAssetId: input.mediaAssetId,
|
|
5284
|
+
knowledgeRevisionId: input.knowledgeRevisionId,
|
|
5285
|
+
evidenceLineageIds: [
|
|
5286
|
+
.../* @__PURE__ */ new Set([...conflictingState.evidenceLineageIds, observation.evidenceLineageId])
|
|
5287
|
+
],
|
|
5288
|
+
affectedObservationLineageIds: [observation.lineageId],
|
|
5289
|
+
status: "conflicted",
|
|
5290
|
+
schemaVersion: 1,
|
|
5291
|
+
createdAt: now
|
|
5292
|
+
});
|
|
5293
|
+
}
|
|
5294
|
+
}
|
|
5295
|
+
if (previous && JSON.stringify(previous.value) !== JSON.stringify(value.value)) {
|
|
5296
|
+
const transitionLineageId = randomUUID7();
|
|
5297
|
+
state.transitions.push({
|
|
5298
|
+
id: randomUUID7(),
|
|
5299
|
+
lineageId: transitionLineageId,
|
|
5300
|
+
mediaAssetId: input.mediaAssetId,
|
|
5301
|
+
knowledgeRevisionId: input.knowledgeRevisionId,
|
|
5302
|
+
beforeStateId: previous.id,
|
|
5303
|
+
afterStateId: stateId,
|
|
5304
|
+
description: `${subject} ${property} changed from ${textFromValue(
|
|
5305
|
+
previous.value
|
|
5306
|
+
)} to ${textFromValue(value.value)}.`,
|
|
5307
|
+
timeRange: range(
|
|
5308
|
+
observation.item.timeRange.startSecs,
|
|
5309
|
+
observation.item.timeRange.endSecs,
|
|
5310
|
+
observation.item.timeRange.precision
|
|
5311
|
+
),
|
|
5312
|
+
evidenceLineageIds: [observation.evidenceLineageId],
|
|
5313
|
+
confidence: observation.item.observation?.confidence ?? observation.item.confidence,
|
|
5314
|
+
schemaVersion: 1,
|
|
5315
|
+
createdAt: now
|
|
5316
|
+
});
|
|
5317
|
+
}
|
|
5318
|
+
previousByProperty.set(key, { id: stateId, lineageId: stateLineageId, value: value.value });
|
|
5319
|
+
}
|
|
5320
|
+
const events = observations.map((observation) => {
|
|
5321
|
+
const item = observation.item;
|
|
5322
|
+
const transition = state.transitions.find(
|
|
5323
|
+
(candidate) => candidate.knowledgeRevisionId === input.knowledgeRevisionId && candidate.timeRange.startSecs === item.timeRange.startSecs && candidate.evidenceLineageIds.includes(observation.evidenceLineageId)
|
|
5324
|
+
);
|
|
5325
|
+
const event = {
|
|
5326
|
+
id: randomUUID7(),
|
|
5327
|
+
lineageId: randomUUID7(),
|
|
5328
|
+
mediaAssetId: input.mediaAssetId,
|
|
5329
|
+
knowledgeRevisionId: input.knowledgeRevisionId,
|
|
5330
|
+
type: transition ? "state-transition" : item.observation?.kind ?? item.modality,
|
|
5331
|
+
description: transition?.description ?? textFromValue(item.observation?.value ?? item.payload).slice(0, 2e3),
|
|
5332
|
+
timeRange: range(
|
|
5333
|
+
item.timeRange.startSecs,
|
|
5334
|
+
item.timeRange.endSecs,
|
|
5335
|
+
item.timeRange.precision
|
|
5336
|
+
),
|
|
5337
|
+
evidenceLineageIds: [observation.evidenceLineageId],
|
|
5338
|
+
observationLineageIds: [observation.lineageId],
|
|
5339
|
+
transitionLineageIds: transition ? [transition.lineageId] : [],
|
|
5340
|
+
confidence: item.observation?.confidence ?? item.confidence,
|
|
5341
|
+
schemaVersion: 1,
|
|
5342
|
+
createdAt: now
|
|
5343
|
+
};
|
|
5344
|
+
state.events.push(event);
|
|
5345
|
+
return event;
|
|
5346
|
+
});
|
|
5347
|
+
const sceneGroups = [];
|
|
5348
|
+
for (const event of events) {
|
|
5349
|
+
const group = sceneGroups.at(-1);
|
|
5350
|
+
if (!group || event.timeRange.startSecs - group.at(-1).timeRange.endSecs > 15 || event.timeRange.endSecs - group[0].timeRange.startSecs > maxSceneDuration) {
|
|
5351
|
+
sceneGroups.push([event]);
|
|
5352
|
+
} else {
|
|
5353
|
+
group.push(event);
|
|
5354
|
+
}
|
|
5355
|
+
}
|
|
5356
|
+
const scenes = sceneGroups.map((group, index) => {
|
|
5357
|
+
const scene = {
|
|
5358
|
+
id: randomUUID7(),
|
|
5359
|
+
lineageId: randomUUID7(),
|
|
5360
|
+
mediaAssetId: input.mediaAssetId,
|
|
5361
|
+
knowledgeRevisionId: input.knowledgeRevisionId,
|
|
5362
|
+
title: `Scene ${index + 1}: ${eventsDescription(group).slice(0, 120)}`,
|
|
5363
|
+
timeRange: range(
|
|
5364
|
+
group[0].timeRange.startSecs,
|
|
5365
|
+
group.at(-1).timeRange.endSecs,
|
|
5366
|
+
group.some((event) => event.timeRange.precision === "estimated") ? "estimated" : "segment"
|
|
5367
|
+
),
|
|
5368
|
+
eventLineageIds: group.map((event) => event.lineageId),
|
|
5369
|
+
evidenceLineageIds: group.flatMap((event) => event.evidenceLineageIds),
|
|
5370
|
+
quality: { ...uncalibrated, coverage: 1 },
|
|
5371
|
+
capabilities: [...new Set(group.map((event) => `larkup:${event.type}`))],
|
|
5372
|
+
schemaVersion: 1,
|
|
5373
|
+
createdAt: now
|
|
5374
|
+
};
|
|
5375
|
+
state.scenes.push(scene);
|
|
5376
|
+
return scene;
|
|
5377
|
+
});
|
|
5378
|
+
const chapterSize = 6;
|
|
5379
|
+
for (let start = 0; start < scenes.length; start += chapterSize) {
|
|
5380
|
+
const group = scenes.slice(start, start + chapterSize);
|
|
5381
|
+
state.chapters.push({
|
|
5382
|
+
id: randomUUID7(),
|
|
5383
|
+
lineageId: randomUUID7(),
|
|
5384
|
+
mediaAssetId: input.mediaAssetId,
|
|
5385
|
+
knowledgeRevisionId: input.knowledgeRevisionId,
|
|
5386
|
+
title: `Chapter ${Math.floor(start / chapterSize) + 1}: ${group[0].title.slice(0, 120)}`,
|
|
5387
|
+
timeRange: range(group[0].timeRange.startSecs, group.at(-1).timeRange.endSecs, "segment"),
|
|
5388
|
+
sceneLineageIds: group.map((scene) => scene.lineageId),
|
|
5389
|
+
eventLineageIds: group.flatMap((scene) => scene.eventLineageIds),
|
|
5390
|
+
evidenceLineageIds: group.flatMap((scene) => scene.evidenceLineageIds),
|
|
5391
|
+
quality: { ...uncalibrated, coverage: 1 },
|
|
5392
|
+
schemaVersion: 1,
|
|
5393
|
+
createdAt: now
|
|
5394
|
+
});
|
|
5395
|
+
}
|
|
5396
|
+
return {
|
|
5397
|
+
evidenceIds: evidence.map((item) => item.id),
|
|
5398
|
+
evidenceLineageIds: evidence.map((item) => item.lineageId),
|
|
5399
|
+
observationIds: observations.map((item) => item.id),
|
|
5400
|
+
observationLineageIds: observations.map((item) => item.lineageId),
|
|
5401
|
+
eventIds: events.map((item) => item.id),
|
|
5402
|
+
sceneIds: scenes.map((item) => item.id)
|
|
5403
|
+
};
|
|
5404
|
+
});
|
|
5405
|
+
}
|
|
5406
|
+
function range(startSecs, endSecs, precision) {
|
|
5407
|
+
return { startSecs: Math.max(0, startSecs), endSecs: Math.max(startSecs, endSecs), precision };
|
|
5408
|
+
}
|
|
5409
|
+
function eventsDescription(events) {
|
|
5410
|
+
return events.map((event) => event.description).filter(Boolean).join(" ").replace(/\s+/g, " ").trim() || "Timeline evidence";
|
|
5411
|
+
}
|
|
5412
|
+
|
|
5413
|
+
// ../../packages/core/src/video-knowledge/manifest-store.ts
|
|
5414
|
+
import { randomUUID as randomUUID8 } from "crypto";
|
|
5415
|
+
function saveVideoKnowledgeProjection(record) {
|
|
5416
|
+
return mutateVideoKnowledgeState((state) => {
|
|
5417
|
+
const projection = {
|
|
5418
|
+
...record,
|
|
5419
|
+
id: randomUUID8(),
|
|
5420
|
+
schemaVersion: 1,
|
|
5421
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
5422
|
+
};
|
|
5423
|
+
state.projections.push(projection);
|
|
5424
|
+
return projection;
|
|
5425
|
+
});
|
|
5426
|
+
}
|
|
5427
|
+
function activateVideoKnowledgeManifest(input) {
|
|
5428
|
+
return mutateVideoKnowledgeState((state) => {
|
|
5429
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
5430
|
+
for (const projection of state.projections) {
|
|
5431
|
+
if (projection.mediaAssetId === input.mediaAssetId)
|
|
5432
|
+
projection.active = input.activeProjectionIds.includes(projection.id);
|
|
5433
|
+
}
|
|
5434
|
+
const manifest = {
|
|
5435
|
+
...input,
|
|
5436
|
+
id: randomUUID8(),
|
|
5437
|
+
schemaVersion: 1,
|
|
5438
|
+
createdAt: now,
|
|
5439
|
+
activatedAt: now
|
|
5440
|
+
};
|
|
5441
|
+
state.manifests.push(manifest);
|
|
5442
|
+
const revision = state.revisions.find(
|
|
5443
|
+
(candidate) => candidate.id === input.knowledgeRevisionId
|
|
5444
|
+
);
|
|
5445
|
+
if (revision) revision.activeManifestId = manifest.id;
|
|
5446
|
+
return manifest;
|
|
5447
|
+
});
|
|
5448
|
+
}
|
|
5449
|
+
|
|
4946
5450
|
// src/commands/media.ts
|
|
4947
5451
|
var MIME_TYPES = {
|
|
4948
5452
|
".png": "image/png",
|
|
@@ -4985,12 +5489,12 @@ async function processMediaCommand(inputs, options) {
|
|
|
4985
5489
|
const assets = await Promise.all(
|
|
4986
5490
|
mediaFiles.map(async (filePath) => {
|
|
4987
5491
|
const type = mediaType(filePath);
|
|
4988
|
-
const stat = await
|
|
4989
|
-
const extension =
|
|
5492
|
+
const stat = await fs10.stat(filePath);
|
|
5493
|
+
const extension = path11.extname(filePath).toLowerCase() || ".bin";
|
|
4990
5494
|
const key = `${type}s/${Date.now()}_${Math.random().toString(36).slice(2)}${extension}`;
|
|
4991
5495
|
const mimeType = MIME_TYPES[extension] || "application/octet-stream";
|
|
4992
|
-
const storageUri = storage.storeFile ? await storage.storeFile(key, filePath, mimeType) : await storage.store(key, await
|
|
4993
|
-
return { type, fileName:
|
|
5496
|
+
const storageUri = storage.storeFile ? await storage.storeFile(key, filePath, mimeType) : await storage.store(key, await fs10.readFile(filePath), mimeType);
|
|
5497
|
+
return { type, fileName: path11.basename(filePath), mimeType, storageUri, fileSize: stat.size };
|
|
4994
5498
|
})
|
|
4995
5499
|
);
|
|
4996
5500
|
const stored = await addMediaAssets(assets);
|
|
@@ -5072,7 +5576,7 @@ async function processMediaAsset(asset) {
|
|
|
5072
5576
|
if (!tool2.processVideo)
|
|
5073
5577
|
throw new Error("The installed Video & Audio tool cannot process videos.");
|
|
5074
5578
|
await update("Extracting video audio", 20);
|
|
5075
|
-
const outputDir = await
|
|
5579
|
+
const outputDir = await fs10.mkdtemp(path11.join(process.cwd(), ".larkup", "tmp-media-"));
|
|
5076
5580
|
try {
|
|
5077
5581
|
const video = await tool2.processVideo(localFile, {
|
|
5078
5582
|
outputDir,
|
|
@@ -5093,7 +5597,7 @@ async function processMediaAsset(asset) {
|
|
|
5093
5597
|
dimensions = { width: video.meta.width, height: video.meta.height };
|
|
5094
5598
|
frameCount = video.frames.length;
|
|
5095
5599
|
} finally {
|
|
5096
|
-
await
|
|
5600
|
+
await fs10.rm(outputDir, { recursive: true, force: true }).catch(() => {
|
|
5097
5601
|
});
|
|
5098
5602
|
}
|
|
5099
5603
|
} else {
|
|
@@ -5125,6 +5629,14 @@ async function processMediaAsset(asset) {
|
|
|
5125
5629
|
contentKind: claimed.type === "video" ? "video-transcript" : "audio-transcript"
|
|
5126
5630
|
}
|
|
5127
5631
|
});
|
|
5632
|
+
const knowledge = await publishCliVideoKnowledge({
|
|
5633
|
+
asset: claimed,
|
|
5634
|
+
localFile,
|
|
5635
|
+
durationSecs,
|
|
5636
|
+
frameCount,
|
|
5637
|
+
documentId: document.id,
|
|
5638
|
+
segments
|
|
5639
|
+
});
|
|
5128
5640
|
await updateMediaAsset(claimed.id, {
|
|
5129
5641
|
processingStatus: "completed",
|
|
5130
5642
|
processingProgress: 100,
|
|
@@ -5132,7 +5644,9 @@ async function processMediaAsset(asset) {
|
|
|
5132
5644
|
caption: `${claimed.type === "video" ? "Video" : "Audio"}: ${Math.round(durationSecs)}s`,
|
|
5133
5645
|
durationSecs,
|
|
5134
5646
|
dimensions,
|
|
5135
|
-
documentIds: [document.id]
|
|
5647
|
+
documentIds: [document.id],
|
|
5648
|
+
activeVideoKnowledgeRevisionId: knowledge.revisionId,
|
|
5649
|
+
activeVideoKnowledgeManifestId: knowledge.manifestId
|
|
5136
5650
|
});
|
|
5137
5651
|
void trackUsageEvent({
|
|
5138
5652
|
type: "media_processing",
|
|
@@ -5155,6 +5669,133 @@ async function processMediaAsset(asset) {
|
|
|
5155
5669
|
log.warn(message);
|
|
5156
5670
|
}
|
|
5157
5671
|
}
|
|
5672
|
+
async function publishCliVideoKnowledge(input) {
|
|
5673
|
+
const hash = createHash("sha256");
|
|
5674
|
+
for await (const chunk of createReadStream(input.localFile)) hash.update(chunk);
|
|
5675
|
+
const revision = await createVideoKnowledgeRevision({
|
|
5676
|
+
mediaAssetId: input.asset.id,
|
|
5677
|
+
sourceFingerprint: hash.digest("hex"),
|
|
5678
|
+
pipelineVersion: "video-knowledge-v1",
|
|
5679
|
+
budget: {
|
|
5680
|
+
maxDurationSecs: input.durationSecs,
|
|
5681
|
+
maxBytes: input.asset.fileSize,
|
|
5682
|
+
maxFrames: input.frameCount,
|
|
5683
|
+
maxModelCalls: 0,
|
|
5684
|
+
maxCostUsd: 0,
|
|
5685
|
+
usedDurationSecs: input.durationSecs,
|
|
5686
|
+
usedFrames: input.frameCount
|
|
5687
|
+
},
|
|
5688
|
+
coverage: {
|
|
5689
|
+
sourceDurationSecs: input.durationSecs,
|
|
5690
|
+
inspectedRanges: [],
|
|
5691
|
+
transcriptCoverage: 0,
|
|
5692
|
+
visualCoverage: 0,
|
|
5693
|
+
ocrCoverage: 0,
|
|
5694
|
+
partialReasons: []
|
|
5695
|
+
}
|
|
5696
|
+
});
|
|
5697
|
+
const job = await createVideoKnowledgeJob({
|
|
5698
|
+
mediaAssetId: input.asset.id,
|
|
5699
|
+
knowledgeRevisionId: revision.id,
|
|
5700
|
+
idempotencyKey: `${input.asset.id}:${revision.sourceFingerprint}:video-knowledge-v1`,
|
|
5701
|
+
budget: revision.budget
|
|
5702
|
+
});
|
|
5703
|
+
const owner = randomUUID9();
|
|
5704
|
+
if (!await claimVideoKnowledgeJob(job.id, owner))
|
|
5705
|
+
throw new Error("Unable to claim CLI video knowledge job.");
|
|
5706
|
+
try {
|
|
5707
|
+
const confidence = {
|
|
5708
|
+
score: 0.8,
|
|
5709
|
+
source: "provider",
|
|
5710
|
+
calibrationStatus: "uncalibrated",
|
|
5711
|
+
uncertaintyReasons: ["CLI transcription has provider-segment timestamp precision."]
|
|
5712
|
+
};
|
|
5713
|
+
const evidence = [
|
|
5714
|
+
...input.segments.filter((segment) => segment.text.trim()).map((segment) => ({
|
|
5715
|
+
modality: "transcript",
|
|
5716
|
+
timeRange: {
|
|
5717
|
+
startSecs: segment.startSecs,
|
|
5718
|
+
endSecs: segment.endSecs,
|
|
5719
|
+
precision: "segment"
|
|
5720
|
+
},
|
|
5721
|
+
payload: { text: segment.text },
|
|
5722
|
+
source: { kind: "provider", provider: "stt" },
|
|
5723
|
+
confidence,
|
|
5724
|
+
observation: { kind: "speech", value: { text: segment.text } }
|
|
5725
|
+
})),
|
|
5726
|
+
...deriveCliAudioSignals(input.segments).map((signal) => ({
|
|
5727
|
+
modality: "audio-event",
|
|
5728
|
+
timeRange: {
|
|
5729
|
+
startSecs: signal.timestampSecs,
|
|
5730
|
+
endSecs: signal.timestampSecs,
|
|
5731
|
+
precision: "segment"
|
|
5732
|
+
},
|
|
5733
|
+
payload: {
|
|
5734
|
+
transcriptChange: signal.transcriptChange,
|
|
5735
|
+
silenceBoundary: signal.silenceBoundary
|
|
5736
|
+
},
|
|
5737
|
+
source: { kind: "heuristic", version: "audio-signals-v1" },
|
|
5738
|
+
confidence: { ...confidence, source: "heuristic" },
|
|
5739
|
+
observation: {
|
|
5740
|
+
kind: "audio-event",
|
|
5741
|
+
value: {
|
|
5742
|
+
transcriptChange: signal.transcriptChange,
|
|
5743
|
+
silenceBoundary: signal.silenceBoundary
|
|
5744
|
+
}
|
|
5745
|
+
}
|
|
5746
|
+
}))
|
|
5747
|
+
];
|
|
5748
|
+
const built = await buildVideoKnowledgeFromEvidence({
|
|
5749
|
+
mediaAssetId: input.asset.id,
|
|
5750
|
+
knowledgeRevisionId: revision.id,
|
|
5751
|
+
evidence
|
|
5752
|
+
});
|
|
5753
|
+
const projection = await saveVideoKnowledgeProjection({
|
|
5754
|
+
mediaAssetId: input.asset.id,
|
|
5755
|
+
knowledgeRevisionId: revision.id,
|
|
5756
|
+
kind: "transcript",
|
|
5757
|
+
documentId: input.documentId,
|
|
5758
|
+
lineageIds: [],
|
|
5759
|
+
evidenceIds: built.evidenceIds,
|
|
5760
|
+
quality: {
|
|
5761
|
+
score: 0.7,
|
|
5762
|
+
source: "heuristic",
|
|
5763
|
+
calibrationStatus: "uncalibrated",
|
|
5764
|
+
uncertaintyReasons: ["Search projection; source evidence is authoritative."]
|
|
5765
|
+
},
|
|
5766
|
+
active: false
|
|
5767
|
+
});
|
|
5768
|
+
await checkpointVideoKnowledgeJob(job.id, owner, "projecting", {
|
|
5769
|
+
completedEvidenceIds: built.evidenceIds,
|
|
5770
|
+
completedProjectionIds: [projection.id]
|
|
5771
|
+
});
|
|
5772
|
+
const manifest = await activateVideoKnowledgeManifest({
|
|
5773
|
+
mediaAssetId: input.asset.id,
|
|
5774
|
+
knowledgeRevisionId: revision.id,
|
|
5775
|
+
activeEvidenceRevisionIds: Object.fromEntries(
|
|
5776
|
+
built.evidenceLineageIds.map((lineageId, index) => [lineageId, built.evidenceIds[index]])
|
|
5777
|
+
),
|
|
5778
|
+
activeObservationRevisionIds: Object.fromEntries(
|
|
5779
|
+
built.observationLineageIds.map((lineageId, index) => [
|
|
5780
|
+
lineageId,
|
|
5781
|
+
built.observationIds[index]
|
|
5782
|
+
])
|
|
5783
|
+
),
|
|
5784
|
+
activeProjectionIds: [projection.id],
|
|
5785
|
+
activationReason: "initial"
|
|
5786
|
+
});
|
|
5787
|
+
await finishVideoKnowledgeJob(job.id, owner, "completed");
|
|
5788
|
+
return { revisionId: revision.id, manifestId: manifest.id };
|
|
5789
|
+
} catch (error) {
|
|
5790
|
+
await finishVideoKnowledgeJob(
|
|
5791
|
+
job.id,
|
|
5792
|
+
owner,
|
|
5793
|
+
"failed",
|
|
5794
|
+
error instanceof Error ? error.message : "CLI knowledge publication failed."
|
|
5795
|
+
);
|
|
5796
|
+
throw error;
|
|
5797
|
+
}
|
|
5798
|
+
}
|
|
5158
5799
|
async function indexPendingMedia() {
|
|
5159
5800
|
const config = await readConfig();
|
|
5160
5801
|
const previousRun = await readRun();
|
|
@@ -5171,7 +5812,7 @@ async function indexPendingMedia() {
|
|
|
5171
5812
|
spinner2.stop(`Indexed ${finalRun.totalChunks} chunks`);
|
|
5172
5813
|
}
|
|
5173
5814
|
function mediaType(filePath) {
|
|
5174
|
-
const extension =
|
|
5815
|
+
const extension = path11.extname(filePath).toLowerCase();
|
|
5175
5816
|
if ([".png", ".jpg", ".jpeg", ".webp", ".gif"].includes(extension)) return "image";
|
|
5176
5817
|
if ([".mp4", ".webm", ".mov", ".mkv"].includes(extension)) return "video";
|
|
5177
5818
|
if ([".mp3", ".m4a", ".wav", ".ogg", ".flac"].includes(extension)) return "audio";
|
|
@@ -5190,6 +5831,25 @@ function formatTime(seconds) {
|
|
|
5190
5831
|
const minutes = Math.floor(seconds / 60);
|
|
5191
5832
|
return `${minutes}:${String(Math.floor(seconds % 60)).padStart(2, "0")}`;
|
|
5192
5833
|
}
|
|
5834
|
+
function deriveCliAudioSignals(chunks) {
|
|
5835
|
+
let previous;
|
|
5836
|
+
return [...chunks].sort((left, right) => left.startSecs - right.startSecs).map((chunk) => {
|
|
5837
|
+
const earlier = new Set(
|
|
5838
|
+
(previous?.text ?? "").toLocaleLowerCase().match(/[\p{Letter}\p{Number}]+/gu) ?? []
|
|
5839
|
+
);
|
|
5840
|
+
const words = new Set(
|
|
5841
|
+
chunk.text.toLocaleLowerCase().match(/[\p{Letter}\p{Number}]+/gu) ?? []
|
|
5842
|
+
);
|
|
5843
|
+
const transcriptChange = words.size === 0 ? 0 : [...words].filter((word) => !earlier.has(word)).length / words.size;
|
|
5844
|
+
const signal = {
|
|
5845
|
+
timestampSecs: chunk.startSecs,
|
|
5846
|
+
transcriptChange,
|
|
5847
|
+
silenceBoundary: Boolean(previous && chunk.startSecs - previous.endSecs >= 2)
|
|
5848
|
+
};
|
|
5849
|
+
previous = chunk;
|
|
5850
|
+
return signal;
|
|
5851
|
+
});
|
|
5852
|
+
}
|
|
5193
5853
|
|
|
5194
5854
|
// src/commands/index-cmd.ts
|
|
5195
5855
|
async function indexCommand(inputs, options) {
|
|
@@ -5200,9 +5860,10 @@ async function indexCommand(inputs, options) {
|
|
|
5200
5860
|
const textFiles = await readTextFiles(files);
|
|
5201
5861
|
const mediaFiles = files.filter(isMediaPath);
|
|
5202
5862
|
for (const document of textFiles) {
|
|
5203
|
-
await addDocument({ title: document.title, content: document.content, source: "
|
|
5863
|
+
await addDocument({ title: document.title, content: document.content, source: "files" });
|
|
5204
5864
|
}
|
|
5205
|
-
if (textFiles.length > 0)
|
|
5865
|
+
if (textFiles.length > 0)
|
|
5866
|
+
log.success(`Loaded ${textFiles.length} document${textFiles.length === 1 ? "" : "s"}.`);
|
|
5206
5867
|
if (mediaFiles.length > 0) await mediaCommand(mediaFiles, { index: false });
|
|
5207
5868
|
if (textFiles.length === 0 && mediaFiles.length === 0) {
|
|
5208
5869
|
log.error("No supported text or media files were found.");
|
|
@@ -5218,7 +5879,9 @@ async function indexCommand(inputs, options) {
|
|
|
5218
5879
|
log.error("Corpus is empty. Add documents first: larkup add-doc --file <path>");
|
|
5219
5880
|
}
|
|
5220
5881
|
if (!getEmbeddingModel(config.embeddingModelId)) {
|
|
5221
|
-
log.error(
|
|
5882
|
+
log.error(
|
|
5883
|
+
`Unknown embedding model "${config.embeddingModelId}". Set it in the Configure stage.`
|
|
5884
|
+
);
|
|
5222
5885
|
}
|
|
5223
5886
|
await ensureApiKey(config, "embedding");
|
|
5224
5887
|
log.info(log.fmt.cyan(`Indexing ${docs.length} document(s) into ${config.vectorStore}\u2026`));
|
|
@@ -5237,7 +5900,11 @@ async function indexCommand(inputs, options) {
|
|
|
5237
5900
|
}
|
|
5238
5901
|
}, 400);
|
|
5239
5902
|
try {
|
|
5240
|
-
await runIndexer(
|
|
5903
|
+
await runIndexer(
|
|
5904
|
+
run.id,
|
|
5905
|
+
config,
|
|
5906
|
+
options.incremental && previousRun?.status === "completed" ? previousRun : null
|
|
5907
|
+
);
|
|
5241
5908
|
} catch (e) {
|
|
5242
5909
|
done = true;
|
|
5243
5910
|
clearInterval(timer);
|
|
@@ -5248,7 +5915,9 @@ async function indexCommand(inputs, options) {
|
|
|
5248
5915
|
clearInterval(timer);
|
|
5249
5916
|
const final = await readRun();
|
|
5250
5917
|
if (final?.status === "completed") {
|
|
5251
|
-
s.stop(
|
|
5918
|
+
s.stop(
|
|
5919
|
+
`Indexed ${final.totalChunks} chunks (${final.dimensions}-dim) in ${((final.durationMs ?? 0) / 1e3).toFixed(1)}s`
|
|
5920
|
+
);
|
|
5252
5921
|
log.success("Indexing complete!");
|
|
5253
5922
|
} else {
|
|
5254
5923
|
s.stop("Indexing failed.");
|
|
@@ -5258,20 +5927,20 @@ async function indexCommand(inputs, options) {
|
|
|
5258
5927
|
}
|
|
5259
5928
|
|
|
5260
5929
|
// src/commands/generate.ts
|
|
5261
|
-
import { promises as
|
|
5262
|
-
import
|
|
5930
|
+
import { promises as fs11 } from "fs";
|
|
5931
|
+
import path12 from "path";
|
|
5263
5932
|
async function generateCommand(options) {
|
|
5264
5933
|
await inServerScope(options.server, async () => {
|
|
5265
5934
|
await requireActive();
|
|
5266
5935
|
const config = await readConfig();
|
|
5267
5936
|
if (options.out) {
|
|
5268
|
-
const dir =
|
|
5937
|
+
const dir = path12.isAbsolute(options.out) ? options.out : path12.join(process.cwd(), options.out);
|
|
5269
5938
|
const server2 = generateServer(config);
|
|
5270
|
-
await
|
|
5939
|
+
await fs11.mkdir(dir, { recursive: true });
|
|
5271
5940
|
for (const f of server2.files) {
|
|
5272
|
-
const dest =
|
|
5273
|
-
await
|
|
5274
|
-
await
|
|
5941
|
+
const dest = path12.join(dir, f.path);
|
|
5942
|
+
await fs11.mkdir(path12.dirname(dest), { recursive: true });
|
|
5943
|
+
await fs11.writeFile(dest, f.contents, "utf8");
|
|
5275
5944
|
}
|
|
5276
5945
|
log.success(`Generated ${server2.files.length} files \u2192 ${dir}`);
|
|
5277
5946
|
} else {
|
|
@@ -5619,8 +6288,8 @@ async function marketplaceCommand(action = "list", toolId) {
|
|
|
5619
6288
|
}
|
|
5620
6289
|
|
|
5621
6290
|
// src/commands/deploy.ts
|
|
5622
|
-
import { promises as
|
|
5623
|
-
import
|
|
6291
|
+
import { promises as fs12 } from "fs";
|
|
6292
|
+
import path13 from "path";
|
|
5624
6293
|
async function deployCommand(target, options) {
|
|
5625
6294
|
await inServerScope(options.server, async () => {
|
|
5626
6295
|
await requireActive();
|
|
@@ -5656,13 +6325,13 @@ async function deployCommand(target, options) {
|
|
|
5656
6325
|
});
|
|
5657
6326
|
}
|
|
5658
6327
|
async function copyGenerated(source, output) {
|
|
5659
|
-
const destination =
|
|
5660
|
-
const relative =
|
|
5661
|
-
if (relative === "" || !relative.startsWith("..") && !
|
|
6328
|
+
const destination = path13.resolve(output);
|
|
6329
|
+
const relative = path13.relative(source, destination);
|
|
6330
|
+
if (relative === "" || !relative.startsWith("..") && !path13.isAbsolute(relative)) {
|
|
5662
6331
|
throw new Error("Deployment output must be outside the generated server directory.");
|
|
5663
6332
|
}
|
|
5664
|
-
await
|
|
5665
|
-
await
|
|
6333
|
+
await fs12.mkdir(destination, { recursive: true });
|
|
6334
|
+
await fs12.cp(source, destination, { recursive: true, force: true });
|
|
5666
6335
|
return destination;
|
|
5667
6336
|
}
|
|
5668
6337
|
|
|
@@ -5747,8 +6416,8 @@ function openCommandForPlatform(url) {
|
|
|
5747
6416
|
}
|
|
5748
6417
|
|
|
5749
6418
|
// src/commands/documents.ts
|
|
5750
|
-
import { promises as
|
|
5751
|
-
import
|
|
6419
|
+
import { promises as fs13 } from "fs";
|
|
6420
|
+
import path14 from "path";
|
|
5752
6421
|
|
|
5753
6422
|
// ../../packages/core/src/corpus-retriever.ts
|
|
5754
6423
|
function applyFilters(docs, filter) {
|
|
@@ -5867,10 +6536,10 @@ async function documentsCommand(action = "list", idOrPath, options) {
|
|
|
5867
6536
|
}
|
|
5868
6537
|
if (action === "export") {
|
|
5869
6538
|
const format = options.format === "jsonl" ? "jsonl" : "csv";
|
|
5870
|
-
const output =
|
|
6539
|
+
const output = path14.resolve(options.out || idOrPath || `corpus.${format}`);
|
|
5871
6540
|
const content = format === "jsonl" ? await exportCorpusAsJSONL(void 0, Number.MAX_SAFE_INTEGER) : await exportCorpusAsCSV(void 0, Number.MAX_SAFE_INTEGER);
|
|
5872
|
-
await
|
|
5873
|
-
await
|
|
6541
|
+
await fs13.mkdir(path14.dirname(output), { recursive: true });
|
|
6542
|
+
await fs13.writeFile(output, content, "utf8");
|
|
5874
6543
|
log.success(`Exported corpus \u2192 ${output}`);
|
|
5875
6544
|
return;
|
|
5876
6545
|
}
|
|
@@ -5896,7 +6565,7 @@ ${document.content}`);
|
|
|
5896
6565
|
return;
|
|
5897
6566
|
}
|
|
5898
6567
|
if (action === "update") {
|
|
5899
|
-
const content = options.file ? await
|
|
6568
|
+
const content = options.file ? await fs13.readFile(path14.resolve(options.file), "utf8") : options.text;
|
|
5900
6569
|
const updated = await updateDocument(document.id, {
|
|
5901
6570
|
title: options.title,
|
|
5902
6571
|
content,
|