claude-code-workflow 6.2.6 → 6.2.9

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.
Files changed (25) hide show
  1. package/ccw/dist/cli.d.ts.map +1 -1
  2. package/ccw/dist/cli.js +18 -7
  3. package/ccw/dist/cli.js.map +1 -1
  4. package/ccw/dist/core/routes/system-routes.js +1 -1
  5. package/ccw/dist/core/routes/system-routes.js.map +1 -1
  6. package/ccw/src/cli.ts +256 -244
  7. package/ccw/src/core/routes/system-routes.ts +1 -1
  8. package/ccw/src/templates/dashboard-js/components/cli-status.js +35 -2
  9. package/ccw/src/templates/dashboard-js/views/cli-manager.js +45 -6
  10. package/codex-lens/src/codexlens/cli/__pycache__/commands.cpython-313.pyc +0 -0
  11. package/codex-lens/src/codexlens/cli/__pycache__/embedding_manager.cpython-313.pyc +0 -0
  12. package/codex-lens/src/codexlens/cli/__pycache__/model_manager.cpython-313.pyc +0 -0
  13. package/codex-lens/src/codexlens/cli/commands.py +41 -15
  14. package/codex-lens/src/codexlens/cli/embedding_manager.py +15 -0
  15. package/codex-lens/src/codexlens/cli/model_manager.py +337 -311
  16. package/codex-lens/src/codexlens/search/__pycache__/chain_search.cpython-313.pyc +0 -0
  17. package/codex-lens/src/codexlens/search/__pycache__/hybrid_search.cpython-313.pyc +0 -0
  18. package/codex-lens/src/codexlens/search/chain_search.py +14 -1
  19. package/codex-lens/src/codexlens/search/hybrid_search.py +25 -12
  20. package/codex-lens/src/codexlens/semantic/__pycache__/vector_store.cpython-313.pyc +0 -0
  21. package/codex-lens/src/codexlens/semantic/vector_store.py +97 -0
  22. package/codex-lens/src/codexlens/storage/__pycache__/path_mapper.cpython-313.pyc +0 -0
  23. package/codex-lens/src/codexlens/storage/path_mapper.py +27 -1
  24. package/package.json +13 -5
  25. package/ccw/package.json +0 -65
@@ -396,7 +396,20 @@ class ChainSearchEngine:
396
396
  all_results = []
397
397
  stats = SearchStats()
398
398
 
399
- executor = self._get_executor(options.max_workers)
399
+ # Force single-threaded execution for vector/hybrid search to avoid GPU crashes
400
+ # DirectML/ONNX have threading issues when multiple threads access GPU resources
401
+ effective_workers = options.max_workers
402
+ if options.enable_vector or options.hybrid_mode:
403
+ effective_workers = 1
404
+ self.logger.debug("Using single-threaded mode for vector search (GPU safety)")
405
+ # Pre-load embedder to avoid initialization overhead per-search
406
+ try:
407
+ from codexlens.semantic.embedder import get_embedder
408
+ get_embedder(profile="code", use_gpu=True)
409
+ except Exception:
410
+ pass # Ignore pre-load failures
411
+
412
+ executor = self._get_executor(effective_workers)
400
413
  # Submit all search tasks
