@javierkaiser/opencode-indexing 0.2.0 → 0.2.3
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/CHANGELOG.md +78 -1
- package/README.md +82 -24
- package/index.ts +56 -14
- package/install.mjs +295 -128
- package/install.ps1 +7 -1
- package/install.sh +1 -1
- package/package.json +6 -2
- package/src/import.ts +30 -9
- package/src/indexer.ts +11 -0
- package/src/rpc.ts +26 -1
- package/src/status.ts +14 -2
- package/src/tools.ts +65 -20
- package/tui/settings-page-data.ts +24 -7
- package/tui/settings-page.tsx +7 -1
- package/tui/workspace-rpc.ts +98 -0
- package/tui.ts +62 -32
package/CHANGELOG.md
CHANGED
|
@@ -5,7 +5,84 @@ All notable changes to this project are documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
-
## [
|
|
8
|
+
## [0.2.3] - 2026-10-16
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- `install.mjs` accepts `--with-codegraph`. It is **off by default** and only
|
|
12
|
+
has effect in `--package` mode, as consent comes from passing the flag. When
|
|
13
|
+
active it detects an existing `codegraph` CLI, installs it globally (`npm install
|
|
14
|
+
-g codegraph`) if it is missing, and registers its MCP with OpenCode via
|
|
15
|
+
`codegraph install --target opencode`. A failure in either step is reported and
|
|
16
|
+
does not cancel this plugin's own install.
|
|
17
|
+
- The README now names `npx` (not `opencode plugin add`) as the recommended
|
|
18
|
+
install method, and shows the companion install in the recommended command:
|
|
19
|
+
`npx @javierkaiser/opencode-indexing --with-codegraph`.
|
|
20
|
+
|
|
21
|
+
## [0.2.1] - 2026-10-15
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- **`opencode plugin add @javierkaiser/opencode-indexing` is now the documented
|
|
26
|
+
install.** It was already possible — the package was published and exported
|
|
27
|
+
`./tui` — but the README told people to run `npm install` and edit
|
|
28
|
+
`opencode.json` by hand, which puts the package in whatever directory they were
|
|
29
|
+
standing in and never tells OpenCode about it. The CLI command installs into
|
|
30
|
+
OpenCode's own cache, records the entry, and brings the update and removal path
|
|
31
|
+
(`plugin check`, `plugin update`, `plugin remove`) with it.
|
|
32
|
+
- **The installer has a package mode**, and picks between the two from where it
|
|
33
|
+
runs: a checkout installs the working tree, an installed copy installs the
|
|
34
|
+
published package. `npx @javierkaiser/opencode-indexing` therefore does the
|
|
35
|
+
right thing with no flags, including the permission rules and the restart that
|
|
36
|
+
`plugin add` alone does not do.
|
|
37
|
+
- `bin` in `package.json`, so `npx` has something to run.
|
|
38
|
+
- The plugin options and `ignoreKiloConfig` are documented in the README. The
|
|
39
|
+
option existed in the code and had tests, but appeared in no documentation.
|
|
40
|
+
|
|
41
|
+
### Fixed
|
|
42
|
+
|
|
43
|
+
- **"No Kilo index found" for a workspace that has one.** The server plugin is
|
|
44
|
+
instantiated for the directory the service runs in, so every RPC that omitted a
|
|
45
|
+
`directory` described *that* project. `kilo.discover` took no directory at all,
|
|
46
|
+
which is why opening the palette in one project and importing reported nothing
|
|
47
|
+
while the footer, using the same client and passing the directory, looked
|
|
48
|
+
correct. `kilo.discover` and `settings.test` now accept a directory, and the
|
|
49
|
+
palette, the settings page and the index actions all send the caller's. The
|
|
50
|
+
directory is injected once by `bindWorkspace` rather than passed at each call
|
|
51
|
+
site, so a new workspace-scoped RPC is correct by default instead of correct by
|
|
52
|
+
remembering.
|
|
53
|
+
- **The tools read and indexed the service's directory.** All seven were pinned to
|
|
54
|
+
the plugin instance's root, so `indexing_search` in a session answered from
|
|
55
|
+
another codebase — results from the wrong project read as plausible — and
|
|
56
|
+
`indexing_import` refused an index that was sitting right there. They now use
|
|
57
|
+
`context.directory`, with the instance root as the fallback for hosts that do
|
|
58
|
+
not report one.
|
|
59
|
+
- **`@lancedb/lancedb` could never load, so no Kilo index was ever importable
|
|
60
|
+
from LanceDB.** `apache-arrow` is that package's *peerDependency*, and the
|
|
61
|
+
installer runs `npm install --omit=peer`, which drops peers from the tree: the
|
|
62
|
+
native binary loaded and then threw `Cannot find module 'apache-arrow'` on first
|
|
63
|
+
use. It is now declared explicitly. This also broke `vectorStore: lancedb`
|
|
64
|
+
outright.
|
|
65
|
+
- **An unreadable index was reported as a missing one.** Discovery swallowed
|
|
66
|
+
backend failures, so "Kilo is not running here" and "Kilo is not installed here"
|
|
67
|
+
both surfaced as *No Kilo index found*. It now names the path it found and the
|
|
68
|
+
reason it could not be read, in `indexing_status`, `indexing_build`,
|
|
69
|
+
`indexing_config`, `settings test kilo`, the import tool and the empty-state
|
|
70
|
+
toast. `indexing_build` is the one that matters most: with nothing reported, a
|
|
71
|
+
build in a workspace whose Kilo index could not be read re-embedded everything
|
|
72
|
+
without saying why.
|
|
73
|
+
- **`apache-arrow` is declared in `package.json`, not only in the installer.**
|
|
74
|
+
It is a *peer* of `@lancedb/lancedb`, and the two install paths disagreed about
|
|
75
|
+
peers: `install.mjs` runs `npm install --omit=peer`, which drops them, while
|
|
76
|
+
the npm-based install OpenCode performs keeps them. Declaring it makes the
|
|
77
|
+
dependency true for both instead of true for whichever path happened to be
|
|
78
|
+
tested.
|
|
79
|
+
- The installer no longer keeps its own copy of the dependency list; it derives
|
|
80
|
+
the installed `package.json` from the published one. That duplication is how
|
|
81
|
+
`apache-arrow` came to be declared for one install path and missing from the
|
|
82
|
+
other.
|
|
83
|
+
- `--package` deletes a previously copied plugin. Both sources define
|
|
84
|
+
`id: "opencode.indexing"` and the config directory is scanned automatically, so
|
|
85
|
+
leaving both would load the plugin twice.
|
|
9
86
|
|
|
10
87
|
## [0.2.0] - 2026-10-14
|
|
11
88
|
|
package/README.md
CHANGED
|
@@ -26,44 +26,82 @@ index is still installed.
|
|
|
26
26
|
|
|
27
27
|
## Install
|
|
28
28
|
|
|
29
|
-
###
|
|
29
|
+
### With npx (recommended)
|
|
30
30
|
|
|
31
31
|
```bash
|
|
32
|
-
|
|
32
|
+
npx @javierkaiser/opencode-indexing
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
This is the whole install: the installer runs `opencode plugin add`, writes the
|
|
36
|
+
permission rules, restarts the service, and, when you ask for it, also installs
|
|
37
|
+
and registers the companion `codegraph`
|
|
38
|
+
MCP. It picks its strategy from where it runs — from an npx cache or an
|
|
39
|
+
unpacked tarball it installs the published package, from a checkout it
|
|
40
|
+
installs your working tree instead — so edits take effect on restart with no
|
|
41
|
+
publish in between. It prints which one it chose.
|
|
36
42
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
+
Add `--with-codegraph` to install and register codegraph as part of the same run
|
|
44
|
+
(the flag is opt-in and only has effect in the published-package mode):
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npx @javierkaiser/opencode-indexing --with-codegraph
|
|
43
48
|
```
|
|
44
49
|
|
|
45
|
-
|
|
50
|
+
| Flag | Effect |
|
|
51
|
+
| --- | --- |
|
|
52
|
+
| `--package [spec]` | Install the published package (default spec `@latest`) |
|
|
53
|
+
| `--local` | Copy this directory into the config dir (development) |
|
|
54
|
+
| `--skip-deps` | `--local` only: copy the files, install no dependencies |
|
|
55
|
+
| `--no-restart` | Do not restart the service |
|
|
56
|
+
| `--with-codegraph` | Install and register codegraph as a companion MCP (opt-in, `--package` only) |
|
|
46
57
|
|
|
47
|
-
|
|
58
|
+
### With the OpenCode CLI
|
|
48
59
|
|
|
49
60
|
```bash
|
|
50
|
-
|
|
51
|
-
|
|
61
|
+
opencode plugin add @javierkaiser/opencode-indexing
|
|
62
|
+
```
|
|
52
63
|
|
|
53
|
-
|
|
54
|
-
|
|
64
|
+
OpenCode downloads the package into its own cache and records it in the global
|
|
65
|
+
`plugins` array, and it loads both halves of the plugin: the server side
|
|
66
|
+
(`index.ts`, which registers the tools) and the terminal UI (`tui.ts`, which
|
|
67
|
+
adds the prompt-footer indicator and the `/indexing` page). It brings `plugin
|
|
68
|
+
check`, `plugin update` and `plugin remove` with it, but it cannot write
|
|
69
|
+
permission rules — add this one to `opencode.json` to keep the host asking
|
|
70
|
+
before the only tool that writes your settings file:
|
|
55
71
|
|
|
56
|
-
|
|
57
|
-
|
|
72
|
+
```jsonc
|
|
73
|
+
{
|
|
74
|
+
"permissions": [
|
|
75
|
+
{ "action": "indexing_config_set", "resource": "*", "effect": "ask" }
|
|
76
|
+
]
|
|
77
|
+
}
|
|
58
78
|
```
|
|
59
79
|
|
|
60
|
-
|
|
80
|
+
The other six tools only read. OpenCode's base policy already allows everything
|
|
81
|
+
(`{ "action": "*", "resource": "*", "effect": "allow" }`), so they need no rule;
|
|
82
|
+
write them out only if you want to tighten the set.
|
|
83
|
+
|
|
84
|
+
`install.sh` and `install.ps1` are thin wrappers over it; PowerShell also accepts
|
|
85
|
+
`-Local`, `-Package`, `-Spec`, `-SkipDeps` and `-NoRestart`.
|
|
61
86
|
|
|
62
|
-
|
|
87
|
+
`--package` deletes any copied plugin it finds: both sources define the same
|
|
88
|
+
plugin id and the config directory is scanned automatically, so leaving both
|
|
89
|
+
would load the plugin twice.
|
|
63
90
|
|
|
64
|
-
|
|
91
|
+
If no package manager is available, a `--local` install still copies the files
|
|
92
|
+
and the plugin runs with reduced features (line chunker instead of tree-sitter,
|
|
93
|
+
no LanceDB).
|
|
65
94
|
|
|
66
|
-
|
|
95
|
+
### Manual
|
|
96
|
+
|
|
97
|
+
To manage the directory yourself, point `opencode.json` at it. Relative paths
|
|
98
|
+
resolve from the config file containing the entry:
|
|
99
|
+
|
|
100
|
+
```jsonc
|
|
101
|
+
{
|
|
102
|
+
"plugins": ["./plugins/opencode-indexing"]
|
|
103
|
+
}
|
|
104
|
+
```
|
|
67
105
|
|
|
68
106
|
## How it works
|
|
69
107
|
|
|
@@ -302,16 +340,36 @@ Settings are stored in `~/.config/opencode/indexing.json` (plugin options → `i
|
|
|
302
340
|
```jsonc
|
|
303
341
|
{
|
|
304
342
|
"plugins": [
|
|
305
|
-
{ "package": "
|
|
343
|
+
{ "package": "@javierkaiser/opencode-indexing", "options": {
|
|
306
344
|
"vectorStore": "qdrant",
|
|
307
345
|
"qdrantUrl": "http://localhost:6333",
|
|
308
346
|
"importFromKilo": true,
|
|
309
|
-
"autoRefresh": false
|
|
347
|
+
"autoRefresh": false,
|
|
348
|
+
"ignoreKiloConfig": false
|
|
310
349
|
}}
|
|
311
350
|
]
|
|
312
351
|
}
|
|
313
352
|
```
|
|
314
353
|
|
|
354
|
+
| Option | Meaning |
|
|
355
|
+
| --- | --- |
|
|
356
|
+
| `vectorStore` | `qdrant` or `lancedb` for the **own** index. Does not affect where an import reads from. |
|
|
357
|
+
| `qdrantUrl` / `qdrantApiKey` | Qdrant connection |
|
|
358
|
+
| `provider` / `model` / `dimension` | Embedding profile, overriding the resolved one |
|
|
359
|
+
| `importFromKilo` | Import a compatible Kilo index on build instead of re-embedding |
|
|
360
|
+
| `autoRefresh` | Refresh inline on search when few files changed |
|
|
361
|
+
| `enabled` | Master switch: when false the own index is neither written nor refreshed |
|
|
362
|
+
| `ignoreKiloConfig` | Stop reading `~/.config/kilo/kilo.jsonc` entirely |
|
|
363
|
+
|
|
364
|
+
`~/.config/kilo/kilo.jsonc` is read as a fallback for the embedding provider,
|
|
365
|
+
model, dimensions **and API keys**, which is what makes a free import possible:
|
|
366
|
+
the same model has to be used to reuse Kilo's vectors. Set `ignoreKiloConfig` to
|
|
367
|
+
`true` to cut that off, or override any single value with the options above, an
|
|
368
|
+
environment variable, or `~/.config/opencode/indexing.json` — in that order of
|
|
369
|
+
precedence, with plugin options winning.
|
|
370
|
+
|
|
371
|
+
### Environment variables
|
|
372
|
+
|
|
315
373
|
| Variable | Meaning |
|
|
316
374
|
| --- | --- |
|
|
317
375
|
| `KILO_INDEX_VECTOR_STORE` | `lancedb` (default) or `qdrant` for the own index |
|
|
@@ -423,7 +481,7 @@ This plugin deliberately stays on the semantic side and coexists with grep/read
|
|
|
423
481
|
(see the tool descriptions and the bundled skill). A code-graph mode (tree-sitter
|
|
424
482
|
symbol/edge extraction into SQLite, exposed as `indexing_graph_*` tools that
|
|
425
483
|
chain after `indexing_search`) is a candidate for a future major version; the
|
|
426
|
-
tree-sitter infrastructure is already in place.
|
|
484
|
+
tree-sitter infrastructure is already in place. Independently, the installer can itself install and register codegraph as a companion MCP (`--with-codegraph`, opt-in, published-package mode only).
|
|
427
485
|
|
|
428
486
|
## Development
|
|
429
487
|
|
package/index.ts
CHANGED
|
@@ -217,6 +217,19 @@ const plugin = {
|
|
|
217
217
|
const directory = (input as { directory?: string } | undefined)?.directory
|
|
218
218
|
return typeof directory === "string" && directory.trim() !== "" ? directory : root
|
|
219
219
|
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Directory of the session a command was typed in.
|
|
223
|
+
*
|
|
224
|
+
* The plugin instance belongs to the directory the service runs in, which is
|
|
225
|
+
* usually a different one entirely, so a command issued from a session has to
|
|
226
|
+
* ask the host where that session is rather than assume its own.
|
|
227
|
+
*/
|
|
228
|
+
const sessionDirectory = async (sessionID: string): Promise<string | undefined> =>
|
|
229
|
+
ctx.session
|
|
230
|
+
.get({ sessionID } as never)
|
|
231
|
+
.then((info: { location?: { directory?: string } }) => info?.location?.directory)
|
|
232
|
+
.catch(() => undefined)
|
|
220
233
|
const options = (ctx.options ?? {}) as unknown as PluginOptionsInput
|
|
221
234
|
const kv: KVStore = createPluginStorage(ctx.storage as never)
|
|
222
235
|
const getSettings = (): Promise<IndexingSettings> => Promise.resolve(resolveSettings(options))
|
|
@@ -357,7 +370,7 @@ Behavior:
|
|
|
357
370
|
* Extracted so the `settings.test` RPC and the `/indexing-config test`
|
|
358
371
|
* subcommand answer identically instead of drifting apart.
|
|
359
372
|
*/
|
|
360
|
-
async function testTarget(target: string): Promise<{ ok: boolean; message: string }> {
|
|
373
|
+
async function testTarget(target: string, workspace: string): Promise<{ ok: boolean; message: string }> {
|
|
361
374
|
const settings = await getSettings()
|
|
362
375
|
try {
|
|
363
376
|
if (target === "qdrant") {
|
|
@@ -379,15 +392,23 @@ Behavior:
|
|
|
379
392
|
return { ok: true, message: `${settings.provider}/${settings.modelId} OK (${vector?.length ?? 0} dimensions)` }
|
|
380
393
|
}
|
|
381
394
|
if (target === "kilo") {
|
|
382
|
-
const
|
|
395
|
+
const problems: string[] = []
|
|
396
|
+
const sources = await discoverKiloSources(workspace, {
|
|
383
397
|
qdrant: createSettingsQdrant(settings),
|
|
384
398
|
homeDir: undefined,
|
|
385
399
|
targetProfile: profileFor(settings),
|
|
400
|
+
onProblem: (message) => problems.push(message),
|
|
386
401
|
})
|
|
387
402
|
const list = sources.map((s) => `${s.kind} ${s.name} (${s.pointsCount ?? "?"} pts, ${s.compatible ? "compatible" : "INCOMPATIBLE"})`)
|
|
403
|
+
// A readable source does not make an unreadable one irrelevant: a
|
|
404
|
+
// partial answer ("Qdrant works, LanceDB does not") is the one that
|
|
405
|
+
// explains why an import picked the source it did.
|
|
406
|
+
const found = sources.length > 0 ? list.join(" · ") : `No importable Kilo index for ${workspace}`
|
|
388
407
|
return {
|
|
389
408
|
ok: sources.length > 0,
|
|
390
|
-
|
|
409
|
+
// With nothing found, a reason beats a bare "not found": the two
|
|
410
|
+
// need completely different actions from the user.
|
|
411
|
+
message: problems.length > 0 ? `${found}. ${problems.join(" · ")}` : found,
|
|
391
412
|
}
|
|
392
413
|
}
|
|
393
414
|
return { ok: false, message: `Unknown test target: ${target}` }
|
|
@@ -412,11 +433,24 @@ Behavior:
|
|
|
412
433
|
const dimension = settings.dimension || (await store.info()).profile?.dimension || 0
|
|
413
434
|
if (!dimension) throw new Error("Embedding dimension unknown")
|
|
414
435
|
const targetProfile = { provider: settings.provider, modelId: settings.modelId, dimension }
|
|
415
|
-
const
|
|
436
|
+
const problems: string[] = []
|
|
437
|
+
const sources = await discoverKiloSources(workspace, {
|
|
438
|
+
qdrant: createSettingsQdrant(settings),
|
|
439
|
+
targetProfile,
|
|
440
|
+
onProblem: (message) => problems.push(message),
|
|
441
|
+
})
|
|
416
442
|
const source = wanted
|
|
417
443
|
? sources.find((item) => item.name === wanted)
|
|
418
444
|
: (sources.find((item) => item.compatible) ?? sources[0])
|
|
419
|
-
if (!source)
|
|
445
|
+
if (!source) {
|
|
446
|
+
// Naming the cause turns "nothing here" into something actionable when
|
|
447
|
+
// the index is present but unreadable.
|
|
448
|
+
throw new Error(
|
|
449
|
+
problems.length > 0
|
|
450
|
+
? `No Kilo source found for ${workspace}. ${problems.join(" · ")}`
|
|
451
|
+
: "No Kilo source found for this workspace",
|
|
452
|
+
)
|
|
453
|
+
}
|
|
420
454
|
if (!source.compatible) throw new Error(`Source ${source.name} has an incompatible embedding profile`)
|
|
421
455
|
await store.ensure(dimension, targetProfile)
|
|
422
456
|
const report = await importFromKilo({
|
|
@@ -548,6 +582,7 @@ class ForgetRefusedError extends Error {}
|
|
|
548
582
|
}
|
|
549
583
|
lines.push("")
|
|
550
584
|
}
|
|
585
|
+
const problems: string[] = []
|
|
551
586
|
const sources = await discoverKiloSources(root, {
|
|
552
587
|
qdrant: createSettingsQdrant(settings),
|
|
553
588
|
homeDir: undefined,
|
|
@@ -556,6 +591,7 @@ class ForgetRefusedError extends Error {}
|
|
|
556
591
|
// compare against, so the report claimed an import would work when it
|
|
557
592
|
// would be refused a moment later.
|
|
558
593
|
targetProfile: profileFor(settings),
|
|
594
|
+
onProblem: (message) => problems.push(message),
|
|
559
595
|
}).catch(() => [])
|
|
560
596
|
lines.push(
|
|
561
597
|
"",
|
|
@@ -563,6 +599,9 @@ class ForgetRefusedError extends Error {}
|
|
|
563
599
|
? `**Kilo sources detected:** ${sources.map((source) => `${source.kind} ${source.name} (${source.pointsCount ?? "?"} pts, ${source.compatible ? "compatible" : "INCOMPATIBLE"})`).join("; ")}`
|
|
564
600
|
: "**Kilo sources detected:** none for this workspace",
|
|
565
601
|
)
|
|
602
|
+
// "None" and "none I could read" are different answers, and only one of
|
|
603
|
+
// them is fixed by indexing from scratch.
|
|
604
|
+
if (problems.length > 0) lines.push("", `**Kilo sources unreadable:** ${problems.join(" · ")}`)
|
|
566
605
|
lines.push(
|
|
567
606
|
"",
|
|
568
607
|
"To change settings:",
|
|
@@ -622,11 +661,15 @@ class ForgetRefusedError extends Error {}
|
|
|
622
661
|
return
|
|
623
662
|
}
|
|
624
663
|
case "test": {
|
|
664
|
+
// Like `import` below, this has to name the session's directory:
|
|
665
|
+
// `test kilo` asks whether an index exists *for a workspace*, and
|
|
666
|
+
// answering about the service's own directory is always wrong.
|
|
625
667
|
const targets =
|
|
626
668
|
parsed.target === "all" ? ["qdrant", "lancedb", "provider", "kilo"] : [parsed.target]
|
|
669
|
+
const workspace = (await sessionDirectory(sessionID)) ?? root
|
|
627
670
|
const results: string[] = []
|
|
628
671
|
for (const target of targets) {
|
|
629
|
-
const result = await testTarget(target)
|
|
672
|
+
const result = await testTarget(target, workspace)
|
|
630
673
|
results.push(`${target}: ${result.ok ? "OK" : "FAIL"} — ${result.message}`)
|
|
631
674
|
}
|
|
632
675
|
await reply(results.join("\n"))
|
|
@@ -636,11 +679,7 @@ class ForgetRefusedError extends Error {}
|
|
|
636
679
|
// The session knows which workspace the user is in; the plugin
|
|
637
680
|
// instance directory is the one the service runs in, which is
|
|
638
681
|
// usually a different directory entirely.
|
|
639
|
-
|
|
640
|
-
.get({ sessionID } as never)
|
|
641
|
-
.then((info: { location?: { directory?: string } }) => info?.location?.directory)
|
|
642
|
-
.catch(() => undefined)
|
|
643
|
-
await reply(await runImport(sessionDirectory, parsed.source))
|
|
682
|
+
await reply(await runImport(await sessionDirectory(sessionID), parsed.source))
|
|
644
683
|
return
|
|
645
684
|
}
|
|
646
685
|
}
|
|
@@ -678,17 +717,19 @@ class ForgetRefusedError extends Error {}
|
|
|
678
717
|
},
|
|
679
718
|
|
|
680
719
|
"settings.test": async (input: unknown) => {
|
|
681
|
-
return testTarget((input as { target: string }).target)
|
|
720
|
+
return testTarget((input as { target: string }).target, rootFor(input))
|
|
682
721
|
},
|
|
683
722
|
|
|
684
|
-
"kilo.discover": async () => {
|
|
723
|
+
"kilo.discover": async (input: unknown) => {
|
|
685
724
|
const settings = await getSettings()
|
|
686
725
|
const targetProfile =
|
|
687
726
|
settings.dimension > 0 ? { provider: settings.provider, modelId: settings.modelId, dimension: settings.dimension } : undefined
|
|
688
|
-
const
|
|
727
|
+
const problems: string[] = []
|
|
728
|
+
const sources = await discoverKiloSources(rootFor(input), {
|
|
689
729
|
qdrant: createSettingsQdrant(settings),
|
|
690
730
|
homeDir: undefined,
|
|
691
731
|
targetProfile,
|
|
732
|
+
onProblem: (message) => problems.push(message),
|
|
692
733
|
})
|
|
693
734
|
return {
|
|
694
735
|
sources: sources.map((source) => ({
|
|
@@ -701,6 +742,7 @@ class ForgetRefusedError extends Error {}
|
|
|
701
742
|
: null,
|
|
702
743
|
compatible: source.compatible,
|
|
703
744
|
})),
|
|
745
|
+
problems,
|
|
704
746
|
}
|
|
705
747
|
},
|
|
706
748
|
|