karajan-code 4.4.0 → 4.4.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "karajan-code",
3
- "version": "4.4.0",
3
+ "version": "4.4.1",
4
4
  "description": "Local multi-agent coding orchestrator with TDD, SonarQube, and code review pipeline",
5
5
  "type": "module",
6
6
  "license": "AGPL-3.0",
@@ -6,12 +6,17 @@
6
6
  */
7
7
  import { installPlaybook } from "../environment/playbook.js";
8
8
  import { renderBrief, listBriefs } from "../environment/briefs.js";
9
- import { openVecStore, projectSlug, getLastIndexedCommit } from "../rag/vec-store.js";
9
+ import { existsSync } from "node:fs";
10
+ import { openVecStore, projectSlug, getLastIndexedCommit, dbPath } from "../rag/vec-store.js";
10
11
  import { ragIndexCommand } from "./rag.js";
11
12
  import { renderPendingBlock, PENDING_EXIT_CODE } from "../utils/pending-user-action.js";
12
- import { onnxConfig, persistOnnxChoice } from "../rag/onnx-fallback.js";
13
+ import { onnxConfig, persistOnnxChoice, resetEmptyStore } from "../rag/onnx-fallback.js";
13
14
 
14
15
  function hasRagIndex(config, projectDir) {
16
+ // KJC-BUG-0128: probing must never CREATE the store — openVecStore runs
17
+ // the DDL, and a table born at the default dim (768) breaks the ONNX
18
+ // fallback (384) later. No file → no index, without side effects.
19
+ if (!existsSync(dbPath())) return false;
15
20
  const db = openVecStore({ dim: config?.rag?.embedder?.dim || 768 });
16
21
  try { return Boolean(getLastIndexedCommit(db, projectSlug(projectDir))); }
17
22
  finally { db.close(); }
@@ -69,11 +74,19 @@ export async function envInstallCommand({ config = null, logger = null, flags =
69
74
  if (explicitProvider) return false;
70
75
  console.log(`⚠ default embedder unavailable (${why}) — trying the built-in ONNX embedder (no install needed)…`);
71
76
  try {
77
+ // KJC-BUG-0128: an empty store may carry a vec table at the wrong
78
+ // dim (the old probe created it at 768) — reset it so ONNX (384)
79
+ // can index. A store with data is never touched.
80
+ if (!resetEmptyStore()) {
81
+ console.log(" the vector store already has data at another dimension — not switching automatically");
82
+ return false;
83
+ }
72
84
  const totals = await ragIndexCommand({ config: onnxConfig(config), logger, flags: { withSources: true } });
73
85
  if ((totals?.indexed ?? 0) > 0) {
74
86
  const p = await persistOnnxChoice(projectDir);
75
87
  console.log(`✓ RAG indexed with the built-in ONNX embedder — persisted in ${p}`);
76
- console.log(" For higher-quality embeddings later: install Ollama and run `kj rag index --rebuild`.");
88
+ console.log(" To move to Ollama later: install it, remove the rag.embedder block from .karajan/kj.config.yml,");
89
+ console.log(" delete the store (~/.karajan/rag.db) and run: kj rag index --with-sources");
77
90
  return true;
78
91
  }
79
92
  } catch (fallbackErr) {
@@ -7,12 +7,39 @@
7
7
  * an index can never be written by one and queried by the other.
8
8
  */
9
9
  import fs from "node:fs/promises";
10
+ import { existsSync, rmSync } from "node:fs";
10
11
  import path from "node:path";
12
+ import Database from "better-sqlite3";
11
13
  import { parseDocument } from "yaml";
12
14
  import { getProjectConfigPath } from "../config/loader.js";
15
+ import { dbPath } from "./vec-store.js";
13
16
 
14
17
  const ONNX_EMBEDDER = { provider: "onnx", dim: 384 };
15
18
 
19
+ /**
20
+ * KJC-BUG-0128: the hasRagIndex probe could leave behind an EMPTY store
21
+ * whose vec table was created at the default dim (768) — ONNX inserts (384)
22
+ * then failed on every chunk. Before the fallback indexes, delete an empty
23
+ * store (plus WAL siblings) so it is recreated at the right dim. A store
24
+ * that already HAS chunks is never touched — switching dims there would
25
+ * destroy other projects' indexes.
26
+ */
27
+ export function resetEmptyStore() {
28
+ const storePath = dbPath();
29
+ if (!existsSync(storePath)) return true;
30
+ // Read-only, schema-agnostic inspection: no DDL, no vec extension, no
31
+ // dimension assumptions — the store is only ever OPENED to be counted.
32
+ const db = new Database(storePath, { readonly: true });
33
+ try {
34
+ const hasChunksTable = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='chunks'").get();
35
+ if (hasChunksTable && db.prepare("SELECT COUNT(*) AS n FROM chunks").get().n > 0) return false;
36
+ } finally {
37
+ db.close();
38
+ }
39
+ for (const suffix of ["", "-wal", "-shm"]) rmSync(storePath + suffix, { force: true });
40
+ return true;
41
+ }
42
+
16
43
  /** The same config, with the embedder swapped to the built-in ONNX. */
17
44
  export function onnxConfig(config) {
18
45
  return {