401
414
  future_to_path = {
402
415
  executor.submit(
@@ -274,19 +274,32 @@ class HybridSearchEngine:
274
274
  )
275
275
  return []
276
276
 
277
- # Auto-detect embedding dimension and select appropriate profile
278
- detected_dim = vector_store.dimension
279
- if detected_dim is None:
280
- self.logger.info("Vector store dimension unknown, using default profile")
281
- profile = "code" # Default fallback
282
- elif detected_dim == 384:
283
- profile = "fast"
284
- elif detected_dim == 768:
285
- profile = "code"
286
- elif detected_dim == 1024:
287
- profile = "multilingual" # or balanced, both are 1024
277
+ # Get stored model configuration (preferred) or auto-detect from dimension
278
+ model_config = vector_store.get_model_config()
279
+ if model_config:
280
+ profile = model_config["model_profile"]
281
+ self.logger.debug(
282
+ "Using stored model config: %s (%s, %dd)",
283
+ profile, model_config["model_name"], model_config["embedding_dim"]
284
+ )
288
285
  else:
289
- profile = "code" # Default fallback
286
+ # Fallback: auto-detect from embedding dimension
287
+ detected_dim = vector_store.dimension
288
+ if detected_dim is None:
289
+ self.logger.info("Vector store dimension unknown, using default profile")
290
+ profile = "code" # Default fallback
291
+ elif detected_dim == 384:
292
+ profile = "fast"
293
+ elif detected_dim == 768:
294
+ profile = "code"
295
+ elif detected_dim == 1024:
296
+ profile = "multilingual" # or balanced, both are 1024
297
+ else:
298
+ profile = "code" # Default fallback
299
+ self.logger.debug(
300
+ "No stored model config, auto-detected profile '%s' from dimension %s",
301
+ profile, detected_dim
302
+ )
290
303
 
291
304
  # Use cached embedder (singleton) for performance
292
305
  embedder = get_embedder(profile=profile)
@@ -116,6 +116,17 @@ class VectorStore:
116
116
  CREATE INDEX IF NOT EXISTS idx_chunks_file
117
117
  ON semantic_chunks(file_path)
118
118
  """)
119
+ # Model configuration table - tracks which model generated the embeddings
120
+ conn.execute("""
121
+ CREATE TABLE IF NOT EXISTS embeddings_config (
122
+ id INTEGER PRIMARY KEY CHECK (id = 1),
123
+ model_profile TEXT NOT NULL,
124
+ model_name TEXT NOT NULL,
125
+ embedding_dim INTEGER NOT NULL,
126
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
127
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
128
+ )
129
+ """)
119
130
  conn.commit()
120
131
 
121
132
  def _init_ann_index(self) -> None:
@@ -932,6 +943,92 @@ class VectorStore:
932
943
  return self._ann_index.count()
933
944
  return 0
934
945
 
946
+ def get_model_config(self) -> Optional[Dict[str, Any]]:
947
+ """Get the model configuration used for embeddings in this store.
948
+
949
+ Returns:
950
+ Dictionary with model_profile, model_name, embedding_dim, or None if not set.
951
+ """
952
+ with sqlite3.connect(self.db_path) as conn:
953
+ row = conn.execute(
954
+ "SELECT model_profile, model_name, embedding_dim, created_at, updated_at "
955
+ "FROM embeddings_config WHERE id = 1"
956
+ ).fetchone()
957
+ if row:
958
+ return {
959
+ "model_profile": row[0],
960
+ "model_name": row[1],
961
+ "embedding_dim": row[2],
962
+ "created_at": row[3],
963
+ "updated_at": row[4],
964
+ }
965
+ return None
966
+
967
+ def set_model_config(
968
+ self, model_profile: str, model_name: str, embedding_dim: int
969
+ ) -> None:
970
+ """Set the model configuration for embeddings in this store.
971
+
972
+ This should be called when generating new embeddings. If a different
973
+ model was previously used, this will update the configuration.
974
+
975
+ Args:
976
+ model_profile: Model profile name (fast, code, minilm, etc.)
977
+ model_name: Full model name (e.g., jinaai/jina-embeddings-v2-base-code)
978
+ embedding_dim: Embedding dimension (e.g., 768)
979
+ """
980
+ with sqlite3.connect(self.db_path) as conn:
981
+ conn.execute(
982
+ """
983
+ INSERT INTO embeddings_config (id, model_profile, model_name, embedding_dim)
984
+ VALUES (1, ?, ?, ?)
985
+ ON CONFLICT(id) DO UPDATE SET
986
+ model_profile = excluded.model_profile,
987
+ model_name = excluded.model_name,
988
+ embedding_dim = excluded.embedding_dim,
989
+ updated_at = CURRENT_TIMESTAMP
990
+ """,
991
+ (model_profile, model_name, embedding_dim)
992
+ )
993
+ conn.commit()
994
+
995
+ def check_model_compatibility(
996
+ self, model_profile: str, model_name: str, embedding_dim: int
997
+ ) -> Tuple[bool, Optional[str]]:
998
+ """Check if the given model is compatible with existing embeddings.
999
+
1000
+ Args:
1001
+ model_profile: Model profile to check
1002
+ model_name: Model name to check
1003
+ embedding_dim: Embedding dimension to check
1004
+
1005
+ Returns:
1006
+ Tuple of (is_compatible, warning_message).
1007
+ is_compatible is True if no existing config or configs match.
1008
+ warning_message is a user-friendly message if incompatible.
1009
+ """
1010
+ existing = self.get_model_config()
1011
+ if existing is None:
1012
+ return True, None
1013
+
1014
+ # Check dimension first (most critical)
1015
+ if existing["embedding_dim"] != embedding_dim:
1016
+ return False, (
1017
+ f"Dimension mismatch: existing embeddings use {existing['embedding_dim']}d "
1018
+ f"({existing['model_profile']}), but requested model uses {embedding_dim}d "
1019
+ f"({model_profile}). Use --force to regenerate all embeddings."
1020
+ )
1021
+
1022
+ # Check model (different models with same dimension may have different semantic spaces)
1023
+ if existing["model_profile"] != model_profile:
1024
+ return False, (
1025
+ f"Model mismatch: existing embeddings use '{existing['model_profile']}' "
1026
+ f"({existing['model_name']}), but requested '{model_profile}' "
1027
+ f"({model_name}). Use --force to regenerate all embeddings."
1028
+ )
1029
+
1030
+ return True, None
1031
+
935
1032
  def close(self) -> None:
936
1033
  """Close the vector store and release resources.
937
1034
 
@@ -14,11 +14,37 @@ Storage Structure:
14
14
  └── _index.db # src/ directory index
15
15
  """
16
16
 
17
+ import json
18
+ import os
17
19
  import platform
18
20
  from pathlib import Path
19
21
  from typing import Optional
20
22
 
21
23
 
24
+ def _get_configured_index_root() -> Path:
25
+ """Get the index root from environment or config file.
26
+
27
+ Priority order:
28
+ 1. CODEXLENS_INDEX_DIR environment variable
29
+ 2. index_dir from ~/.codexlens/config.json
30
+ 3. Default: ~/.codexlens/indexes
31
+ """
32
+ env_override = os.getenv("CODEXLENS_INDEX_DIR")
33
+ if env_override:
34
+ return Path(env_override).expanduser().resolve()
35
+
36
+ config_file = Path.home() / ".codexlens" / "config.json"
37
+ if config_file.exists():
38
+ try:
39
+ cfg = json.loads(config_file.read_text(encoding="utf-8"))
40
+ if "index_dir" in cfg:
41
+ return Path(cfg["index_dir"]).expanduser().resolve()
42
+ except (json.JSONDecodeError, OSError):
43
+ pass
44
+
45
+ return Path.home() / ".codexlens" / "indexes"
46
+
47
+
22
48
  class PathMapper:
23
49
  """Bidirectional mapping tool for source paths ↔ index paths.
24
50
 
@@ -31,7 +57,7 @@ class PathMapper:
31
57
  index_root: Configured index root directory
32
58
  """
33
59
 
34
- DEFAULT_INDEX_ROOT = Path.home() / ".codexlens" / "indexes"
60
+ DEFAULT_INDEX_ROOT = _get_configured_index_root()
35
61
  INDEX_DB_NAME = "_index.db"
36
62
 
37
63
  def __init__(self, index_root: Optional[Path] = None):
package/package.json CHANGED
@@ -1,16 +1,18 @@
1
1
  {
2
2
  "name": "claude-code-workflow",
3
- "version": "6.2.6",
3
+ "version": "6.2.9",
4
4
  "description": "JSON-driven multi-agent development framework with intelligent CLI orchestration (Gemini/Qwen/Codex), context-first architecture, and automated workflow execution",
5
5
  "type": "module",
6
6
  "main": "ccw/src/index.js",
7
7
  "bin": {
8
- "ccw": "./ccw/bin/ccw.js"
8
+ "ccw": "./ccw/bin/ccw.js",
9
+ "ccw-mcp": "./ccw/bin/ccw-mcp.js"
9
10
  },
10
11
  "scripts": {
12
+ "build": "tsc -p ccw/tsconfig.json",
11
13
  "start": "node ccw/bin/ccw.js",
12
14
  "test": "node --test",
13
- "prepublishOnly": "echo 'Ready to publish @dyw/claude-code-workflow'"
15
+ "prepublishOnly": "npm run build && echo 'Ready to publish @dyw/claude-code-workflow'"
14
16
  },
15
17
  "keywords": [
16
18
  "claude",
@@ -45,7 +47,6 @@
45
47
  "ccw/bin/",
46
48
  "ccw/dist/",
47
49
  "ccw/src/",
48
- "ccw/package.json",
49
50
  ".claude/agents/",
50
51
  ".claude/commands/",
51
52
  ".claude/output-styles/",
@@ -69,5 +70,12 @@
69
70
  "bugs": {
70
71
  "url": "https://github.com/catlog22/Claude-Code-Workflow/issues"
71
72
  },
72
- "homepage": "https://github.com/catlog22/Claude-Code-Workflow#readme"
73
+ "homepage": "https://github.com/catlog22/Claude-Code-Workflow#readme",
74
+ "devDependencies": {
75
+ "@types/better-sqlite3": "^7.6.12",
76
+ "@types/gradient-string": "^1.1.6",
77
+ "@types/inquirer": "^9.0.9",
78
+ "@types/node": "^25.0.1",
79
+ "typescript": "^5.9.3"
80
+ }
73
81
  }
package/ccw/package.json DELETED
@@ -1,65 +0,0 @@
1
- {
2
- "name": "claude-code-workflow",
3
- "version": "6.2.6",
4
- "description": "Claude Code Workflow CLI - Dashboard viewer for workflow sessions and reviews",
5
- "type": "module",
6
- "main": "dist/index.js",
7
- "types": "dist/index.d.ts",
8
- "bin": {
9
- "ccw": "./bin/ccw.js",
10
- "ccw-mcp": "./bin/ccw-mcp.js"
11
- },
12
- "scripts": {
13
- "build": "tsc",
14
- "dev": "tsx watch src/cli.ts",
15
- "test": "node --test tests/*.test.js",
16
- "test:codexlens": "node --test tests/codex-lens*.test.js",
17
- "test:mcp": "node --test tests/mcp-server.test.js",
18
- "lint": "eslint src/"
19
- },
20
- "keywords": [
21
- "claude",
22
- "workflow",
23
- "cli",
24
- "dashboard",
25
- "code-review"
26
- ],
27
- "author": "Claude Code Workflow",
28
- "license": "MIT",
29
- "engines": {
30
- "node": ">=16.0.0"
31
- },
32
- "dependencies": {
33
- "@modelcontextprotocol/sdk": "^1.0.4",
34
- "better-sqlite3": "^11.7.0",
35
- "boxen": "^7.1.0",
36
- "chalk": "^5.3.0",
37
- "commander": "^11.0.0",
38
- "figlet": "^1.7.0",
39
- "glob": "^10.3.0",
40
- "gradient-string": "^2.0.2",
41
- "inquirer": "^9.2.0",
42
- "open": "^9.1.0",
43
- "ora": "^7.0.0",
44
- "zod": "^4.1.13"
45
- },
46
- "files": [
47
- "bin/",
48
- "dist/",
49
- "src/",
50
- "README.md",
51
- "LICENSE"
52
- ],
53
- "repository": {
54
- "type": "git",
55
- "url": "https://github.com/claude-code-workflow/ccw"
56
- },
57
- "devDependencies": {
58
- "@types/better-sqlite3": "^7.6.12",
59
- "@types/gradient-string": "^1.1.6",
60
- "@types/inquirer": "^9.0.9",
61
- "@types/node": "^25.0.1",
62
- "tsx": "^4.21.0",
63
- "typescript": "^5.9.3"
64
- }
65
- }