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,294 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, statSync } from 'fs';
|
|
2
|
+
import { join, dirname } from 'path';
|
|
3
|
+
import { StoragePaths, ensureStorageDir } from '../config/storage-paths.js';
|
|
4
|
+
|
|
5
|
+
interface CacheEntry<T> {
|
|
6
|
+
data: T;
|
|
7
|
+
timestamp: number;
|
|
8
|
+
fileHashes: Map<string, number>; // file path -> mtime
|
|
9
|
+
ttl?: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface CacheOptions {
|
|
13
|
+
ttl?: number; // Time-to-live in milliseconds (default: 5 minutes)
|
|
14
|
+
cacheDir?: string; // Cache directory (default: .ccw-cache)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* CacheManager class for storing and retrieving dashboard data
|
|
19
|
+
* Tracks file modification times to detect changes and invalidate cache
|
|
20
|
+
*/
|
|
21
|
+
export class CacheManager<T> {
|
|
22
|
+
private cacheFile: string;
|
|
23
|
+
private ttl: number;
|
|
24
|
+
private cacheDir: string;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Create a new CacheManager instance
|
|
28
|
+
* @param cacheKey - Unique identifier for this cache (e.g., 'dashboard-data')
|
|
29
|
+
* @param options - Cache configuration options
|
|
30
|
+
*/
|
|
31
|
+
constructor(cacheKey: string, options: CacheOptions = {}) {
|
|
32
|
+
if (!options.cacheDir) {
|
|
33
|
+
throw new Error('CacheManager requires cacheDir option. Use StoragePaths.project(path).cache');
|
|
34
|
+
}
|
|
35
|
+
this.ttl = options.ttl || 5 * 60 * 1000; // Default: 5 minutes
|
|
36
|
+
this.cacheDir = options.cacheDir;
|
|
37
|
+
this.cacheFile = join(this.cacheDir, `${cacheKey}.json`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Get cached data if valid, otherwise return null
|
|
42
|
+
* @param watchPaths - Array of file/directory paths to check for modifications
|
|
43
|
+
* @returns Cached data or null if invalid/expired
|
|
44
|
+
*/
|
|
45
|
+
get(watchPaths: string[] = []): T | null {
|
|
46
|
+
if (!existsSync(this.cacheFile)) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
const content = readFileSync(this.cacheFile, 'utf8');
|
|
52
|
+
const entry: CacheEntry<T> = JSON.parse(content, (key, value) => {
|
|
53
|
+
// Revive Map objects from JSON
|
|
54
|
+
if (key === 'fileHashes' && value && typeof value === 'object') {
|
|
55
|
+
return new Map(Object.entries(value));
|
|
56
|
+
}
|
|
57
|
+
return value;
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Check TTL expiration
|
|
61
|
+
if (this.ttl > 0) {
|
|
62
|
+
const age = Date.now() - entry.timestamp;
|
|
63
|
+
if (age > this.ttl) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Check if any watched files have changed
|
|
69
|
+
if (watchPaths.length > 0) {
|
|
70
|
+
const currentHashes = this.computeFileHashes(watchPaths);
|
|
71
|
+
if (!this.hashesMatch(entry.fileHashes, currentHashes)) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return entry.data;
|
|
77
|
+
} catch (err) {
|
|
78
|
+
// If cache file is corrupted or unreadable, treat as invalid
|
|
79
|
+
console.warn(`Cache read error for ${this.cacheFile}:`, (err as Error).message);
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Store data in cache with current timestamp and file hashes
|
|
86
|
+
* @param data - Data to cache
|
|
87
|
+
* @param watchPaths - Array of file/directory paths to track
|
|
88
|
+
*/
|
|
89
|
+
set(data: T, watchPaths: string[] = []): void {
|
|
90
|
+
try {
|
|
91
|
+
// Ensure cache directory exists
|
|
92
|
+
if (!existsSync(this.cacheDir)) {
|
|
93
|
+
mkdirSync(this.cacheDir, { recursive: true });
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const entry: CacheEntry<T> = {
|
|
97
|
+
data,
|
|
98
|
+
timestamp: Date.now(),
|
|
99
|
+
fileHashes: this.computeFileHashes(watchPaths),
|
|
100
|
+
ttl: this.ttl
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
// Convert Map to plain object for JSON serialization
|
|
104
|
+
const serializable = {
|
|
105
|
+
...entry,
|
|
106
|
+
fileHashes: Object.fromEntries(entry.fileHashes)
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
writeFileSync(this.cacheFile, JSON.stringify(serializable, null, 2), 'utf8');
|
|
110
|
+
} catch (err) {
|
|
111
|
+
console.warn(`Cache write error for ${this.cacheFile}:`, (err as Error).message);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Invalidate (delete) the cache
|
|
117
|
+
*/
|
|
118
|
+
invalidate(): void {
|
|
119
|
+
try {
|
|
120
|
+
if (existsSync(this.cacheFile)) {
|
|
121
|
+
const fs = require('fs');
|
|
122
|
+
fs.unlinkSync(this.cacheFile);
|
|
123
|
+
}
|
|
124
|
+
} catch (err) {
|
|
125
|
+
console.warn(`Cache invalidation error for ${this.cacheFile}:`, (err as Error).message);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Check if cache is valid without retrieving data
|
|
131
|
+
* @param watchPaths - Array of file/directory paths to check
|
|
132
|
+
* @returns True if cache exists and is valid
|
|
133
|
+
*/
|
|
134
|
+
isValid(watchPaths: string[] = []): boolean {
|
|
135
|
+
return this.get(watchPaths) !== null;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Compute file modification times for all watched paths
|
|
140
|
+
* @param watchPaths - Array of file/directory paths
|
|
141
|
+
* @returns Map of path to mtime
|
|
142
|
+
*/
|
|
143
|
+
private computeFileHashes(watchPaths: string[]): Map<string, number> {
|
|
144
|
+
const hashes = new Map<string, number>();
|
|
145
|
+
|
|
146
|
+
for (const path of watchPaths) {
|
|
147
|
+
try {
|
|
148
|
+
if (!existsSync(path)) {
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const stats = statSync(path);
|
|
153
|
+
|
|
154
|
+
if (stats.isDirectory()) {
|
|
155
|
+
// For directories, use directory mtime (detects file additions/deletions)
|
|
156
|
+
hashes.set(path, stats.mtimeMs);
|
|
157
|
+
|
|
158
|
+
// Also recursively scan for workflow session files
|
|
159
|
+
this.scanDirectory(path, hashes);
|
|
160
|
+
} else {
|
|
161
|
+
// For files, use file mtime
|
|
162
|
+
hashes.set(path, stats.mtimeMs);
|
|
163
|
+
}
|
|
164
|
+
} catch (err) {
|
|
165
|
+
// Skip paths that can't be accessed
|
|
166
|
+
console.warn(`Cannot access path ${path}:`, (err as Error).message);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return hashes;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Recursively scan directory for important files
|
|
175
|
+
* @param dirPath - Directory to scan
|
|
176
|
+
* @param hashes - Map to store file hashes
|
|
177
|
+
* @param depth - Current recursion depth (max 3)
|
|
178
|
+
*/
|
|
179
|
+
private scanDirectory(dirPath: string, hashes: Map<string, number>, depth: number = 0): void {
|
|
180
|
+
if (depth > 3) return; // Limit recursion depth
|
|
181
|
+
|
|
182
|
+
try {
|
|
183
|
+
const fs = require('fs');
|
|
184
|
+
const entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
185
|
+
|
|
186
|
+
for (const entry of entries) {
|
|
187
|
+
const fullPath = join(dirPath, entry.name);
|
|
188
|
+
|
|
189
|
+
if (entry.isDirectory()) {
|
|
190
|
+
// Track important directories
|
|
191
|
+
if (entry.name === '.task' || entry.name === '.review' || entry.name === '.summaries') {
|
|
192
|
+
const stats = statSync(fullPath);
|
|
193
|
+
hashes.set(fullPath, stats.mtimeMs);
|
|
194
|
+
this.scanDirectory(fullPath, hashes, depth + 1);
|
|
195
|
+
} else if (entry.name.startsWith('WFS-')) {
|
|
196
|
+
// Scan WFS session directories
|
|
197
|
+
const stats = statSync(fullPath);
|
|
198
|
+
hashes.set(fullPath, stats.mtimeMs);
|
|
199
|
+
this.scanDirectory(fullPath, hashes, depth + 1);
|
|
200
|
+
}
|
|
201
|
+
} else if (entry.isFile()) {
|
|
202
|
+
// Track important files
|
|
203
|
+
if (
|
|
204
|
+
entry.name.endsWith('.json') ||
|
|
205
|
+
entry.name === 'IMPL_PLAN.md' ||
|
|
206
|
+
entry.name === 'TODO_LIST.md' ||
|
|
207
|
+
entry.name === 'workflow-session.json'
|
|
208
|
+
) {
|
|
209
|
+
const stats = statSync(fullPath);
|
|
210
|
+
hashes.set(fullPath, stats.mtimeMs);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
} catch (err) {
|
|
215
|
+
// Skip directories that can't be read
|
|
216
|
+
console.warn(`Cannot scan directory ${dirPath}:`, (err as Error).message);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Compare two file hash maps
|
|
222
|
+
* @param oldHashes - Previous hashes
|
|
223
|
+
* @param newHashes - Current hashes
|
|
224
|
+
* @returns True if hashes match (no changes)
|
|
225
|
+
*/
|
|
226
|
+
private hashesMatch(oldHashes: Map<string, number>, newHashes: Map<string, number>): boolean {
|
|
227
|
+
// Check if any files were added or removed
|
|
228
|
+
if (oldHashes.size !== newHashes.size) {
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Check if any file mtimes changed
|
|
233
|
+
const entries = Array.from(oldHashes.entries());
|
|
234
|
+
for (let i = 0; i < entries.length; i++) {
|
|
235
|
+
const path = entries[i][0];
|
|
236
|
+
const oldMtime = entries[i][1];
|
|
237
|
+
const newMtime = newHashes.get(path);
|
|
238
|
+
if (newMtime === undefined || newMtime !== oldMtime) {
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return true;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Get cache statistics
|
|
248
|
+
* @returns Cache info object
|
|
249
|
+
*/
|
|
250
|
+
getStats(): { exists: boolean; age?: number; fileCount?: number; size?: number } {
|
|
251
|
+
if (!existsSync(this.cacheFile)) {
|
|
252
|
+
return { exists: false };
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
try {
|
|
256
|
+
const stats = statSync(this.cacheFile);
|
|
257
|
+
const content = readFileSync(this.cacheFile, 'utf8');
|
|
258
|
+
const entry = JSON.parse(content);
|
|
259
|
+
|
|
260
|
+
return {
|
|
261
|
+
exists: true,
|
|
262
|
+
age: Date.now() - entry.timestamp,
|
|
263
|
+
fileCount: Object.keys(entry.fileHashes || {}).length,
|
|
264
|
+
size: stats.size
|
|
265
|
+
};
|
|
266
|
+
} catch {
|
|
267
|
+
return { exists: false };
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Extract project path from workflow directory
|
|
274
|
+
* @param workflowDir - Path to .workflow directory (e.g., /project/.workflow)
|
|
275
|
+
* @returns Project root path
|
|
276
|
+
*/
|
|
277
|
+
function extractProjectPath(workflowDir: string): string {
|
|
278
|
+
// workflowDir is typically {projectPath}/.workflow
|
|
279
|
+
return workflowDir.replace(/[\/\\]\.workflow$/, '') || workflowDir;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Create a cache manager for dashboard data
|
|
284
|
+
* @param workflowDir - Path to .workflow directory
|
|
285
|
+
* @param ttl - Optional TTL in milliseconds
|
|
286
|
+
* @returns CacheManager instance
|
|
287
|
+
*/
|
|
288
|
+
export function createDashboardCache(workflowDir: string, ttl?: number): CacheManager<any> {
|
|
289
|
+
// Use centralized storage path
|
|
290
|
+
const projectPath = extractProjectPath(workflowDir);
|
|
291
|
+
const cacheDir = StoragePaths.project(projectPath).cache;
|
|
292
|
+
ensureStorageDir(cacheDir);
|
|
293
|
+
return new CacheManager('dashboard-data', { cacheDir, ttl });
|
|
294
|
+
}
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLAUDE.md Freshness Calculator
|
|
3
|
+
* Calculates freshness scores based on git changes since last update
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { execSync } from 'child_process';
|
|
7
|
+
import { existsSync, statSync, readdirSync } from 'fs';
|
|
8
|
+
import { dirname, extname, relative, join } from 'path';
|
|
9
|
+
import { getCoreMemoryStore, ClaudeUpdateRecord } from './core-memory-store.js';
|
|
10
|
+
|
|
11
|
+
// Source file extensions to track (from detect-changed-modules.ts)
|
|
12
|
+
const SOURCE_EXTENSIONS = [
|
|
13
|
+
'.md', '.js', '.ts', '.jsx', '.tsx',
|
|
14
|
+
'.py', '.go', '.rs', '.java', '.cpp', '.c', '.h',
|
|
15
|
+
'.sh', '.ps1', '.json', '.yaml', '.yml'
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
// Directories to exclude
|
|
19
|
+
const EXCLUDE_DIRS = [
|
|
20
|
+
'.git', '__pycache__', 'node_modules', '.venv', 'venv', 'env',
|
|
21
|
+
'dist', 'build', '.cache', '.pytest_cache', '.mypy_cache',
|
|
22
|
+
'coverage', '.nyc_output', 'logs', 'tmp', 'temp', '.ccw', '.workflow'
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
export interface FreshnessResult {
|
|
26
|
+
path: string;
|
|
27
|
+
level: 'user' | 'project' | 'module';
|
|
28
|
+
relativePath: string;
|
|
29
|
+
parentDirectory?: string;
|
|
30
|
+
lastUpdated: string | null;
|
|
31
|
+
lastModified: string;
|
|
32
|
+
changedFilesCount: number;
|
|
33
|
+
freshness: number;
|
|
34
|
+
updateSource?: string;
|
|
35
|
+
needsUpdate: boolean;
|
|
36
|
+
changedFiles?: string[];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface FreshnessSummary {
|
|
40
|
+
totalFiles: number;
|
|
41
|
+
staleCount: number;
|
|
42
|
+
averageFreshness: number;
|
|
43
|
+
lastScanAt: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface FreshnessResponse {
|
|
47
|
+
files: FreshnessResult[];
|
|
48
|
+
summary: FreshnessSummary;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Check if git is available and we're in a repo
|
|
53
|
+
*/
|
|
54
|
+
function isGitRepo(basePath: string): boolean {
|
|
55
|
+
try {
|
|
56
|
+
execSync('git rev-parse --git-dir', { cwd: basePath, stdio: 'pipe' });
|
|
57
|
+
return true;
|
|
58
|
+
} catch (e) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Get current git commit hash
|
|
65
|
+
*/
|
|
66
|
+
export function getCurrentGitCommit(basePath: string): string | null {
|
|
67
|
+
try {
|
|
68
|
+
const output = execSync('git rev-parse HEAD', {
|
|
69
|
+
cwd: basePath,
|
|
70
|
+
encoding: 'utf8',
|
|
71
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
72
|
+
}).trim();
|
|
73
|
+
return output || null;
|
|
74
|
+
} catch (e) {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Get files changed since a specific date within a directory
|
|
81
|
+
*/
|
|
82
|
+
function getChangedFilesSince(basePath: string, modulePath: string, sinceDate: string): string[] {
|
|
83
|
+
try {
|
|
84
|
+
// Format date for git
|
|
85
|
+
const date = new Date(sinceDate);
|
|
86
|
+
const formattedDate = date.toISOString().split('T')[0];
|
|
87
|
+
|
|
88
|
+
// Get files changed since the date
|
|
89
|
+
const output = execSync(
|
|
90
|
+
`git log --name-only --since="${formattedDate}" --pretty=format: -- "${modulePath}"`,
|
|
91
|
+
{
|
|
92
|
+
cwd: basePath,
|
|
93
|
+
encoding: 'utf8',
|
|
94
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
95
|
+
}
|
|
96
|
+
).trim();
|
|
97
|
+
|
|
98
|
+
if (!output) return [];
|
|
99
|
+
|
|
100
|
+
// Get unique files and filter by source extensions
|
|
101
|
+
const files = [...new Set(output.split('\n').filter(f => f.trim()))];
|
|
102
|
+
return files.filter(f => {
|
|
103
|
+
const ext = extname(f).toLowerCase();
|
|
104
|
+
return SOURCE_EXTENSIONS.includes(ext);
|
|
105
|
+
});
|
|
106
|
+
} catch (e) {
|
|
107
|
+
// Fallback to mtime-based detection
|
|
108
|
+
return findFilesModifiedSince(modulePath, sinceDate);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Fallback: Find files modified since a date using mtime
|
|
114
|
+
*/
|
|
115
|
+
function findFilesModifiedSince(dirPath: string, sinceDate: string): string[] {
|
|
116
|
+
const results: string[] = [];
|
|
117
|
+
const cutoffTime = new Date(sinceDate).getTime();
|
|
118
|
+
|
|
119
|
+
function scan(currentPath: string): void {
|
|
120
|
+
try {
|
|
121
|
+
const entries = readdirSync(currentPath, { withFileTypes: true });
|
|
122
|
+
|
|
123
|
+
for (const entry of entries) {
|
|
124
|
+
if (entry.isDirectory()) {
|
|
125
|
+
if (EXCLUDE_DIRS.includes(entry.name)) continue;
|
|
126
|
+
scan(join(currentPath, entry.name));
|
|
127
|
+
} else if (entry.isFile()) {
|
|
128
|
+
const ext = extname(entry.name).toLowerCase();
|
|
129
|
+
if (!SOURCE_EXTENSIONS.includes(ext)) continue;
|
|
130
|
+
|
|
131
|
+
const fullPath = join(currentPath, entry.name);
|
|
132
|
+
try {
|
|
133
|
+
const stat = statSync(fullPath);
|
|
134
|
+
if (stat.mtimeMs > cutoffTime) {
|
|
135
|
+
results.push(relative(dirPath, fullPath));
|
|
136
|
+
}
|
|
137
|
+
} catch (e) {
|
|
138
|
+
// Skip files we can't stat
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
} catch (e) {
|
|
143
|
+
// Ignore permission errors
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (existsSync(dirPath)) {
|
|
148
|
+
scan(dirPath);
|
|
149
|
+
}
|
|
150
|
+
return results;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Calculate freshness for a single CLAUDE.md file
|
|
155
|
+
*/
|
|
156
|
+
export function calculateFreshness(
|
|
157
|
+
filePath: string,
|
|
158
|
+
fileLevel: 'user' | 'project' | 'module',
|
|
159
|
+
lastUpdateTime: string | null,
|
|
160
|
+
lastModified: string,
|
|
161
|
+
projectPath: string,
|
|
162
|
+
threshold: number = 20
|
|
163
|
+
): FreshnessResult {
|
|
164
|
+
// Use lastUpdateTime from history, or fall back to file mtime
|
|
165
|
+
const effectiveUpdateTime = lastUpdateTime || lastModified;
|
|
166
|
+
|
|
167
|
+
// Calculate module path for change detection
|
|
168
|
+
let modulePath: string | null = null;
|
|
169
|
+
let changedFiles: string[] = [];
|
|
170
|
+
|
|
171
|
+
if (fileLevel === 'module') {
|
|
172
|
+
// For module-level files, scan the parent directory
|
|
173
|
+
modulePath = dirname(filePath);
|
|
174
|
+
} else if (fileLevel === 'project') {
|
|
175
|
+
// For project-level files, scan the project root
|
|
176
|
+
modulePath = projectPath;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Only calculate changes for module/project level in git repos
|
|
180
|
+
if (modulePath && isGitRepo(projectPath)) {
|
|
181
|
+
changedFiles = getChangedFilesSince(projectPath, modulePath, effectiveUpdateTime);
|
|
182
|
+
// Exclude the CLAUDE.md file itself
|
|
183
|
+
changedFiles = changedFiles.filter(f => !f.endsWith('CLAUDE.md'));
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Calculate freshness percentage
|
|
187
|
+
const changedCount = changedFiles.length;
|
|
188
|
+
const freshness = Math.max(0, 100 - Math.floor((changedCount / threshold) * 100));
|
|
189
|
+
|
|
190
|
+
// Determine parent directory for display
|
|
191
|
+
const parentDirectory = fileLevel === 'module'
|
|
192
|
+
? filePath.split(/[\\/]/).slice(-2, -1)[0]
|
|
193
|
+
: undefined;
|
|
194
|
+
|
|
195
|
+
return {
|
|
196
|
+
path: filePath,
|
|
197
|
+
level: fileLevel,
|
|
198
|
+
relativePath: relative(projectPath, filePath).replace(/\\/g, '/'),
|
|
199
|
+
parentDirectory,
|
|
200
|
+
lastUpdated: lastUpdateTime,
|
|
201
|
+
lastModified,
|
|
202
|
+
changedFilesCount: changedCount,
|
|
203
|
+
freshness,
|
|
204
|
+
needsUpdate: freshness < 50,
|
|
205
|
+
changedFiles: changedFiles.slice(0, 20) // Limit to first 20 for detail view
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Calculate freshness for all CLAUDE.md files in a project
|
|
211
|
+
*/
|
|
212
|
+
export function calculateAllFreshness(
|
|
213
|
+
claudeFiles: Array<{
|
|
214
|
+
path: string;
|
|
215
|
+
level: 'user' | 'project' | 'module';
|
|
216
|
+
lastModified: string;
|
|
217
|
+
}>,
|
|
218
|
+
projectPath: string,
|
|
219
|
+
threshold: number = 20
|
|
220
|
+
): FreshnessResponse {
|
|
221
|
+
// Get update records from store
|
|
222
|
+
const store = getCoreMemoryStore(projectPath);
|
|
223
|
+
const updateRecords = store.getAllClaudeUpdateRecords();
|
|
224
|
+
|
|
225
|
+
// Create a map for quick lookup
|
|
226
|
+
const updateMap = new Map<string, ClaudeUpdateRecord>();
|
|
227
|
+
for (const record of updateRecords) {
|
|
228
|
+
updateMap.set(record.file_path, record);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const results: FreshnessResult[] = [];
|
|
232
|
+
|
|
233
|
+
for (const file of claudeFiles) {
|
|
234
|
+
const updateRecord = updateMap.get(file.path);
|
|
235
|
+
|
|
236
|
+
const result = calculateFreshness(
|
|
237
|
+
file.path,
|
|
238
|
+
file.level,
|
|
239
|
+
updateRecord?.updated_at || null,
|
|
240
|
+
file.lastModified,
|
|
241
|
+
projectPath,
|
|
242
|
+
threshold
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
if (updateRecord) {
|
|
246
|
+
result.updateSource = updateRecord.update_source;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
results.push(result);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Calculate summary
|
|
253
|
+
const staleCount = results.filter(r => r.needsUpdate).length;
|
|
254
|
+
const totalFreshness = results.reduce((sum, r) => sum + r.freshness, 0);
|
|
255
|
+
const averageFreshness = results.length > 0 ? Math.round(totalFreshness / results.length) : 100;
|
|
256
|
+
|
|
257
|
+
return {
|
|
258
|
+
files: results,
|
|
259
|
+
summary: {
|
|
260
|
+
totalFiles: results.length,
|
|
261
|
+
staleCount,
|
|
262
|
+
averageFreshness,
|
|
263
|
+
lastScanAt: new Date().toISOString()
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Mark a CLAUDE.md file as updated
|
|
270
|
+
*/
|
|
271
|
+
export function markFileAsUpdated(
|
|
272
|
+
filePath: string,
|
|
273
|
+
fileLevel: 'user' | 'project' | 'module',
|
|
274
|
+
updateSource: 'manual' | 'cli_sync' | 'dashboard' | 'api',
|
|
275
|
+
projectPath: string,
|
|
276
|
+
metadata?: object
|
|
277
|
+
): ClaudeUpdateRecord {
|
|
278
|
+
const store = getCoreMemoryStore(projectPath);
|
|
279
|
+
const now = new Date().toISOString();
|
|
280
|
+
|
|
281
|
+
// Get current git commit
|
|
282
|
+
const gitCommit = getCurrentGitCommit(projectPath);
|
|
283
|
+
|
|
284
|
+
// Calculate changed files count before this update
|
|
285
|
+
const lastUpdate = store.getLastClaudeUpdate(filePath);
|
|
286
|
+
let filesChangedCount = 0;
|
|
287
|
+
|
|
288
|
+
if (lastUpdate && isGitRepo(projectPath)) {
|
|
289
|
+
const modulePath = fileLevel === 'module' ? dirname(filePath) : projectPath;
|
|
290
|
+
const changedFiles = getChangedFilesSince(projectPath, modulePath, lastUpdate.updated_at);
|
|
291
|
+
filesChangedCount = changedFiles.filter(f => !f.endsWith('CLAUDE.md')).length;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Insert update record
|
|
295
|
+
const record = store.insertClaudeUpdateRecord({
|
|
296
|
+
file_path: filePath,
|
|
297
|
+
file_level: fileLevel,
|
|
298
|
+
module_path: fileLevel === 'module' ? dirname(filePath) : undefined,
|
|
299
|
+
updated_at: now,
|
|
300
|
+
update_source: updateSource,
|
|
301
|
+
git_commit_hash: gitCommit || undefined,
|
|
302
|
+
files_changed_before_update: filesChangedCount,
|
|
303
|
+
metadata: metadata ? JSON.stringify(metadata) : undefined
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
return record;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Get update history for a file
|
|
311
|
+
*/
|
|
312
|
+
export function getUpdateHistory(
|
|
313
|
+
filePath: string,
|
|
314
|
+
projectPath: string,
|
|
315
|
+
limit: number = 50
|
|
316
|
+
): ClaudeUpdateRecord[] {
|
|
317
|
+
const store = getCoreMemoryStore(projectPath);
|
|
318
|
+
return store.getClaudeUpdateHistory(filePath, limit);
|
|
319
|
+
}
|