clanka 0.2.69 → 0.2.71
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/Agent.d.ts +2 -2
- package/dist/Agent.d.ts.map +1 -1
- package/dist/Agent.js +4 -1
- package/dist/Agent.js.map +1 -1
- package/dist/Agent.test.js.map +1 -1
- package/dist/AgentExecutor.d.ts +136 -136
- package/dist/AgentExecutor.d.ts.map +1 -1
- package/dist/AgentExecutor.js.map +1 -1
- package/dist/AgentOutput.d.ts +1 -0
- package/dist/AgentOutput.d.ts.map +1 -1
- package/dist/AgentOutput.js +1 -0
- package/dist/AgentOutput.js.map +1 -1
- package/dist/AgentTools.d.ts +270 -270
- package/dist/AgentTools.d.ts.map +1 -1
- package/dist/AgentTools.js +1 -0
- package/dist/AgentTools.js.map +1 -1
- package/dist/ApplyPatch.d.ts.map +1 -1
- package/dist/ChunkRepo.d.ts +18 -17
- package/dist/ChunkRepo.d.ts.map +1 -1
- package/dist/ChunkRepo.js +37 -21
- package/dist/ChunkRepo.js.map +1 -1
- package/dist/ChunkRepo.test.d.ts +2 -0
- package/dist/ChunkRepo.test.d.ts.map +1 -0
- package/dist/ChunkRepo.test.js +63 -0
- package/dist/ChunkRepo.test.js.map +1 -0
- package/dist/CodeChunker.d.ts.map +1 -1
- package/dist/CodeChunker.js +1 -1
- package/dist/CodeChunker.js.map +1 -1
- package/dist/Codex.d.ts +1 -1
- package/dist/Codex.d.ts.map +1 -1
- package/dist/CodexAuth.d.ts +5 -4
- package/dist/CodexAuth.d.ts.map +1 -1
- package/dist/CodexAuth.js +5 -1
- package/dist/CodexAuth.js.map +1 -1
- package/dist/Copilot.d.ts +1 -1
- package/dist/Copilot.d.ts.map +1 -1
- package/dist/CopilotAuth.d.ts +5 -4
- package/dist/CopilotAuth.d.ts.map +1 -1
- package/dist/CopilotAuth.js +5 -1
- package/dist/CopilotAuth.js.map +1 -1
- package/dist/ExaSearch.d.ts.map +1 -1
- package/dist/ExaSearch.js +1 -0
- package/dist/ExaSearch.js.map +1 -1
- package/dist/OutputFormatter.d.ts.map +1 -1
- package/dist/OutputFormatter.js.map +1 -1
- package/dist/ScriptExtraction.d.ts.map +1 -1
- package/dist/ScriptPreprocessing.d.ts.map +1 -1
- package/dist/SemanticSearch/Service.d.ts.map +1 -1
- package/dist/SemanticSearch.d.ts.map +1 -1
- package/dist/Sqlite.d.ts +1 -1
- package/dist/Sqlite.d.ts.map +1 -1
- package/dist/Sqlite.js +2 -2
- package/dist/Sqlite.js.map +1 -1
- package/dist/ToolkitRenderer.js.map +1 -1
- package/dist/TypeBuilder.d.ts.map +1 -1
- package/dist/TypeBuilder.test.js +1 -0
- package/dist/TypeBuilder.test.js.map +1 -1
- package/package.json +21 -30
- package/src/Agent.ts +4 -4
- package/src/AgentOutput.ts +2 -5
- package/src/AgentTools.ts +1 -0
- package/src/ChunkRepo.test.ts +89 -0
- package/src/ChunkRepo.ts +38 -21
- package/src/CodeChunker.ts +3 -3
- package/src/CodexAuth.ts +5 -3
- package/src/CopilotAuth.ts +5 -3
- package/src/ExaSearch.ts +1 -0
- package/src/Sqlite.ts +2 -2
- package/src/TypeBuilder.test.ts +1 -0
- package/dist/internal/sqlite-vector.d.ts +0 -16
- package/dist/internal/sqlite-vector.d.ts.map +0 -1
- package/dist/internal/sqlite-vector.js +0 -181
- package/dist/internal/sqlite-vector.js.map +0 -1
- package/src/internal/sqlite-vector.ts +0 -214
package/src/AgentOutput.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @since 1.0.0
|
|
3
3
|
*/
|
|
4
|
+
/** @effect-diagnostics schemaNumber:off */
|
|
4
5
|
import * as Prompt from "effect/unstable/ai/Prompt"
|
|
5
6
|
import * as AiError from "effect/unstable/ai/AiError"
|
|
6
7
|
import * as Schema from "effect/Schema"
|
|
@@ -177,11 +178,7 @@ export class SubagentPart extends Schema.TaggedClass<SubagentPart>()(
|
|
|
177
178
|
* @category Output
|
|
178
179
|
*/
|
|
179
180
|
export type Output =
|
|
180
|
-
|
|
|
181
|
-
| ContentPart
|
|
182
|
-
| SubagentStart
|
|
183
|
-
| SubagentComplete
|
|
184
|
-
| SubagentPart
|
|
181
|
+
AgentStart | ContentPart | SubagentStart | SubagentComplete | SubagentPart
|
|
185
182
|
|
|
186
183
|
/**
|
|
187
184
|
* @since 1.0.0
|
package/src/AgentTools.ts
CHANGED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { mkdtemp, rm } from "node:fs/promises"
|
|
2
|
+
import { tmpdir } from "node:os"
|
|
3
|
+
import { join } from "node:path"
|
|
4
|
+
import * as NodeServices from "@effect/platform-node/NodeServices"
|
|
5
|
+
import { assert, describe, it } from "@effect/vitest"
|
|
6
|
+
import * as Effect from "effect/Effect"
|
|
7
|
+
import * as Layer from "effect/Layer"
|
|
8
|
+
import * as EmbeddingModel from "effect/unstable/ai/EmbeddingModel"
|
|
9
|
+
import * as SqlClient from "effect/unstable/sql/SqlClient"
|
|
10
|
+
import { Chunk, ChunkRepo, layer, SyncId } from "./ChunkRepo.ts"
|
|
11
|
+
import { SqliteLayer } from "./Sqlite.ts"
|
|
12
|
+
|
|
13
|
+
const withDatabase = Effect.acquireRelease(
|
|
14
|
+
Effect.promise(() => mkdtemp(join(tmpdir(), "clanka-"))),
|
|
15
|
+
(directory) => Effect.promise(() => rm(directory, { recursive: true })),
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
const sqliteLayer = (database: string) =>
|
|
19
|
+
SqliteLayer(database).pipe(Layer.provide(NodeServices.layer))
|
|
20
|
+
|
|
21
|
+
describe("ChunkRepo", () => {
|
|
22
|
+
it.live("backfills and synchronizes the vec0 index", () =>
|
|
23
|
+
Effect.gen(function* () {
|
|
24
|
+
const directory = yield* withDatabase
|
|
25
|
+
const database = join(directory, "search.sqlite")
|
|
26
|
+
const existingVector = new Float32Array([0, 1, 0])
|
|
27
|
+
|
|
28
|
+
yield* Effect.gen(function* () {
|
|
29
|
+
const sql = yield* SqlClient.SqlClient
|
|
30
|
+
yield* sql`INSERT INTO chunks(path, content, hash, vector, syncId)
|
|
31
|
+
VALUES ('existing.ts', 'existing', 'existing', ${existingVector}, 'sync')`
|
|
32
|
+
}).pipe(Effect.provide(sqliteLayer(database)), Effect.scoped)
|
|
33
|
+
|
|
34
|
+
const databaseLayer = sqliteLayer(database)
|
|
35
|
+
const repoLayer = Layer.merge(
|
|
36
|
+
layer.pipe(Layer.provide(databaseLayer)),
|
|
37
|
+
databaseLayer,
|
|
38
|
+
).pipe(Layer.provide(Layer.succeed(EmbeddingModel.Dimensions, 3)))
|
|
39
|
+
|
|
40
|
+
yield* Effect.gen(function* () {
|
|
41
|
+
const repo = yield* ChunkRepo
|
|
42
|
+
const sql = yield* SqlClient.SqlClient
|
|
43
|
+
|
|
44
|
+
const backfilled = yield* repo.search({
|
|
45
|
+
vector: existingVector,
|
|
46
|
+
limit: 1,
|
|
47
|
+
})
|
|
48
|
+
assert.strictEqual(backfilled[0]?.path, "existing.ts")
|
|
49
|
+
|
|
50
|
+
const inserted = yield* repo.insert(
|
|
51
|
+
Chunk.insert.make({
|
|
52
|
+
path: "inserted.ts",
|
|
53
|
+
content: "inserted",
|
|
54
|
+
hash: "inserted",
|
|
55
|
+
vector: new Float32Array([1, 0, 0]),
|
|
56
|
+
syncId: SyncId.make("sync"),
|
|
57
|
+
}),
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
const insertedResult = yield* repo.search({
|
|
61
|
+
vector: new Float32Array([1, 0, 0]),
|
|
62
|
+
limit: 1,
|
|
63
|
+
})
|
|
64
|
+
assert.strictEqual(insertedResult[0]?.id, inserted.id)
|
|
65
|
+
|
|
66
|
+
yield* sql`UPDATE chunks
|
|
67
|
+
SET vector = ${new Float32Array([0, 0, 1])}
|
|
68
|
+
WHERE id = ${inserted.id}`
|
|
69
|
+
|
|
70
|
+
const updatedResult = yield* repo.search({
|
|
71
|
+
vector: new Float32Array([0, 0, 1]),
|
|
72
|
+
limit: 1,
|
|
73
|
+
})
|
|
74
|
+
assert.strictEqual(updatedResult[0]?.id, inserted.id)
|
|
75
|
+
|
|
76
|
+
yield* repo.deleteByPath("inserted.ts")
|
|
77
|
+
|
|
78
|
+
const deletedResult = yield* repo.search({
|
|
79
|
+
vector: new Float32Array([0, 0, 1]),
|
|
80
|
+
limit: 2,
|
|
81
|
+
})
|
|
82
|
+
assert.deepStrictEqual(
|
|
83
|
+
deletedResult.map((chunk) => chunk.path),
|
|
84
|
+
["existing.ts"],
|
|
85
|
+
)
|
|
86
|
+
}).pipe(Effect.provide(repoLayer), Effect.scoped)
|
|
87
|
+
}),
|
|
88
|
+
)
|
|
89
|
+
})
|
package/src/ChunkRepo.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/** @effect-diagnostics schemaNumber:off */
|
|
1
2
|
import * as Effect from "effect/Effect"
|
|
2
3
|
import * as Layer from "effect/Layer"
|
|
3
4
|
import * as Schema from "effect/Schema"
|
|
@@ -139,23 +140,40 @@ export const layer = Layer.effect(
|
|
|
139
140
|
Effect.gen(function* () {
|
|
140
141
|
const sql = yield* SqlClient.SqlClient
|
|
141
142
|
const dimensions = yield* EmbeddingModel.Dimensions
|
|
143
|
+
|
|
144
|
+
yield* Effect.gen(function* () {
|
|
145
|
+
yield* sql`CREATE VIRTUAL TABLE IF NOT EXISTS chunk_vectors USING vec0(
|
|
146
|
+
vector float[${sql.literal(String(dimensions))}]
|
|
147
|
+
)`
|
|
148
|
+
yield* sql`CREATE TRIGGER IF NOT EXISTS chunks_vector_insert
|
|
149
|
+
AFTER INSERT ON chunks
|
|
150
|
+
BEGIN
|
|
151
|
+
INSERT INTO chunk_vectors(rowid, vector) VALUES (new.id, new.vector);
|
|
152
|
+
END`
|
|
153
|
+
yield* sql`CREATE TRIGGER IF NOT EXISTS chunks_vector_update
|
|
154
|
+
AFTER UPDATE OF vector ON chunks
|
|
155
|
+
BEGIN
|
|
156
|
+
DELETE FROM chunk_vectors WHERE rowid = old.id;
|
|
157
|
+
INSERT INTO chunk_vectors(rowid, vector) VALUES (new.id, new.vector);
|
|
158
|
+
END`
|
|
159
|
+
yield* sql`CREATE TRIGGER IF NOT EXISTS chunks_vector_delete
|
|
160
|
+
AFTER DELETE ON chunks
|
|
161
|
+
BEGIN
|
|
162
|
+
DELETE FROM chunk_vectors WHERE rowid = old.id;
|
|
163
|
+
END`
|
|
164
|
+
yield* sql`DELETE FROM chunk_vectors
|
|
165
|
+
WHERE rowid NOT IN (SELECT id FROM chunks)`
|
|
166
|
+
yield* sql`INSERT INTO chunk_vectors(rowid, vector)
|
|
167
|
+
SELECT id, vector FROM chunks
|
|
168
|
+
WHERE id NOT IN (SELECT rowid FROM chunk_vectors)`
|
|
169
|
+
}).pipe(sql.withTransaction)
|
|
170
|
+
|
|
142
171
|
const loaders = yield* SqlModel.makeResolvers(Chunk, {
|
|
143
172
|
tableName: "chunks",
|
|
144
173
|
idColumn: "id",
|
|
145
174
|
spanPrefix: "ChunkRepo",
|
|
146
175
|
})
|
|
147
176
|
|
|
148
|
-
let needsQuantization = true
|
|
149
|
-
|
|
150
|
-
const maybeQuantize = Effect.gen(function* () {
|
|
151
|
-
if (!needsQuantization) return
|
|
152
|
-
needsQuantization = false
|
|
153
|
-
yield* sql`select vector_init('chunks', 'vector', 'type=FLOAT32,dimension=${sql.literal(String(dimensions))}')`
|
|
154
|
-
yield* sql`select vector_quantize('chunks', 'vector')`
|
|
155
|
-
}).pipe(Effect.mapError((reason) => new ChunkRepoError({ reason })))
|
|
156
|
-
|
|
157
|
-
yield* Effect.forkScoped(maybeQuantize)
|
|
158
|
-
|
|
159
177
|
const search = SqlSchema.findAll({
|
|
160
178
|
Request: Schema.Struct({
|
|
161
179
|
vector: Float32ArraySchema,
|
|
@@ -165,9 +183,11 @@ export const layer = Layer.effect(
|
|
|
165
183
|
execute: ({ vector, limit }) =>
|
|
166
184
|
sql`
|
|
167
185
|
select chunks.id, chunks.path, chunks.content, chunks.hash, chunks.syncId
|
|
168
|
-
from
|
|
169
|
-
JOIN
|
|
170
|
-
|
|
186
|
+
from chunk_vectors
|
|
187
|
+
JOIN chunks ON chunks.id = chunk_vectors.rowid
|
|
188
|
+
WHERE chunk_vectors.vector MATCH ${vector}
|
|
189
|
+
AND k = CAST(${limit} AS INTEGER)
|
|
190
|
+
ORDER BY chunk_vectors.distance
|
|
171
191
|
`,
|
|
172
192
|
})
|
|
173
193
|
|
|
@@ -188,9 +208,8 @@ export const layer = Layer.effect(
|
|
|
188
208
|
const findByIdResolver = loaders.findById.pipe(RequestResolver.setDelay(5))
|
|
189
209
|
|
|
190
210
|
return ChunkRepo.of({
|
|
191
|
-
insert: (insert) =>
|
|
192
|
-
|
|
193
|
-
return SqlResolver.request(insert, insertResolver).pipe(
|
|
211
|
+
insert: (insert) =>
|
|
212
|
+
SqlResolver.request(insert, insertResolver).pipe(
|
|
194
213
|
Effect.catchTags(
|
|
195
214
|
{
|
|
196
215
|
SchemaError: Effect.die,
|
|
@@ -198,8 +217,7 @@ export const layer = Layer.effect(
|
|
|
198
217
|
},
|
|
199
218
|
(reason) => Effect.fail(new ChunkRepoError({ reason })),
|
|
200
219
|
),
|
|
201
|
-
)
|
|
202
|
-
},
|
|
220
|
+
),
|
|
203
221
|
findById: (id) =>
|
|
204
222
|
SqlResolver.request(id, findByIdResolver).pipe(
|
|
205
223
|
Effect.catchTags({
|
|
@@ -217,7 +235,6 @@ export const layer = Layer.effect(
|
|
|
217
235
|
}),
|
|
218
236
|
),
|
|
219
237
|
search: Effect.fn("ChunkRepo.search")(function* (options) {
|
|
220
|
-
yield* maybeQuantize
|
|
221
238
|
return yield* search(options as any).pipe(
|
|
222
239
|
Effect.catchTags({
|
|
223
240
|
SqlError: (reason) => Effect.fail(new ChunkRepoError({ reason })),
|
|
@@ -225,7 +242,7 @@ export const layer = Layer.effect(
|
|
|
225
242
|
}),
|
|
226
243
|
)
|
|
227
244
|
}),
|
|
228
|
-
quantize:
|
|
245
|
+
quantize: Effect.void,
|
|
229
246
|
setSyncId: (chunkId, syncId) =>
|
|
230
247
|
sql`update chunks set syncId = ${syncId} where id = ${chunkId}`.pipe(
|
|
231
248
|
Effect.mapError((reason) => new ChunkRepoError({ reason })),
|
package/src/CodeChunker.ts
CHANGED
|
@@ -414,7 +414,7 @@ const splitRange = (
|
|
|
414
414
|
}
|
|
415
415
|
const out = [] as Array<LineRange>
|
|
416
416
|
|
|
417
|
-
for (let startLine = range.startLine; startLine <= range.endLine;
|
|
417
|
+
for (let startLine = range.startLine; startLine <= range.endLine;) {
|
|
418
418
|
const maxEndLine = Math.min(
|
|
419
419
|
range.endLine,
|
|
420
420
|
startLine + settings.chunkSize - 1,
|
|
@@ -778,7 +778,7 @@ const chunkWithLineWindows = (
|
|
|
778
778
|
const out = [] as Array<CodeChunk>
|
|
779
779
|
const prefixSums = lineLengthPrefixSums(lines)
|
|
780
780
|
|
|
781
|
-
for (let index = 0; index < lines.length;
|
|
781
|
+
for (let index = 0; index < lines.length;) {
|
|
782
782
|
if (!isMeaningfulLine(lines[index]!)) {
|
|
783
783
|
index++
|
|
784
784
|
continue
|
|
@@ -935,7 +935,7 @@ export const layer: Layer.Layer<
|
|
|
935
935
|
return yield* pipe(
|
|
936
936
|
fs.readFileString(absolutePath),
|
|
937
937
|
Effect.map((content) => chunkFileContent(path, content, options)),
|
|
938
|
-
Effect.
|
|
938
|
+
Effect.orElseSucceed(() => []),
|
|
939
939
|
)
|
|
940
940
|
})
|
|
941
941
|
|
package/src/CodexAuth.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @since 1.0.0
|
|
3
3
|
*/
|
|
4
|
+
/** @effect-diagnostics schemaNumber:off */
|
|
4
5
|
import * as Effect from "effect/Effect"
|
|
5
6
|
import * as Encoding from "effect/Encoding"
|
|
6
7
|
import * as Function from "effect/Function"
|
|
@@ -303,9 +304,10 @@ export class CodexAuth extends Context.Service<
|
|
|
303
304
|
HttpClient.filterStatusOk,
|
|
304
305
|
HttpClient.retryTransient({
|
|
305
306
|
times: 5,
|
|
306
|
-
schedule: Schedule.
|
|
307
|
-
Schedule.
|
|
308
|
-
|
|
307
|
+
schedule: Schedule.min([
|
|
308
|
+
Schedule.exponential(150),
|
|
309
|
+
Schedule.spaced(5000),
|
|
310
|
+
]),
|
|
309
311
|
}),
|
|
310
312
|
)
|
|
311
313
|
const semaphore = Semaphore.makeUnsafe(1)
|
package/src/CopilotAuth.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @since 1.0.0
|
|
3
3
|
*/
|
|
4
|
+
/** @effect-diagnostics schemaNumber:off */
|
|
4
5
|
import * as Effect from "effect/Effect"
|
|
5
6
|
import * as Function from "effect/Function"
|
|
6
7
|
import * as Layer from "effect/Layer"
|
|
@@ -235,9 +236,10 @@ export class GithubCopilotAuth extends Context.Service<
|
|
|
235
236
|
HttpClient.filterStatusOk,
|
|
236
237
|
HttpClient.retryTransient({
|
|
237
238
|
times: 5,
|
|
238
|
-
schedule: Schedule.
|
|
239
|
-
Schedule.
|
|
240
|
-
|
|
239
|
+
schedule: Schedule.min([
|
|
240
|
+
Schedule.exponential(150),
|
|
241
|
+
Schedule.spaced(5000),
|
|
242
|
+
]),
|
|
241
243
|
}),
|
|
242
244
|
)
|
|
243
245
|
const semaphore = Semaphore.makeUnsafe(1)
|
package/src/ExaSearch.ts
CHANGED
|
@@ -27,6 +27,7 @@ export class ExaSearch extends Context.Service<
|
|
|
27
27
|
*/
|
|
28
28
|
export const ExaSearchOptions = Schema.Struct({
|
|
29
29
|
query: Schema.String,
|
|
30
|
+
// @effect-diagnostics-next-line schemaNumber:off
|
|
30
31
|
numResults: Schema.optional(Schema.Number).annotate({
|
|
31
32
|
documentation: "The number of search results to return. Defaults to 3.",
|
|
32
33
|
}),
|
package/src/Sqlite.ts
CHANGED
|
@@ -8,7 +8,7 @@ import * as Layer from "effect/Layer"
|
|
|
8
8
|
import * as SqlClient from "effect/unstable/sql/SqlClient"
|
|
9
9
|
import * as FileSystem from "effect/FileSystem"
|
|
10
10
|
import * as Path from "effect/Path"
|
|
11
|
-
import {
|
|
11
|
+
import { getLoadablePath } from "sqlite-vec"
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* @since 1.0.0
|
|
@@ -37,7 +37,7 @@ export const SqliteLayer = (database: string) =>
|
|
|
37
37
|
Layer.effectDiscard(
|
|
38
38
|
Effect.gen(function* () {
|
|
39
39
|
const client = yield* SqliteClient.SqliteClient
|
|
40
|
-
yield* client.loadExtension(
|
|
40
|
+
yield* client.loadExtension(getLoadablePath())
|
|
41
41
|
}),
|
|
42
42
|
),
|
|
43
43
|
),
|
package/src/TypeBuilder.test.ts
CHANGED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Gets the absolute path to the SQLite Vector extension binary for the current platform
|
|
3
|
-
*
|
|
4
|
-
* @returns Absolute path to the extension binary (.so, .dylib, or .dll)
|
|
5
|
-
* @throws {ExtensionNotFoundError} If the extension binary cannot be found
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* ```typescript
|
|
9
|
-
* import { getExtensionPath } from '@sqliteai/sqlite-vector';
|
|
10
|
-
*
|
|
11
|
-
* const extensionPath = getExtensionPath();
|
|
12
|
-
* // On macOS ARM64: /path/to/node_modules/@sqliteai/sqlite-vector-darwin-arm64/vector.dylib
|
|
13
|
-
* ```
|
|
14
|
-
*/
|
|
15
|
-
export declare function getExtensionPath(): string;
|
|
16
|
-
//# sourceMappingURL=sqlite-vector.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite-vector.d.ts","sourceRoot":"","sources":["../../src/internal/sqlite-vector.ts"],"names":[],"mappings":"AAmLA;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAoBzC"}
|
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
import { resolve } from "node:path";
|
|
2
|
-
import { platform, arch } from "node:os";
|
|
3
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
4
|
-
import { execSync } from "node:child_process";
|
|
5
|
-
/**
|
|
6
|
-
* Binary extension for each platform
|
|
7
|
-
*/
|
|
8
|
-
const PLATFORM_EXTENSIONS = {
|
|
9
|
-
darwin: ".dylib",
|
|
10
|
-
linux: ".so",
|
|
11
|
-
win32: ".dll",
|
|
12
|
-
};
|
|
13
|
-
/**
|
|
14
|
-
* Detects if the system uses musl libc (Alpine Linux, etc.)
|
|
15
|
-
* Uses multiple detection strategies for reliability
|
|
16
|
-
*/
|
|
17
|
-
function isMusl() {
|
|
18
|
-
// Only relevant for Linux
|
|
19
|
-
if (platform() !== "linux") {
|
|
20
|
-
return false;
|
|
21
|
-
}
|
|
22
|
-
// Strategy 1: Check for musl-specific files
|
|
23
|
-
const muslFiles = [
|
|
24
|
-
"/lib/ld-musl-x86_64.so.1",
|
|
25
|
-
"/lib/ld-musl-aarch64.so.1",
|
|
26
|
-
"/lib/ld-musl-armhf.so.1",
|
|
27
|
-
];
|
|
28
|
-
for (const file of muslFiles) {
|
|
29
|
-
if (existsSync(file)) {
|
|
30
|
-
return true;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
// Strategy 2: Check ldd version output
|
|
34
|
-
try {
|
|
35
|
-
const lddVersion = execSync("ldd --version 2>&1", {
|
|
36
|
-
encoding: "utf-8",
|
|
37
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
38
|
-
});
|
|
39
|
-
if (lddVersion.includes("musl")) {
|
|
40
|
-
return true;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
catch {
|
|
44
|
-
// ldd command failed, continue to next strategy
|
|
45
|
-
}
|
|
46
|
-
// Strategy 3: Check /etc/os-release for Alpine
|
|
47
|
-
try {
|
|
48
|
-
if (existsSync("/etc/os-release")) {
|
|
49
|
-
const osRelease = readFileSync("/etc/os-release", "utf-8");
|
|
50
|
-
if (osRelease.includes("Alpine") || osRelease.includes("musl")) {
|
|
51
|
-
return true;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
catch {
|
|
56
|
-
// File read failed, continue to next strategy
|
|
57
|
-
}
|
|
58
|
-
// Strategy 4: Check process.report.getReport() for musl
|
|
59
|
-
try {
|
|
60
|
-
const report = process.report?.getReport?.();
|
|
61
|
-
if (report?.header?.glibcVersionRuntime === "") {
|
|
62
|
-
// Empty glibc version often indicates musl
|
|
63
|
-
return true;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
catch {
|
|
67
|
-
// Report not available
|
|
68
|
-
}
|
|
69
|
-
return false;
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Gets the current platform identifier
|
|
73
|
-
* @throws {Error} If the platform is unsupported
|
|
74
|
-
*/
|
|
75
|
-
function getCurrentPlatform() {
|
|
76
|
-
const platformName = platform();
|
|
77
|
-
const archName = arch();
|
|
78
|
-
// macOS
|
|
79
|
-
if (platformName === "darwin") {
|
|
80
|
-
if (archName === "arm64")
|
|
81
|
-
return "darwin-arm64";
|
|
82
|
-
if (archName === "x64" || archName === "ia32")
|
|
83
|
-
return "darwin-x86_64";
|
|
84
|
-
}
|
|
85
|
-
// Linux (with musl detection)
|
|
86
|
-
if (platformName === "linux") {
|
|
87
|
-
const muslSuffix = isMusl() ? "-musl" : "";
|
|
88
|
-
if (archName === "arm64") {
|
|
89
|
-
return `linux-arm64${muslSuffix}`;
|
|
90
|
-
}
|
|
91
|
-
if (archName === "x64" || archName === "ia32") {
|
|
92
|
-
return `linux-x86_64${muslSuffix}`;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
// Windows
|
|
96
|
-
if (platformName === "win32") {
|
|
97
|
-
if (archName === "x64" || archName === "ia32")
|
|
98
|
-
return "win32-x86_64";
|
|
99
|
-
}
|
|
100
|
-
// Unsupported platform
|
|
101
|
-
throw new Error(`Unsupported platform: ${platformName}-${archName}. ` +
|
|
102
|
-
`Supported platforms: darwin-arm64, darwin-x86_64, linux-arm64, linux-x86_64, win32-x86_64 ` +
|
|
103
|
-
`(with glibc or musl support for Linux)`);
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* Gets the package name for the current platform
|
|
107
|
-
*/
|
|
108
|
-
function getPlatformPackageName() {
|
|
109
|
-
const currentPlatform = getCurrentPlatform();
|
|
110
|
-
return `@sqliteai/sqlite-vector-${currentPlatform}`;
|
|
111
|
-
}
|
|
112
|
-
/**
|
|
113
|
-
* Gets the binary filename for the current platform
|
|
114
|
-
*/
|
|
115
|
-
function getBinaryName() {
|
|
116
|
-
const platformName = platform();
|
|
117
|
-
const extension = PLATFORM_EXTENSIONS[platformName];
|
|
118
|
-
if (!extension) {
|
|
119
|
-
throw new Error(`Unknown platform: ${platformName}`);
|
|
120
|
-
}
|
|
121
|
-
return `vector${extension}`;
|
|
122
|
-
}
|
|
123
|
-
/**
|
|
124
|
-
* Error thrown when the SQLite Vector extension cannot be found
|
|
125
|
-
*/
|
|
126
|
-
class ExtensionNotFoundError extends Error {
|
|
127
|
-
constructor(message) {
|
|
128
|
-
super(message);
|
|
129
|
-
this.name = "ExtensionNotFoundError";
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
/**
|
|
133
|
-
* Attempts to load the platform-specific package
|
|
134
|
-
* @returns The path to the extension binary, or null if not found
|
|
135
|
-
*/
|
|
136
|
-
function tryLoadPlatformPackage() {
|
|
137
|
-
try {
|
|
138
|
-
const packageName = getPlatformPackageName();
|
|
139
|
-
const platformPackage = import.meta.resolve(packageName);
|
|
140
|
-
return platformPackage
|
|
141
|
-
.replace(/\/index\.js$/, `/${getBinaryName()}`)
|
|
142
|
-
.replace("file://", "");
|
|
143
|
-
}
|
|
144
|
-
catch {
|
|
145
|
-
// Platform package not installed or failed to load
|
|
146
|
-
// This is expected when optionalDependencies fail
|
|
147
|
-
}
|
|
148
|
-
return null;
|
|
149
|
-
}
|
|
150
|
-
/**
|
|
151
|
-
* Gets the absolute path to the SQLite Vector extension binary for the current platform
|
|
152
|
-
*
|
|
153
|
-
* @returns Absolute path to the extension binary (.so, .dylib, or .dll)
|
|
154
|
-
* @throws {ExtensionNotFoundError} If the extension binary cannot be found
|
|
155
|
-
*
|
|
156
|
-
* @example
|
|
157
|
-
* ```typescript
|
|
158
|
-
* import { getExtensionPath } from '@sqliteai/sqlite-vector';
|
|
159
|
-
*
|
|
160
|
-
* const extensionPath = getExtensionPath();
|
|
161
|
-
* // On macOS ARM64: /path/to/node_modules/@sqliteai/sqlite-vector-darwin-arm64/vector.dylib
|
|
162
|
-
* ```
|
|
163
|
-
*/
|
|
164
|
-
export function getExtensionPath() {
|
|
165
|
-
// Try to load from platform-specific package
|
|
166
|
-
const platformPath = tryLoadPlatformPackage();
|
|
167
|
-
if (platformPath) {
|
|
168
|
-
return resolve(platformPath);
|
|
169
|
-
}
|
|
170
|
-
// If we reach here, the platform package wasn't installed
|
|
171
|
-
const currentPlatform = getCurrentPlatform();
|
|
172
|
-
const packageName = getPlatformPackageName();
|
|
173
|
-
throw new ExtensionNotFoundError(`SQLite Vector extension not found for platform: ${currentPlatform}\n\n` +
|
|
174
|
-
`The platform-specific package "${packageName}" is not installed.\n` +
|
|
175
|
-
`This usually happens when:\n` +
|
|
176
|
-
` 1. Your platform is not supported\n` +
|
|
177
|
-
` 2. npm failed to install optional dependencies\n` +
|
|
178
|
-
` 3. You're installing with --no-optional flag\n\n` +
|
|
179
|
-
`Try running: npm install --force`);
|
|
180
|
-
}
|
|
181
|
-
//# sourceMappingURL=sqlite-vector.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite-vector.js","sourceRoot":"","sources":["../../src/internal/sqlite-vector.ts"],"names":[],"mappings":"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"}
|