@larkup/cli 0.1.17 → 0.1.20
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/index.js +157 -22
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -66,6 +66,92 @@ var prompts = {
|
|
|
66
66
|
spinner: p.spinner
|
|
67
67
|
};
|
|
68
68
|
|
|
69
|
+
// package.json
|
|
70
|
+
var package_default = {
|
|
71
|
+
name: "@larkup/cli",
|
|
72
|
+
version: "0.1.20",
|
|
73
|
+
publishConfig: {
|
|
74
|
+
access: "public"
|
|
75
|
+
},
|
|
76
|
+
type: "module",
|
|
77
|
+
bin: {
|
|
78
|
+
larkup: "./dist/index.js"
|
|
79
|
+
},
|
|
80
|
+
files: [
|
|
81
|
+
"dist"
|
|
82
|
+
],
|
|
83
|
+
scripts: {
|
|
84
|
+
build: "tsup",
|
|
85
|
+
dev: "tsup --watch",
|
|
86
|
+
larkup: "tsx src/index.ts"
|
|
87
|
+
},
|
|
88
|
+
dependencies: {
|
|
89
|
+
"@ai-sdk/cohere": "^3.0.39",
|
|
90
|
+
"@ai-sdk/deepseek": "^2.0.39",
|
|
91
|
+
"@ai-sdk/gateway": "^3.0.133",
|
|
92
|
+
"@ai-sdk/google": "^3.0.83",
|
|
93
|
+
"@ai-sdk/mistral": "^3.0.40",
|
|
94
|
+
"@ai-sdk/openai": "^3.0.68",
|
|
95
|
+
"@ai-sdk/openai-compatible": "^2.0.51",
|
|
96
|
+
"@clack/prompts": "^0.10.1",
|
|
97
|
+
"@lancedb/lancedb": "^0.30.0",
|
|
98
|
+
"@larkup/core": "workspace:*",
|
|
99
|
+
"@larkup/vector-stores": "workspace:*",
|
|
100
|
+
"@pinecone-database/pinecone": "^7.2.0",
|
|
101
|
+
ai: "^6.0.197",
|
|
102
|
+
chalk: "^5.6.2",
|
|
103
|
+
chromadb: "^1.10.5",
|
|
104
|
+
"cli-table3": "^0.6.5",
|
|
105
|
+
commander: "^13.1.0",
|
|
106
|
+
zod: "^4.4.3"
|
|
107
|
+
},
|
|
108
|
+
devDependencies: {
|
|
109
|
+
tsup: "^8.0.0",
|
|
110
|
+
tsx: "^4.22.4",
|
|
111
|
+
typescript: "5.7.3"
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// src/updater.ts
|
|
116
|
+
var VERSION_CHECK_URL = "https://larkup.de/api/version";
|
|
117
|
+
function compareVersions(a, b) {
|
|
118
|
+
const pa = a.replace(/^v/, "").split(".").map(Number);
|
|
119
|
+
const pb = b.replace(/^v/, "").split(".").map(Number);
|
|
120
|
+
for (let i = 0; i < 3; i++) {
|
|
121
|
+
const va = pa[i] || 0;
|
|
122
|
+
const vb = pb[i] || 0;
|
|
123
|
+
if (va > vb) return 1;
|
|
124
|
+
if (va < vb) return -1;
|
|
125
|
+
}
|
|
126
|
+
return 0;
|
|
127
|
+
}
|
|
128
|
+
async function checkUpdate() {
|
|
129
|
+
try {
|
|
130
|
+
const controller = new AbortController();
|
|
131
|
+
const timeout = setTimeout(() => controller.abort(), 1500);
|
|
132
|
+
const res = await fetch(VERSION_CHECK_URL, {
|
|
133
|
+
signal: controller.signal
|
|
134
|
+
});
|
|
135
|
+
clearTimeout(timeout);
|
|
136
|
+
if (!res.ok) return;
|
|
137
|
+
const data = await res.json();
|
|
138
|
+
const currentVersion = package_default.version;
|
|
139
|
+
if (data.version && compareVersions(data.version, currentVersion) > 0) {
|
|
140
|
+
console.log("");
|
|
141
|
+
log.info(`\u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E`);
|
|
142
|
+
log.info(
|
|
143
|
+
`\u2502 Update available: ${currentVersion} \u2192 ${data.version}${" ".repeat(25 - currentVersion.length - data.version.length)}\u2502`
|
|
144
|
+
);
|
|
145
|
+
log.info(
|
|
146
|
+
`\u2502 Run: ${log.fmt.cyan("npm install -g @larkup/cli")} \u2502`
|
|
147
|
+
);
|
|
148
|
+
log.info(`\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F`);
|
|
149
|
+
console.log("");
|
|
150
|
+
}
|
|
151
|
+
} catch {
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
69
155
|
// ../../packages/core/src/workspace.ts
|
|
70
156
|
import { promises as fs } from "fs";
|
|
71
157
|
import path from "path";
|
|
@@ -245,11 +331,17 @@ async function nextPort(ws) {
|
|
|
245
331
|
}
|
|
246
332
|
return candidate;
|
|
247
333
|
}
|
|
248
|
-
function defaultConfigFor(id, name) {
|
|
334
|
+
function defaultConfigFor(id, name, prevConfig = {}) {
|
|
249
335
|
return {
|
|
250
336
|
...DEFAULT_CONFIG,
|
|
251
337
|
projectName: name.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "my-rag",
|
|
252
338
|
storeConfig: { mode: "local", dbPath: relServerPath(id, "lancedb") },
|
|
339
|
+
embeddingApiKey: prevConfig.embeddingApiKey ?? DEFAULT_CONFIG.embeddingApiKey,
|
|
340
|
+
customEmbeddings: prevConfig.customEmbeddings ?? DEFAULT_CONFIG.customEmbeddings,
|
|
341
|
+
chatApiKey: prevConfig.chatApiKey ?? DEFAULT_CONFIG.chatApiKey,
|
|
342
|
+
customChatModels: prevConfig.customChatModels ?? DEFAULT_CONFIG.customChatModels,
|
|
343
|
+
serperApiKey: prevConfig.serperApiKey ?? DEFAULT_CONFIG.serperApiKey,
|
|
344
|
+
firecrawlApiKey: prevConfig.firecrawlApiKey ?? DEFAULT_CONFIG.firecrawlApiKey,
|
|
253
345
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
254
346
|
};
|
|
255
347
|
}
|
|
@@ -267,9 +359,17 @@ function createServer(name) {
|
|
|
267
359
|
};
|
|
268
360
|
const dir = serverDir(id);
|
|
269
361
|
await fs.mkdir(dir, { recursive: true });
|
|
362
|
+
let prevConfig = {};
|
|
363
|
+
if (ws.activeServerId) {
|
|
364
|
+
try {
|
|
365
|
+
const raw = await fs.readFile(path.join(serverDir(ws.activeServerId), "config.json"), "utf8");
|
|
366
|
+
prevConfig = JSON.parse(raw);
|
|
367
|
+
} catch {
|
|
368
|
+
}
|
|
369
|
+
}
|
|
270
370
|
await fs.writeFile(
|
|
271
371
|
path.join(dir, "config.json"),
|
|
272
|
-
JSON.stringify(defaultConfigFor(id, meta.name), null, 2),
|
|
372
|
+
JSON.stringify(defaultConfigFor(id, meta.name, prevConfig), null, 2),
|
|
273
373
|
"utf8"
|
|
274
374
|
);
|
|
275
375
|
const next = {
|
|
@@ -1529,27 +1629,37 @@ if (IS_SERVERLESS && MODE !== "cloud") {
|
|
|
1529
1629
|
console.warn("[LanceDB] Running on serverless \u2014 using /tmp/lancedb. Data will NOT persist between invocations. Use LanceDB Cloud for production.")
|
|
1530
1630
|
}
|
|
1531
1631
|
|
|
1632
|
+
let _conn = null
|
|
1532
1633
|
let _table = null
|
|
1533
1634
|
|
|
1534
|
-
async function
|
|
1535
|
-
if (
|
|
1536
|
-
let conn
|
|
1635
|
+
async function getConn() {
|
|
1636
|
+
if (_conn) return _conn
|
|
1537
1637
|
if (MODE === "cloud") {
|
|
1538
1638
|
if (!URI || !API_KEY) {
|
|
1539
1639
|
throw new Error("LanceDB Cloud needs LANCEDB_URI and LANCEDB_API_KEY.")
|
|
1540
1640
|
}
|
|
1541
|
-
|
|
1641
|
+
_conn = await lancedb.connect(URI, { apiKey: API_KEY })
|
|
1542
1642
|
} else {
|
|
1543
1643
|
const abs = path.isAbsolute(DB_PATH) ? DB_PATH : path.join(process.cwd(), DB_PATH)
|
|
1544
|
-
|
|
1644
|
+
_conn = await lancedb.connect(abs)
|
|
1545
1645
|
}
|
|
1646
|
+
return _conn
|
|
1647
|
+
}
|
|
1546
1648
|
|
|
1547
|
-
|
|
1548
|
-
return _table
|
|
1649
|
+
async function getTable() {
|
|
1650
|
+
if (_table) return _table
|
|
1651
|
+
const conn = await getConn()
|
|
1652
|
+
const names = await conn.tableNames()
|
|
1653
|
+
if (names.includes(TABLE)) {
|
|
1654
|
+
_table = await conn.openTable(TABLE)
|
|
1655
|
+
return _table
|
|
1656
|
+
}
|
|
1657
|
+
return null
|
|
1549
1658
|
}
|
|
1550
1659
|
|
|
1551
1660
|
export async function query(vector, topK) {
|
|
1552
|
-
const t = await
|
|
1661
|
+
const t = await getTable()
|
|
1662
|
+
if (!t) return []
|
|
1553
1663
|
const rows = await t.search(vector).limit(topK).toArray()
|
|
1554
1664
|
return rows.map((row) => ({
|
|
1555
1665
|
id: row.id,
|
|
@@ -1562,7 +1672,8 @@ export async function query(vector, topK) {
|
|
|
1562
1672
|
}
|
|
1563
1673
|
|
|
1564
1674
|
export async function list({ page = 1, limit = 20 } = {}) {
|
|
1565
|
-
const t = await
|
|
1675
|
+
const t = await getTable()
|
|
1676
|
+
if (!t) return { documents: [], total: 0, page, limit, totalPages: 0 }
|
|
1566
1677
|
// Fetch all rows to get total count, then slice for the page.
|
|
1567
1678
|
// We explicitly exclude the "vector" column to avoid memory bloat and Rust panics on full scans.
|
|
1568
1679
|
const allRows = await t.query().select(["id", "text", "title", "url", "documentId"]).toArray()
|
|
@@ -1585,7 +1696,8 @@ export async function list({ page = 1, limit = 20 } = {}) {
|
|
|
1585
1696
|
}
|
|
1586
1697
|
|
|
1587
1698
|
export async function get(id) {
|
|
1588
|
-
const t = await
|
|
1699
|
+
const t = await getTable()
|
|
1700
|
+
if (!t) return null
|
|
1589
1701
|
const rows = await t.query().filter(\`id = '\${id}'\`).limit(1).toArray()
|
|
1590
1702
|
if (!rows.length) return null;
|
|
1591
1703
|
const row = rows[0];
|
|
@@ -1593,24 +1705,44 @@ export async function get(id) {
|
|
|
1593
1705
|
}
|
|
1594
1706
|
|
|
1595
1707
|
export async function add(docs) {
|
|
1596
|
-
|
|
1597
|
-
await
|
|
1708
|
+
if (docs.length === 0) return { success: true }
|
|
1709
|
+
let t = await getTable()
|
|
1710
|
+
if (t) {
|
|
1711
|
+
await t.add(docs)
|
|
1712
|
+
} else {
|
|
1713
|
+
const conn = await getConn()
|
|
1714
|
+
const names = await conn.tableNames()
|
|
1715
|
+
if (names.includes(TABLE)) {
|
|
1716
|
+
t = await conn.openTable(TABLE)
|
|
1717
|
+
_table = t
|
|
1718
|
+
await t.add(docs)
|
|
1719
|
+
} else {
|
|
1720
|
+
t = await conn.createTable(TABLE, docs)
|
|
1721
|
+
_table = t
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1598
1724
|
return { success: true }
|
|
1599
1725
|
}
|
|
1600
1726
|
|
|
1601
1727
|
export async function remove(id) {
|
|
1602
|
-
const t = await
|
|
1728
|
+
const t = await getTable()
|
|
1729
|
+
if (!t) return { success: true }
|
|
1603
1730
|
await t.delete(\`id = '\${id}'\`)
|
|
1604
1731
|
return { success: true }
|
|
1605
1732
|
}
|
|
1606
1733
|
|
|
1607
1734
|
export async function update(id, doc) {
|
|
1608
|
-
|
|
1735
|
+
let t = await getTable()
|
|
1736
|
+
if (!t) {
|
|
1737
|
+
const conn = await getConn()
|
|
1738
|
+
t = await conn.createTable(TABLE, [doc])
|
|
1739
|
+
_table = t
|
|
1740
|
+
return { success: true }
|
|
1741
|
+
}
|
|
1609
1742
|
await t.delete(\`id = '\${id}'\`)
|
|
1610
1743
|
await t.add([doc])
|
|
1611
1744
|
return { success: true }
|
|
1612
|
-
}
|
|
1613
|
-
`;
|
|
1745
|
+
}`;
|
|
1614
1746
|
}
|
|
1615
1747
|
function pineconeStore() {
|
|
1616
1748
|
return `import { Pinecone } from "@pinecone-database/pinecone"
|
|
@@ -1972,9 +2104,10 @@ const server = createServer(async (req, res) => {
|
|
|
1972
2104
|
if (!doc.text) return send(res, 400, { error: "Missing text" })
|
|
1973
2105
|
const vector = await embedQuery(doc.text)
|
|
1974
2106
|
const id = doc.id || Math.random().toString(36).slice(2)
|
|
1975
|
-
await store.add([{ id, vector, text: doc.text, title: doc.title || "Untitled", url: doc.url, documentId: doc.documentId || id }])
|
|
2107
|
+
await store.add([{ id, vector, text: doc.text, title: doc.title || "Untitled", url: doc.url || "", documentId: doc.documentId || id }])
|
|
1976
2108
|
return send(res, 200, { success: true, id })
|
|
1977
2109
|
} catch (err) {
|
|
2110
|
+
console.error("[POST /documents] Error:", err)
|
|
1978
2111
|
return send(res, 500, { error: String(err?.message || err) })
|
|
1979
2112
|
}
|
|
1980
2113
|
}
|
|
@@ -2027,7 +2160,7 @@ const server = createServer(async (req, res) => {
|
|
|
2027
2160
|
for (const [idx, chunk] of chunks.entries()) {
|
|
2028
2161
|
const id = \`\${documentId}-\${idx}\`
|
|
2029
2162
|
const vector = await embedQuery(chunk)
|
|
2030
|
-
await store.add([{ id, vector, text: chunk, title: \`\${title} (part \${idx + 1})\`, url: targetUrl, documentId }])
|
|
2163
|
+
await store.add([{ id, vector, text: chunk, title: \`\${title} (part \${idx + 1})\`, url: targetUrl || "", documentId }])
|
|
2031
2164
|
}
|
|
2032
2165
|
|
|
2033
2166
|
return send(res, 200, { success: true, documentId, chunks: chunks.length })
|
|
@@ -5180,6 +5313,8 @@ program.command("chat").description("Chat with your knowledge base in the termin
|
|
|
5180
5313
|
program.command("settings").description("Configure CLI settings (e.g., chat models)").option("--server <id>", "Target a specific server instead of the active one").action(async (options) => {
|
|
5181
5314
|
await settingsCommand(options);
|
|
5182
5315
|
});
|
|
5183
|
-
|
|
5184
|
-
|
|
5316
|
+
checkUpdate().then(() => {
|
|
5317
|
+
program.parseAsync(process.argv).catch((err) => {
|
|
5318
|
+
log.error(err instanceof Error ? err.message : String(err));
|
|
5319
|
+
});
|
|
5185
5320
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@larkup/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.20",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
"cli-table3": "^0.6.5",
|
|
29
29
|
"commander": "^13.1.0",
|
|
30
30
|
"zod": "^4.4.3",
|
|
31
|
-
"@larkup/core": "0.1.
|
|
32
|
-
"@larkup/vector-stores": "0.1.
|
|
31
|
+
"@larkup/core": "0.1.20",
|
|
32
|
+
"@larkup/vector-stores": "0.1.20"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"tsup": "^8.0.0",
|