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,41 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
// Tool parameter schema for Zod validation
|
|
4
|
+
export const ToolParamSchema = z.object({
|
|
5
|
+
name: z.string(),
|
|
6
|
+
type: z.enum(['string', 'number', 'boolean', 'object', 'array']),
|
|
7
|
+
description: z.string(),
|
|
8
|
+
required: z.boolean().default(false),
|
|
9
|
+
default: z.any().optional(),
|
|
10
|
+
enum: z.array(z.string()).optional(),
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
export type ToolParam = z.infer<typeof ToolParamSchema>;
|
|
14
|
+
|
|
15
|
+
// Tool Schema definition (MCP compatible)
|
|
16
|
+
export interface ToolSchema {
|
|
17
|
+
name: string;
|
|
18
|
+
description: string;
|
|
19
|
+
inputSchema: {
|
|
20
|
+
type: 'object';
|
|
21
|
+
properties: Record<string, unknown>;
|
|
22
|
+
required?: string[];
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Tool execution result
|
|
27
|
+
export interface ToolResult<T = unknown> {
|
|
28
|
+
success: boolean;
|
|
29
|
+
result?: T;
|
|
30
|
+
error?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Tool handler function type
|
|
34
|
+
export type ToolHandler<TParams = Record<string, unknown>, TResult = unknown> =
|
|
35
|
+
(params: TParams) => Promise<ToolResult<TResult>>;
|
|
36
|
+
|
|
37
|
+
// Tool registration entry
|
|
38
|
+
export interface ToolRegistration<TParams = Record<string, unknown>> {
|
|
39
|
+
schema: ToolSchema;
|
|
40
|
+
handler: ToolHandler<TParams>;
|
|
41
|
+
}
|
|
@@ -5,17 +5,18 @@ import { resolve } from 'path';
|
|
|
5
5
|
/**
|
|
6
6
|
* Launch a URL or file in the default browser
|
|
7
7
|
* Cross-platform compatible (Windows/macOS/Linux)
|
|
8
|
-
* @param
|
|
9
|
-
* @returns
|
|
8
|
+
* @param urlOrPath - HTTP URL or path to HTML file
|
|
9
|
+
* @returns Promise that resolves when browser is launched
|
|
10
10
|
*/
|
|
11
|
-
export async function launchBrowser(urlOrPath) {
|
|
11
|
+
export async function launchBrowser(urlOrPath: string): Promise<void> {
|
|
12
12
|
// Check if it's already a URL (http:// or https://)
|
|
13
13
|
if (urlOrPath.startsWith('http://') || urlOrPath.startsWith('https://')) {
|
|
14
14
|
try {
|
|
15
15
|
await open(urlOrPath);
|
|
16
16
|
return;
|
|
17
17
|
} catch (error) {
|
|
18
|
-
|
|
18
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
19
|
+
throw new Error(`Failed to open browser: ${message}`);
|
|
19
20
|
}
|
|
20
21
|
}
|
|
21
22
|
|
|
@@ -23,7 +24,7 @@ export async function launchBrowser(urlOrPath) {
|
|
|
23
24
|
const absolutePath = resolve(urlOrPath);
|
|
24
25
|
|
|
25
26
|
// Construct file:// URL based on platform
|
|
26
|
-
let url;
|
|
27
|
+
let url: string;
|
|
27
28
|
if (platform() === 'win32') {
|
|
28
29
|
// Windows: file:///C:/path/to/file.html
|
|
29
30
|
url = `file:///${absolutePath.replace(/\\/g, '/')}`;
|
|
@@ -40,16 +41,17 @@ export async function launchBrowser(urlOrPath) {
|
|
|
40
41
|
try {
|
|
41
42
|
await open(absolutePath);
|
|
42
43
|
} catch (fallbackError) {
|
|
43
|
-
|
|
44
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
45
|
+
throw new Error(`Failed to open browser: ${message}`);
|
|
44
46
|
}
|
|
45
47
|
}
|
|
46
48
|
}
|
|
47
49
|
|
|
48
50
|
/**
|
|
49
51
|
* Check if we're running in a headless/CI environment
|
|
50
|
-
* @returns
|
|
52
|
+
* @returns True if running in headless environment
|
|
51
53
|
*/
|
|
52
|
-
export function isHeadlessEnvironment() {
|
|
54
|
+
export function isHeadlessEnvironment(): boolean {
|
|
53
55
|
return !!(
|
|
54
56
|
process.env.CI ||
|
|
55
57
|
process.env.CONTINUOUS_INTEGRATION ||
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { readFileSync, existsSync, writeFileSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Safely read a JSON file
|
|
6
|
+
* @param filePath - Path to JSON file
|
|
7
|
+
* @returns Parsed JSON or null on error
|
|
8
|
+
*/
|
|
9
|
+
export function readJsonFile(filePath: string): unknown | null {
|
|
10
|
+
if (!existsSync(filePath)) return null;
|
|
11
|
+
try {
|
|
12
|
+
return JSON.parse(readFileSync(filePath, 'utf8'));
|
|
13
|
+
} catch {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Safely read a text file
|
|
20
|
+
* @param filePath - Path to text file
|
|
21
|
+
* @returns File contents or null on error
|
|
22
|
+
*/
|
|
23
|
+
export function readTextFile(filePath: string): string | null {
|
|
24
|
+
if (!existsSync(filePath)) return null;
|
|
25
|
+
try {
|
|
26
|
+
return readFileSync(filePath, 'utf8');
|
|
27
|
+
} catch {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Write content to a file
|
|
34
|
+
* @param filePath - Path to file
|
|
35
|
+
* @param content - Content to write
|
|
36
|
+
*/
|
|
37
|
+
export function writeTextFile(filePath: string, content: string): void {
|
|
38
|
+
writeFileSync(filePath, content, 'utf8');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Check if a path exists
|
|
43
|
+
* @param filePath - Path to check
|
|
44
|
+
* @returns True if path exists
|
|
45
|
+
*/
|
|
46
|
+
export function pathExists(filePath: string): boolean {
|
|
47
|
+
return existsSync(filePath);
|
|
48
|
+
}
|
|
@@ -1,13 +1,32 @@
|
|
|
1
1
|
import { resolve, join, relative, isAbsolute } from 'path';
|
|
2
2
|
import { existsSync, mkdirSync, realpathSync, statSync, readFileSync, writeFileSync } from 'fs';
|
|
3
3
|
import { homedir } from 'os';
|
|
4
|
+
import { StoragePaths, ensureStorageDir, LegacyPaths } from '../config/storage-paths.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Validation result for path operations
|
|
8
|
+
*/
|
|
9
|
+
export interface PathValidationResult {
|
|
10
|
+
valid: boolean;
|
|
11
|
+
path: string | null;
|
|
12
|
+
error: string | null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Options for path validation
|
|
17
|
+
*/
|
|
18
|
+
export interface ValidatePathOptions {
|
|
19
|
+
baseDir?: string | null;
|
|
20
|
+
mustExist?: boolean;
|
|
21
|
+
allowHome?: boolean;
|
|
22
|
+
}
|
|
4
23
|
|
|
5
24
|
/**
|
|
6
25
|
* Resolve a path, handling ~ for home directory
|
|
7
|
-
* @param
|
|
8
|
-
* @returns
|
|
26
|
+
* @param inputPath - Path to resolve
|
|
27
|
+
* @returns Absolute path
|
|
9
28
|
*/
|
|
10
|
-
export function resolvePath(inputPath) {
|
|
29
|
+
export function resolvePath(inputPath: string): string {
|
|
11
30
|
if (!inputPath) return process.cwd();
|
|
12
31
|
|
|
13
32
|
// Handle ~ for home directory
|
|
@@ -21,14 +40,11 @@ export function resolvePath(inputPath) {
|
|
|
21
40
|
/**
|
|
22
41
|
* Validate and sanitize a user-provided path
|
|
23
42
|
* Prevents path traversal attacks and validates path is within allowed boundaries
|
|
24
|
-
* @param
|
|
25
|
-
* @param
|
|
26
|
-
* @
|
|
27
|
-
* @param {boolean} options.mustExist - Whether path must exist (default: false)
|
|
28
|
-
* @param {boolean} options.allowHome - Whether to allow home directory paths (default: true)
|
|
29
|
-
* @returns {Object} - { valid: boolean, path: string|null, error: string|null }
|
|
43
|
+
* @param inputPath - User-provided path
|
|
44
|
+
* @param options - Validation options
|
|
45
|
+
* @returns Validation result with path or error
|
|
30
46
|
*/
|
|
31
|
-
export function validatePath(inputPath, options = {}) {
|
|
47
|
+
export function validatePath(inputPath: string, options: ValidatePathOptions = {}): PathValidationResult {
|
|
32
48
|
const { baseDir = null, mustExist = false, allowHome = true } = options;
|
|
33
49
|
|
|
34
50
|
// Check for empty/null input
|
|
@@ -45,11 +61,12 @@ export function validatePath(inputPath, options = {}) {
|
|
|
45
61
|
}
|
|
46
62
|
|
|
47
63
|
// Resolve the path
|
|
48
|
-
let resolvedPath;
|
|
64
|
+
let resolvedPath: string;
|
|
49
65
|
try {
|
|
50
66
|
resolvedPath = resolvePath(trimmedPath);
|
|
51
67
|
} catch (err) {
|
|
52
|
-
|
|
68
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
69
|
+
return { valid: false, path: null, error: `Invalid path: ${message}` };
|
|
53
70
|
}
|
|
54
71
|
|
|
55
72
|
// Check if path exists when required
|
|
@@ -63,7 +80,8 @@ export function validatePath(inputPath, options = {}) {
|
|
|
63
80
|
try {
|
|
64
81
|
realPath = realpathSync(resolvedPath);
|
|
65
82
|
} catch (err) {
|
|
66
|
-
|
|
83
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
84
|
+
return { valid: false, path: null, error: `Cannot resolve path: ${message}` };
|
|
67
85
|
}
|
|
68
86
|
}
|
|
69
87
|
|
|
@@ -95,11 +113,11 @@ export function validatePath(inputPath, options = {}) {
|
|
|
95
113
|
|
|
96
114
|
/**
|
|
97
115
|
* Validate output file path for writing
|
|
98
|
-
* @param
|
|
99
|
-
* @param
|
|
100
|
-
* @returns
|
|
116
|
+
* @param outputPath - Output file path
|
|
117
|
+
* @param defaultDir - Default directory if path is relative
|
|
118
|
+
* @returns Validation result with path or error
|
|
101
119
|
*/
|
|
102
|
-
export function validateOutputPath(outputPath, defaultDir = process.cwd()) {
|
|
120
|
+
export function validateOutputPath(outputPath: string, defaultDir: string = process.cwd()): PathValidationResult {
|
|
103
121
|
if (!outputPath || typeof outputPath !== 'string') {
|
|
104
122
|
return { valid: false, path: null, error: 'Output path is required' };
|
|
105
123
|
}
|
|
@@ -112,12 +130,13 @@ export function validateOutputPath(outputPath, defaultDir = process.cwd()) {
|
|
|
112
130
|
}
|
|
113
131
|
|
|
114
132
|
// Resolve the path
|
|
115
|
-
let resolvedPath;
|
|
133
|
+
let resolvedPath: string;
|
|
116
134
|
try {
|
|
117
135
|
resolvedPath = isAbsolute(trimmedPath) ? trimmedPath : join(defaultDir, trimmedPath);
|
|
118
136
|
resolvedPath = resolve(resolvedPath);
|
|
119
137
|
} catch (err) {
|
|
120
|
-
|
|
138
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
139
|
+
return { valid: false, path: null, error: `Invalid output path: ${message}` };
|
|
121
140
|
}
|
|
122
141
|
|
|
123
142
|
// Ensure it's not a directory
|
|
@@ -137,9 +156,9 @@ export function validateOutputPath(outputPath, defaultDir = process.cwd()) {
|
|
|
137
156
|
|
|
138
157
|
/**
|
|
139
158
|
* Get potential template locations
|
|
140
|
-
* @returns
|
|
159
|
+
* @returns Array of existing template directories
|
|
141
160
|
*/
|
|
142
|
-
export function getTemplateLocations() {
|
|
161
|
+
export function getTemplateLocations(): string[] {
|
|
143
162
|
const locations = [
|
|
144
163
|
join(homedir(), '.claude', 'templates'),
|
|
145
164
|
join(process.cwd(), '.claude', 'templates')
|
|
@@ -150,10 +169,10 @@ export function getTemplateLocations() {
|
|
|
150
169
|
|
|
151
170
|
/**
|
|
152
171
|
* Find a template file in known locations
|
|
153
|
-
* @param
|
|
154
|
-
* @returns
|
|
172
|
+
* @param templateName - Name of template file (e.g., 'workflow-dashboard.html')
|
|
173
|
+
* @returns Path to template or null if not found
|
|
155
174
|
*/
|
|
156
|
-
export function findTemplate(templateName) {
|
|
175
|
+
export function findTemplate(templateName: string): string | null {
|
|
157
176
|
const locations = getTemplateLocations();
|
|
158
177
|
|
|
159
178
|
for (const loc of locations) {
|
|
@@ -168,45 +187,58 @@ export function findTemplate(templateName) {
|
|
|
168
187
|
|
|
169
188
|
/**
|
|
170
189
|
* Ensure directory exists, creating if necessary
|
|
171
|
-
* @param
|
|
190
|
+
* @param dirPath - Directory path to ensure
|
|
172
191
|
*/
|
|
173
|
-
export function ensureDir(dirPath) {
|
|
192
|
+
export function ensureDir(dirPath: string): void {
|
|
174
193
|
if (!existsSync(dirPath)) {
|
|
175
194
|
mkdirSync(dirPath, { recursive: true });
|
|
176
195
|
}
|
|
177
196
|
}
|
|
178
197
|
|
|
179
198
|
/**
|
|
180
|
-
*
|
|
181
|
-
* @param
|
|
182
|
-
* @returns
|
|
199
|
+
* Normalize path for display (handle Windows backslashes)
|
|
200
|
+
* @param filePath - Path to normalize
|
|
201
|
+
* @returns Normalized path with forward slashes
|
|
183
202
|
*/
|
|
184
|
-
export function
|
|
185
|
-
return
|
|
203
|
+
export function normalizePathForDisplay(filePath: string): string {
|
|
204
|
+
return filePath.replace(/\\/g, '/');
|
|
186
205
|
}
|
|
187
206
|
|
|
207
|
+
// Recent paths storage - uses centralized storage with backward compatibility
|
|
208
|
+
const MAX_RECENT_PATHS = 10;
|
|
209
|
+
|
|
188
210
|
/**
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
* @returns {string}
|
|
211
|
+
* Get the recent paths file location
|
|
212
|
+
* Uses new location but falls back to legacy location for backward compatibility
|
|
192
213
|
*/
|
|
193
|
-
|
|
194
|
-
|
|
214
|
+
function getRecentPathsFile(): string {
|
|
215
|
+
const newPath = StoragePaths.global.recentPaths();
|
|
216
|
+
const legacyPath = LegacyPaths.recentPaths();
|
|
217
|
+
|
|
218
|
+
// Backward compatibility: use legacy if it exists and new doesn't
|
|
219
|
+
if (!existsSync(newPath) && existsSync(legacyPath)) {
|
|
220
|
+
return legacyPath;
|
|
221
|
+
}
|
|
222
|
+
return newPath;
|
|
195
223
|
}
|
|
196
224
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
225
|
+
/**
|
|
226
|
+
* Recent paths data structure
|
|
227
|
+
*/
|
|
228
|
+
interface RecentPathsData {
|
|
229
|
+
paths: string[];
|
|
230
|
+
}
|
|
200
231
|
|
|
201
232
|
/**
|
|
202
233
|
* Get recent project paths
|
|
203
|
-
* @returns
|
|
234
|
+
* @returns Array of recent paths
|
|
204
235
|
*/
|
|
205
|
-
export function getRecentPaths() {
|
|
236
|
+
export function getRecentPaths(): string[] {
|
|
206
237
|
try {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
const
|
|
238
|
+
const recentPathsFile = getRecentPathsFile();
|
|
239
|
+
if (existsSync(recentPathsFile)) {
|
|
240
|
+
const content = readFileSync(recentPathsFile, 'utf8');
|
|
241
|
+
const data = JSON.parse(content) as RecentPathsData;
|
|
210
242
|
return Array.isArray(data.paths) ? data.paths : [];
|
|
211
243
|
}
|
|
212
244
|
} catch {
|
|
@@ -217,9 +249,9 @@ export function getRecentPaths() {
|
|
|
217
249
|
|
|
218
250
|
/**
|
|
219
251
|
* Track a project path (add to recent paths)
|
|
220
|
-
* @param
|
|
252
|
+
* @param projectPath - Path to track
|
|
221
253
|
*/
|
|
222
|
-
export function trackRecentPath(projectPath) {
|
|
254
|
+
export function trackRecentPath(projectPath: string): void {
|
|
223
255
|
try {
|
|
224
256
|
const normalized = normalizePathForDisplay(resolvePath(projectPath));
|
|
225
257
|
let paths = getRecentPaths();
|
|
@@ -233,8 +265,10 @@ export function trackRecentPath(projectPath) {
|
|
|
233
265
|
// Limit to max
|
|
234
266
|
paths = paths.slice(0, MAX_RECENT_PATHS);
|
|
235
267
|
|
|
236
|
-
// Save
|
|
237
|
-
|
|
268
|
+
// Save to new centralized location
|
|
269
|
+
const recentPathsFile = StoragePaths.global.recentPaths();
|
|
270
|
+
ensureStorageDir(StoragePaths.global.config());
|
|
271
|
+
writeFileSync(recentPathsFile, JSON.stringify({ paths }, null, 2), 'utf8');
|
|
238
272
|
} catch {
|
|
239
273
|
// Ignore errors
|
|
240
274
|
}
|
|
@@ -243,37 +277,39 @@ export function trackRecentPath(projectPath) {
|
|
|
243
277
|
/**
|
|
244
278
|
* Clear recent paths
|
|
245
279
|
*/
|
|
246
|
-
export function clearRecentPaths() {
|
|
280
|
+
export function clearRecentPaths(): void {
|
|
247
281
|
try {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
}
|
|
282
|
+
const recentPathsFile = StoragePaths.global.recentPaths();
|
|
283
|
+
ensureStorageDir(StoragePaths.global.config());
|
|
284
|
+
writeFileSync(recentPathsFile, JSON.stringify({ paths: [] }, null, 2), 'utf8');
|
|
251
285
|
} catch {
|
|
252
286
|
// Ignore errors
|
|
253
287
|
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
/**
|
|
257
|
-
* Remove a specific path from recent paths
|
|
258
|
-
* @param
|
|
259
|
-
* @returns
|
|
260
|
-
*/
|
|
261
|
-
export function removeRecentPath(pathToRemove) {
|
|
262
|
-
try {
|
|
263
|
-
const normalized = normalizePathForDisplay(resolvePath(pathToRemove));
|
|
264
|
-
let paths = getRecentPaths();
|
|
265
|
-
const originalLength = paths.length;
|
|
266
|
-
|
|
267
|
-
// Filter out the path to remove
|
|
268
|
-
paths = paths.filter(p => normalizePathForDisplay(p) !== normalized);
|
|
269
|
-
|
|
270
|
-
if (paths.length < originalLength) {
|
|
271
|
-
// Save updated list
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
return false;
|
|
278
|
-
}
|
|
279
|
-
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Remove a specific path from recent paths
|
|
292
|
+
* @param pathToRemove - Path to remove
|
|
293
|
+
* @returns True if removed, false if not found
|
|
294
|
+
*/
|
|
295
|
+
export function removeRecentPath(pathToRemove: string): boolean {
|
|
296
|
+
try {
|
|
297
|
+
const normalized = normalizePathForDisplay(resolvePath(pathToRemove));
|
|
298
|
+
let paths = getRecentPaths();
|
|
299
|
+
const originalLength = paths.length;
|
|
300
|
+
|
|
301
|
+
// Filter out the path to remove
|
|
302
|
+
paths = paths.filter(p => normalizePathForDisplay(p) !== normalized);
|
|
303
|
+
|
|
304
|
+
if (paths.length < originalLength) {
|
|
305
|
+
// Save updated list to new centralized location
|
|
306
|
+
const recentPathsFile = StoragePaths.global.recentPaths();
|
|
307
|
+
ensureStorageDir(StoragePaths.global.config());
|
|
308
|
+
writeFileSync(recentPathsFile, JSON.stringify({ paths }, null, 2), 'utf8');
|
|
309
|
+
return true;
|
|
310
|
+
}
|
|
311
|
+
return false;
|
|
312
|
+
} catch {
|
|
313
|
+
return false;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized Path Validation Utility
|
|
3
|
+
*
|
|
4
|
+
* Provides secure path validation and resolution for MCP tools.
|
|
5
|
+
* Prevents path traversal attacks and ensures operations stay within allowed directories.
|
|
6
|
+
*
|
|
7
|
+
* Inspired by MCP filesystem server's security model.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { resolve, isAbsolute, normalize, relative } from 'path';
|
|
11
|
+
import { realpath, access } from 'fs/promises';
|
|
12
|
+
import { constants } from 'fs';
|
|
13
|
+
|
|
14
|
+
// Environment variable configuration
|
|
15
|
+
const ENV_PROJECT_ROOT = 'CCW_PROJECT_ROOT';
|
|
16
|
+
const ENV_ALLOWED_DIRS = 'CCW_ALLOWED_DIRS';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Get project root directory
|
|
20
|
+
* Priority: CCW_PROJECT_ROOT > process.cwd()
|
|
21
|
+
*/
|
|
22
|
+
export function getProjectRoot(): string {
|
|
23
|
+
return process.env[ENV_PROJECT_ROOT] || process.cwd();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Get allowed directories list
|
|
28
|
+
* Priority: CCW_ALLOWED_DIRS > [getProjectRoot()]
|
|
29
|
+
*/
|
|
30
|
+
export function getAllowedDirectories(): string[] {
|
|
31
|
+
const envDirs = process.env[ENV_ALLOWED_DIRS];
|
|
32
|
+
if (envDirs) {
|
|
33
|
+
return envDirs.split(',').map(d => d.trim()).filter(Boolean);
|
|
34
|
+
}
|
|
35
|
+
return [getProjectRoot()];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Normalize path (unify separators to forward slash)
|
|
40
|
+
*/
|
|
41
|
+
export function normalizePath(p: string): string {
|
|
42
|
+
return normalize(p).replace(/\\/g, '/');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Check if path is within allowed directories
|
|
47
|
+
*/
|
|
48
|
+
export function isPathWithinAllowedDirectories(
|
|
49
|
+
targetPath: string,
|
|
50
|
+
allowedDirectories: string[]
|
|
51
|
+
): boolean {
|
|
52
|
+
const normalizedTarget = normalizePath(targetPath);
|
|
53
|
+
return allowedDirectories.some(dir => {
|
|
54
|
+
const normalizedDir = normalizePath(dir);
|
|
55
|
+
// Check if path equals or starts with allowed directory
|
|
56
|
+
return normalizedTarget === normalizedDir ||
|
|
57
|
+
normalizedTarget.startsWith(normalizedDir + '/');
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Validate and resolve path (core function)
|
|
63
|
+
*
|
|
64
|
+
* Security model:
|
|
65
|
+
* 1. Resolve to absolute path
|
|
66
|
+
* 2. Check against allowed directories
|
|
67
|
+
* 3. Resolve symlinks and re-verify
|
|
68
|
+
*
|
|
69
|
+
* @param filePath - Path to validate
|
|
70
|
+
* @param options - Validation options
|
|
71
|
+
* @returns Validated absolute path
|
|
72
|
+
* @throws Error if path is outside allowed directories or validation fails
|
|
73
|
+
*/
|
|
74
|
+
export async function validatePath(
|
|
75
|
+
filePath: string,
|
|
76
|
+
options: {
|
|
77
|
+
allowedDirectories?: string[];
|
|
78
|
+
mustExist?: boolean;
|
|
79
|
+
} = {}
|
|
80
|
+
): Promise<string> {
|
|
81
|
+
const allowedDirs = options.allowedDirectories || getAllowedDirectories();
|
|
82
|
+
|
|
83
|
+
// 1. Resolve to absolute path
|
|
84
|
+
const absolutePath = isAbsolute(filePath)
|
|
85
|
+
? filePath
|
|
86
|
+
: resolve(getProjectRoot(), filePath);
|
|
87
|
+
const normalizedPath = normalizePath(absolutePath);
|
|
88
|
+
|
|
89
|
+
// 2. Initial sandbox check
|
|
90
|
+
if (!isPathWithinAllowedDirectories(normalizedPath, allowedDirs)) {
|
|
91
|
+
throw new Error(
|
|
92
|
+
`Access denied: path "${normalizedPath}" is outside allowed directories. ` +
|
|
93
|
+
`Allowed: [${allowedDirs.join(', ')}]`
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// 3. Try to resolve symlinks and re-verify
|
|
98
|
+
try {
|
|
99
|
+
const realPath = await realpath(absolutePath);
|
|
100
|
+
const normalizedReal = normalizePath(realPath);
|
|
101
|
+
|
|
102
|
+
if (!isPathWithinAllowedDirectories(normalizedReal, allowedDirs)) {
|
|
103
|
+
throw new Error(
|
|
104
|
+
`Access denied: symlink target "${normalizedReal}" is outside allowed directories`
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return normalizedReal;
|
|
109
|
+
} catch (error: any) {
|
|
110
|
+
// File doesn't exist - validate parent directory
|
|
111
|
+
if (error.code === 'ENOENT') {
|
|
112
|
+
if (options.mustExist) {
|
|
113
|
+
throw new Error(`File not found: ${absolutePath}`);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Validate parent directory's real path
|
|
117
|
+
const parentDir = resolve(absolutePath, '..');
|
|
118
|
+
try {
|
|
119
|
+
const realParent = await realpath(parentDir);
|
|
120
|
+
const normalizedParent = normalizePath(realParent);
|
|
121
|
+
|
|
122
|
+
if (!isPathWithinAllowedDirectories(normalizedParent, allowedDirs)) {
|
|
123
|
+
throw new Error(
|
|
124
|
+
`Access denied: parent directory "${normalizedParent}" is outside allowed directories`
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
} catch (parentError: any) {
|
|
128
|
+
if (parentError.code === 'ENOENT') {
|
|
129
|
+
// Parent directory doesn't exist either - return original absolute path
|
|
130
|
+
// Let the caller create it if needed
|
|
131
|
+
return absolutePath;
|
|
132
|
+
}
|
|
133
|
+
throw parentError;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return absolutePath;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Re-throw access denied errors
|
|
140
|
+
if (error.message?.includes('Access denied')) {
|
|
141
|
+
throw error;
|
|
142
|
+
}
|
|
143
|
+
throw error;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Resolve project-relative path (simplified, no strict validation)
|
|
149
|
+
* Use for cases where strict security validation is not needed
|
|
150
|
+
*/
|
|
151
|
+
export function resolveProjectPath(...pathSegments: string[]): string {
|
|
152
|
+
return resolve(getProjectRoot(), ...pathSegments);
|
|
153
|
+
}
|