claude-code-workflow 6.1.4 → 6.2.2
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/.claude/CLAUDE.md +10 -0
- package/.claude/agents/action-planning-agent.md +857 -778
- package/.claude/agents/cli-execution-agent.md +266 -269
- package/.claude/agents/cli-explore-agent.md +2 -2
- package/.claude/agents/cli-lite-planning-agent.md +142 -92
- package/.claude/agents/cli-planning-agent.md +4 -4
- package/.claude/agents/code-developer.md +7 -6
- package/.claude/agents/conceptual-planning-agent.md +2 -2
- package/.claude/agents/context-search-agent.md +31 -32
- package/.claude/agents/doc-generator.md +4 -4
- package/.claude/agents/memory-bridge.md +93 -93
- package/.claude/agents/test-context-search-agent.md +8 -7
- package/.claude/agents/test-fix-agent.md +7 -6
- package/.claude/commands/clean.md +516 -0
- package/.claude/commands/memory/compact.md +383 -0
- package/.claude/commands/memory/docs-full-cli.md +471 -471
- package/.claude/commands/memory/docs-related-cli.md +386 -386
- package/.claude/commands/memory/docs.md +615 -615
- package/.claude/commands/memory/load.md +5 -5
- package/.claude/commands/memory/tech-research-rules.md +310 -0
- package/.claude/commands/memory/update-full.md +332 -332
- package/.claude/commands/memory/workflow-skill-memory.md +4 -4
- package/.claude/commands/task/create.md +151 -151
- package/.claude/commands/version.md +254 -254
- package/.claude/commands/workflow/brainstorm/api-designer.md +587 -585
- package/.claude/commands/workflow/brainstorm/artifacts.md +1 -0
- package/.claude/commands/workflow/brainstorm/auto-parallel.md +443 -443
- package/.claude/commands/workflow/brainstorm/data-architect.md +220 -220
- package/.claude/commands/workflow/brainstorm/product-manager.md +200 -200
- package/.claude/commands/workflow/brainstorm/product-owner.md +200 -200
- package/.claude/commands/workflow/brainstorm/scrum-master.md +200 -200
- package/.claude/commands/workflow/brainstorm/subject-matter-expert.md +200 -200
- package/.claude/commands/workflow/brainstorm/system-architect.md +389 -387
- package/.claude/commands/workflow/brainstorm/ui-designer.md +221 -221
- package/.claude/commands/workflow/brainstorm/ux-expert.md +221 -221
- package/.claude/commands/workflow/debug.md +321 -0
- package/.claude/commands/workflow/execute.md +13 -0
- package/.claude/commands/workflow/init.md +165 -164
- package/.claude/commands/workflow/lite-execute.md +119 -13
- package/.claude/commands/workflow/lite-fix.md +623 -621
- package/.claude/commands/workflow/lite-plan.md +610 -592
- package/.claude/commands/workflow/plan.md +5 -5
- package/.claude/commands/workflow/review-module-cycle.md +2 -0
- package/.claude/commands/workflow/review-session-cycle.md +2 -0
- package/.claude/commands/workflow/review.md +297 -291
- package/.claude/commands/workflow/session/complete.md +153 -500
- package/.claude/commands/workflow/session/list.md +95 -95
- package/.claude/commands/workflow/session/resume.md +60 -60
- package/.claude/commands/workflow/session/start.md +199 -199
- package/.claude/commands/workflow/tdd-plan.md +3 -3
- package/.claude/commands/workflow/tdd-verify.md +23 -9
- package/.claude/commands/workflow/test-cycle-execute.md +2 -0
- package/.claude/commands/workflow/test-fix-gen.md +699 -699
- package/.claude/commands/workflow/tools/conflict-resolution.md +104 -18
- package/.claude/commands/workflow/tools/context-gather.md +436 -434
- package/.claude/commands/workflow/tools/task-generate-agent.md +490 -291
- package/.claude/commands/workflow/tools/task-generate-tdd.md +18 -10
- package/.claude/commands/workflow/tools/test-concept-enhanced.md +2 -1
- package/.claude/commands/workflow/tools/test-context-gather.md +1 -0
- package/.claude/commands/workflow/tools/test-task-generate.md +1 -0
- package/.claude/commands/workflow/ui-design/import-from-code.md +9 -6
- package/.claude/skills/command-guide/SKILL.md +5 -5
- package/.claude/skills/command-guide/index/all-commands.json +1 -1
- package/.claude/skills/command-guide/index/by-category.json +1 -1
- package/.claude/skills/command-guide/index/by-use-case.json +1 -1
- package/.claude/skills/command-guide/reference/agents/action-planning-agent.md +857 -778
- package/.claude/skills/command-guide/reference/agents/cli-execution-agent.md +266 -269
- package/.claude/skills/command-guide/reference/agents/cli-explore-agent.md +2 -2
- package/.claude/skills/command-guide/reference/agents/cli-lite-planning-agent.md +142 -92
- package/.claude/skills/command-guide/reference/agents/cli-planning-agent.md +4 -4
- package/.claude/skills/command-guide/reference/agents/code-developer.md +7 -6
- package/.claude/skills/command-guide/reference/agents/conceptual-planning-agent.md +2 -2
- package/.claude/skills/command-guide/reference/agents/context-search-agent.md +31 -32
- package/.claude/skills/command-guide/reference/agents/doc-generator.md +4 -4
- package/.claude/skills/command-guide/reference/agents/memory-bridge.md +93 -93
- package/.claude/skills/command-guide/reference/agents/test-context-search-agent.md +8 -7
- package/.claude/skills/command-guide/reference/agents/test-fix-agent.md +7 -6
- package/.claude/skills/command-guide/reference/commands/memory/docs-full-cli.md +471 -471
- package/.claude/skills/command-guide/reference/commands/memory/docs-related-cli.md +386 -386
- package/.claude/skills/command-guide/reference/commands/memory/docs.md +17 -16
- package/.claude/skills/command-guide/reference/commands/memory/load.md +5 -5
- package/.claude/skills/command-guide/reference/commands/memory/tech-research.md +194 -357
- package/.claude/skills/command-guide/reference/commands/memory/update-full.md +332 -332
- package/.claude/skills/command-guide/reference/commands/memory/workflow-skill-memory.md +4 -4
- package/.claude/skills/command-guide/reference/commands/task/create.md +151 -151
- package/.claude/skills/command-guide/reference/commands/version.md +254 -254
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/api-designer.md +585 -585
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/auto-parallel.md +443 -443
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/data-architect.md +220 -220
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/product-manager.md +200 -200
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/product-owner.md +200 -200
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/scrum-master.md +200 -200
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/subject-matter-expert.md +200 -200
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/system-architect.md +387 -387
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/ui-designer.md +221 -221
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/ux-expert.md +221 -221
- package/.claude/skills/command-guide/reference/commands/workflow/execute.md +25 -20
- package/.claude/skills/command-guide/reference/commands/workflow/init.md +164 -164
- package/.claude/skills/command-guide/reference/commands/workflow/lite-execute.md +748 -686
- package/.claude/skills/command-guide/reference/commands/workflow/lite-fix.md +664 -621
- package/.claude/skills/command-guide/reference/commands/workflow/lite-plan.md +645 -592
- package/.claude/skills/command-guide/reference/commands/workflow/plan.md +5 -5
- package/.claude/skills/command-guide/reference/commands/workflow/review.md +25 -18
- package/.claude/skills/command-guide/reference/commands/workflow/session/complete.md +547 -500
- package/.claude/skills/command-guide/reference/commands/workflow/session/list.md +45 -27
- package/.claude/skills/command-guide/reference/commands/workflow/session/resume.md +35 -19
- package/.claude/skills/command-guide/reference/commands/workflow/session/start.md +90 -33
- package/.claude/skills/command-guide/reference/commands/workflow/tdd-plan.md +3 -3
- package/.claude/skills/command-guide/reference/commands/workflow/tdd-verify.md +23 -9
- package/.claude/skills/command-guide/reference/commands/workflow/test-fix-gen.md +699 -699
- package/.claude/skills/command-guide/reference/commands/workflow/tools/conflict-resolution.md +103 -17
- package/.claude/skills/command-guide/reference/commands/workflow/tools/context-gather.md +434 -434
- package/.claude/skills/command-guide/reference/commands/workflow/tools/task-generate-agent.md +487 -291
- package/.claude/skills/command-guide/reference/commands/workflow/tools/task-generate-tdd.md +17 -10
- package/.claude/skills/command-guide/reference/commands/workflow/tools/test-concept-enhanced.md +1 -1
- package/.claude/skills/command-guide/reference/commands/workflow/ui-design/import-from-code.md +6 -6
- package/.claude/workflows/chinese-response.md +38 -0
- package/.claude/workflows/cli-templates/prompts/rules/rule-api.txt +122 -0
- package/.claude/workflows/cli-templates/prompts/rules/rule-components.txt +122 -0
- package/.claude/workflows/cli-templates/prompts/rules/rule-config.txt +89 -0
- package/.claude/workflows/cli-templates/prompts/rules/rule-core.txt +60 -0
- package/.claude/workflows/cli-templates/prompts/rules/rule-patterns.txt +70 -0
- package/.claude/workflows/cli-templates/prompts/rules/rule-testing.txt +81 -0
- package/.claude/workflows/cli-templates/prompts/rules/tech-rules-agent-prompt.txt +89 -0
- package/.claude/workflows/cli-templates/prompts/workflow/gemini-solution-design.txt +131 -131
- package/.claude/workflows/cli-templates/prompts/workflow/skill-conflict-patterns.txt +5 -9
- package/.claude/workflows/cli-templates/prompts/workflow/skill-lessons-learned.txt +5 -9
- package/.claude/workflows/cli-templates/protocols/analysis-protocol.md +112 -0
- package/.claude/workflows/cli-templates/protocols/write-protocol.md +201 -0
- package/.claude/workflows/cli-templates/schemas/conflict-resolution-schema.json +137 -0
- package/.claude/workflows/cli-templates/schemas/debug-log-json-schema.json +127 -0
- package/.claude/workflows/cli-templates/schemas/fix-plan-json-schema.json +25 -0
- package/.claude/workflows/cli-templates/schemas/plan-json-schema.json +25 -0
- package/.claude/workflows/cli-tools-usage.md +526 -0
- package/{CLAUDE.md → .claude/workflows/coding-philosophy.md} +24 -45
- package/.claude/workflows/context-tools.md +84 -0
- package/.claude/workflows/file-modification.md +64 -0
- package/.claude/workflows/tool-strategy.md +216 -79
- package/.claude/workflows/windows-platform.md +16 -0
- package/.claude/workflows/workflow-architecture.md +942 -942
- package/.codex/AGENTS.md +63 -330
- package/.codex/prompts/debug.md +318 -0
- package/.codex/prompts/execute.md +273 -0
- package/.codex/prompts/lite-execute.md +164 -0
- package/.codex/prompts/lite-plan.md +469 -0
- package/.codex/prompts.zip +0 -0
- package/.gemini/GEMINI.md +25 -164
- package/.qwen/QWEN.md +0 -139
- package/README.md +29 -9
- package/ccw/README.md +30 -6
- package/ccw/bin/ccw-mcp.js +7 -0
- package/ccw/bin/ccw.js +9 -9
- package/ccw/package.json +65 -47
- package/ccw/src/.workflow/.cli-history/history.db +0 -0
- package/ccw/src/.workflow/.cli-history/history.db-shm +0 -0
- package/ccw/src/.workflow/.cli-history/history.db-wal +0 -0
- package/ccw/src/cli.ts +244 -0
- package/ccw/src/commands/cli.ts +740 -0
- package/ccw/src/commands/core-memory.ts +770 -0
- package/ccw/src/commands/hook.ts +315 -0
- package/ccw/src/commands/install.ts +519 -0
- package/ccw/src/commands/{list.js → list.ts} +1 -1
- package/ccw/src/commands/memory.ts +1090 -0
- package/ccw/src/commands/{serve.js → serve.ts} +14 -5
- package/ccw/src/commands/session-path-resolver.ts +372 -0
- package/ccw/src/commands/session.ts +1141 -0
- package/ccw/src/commands/{stop.js → stop.ts} +16 -6
- package/ccw/src/commands/tool.ts +201 -0
- package/ccw/src/commands/{uninstall.js → uninstall.ts} +89 -40
- package/ccw/src/commands/{upgrade.js → upgrade.ts} +68 -23
- package/ccw/src/commands/{view.js → view.ts} +22 -8
- package/ccw/src/config/storage-paths.ts +670 -0
- package/ccw/src/core/cache-manager.ts +294 -0
- package/ccw/src/core/claude-freshness.ts +319 -0
- package/ccw/src/core/core-memory-store.ts +1528 -0
- package/ccw/src/core/{dashboard-generator-patch.js → dashboard-generator-patch.ts} +18 -0
- package/ccw/src/core/{dashboard-generator.js → dashboard-generator.ts} +69 -12
- package/ccw/src/core/data-aggregator.ts +584 -0
- package/ccw/src/core/history-importer.ts +625 -0
- package/ccw/src/core/{lite-scanner.js → lite-scanner-complete.ts} +162 -66
- package/ccw/src/core/lite-scanner.ts +469 -0
- package/ccw/src/core/{manifest.js → manifest.ts} +104 -34
- package/ccw/src/core/memory-embedder-bridge.ts +262 -0
- package/ccw/src/core/memory-store.ts +978 -0
- package/ccw/src/core/routes/ccw-routes.ts +96 -0
- package/ccw/src/core/routes/claude-routes.ts +1183 -0
- package/ccw/src/core/routes/cli-routes.ts +561 -0
- package/ccw/src/core/routes/codexlens-routes.ts +806 -0
- package/ccw/src/core/routes/core-memory-routes.ts +605 -0
- package/ccw/src/core/routes/files-routes.ts +428 -0
- package/ccw/src/core/routes/graph-routes.md +164 -0
- package/ccw/src/core/routes/graph-routes.ts +626 -0
- package/ccw/src/core/routes/help-routes.ts +308 -0
- package/ccw/src/core/routes/hooks-routes.ts +405 -0
- package/ccw/src/core/routes/mcp-routes.ts +1271 -0
- package/ccw/src/core/routes/mcp-routes.ts.backup +550 -0
- package/ccw/src/core/routes/mcp-templates-db.ts +268 -0
- package/ccw/src/core/routes/memory-routes.ts +1206 -0
- package/ccw/src/core/routes/rules-routes.ts +526 -0
- package/ccw/src/core/routes/session-routes.ts +467 -0
- package/ccw/src/core/routes/skills-routes.ts +599 -0
- package/ccw/src/core/routes/status-routes.ts +57 -0
- package/ccw/src/core/routes/system-routes.ts +427 -0
- package/ccw/src/core/server.ts +431 -0
- package/ccw/src/core/session-clustering-service.ts +1258 -0
- package/ccw/src/core/session-scanner.ts +283 -0
- package/ccw/src/core/websocket.ts +190 -0
- package/ccw/src/{index.js → index.ts} +1 -0
- package/ccw/src/mcp-server/index.ts +186 -0
- package/ccw/src/templates/assets/css/github-dark.min.css +10 -0
- package/ccw/src/templates/assets/css/github.min.css +10 -0
- package/ccw/src/templates/assets/js/cytoscape.min.js +32 -0
- package/ccw/src/templates/assets/js/d3.min.js +2 -0
- package/ccw/src/templates/assets/js/highlight.min.js +1244 -0
- package/ccw/src/templates/assets/js/lucide.min.js +12 -0
- package/ccw/src/templates/assets/js/marked.min.js +69 -0
- package/ccw/src/templates/assets/js/tailwind.js +83 -0
- package/ccw/src/templates/dashboard-css/01-base.css +11 -0
- package/ccw/src/templates/dashboard-css/02-session.css +22 -0
- package/ccw/src/templates/dashboard-css/04-lite-tasks.css +10 -0
- package/ccw/src/templates/dashboard-css/06-cards.css +10 -4
- package/ccw/src/templates/dashboard-css/07-managers.css +1178 -7
- package/ccw/src/templates/dashboard-css/09-explorer.css +23 -12
- package/ccw/src/templates/dashboard-css/10-cli-status.css +337 -0
- package/ccw/src/templates/dashboard-css/11-cli-history.css +271 -0
- package/ccw/src/templates/dashboard-css/12-cli-legacy.css +796 -0
- package/ccw/src/templates/dashboard-css/13-cli-ccw.css +199 -0
- package/ccw/src/templates/dashboard-css/14-cli-modals.css +258 -0
- package/ccw/src/templates/dashboard-css/15-cli-endpoints.css +305 -0
- package/ccw/src/templates/dashboard-css/16-cli-session.css +241 -0
- package/ccw/src/templates/dashboard-css/17-cli-conversation.css +283 -0
- package/ccw/src/templates/dashboard-css/18-cli-settings.css +160 -0
- package/ccw/src/templates/dashboard-css/19-cli-native-session.css +496 -0
- package/ccw/src/templates/dashboard-css/20-cli-taskqueue.css +188 -0
- package/ccw/src/templates/dashboard-css/21-cli-toolmgmt.css +310 -0
- package/ccw/src/templates/dashboard-css/22-cli-semantic.css +240 -0
- package/ccw/src/templates/dashboard-css/23-memory.css +2390 -0
- package/ccw/src/templates/dashboard-css/24-prompt-history.css +1089 -0
- package/ccw/src/templates/dashboard-css/25-skills-rules.css +326 -0
- package/ccw/src/templates/dashboard-css/26-claude-manager.css +908 -0
- package/ccw/src/templates/dashboard-css/27-graph-explorer.css +1678 -0
- package/ccw/src/templates/dashboard-css/28-mcp-manager.css +748 -0
- package/ccw/src/templates/dashboard-css/29-help.css +264 -0
- package/ccw/src/templates/dashboard-css/30-core-memory.css +1700 -0
- package/ccw/src/templates/dashboard-js/api.js +162 -142
- package/ccw/src/templates/dashboard-js/components/carousel.js +4 -4
- package/ccw/src/templates/dashboard-js/components/cli-history.js +876 -0
- package/ccw/src/templates/dashboard-js/components/cli-status.js +978 -0
- package/ccw/src/templates/dashboard-js/components/global-notifications.js +508 -219
- package/ccw/src/templates/dashboard-js/components/hook-manager.js +1277 -282
- package/ccw/src/templates/dashboard-js/components/index-manager.js +302 -0
- package/ccw/src/templates/dashboard-js/components/mcp-manager.js +718 -27
- package/ccw/src/templates/dashboard-js/components/modals.js +66 -0
- package/ccw/src/templates/dashboard-js/components/navigation.js +80 -12
- package/ccw/src/templates/dashboard-js/components/notifications.js +758 -194
- package/ccw/src/templates/dashboard-js/components/storage-manager.js +478 -0
- package/ccw/src/templates/dashboard-js/components/tabs-other.js +157 -6
- package/ccw/src/templates/dashboard-js/components/task-queue-sidebar.js +716 -0
- package/ccw/src/templates/dashboard-js/help-i18n.js +272 -0
- package/ccw/src/templates/dashboard-js/i18n.js +2807 -0
- package/ccw/src/templates/dashboard-js/main.js +15 -0
- package/ccw/src/templates/dashboard-js/state.js +243 -42
- package/ccw/src/templates/dashboard-js/utils.js +47 -1
- package/ccw/src/templates/dashboard-js/views/claude-manager.js +912 -0
- package/ccw/src/templates/dashboard-js/views/cli-manager.js +2272 -0
- package/ccw/src/templates/dashboard-js/views/codexlens-manager.js +964 -0
- package/ccw/src/templates/dashboard-js/views/core-memory-clusters.js +503 -0
- package/ccw/src/templates/dashboard-js/views/core-memory.js +782 -0
- package/ccw/src/templates/dashboard-js/views/explorer.js +888 -852
- package/ccw/src/templates/dashboard-js/views/graph-explorer.js +1157 -0
- package/ccw/src/templates/dashboard-js/views/help.js +856 -0
- package/ccw/src/templates/dashboard-js/views/history.js +337 -0
- package/ccw/src/templates/dashboard-js/views/home.js +61 -15
- package/ccw/src/templates/dashboard-js/views/hook-manager.js +311 -43
- package/ccw/src/templates/dashboard-js/views/lite-tasks.js +204 -28
- package/ccw/src/templates/dashboard-js/views/mcp-manager.js +2187 -411
- package/ccw/src/templates/dashboard-js/views/mcp-manager.js.backup +1729 -0
- package/ccw/src/templates/dashboard-js/views/mcp-manager.js.new +928 -0
- package/ccw/src/templates/dashboard-js/views/memory.js +1221 -0
- package/ccw/src/templates/dashboard-js/views/prompt-history.js +713 -0
- package/ccw/src/templates/dashboard-js/views/rules-manager.js +828 -0
- package/ccw/src/templates/dashboard-js/views/session-detail.js +54 -53
- package/ccw/src/templates/dashboard-js/views/skills-manager.js +819 -0
- package/ccw/src/templates/dashboard.html +185 -85
- package/ccw/src/templates/hooks-config-example.json +60 -0
- package/ccw/src/tools/classify-folders.ts +245 -0
- package/ccw/src/tools/cli-config-manager.ts +268 -0
- package/ccw/src/tools/cli-executor.ts +2014 -0
- package/ccw/src/tools/cli-history-store.ts +1195 -0
- package/ccw/src/tools/codex-lens.ts +1141 -0
- package/ccw/src/tools/{convert-tokens-to-css.js → convert-tokens-to-css.ts} +73 -23
- package/ccw/src/tools/core-memory.ts +444 -0
- package/ccw/src/tools/detect-changed-modules.ts +325 -0
- package/ccw/src/tools/{discover-design-files.js → discover-design-files.ts} +74 -24
- package/ccw/src/tools/edit-file.ts +568 -0
- package/ccw/src/tools/{generate-module-docs.js → generate-module-docs.ts} +207 -185
- package/ccw/src/tools/{get-modules-by-depth.js → get-modules-by-depth.ts} +120 -79
- package/ccw/src/tools/index.ts +370 -0
- package/ccw/src/tools/native-session-discovery.ts +795 -0
- package/ccw/src/tools/notifier.ts +129 -0
- package/ccw/src/tools/read-file.ts +410 -0
- package/ccw/src/tools/resume-strategy.ts +345 -0
- package/ccw/src/tools/session-content-parser.ts +619 -0
- package/ccw/src/tools/session-manager.ts +1026 -0
- package/ccw/src/tools/smart-context.ts +228 -0
- package/ccw/src/tools/smart-search.ts +2065 -0
- package/ccw/src/tools/smart-search.ts.backup +1233 -0
- package/ccw/src/tools/storage-manager.ts +455 -0
- package/ccw/src/tools/write-file.ts +222 -0
- package/ccw/src/types/config.ts +11 -0
- package/ccw/src/types/index.ts +3 -0
- package/ccw/src/types/session.ts +25 -0
- package/ccw/src/types/tool.ts +41 -0
- package/ccw/src/utils/{browser-launcher.js → browser-launcher.ts} +10 -8
- package/ccw/src/utils/file-utils.ts +48 -0
- package/ccw/src/utils/{path-resolver.js → path-resolver.ts} +114 -78
- package/ccw/src/utils/path-validator.ts +153 -0
- package/ccw/src/utils/{ui.js → ui.ts} +32 -25
- package/codex-lens/pyproject.toml +48 -0
- package/codex-lens/src/codexlens/.workflow/.cli-history/history.db +0 -0
- package/codex-lens/src/codexlens/__init__.py +28 -0
- package/codex-lens/src/codexlens/__main__.py +14 -0
- package/codex-lens/src/codexlens/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/__pycache__/__main__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/__pycache__/config.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/__pycache__/entities.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/__pycache__/errors.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/__init__.py +27 -0
- package/codex-lens/src/codexlens/cli/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/__pycache__/commands.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/__pycache__/embedding_manager.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/__pycache__/model_manager.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/__pycache__/output.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/commands.py +1931 -0
- package/codex-lens/src/codexlens/cli/embedding_manager.py +620 -0
- package/codex-lens/src/codexlens/cli/model_manager.py +289 -0
- package/codex-lens/src/codexlens/cli/output.py +124 -0
- package/codex-lens/src/codexlens/config.py +201 -0
- package/codex-lens/src/codexlens/entities.py +121 -0
- package/codex-lens/src/codexlens/errors.py +55 -0
- package/codex-lens/src/codexlens/indexing/README.md +77 -0
- package/codex-lens/src/codexlens/indexing/__init__.py +4 -0
- package/codex-lens/src/codexlens/indexing/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/indexing/__pycache__/symbol_extractor.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/indexing/symbol_extractor.py +243 -0
- package/codex-lens/src/codexlens/parsers/__init__.py +8 -0
- package/codex-lens/src/codexlens/parsers/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/parsers/__pycache__/encoding.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/parsers/__pycache__/factory.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/parsers/__pycache__/tokenizer.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/parsers/__pycache__/treesitter_parser.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/parsers/encoding.py +202 -0
- package/codex-lens/src/codexlens/parsers/factory.py +256 -0
- package/codex-lens/src/codexlens/parsers/tokenizer.py +98 -0
- package/codex-lens/src/codexlens/parsers/treesitter_parser.py +335 -0
- package/codex-lens/src/codexlens/search/__init__.py +15 -0
- package/codex-lens/src/codexlens/search/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/__pycache__/chain_search.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/__pycache__/enrichment.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/__pycache__/hybrid_search.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/__pycache__/query_parser.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/__pycache__/ranking.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/chain_search.py +647 -0
- package/codex-lens/src/codexlens/search/enrichment.py +150 -0
- package/codex-lens/src/codexlens/search/hybrid_search.py +313 -0
- package/codex-lens/src/codexlens/search/query_parser.py +242 -0
- package/codex-lens/src/codexlens/search/ranking.py +274 -0
- package/codex-lens/src/codexlens/semantic/__init__.py +39 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/ann_index.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/chunker.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/code_extractor.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/embedder.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/graph_analyzer.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/llm_enhancer.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/vector_store.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/ann_index.py +414 -0
- package/codex-lens/src/codexlens/semantic/chunker.py +448 -0
- package/codex-lens/src/codexlens/semantic/code_extractor.py +274 -0
- package/codex-lens/src/codexlens/semantic/embedder.py +185 -0
- package/codex-lens/src/codexlens/semantic/vector_store.py +955 -0
- package/codex-lens/src/codexlens/storage/__init__.py +29 -0
- package/codex-lens/src/codexlens/storage/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/dir_index.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/file_cache.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/index_tree.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/migration_manager.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/path_mapper.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/registry.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/sqlite_store.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/sqlite_utils.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/dir_index.py +1850 -0
- package/codex-lens/src/codexlens/storage/file_cache.py +32 -0
- package/codex-lens/src/codexlens/storage/index_tree.py +776 -0
- package/codex-lens/src/codexlens/storage/migration_manager.py +154 -0
- package/codex-lens/src/codexlens/storage/migrations/__init__.py +1 -0
- package/codex-lens/src/codexlens/storage/migrations/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_001_normalize_keywords.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_002_add_token_metadata.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_003_code_relationships.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_004_dual_fts.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_005_cleanup_unused_fields.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/migrations/migration_001_normalize_keywords.py +123 -0
- package/codex-lens/src/codexlens/storage/migrations/migration_002_add_token_metadata.py +48 -0
- package/codex-lens/src/codexlens/storage/migrations/migration_004_dual_fts.py +232 -0
- package/codex-lens/src/codexlens/storage/migrations/migration_005_cleanup_unused_fields.py +196 -0
- package/codex-lens/src/codexlens/storage/path_mapper.py +274 -0
- package/codex-lens/src/codexlens/storage/registry.py +670 -0
- package/codex-lens/src/codexlens/storage/sqlite_store.py +576 -0
- package/codex-lens/src/codexlens/storage/sqlite_utils.py +64 -0
- package/package.json +4 -1
- package/.claude/commands/memory/tech-research.md +0 -477
- package/.claude/scripts/classify-folders.sh +0 -39
- package/.claude/scripts/convert_tokens_to_css.sh +0 -229
- package/.claude/scripts/detect_changed_modules.sh +0 -161
- package/.claude/scripts/discover-design-files.sh +0 -87
- package/.claude/scripts/extract-animations.js +0 -243
- package/.claude/scripts/extract-computed-styles.js +0 -118
- package/.claude/scripts/extract-layout-structure.js +0 -411
- package/.claude/scripts/generate_module_docs.sh +0 -717
- package/.claude/scripts/get_modules_by_depth.sh +0 -170
- package/.claude/scripts/ui-generate-preview.sh +0 -395
- package/.claude/scripts/ui-instantiate-prototypes.sh +0 -815
- package/.claude/scripts/update_module_claude.sh +0 -337
- package/.claude/workflows/context-search-strategy.md +0 -77
- package/.claude/workflows/intelligent-tools-strategy.md +0 -662
- package/ccw/src/cli.js +0 -119
- package/ccw/src/commands/install.js +0 -324
- package/ccw/src/commands/tool.js +0 -138
- package/ccw/src/core/data-aggregator.js +0 -409
- package/ccw/src/core/server.js +0 -2063
- package/ccw/src/core/session-scanner.js +0 -235
- package/ccw/src/tools/classify-folders.js +0 -204
- package/ccw/src/tools/detect-changed-modules.js +0 -288
- package/ccw/src/tools/edit-file.js +0 -266
- package/ccw/src/tools/index.js +0 -176
- package/ccw/src/utils/file-utils.js +0 -48
|
@@ -0,0 +1,1090 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Command - Context tracking and prompt optimization
|
|
3
|
+
* Provides CLI interface for Memory module operations
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
import { getMemoryStore, type Entity, type HotEntity, type PromptHistory } from '../core/memory-store.js';
|
|
8
|
+
import { HistoryImporter } from '../core/history-importer.js';
|
|
9
|
+
import { notifyMemoryUpdate, notifyRefreshRequired } from '../tools/notifier.js';
|
|
10
|
+
import { join } from 'path';
|
|
11
|
+
import { existsSync, readdirSync } from 'fs';
|
|
12
|
+
import { StoragePaths } from '../config/storage-paths.js';
|
|
13
|
+
import {
|
|
14
|
+
generateEmbeddings,
|
|
15
|
+
searchMemories,
|
|
16
|
+
getEmbeddingStatus,
|
|
17
|
+
isEmbedderAvailable,
|
|
18
|
+
type EmbedOptions,
|
|
19
|
+
type SearchOptions as EmbedSearchOptions
|
|
20
|
+
} from '../core/memory-embedder-bridge.js';
|
|
21
|
+
import { getCoreMemoryStore } from '../core/core-memory-store.js';
|
|
22
|
+
import { CliHistoryStore } from '../tools/cli-history-store.js';
|
|
23
|
+
|
|
24
|
+
interface TrackOptions {
|
|
25
|
+
type?: string;
|
|
26
|
+
action?: string;
|
|
27
|
+
value?: string;
|
|
28
|
+
session?: string;
|
|
29
|
+
stdin?: boolean;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
interface ImportOptions {
|
|
33
|
+
source?: string;
|
|
34
|
+
project?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface StatsOptions {
|
|
38
|
+
type?: string;
|
|
39
|
+
limit?: string;
|
|
40
|
+
sort?: string;
|
|
41
|
+
json?: boolean;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
interface SearchOptions {
|
|
45
|
+
limit?: string;
|
|
46
|
+
json?: boolean;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
interface SuggestOptions {
|
|
50
|
+
context?: string;
|
|
51
|
+
limit?: string;
|
|
52
|
+
json?: boolean;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
interface PruneOptions {
|
|
56
|
+
olderThan?: string;
|
|
57
|
+
dryRun?: boolean;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
interface EmbedCommandOptions {
|
|
61
|
+
id?: string;
|
|
62
|
+
force?: boolean;
|
|
63
|
+
batchSize?: string;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
interface SearchCommandOptions {
|
|
67
|
+
topK?: string;
|
|
68
|
+
type?: 'core_memory' | 'workflow' | 'cli_history';
|
|
69
|
+
minScore?: string;
|
|
70
|
+
json?: boolean;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
interface EmbedStatusOptions {
|
|
74
|
+
json?: boolean;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Read JSON data from stdin (for Claude Code hooks)
|
|
79
|
+
*/
|
|
80
|
+
async function readStdin(): Promise<string> {
|
|
81
|
+
return new Promise((resolve) => {
|
|
82
|
+
let data = '';
|
|
83
|
+
process.stdin.setEncoding('utf8');
|
|
84
|
+
process.stdin.on('readable', () => {
|
|
85
|
+
let chunk;
|
|
86
|
+
while ((chunk = process.stdin.read()) !== null) {
|
|
87
|
+
data += chunk;
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
process.stdin.on('end', () => {
|
|
91
|
+
resolve(data);
|
|
92
|
+
});
|
|
93
|
+
// Handle case where stdin is empty or not piped
|
|
94
|
+
if (process.stdin.isTTY) {
|
|
95
|
+
resolve('');
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Normalize file path for consistent storage
|
|
102
|
+
*/
|
|
103
|
+
function normalizePath(filePath: string): string {
|
|
104
|
+
// Convert Windows paths to forward slashes and remove drive letter variations
|
|
105
|
+
return filePath
|
|
106
|
+
.replace(/\\/g, '/')
|
|
107
|
+
.replace(/^[A-Za-z]:/, (match) => match.toLowerCase());
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Get project path from hook data or current working directory
|
|
112
|
+
*/
|
|
113
|
+
function getProjectPath(hookCwd?: string): string {
|
|
114
|
+
// Prefer hook's cwd (actual project workspace) over process.cwd()
|
|
115
|
+
return hookCwd || process.cwd();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Track entity access (used by hooks)
|
|
120
|
+
*/
|
|
121
|
+
async function trackAction(options: TrackOptions): Promise<void> {
|
|
122
|
+
let { type, action, value, session, stdin } = options;
|
|
123
|
+
let hookCwd: string | undefined;
|
|
124
|
+
|
|
125
|
+
// If --stdin flag is set, read from stdin (Claude Code hook format)
|
|
126
|
+
if (stdin) {
|
|
127
|
+
try {
|
|
128
|
+
const stdinData = await readStdin();
|
|
129
|
+
if (stdinData) {
|
|
130
|
+
const hookData = JSON.parse(stdinData);
|
|
131
|
+
session = hookData.session_id || session;
|
|
132
|
+
hookCwd = hookData.cwd; // Extract workspace path from hook
|
|
133
|
+
|
|
134
|
+
// Extract value based on hook event
|
|
135
|
+
if (hookData.tool_input) {
|
|
136
|
+
// PostToolUse event
|
|
137
|
+
value = hookData.tool_input.file_path ||
|
|
138
|
+
hookData.tool_input.paths ||
|
|
139
|
+
hookData.tool_input.path ||
|
|
140
|
+
JSON.stringify(hookData.tool_input);
|
|
141
|
+
} else if (hookData.prompt) {
|
|
142
|
+
// UserPromptSubmit event
|
|
143
|
+
value = hookData.prompt;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
} catch {
|
|
147
|
+
// Silently continue if stdin parsing fails
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (!type || !action) {
|
|
152
|
+
console.error(chalk.red('Error: --type and --action are required'));
|
|
153
|
+
console.error(chalk.gray('Usage: ccw memory track --type file --action read --value "path" --session "id"'));
|
|
154
|
+
console.error(chalk.gray(' ccw memory track --type file --action read --stdin'));
|
|
155
|
+
process.exit(1);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Validate type and action
|
|
159
|
+
const validTypes = ['file', 'module', 'topic', 'url'];
|
|
160
|
+
const validActions = ['read', 'write', 'mention'];
|
|
161
|
+
|
|
162
|
+
if (!validTypes.includes(type)) {
|
|
163
|
+
if (!stdin) {
|
|
164
|
+
console.error(chalk.red(`Error: Invalid type "${type}". Must be one of: ${validTypes.join(', ')}`));
|
|
165
|
+
}
|
|
166
|
+
process.exit(stdin ? 0 : 1);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (!validActions.includes(action)) {
|
|
170
|
+
if (!stdin) {
|
|
171
|
+
console.error(chalk.red(`Error: Invalid action "${action}". Must be one of: ${validActions.join(', ')}`));
|
|
172
|
+
}
|
|
173
|
+
process.exit(stdin ? 0 : 1);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Skip if no value provided
|
|
177
|
+
if (!value) {
|
|
178
|
+
if (stdin) {
|
|
179
|
+
process.exit(0);
|
|
180
|
+
}
|
|
181
|
+
console.error(chalk.red('Error: --value is required'));
|
|
182
|
+
process.exit(1);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
try {
|
|
186
|
+
const projectPath = getProjectPath(hookCwd);
|
|
187
|
+
const store = getMemoryStore(projectPath);
|
|
188
|
+
const now = new Date().toISOString();
|
|
189
|
+
|
|
190
|
+
// Normalize value for file types
|
|
191
|
+
const normalizedValue = type === 'file' ? normalizePath(value) : value.toLowerCase();
|
|
192
|
+
|
|
193
|
+
// Upsert entity
|
|
194
|
+
const entityId = store.upsertEntity({
|
|
195
|
+
type: type as Entity['type'],
|
|
196
|
+
value: value,
|
|
197
|
+
normalized_value: normalizedValue,
|
|
198
|
+
first_seen_at: now,
|
|
199
|
+
last_seen_at: now
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// Log access
|
|
203
|
+
store.logAccess({
|
|
204
|
+
entity_id: entityId,
|
|
205
|
+
action: action as 'read' | 'write' | 'mention',
|
|
206
|
+
session_id: session,
|
|
207
|
+
timestamp: now
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// Update statistics
|
|
211
|
+
store.updateStats(entityId, action as 'read' | 'write' | 'mention');
|
|
212
|
+
|
|
213
|
+
// Calculate heat score periodically (every 10th access)
|
|
214
|
+
const stats = store.getStats(entityId);
|
|
215
|
+
if (stats) {
|
|
216
|
+
const totalAccess = stats.read_count + stats.write_count + stats.mention_count;
|
|
217
|
+
if (totalAccess % 10 === 0) {
|
|
218
|
+
store.calculateHeatScore(entityId);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Notify server of memory update (best-effort, non-blocking)
|
|
223
|
+
notifyMemoryUpdate({
|
|
224
|
+
entityType: type,
|
|
225
|
+
entityId: String(entityId),
|
|
226
|
+
action: action
|
|
227
|
+
}).catch(() => { /* ignore errors - server may not be running */ });
|
|
228
|
+
|
|
229
|
+
if (stdin) {
|
|
230
|
+
// Silent mode for hooks - just exit successfully
|
|
231
|
+
process.exit(0);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
console.log(chalk.green('✓ Tracked:'), chalk.cyan(`${type}:${action}`), chalk.gray(value));
|
|
235
|
+
} catch (error) {
|
|
236
|
+
if (stdin) {
|
|
237
|
+
// Silent failure for hooks
|
|
238
|
+
process.exit(0);
|
|
239
|
+
}
|
|
240
|
+
console.error(chalk.red(`Error tracking: ${(error as Error).message}`));
|
|
241
|
+
process.exit(1);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Import Claude Code history
|
|
247
|
+
*/
|
|
248
|
+
async function importAction(options: ImportOptions): Promise<void> {
|
|
249
|
+
const { source = 'all', project } = options;
|
|
250
|
+
|
|
251
|
+
console.log(chalk.bold.cyan('\n Importing Claude Code History\n'));
|
|
252
|
+
console.log(chalk.gray(` Source: ${source}`));
|
|
253
|
+
if (project) {
|
|
254
|
+
console.log(chalk.gray(` Project: ${project}`));
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
try {
|
|
258
|
+
const projectPath = getProjectPath();
|
|
259
|
+
const paths = StoragePaths.project(projectPath);
|
|
260
|
+
const dbPath = join(paths.memory, 'history.db');
|
|
261
|
+
|
|
262
|
+
// Ensure memory directory exists
|
|
263
|
+
const { mkdirSync } = await import('fs');
|
|
264
|
+
if (!existsSync(paths.memory)) {
|
|
265
|
+
mkdirSync(paths.memory, { recursive: true });
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const importer = new HistoryImporter(dbPath);
|
|
269
|
+
let totalImported = 0;
|
|
270
|
+
let totalSkipped = 0;
|
|
271
|
+
let totalErrors = 0;
|
|
272
|
+
|
|
273
|
+
// Import global history
|
|
274
|
+
if (source === 'all' || source === 'history') {
|
|
275
|
+
console.log(chalk.gray('\n Importing global history...'));
|
|
276
|
+
const globalResult = await importer.importGlobalHistory();
|
|
277
|
+
totalImported += globalResult.imported;
|
|
278
|
+
totalSkipped += globalResult.skipped;
|
|
279
|
+
totalErrors += globalResult.errors;
|
|
280
|
+
console.log(chalk.gray(` Imported: ${globalResult.imported}, Skipped: ${globalResult.skipped}, Errors: ${globalResult.errors}`));
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Import project sessions
|
|
284
|
+
if (source === 'all' || source === 'sessions') {
|
|
285
|
+
const claudeHome = process.env.USERPROFILE || process.env.HOME || '';
|
|
286
|
+
const projectsDir = join(claudeHome, '.claude', 'projects');
|
|
287
|
+
|
|
288
|
+
if (existsSync(projectsDir)) {
|
|
289
|
+
const projects = project
|
|
290
|
+
? [project]
|
|
291
|
+
: readdirSync(projectsDir).filter(f => {
|
|
292
|
+
const fullPath = join(projectsDir, f);
|
|
293
|
+
return existsSync(fullPath) && require('fs').statSync(fullPath).isDirectory();
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
for (const proj of projects) {
|
|
297
|
+
console.log(chalk.gray(`\n Importing sessions for: ${proj}...`));
|
|
298
|
+
const sessionResult = await importer.importProjectSessions(proj);
|
|
299
|
+
totalImported += sessionResult.imported;
|
|
300
|
+
totalSkipped += sessionResult.skipped;
|
|
301
|
+
totalErrors += sessionResult.errors;
|
|
302
|
+
console.log(chalk.gray(` Imported: ${sessionResult.imported}, Skipped: ${sessionResult.skipped}, Errors: ${sessionResult.errors}`));
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
importer.close();
|
|
308
|
+
|
|
309
|
+
console.log(chalk.bold.green('\n Import Complete\n'));
|
|
310
|
+
console.log(chalk.gray(` Total Imported: ${totalImported}`));
|
|
311
|
+
console.log(chalk.gray(` Total Skipped: ${totalSkipped}`));
|
|
312
|
+
console.log(chalk.gray(` Total Errors: ${totalErrors}`));
|
|
313
|
+
console.log(chalk.gray(` Database: ${dbPath}\n`));
|
|
314
|
+
|
|
315
|
+
// Notify server to refresh memory data
|
|
316
|
+
if (totalImported > 0) {
|
|
317
|
+
notifyRefreshRequired('memory').catch(() => { /* ignore */ });
|
|
318
|
+
}
|
|
319
|
+
} catch (error) {
|
|
320
|
+
console.error(chalk.red(`\n Error importing: ${(error as Error).message}\n`));
|
|
321
|
+
process.exit(1);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Show hotspot statistics
|
|
327
|
+
*/
|
|
328
|
+
async function statsAction(options: StatsOptions): Promise<void> {
|
|
329
|
+
const { type, limit = '20', sort = 'heat', json } = options;
|
|
330
|
+
const limitNum = parseInt(limit, 10);
|
|
331
|
+
|
|
332
|
+
try {
|
|
333
|
+
const projectPath = getProjectPath();
|
|
334
|
+
const store = getMemoryStore(projectPath);
|
|
335
|
+
|
|
336
|
+
// Get hot entities
|
|
337
|
+
const hotEntities = store.getHotEntities(limitNum * 2); // Get more to filter
|
|
338
|
+
|
|
339
|
+
// Filter by type if specified
|
|
340
|
+
let filtered: HotEntity[] = type
|
|
341
|
+
? hotEntities.filter((e: HotEntity) => e.type === type)
|
|
342
|
+
: hotEntities;
|
|
343
|
+
|
|
344
|
+
// Sort by specified field
|
|
345
|
+
if (sort === 'reads') {
|
|
346
|
+
filtered.sort((a: HotEntity, b: HotEntity) => b.stats.read_count - a.stats.read_count);
|
|
347
|
+
} else if (sort === 'writes') {
|
|
348
|
+
filtered.sort((a: HotEntity, b: HotEntity) => b.stats.write_count - a.stats.write_count);
|
|
349
|
+
}
|
|
350
|
+
// Default is already sorted by heat_score
|
|
351
|
+
|
|
352
|
+
// Limit results
|
|
353
|
+
filtered = filtered.slice(0, limitNum);
|
|
354
|
+
|
|
355
|
+
if (json) {
|
|
356
|
+
const output = filtered.map((e: HotEntity) => ({
|
|
357
|
+
type: e.type,
|
|
358
|
+
value: e.value,
|
|
359
|
+
reads: e.stats.read_count,
|
|
360
|
+
writes: e.stats.write_count,
|
|
361
|
+
mentions: e.stats.mention_count,
|
|
362
|
+
heat: Math.round(e.stats.heat_score * 100) / 100,
|
|
363
|
+
lastSeen: e.last_seen_at
|
|
364
|
+
}));
|
|
365
|
+
console.log(JSON.stringify(output, null, 2));
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
console.log(chalk.bold.cyan('\n Memory Hotspot Statistics\n'));
|
|
370
|
+
|
|
371
|
+
if (type) {
|
|
372
|
+
console.log(chalk.gray(` Type: ${type}`));
|
|
373
|
+
}
|
|
374
|
+
console.log(chalk.gray(` Sort: ${sort} | Limit: ${limit}\n`));
|
|
375
|
+
|
|
376
|
+
if (filtered.length === 0) {
|
|
377
|
+
console.log(chalk.yellow(' No data yet. Use hooks to track file access or run:'));
|
|
378
|
+
console.log(chalk.gray(' ccw memory track --type file --action read --value "path/to/file"'));
|
|
379
|
+
console.log(chalk.gray(' ccw memory import --source all\n'));
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Display table header
|
|
384
|
+
console.log(chalk.gray(' ─────────────────────────────────────────────────────────────────'));
|
|
385
|
+
console.log(
|
|
386
|
+
chalk.bold(' Type ') +
|
|
387
|
+
chalk.bold('Heat ') +
|
|
388
|
+
chalk.bold('R ') +
|
|
389
|
+
chalk.bold('W ') +
|
|
390
|
+
chalk.bold('M ') +
|
|
391
|
+
chalk.bold('Value')
|
|
392
|
+
);
|
|
393
|
+
console.log(chalk.gray(' ─────────────────────────────────────────────────────────────────'));
|
|
394
|
+
|
|
395
|
+
for (const entity of filtered) {
|
|
396
|
+
const typeStr = entity.type.padEnd(8);
|
|
397
|
+
const heatStr = entity.stats.heat_score.toFixed(1).padStart(6);
|
|
398
|
+
const readStr = String(entity.stats.read_count).padStart(3);
|
|
399
|
+
const writeStr = String(entity.stats.write_count).padStart(3);
|
|
400
|
+
const mentionStr = String(entity.stats.mention_count).padStart(3);
|
|
401
|
+
|
|
402
|
+
// Truncate value if too long
|
|
403
|
+
const maxValueLen = 40;
|
|
404
|
+
let valueStr = entity.value;
|
|
405
|
+
if (valueStr.length > maxValueLen) {
|
|
406
|
+
valueStr = '...' + valueStr.slice(-maxValueLen + 3);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// Color based on type
|
|
410
|
+
const typeColor = entity.type === 'file' ? chalk.blue :
|
|
411
|
+
entity.type === 'module' ? chalk.magenta :
|
|
412
|
+
entity.type === 'topic' ? chalk.yellow : chalk.gray;
|
|
413
|
+
|
|
414
|
+
console.log(
|
|
415
|
+
' ' +
|
|
416
|
+
typeColor(typeStr) +
|
|
417
|
+
chalk.cyan(heatStr) + ' ' +
|
|
418
|
+
chalk.green(readStr) + ' ' +
|
|
419
|
+
chalk.red(writeStr) + ' ' +
|
|
420
|
+
chalk.yellow(mentionStr) + ' ' +
|
|
421
|
+
chalk.gray(valueStr)
|
|
422
|
+
);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
console.log(chalk.gray(' ─────────────────────────────────────────────────────────────────'));
|
|
426
|
+
console.log(chalk.gray(`\n R=Reads, W=Writes, M=Mentions, Heat=Composite score\n`));
|
|
427
|
+
|
|
428
|
+
} catch (error) {
|
|
429
|
+
if (json) {
|
|
430
|
+
console.log(JSON.stringify({ error: (error as Error).message }, null, 2));
|
|
431
|
+
} else {
|
|
432
|
+
console.error(chalk.red(`\n Error: ${(error as Error).message}\n`));
|
|
433
|
+
}
|
|
434
|
+
process.exit(1);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Search through prompt history
|
|
440
|
+
*/
|
|
441
|
+
async function searchAction(query: string | undefined, options: SearchOptions): Promise<void> {
|
|
442
|
+
if (!query) {
|
|
443
|
+
console.error(chalk.red('Error: Search query is required'));
|
|
444
|
+
console.error(chalk.gray('Usage: ccw memory search "<query>"'));
|
|
445
|
+
process.exit(1);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
const { limit = '20', json } = options;
|
|
449
|
+
const limitNum = parseInt(limit, 10);
|
|
450
|
+
|
|
451
|
+
try {
|
|
452
|
+
const projectPath = getProjectPath();
|
|
453
|
+
const store = getMemoryStore(projectPath);
|
|
454
|
+
|
|
455
|
+
// Search prompts using FTS
|
|
456
|
+
const results = store.searchPrompts(query, limitNum);
|
|
457
|
+
|
|
458
|
+
if (json) {
|
|
459
|
+
const output = results.map((p: PromptHistory) => ({
|
|
460
|
+
id: p.id,
|
|
461
|
+
sessionId: p.session_id,
|
|
462
|
+
prompt: p.prompt_text?.substring(0, 200) + (p.prompt_text && p.prompt_text.length > 200 ? '...' : ''),
|
|
463
|
+
timestamp: p.timestamp,
|
|
464
|
+
intentLabel: p.intent_label
|
|
465
|
+
}));
|
|
466
|
+
console.log(JSON.stringify(output, null, 2));
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
console.log(chalk.bold.cyan('\n Searching Prompt History\n'));
|
|
471
|
+
console.log(chalk.gray(` Query: ${query}`));
|
|
472
|
+
console.log(chalk.gray(` Limit: ${limit}\n`));
|
|
473
|
+
|
|
474
|
+
if (results.length === 0) {
|
|
475
|
+
console.log(chalk.yellow(' No results found.'));
|
|
476
|
+
console.log(chalk.gray(' Try importing history first: ccw memory import --source all\n'));
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
console.log(chalk.gray(' ─────────────────────────────────────────────────────────────────'));
|
|
481
|
+
|
|
482
|
+
for (const prompt of results) {
|
|
483
|
+
const timestamp = new Date(prompt.timestamp).toLocaleString();
|
|
484
|
+
const preview = prompt.prompt_text?.substring(0, 80).replace(/\n/g, ' ') || '(no content)';
|
|
485
|
+
|
|
486
|
+
console.log(chalk.gray(` ${timestamp}`));
|
|
487
|
+
console.log(chalk.white(` ${preview}${preview.length >= 80 ? '...' : ''}`));
|
|
488
|
+
if (prompt.intent_label) {
|
|
489
|
+
console.log(chalk.cyan(` Intent: ${prompt.intent_label}`));
|
|
490
|
+
}
|
|
491
|
+
console.log(chalk.gray(' ─────────────────────────────────────────────────────────────────'));
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
console.log(chalk.gray(`\n Found ${results.length} result(s)\n`));
|
|
495
|
+
|
|
496
|
+
} catch (error) {
|
|
497
|
+
if (json) {
|
|
498
|
+
console.log(JSON.stringify({ error: (error as Error).message }, null, 2));
|
|
499
|
+
} else {
|
|
500
|
+
console.error(chalk.red(`\n Error: ${(error as Error).message}\n`));
|
|
501
|
+
}
|
|
502
|
+
process.exit(1);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* Get optimization suggestions based on similar successful prompts
|
|
508
|
+
*/
|
|
509
|
+
async function suggestAction(options: SuggestOptions): Promise<void> {
|
|
510
|
+
const { context, limit = '5', json } = options;
|
|
511
|
+
const limitNum = parseInt(limit, 10);
|
|
512
|
+
|
|
513
|
+
try {
|
|
514
|
+
const projectPath = getProjectPath();
|
|
515
|
+
const store = getMemoryStore(projectPath);
|
|
516
|
+
|
|
517
|
+
// Get hot entities for suggestions
|
|
518
|
+
const hotEntities = store.getHotEntities(limitNum);
|
|
519
|
+
|
|
520
|
+
const suggestions = hotEntities.map((e: HotEntity) => ({
|
|
521
|
+
type: e.type,
|
|
522
|
+
value: e.value,
|
|
523
|
+
reason: `Frequently accessed (${e.stats.read_count} reads, ${e.stats.write_count} writes)`,
|
|
524
|
+
heat: e.stats.heat_score
|
|
525
|
+
}));
|
|
526
|
+
|
|
527
|
+
if (json) {
|
|
528
|
+
console.log(JSON.stringify({ suggestions, context }, null, 2));
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
console.log(chalk.bold.cyan('\n Memory Optimization Suggestions\n'));
|
|
533
|
+
|
|
534
|
+
if (context) {
|
|
535
|
+
console.log(chalk.gray(` Context: ${context}\n`));
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
if (suggestions.length === 0) {
|
|
539
|
+
console.log(chalk.yellow(' No suggestions available yet.'));
|
|
540
|
+
console.log(chalk.gray(' Track more file access to get suggestions.\n'));
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
console.log(chalk.gray(' Based on your access patterns:\n'));
|
|
545
|
+
|
|
546
|
+
for (let i = 0; i < suggestions.length; i++) {
|
|
547
|
+
const s = suggestions[i];
|
|
548
|
+
console.log(chalk.cyan(` ${i + 1}. ${s.type}: `) + chalk.white(s.value));
|
|
549
|
+
console.log(chalk.gray(` ${s.reason}`));
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
console.log(chalk.gray('\n Tip: Include frequently accessed files in your context for better results.\n'));
|
|
553
|
+
|
|
554
|
+
} catch (error) {
|
|
555
|
+
if (json) {
|
|
556
|
+
console.log(JSON.stringify({ error: (error as Error).message }, null, 2));
|
|
557
|
+
} else {
|
|
558
|
+
console.error(chalk.red(`\n Error: ${(error as Error).message}\n`));
|
|
559
|
+
}
|
|
560
|
+
process.exit(1);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
/**
|
|
565
|
+
* Parse age string to milliseconds
|
|
566
|
+
*/
|
|
567
|
+
function parseAge(ageStr: string): number {
|
|
568
|
+
const match = ageStr.match(/^(\d+)([dhm])$/);
|
|
569
|
+
if (!match) {
|
|
570
|
+
throw new Error(`Invalid age format: ${ageStr}. Use format like 30d, 24h, or 60m`);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
const value = parseInt(match[1], 10);
|
|
574
|
+
const unit = match[2];
|
|
575
|
+
|
|
576
|
+
switch (unit) {
|
|
577
|
+
case 'd': return value * 24 * 60 * 60 * 1000;
|
|
578
|
+
case 'h': return value * 60 * 60 * 1000;
|
|
579
|
+
case 'm': return value * 60 * 1000;
|
|
580
|
+
default: throw new Error(`Unknown unit: ${unit}`);
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/**
|
|
585
|
+
* Clean up old data
|
|
586
|
+
*/
|
|
587
|
+
async function pruneAction(options: PruneOptions): Promise<void> {
|
|
588
|
+
const { olderThan = '30d', dryRun } = options;
|
|
589
|
+
|
|
590
|
+
console.log(chalk.bold.cyan('\n Pruning Memory Data\n'));
|
|
591
|
+
console.log(chalk.gray(` Older than: ${olderThan}`));
|
|
592
|
+
console.log(chalk.gray(` Mode: ${dryRun ? 'Dry run (preview)' : 'Delete'}\n`));
|
|
593
|
+
|
|
594
|
+
try {
|
|
595
|
+
const ageMs = parseAge(olderThan);
|
|
596
|
+
const cutoffDate = new Date(Date.now() - ageMs);
|
|
597
|
+
const cutoffStr = cutoffDate.toISOString();
|
|
598
|
+
|
|
599
|
+
const projectPath = getProjectPath();
|
|
600
|
+
const paths = StoragePaths.project(projectPath);
|
|
601
|
+
|
|
602
|
+
if (!existsSync(paths.memoryDb)) {
|
|
603
|
+
console.log(chalk.yellow(' No memory database found. Nothing to prune.\n'));
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
// Use direct database access for pruning
|
|
608
|
+
const Database = require('better-sqlite3');
|
|
609
|
+
const db = new Database(paths.memoryDb);
|
|
610
|
+
|
|
611
|
+
// Count records to prune
|
|
612
|
+
const accessLogsCount = db.prepare(`
|
|
613
|
+
SELECT COUNT(*) as count FROM access_logs WHERE timestamp < ?
|
|
614
|
+
`).get(cutoffStr) as { count: number };
|
|
615
|
+
|
|
616
|
+
const entitiesCount = db.prepare(`
|
|
617
|
+
SELECT COUNT(*) as count FROM entities WHERE last_seen_at < ?
|
|
618
|
+
`).get(cutoffStr) as { count: number };
|
|
619
|
+
|
|
620
|
+
console.log(chalk.gray(` Access logs to prune: ${accessLogsCount.count}`));
|
|
621
|
+
console.log(chalk.gray(` Entities to prune: ${entitiesCount.count}`));
|
|
622
|
+
|
|
623
|
+
if (dryRun) {
|
|
624
|
+
console.log(chalk.yellow('\n Dry run - no changes made.\n'));
|
|
625
|
+
db.close();
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
if (accessLogsCount.count === 0 && entitiesCount.count === 0) {
|
|
630
|
+
console.log(chalk.green('\n Nothing to prune.\n'));
|
|
631
|
+
db.close();
|
|
632
|
+
return;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
// Delete old access logs
|
|
636
|
+
const deleteAccessLogs = db.prepare(`DELETE FROM access_logs WHERE timestamp < ?`);
|
|
637
|
+
const accessResult = deleteAccessLogs.run(cutoffStr);
|
|
638
|
+
|
|
639
|
+
// Delete entities not seen recently (and their stats)
|
|
640
|
+
const deleteStats = db.prepare(`
|
|
641
|
+
DELETE FROM entity_stats WHERE entity_id IN (
|
|
642
|
+
SELECT id FROM entities WHERE last_seen_at < ?
|
|
643
|
+
)
|
|
644
|
+
`);
|
|
645
|
+
deleteStats.run(cutoffStr);
|
|
646
|
+
|
|
647
|
+
const deleteEntities = db.prepare(`DELETE FROM entities WHERE last_seen_at < ?`);
|
|
648
|
+
const entitiesResult = deleteEntities.run(cutoffStr);
|
|
649
|
+
|
|
650
|
+
db.close();
|
|
651
|
+
|
|
652
|
+
console.log(chalk.green(`\n Pruned ${accessResult.changes} access logs`));
|
|
653
|
+
console.log(chalk.green(` Pruned ${entitiesResult.changes} entities\n`));
|
|
654
|
+
|
|
655
|
+
// Notify server to refresh memory data
|
|
656
|
+
if (accessResult.changes > 0 || entitiesResult.changes > 0) {
|
|
657
|
+
notifyRefreshRequired('memory').catch(() => { /* ignore */ });
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
} catch (error) {
|
|
661
|
+
console.error(chalk.red(`\n Error: ${(error as Error).message}\n`));
|
|
662
|
+
process.exit(1);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
/**
|
|
667
|
+
* Chunk and prepare memories for embedding
|
|
668
|
+
*/
|
|
669
|
+
async function chunkMemoriesForEmbedding(projectPath: string, sourceId?: string, force?: boolean): Promise<number> {
|
|
670
|
+
const coreMemoryStore = getCoreMemoryStore(projectPath);
|
|
671
|
+
let chunksCreated = 0;
|
|
672
|
+
|
|
673
|
+
// 1. Chunk core memories
|
|
674
|
+
const memories = coreMemoryStore.getMemories({ archived: false, limit: 1000 });
|
|
675
|
+
for (const memory of memories) {
|
|
676
|
+
if (sourceId && memory.id !== sourceId) continue;
|
|
677
|
+
|
|
678
|
+
// Check if already chunked (skip unless force)
|
|
679
|
+
const existingChunks = coreMemoryStore.getChunks(memory.id);
|
|
680
|
+
if (existingChunks.length > 0 && !force) continue;
|
|
681
|
+
|
|
682
|
+
// Delete old chunks if force
|
|
683
|
+
if (force && existingChunks.length > 0) {
|
|
684
|
+
coreMemoryStore.deleteChunks(memory.id);
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
// Chunk the memory content
|
|
688
|
+
const chunks = coreMemoryStore.chunkContent(memory.content, memory.id, 'core_memory');
|
|
689
|
+
|
|
690
|
+
// Insert chunks
|
|
691
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
692
|
+
coreMemoryStore.insertChunk({
|
|
693
|
+
source_id: memory.id,
|
|
694
|
+
source_type: 'core_memory',
|
|
695
|
+
chunk_index: i,
|
|
696
|
+
content: chunks[i],
|
|
697
|
+
created_at: new Date().toISOString()
|
|
698
|
+
});
|
|
699
|
+
chunksCreated++;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
// 2. Chunk CLI history
|
|
704
|
+
try {
|
|
705
|
+
const cliHistoryStore = new CliHistoryStore(projectPath);
|
|
706
|
+
const history = cliHistoryStore.getHistory({ limit: 500 });
|
|
707
|
+
|
|
708
|
+
for (const exec of history.executions) {
|
|
709
|
+
if (sourceId && exec.id !== sourceId) continue;
|
|
710
|
+
|
|
711
|
+
// Check if already chunked
|
|
712
|
+
const existingChunks = coreMemoryStore.getChunks(exec.id);
|
|
713
|
+
if (existingChunks.length > 0 && !force) continue;
|
|
714
|
+
|
|
715
|
+
// Delete old chunks if force
|
|
716
|
+
if (force && existingChunks.length > 0) {
|
|
717
|
+
coreMemoryStore.deleteChunks(exec.id);
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
// Get conversation content
|
|
721
|
+
const conversation = cliHistoryStore.getConversation(exec.id);
|
|
722
|
+
if (!conversation || !conversation.turns || conversation.turns.length === 0) continue;
|
|
723
|
+
|
|
724
|
+
// Create content from turns
|
|
725
|
+
const content = conversation.turns
|
|
726
|
+
.map((t: any) => `Prompt: ${t.prompt}\nOutput: ${(t.stdout || '').substring(0, 500)}`)
|
|
727
|
+
.join('\n---\n');
|
|
728
|
+
|
|
729
|
+
// Chunk the content
|
|
730
|
+
const chunks = coreMemoryStore.chunkContent(content, exec.id, 'cli_history');
|
|
731
|
+
|
|
732
|
+
// Insert chunks
|
|
733
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
734
|
+
coreMemoryStore.insertChunk({
|
|
735
|
+
source_id: exec.id,
|
|
736
|
+
source_type: 'cli_history',
|
|
737
|
+
chunk_index: i,
|
|
738
|
+
content: chunks[i],
|
|
739
|
+
created_at: new Date().toISOString()
|
|
740
|
+
});
|
|
741
|
+
chunksCreated++;
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
} catch {
|
|
745
|
+
// CLI history might not exist, continue
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
return chunksCreated;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
/**
|
|
752
|
+
* Generate embeddings for memory chunks
|
|
753
|
+
*/
|
|
754
|
+
async function embedAction(options: EmbedCommandOptions): Promise<void> {
|
|
755
|
+
const { id, force, batchSize } = options;
|
|
756
|
+
|
|
757
|
+
try {
|
|
758
|
+
// Check embedder availability
|
|
759
|
+
if (!isEmbedderAvailable()) {
|
|
760
|
+
console.error(chalk.red('\nError: Memory embedder not available'));
|
|
761
|
+
console.error(chalk.gray('Ensure CodexLens venv exists at ~/.codexlens/venv\n'));
|
|
762
|
+
process.exit(1);
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
const projectPath = getProjectPath();
|
|
766
|
+
const paths = StoragePaths.project(projectPath);
|
|
767
|
+
const dbPath = join(paths.root, 'core-memory', 'core_memory.db');
|
|
768
|
+
|
|
769
|
+
if (!existsSync(dbPath)) {
|
|
770
|
+
console.error(chalk.red('\nError: Core memory database not found'));
|
|
771
|
+
console.error(chalk.gray('Create memories first using "ccw core-memory import"\n'));
|
|
772
|
+
process.exit(1);
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
// Step 1: Chunk memories first
|
|
776
|
+
console.log(chalk.cyan('Chunking memories...'));
|
|
777
|
+
const chunksCreated = await chunkMemoriesForEmbedding(projectPath, id, force);
|
|
778
|
+
if (chunksCreated > 0) {
|
|
779
|
+
console.log(chalk.green(` Created ${chunksCreated} new chunks`));
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
// Step 2: Generate embeddings
|
|
783
|
+
console.log(chalk.cyan('Generating embeddings...'));
|
|
784
|
+
|
|
785
|
+
const embedOptions: EmbedOptions = {
|
|
786
|
+
sourceId: id,
|
|
787
|
+
force: force || false,
|
|
788
|
+
batchSize: batchSize ? parseInt(batchSize, 10) : 8
|
|
789
|
+
};
|
|
790
|
+
|
|
791
|
+
const result = await generateEmbeddings(dbPath, embedOptions);
|
|
792
|
+
|
|
793
|
+
if (!result.success) {
|
|
794
|
+
console.error(chalk.red(`\nError: ${result.error}\n`));
|
|
795
|
+
process.exit(1);
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
console.log(chalk.green(`\n✓ Processed ${result.chunks_processed} chunks in ${result.elapsed_time.toFixed(1)}s`));
|
|
799
|
+
|
|
800
|
+
// Get status to show breakdown by type
|
|
801
|
+
const status = await getEmbeddingStatus(dbPath);
|
|
802
|
+
if (status.success && Object.keys(status.by_type).length > 0) {
|
|
803
|
+
for (const [type, stats] of Object.entries(status.by_type)) {
|
|
804
|
+
if (stats.total > 0) {
|
|
805
|
+
console.log(chalk.white(` - ${type}: ${stats.embedded} chunks`));
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
console.log();
|
|
810
|
+
|
|
811
|
+
} catch (error) {
|
|
812
|
+
console.error(chalk.red(`\nError: ${(error as Error).message}\n`));
|
|
813
|
+
process.exit(1);
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
/**
|
|
818
|
+
* Search memories using semantic search
|
|
819
|
+
*/
|
|
820
|
+
async function searchEmbedAction(query: string | undefined, options: SearchCommandOptions): Promise<void> {
|
|
821
|
+
if (!query) {
|
|
822
|
+
console.error(chalk.red('Error: Search query is required'));
|
|
823
|
+
console.error(chalk.gray('Usage: ccw memory search "<query>"'));
|
|
824
|
+
process.exit(1);
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
const { topK = '10', type, minScore = '0.5', json } = options;
|
|
828
|
+
|
|
829
|
+
try {
|
|
830
|
+
// Check embedder availability
|
|
831
|
+
if (!isEmbedderAvailable()) {
|
|
832
|
+
console.error(chalk.red('\nError: Memory embedder not available'));
|
|
833
|
+
console.error(chalk.gray('Ensure CodexLens venv exists at ~/.codexlens/venv\n'));
|
|
834
|
+
process.exit(1);
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
const projectPath = getProjectPath();
|
|
838
|
+
const paths = StoragePaths.project(projectPath);
|
|
839
|
+
const dbPath = join(paths.root, 'core-memory', 'core_memory.db');
|
|
840
|
+
|
|
841
|
+
if (!existsSync(dbPath)) {
|
|
842
|
+
console.error(chalk.red('\nError: Core memory database not found'));
|
|
843
|
+
console.error(chalk.gray('Create memories first using "ccw core-memory import"\n'));
|
|
844
|
+
process.exit(1);
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
const searchOptions: EmbedSearchOptions = {
|
|
848
|
+
topK: parseInt(topK, 10),
|
|
849
|
+
minScore: parseFloat(minScore),
|
|
850
|
+
sourceType: type
|
|
851
|
+
};
|
|
852
|
+
|
|
853
|
+
const result = await searchMemories(dbPath, query, searchOptions);
|
|
854
|
+
|
|
855
|
+
if (!result.success) {
|
|
856
|
+
console.error(chalk.red(`\nError: ${result.error}\n`));
|
|
857
|
+
process.exit(1);
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
if (json) {
|
|
861
|
+
const output = result.matches.map(m => ({
|
|
862
|
+
sourceId: m.source_id,
|
|
863
|
+
sourceType: m.source_type,
|
|
864
|
+
score: m.score,
|
|
865
|
+
content: m.content,
|
|
866
|
+
restoreCommand: m.restore_command
|
|
867
|
+
}));
|
|
868
|
+
console.log(JSON.stringify(output, null, 2));
|
|
869
|
+
return;
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
console.log(chalk.bold.cyan(`\nFound ${result.matches.length} matches for "${query}":\n`));
|
|
873
|
+
|
|
874
|
+
if (result.matches.length === 0) {
|
|
875
|
+
console.log(chalk.yellow('No results found. Try:'));
|
|
876
|
+
console.log(chalk.gray(' - Using different keywords'));
|
|
877
|
+
console.log(chalk.gray(' - Lowering --min-score threshold'));
|
|
878
|
+
console.log(chalk.gray(' - Running "ccw memory embed" to generate embeddings\n'));
|
|
879
|
+
return;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
for (let i = 0; i < result.matches.length; i++) {
|
|
883
|
+
const match = result.matches[i];
|
|
884
|
+
const preview = match.content.length > 80
|
|
885
|
+
? match.content.substring(0, 80) + '...'
|
|
886
|
+
: match.content;
|
|
887
|
+
|
|
888
|
+
console.log(chalk.bold.white(`${i + 1}. [${match.score.toFixed(2)}] ${match.source_id}`) + chalk.gray(` (${match.source_type})`));
|
|
889
|
+
console.log(chalk.white(` "${preview}"`));
|
|
890
|
+
console.log(chalk.cyan(` → ${match.restore_command}`));
|
|
891
|
+
console.log();
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
} catch (error) {
|
|
895
|
+
if (json) {
|
|
896
|
+
console.log(JSON.stringify({ error: (error as Error).message }, null, 2));
|
|
897
|
+
} else {
|
|
898
|
+
console.error(chalk.red(`\nError: ${(error as Error).message}\n`));
|
|
899
|
+
}
|
|
900
|
+
process.exit(1);
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
/**
|
|
905
|
+
* Show embedding status
|
|
906
|
+
*/
|
|
907
|
+
async function embedStatusAction(options: EmbedStatusOptions): Promise<void> {
|
|
908
|
+
const { json } = options;
|
|
909
|
+
|
|
910
|
+
try {
|
|
911
|
+
// Check embedder availability
|
|
912
|
+
if (!isEmbedderAvailable()) {
|
|
913
|
+
console.error(chalk.red('\nError: Memory embedder not available'));
|
|
914
|
+
console.error(chalk.gray('Ensure CodexLens venv exists at ~/.codexlens/venv\n'));
|
|
915
|
+
process.exit(1);
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
const projectPath = getProjectPath();
|
|
919
|
+
const paths = StoragePaths.project(projectPath);
|
|
920
|
+
const dbPath = join(paths.root, 'core-memory', 'core_memory.db');
|
|
921
|
+
|
|
922
|
+
if (!existsSync(dbPath)) {
|
|
923
|
+
console.error(chalk.red('\nError: Core memory database not found'));
|
|
924
|
+
console.error(chalk.gray('Create memories first using "ccw core-memory import"\n'));
|
|
925
|
+
process.exit(1);
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
const status = await getEmbeddingStatus(dbPath);
|
|
929
|
+
|
|
930
|
+
if (!status.success) {
|
|
931
|
+
console.error(chalk.red(`\nError: ${status.error}\n`));
|
|
932
|
+
process.exit(1);
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
if (json) {
|
|
936
|
+
console.log(JSON.stringify(status, null, 2));
|
|
937
|
+
return;
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
const embeddedPercent = status.total_chunks > 0
|
|
941
|
+
? Math.round((status.embedded_chunks / status.total_chunks) * 100)
|
|
942
|
+
: 0;
|
|
943
|
+
|
|
944
|
+
console.log(chalk.bold.cyan('\nEmbedding Status:'));
|
|
945
|
+
console.log(chalk.white(` Total chunks: ${status.total_chunks}`));
|
|
946
|
+
console.log(chalk.white(` Embedded: ${status.embedded_chunks} (${embeddedPercent}%)`));
|
|
947
|
+
console.log(chalk.white(` Pending: ${status.pending_chunks}`));
|
|
948
|
+
|
|
949
|
+
if (Object.keys(status.by_type).length > 0) {
|
|
950
|
+
console.log(chalk.bold.white('\nBy Type:'));
|
|
951
|
+
for (const [type, stats] of Object.entries(status.by_type)) {
|
|
952
|
+
const typePercent = stats.total > 0
|
|
953
|
+
? Math.round((stats.embedded / stats.total) * 100)
|
|
954
|
+
: 0;
|
|
955
|
+
console.log(chalk.cyan(` ${type}: `) + chalk.white(`${stats.embedded}/${stats.total} (${typePercent}%)`));
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
console.log();
|
|
959
|
+
|
|
960
|
+
} catch (error) {
|
|
961
|
+
if (json) {
|
|
962
|
+
console.log(JSON.stringify({ error: (error as Error).message }, null, 2));
|
|
963
|
+
} else {
|
|
964
|
+
console.error(chalk.red(`\nError: ${(error as Error).message}\n`));
|
|
965
|
+
}
|
|
966
|
+
process.exit(1);
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
/**
|
|
971
|
+
* Memory command entry point
|
|
972
|
+
* @param {string} subcommand - Subcommand (track, import, stats, search, suggest, prune, embed, embed-status)
|
|
973
|
+
* @param {string|string[]} args - Arguments array
|
|
974
|
+
* @param {Object} options - CLI options
|
|
975
|
+
*/
|
|
976
|
+
export async function memoryCommand(
|
|
977
|
+
subcommand: string,
|
|
978
|
+
args: string | string[],
|
|
979
|
+
options: TrackOptions | ImportOptions | StatsOptions | SearchOptions | SuggestOptions | PruneOptions | EmbedCommandOptions | SearchCommandOptions | EmbedStatusOptions
|
|
980
|
+
): Promise<void> {
|
|
981
|
+
const argsArray = Array.isArray(args) ? args : (args ? [args] : []);
|
|
982
|
+
|
|
983
|
+
switch (subcommand) {
|
|
984
|
+
case 'track':
|
|
985
|
+
await trackAction(options as TrackOptions);
|
|
986
|
+
break;
|
|
987
|
+
|
|
988
|
+
case 'import':
|
|
989
|
+
await importAction(options as ImportOptions);
|
|
990
|
+
break;
|
|
991
|
+
|
|
992
|
+
case 'stats':
|
|
993
|
+
await statsAction(options as StatsOptions);
|
|
994
|
+
break;
|
|
995
|
+
|
|
996
|
+
case 'search':
|
|
997
|
+
// Check if this is semantic search (has --top-k or --min-score) or prompt history search
|
|
998
|
+
if ('topK' in options || 'minScore' in options) {
|
|
999
|
+
await searchEmbedAction(argsArray[0], options as SearchCommandOptions);
|
|
1000
|
+
} else {
|
|
1001
|
+
await searchAction(argsArray[0], options as SearchOptions);
|
|
1002
|
+
}
|
|
1003
|
+
break;
|
|
1004
|
+
|
|
1005
|
+
case 'suggest':
|
|
1006
|
+
await suggestAction(options as SuggestOptions);
|
|
1007
|
+
break;
|
|
1008
|
+
|
|
1009
|
+
case 'prune':
|
|
1010
|
+
await pruneAction(options as PruneOptions);
|
|
1011
|
+
break;
|
|
1012
|
+
|
|
1013
|
+
case 'embed':
|
|
1014
|
+
await embedAction(options as EmbedCommandOptions);
|
|
1015
|
+
break;
|
|
1016
|
+
|
|
1017
|
+
case 'embed-status':
|
|
1018
|
+
await embedStatusAction(options as EmbedStatusOptions);
|
|
1019
|
+
break;
|
|
1020
|
+
|
|
1021
|
+
default:
|
|
1022
|
+
console.log(chalk.bold.cyan('\n CCW Memory Module\n'));
|
|
1023
|
+
console.log(' Context tracking and prompt optimization.\n');
|
|
1024
|
+
console.log(' Subcommands:');
|
|
1025
|
+
console.log(chalk.gray(' track Track entity access (used by hooks)'));
|
|
1026
|
+
console.log(chalk.gray(' import Import Claude Code history'));
|
|
1027
|
+
console.log(chalk.gray(' stats Show hotspot statistics'));
|
|
1028
|
+
console.log(chalk.gray(' search <query> Search through prompt history (semantic or FTS)'));
|
|
1029
|
+
console.log(chalk.gray(' suggest Get optimization suggestions'));
|
|
1030
|
+
console.log(chalk.gray(' prune Clean up old data'));
|
|
1031
|
+
console.log(chalk.gray(' embed Generate embeddings for semantic search'));
|
|
1032
|
+
console.log(chalk.gray(' embed-status Show embedding generation status'));
|
|
1033
|
+
console.log();
|
|
1034
|
+
console.log(' Track Options:');
|
|
1035
|
+
console.log(chalk.gray(' --type <type> Entity type: file, module, topic'));
|
|
1036
|
+
console.log(chalk.gray(' --action <action> Action: read, write, mention'));
|
|
1037
|
+
console.log(chalk.gray(' --value <value> Entity value (file path, etc.)'));
|
|
1038
|
+
console.log(chalk.gray(' --session <id> Session ID (optional)'));
|
|
1039
|
+
console.log();
|
|
1040
|
+
console.log(' Import Options:');
|
|
1041
|
+
console.log(chalk.gray(' --source <source> Source: history, sessions, all (default: all)'));
|
|
1042
|
+
console.log(chalk.gray(' --project <name> Project name filter (optional)'));
|
|
1043
|
+
console.log();
|
|
1044
|
+
console.log(' Stats Options:');
|
|
1045
|
+
console.log(chalk.gray(' --type <type> Filter: file, module, topic (optional)'));
|
|
1046
|
+
console.log(chalk.gray(' --limit <n> Number of results (default: 20)'));
|
|
1047
|
+
console.log(chalk.gray(' --sort <field> Sort by: heat, reads, writes (default: heat)'));
|
|
1048
|
+
console.log(chalk.gray(' --json Output as JSON'));
|
|
1049
|
+
console.log();
|
|
1050
|
+
console.log(' Search Options (Prompt History):');
|
|
1051
|
+
console.log(chalk.gray(' --limit <n> Number of results (default: 20)'));
|
|
1052
|
+
console.log(chalk.gray(' --json Output as JSON'));
|
|
1053
|
+
console.log();
|
|
1054
|
+
console.log(' Search Options (Semantic - requires embeddings):');
|
|
1055
|
+
console.log(chalk.gray(' --top-k <n> Number of results (default: 10)'));
|
|
1056
|
+
console.log(chalk.gray(' --min-score <f> Minimum similarity score (default: 0.5)'));
|
|
1057
|
+
console.log(chalk.gray(' --type <type> Filter: core_memory, workflow, cli_history'));
|
|
1058
|
+
console.log(chalk.gray(' --json Output as JSON'));
|
|
1059
|
+
console.log();
|
|
1060
|
+
console.log(' Embed Options:');
|
|
1061
|
+
console.log(chalk.gray(' --id <id> Specific memory/session ID to embed'));
|
|
1062
|
+
console.log(chalk.gray(' --force Force re-embed all chunks'));
|
|
1063
|
+
console.log(chalk.gray(' --batch-size <n> Batch size for embedding (default: 8)'));
|
|
1064
|
+
console.log();
|
|
1065
|
+
console.log(' Embed Status Options:');
|
|
1066
|
+
console.log(chalk.gray(' --json Output as JSON'));
|
|
1067
|
+
console.log();
|
|
1068
|
+
console.log(' Suggest Options:');
|
|
1069
|
+
console.log(chalk.gray(' --context <text> Current task context (optional)'));
|
|
1070
|
+
console.log(chalk.gray(' --limit <n> Number of suggestions (default: 5)'));
|
|
1071
|
+
console.log(chalk.gray(' --json Output as JSON'));
|
|
1072
|
+
console.log();
|
|
1073
|
+
console.log(' Prune Options:');
|
|
1074
|
+
console.log(chalk.gray(' --older-than <age> Age threshold (default: 30d)'));
|
|
1075
|
+
console.log(chalk.gray(' --dry-run Preview without deleting'));
|
|
1076
|
+
console.log();
|
|
1077
|
+
console.log(' Examples:');
|
|
1078
|
+
console.log(chalk.gray(' ccw memory track --type file --action read --value "src/auth.ts"'));
|
|
1079
|
+
console.log(chalk.gray(' ccw memory import --source history --project "my-app"'));
|
|
1080
|
+
console.log(chalk.gray(' ccw memory stats --type file --sort heat --limit 10'));
|
|
1081
|
+
console.log(chalk.gray(' ccw memory search "authentication patterns" # FTS search'));
|
|
1082
|
+
console.log(chalk.gray(' ccw memory embed # Generate all embeddings'));
|
|
1083
|
+
console.log(chalk.gray(' ccw memory embed --id CMEM-xxx # Embed specific memory'));
|
|
1084
|
+
console.log(chalk.gray(' ccw memory embed-status # Check embedding status'));
|
|
1085
|
+
console.log(chalk.gray(' ccw memory search "auth patterns" --top-k 5 # Semantic search'));
|
|
1086
|
+
console.log(chalk.gray(' ccw memory suggest --context "implementing JWT auth"'));
|
|
1087
|
+
console.log(chalk.gray(' ccw memory prune --older-than 60d --dry-run'));
|
|
1088
|
+
console.log();
|
|
1089
|
+
}
|
|
1090
|
+
}
|