clanka 0.1.22 → 0.2.1
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 +1 -0
- package/dist/Agent.d.ts.map +1 -1
- package/dist/Agent.js +5 -1
- package/dist/Agent.js.map +1 -1
- package/dist/AgentTools.d.ts.map +1 -1
- package/dist/AgentTools.js +15 -6
- package/dist/AgentTools.js.map +1 -1
- package/dist/ChunkRepo.d.ts +1 -0
- package/dist/ChunkRepo.d.ts.map +1 -1
- package/dist/ChunkRepo.js +1 -0
- package/dist/ChunkRepo.js.map +1 -1
- package/dist/CodeChunker.d.ts +12 -0
- package/dist/CodeChunker.d.ts.map +1 -1
- package/dist/CodeChunker.js +26 -4
- package/dist/CodeChunker.js.map +1 -1
- package/dist/OutputFormatter.js +1 -1
- package/dist/OutputFormatter.js.map +1 -1
- package/dist/SemanticSearch.d.ts +9 -3
- package/dist/SemanticSearch.d.ts.map +1 -1
- package/dist/SemanticSearch.js +99 -36
- package/dist/SemanticSearch.js.map +1 -1
- package/package.json +1 -1
- package/src/Agent.ts +5 -1
- package/src/AgentTools.ts +17 -8
- package/src/ChunkRepo.ts +5 -0
- package/src/CodeChunker.ts +60 -16
- package/src/OutputFormatter.ts +1 -1
- package/src/SemanticSearch.ts +153 -58
package/dist/SemanticSearch.js
CHANGED
|
@@ -10,12 +10,18 @@ import { pipe } from "effect/Function";
|
|
|
10
10
|
import * as EmbeddingModel from "effect/unstable/ai/EmbeddingModel";
|
|
11
11
|
import * as RequestResolver from "effect/RequestResolver";
|
|
12
12
|
import * as Option from "effect/Option";
|
|
13
|
+
import * as Path from "effect/Path";
|
|
13
14
|
import * as ServiceMap from "effect/ServiceMap";
|
|
14
15
|
import * as Fiber from "effect/Fiber";
|
|
15
16
|
import * as Duration from "effect/Duration";
|
|
16
17
|
import * as FiberHandle from "effect/FiberHandle";
|
|
17
18
|
import { SqliteLayer } from "./Sqlite.js";
|
|
18
19
|
import * as Console from "effect/Console";
|
|
20
|
+
const normalizePath = (path) => path.replace(/\\/g, "/");
|
|
21
|
+
const chunkConfig = {
|
|
22
|
+
chunkSize: 20,
|
|
23
|
+
chunkOverlap: 5,
|
|
24
|
+
};
|
|
19
25
|
/**
|
|
20
26
|
* @since 1.0.0
|
|
21
27
|
* @category Services
|
|
@@ -30,48 +36,68 @@ export const layer = (options) => Layer.effect(SemanticSearch, Effect.gen(functi
|
|
|
30
36
|
const chunker = yield* CodeChunker.CodeChunker;
|
|
31
37
|
const repo = yield* ChunkRepo.ChunkRepo;
|
|
32
38
|
const embeddings = yield* EmbeddingModel.EmbeddingModel;
|
|
39
|
+
const pathService = yield* Path.Path;
|
|
40
|
+
const root = pathService.resolve(options.directory);
|
|
33
41
|
const resolver = embeddings.resolver.pipe(RequestResolver.setDelay(options.embeddingBatchSize ?? Duration.millis(50)), RequestResolver.batchN(options.embeddingBatchSize ?? 500));
|
|
42
|
+
const concurrency = options.concurrency ?? 2000;
|
|
34
43
|
const indexHandle = yield* FiberHandle.make();
|
|
35
44
|
const console = yield* Console.Console;
|
|
36
|
-
const
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
45
|
+
const resolveIndexedPath = (path) => {
|
|
46
|
+
const absolutePath = pathService.resolve(root, path);
|
|
47
|
+
const relativePath = normalizePath(pathService.relative(root, absolutePath));
|
|
48
|
+
if (relativePath.length === 0 ||
|
|
49
|
+
relativePath === ".." ||
|
|
50
|
+
relativePath.startsWith("../")) {
|
|
51
|
+
return Option.none();
|
|
52
|
+
}
|
|
53
|
+
return Option.some(relativePath);
|
|
54
|
+
};
|
|
55
|
+
const processChunk = Effect.fnUntraced(function* (options) {
|
|
56
|
+
if (options.checkExisting) {
|
|
44
57
|
const id = yield* repo.exists({
|
|
45
|
-
path: chunk.path,
|
|
46
|
-
startLine: chunk.startLine,
|
|
47
|
-
hash: chunk.contentHash,
|
|
58
|
+
path: options.chunk.path,
|
|
59
|
+
startLine: options.chunk.startLine,
|
|
60
|
+
hash: options.chunk.contentHash,
|
|
48
61
|
});
|
|
49
62
|
if (Option.isSome(id)) {
|
|
50
|
-
yield* repo.setSyncId(id.value, syncId);
|
|
63
|
+
yield* repo.setSyncId(id.value, options.syncId);
|
|
51
64
|
return;
|
|
52
65
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
66
|
+
}
|
|
67
|
+
const result = yield* Effect.request(new EmbeddingModel.EmbeddingRequest({
|
|
68
|
+
input: `File: ${options.chunk.path}
|
|
69
|
+
Lines: ${options.chunk.startLine}-${options.chunk.endLine}
|
|
56
70
|
|
|
57
|
-
${chunk.content}`,
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
${options.chunk.content}`,
|
|
72
|
+
}), resolver);
|
|
73
|
+
const vector = new Float32Array(result.vector);
|
|
74
|
+
yield* repo.insert(ChunkRepo.Chunk.insert.makeUnsafe({
|
|
75
|
+
path: options.chunk.path,
|
|
76
|
+
startLine: options.chunk.startLine,
|
|
77
|
+
endLine: options.chunk.endLine,
|
|
78
|
+
hash: options.chunk.contentHash,
|
|
79
|
+
content: options.chunk.content,
|
|
80
|
+
vector,
|
|
81
|
+
syncId: options.syncId,
|
|
82
|
+
}));
|
|
83
|
+
}, Effect.ignore({
|
|
84
|
+
log: "Warn",
|
|
85
|
+
message: "Failed to process chunk for embedding",
|
|
86
|
+
}), (effect, options) => Effect.annotateLogs(effect, {
|
|
87
|
+
chunk: `${options.chunk.path}/${options.chunk.startLine}`,
|
|
88
|
+
}));
|
|
89
|
+
const index = Effect.gen(function* () {
|
|
90
|
+
const syncId = ChunkRepo.SyncId.makeUnsafe(crypto.randomUUID());
|
|
91
|
+
yield* Effect.logInfo("Starting SemanticSearch index");
|
|
92
|
+
yield* pipe(chunker.chunkCodebase({
|
|
93
|
+
root,
|
|
94
|
+
...chunkConfig,
|
|
95
|
+
}), Stream.tap((chunk) => processChunk({
|
|
96
|
+
chunk,
|
|
97
|
+
syncId,
|
|
98
|
+
checkExisting: true,
|
|
99
|
+
}), { concurrency }), Stream.runDrain);
|
|
100
|
+
yield* repo.deleteForSyncId(syncId);
|
|
75
101
|
yield* Effect.logInfo("Finished SemanticSearch index");
|
|
76
102
|
}).pipe(Effect.withSpan("SemanticSearch.index"), Effect.withLogSpan("SemanticSearch.index"), Effect.provideService(Console.Console, console));
|
|
77
103
|
const runIndex = FiberHandle.run(indexHandle, index, {
|
|
@@ -90,7 +116,36 @@ ${chunk.content}`,
|
|
|
90
116
|
});
|
|
91
117
|
return results.map((r) => r.format()).join("\n\n");
|
|
92
118
|
}, Effect.orDie),
|
|
93
|
-
|
|
119
|
+
updateFile: Effect.fn("SemanticSearch.updateFile")(function* (path) {
|
|
120
|
+
yield* Fiber.join(initialIndex);
|
|
121
|
+
const indexedPath = resolveIndexedPath(path);
|
|
122
|
+
if (Option.isNone(indexedPath)) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
yield* repo.deleteByPath(indexedPath.value);
|
|
126
|
+
const chunks = yield* chunker.chunkFile({
|
|
127
|
+
root,
|
|
128
|
+
path: indexedPath.value,
|
|
129
|
+
...chunkConfig,
|
|
130
|
+
});
|
|
131
|
+
if (chunks.length === 0) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const syncId = ChunkRepo.SyncId.makeUnsafe(crypto.randomUUID());
|
|
135
|
+
yield* pipe(Stream.fromArray(chunks), Stream.tap((chunk) => processChunk({
|
|
136
|
+
chunk,
|
|
137
|
+
syncId,
|
|
138
|
+
checkExisting: false,
|
|
139
|
+
}), { concurrency }), Stream.runDrain);
|
|
140
|
+
}, Effect.orDie),
|
|
141
|
+
removeFile: Effect.fn("SemanticSearch.removeFile")(function* (path) {
|
|
142
|
+
yield* Fiber.join(initialIndex);
|
|
143
|
+
const indexedPath = resolveIndexedPath(path);
|
|
144
|
+
if (Option.isNone(indexedPath)) {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
yield* repo.deleteByPath(indexedPath.value);
|
|
148
|
+
}, Effect.orDie),
|
|
94
149
|
});
|
|
95
150
|
})).pipe(Layer.provide([
|
|
96
151
|
CodeChunker.layer,
|
|
@@ -100,8 +155,16 @@ ${chunk.content}`,
|
|
|
100
155
|
* @since 1.0.0
|
|
101
156
|
* @category Utils
|
|
102
157
|
*/
|
|
103
|
-
export const
|
|
158
|
+
export const maybeUpdateFile = (path) => Effect.serviceOption(SemanticSearch).pipe(Effect.flatMap(Option.match({
|
|
159
|
+
onNone: () => Effect.void,
|
|
160
|
+
onSome: (service) => service.updateFile(path),
|
|
161
|
+
})));
|
|
162
|
+
/**
|
|
163
|
+
* @since 1.0.0
|
|
164
|
+
* @category Utils
|
|
165
|
+
*/
|
|
166
|
+
export const maybeRemoveFile = (path) => Effect.serviceOption(SemanticSearch).pipe(Effect.flatMap(Option.match({
|
|
104
167
|
onNone: () => Effect.void,
|
|
105
|
-
onSome: (service) => service.
|
|
168
|
+
onSome: (service) => service.removeFile(path),
|
|
106
169
|
})));
|
|
107
170
|
//# sourceMappingURL=SemanticSearch.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SemanticSearch.js","sourceRoot":"","sources":["../src/SemanticSearch.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAA;AAC/C,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AACtC,OAAO,KAAK,cAAc,MAAM,mCAAmC,CAAA;AACnE,OAAO,KAAK,eAAe,MAAM,wBAAwB,CAAA;AACzD,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"SemanticSearch.js","sourceRoot":"","sources":["../src/SemanticSearch.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/Agent.ts
CHANGED
|
@@ -166,6 +166,7 @@ ${content}
|
|
|
166
166
|
let finalSummary = Option.none<string>()
|
|
167
167
|
|
|
168
168
|
const output = yield* Queue.make<Output, AgentFinished | AiError.AiError>()
|
|
169
|
+
let inputTokens = 0
|
|
169
170
|
let outputTokens = 0
|
|
170
171
|
const prompt = opts.disableHistory ? MutableRef.make(Prompt.empty) : history
|
|
171
172
|
|
|
@@ -376,10 +377,12 @@ ${content}
|
|
|
376
377
|
outputTokens += usage.outputTokens.total
|
|
377
378
|
}
|
|
378
379
|
if (usage.inputTokens.total !== undefined) {
|
|
380
|
+
inputTokens += usage.inputTokens.total
|
|
379
381
|
maybeSend({
|
|
380
382
|
agentId,
|
|
381
383
|
part: new Usage({
|
|
382
|
-
|
|
384
|
+
contextTokens: usage.inputTokens.total,
|
|
385
|
+
inputTokens,
|
|
383
386
|
outputTokens,
|
|
384
387
|
}),
|
|
385
388
|
})
|
|
@@ -704,6 +707,7 @@ export class ScriptEnd extends Schema.TaggedClass<ScriptEnd>()(
|
|
|
704
707
|
* @category Output
|
|
705
708
|
*/
|
|
706
709
|
export class Usage extends Schema.TaggedClass<Usage>()("Usage", {
|
|
710
|
+
contextTokens: Schema.Number,
|
|
707
711
|
inputTokens: Schema.Number,
|
|
708
712
|
outputTokens: Schema.Number,
|
|
709
713
|
}) {}
|
package/src/AgentTools.ts
CHANGED
|
@@ -212,7 +212,9 @@ const SearchTool = Toolkit.make(
|
|
|
212
212
|
Tool.make("search", {
|
|
213
213
|
description: "Semantic code search",
|
|
214
214
|
parameters: Schema.Struct({
|
|
215
|
-
query: Schema.String
|
|
215
|
+
query: Schema.String.annotate({
|
|
216
|
+
documentation: "Describe what you are looking for",
|
|
217
|
+
}),
|
|
216
218
|
limit: Schema.optional(Schema.Finite).annotate({
|
|
217
219
|
documentation: "Number of results (defaults to 5, max 10)",
|
|
218
220
|
}),
|
|
@@ -295,14 +297,18 @@ export const AgentToolHandlersNoDeps = AgentToolsWithSearch.toLayer(
|
|
|
295
297
|
recursive: true,
|
|
296
298
|
})
|
|
297
299
|
yield* fs.writeFileString(path, options.content)
|
|
298
|
-
yield* SemanticSearch.
|
|
300
|
+
yield* SemanticSearch.maybeUpdateFile(pathService.relative(cwd, path))
|
|
299
301
|
}, Effect.orDie),
|
|
300
302
|
removeFile: Effect.fn("AgentTools.removeFile")(function* (path) {
|
|
301
303
|
yield* Effect.logInfo(`Calling "removeFile"`).pipe(
|
|
302
304
|
Effect.annotateLogs({ path }),
|
|
303
305
|
)
|
|
304
306
|
const cwd = yield* CurrentDirectory
|
|
305
|
-
|
|
307
|
+
const absolutePath = pathService.resolve(cwd, path)
|
|
308
|
+
yield* fs.remove(absolutePath, { force: true })
|
|
309
|
+
yield* SemanticSearch.maybeRemoveFile(
|
|
310
|
+
pathService.relative(cwd, absolutePath),
|
|
311
|
+
)
|
|
306
312
|
}, Effect.orDie),
|
|
307
313
|
renameFile: Effect.fn("AgentTools.renameFile")(function* (options) {
|
|
308
314
|
yield* Effect.logInfo(`Calling "renameFile"`).pipe(
|
|
@@ -314,7 +320,9 @@ export const AgentToolHandlersNoDeps = AgentToolsWithSearch.toLayer(
|
|
|
314
320
|
yield* fs.makeDirectory(pathService.dirname(to), {
|
|
315
321
|
recursive: true,
|
|
316
322
|
})
|
|
317
|
-
|
|
323
|
+
yield* fs.rename(from, to)
|
|
324
|
+
yield* SemanticSearch.maybeRemoveFile(pathService.relative(cwd, from))
|
|
325
|
+
yield* SemanticSearch.maybeUpdateFile(pathService.relative(cwd, to))
|
|
318
326
|
}, Effect.orDie),
|
|
319
327
|
mkdir: Effect.fn("AgentTools.mkdir")(function* (path) {
|
|
320
328
|
yield* Effect.logInfo(`Calling "mkdir"`).pipe(
|
|
@@ -458,8 +466,7 @@ export const AgentToolHandlersNoDeps = AgentToolsWithSearch.toLayer(
|
|
|
458
466
|
}
|
|
459
467
|
>
|
|
460
468
|
const out = [] as Array<string>
|
|
461
|
-
const rel = (path: string) =>
|
|
462
|
-
pathService.relative(cwd, path).replaceAll("\\", "/")
|
|
469
|
+
const rel = (path: string) => pathService.relative(cwd, path)
|
|
463
470
|
const load = Effect.fn("AgentTools.applyPatch.load")(function* (
|
|
464
471
|
path: string,
|
|
465
472
|
reason: "delete" | "update",
|
|
@@ -545,6 +552,7 @@ export const AgentToolHandlersNoDeps = AgentToolsWithSearch.toLayer(
|
|
|
545
552
|
recursive: true,
|
|
546
553
|
})
|
|
547
554
|
yield* fs.writeFileString(step.path, step.next)
|
|
555
|
+
yield* SemanticSearch.maybeUpdateFile(rel(step.path))
|
|
548
556
|
break
|
|
549
557
|
}
|
|
550
558
|
case "move": {
|
|
@@ -553,17 +561,18 @@ export const AgentToolHandlersNoDeps = AgentToolsWithSearch.toLayer(
|
|
|
553
561
|
})
|
|
554
562
|
yield* fs.writeFileString(step.movePath, step.next)
|
|
555
563
|
yield* fs.remove(step.path)
|
|
564
|
+
yield* SemanticSearch.maybeRemoveFile(rel(step.path))
|
|
565
|
+
yield* SemanticSearch.maybeUpdateFile(rel(step.movePath))
|
|
556
566
|
break
|
|
557
567
|
}
|
|
558
568
|
case "delete": {
|
|
559
569
|
yield* fs.remove(step.path)
|
|
570
|
+
yield* SemanticSearch.maybeRemoveFile(rel(step.path))
|
|
560
571
|
break
|
|
561
572
|
}
|
|
562
573
|
}
|
|
563
574
|
}
|
|
564
575
|
|
|
565
|
-
yield* SemanticSearch.maybeReindex
|
|
566
|
-
|
|
567
576
|
return `Success. Updated the following files:\n${out.join("\n")}`
|
|
568
577
|
}, Effect.orDie),
|
|
569
578
|
delegate: Effect.fn("AgentTools.delegate")(function* (prompt) {
|
package/src/ChunkRepo.ts
CHANGED
|
@@ -126,6 +126,7 @@ export class ChunkRepo extends ServiceMap.Service<
|
|
|
126
126
|
chunkId: ChunkId,
|
|
127
127
|
syncId: SyncId,
|
|
128
128
|
): Effect.Effect<void, ChunkRepoError>
|
|
129
|
+
deleteByPath(path: string): Effect.Effect<void, ChunkRepoError>
|
|
129
130
|
deleteForSyncId(syncId: SyncId): Effect.Effect<void, ChunkRepoError>
|
|
130
131
|
}
|
|
131
132
|
>()("clanka/ChunkRepo") {}
|
|
@@ -223,6 +224,10 @@ export const layer = Layer.effect(
|
|
|
223
224
|
sql`update chunks set syncId = ${syncId} where id = ${chunkId}`.pipe(
|
|
224
225
|
Effect.mapError((reason) => new ChunkRepoError({ reason })),
|
|
225
226
|
),
|
|
227
|
+
deleteByPath: (path) =>
|
|
228
|
+
sql`delete from chunks where path = ${path}`.pipe(
|
|
229
|
+
Effect.mapError((reason) => new ChunkRepoError({ reason })),
|
|
230
|
+
),
|
|
226
231
|
deleteForSyncId: (syncId) =>
|
|
227
232
|
sql`delete from chunks where syncId != ${syncId}`.pipe(
|
|
228
233
|
Effect.mapError((reason) => new ChunkRepoError({ reason })),
|
package/src/CodeChunker.ts
CHANGED
|
@@ -36,6 +36,18 @@ export class CodeChunker extends ServiceMap.Service<
|
|
|
36
36
|
readonly root: string
|
|
37
37
|
readonly maxFileSize?: string | undefined
|
|
38
38
|
}): Effect.Effect<ReadonlyArray<string>>
|
|
39
|
+
chunkFile(options: {
|
|
40
|
+
readonly root: string
|
|
41
|
+
readonly path: string
|
|
42
|
+
readonly chunkSize: number
|
|
43
|
+
readonly chunkOverlap: number
|
|
44
|
+
}): Effect.Effect<ReadonlyArray<CodeChunk>>
|
|
45
|
+
chunkFiles(options: {
|
|
46
|
+
readonly root: string
|
|
47
|
+
readonly paths: ReadonlyArray<string>
|
|
48
|
+
readonly chunkSize: number
|
|
49
|
+
readonly chunkOverlap: number
|
|
50
|
+
}): Stream.Stream<CodeChunk>
|
|
39
51
|
chunkCodebase(options: {
|
|
40
52
|
readonly root: string
|
|
41
53
|
readonly maxFileSize?: string | undefined
|
|
@@ -346,6 +358,46 @@ export const layer: Layer.Layer<
|
|
|
346
358
|
)
|
|
347
359
|
})
|
|
348
360
|
|
|
361
|
+
const chunkFile: CodeChunker["Service"]["chunkFile"] = Effect.fn(
|
|
362
|
+
"CodeChunker.chunkFile",
|
|
363
|
+
)(function* (options): Effect.fn.Return<ReadonlyArray<CodeChunk>> {
|
|
364
|
+
const root = pathService.resolve(options.root)
|
|
365
|
+
const absolutePath = pathService.resolve(root, options.path)
|
|
366
|
+
const path = normalizePath(pathService.relative(root, absolutePath))
|
|
367
|
+
|
|
368
|
+
if (
|
|
369
|
+
path.length === 0 ||
|
|
370
|
+
path === ".." ||
|
|
371
|
+
path.startsWith("../") ||
|
|
372
|
+
!isMeaningfulFile(path)
|
|
373
|
+
) {
|
|
374
|
+
return []
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
return yield* pipe(
|
|
378
|
+
fs.readFileString(absolutePath),
|
|
379
|
+
Effect.map((content) => chunkFileContent(path, content, options)),
|
|
380
|
+
Effect.catch(() => Effect.succeed([])),
|
|
381
|
+
)
|
|
382
|
+
})
|
|
383
|
+
|
|
384
|
+
const chunkFiles: CodeChunker["Service"]["chunkFiles"] = (options) =>
|
|
385
|
+
Stream.fromArray(options.paths).pipe(
|
|
386
|
+
Stream.flatMap(
|
|
387
|
+
(path) =>
|
|
388
|
+
pipe(
|
|
389
|
+
chunkFile({
|
|
390
|
+
root: options.root,
|
|
391
|
+
path,
|
|
392
|
+
chunkSize: options.chunkSize,
|
|
393
|
+
chunkOverlap: options.chunkOverlap,
|
|
394
|
+
}),
|
|
395
|
+
Stream.fromArrayEffect,
|
|
396
|
+
),
|
|
397
|
+
{ concurrency: 5 },
|
|
398
|
+
),
|
|
399
|
+
)
|
|
400
|
+
|
|
349
401
|
const chunkCodebase: CodeChunker["Service"]["chunkCodebase"] =
|
|
350
402
|
Effect.fnUntraced(function* (options) {
|
|
351
403
|
const root = pathService.resolve(options.root)
|
|
@@ -356,26 +408,18 @@ export const layer: Layer.Layer<
|
|
|
356
408
|
: { maxFileSize: options.maxFileSize }),
|
|
357
409
|
})
|
|
358
410
|
|
|
359
|
-
return
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
Effect.map((content) =>
|
|
366
|
-
chunkFileContent(path, content, options),
|
|
367
|
-
),
|
|
368
|
-
Effect.catch(() => Effect.succeed([])),
|
|
369
|
-
Stream.fromArrayEffect,
|
|
370
|
-
)
|
|
371
|
-
},
|
|
372
|
-
{ concurrency: 5 },
|
|
373
|
-
),
|
|
374
|
-
)
|
|
411
|
+
return chunkFiles({
|
|
412
|
+
root,
|
|
413
|
+
paths: files,
|
|
414
|
+
chunkSize: options.chunkSize,
|
|
415
|
+
chunkOverlap: options.chunkOverlap,
|
|
416
|
+
})
|
|
375
417
|
}, Stream.unwrap)
|
|
376
418
|
|
|
377
419
|
return CodeChunker.of({
|
|
378
420
|
listFiles,
|
|
421
|
+
chunkFile,
|
|
422
|
+
chunkFiles,
|
|
379
423
|
chunkCodebase,
|
|
380
424
|
})
|
|
381
425
|
}),
|
package/src/OutputFormatter.ts
CHANGED
|
@@ -78,7 +78,7 @@ ${output.summary}\n\n`
|
|
|
78
78
|
return `${prefix}${chalk.red(`Error: ${output.error.reason._tag}. Retrying...`)}\n\n${chalk.dim(Cause.pretty(Cause.fail(output.error)))}\n\n`
|
|
79
79
|
}
|
|
80
80
|
case "Usage": {
|
|
81
|
-
return `${prefix}${chalkInfoHeading(`${infoIcon} Usage:`)} ${numberFormat.format(output.inputTokens)} input / ${numberFormat.format(output.outputTokens)} output\n\n`
|
|
81
|
+
return `${prefix}${chalkInfoHeading(`${infoIcon} Usage:`)} ${numberFormat.format(output.inputTokens)} context / ${numberFormat.format(output.inputTokens)} input / ${numberFormat.format(output.outputTokens)} output\n\n`
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
}),
|