claude-code-workflow 6.1.3 → 6.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +145 -274
- package/bin/ccw-mcp.js +7 -0
- package/bin/ccw.js +10 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +219 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/cli.d.ts +32 -0
- package/dist/commands/cli.d.ts.map +1 -0
- package/dist/commands/cli.js +619 -0
- package/dist/commands/cli.js.map +1 -0
- package/dist/commands/core-memory.d.ts +32 -0
- package/dist/commands/core-memory.d.ts.map +1 -0
- package/dist/commands/core-memory.js +640 -0
- package/dist/commands/core-memory.js.map +1 -0
- package/dist/commands/hook.d.ts +16 -0
- package/dist/commands/hook.d.ts.map +1 -0
- package/dist/commands/hook.js +276 -0
- package/dist/commands/hook.js.map +1 -0
- package/dist/commands/install.d.ts +12 -0
- package/dist/commands/install.d.ts.map +1 -0
- package/dist/commands/install.js +443 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/list.d.ts +5 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +32 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/memory.d.ts +57 -0
- package/dist/commands/memory.d.ts.map +1 -0
- package/dist/commands/memory.js +890 -0
- package/dist/commands/memory.js.map +1 -0
- package/dist/commands/serve.d.ts +12 -0
- package/dist/commands/serve.d.ts.map +1 -0
- package/dist/commands/serve.js +63 -0
- package/dist/commands/serve.js.map +1 -0
- package/dist/commands/session-path-resolver.d.ts +45 -0
- package/dist/commands/session-path-resolver.d.ts.map +1 -0
- package/dist/commands/session-path-resolver.js +302 -0
- package/dist/commands/session-path-resolver.js.map +1 -0
- package/dist/commands/session.d.ts +12 -0
- package/dist/commands/session.d.ts.map +1 -0
- package/dist/commands/session.js +954 -0
- package/dist/commands/session.js.map +1 -0
- package/dist/commands/stop.d.ts +11 -0
- package/dist/commands/stop.d.ts.map +1 -0
- package/dist/commands/stop.js +96 -0
- package/dist/commands/stop.js.map +1 -0
- package/dist/commands/tool.d.ts +29 -0
- package/dist/commands/tool.d.ts.map +1 -0
- package/dist/commands/tool.js +173 -0
- package/dist/commands/tool.js.map +1 -0
- package/dist/commands/uninstall.d.ts +9 -0
- package/dist/commands/uninstall.d.ts.map +1 -0
- package/dist/commands/uninstall.js +239 -0
- package/dist/commands/uninstall.js.map +1 -0
- package/dist/commands/upgrade.d.ts +10 -0
- package/dist/commands/upgrade.d.ts.map +1 -0
- package/dist/commands/upgrade.js +288 -0
- package/dist/commands/upgrade.js.map +1 -0
- package/dist/commands/view.d.ts +14 -0
- package/dist/commands/view.d.ts.map +1 -0
- package/dist/commands/view.js +100 -0
- package/dist/commands/view.js.map +1 -0
- package/dist/config/storage-paths.d.ts +184 -0
- package/dist/config/storage-paths.d.ts.map +1 -0
- package/dist/config/storage-paths.js +536 -0
- package/dist/config/storage-paths.js.map +1 -0
- package/dist/core/cache-manager.d.ts +80 -0
- package/dist/core/cache-manager.d.ts.map +1 -0
- package/dist/core/cache-manager.js +260 -0
- package/dist/core/cache-manager.js.map +1 -0
- package/dist/core/claude-freshness.d.ts +53 -0
- package/dist/core/claude-freshness.d.ts.map +1 -0
- package/dist/core/claude-freshness.js +232 -0
- package/dist/core/claude-freshness.js.map +1 -0
- package/dist/core/core-memory-store.d.ts +320 -0
- package/dist/core/core-memory-store.d.ts.map +1 -0
- package/dist/core/core-memory-store.js +1177 -0
- package/dist/core/core-memory-store.js.map +1 -0
- package/dist/core/dashboard-generator-patch.d.ts +2 -0
- package/dist/core/dashboard-generator-patch.d.ts.map +1 -0
- package/dist/core/dashboard-generator-patch.js +48 -0
- package/dist/core/dashboard-generator-patch.js.map +1 -0
- package/dist/core/dashboard-generator.d.ts +8 -0
- package/dist/core/dashboard-generator.d.ts.map +1 -0
- package/dist/core/dashboard-generator.js +695 -0
- package/dist/core/dashboard-generator.js.map +1 -0
- package/dist/core/data-aggregator.d.ts +145 -0
- package/dist/core/data-aggregator.d.ts.map +1 -0
- package/dist/core/data-aggregator.js +416 -0
- package/dist/core/data-aggregator.js.map +1 -0
- package/dist/core/history-importer.d.ts +102 -0
- package/dist/core/history-importer.d.ts.map +1 -0
- package/dist/core/history-importer.js +493 -0
- package/dist/core/history-importer.js.map +1 -0
- package/dist/core/lite-scanner-complete.d.ts +81 -0
- package/dist/core/lite-scanner-complete.d.ts.map +1 -0
- package/dist/core/lite-scanner-complete.js +368 -0
- package/dist/core/lite-scanner-complete.js.map +1 -0
- package/dist/core/lite-scanner.d.ts +81 -0
- package/dist/core/lite-scanner.d.ts.map +1 -0
- package/dist/core/lite-scanner.js +368 -0
- package/dist/core/lite-scanner.js.map +1 -0
- package/dist/core/manifest.d.ts +88 -0
- package/dist/core/manifest.d.ts.map +1 -0
- package/dist/core/manifest.js +214 -0
- package/dist/core/manifest.js.map +1 -0
- package/dist/core/memory-embedder-bridge.d.ts +83 -0
- package/dist/core/memory-embedder-bridge.d.ts.map +1 -0
- package/dist/core/memory-embedder-bridge.js +181 -0
- package/dist/core/memory-embedder-bridge.js.map +1 -0
- package/dist/core/memory-store.d.ts +249 -0
- package/dist/core/memory-store.d.ts.map +1 -0
- package/dist/core/memory-store.js +781 -0
- package/dist/core/memory-store.js.map +1 -0
- package/dist/core/routes/ccw-routes.d.ts +20 -0
- package/dist/core/routes/ccw-routes.d.ts.map +1 -0
- package/dist/core/routes/ccw-routes.js +70 -0
- package/dist/core/routes/ccw-routes.js.map +1 -0
- package/dist/core/routes/claude-routes.d.ts +19 -0
- package/dist/core/routes/claude-routes.d.ts.map +1 -0
- package/dist/core/routes/claude-routes.js +1017 -0
- package/dist/core/routes/claude-routes.js.map +1 -0
- package/dist/core/routes/cli-routes.d.ts +20 -0
- package/dist/core/routes/cli-routes.d.ts.map +1 -0
- package/dist/core/routes/cli-routes.js +468 -0
- package/dist/core/routes/cli-routes.js.map +1 -0
- package/dist/core/routes/codexlens-routes.d.ts +20 -0
- package/dist/core/routes/codexlens-routes.d.ts.map +1 -0
- package/dist/core/routes/codexlens-routes.js +754 -0
- package/dist/core/routes/codexlens-routes.js.map +1 -0
- package/dist/core/routes/core-memory-routes.d.ts +21 -0
- package/dist/core/routes/core-memory-routes.d.ts.map +1 -0
- package/dist/core/routes/core-memory-routes.js +520 -0
- package/dist/core/routes/core-memory-routes.js.map +1 -0
- package/dist/core/routes/files-routes.d.ts +20 -0
- package/dist/core/routes/files-routes.d.ts.map +1 -0
- package/dist/core/routes/files-routes.js +374 -0
- package/dist/core/routes/files-routes.js.map +1 -0
- package/dist/core/routes/graph-routes.d.ts +20 -0
- package/dist/core/routes/graph-routes.d.ts.map +1 -0
- package/dist/core/routes/graph-routes.js +517 -0
- package/dist/core/routes/graph-routes.js.map +1 -0
- package/dist/core/routes/help-routes.d.ts +20 -0
- package/dist/core/routes/help-routes.d.ts.map +1 -0
- package/dist/core/routes/help-routes.js +250 -0
- package/dist/core/routes/help-routes.js.map +1 -0
- package/dist/core/routes/hooks-routes.d.ts +21 -0
- package/dist/core/routes/hooks-routes.d.ts.map +1 -0
- package/dist/core/routes/hooks-routes.js +346 -0
- package/dist/core/routes/hooks-routes.js.map +1 -0
- package/dist/core/routes/mcp-routes.d.ts +20 -0
- package/dist/core/routes/mcp-routes.d.ts.map +1 -0
- package/dist/core/routes/mcp-routes.js +1129 -0
- package/dist/core/routes/mcp-routes.js.map +1 -0
- package/dist/core/routes/mcp-templates-db.d.ts +54 -0
- package/dist/core/routes/mcp-templates-db.d.ts.map +1 -0
- package/dist/core/routes/mcp-templates-db.js +226 -0
- package/dist/core/routes/mcp-templates-db.js.map +1 -0
- package/dist/core/routes/memory-routes.d.ts +21 -0
- package/dist/core/routes/memory-routes.d.ts.map +1 -0
- package/dist/core/routes/memory-routes.js +1095 -0
- package/dist/core/routes/memory-routes.js.map +1 -0
- package/dist/core/routes/rules-routes.d.ts +20 -0
- package/dist/core/routes/rules-routes.d.ts.map +1 -0
- package/dist/core/routes/rules-routes.js +442 -0
- package/dist/core/routes/rules-routes.js.map +1 -0
- package/dist/core/routes/session-routes.d.ts +20 -0
- package/dist/core/routes/session-routes.d.ts.map +1 -0
- package/dist/core/routes/session-routes.js +423 -0
- package/dist/core/routes/session-routes.js.map +1 -0
- package/dist/core/routes/skills-routes.d.ts +20 -0
- package/dist/core/routes/skills-routes.d.ts.map +1 -0
- package/dist/core/routes/skills-routes.js +533 -0
- package/dist/core/routes/skills-routes.js.map +1 -0
- package/dist/core/routes/status-routes.d.ts +20 -0
- package/dist/core/routes/status-routes.d.ts.map +1 -0
- package/dist/core/routes/status-routes.js +38 -0
- package/dist/core/routes/status-routes.js.map +1 -0
- package/dist/core/routes/system-routes.d.ts +22 -0
- package/dist/core/routes/system-routes.d.ts.map +1 -0
- package/dist/core/routes/system-routes.js +354 -0
- package/dist/core/routes/system-routes.js.map +1 -0
- package/dist/core/server.d.ts +17 -0
- package/dist/core/server.d.ts.map +1 -0
- package/dist/core/server.js +386 -0
- package/dist/core/server.js.map +1 -0
- package/dist/core/session-clustering-service.d.ts +153 -0
- package/dist/core/session-clustering-service.d.ts.map +1 -0
- package/dist/core/session-clustering-service.js +1065 -0
- package/dist/core/session-clustering-service.js.map +1 -0
- package/dist/core/session-scanner.d.ts +32 -0
- package/dist/core/session-scanner.d.ts.map +1 -0
- package/dist/core/session-scanner.js +253 -0
- package/dist/core/session-scanner.js.map +1 -0
- package/dist/core/websocket.d.ts +23 -0
- package/dist/core/websocket.d.ts.map +1 -0
- package/dist/core/websocket.js +168 -0
- package/dist/core/websocket.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-server/index.d.ts +7 -0
- package/dist/mcp-server/index.d.ts.map +1 -0
- package/dist/mcp-server/index.js +157 -0
- package/dist/mcp-server/index.js.map +1 -0
- package/dist/tools/classify-folders.d.ts +26 -0
- package/dist/tools/classify-folders.d.ts.map +1 -0
- package/dist/tools/classify-folders.js +201 -0
- package/dist/tools/classify-folders.js.map +1 -0
- package/dist/tools/cli-config-manager.d.ts +62 -0
- package/dist/tools/cli-config-manager.d.ts.map +1 -0
- package/dist/tools/cli-config-manager.js +221 -0
- package/dist/tools/cli-config-manager.js.map +1 -0
- package/dist/tools/cli-executor.d.ts +373 -0
- package/dist/tools/cli-executor.d.ts.map +1 -0
- package/dist/tools/cli-executor.js +1625 -0
- package/dist/tools/cli-executor.js.map +1 -0
- package/dist/tools/cli-history-store.d.ts +330 -0
- package/dist/tools/cli-history-store.d.ts.map +1 -0
- package/dist/tools/cli-history-store.js +916 -0
- package/dist/tools/cli-history-store.js.map +1 -0
- package/dist/tools/codex-lens.d.ts +118 -0
- package/dist/tools/codex-lens.d.ts.map +1 -0
- package/dist/tools/codex-lens.js +962 -0
- package/dist/tools/codex-lens.js.map +1 -0
- package/dist/tools/convert-tokens-to-css.d.ts +14 -0
- package/dist/tools/convert-tokens-to-css.d.ts.map +1 -0
- package/dist/tools/convert-tokens-to-css.js +244 -0
- package/dist/tools/convert-tokens-to-css.js.map +1 -0
- package/dist/tools/core-memory.d.ts +66 -0
- package/dist/tools/core-memory.d.ts.map +1 -0
- package/dist/tools/core-memory.js +324 -0
- package/dist/tools/core-memory.js.map +1 -0
- package/dist/tools/detect-changed-modules.d.ts +24 -0
- package/dist/tools/detect-changed-modules.d.ts.map +1 -0
- package/dist/tools/detect-changed-modules.js +277 -0
- package/dist/tools/detect-changed-modules.js.map +1 -0
- package/dist/tools/discover-design-files.d.ts +36 -0
- package/dist/tools/discover-design-files.d.ts.map +1 -0
- package/dist/tools/discover-design-files.js +147 -0
- package/dist/tools/discover-design-files.js.map +1 -0
- package/dist/tools/edit-file.d.ts +28 -0
- package/dist/tools/edit-file.d.ts.map +1 -0
- package/dist/tools/edit-file.js +479 -0
- package/dist/tools/edit-file.js.map +1 -0
- package/dist/tools/generate-module-docs.d.ts +22 -0
- package/dist/tools/generate-module-docs.d.ts.map +1 -0
- package/dist/tools/generate-module-docs.js +379 -0
- package/dist/tools/generate-module-docs.js.map +1 -0
- package/dist/tools/get-modules-by-depth.d.ts +15 -0
- package/dist/tools/get-modules-by-depth.d.ts.map +1 -0
- package/dist/tools/get-modules-by-depth.js +296 -0
- package/dist/tools/get-modules-by-depth.js.map +1 -0
- package/dist/tools/index.d.ts +55 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +304 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/native-session-discovery.d.ts +97 -0
- package/dist/tools/native-session-discovery.d.ts.map +1 -0
- package/dist/tools/native-session-discovery.js +700 -0
- package/dist/tools/native-session-discovery.js.map +1 -0
- package/dist/tools/notifier.d.ts +50 -0
- package/dist/tools/notifier.d.ts.map +1 -0
- package/dist/tools/notifier.js +90 -0
- package/dist/tools/notifier.js.map +1 -0
- package/dist/tools/read-file.d.ts +32 -0
- package/dist/tools/read-file.d.ts.map +1 -0
- package/dist/tools/read-file.js +329 -0
- package/dist/tools/read-file.js.map +1 -0
- package/dist/tools/resume-strategy.d.ts +48 -0
- package/dist/tools/resume-strategy.d.ts.map +1 -0
- package/dist/tools/resume-strategy.js +248 -0
- package/dist/tools/resume-strategy.js.map +1 -0
- package/dist/tools/session-content-parser.d.ts +58 -0
- package/dist/tools/session-content-parser.d.ts.map +1 -0
- package/dist/tools/session-content-parser.js +420 -0
- package/dist/tools/session-content-parser.js.map +1 -0
- package/dist/tools/session-manager.d.ts +9 -0
- package/dist/tools/session-manager.d.ts.map +1 -0
- package/dist/tools/session-manager.js +834 -0
- package/dist/tools/session-manager.js.map +1 -0
- package/dist/tools/smart-context.d.ts +35 -0
- package/dist/tools/smart-context.d.ts.map +1 -0
- package/dist/tools/smart-context.js +182 -0
- package/dist/tools/smart-context.js.map +1 -0
- package/dist/tools/smart-search.d.ts +105 -0
- package/dist/tools/smart-search.d.ts.map +1 -0
- package/dist/tools/smart-search.js +1753 -0
- package/dist/tools/smart-search.js.map +1 -0
- package/dist/tools/storage-manager.d.ts +114 -0
- package/dist/tools/storage-manager.d.ts.map +1 -0
- package/dist/tools/storage-manager.js +392 -0
- package/dist/tools/storage-manager.js.map +1 -0
- package/dist/tools/ui-generate-preview.d.ts +39 -0
- package/dist/tools/ui-generate-preview.d.ts.map +1 -0
- package/dist/tools/ui-generate-preview.js +300 -0
- package/dist/tools/ui-generate-preview.js.map +1 -0
- package/dist/tools/ui-instantiate-prototypes.d.ts +75 -0
- package/dist/tools/ui-instantiate-prototypes.d.ts.map +1 -0
- package/dist/tools/ui-instantiate-prototypes.js +256 -0
- package/dist/tools/ui-instantiate-prototypes.js.map +1 -0
- package/dist/tools/update-module-claude.d.ts +80 -0
- package/dist/tools/update-module-claude.d.ts.map +1 -0
- package/dist/tools/update-module-claude.js +351 -0
- package/dist/tools/update-module-claude.js.map +1 -0
- package/dist/tools/write-file.d.ts +19 -0
- package/dist/tools/write-file.d.ts.map +1 -0
- package/dist/tools/write-file.js +193 -0
- package/dist/tools/write-file.js.map +1 -0
- package/dist/types/config.d.ts +11 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +2 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +4 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/session.d.ts +20 -0
- package/dist/types/session.d.ts.map +1 -0
- package/dist/types/session.js +2 -0
- package/dist/types/session.js.map +1 -0
- package/dist/types/tool.d.ts +36 -0
- package/dist/types/tool.d.ts.map +1 -0
- package/dist/types/tool.js +11 -0
- package/dist/types/tool.js.map +1 -0
- package/dist/utils/browser-launcher.d.ts +13 -0
- package/dist/utils/browser-launcher.d.ts.map +1 -0
- package/dist/utils/browser-launcher.js +60 -0
- package/dist/utils/browser-launcher.js.map +1 -0
- package/dist/utils/file-utils.d.ts +25 -0
- package/dist/utils/file-utils.d.ts.map +1 -0
- package/dist/utils/file-utils.js +48 -0
- package/dist/utils/file-utils.js.map +1 -0
- package/dist/utils/path-resolver.d.ts +80 -0
- package/dist/utils/path-resolver.d.ts.map +1 -0
- package/dist/utils/path-resolver.js +260 -0
- package/dist/utils/path-resolver.js.map +1 -0
- package/dist/utils/path-validator.d.ts +49 -0
- package/dist/utils/path-validator.d.ts.map +1 -0
- package/dist/utils/path-validator.js +123 -0
- package/dist/utils/path-validator.js.map +1 -0
- package/dist/utils/ui.d.ts +62 -0
- package/dist/utils/ui.d.ts.map +1 -0
- package/dist/utils/ui.js +129 -0
- package/dist/utils/ui.js.map +1 -0
- package/package.json +65 -67
- package/src/.workflow/.cli-history/history.db +0 -0
- package/src/.workflow/.cli-history/history.db-shm +0 -0
- package/src/.workflow/.cli-history/history.db-wal +0 -0
- package/src/cli.ts +244 -0
- package/src/commands/cli.ts +740 -0
- package/src/commands/core-memory.ts +770 -0
- package/src/commands/hook.ts +315 -0
- package/src/commands/install.ts +519 -0
- package/src/commands/list.ts +37 -0
- package/src/commands/memory.ts +1090 -0
- package/src/commands/serve.ts +76 -0
- package/src/commands/session-path-resolver.ts +372 -0
- package/src/commands/session.ts +1141 -0
- package/src/commands/stop.ts +111 -0
- package/src/commands/tool.ts +201 -0
- package/src/commands/uninstall.ts +287 -0
- package/src/commands/upgrade.ts +352 -0
- package/src/commands/view.ts +119 -0
- package/src/config/storage-paths.ts +670 -0
- package/src/core/cache-manager.ts +294 -0
- package/src/core/claude-freshness.ts +319 -0
- package/src/core/core-memory-store.ts +1528 -0
- package/src/core/dashboard-generator-patch.ts +47 -0
- package/src/core/dashboard-generator.ts +739 -0
- package/src/core/data-aggregator.ts +584 -0
- package/src/core/history-importer.ts +625 -0
- package/src/core/lite-scanner-complete.ts +469 -0
- package/src/core/lite-scanner.ts +469 -0
- package/src/core/manifest.ts +271 -0
- package/src/core/memory-embedder-bridge.ts +262 -0
- package/src/core/memory-store.ts +978 -0
- package/src/core/routes/ccw-routes.ts +96 -0
- package/src/core/routes/claude-routes.ts +1183 -0
- package/src/core/routes/cli-routes.ts +561 -0
- package/src/core/routes/codexlens-routes.ts +806 -0
- package/src/core/routes/core-memory-routes.ts +605 -0
- package/src/core/routes/files-routes.ts +428 -0
- package/src/core/routes/graph-routes.md +164 -0
- package/src/core/routes/graph-routes.ts +626 -0
- package/src/core/routes/help-routes.ts +308 -0
- package/src/core/routes/hooks-routes.ts +405 -0
- package/src/core/routes/mcp-routes.ts +1271 -0
- package/src/core/routes/mcp-routes.ts.backup +550 -0
- package/src/core/routes/mcp-templates-db.ts +268 -0
- package/src/core/routes/memory-routes.ts +1206 -0
- package/src/core/routes/rules-routes.ts +526 -0
- package/src/core/routes/session-routes.ts +467 -0
- package/src/core/routes/skills-routes.ts +599 -0
- package/src/core/routes/status-routes.ts +57 -0
- package/src/core/routes/system-routes.ts +427 -0
- package/src/core/server.ts +431 -0
- package/src/core/session-clustering-service.ts +1258 -0
- package/src/core/session-scanner.ts +283 -0
- package/src/core/websocket.ts +190 -0
- package/src/index.ts +10 -0
- package/src/mcp-server/index.ts +186 -0
- package/src/templates/assets/css/github-dark.min.css +10 -0
- package/src/templates/assets/css/github.min.css +10 -0
- package/src/templates/assets/js/cytoscape.min.js +32 -0
- package/src/templates/assets/js/d3.min.js +2 -0
- package/src/templates/assets/js/highlight.min.js +1244 -0
- package/src/templates/assets/js/lucide.min.js +12 -0
- package/src/templates/assets/js/marked.min.js +69 -0
- package/src/templates/assets/js/tailwind.js +83 -0
- package/src/templates/dashboard-css/01-base.css +302 -0
- package/src/templates/dashboard-css/02-session.css +748 -0
- package/src/templates/dashboard-css/04-lite-tasks.css +1181 -0
- package/src/templates/dashboard-css/06-cards.css +1576 -0
- package/src/templates/dashboard-css/07-managers.css +2107 -0
- package/src/templates/dashboard-css/09-explorer.css +1408 -0
- package/src/templates/dashboard-css/10-cli-status.css +337 -0
- package/src/templates/dashboard-css/11-cli-history.css +271 -0
- package/src/templates/dashboard-css/12-cli-legacy.css +796 -0
- package/src/templates/dashboard-css/13-cli-ccw.css +199 -0
- package/src/templates/dashboard-css/14-cli-modals.css +258 -0
- package/src/templates/dashboard-css/15-cli-endpoints.css +305 -0
- package/src/templates/dashboard-css/16-cli-session.css +241 -0
- package/src/templates/dashboard-css/17-cli-conversation.css +283 -0
- package/src/templates/dashboard-css/18-cli-settings.css +160 -0
- package/src/templates/dashboard-css/19-cli-native-session.css +496 -0
- package/src/templates/dashboard-css/20-cli-taskqueue.css +188 -0
- package/src/templates/dashboard-css/21-cli-toolmgmt.css +310 -0
- package/src/templates/dashboard-css/22-cli-semantic.css +240 -0
- package/src/templates/dashboard-css/23-memory.css +2390 -0
- package/src/templates/dashboard-css/24-prompt-history.css +1089 -0
- package/src/templates/dashboard-css/25-skills-rules.css +326 -0
- package/src/templates/dashboard-css/26-claude-manager.css +908 -0
- package/src/templates/dashboard-css/27-graph-explorer.css +1678 -0
- package/src/templates/dashboard-css/28-mcp-manager.css +748 -0
- package/src/templates/dashboard-css/29-help.css +264 -0
- package/src/templates/dashboard-css/30-core-memory.css +1700 -0
- package/src/templates/dashboard-js/api.js +220 -0
- package/src/templates/dashboard-js/components/carousel.js +398 -0
- package/src/templates/dashboard-js/components/cli-history.js +876 -0
- package/src/templates/dashboard-js/components/cli-status.js +978 -0
- package/src/templates/dashboard-js/components/global-notifications.js +508 -0
- package/src/templates/dashboard-js/components/hook-manager.js +1278 -0
- package/src/templates/dashboard-js/components/index-manager.js +302 -0
- package/src/templates/dashboard-js/components/mcp-manager.js +1219 -0
- package/src/templates/dashboard-js/components/modals.js +326 -0
- package/src/templates/dashboard-js/components/navigation.js +313 -0
- package/src/templates/dashboard-js/components/notifications.js +758 -0
- package/src/templates/dashboard-js/components/storage-manager.js +478 -0
- package/src/templates/dashboard-js/components/tabs-other.js +424 -0
- package/src/templates/dashboard-js/components/task-queue-sidebar.js +716 -0
- package/src/templates/dashboard-js/help-i18n.js +272 -0
- package/src/templates/dashboard-js/i18n.js +2807 -0
- package/src/templates/dashboard-js/main.js +87 -0
- package/src/templates/dashboard-js/state.js +243 -0
- package/src/templates/dashboard-js/utils.js +199 -0
- package/src/templates/dashboard-js/views/claude-manager.js +912 -0
- package/src/templates/dashboard-js/views/cli-manager.js +2272 -0
- package/src/templates/dashboard-js/views/codexlens-manager.js +964 -0
- package/src/templates/dashboard-js/views/core-memory-clusters.js +503 -0
- package/src/templates/dashboard-js/views/core-memory.js +782 -0
- package/src/templates/dashboard-js/views/explorer.js +888 -0
- package/src/templates/dashboard-js/views/graph-explorer.js +1157 -0
- package/src/templates/dashboard-js/views/help.js +856 -0
- package/src/templates/dashboard-js/views/history.js +337 -0
- package/src/templates/dashboard-js/views/home.js +243 -0
- package/src/templates/dashboard-js/views/hook-manager.js +660 -0
- package/src/templates/dashboard-js/views/lite-tasks.js +861 -0
- package/src/templates/dashboard-js/views/mcp-manager.js +2187 -0
- package/src/templates/dashboard-js/views/mcp-manager.js.backup +1729 -0
- package/src/templates/dashboard-js/views/mcp-manager.js.new +928 -0
- package/src/templates/dashboard-js/views/memory.js +1221 -0
- package/src/templates/dashboard-js/views/prompt-history.js +713 -0
- package/src/templates/dashboard-js/views/rules-manager.js +828 -0
- package/src/templates/dashboard-js/views/session-detail.js +781 -0
- package/src/templates/dashboard-js/views/skills-manager.js +819 -0
- package/src/templates/dashboard.html +831 -0
- package/src/templates/hooks-config-example.json +60 -0
- package/src/tools/classify-folders.ts +245 -0
- package/src/tools/cli-config-manager.ts +268 -0
- package/src/tools/cli-executor.ts +2014 -0
- package/src/tools/cli-history-store.ts +1195 -0
- package/src/tools/codex-lens.ts +1141 -0
- package/src/tools/convert-tokens-to-css.ts +300 -0
- package/src/tools/core-memory.ts +444 -0
- package/src/tools/detect-changed-modules.ts +325 -0
- package/src/tools/discover-design-files.ts +184 -0
- package/src/tools/edit-file.ts +568 -0
- package/src/tools/generate-module-docs.ts +438 -0
- package/src/tools/get-modules-by-depth.ts +349 -0
- package/src/tools/index.ts +370 -0
- package/src/tools/native-session-discovery.ts +795 -0
- package/src/tools/notifier.ts +129 -0
- package/src/tools/read-file.ts +410 -0
- package/src/tools/resume-strategy.ts +345 -0
- package/src/tools/session-content-parser.ts +619 -0
- package/src/tools/session-manager.ts +1026 -0
- package/src/tools/smart-context.ts +228 -0
- package/src/tools/smart-search.ts +2065 -0
- package/src/tools/smart-search.ts.backup +1233 -0
- package/src/tools/storage-manager.ts +455 -0
- package/src/tools/write-file.ts +222 -0
- package/src/types/config.ts +11 -0
- package/src/types/index.ts +3 -0
- package/src/types/session.ts +25 -0
- package/src/types/tool.ts +41 -0
- package/src/utils/browser-launcher.ts +62 -0
- package/src/utils/file-utils.ts +48 -0
- package/src/utils/path-resolver.ts +315 -0
- package/src/utils/path-validator.ts +153 -0
- package/src/utils/ui.ts +155 -0
- package/.claude/agents/action-planning-agent.md +0 -778
- package/.claude/agents/cli-execution-agent.md +0 -270
- package/.claude/agents/cli-explore-agent.md +0 -182
- package/.claude/agents/cli-lite-planning-agent.md +0 -396
- package/.claude/agents/cli-planning-agent.md +0 -558
- package/.claude/agents/code-developer.md +0 -310
- package/.claude/agents/conceptual-planning-agent.md +0 -308
- package/.claude/agents/context-search-agent.md +0 -582
- package/.claude/agents/doc-generator.md +0 -330
- package/.claude/agents/memory-bridge.md +0 -94
- package/.claude/agents/test-context-search-agent.md +0 -399
- package/.claude/agents/test-fix-agent.md +0 -343
- package/.claude/agents/ui-design-agent.md +0 -593
- package/.claude/agents/universal-executor.md +0 -131
- package/.claude/commands/cli/cli-init.md +0 -440
- package/.claude/commands/enhance-prompt.md +0 -93
- package/.claude/commands/memory/code-map-memory.md +0 -687
- package/.claude/commands/memory/docs-full-cli.md +0 -471
- package/.claude/commands/memory/docs-related-cli.md +0 -386
- package/.claude/commands/memory/docs.md +0 -615
- package/.claude/commands/memory/load-skill-memory.md +0 -182
- package/.claude/commands/memory/load.md +0 -240
- package/.claude/commands/memory/skill-memory.md +0 -525
- package/.claude/commands/memory/style-skill-memory.md +0 -396
- package/.claude/commands/memory/tech-research.md +0 -477
- package/.claude/commands/memory/update-full.md +0 -332
- package/.claude/commands/memory/update-related.md +0 -332
- package/.claude/commands/memory/workflow-skill-memory.md +0 -517
- package/.claude/commands/task/breakdown.md +0 -204
- package/.claude/commands/task/create.md +0 -152
- package/.claude/commands/task/execute.md +0 -270
- package/.claude/commands/task/replan.md +0 -437
- package/.claude/commands/version.md +0 -254
- package/.claude/commands/workflow/action-plan-verify.md +0 -447
- package/.claude/commands/workflow/brainstorm/api-designer.md +0 -585
- package/.claude/commands/workflow/brainstorm/artifacts.md +0 -452
- package/.claude/commands/workflow/brainstorm/auto-parallel.md +0 -443
- package/.claude/commands/workflow/brainstorm/data-architect.md +0 -220
- package/.claude/commands/workflow/brainstorm/product-manager.md +0 -200
- package/.claude/commands/workflow/brainstorm/product-owner.md +0 -200
- package/.claude/commands/workflow/brainstorm/scrum-master.md +0 -200
- package/.claude/commands/workflow/brainstorm/subject-matter-expert.md +0 -200
- package/.claude/commands/workflow/brainstorm/synthesis.md +0 -398
- package/.claude/commands/workflow/brainstorm/system-architect.md +0 -387
- package/.claude/commands/workflow/brainstorm/ui-designer.md +0 -221
- package/.claude/commands/workflow/brainstorm/ux-expert.md +0 -221
- package/.claude/commands/workflow/execute.md +0 -460
- package/.claude/commands/workflow/init.md +0 -164
- package/.claude/commands/workflow/lite-execute.md +0 -686
- package/.claude/commands/workflow/lite-fix.md +0 -621
- package/.claude/commands/workflow/lite-plan.md +0 -592
- package/.claude/commands/workflow/plan.md +0 -551
- package/.claude/commands/workflow/replan.md +0 -515
- package/.claude/commands/workflow/review-fix.md +0 -606
- package/.claude/commands/workflow/review-module-cycle.md +0 -765
- package/.claude/commands/workflow/review-session-cycle.md +0 -776
- package/.claude/commands/workflow/review.md +0 -291
- package/.claude/commands/workflow/session/complete.md +0 -500
- package/.claude/commands/workflow/session/list.md +0 -96
- package/.claude/commands/workflow/session/resume.md +0 -61
- package/.claude/commands/workflow/session/start.md +0 -200
- package/.claude/commands/workflow/tdd-plan.md +0 -460
- package/.claude/commands/workflow/tdd-verify.md +0 -386
- package/.claude/commands/workflow/test-cycle-execute.md +0 -498
- package/.claude/commands/workflow/test-fix-gen.md +0 -699
- package/.claude/commands/workflow/test-gen.md +0 -529
- package/.claude/commands/workflow/tools/conflict-resolution.md +0 -680
- package/.claude/commands/workflow/tools/context-gather.md +0 -434
- package/.claude/commands/workflow/tools/task-generate-agent.md +0 -291
- package/.claude/commands/workflow/tools/task-generate-tdd.md +0 -518
- package/.claude/commands/workflow/tools/tdd-coverage-analysis.md +0 -309
- package/.claude/commands/workflow/tools/test-concept-enhanced.md +0 -163
- package/.claude/commands/workflow/tools/test-context-gather.md +0 -235
- package/.claude/commands/workflow/tools/test-task-generate.md +0 -256
- package/.claude/commands/workflow/ui-design/animation-extract.md +0 -1150
- package/.claude/commands/workflow/ui-design/codify-style.md +0 -652
- package/.claude/commands/workflow/ui-design/design-sync.md +0 -454
- package/.claude/commands/workflow/ui-design/explore-auto.md +0 -678
- package/.claude/commands/workflow/ui-design/generate.md +0 -504
- package/.claude/commands/workflow/ui-design/imitate-auto.md +0 -745
- package/.claude/commands/workflow/ui-design/import-from-code.md +0 -537
- package/.claude/commands/workflow/ui-design/layout-extract.md +0 -788
- package/.claude/commands/workflow/ui-design/reference-page-generator.md +0 -356
- package/.claude/commands/workflow/ui-design/style-extract.md +0 -773
- 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/skills/command-guide/SKILL.md +0 -388
- package/.claude/skills/command-guide/UPDATE-GUIDELINE.md +0 -592
- package/.claude/skills/command-guide/guides/cli-tools-guide.md +0 -410
- package/.claude/skills/command-guide/guides/examples.md +0 -537
- package/.claude/skills/command-guide/guides/getting-started.md +0 -242
- package/.claude/skills/command-guide/guides/implementation-details.md +0 -1010
- package/.claude/skills/command-guide/guides/index-structure.md +0 -326
- package/.claude/skills/command-guide/guides/troubleshooting.md +0 -92
- package/.claude/skills/command-guide/guides/ui-design-workflow-guide.md +0 -316
- package/.claude/skills/command-guide/guides/workflow-patterns.md +0 -662
- package/.claude/skills/command-guide/index/all-commands.json +0 -772
- package/.claude/skills/command-guide/index/by-category.json +0 -800
- package/.claude/skills/command-guide/index/by-use-case.json +0 -786
- package/.claude/skills/command-guide/index/command-relationships.json +0 -307
- package/.claude/skills/command-guide/index/essential-commands.json +0 -112
- package/.claude/skills/command-guide/reference/agents/action-planning-agent.md +0 -778
- package/.claude/skills/command-guide/reference/agents/cli-execution-agent.md +0 -270
- package/.claude/skills/command-guide/reference/agents/cli-explore-agent.md +0 -182
- package/.claude/skills/command-guide/reference/agents/cli-lite-planning-agent.md +0 -396
- package/.claude/skills/command-guide/reference/agents/cli-planning-agent.md +0 -558
- package/.claude/skills/command-guide/reference/agents/code-developer.md +0 -310
- package/.claude/skills/command-guide/reference/agents/conceptual-planning-agent.md +0 -308
- package/.claude/skills/command-guide/reference/agents/context-search-agent.md +0 -582
- package/.claude/skills/command-guide/reference/agents/doc-generator.md +0 -330
- package/.claude/skills/command-guide/reference/agents/memory-bridge.md +0 -94
- package/.claude/skills/command-guide/reference/agents/test-context-search-agent.md +0 -399
- package/.claude/skills/command-guide/reference/agents/test-fix-agent.md +0 -343
- package/.claude/skills/command-guide/reference/agents/ui-design-agent.md +0 -593
- package/.claude/skills/command-guide/reference/agents/universal-executor.md +0 -131
- package/.claude/skills/command-guide/reference/commands/cli/cli-init.md +0 -440
- package/.claude/skills/command-guide/reference/commands/enhance-prompt.md +0 -93
- package/.claude/skills/command-guide/reference/commands/memory/code-map-memory.md +0 -687
- package/.claude/skills/command-guide/reference/commands/memory/docs-full-cli.md +0 -471
- package/.claude/skills/command-guide/reference/commands/memory/docs-related-cli.md +0 -386
- package/.claude/skills/command-guide/reference/commands/memory/docs.md +0 -615
- package/.claude/skills/command-guide/reference/commands/memory/load-skill-memory.md +0 -182
- package/.claude/skills/command-guide/reference/commands/memory/load.md +0 -240
- package/.claude/skills/command-guide/reference/commands/memory/skill-memory.md +0 -525
- package/.claude/skills/command-guide/reference/commands/memory/style-skill-memory.md +0 -396
- package/.claude/skills/command-guide/reference/commands/memory/tech-research.md +0 -477
- package/.claude/skills/command-guide/reference/commands/memory/update-full.md +0 -332
- package/.claude/skills/command-guide/reference/commands/memory/update-related.md +0 -332
- package/.claude/skills/command-guide/reference/commands/memory/workflow-skill-memory.md +0 -517
- package/.claude/skills/command-guide/reference/commands/task/breakdown.md +0 -204
- package/.claude/skills/command-guide/reference/commands/task/create.md +0 -152
- package/.claude/skills/command-guide/reference/commands/task/execute.md +0 -270
- package/.claude/skills/command-guide/reference/commands/task/replan.md +0 -437
- package/.claude/skills/command-guide/reference/commands/version.md +0 -254
- package/.claude/skills/command-guide/reference/commands/workflow/action-plan-verify.md +0 -447
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/api-designer.md +0 -585
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/artifacts.md +0 -452
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/auto-parallel.md +0 -443
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/data-architect.md +0 -220
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/product-manager.md +0 -200
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/product-owner.md +0 -200
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/scrum-master.md +0 -200
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/subject-matter-expert.md +0 -200
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/synthesis.md +0 -398
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/system-architect.md +0 -387
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/ui-designer.md +0 -221
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/ux-expert.md +0 -221
- package/.claude/skills/command-guide/reference/commands/workflow/execute.md +0 -460
- package/.claude/skills/command-guide/reference/commands/workflow/init.md +0 -164
- package/.claude/skills/command-guide/reference/commands/workflow/lite-execute.md +0 -686
- package/.claude/skills/command-guide/reference/commands/workflow/lite-fix.md +0 -621
- package/.claude/skills/command-guide/reference/commands/workflow/lite-plan.md +0 -592
- package/.claude/skills/command-guide/reference/commands/workflow/plan.md +0 -551
- package/.claude/skills/command-guide/reference/commands/workflow/replan.md +0 -515
- package/.claude/skills/command-guide/reference/commands/workflow/review-fix.md +0 -606
- package/.claude/skills/command-guide/reference/commands/workflow/review-module-cycle.md +0 -765
- package/.claude/skills/command-guide/reference/commands/workflow/review-session-cycle.md +0 -776
- package/.claude/skills/command-guide/reference/commands/workflow/review.md +0 -291
- package/.claude/skills/command-guide/reference/commands/workflow/session/complete.md +0 -500
- package/.claude/skills/command-guide/reference/commands/workflow/session/list.md +0 -96
- package/.claude/skills/command-guide/reference/commands/workflow/session/resume.md +0 -61
- package/.claude/skills/command-guide/reference/commands/workflow/session/start.md +0 -200
- package/.claude/skills/command-guide/reference/commands/workflow/tdd-plan.md +0 -460
- package/.claude/skills/command-guide/reference/commands/workflow/tdd-verify.md +0 -386
- package/.claude/skills/command-guide/reference/commands/workflow/test-cycle-execute.md +0 -498
- package/.claude/skills/command-guide/reference/commands/workflow/test-fix-gen.md +0 -699
- package/.claude/skills/command-guide/reference/commands/workflow/test-gen.md +0 -529
- package/.claude/skills/command-guide/reference/commands/workflow/tools/conflict-resolution.md +0 -680
- package/.claude/skills/command-guide/reference/commands/workflow/tools/context-gather.md +0 -434
- package/.claude/skills/command-guide/reference/commands/workflow/tools/task-generate-agent.md +0 -291
- package/.claude/skills/command-guide/reference/commands/workflow/tools/task-generate-tdd.md +0 -518
- package/.claude/skills/command-guide/reference/commands/workflow/tools/tdd-coverage-analysis.md +0 -309
- package/.claude/skills/command-guide/reference/commands/workflow/tools/test-concept-enhanced.md +0 -163
- package/.claude/skills/command-guide/reference/commands/workflow/tools/test-context-gather.md +0 -235
- package/.claude/skills/command-guide/reference/commands/workflow/tools/test-task-generate.md +0 -256
- package/.claude/skills/command-guide/reference/commands/workflow/ui-design/animation-extract.md +0 -1150
- package/.claude/skills/command-guide/reference/commands/workflow/ui-design/codify-style.md +0 -652
- package/.claude/skills/command-guide/reference/commands/workflow/ui-design/design-sync.md +0 -454
- package/.claude/skills/command-guide/reference/commands/workflow/ui-design/explore-auto.md +0 -678
- package/.claude/skills/command-guide/reference/commands/workflow/ui-design/generate.md +0 -504
- package/.claude/skills/command-guide/reference/commands/workflow/ui-design/imitate-auto.md +0 -745
- package/.claude/skills/command-guide/reference/commands/workflow/ui-design/import-from-code.md +0 -537
- package/.claude/skills/command-guide/reference/commands/workflow/ui-design/layout-extract.md +0 -788
- package/.claude/skills/command-guide/reference/commands/workflow/ui-design/reference-page-generator.md +0 -356
- package/.claude/skills/command-guide/reference/commands/workflow/ui-design/style-extract.md +0 -773
- package/.claude/skills/command-guide/scripts/analyze_commands.py +0 -502
- package/.claude/skills/command-guide/scripts/update-index.sh +0 -130
- package/.claude/skills/command-guide/templates/issue-bug.md +0 -104
- package/.claude/skills/command-guide/templates/issue-diagnosis.md +0 -275
- package/.claude/skills/command-guide/templates/issue-feature.md +0 -97
- package/.claude/skills/command-guide/templates/issue-question.md +0 -141
- package/.claude/skills/prompt-enhancer/SKILL.md +0 -124
- package/.claude/workflows/_template-compare-matrix.html +0 -692
- package/.claude/workflows/cli-templates/fix-plan-template.json +0 -75
- package/.claude/workflows/cli-templates/fix-progress-template.json +0 -48
- package/.claude/workflows/cli-templates/memory/style-skill-memory/skill-md-template.md +0 -299
- package/.claude/workflows/cli-templates/planning-roles/data-architect.md +0 -120
- package/.claude/workflows/cli-templates/planning-roles/product-manager.md +0 -119
- package/.claude/workflows/cli-templates/planning-roles/product-owner.md +0 -261
- package/.claude/workflows/cli-templates/planning-roles/scrum-master.md +0 -186
- package/.claude/workflows/cli-templates/planning-roles/subject-matter-expert.md +0 -281
- package/.claude/workflows/cli-templates/planning-roles/synthesis-role.md +0 -414
- package/.claude/workflows/cli-templates/planning-roles/system-architect.md +0 -106
- package/.claude/workflows/cli-templates/planning-roles/test-strategist.md +0 -124
- package/.claude/workflows/cli-templates/planning-roles/ui-designer.md +0 -379
- package/.claude/workflows/cli-templates/planning-roles/ux-expert.md +0 -240
- package/.claude/workflows/cli-templates/prompts/analysis/01-diagnose-bug-root-cause.txt +0 -127
- package/.claude/workflows/cli-templates/prompts/analysis/01-trace-code-execution.txt +0 -115
- package/.claude/workflows/cli-templates/prompts/analysis/02-analyze-code-patterns.txt +0 -37
- package/.claude/workflows/cli-templates/prompts/analysis/02-analyze-technical-document.txt +0 -33
- package/.claude/workflows/cli-templates/prompts/analysis/02-review-architecture.txt +0 -29
- package/.claude/workflows/cli-templates/prompts/analysis/02-review-code-quality.txt +0 -28
- package/.claude/workflows/cli-templates/prompts/analysis/03-analyze-performance.txt +0 -29
- package/.claude/workflows/cli-templates/prompts/analysis/03-assess-security-risks.txt +0 -29
- package/.claude/workflows/cli-templates/prompts/analysis/03-review-quality-standards.txt +0 -29
- package/.claude/workflows/cli-templates/prompts/development/02-generate-tests.txt +0 -70
- package/.claude/workflows/cli-templates/prompts/development/02-implement-component-ui.txt +0 -55
- package/.claude/workflows/cli-templates/prompts/development/02-implement-feature.txt +0 -58
- package/.claude/workflows/cli-templates/prompts/development/02-refactor-codebase.txt +0 -55
- package/.claude/workflows/cli-templates/prompts/development/03-debug-runtime-issues.txt +0 -55
- package/.claude/workflows/cli-templates/prompts/documentation/api.txt +0 -15
- package/.claude/workflows/cli-templates/prompts/documentation/folder-navigation.txt +0 -27
- package/.claude/workflows/cli-templates/prompts/documentation/module-readme.txt +0 -49
- package/.claude/workflows/cli-templates/prompts/documentation/project-architecture.txt +0 -41
- package/.claude/workflows/cli-templates/prompts/documentation/project-examples.txt +0 -35
- package/.claude/workflows/cli-templates/prompts/documentation/project-readme.txt +0 -35
- package/.claude/workflows/cli-templates/prompts/memory/02-document-module-structure.txt +0 -165
- package/.claude/workflows/cli-templates/prompts/planning/01-plan-architecture-design.txt +0 -109
- package/.claude/workflows/cli-templates/prompts/planning/02-breakdown-task-steps.txt +0 -30
- package/.claude/workflows/cli-templates/prompts/planning/02-design-component-spec.txt +0 -28
- package/.claude/workflows/cli-templates/prompts/planning/03-evaluate-concept-feasibility.txt +0 -127
- package/.claude/workflows/cli-templates/prompts/planning/03-plan-migration-strategy.txt +0 -30
- package/.claude/workflows/cli-templates/prompts/tech/tech-module-format.txt +0 -359
- package/.claude/workflows/cli-templates/prompts/tech/tech-skill-index.txt +0 -185
- package/.claude/workflows/cli-templates/prompts/test/test-concept-analysis.txt +0 -179
- package/.claude/workflows/cli-templates/prompts/universal/00-universal-creative-style.txt +0 -95
- package/.claude/workflows/cli-templates/prompts/universal/00-universal-rigorous-style.txt +0 -92
- package/.claude/workflows/cli-templates/prompts/verification/codex-technical.txt +0 -28
- package/.claude/workflows/cli-templates/prompts/verification/cross-validation.txt +0 -28
- package/.claude/workflows/cli-templates/prompts/verification/gemini-strategic.txt +0 -27
- package/.claude/workflows/cli-templates/prompts/workflow/analysis-results-structure.txt +0 -224
- package/.claude/workflows/cli-templates/prompts/workflow/codex-feasibility-validation.txt +0 -176
- package/.claude/workflows/cli-templates/prompts/workflow/gemini-solution-design.txt +0 -131
- package/.claude/workflows/cli-templates/prompts/workflow/impl-plan-template.txt +0 -286
- package/.claude/workflows/cli-templates/prompts/workflow/skill-aggregation.txt +0 -172
- package/.claude/workflows/cli-templates/prompts/workflow/skill-conflict-patterns.txt +0 -98
- package/.claude/workflows/cli-templates/prompts/workflow/skill-index.txt +0 -224
- package/.claude/workflows/cli-templates/prompts/workflow/skill-lessons-learned.txt +0 -98
- package/.claude/workflows/cli-templates/prompts/workflow/skill-sessions-timeline.txt +0 -53
- package/.claude/workflows/cli-templates/prompts/workflow/task-json-agent-mode.txt +0 -123
- package/.claude/workflows/cli-templates/prompts/workflow/task-json-cli-mode.txt +0 -182
- package/.claude/workflows/cli-templates/schemas/diagnosis-json-schema.json +0 -234
- package/.claude/workflows/cli-templates/schemas/explore-json-schema.json +0 -124
- package/.claude/workflows/cli-templates/schemas/fix-plan-json-schema.json +0 -273
- package/.claude/workflows/cli-templates/schemas/plan-json-schema.json +0 -219
- package/.claude/workflows/cli-templates/schemas/project-json-schema.json +0 -221
- package/.claude/workflows/cli-templates/schemas/review-deep-dive-results-schema.json +0 -82
- package/.claude/workflows/cli-templates/schemas/review-dimension-results-schema.json +0 -51
- package/.claude/workflows/cli-templates/tech-stacks/go-dev.md +0 -91
- package/.claude/workflows/cli-templates/tech-stacks/java-dev.md +0 -107
- package/.claude/workflows/cli-templates/tech-stacks/javascript-dev.md +0 -58
- package/.claude/workflows/cli-templates/tech-stacks/python-dev.md +0 -79
- package/.claude/workflows/cli-templates/tech-stacks/react-dev.md +0 -103
- package/.claude/workflows/cli-templates/tech-stacks/typescript-dev.md +0 -83
- package/.claude/workflows/cli-templates/ui-design/systems/animation-tokens.json +0 -247
- package/.claude/workflows/cli-templates/ui-design/systems/design-tokens.json +0 -342
- package/.claude/workflows/cli-templates/ui-design/systems/layout-templates.json +0 -145
- package/.claude/workflows/context-search-strategy.md +0 -77
- package/.claude/workflows/intelligent-tools-strategy.md +0 -662
- package/.claude/workflows/review-directory-specification.md +0 -336
- package/.claude/workflows/task-core.md +0 -214
- package/.claude/workflows/tool-strategy.md +0 -79
- package/.claude/workflows/workflow-architecture.md +0 -942
- package/.codex/AGENTS.md +0 -330
- package/.gemini/GEMINI.md +0 -164
- package/.qwen/QWEN.md +0 -164
- package/CLAUDE.md +0 -91
- package/LICENSE +0 -21
- package/ccw/README.md +0 -121
- package/ccw/bin/ccw.js +0 -10
- package/ccw/package.json +0 -47
- package/ccw/src/cli.js +0 -119
- package/ccw/src/commands/install.js +0 -324
- package/ccw/src/commands/list.js +0 -37
- package/ccw/src/commands/serve.js +0 -67
- package/ccw/src/commands/stop.js +0 -101
- package/ccw/src/commands/tool.js +0 -138
- package/ccw/src/commands/uninstall.js +0 -238
- package/ccw/src/commands/upgrade.js +0 -307
- package/ccw/src/commands/view.js +0 -105
- package/ccw/src/core/dashboard-generator-patch.js +0 -29
- package/ccw/src/core/dashboard-generator.js +0 -682
- package/ccw/src/core/data-aggregator.js +0 -409
- package/ccw/src/core/lite-scanner.js +0 -314
- package/ccw/src/core/manifest.js +0 -201
- package/ccw/src/core/server.js +0 -2063
- package/ccw/src/core/session-scanner.js +0 -235
- package/ccw/src/index.js +0 -9
- package/ccw/src/templates/dashboard-css/01-base.css +0 -291
- package/ccw/src/templates/dashboard-css/02-session.css +0 -726
- package/ccw/src/templates/dashboard-css/04-lite-tasks.css +0 -843
- package/ccw/src/templates/dashboard-css/06-cards.css +0 -1570
- package/ccw/src/templates/dashboard-css/07-managers.css +0 -936
- package/ccw/src/templates/dashboard-css/09-explorer.css +0 -1397
- package/ccw/src/templates/dashboard-js/api.js +0 -200
- package/ccw/src/templates/dashboard-js/components/carousel.js +0 -398
- package/ccw/src/templates/dashboard-js/components/global-notifications.js +0 -219
- package/ccw/src/templates/dashboard-js/components/hook-manager.js +0 -283
- package/ccw/src/templates/dashboard-js/components/mcp-manager.js +0 -528
- package/ccw/src/templates/dashboard-js/components/modals.js +0 -260
- package/ccw/src/templates/dashboard-js/components/navigation.js +0 -245
- package/ccw/src/templates/dashboard-js/components/notifications.js +0 -194
- package/ccw/src/templates/dashboard-js/components/tabs-other.js +0 -273
- package/ccw/src/templates/dashboard-js/main.js +0 -72
- package/ccw/src/templates/dashboard-js/state.js +0 -42
- package/ccw/src/templates/dashboard-js/utils.js +0 -153
- package/ccw/src/templates/dashboard-js/views/explorer.js +0 -852
- package/ccw/src/templates/dashboard-js/views/home.js +0 -197
- package/ccw/src/templates/dashboard-js/views/hook-manager.js +0 -392
- package/ccw/src/templates/dashboard-js/views/lite-tasks.js +0 -395
- package/ccw/src/templates/dashboard-js/views/mcp-manager.js +0 -411
- package/ccw/src/templates/dashboard-js/views/session-detail.js +0 -780
- package/ccw/src/templates/dashboard.html +0 -731
- package/ccw/src/tools/classify-folders.js +0 -204
- package/ccw/src/tools/convert-tokens-to-css.js +0 -250
- package/ccw/src/tools/detect-changed-modules.js +0 -288
- package/ccw/src/tools/discover-design-files.js +0 -134
- package/ccw/src/tools/edit-file.js +0 -266
- package/ccw/src/tools/generate-module-docs.js +0 -416
- package/ccw/src/tools/get-modules-by-depth.js +0 -308
- package/ccw/src/tools/index.js +0 -176
- package/ccw/src/utils/browser-launcher.js +0 -60
- package/ccw/src/utils/file-utils.js +0 -48
- package/ccw/src/utils/path-resolver.js +0 -279
- package/ccw/src/utils/ui.js +0 -148
- /package/{ccw/src → src}/templates/dashboard-css/03-tasks.css +0 -0
- /package/{ccw/src → src}/templates/dashboard-css/05-context.css +0 -0
- /package/{ccw/src → src}/templates/dashboard-css/08-review.css +0 -0
- /package/{ccw/src → src}/templates/dashboard-js/components/_conflict_tab.js +0 -0
- /package/{ccw/src → src}/templates/dashboard-js/components/_exp_helpers.js +0 -0
- /package/{ccw/src → src}/templates/dashboard-js/components/_review_tab.js +0 -0
- /package/{ccw/src → src}/templates/dashboard-js/components/flowchart.js +0 -0
- /package/{ccw/src → src}/templates/dashboard-js/components/sidebar.js +0 -0
- /package/{ccw/src → src}/templates/dashboard-js/components/tabs-context.js +0 -0
- /package/{ccw/src → src}/templates/dashboard-js/components/task-drawer-core.js +0 -0
- /package/{ccw/src → src}/templates/dashboard-js/components/task-drawer-renderers.js +0 -0
- /package/{ccw/src → src}/templates/dashboard-js/components/theme.js +0 -0
- /package/{ccw/src → src}/templates/dashboard-js/components/version-check.js +0 -0
- /package/{ccw/src → src}/templates/dashboard-js/views/fix-session.js +0 -0
- /package/{ccw/src → src}/templates/dashboard-js/views/project-overview.js +0 -0
- /package/{ccw/src → src}/templates/dashboard-js/views/review-session.js +0 -0
- /package/{ccw/src → src}/templates/review-cycle-dashboard.html +0 -0
- /package/{ccw/src → src}/templates/workflow-dashboard.html +0 -0
- /package/{ccw/src → src}/tools/ui-generate-preview.js +0 -0
- /package/{ccw/src → src}/tools/ui-instantiate-prototypes.js +0 -0
- /package/{ccw/src → src}/tools/update-module-claude.js +0 -0
package/ccw/src/core/server.js
DELETED
|
@@ -1,2063 +0,0 @@
|
|
|
1
|
-
import http from 'http';
|
|
2
|
-
import { URL } from 'url';
|
|
3
|
-
import { readFileSync, writeFileSync, existsSync, readdirSync, mkdirSync, statSync, promises as fsPromises } from 'fs';
|
|
4
|
-
import { join, dirname } from 'path';
|
|
5
|
-
import { homedir } from 'os';
|
|
6
|
-
import { createHash } from 'crypto';
|
|
7
|
-
import { scanSessions } from './session-scanner.js';
|
|
8
|
-
import { aggregateData } from './data-aggregator.js';
|
|
9
|
-
import { resolvePath, getRecentPaths, trackRecentPath, removeRecentPath, normalizePathForDisplay, getWorkflowDir } from '../utils/path-resolver.js';
|
|
10
|
-
|
|
11
|
-
// Claude config file paths
|
|
12
|
-
const CLAUDE_CONFIG_PATH = join(homedir(), '.claude.json');
|
|
13
|
-
const CLAUDE_SETTINGS_DIR = join(homedir(), '.claude');
|
|
14
|
-
const CLAUDE_GLOBAL_SETTINGS = join(CLAUDE_SETTINGS_DIR, 'settings.json');
|
|
15
|
-
const CLAUDE_GLOBAL_SETTINGS_LOCAL = join(CLAUDE_SETTINGS_DIR, 'settings.local.json');
|
|
16
|
-
|
|
17
|
-
// Enterprise managed MCP paths (platform-specific)
|
|
18
|
-
function getEnterpriseMcpPath() {
|
|
19
|
-
const platform = process.platform;
|
|
20
|
-
if (platform === 'darwin') {
|
|
21
|
-
return '/Library/Application Support/ClaudeCode/managed-mcp.json';
|
|
22
|
-
} else if (platform === 'win32') {
|
|
23
|
-
return 'C:\\Program Files\\ClaudeCode\\managed-mcp.json';
|
|
24
|
-
} else {
|
|
25
|
-
// Linux and WSL
|
|
26
|
-
return '/etc/claude-code/managed-mcp.json';
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// WebSocket clients for real-time notifications
|
|
31
|
-
const wsClients = new Set();
|
|
32
|
-
|
|
33
|
-
const TEMPLATE_PATH = join(import.meta.dirname, '../templates/dashboard.html');
|
|
34
|
-
const MODULE_CSS_DIR = join(import.meta.dirname, '../templates/dashboard-css');
|
|
35
|
-
const JS_FILE = join(import.meta.dirname, '../templates/dashboard.js');
|
|
36
|
-
const MODULE_JS_DIR = join(import.meta.dirname, '../templates/dashboard-js');
|
|
37
|
-
|
|
38
|
-
// Modular CSS files in load order
|
|
39
|
-
const MODULE_CSS_FILES = [
|
|
40
|
-
'01-base.css',
|
|
41
|
-
'02-session.css',
|
|
42
|
-
'03-tasks.css',
|
|
43
|
-
'04-lite-tasks.css',
|
|
44
|
-
'05-context.css',
|
|
45
|
-
'06-cards.css',
|
|
46
|
-
'07-managers.css',
|
|
47
|
-
'08-review.css',
|
|
48
|
-
'09-explorer.css'
|
|
49
|
-
];
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Handle POST request with JSON body
|
|
53
|
-
*/
|
|
54
|
-
function handlePostRequest(req, res, handler) {
|
|
55
|
-
let body = '';
|
|
56
|
-
req.on('data', chunk => { body += chunk; });
|
|
57
|
-
req.on('end', async () => {
|
|
58
|
-
try {
|
|
59
|
-
const parsed = JSON.parse(body);
|
|
60
|
-
const result = await handler(parsed);
|
|
61
|
-
|
|
62
|
-
if (result.error) {
|
|
63
|
-
const status = result.status || 500;
|
|
64
|
-
res.writeHead(status, { 'Content-Type': 'application/json' });
|
|
65
|
-
res.end(JSON.stringify({ error: result.error }));
|
|
66
|
-
} else {
|
|
67
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
68
|
-
res.end(JSON.stringify(result));
|
|
69
|
-
}
|
|
70
|
-
} catch (error) {
|
|
71
|
-
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
72
|
-
res.end(JSON.stringify({ error: error.message }));
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// Modular JS files in dependency order
|
|
78
|
-
const MODULE_FILES = [
|
|
79
|
-
'utils.js',
|
|
80
|
-
'state.js',
|
|
81
|
-
'api.js',
|
|
82
|
-
'components/theme.js',
|
|
83
|
-
'components/modals.js',
|
|
84
|
-
'components/navigation.js',
|
|
85
|
-
'components/sidebar.js',
|
|
86
|
-
'components/carousel.js',
|
|
87
|
-
'components/notifications.js',
|
|
88
|
-
'components/global-notifications.js',
|
|
89
|
-
'components/version-check.js',
|
|
90
|
-
'components/mcp-manager.js',
|
|
91
|
-
'components/hook-manager.js',
|
|
92
|
-
'components/_exp_helpers.js',
|
|
93
|
-
'components/tabs-other.js',
|
|
94
|
-
'components/tabs-context.js',
|
|
95
|
-
'components/_conflict_tab.js',
|
|
96
|
-
'components/_review_tab.js',
|
|
97
|
-
'components/task-drawer-core.js',
|
|
98
|
-
'components/task-drawer-renderers.js',
|
|
99
|
-
'components/flowchart.js',
|
|
100
|
-
'views/home.js',
|
|
101
|
-
'views/project-overview.js',
|
|
102
|
-
'views/session-detail.js',
|
|
103
|
-
'views/review-session.js',
|
|
104
|
-
'views/lite-tasks.js',
|
|
105
|
-
'views/fix-session.js',
|
|
106
|
-
'views/mcp-manager.js',
|
|
107
|
-
'views/hook-manager.js',
|
|
108
|
-
'views/explorer.js',
|
|
109
|
-
'main.js'
|
|
110
|
-
];
|
|
111
|
-
/**
|
|
112
|
-
* Create and start the dashboard server
|
|
113
|
-
* @param {Object} options - Server options
|
|
114
|
-
* @param {number} options.port - Port to listen on (default: 3456)
|
|
115
|
-
* @param {string} options.initialPath - Initial project path
|
|
116
|
-
* @returns {Promise<http.Server>}
|
|
117
|
-
*/
|
|
118
|
-
export async function startServer(options = {}) {
|
|
119
|
-
const port = options.port || 3456;
|
|
120
|
-
const initialPath = options.initialPath || process.cwd();
|
|
121
|
-
|
|
122
|
-
const server = http.createServer(async (req, res) => {
|
|
123
|
-
const url = new URL(req.url, `http://localhost:${port}`);
|
|
124
|
-
const pathname = url.pathname;
|
|
125
|
-
|
|
126
|
-
// CORS headers for API requests
|
|
127
|
-
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
128
|
-
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
129
|
-
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
130
|
-
|
|
131
|
-
if (req.method === 'OPTIONS') {
|
|
132
|
-
res.writeHead(200);
|
|
133
|
-
res.end();
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
try {
|
|
138
|
-
// Debug log for API requests
|
|
139
|
-
if (pathname.startsWith('/api/')) {
|
|
140
|
-
console.log(`[API] ${req.method} ${pathname}`);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// API: Get workflow data for a path
|
|
144
|
-
if (pathname === '/api/data') {
|
|
145
|
-
const projectPath = url.searchParams.get('path') || initialPath;
|
|
146
|
-
const data = await getWorkflowData(projectPath);
|
|
147
|
-
|
|
148
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
149
|
-
res.end(JSON.stringify(data));
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// API: Get recent paths
|
|
154
|
-
if (pathname === '/api/recent-paths') {
|
|
155
|
-
const paths = getRecentPaths();
|
|
156
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
157
|
-
res.end(JSON.stringify({ paths }));
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// API: Switch workspace path (for ccw view command)
|
|
162
|
-
if (pathname === '/api/switch-path') {
|
|
163
|
-
const newPath = url.searchParams.get('path');
|
|
164
|
-
if (!newPath) {
|
|
165
|
-
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
166
|
-
res.end(JSON.stringify({ error: 'Path is required' }));
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
const resolved = resolvePath(newPath);
|
|
171
|
-
if (!existsSync(resolved)) {
|
|
172
|
-
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
173
|
-
res.end(JSON.stringify({ error: 'Path does not exist' }));
|
|
174
|
-
return;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// Track the path and return success
|
|
178
|
-
trackRecentPath(resolved);
|
|
179
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
180
|
-
res.end(JSON.stringify({
|
|
181
|
-
success: true,
|
|
182
|
-
path: resolved,
|
|
183
|
-
recentPaths: getRecentPaths()
|
|
184
|
-
}));
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// API: Health check (for ccw view to detect running server)
|
|
189
|
-
if (pathname === '/api/health') {
|
|
190
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
191
|
-
res.end(JSON.stringify({ status: 'ok', timestamp: Date.now() }));
|
|
192
|
-
return;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// API: Version check (check for npm updates)
|
|
196
|
-
if (pathname === '/api/version-check') {
|
|
197
|
-
const versionData = await checkNpmVersion();
|
|
198
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
199
|
-
res.end(JSON.stringify(versionData));
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
// API: Shutdown server (for ccw stop command)
|
|
205
|
-
if (pathname === '/api/shutdown' && req.method === 'POST') {
|
|
206
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
207
|
-
res.end(JSON.stringify({ status: 'shutting_down' }));
|
|
208
|
-
|
|
209
|
-
// Graceful shutdown
|
|
210
|
-
console.log('\n Received shutdown signal...');
|
|
211
|
-
setTimeout(() => {
|
|
212
|
-
server.close(() => {
|
|
213
|
-
console.log(' Server stopped.\n');
|
|
214
|
-
process.exit(0);
|
|
215
|
-
});
|
|
216
|
-
// Force exit after 3 seconds if graceful shutdown fails
|
|
217
|
-
setTimeout(() => process.exit(0), 3000);
|
|
218
|
-
}, 100);
|
|
219
|
-
return;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// API: Remove a recent path
|
|
223
|
-
if (pathname === '/api/remove-recent-path' && req.method === 'POST') {
|
|
224
|
-
handlePostRequest(req, res, async (body) => {
|
|
225
|
-
const { path } = body;
|
|
226
|
-
if (!path) {
|
|
227
|
-
return { error: 'path is required', status: 400 };
|
|
228
|
-
}
|
|
229
|
-
const removed = removeRecentPath(path);
|
|
230
|
-
return { success: removed, paths: getRecentPaths() };
|
|
231
|
-
});
|
|
232
|
-
return;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
// API: Read a JSON file (for fix progress tracking)
|
|
236
|
-
if (pathname === '/api/file') {
|
|
237
|
-
const filePath = url.searchParams.get('path');
|
|
238
|
-
if (!filePath) {
|
|
239
|
-
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
240
|
-
res.end(JSON.stringify({ error: 'File path is required' }));
|
|
241
|
-
return;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
try {
|
|
245
|
-
const content = await fsPromises.readFile(filePath, 'utf-8');
|
|
246
|
-
const json = JSON.parse(content);
|
|
247
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
248
|
-
res.end(JSON.stringify(json));
|
|
249
|
-
} catch (err) {
|
|
250
|
-
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
251
|
-
res.end(JSON.stringify({ error: 'File not found or invalid JSON' }));
|
|
252
|
-
}
|
|
253
|
-
return;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// API: Get session detail data (context, summaries, impl-plan, review)
|
|
257
|
-
if (pathname === '/api/session-detail') {
|
|
258
|
-
const sessionPath = url.searchParams.get('path');
|
|
259
|
-
const dataType = url.searchParams.get('type') || 'all';
|
|
260
|
-
|
|
261
|
-
if (!sessionPath) {
|
|
262
|
-
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
263
|
-
res.end(JSON.stringify({ error: 'Session path is required' }));
|
|
264
|
-
return;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
const detail = await getSessionDetailData(sessionPath, dataType);
|
|
268
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
269
|
-
res.end(JSON.stringify(detail));
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
// API: Update task status
|
|
274
|
-
if (pathname === '/api/update-task-status' && req.method === 'POST') {
|
|
275
|
-
handlePostRequest(req, res, async (body) => {
|
|
276
|
-
const { sessionPath, taskId, newStatus } = body;
|
|
277
|
-
|
|
278
|
-
if (!sessionPath || !taskId || !newStatus) {
|
|
279
|
-
return { error: 'sessionPath, taskId, and newStatus are required', status: 400 };
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
return await updateTaskStatus(sessionPath, taskId, newStatus);
|
|
283
|
-
});
|
|
284
|
-
return;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
// API: Bulk update task status
|
|
288
|
-
if (pathname === '/api/bulk-update-task-status' && req.method === 'POST') {
|
|
289
|
-
handlePostRequest(req, res, async (body) => {
|
|
290
|
-
const { sessionPath, taskIds, newStatus } = body;
|
|
291
|
-
|
|
292
|
-
if (!sessionPath || !taskIds || !newStatus) {
|
|
293
|
-
return { error: 'sessionPath, taskIds, and newStatus are required', status: 400 };
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
const results = [];
|
|
297
|
-
for (const taskId of taskIds) {
|
|
298
|
-
try {
|
|
299
|
-
const result = await updateTaskStatus(sessionPath, taskId, newStatus);
|
|
300
|
-
results.push(result);
|
|
301
|
-
} catch (err) {
|
|
302
|
-
results.push({ taskId, error: err.message });
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
return { success: true, results };
|
|
306
|
-
});
|
|
307
|
-
return;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
// API: Get MCP configuration
|
|
311
|
-
if (pathname === '/api/mcp-config') {
|
|
312
|
-
const mcpData = getMcpConfig();
|
|
313
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
314
|
-
res.end(JSON.stringify(mcpData));
|
|
315
|
-
return;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
// API: Toggle MCP server enabled/disabled
|
|
319
|
-
if (pathname === '/api/mcp-toggle' && req.method === 'POST') {
|
|
320
|
-
handlePostRequest(req, res, async (body) => {
|
|
321
|
-
const { projectPath, serverName, enable } = body;
|
|
322
|
-
if (!projectPath || !serverName) {
|
|
323
|
-
return { error: 'projectPath and serverName are required', status: 400 };
|
|
324
|
-
}
|
|
325
|
-
return toggleMcpServerEnabled(projectPath, serverName, enable);
|
|
326
|
-
});
|
|
327
|
-
return;
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
// API: Copy MCP server to project
|
|
331
|
-
if (pathname === '/api/mcp-copy-server' && req.method === 'POST') {
|
|
332
|
-
handlePostRequest(req, res, async (body) => {
|
|
333
|
-
const { projectPath, serverName, serverConfig } = body;
|
|
334
|
-
if (!projectPath || !serverName || !serverConfig) {
|
|
335
|
-
return { error: 'projectPath, serverName, and serverConfig are required', status: 400 };
|
|
336
|
-
}
|
|
337
|
-
return addMcpServerToProject(projectPath, serverName, serverConfig);
|
|
338
|
-
});
|
|
339
|
-
return;
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
// API: Remove MCP server from project
|
|
343
|
-
if (pathname === '/api/mcp-remove-server' && req.method === 'POST') {
|
|
344
|
-
handlePostRequest(req, res, async (body) => {
|
|
345
|
-
const { projectPath, serverName } = body;
|
|
346
|
-
if (!projectPath || !serverName) {
|
|
347
|
-
return { error: 'projectPath and serverName are required', status: 400 };
|
|
348
|
-
}
|
|
349
|
-
return removeMcpServerFromProject(projectPath, serverName);
|
|
350
|
-
});
|
|
351
|
-
return;
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
// API: Hook endpoint for Claude Code notifications
|
|
355
|
-
if (pathname === '/api/hook' && req.method === 'POST') {
|
|
356
|
-
handlePostRequest(req, res, async (body) => {
|
|
357
|
-
const { type, filePath, sessionId } = body;
|
|
358
|
-
|
|
359
|
-
// Determine session ID from file path if not provided
|
|
360
|
-
let resolvedSessionId = sessionId;
|
|
361
|
-
if (!resolvedSessionId && filePath) {
|
|
362
|
-
resolvedSessionId = extractSessionIdFromPath(filePath);
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
// Broadcast to all connected WebSocket clients
|
|
366
|
-
const notification = {
|
|
367
|
-
type: type || 'session_updated',
|
|
368
|
-
payload: {
|
|
369
|
-
sessionId: resolvedSessionId,
|
|
370
|
-
filePath: filePath,
|
|
371
|
-
timestamp: new Date().toISOString()
|
|
372
|
-
}
|
|
373
|
-
};
|
|
374
|
-
|
|
375
|
-
broadcastToClients(notification);
|
|
376
|
-
|
|
377
|
-
return { success: true, notification };
|
|
378
|
-
});
|
|
379
|
-
return;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
// API: Get hooks configuration
|
|
383
|
-
if (pathname === '/api/hooks' && req.method === 'GET') {
|
|
384
|
-
const projectPathParam = url.searchParams.get('path');
|
|
385
|
-
const hooksData = getHooksConfig(projectPathParam);
|
|
386
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
387
|
-
res.end(JSON.stringify(hooksData));
|
|
388
|
-
return;
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
// API: Save hook
|
|
392
|
-
if (pathname === '/api/hooks' && req.method === 'POST') {
|
|
393
|
-
handlePostRequest(req, res, async (body) => {
|
|
394
|
-
const { projectPath, scope, event, hookData } = body;
|
|
395
|
-
if (!scope || !event || !hookData) {
|
|
396
|
-
return { error: 'scope, event, and hookData are required', status: 400 };
|
|
397
|
-
}
|
|
398
|
-
return saveHookToSettings(projectPath, scope, event, hookData);
|
|
399
|
-
});
|
|
400
|
-
return;
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
// API: Delete hook
|
|
404
|
-
if (pathname === '/api/hooks' && req.method === 'DELETE') {
|
|
405
|
-
handlePostRequest(req, res, async (body) => {
|
|
406
|
-
const { projectPath, scope, event, hookIndex } = body;
|
|
407
|
-
if (!scope || !event || hookIndex === undefined) {
|
|
408
|
-
return { error: 'scope, event, and hookIndex are required', status: 400 };
|
|
409
|
-
}
|
|
410
|
-
return deleteHookFromSettings(projectPath, scope, event, hookIndex);
|
|
411
|
-
});
|
|
412
|
-
return;
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
// API: List directory files with .gitignore filtering (Explorer view)
|
|
416
|
-
if (pathname === '/api/files') {
|
|
417
|
-
const dirPath = url.searchParams.get('path') || initialPath;
|
|
418
|
-
const filesData = await listDirectoryFiles(dirPath);
|
|
419
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
420
|
-
res.end(JSON.stringify(filesData));
|
|
421
|
-
return;
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
// API: Get file content for preview (Explorer view)
|
|
425
|
-
if (pathname === '/api/file-content') {
|
|
426
|
-
const filePath = url.searchParams.get('path');
|
|
427
|
-
if (!filePath) {
|
|
428
|
-
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
429
|
-
res.end(JSON.stringify({ error: 'File path is required' }));
|
|
430
|
-
return;
|
|
431
|
-
}
|
|
432
|
-
const fileData = await getFileContent(filePath);
|
|
433
|
-
res.writeHead(fileData.error ? 404 : 200, { 'Content-Type': 'application/json' });
|
|
434
|
-
res.end(JSON.stringify(fileData));
|
|
435
|
-
return;
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
// API: Update CLAUDE.md using CLI tools (Explorer view)
|
|
439
|
-
if (pathname === '/api/update-claude-md' && req.method === 'POST') {
|
|
440
|
-
handlePostRequest(req, res, async (body) => {
|
|
441
|
-
const { path: targetPath, tool = 'gemini', strategy = 'single-layer' } = body;
|
|
442
|
-
if (!targetPath) {
|
|
443
|
-
return { error: 'path is required', status: 400 };
|
|
444
|
-
}
|
|
445
|
-
return await triggerUpdateClaudeMd(targetPath, tool, strategy);
|
|
446
|
-
});
|
|
447
|
-
return;
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
// Serve dashboard HTML
|
|
451
|
-
if (pathname === '/' || pathname === '/index.html') {
|
|
452
|
-
const html = generateServerDashboard(initialPath);
|
|
453
|
-
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
454
|
-
res.end(html);
|
|
455
|
-
return;
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
// 404
|
|
459
|
-
res.writeHead(404, { 'Content-Type': 'text/plain' });
|
|
460
|
-
res.end('Not Found');
|
|
461
|
-
|
|
462
|
-
} catch (error) {
|
|
463
|
-
console.error('Server error:', error);
|
|
464
|
-
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
465
|
-
res.end(JSON.stringify({ error: error.message }));
|
|
466
|
-
}
|
|
467
|
-
});
|
|
468
|
-
|
|
469
|
-
// Handle WebSocket upgrade requests
|
|
470
|
-
server.on('upgrade', (req, socket, head) => {
|
|
471
|
-
if (req.url === '/ws') {
|
|
472
|
-
handleWebSocketUpgrade(req, socket, head);
|
|
473
|
-
} else {
|
|
474
|
-
socket.destroy();
|
|
475
|
-
}
|
|
476
|
-
});
|
|
477
|
-
|
|
478
|
-
return new Promise((resolve, reject) => {
|
|
479
|
-
server.listen(port, () => {
|
|
480
|
-
console.log(`Dashboard server running at http://localhost:${port}`);
|
|
481
|
-
console.log(`WebSocket endpoint available at ws://localhost:${port}/ws`);
|
|
482
|
-
console.log(`Hook endpoint available at POST http://localhost:${port}/api/hook`);
|
|
483
|
-
resolve(server);
|
|
484
|
-
});
|
|
485
|
-
server.on('error', reject);
|
|
486
|
-
});
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
// ========================================
|
|
490
|
-
// WebSocket Functions
|
|
491
|
-
// ========================================
|
|
492
|
-
|
|
493
|
-
/**
|
|
494
|
-
* Handle WebSocket upgrade
|
|
495
|
-
*/
|
|
496
|
-
function handleWebSocketUpgrade(req, socket, head) {
|
|
497
|
-
const key = req.headers['sec-websocket-key'];
|
|
498
|
-
const acceptKey = createHash('sha1')
|
|
499
|
-
.update(key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')
|
|
500
|
-
.digest('base64');
|
|
501
|
-
|
|
502
|
-
const responseHeaders = [
|
|
503
|
-
'HTTP/1.1 101 Switching Protocols',
|
|
504
|
-
'Upgrade: websocket',
|
|
505
|
-
'Connection: Upgrade',
|
|
506
|
-
`Sec-WebSocket-Accept: ${acceptKey}`,
|
|
507
|
-
'',
|
|
508
|
-
''
|
|
509
|
-
].join('\r\n');
|
|
510
|
-
|
|
511
|
-
socket.write(responseHeaders);
|
|
512
|
-
|
|
513
|
-
// Add to clients set
|
|
514
|
-
wsClients.add(socket);
|
|
515
|
-
console.log(`[WS] Client connected (${wsClients.size} total)`);
|
|
516
|
-
|
|
517
|
-
// Handle incoming messages
|
|
518
|
-
socket.on('data', (buffer) => {
|
|
519
|
-
try {
|
|
520
|
-
const frame = parseWebSocketFrame(buffer);
|
|
521
|
-
if (!frame) return;
|
|
522
|
-
|
|
523
|
-
const { opcode, payload } = frame;
|
|
524
|
-
|
|
525
|
-
switch (opcode) {
|
|
526
|
-
case 0x1: // Text frame
|
|
527
|
-
if (payload) {
|
|
528
|
-
console.log('[WS] Received:', payload);
|
|
529
|
-
}
|
|
530
|
-
break;
|
|
531
|
-
case 0x8: // Close frame
|
|
532
|
-
socket.end();
|
|
533
|
-
break;
|
|
534
|
-
case 0x9: // Ping frame - respond with Pong
|
|
535
|
-
const pongFrame = Buffer.alloc(2);
|
|
536
|
-
pongFrame[0] = 0x8A; // Pong opcode with FIN bit
|
|
537
|
-
pongFrame[1] = 0x00; // No payload
|
|
538
|
-
socket.write(pongFrame);
|
|
539
|
-
break;
|
|
540
|
-
case 0xA: // Pong frame - ignore
|
|
541
|
-
break;
|
|
542
|
-
default:
|
|
543
|
-
// Ignore other frame types (binary, continuation)
|
|
544
|
-
break;
|
|
545
|
-
}
|
|
546
|
-
} catch (e) {
|
|
547
|
-
// Ignore parse errors
|
|
548
|
-
}
|
|
549
|
-
});
|
|
550
|
-
|
|
551
|
-
// Handle disconnect
|
|
552
|
-
socket.on('close', () => {
|
|
553
|
-
wsClients.delete(socket);
|
|
554
|
-
console.log(`[WS] Client disconnected (${wsClients.size} remaining)`);
|
|
555
|
-
});
|
|
556
|
-
|
|
557
|
-
socket.on('error', () => {
|
|
558
|
-
wsClients.delete(socket);
|
|
559
|
-
});
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
/**
|
|
563
|
-
* Parse WebSocket frame (simplified)
|
|
564
|
-
* Returns { opcode, payload } or null
|
|
565
|
-
*/
|
|
566
|
-
function parseWebSocketFrame(buffer) {
|
|
567
|
-
if (buffer.length < 2) return null;
|
|
568
|
-
|
|
569
|
-
const firstByte = buffer[0];
|
|
570
|
-
const opcode = firstByte & 0x0f; // Extract opcode (bits 0-3)
|
|
571
|
-
|
|
572
|
-
// Opcode types:
|
|
573
|
-
// 0x0 = continuation, 0x1 = text, 0x2 = binary
|
|
574
|
-
// 0x8 = close, 0x9 = ping, 0xA = pong
|
|
575
|
-
|
|
576
|
-
const secondByte = buffer[1];
|
|
577
|
-
const isMasked = (secondByte & 0x80) !== 0;
|
|
578
|
-
let payloadLength = secondByte & 0x7f;
|
|
579
|
-
|
|
580
|
-
let offset = 2;
|
|
581
|
-
if (payloadLength === 126) {
|
|
582
|
-
payloadLength = buffer.readUInt16BE(2);
|
|
583
|
-
offset = 4;
|
|
584
|
-
} else if (payloadLength === 127) {
|
|
585
|
-
payloadLength = Number(buffer.readBigUInt64BE(2));
|
|
586
|
-
offset = 10;
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
let mask = null;
|
|
590
|
-
if (isMasked) {
|
|
591
|
-
mask = buffer.slice(offset, offset + 4);
|
|
592
|
-
offset += 4;
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
const payload = buffer.slice(offset, offset + payloadLength);
|
|
596
|
-
|
|
597
|
-
if (isMasked && mask) {
|
|
598
|
-
for (let i = 0; i < payload.length; i++) {
|
|
599
|
-
payload[i] ^= mask[i % 4];
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
return { opcode, payload: payload.toString('utf8') };
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
/**
|
|
607
|
-
* Create WebSocket frame
|
|
608
|
-
*/
|
|
609
|
-
function createWebSocketFrame(data) {
|
|
610
|
-
const payload = Buffer.from(JSON.stringify(data), 'utf8');
|
|
611
|
-
const length = payload.length;
|
|
612
|
-
|
|
613
|
-
let frame;
|
|
614
|
-
if (length <= 125) {
|
|
615
|
-
frame = Buffer.alloc(2 + length);
|
|
616
|
-
frame[0] = 0x81; // Text frame, FIN
|
|
617
|
-
frame[1] = length;
|
|
618
|
-
payload.copy(frame, 2);
|
|
619
|
-
} else if (length <= 65535) {
|
|
620
|
-
frame = Buffer.alloc(4 + length);
|
|
621
|
-
frame[0] = 0x81;
|
|
622
|
-
frame[1] = 126;
|
|
623
|
-
frame.writeUInt16BE(length, 2);
|
|
624
|
-
payload.copy(frame, 4);
|
|
625
|
-
} else {
|
|
626
|
-
frame = Buffer.alloc(10 + length);
|
|
627
|
-
frame[0] = 0x81;
|
|
628
|
-
frame[1] = 127;
|
|
629
|
-
frame.writeBigUInt64BE(BigInt(length), 2);
|
|
630
|
-
payload.copy(frame, 10);
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
return frame;
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
/**
|
|
637
|
-
* Broadcast message to all connected WebSocket clients
|
|
638
|
-
*/
|
|
639
|
-
function broadcastToClients(data) {
|
|
640
|
-
const frame = createWebSocketFrame(data);
|
|
641
|
-
|
|
642
|
-
for (const client of wsClients) {
|
|
643
|
-
try {
|
|
644
|
-
client.write(frame);
|
|
645
|
-
} catch (e) {
|
|
646
|
-
wsClients.delete(client);
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
console.log(`[WS] Broadcast to ${wsClients.size} clients:`, data.type);
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
/**
|
|
654
|
-
* Extract session ID from file path
|
|
655
|
-
*/
|
|
656
|
-
function extractSessionIdFromPath(filePath) {
|
|
657
|
-
// Normalize path
|
|
658
|
-
const normalized = filePath.replace(/\\/g, '/');
|
|
659
|
-
|
|
660
|
-
// Look for session pattern: WFS-xxx, WRS-xxx, etc.
|
|
661
|
-
const sessionMatch = normalized.match(/\/(W[A-Z]S-[^/]+)\//);
|
|
662
|
-
if (sessionMatch) {
|
|
663
|
-
return sessionMatch[1];
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
// Look for .workflow/.sessions/xxx pattern
|
|
667
|
-
const sessionsMatch = normalized.match(/\.workflow\/\.sessions\/([^/]+)/);
|
|
668
|
-
if (sessionsMatch) {
|
|
669
|
-
return sessionsMatch[1];
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
// Look for lite-plan/lite-fix pattern
|
|
673
|
-
const liteMatch = normalized.match(/\.(lite-plan|lite-fix)\/([^/]+)/);
|
|
674
|
-
if (liteMatch) {
|
|
675
|
-
return liteMatch[2];
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
return null;
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
/**
|
|
682
|
-
* Get workflow data for a project path
|
|
683
|
-
* @param {string} projectPath
|
|
684
|
-
* @returns {Promise<Object>}
|
|
685
|
-
*/
|
|
686
|
-
async function getWorkflowData(projectPath) {
|
|
687
|
-
const resolvedPath = resolvePath(projectPath);
|
|
688
|
-
const workflowDir = join(resolvedPath, '.workflow');
|
|
689
|
-
|
|
690
|
-
// Track this path
|
|
691
|
-
trackRecentPath(resolvedPath);
|
|
692
|
-
|
|
693
|
-
// Check if .workflow exists
|
|
694
|
-
if (!existsSync(workflowDir)) {
|
|
695
|
-
return {
|
|
696
|
-
generatedAt: new Date().toISOString(),
|
|
697
|
-
activeSessions: [],
|
|
698
|
-
archivedSessions: [],
|
|
699
|
-
liteTasks: { litePlan: [], liteFix: [] },
|
|
700
|
-
reviewData: { dimensions: {} },
|
|
701
|
-
projectOverview: null,
|
|
702
|
-
statistics: {
|
|
703
|
-
totalSessions: 0,
|
|
704
|
-
activeSessions: 0,
|
|
705
|
-
totalTasks: 0,
|
|
706
|
-
completedTasks: 0,
|
|
707
|
-
reviewFindings: 0,
|
|
708
|
-
litePlanCount: 0,
|
|
709
|
-
liteFixCount: 0
|
|
710
|
-
},
|
|
711
|
-
projectPath: normalizePathForDisplay(resolvedPath),
|
|
712
|
-
recentPaths: getRecentPaths()
|
|
713
|
-
};
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
// Scan and aggregate data
|
|
717
|
-
const sessions = await scanSessions(workflowDir);
|
|
718
|
-
const data = await aggregateData(sessions, workflowDir);
|
|
719
|
-
|
|
720
|
-
data.projectPath = normalizePathForDisplay(resolvedPath);
|
|
721
|
-
data.recentPaths = getRecentPaths();
|
|
722
|
-
|
|
723
|
-
return data;
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
/**
|
|
727
|
-
* Get session detail data (context, summaries, impl-plan, review)
|
|
728
|
-
* @param {string} sessionPath - Path to session directory
|
|
729
|
-
* @param {string} dataType - Type of data to load: context, summary, impl-plan, review, or all
|
|
730
|
-
* @returns {Promise<Object>}
|
|
731
|
-
*/
|
|
732
|
-
async function getSessionDetailData(sessionPath, dataType) {
|
|
733
|
-
const result = {};
|
|
734
|
-
|
|
735
|
-
// Normalize path
|
|
736
|
-
const normalizedPath = sessionPath.replace(/\\/g, '/');
|
|
737
|
-
|
|
738
|
-
try {
|
|
739
|
-
// Load context-package.json (in .process/ subfolder)
|
|
740
|
-
if (dataType === 'context' || dataType === 'all') {
|
|
741
|
-
// Try .process/context-package.json first (common location)
|
|
742
|
-
let contextFile = join(normalizedPath, '.process', 'context-package.json');
|
|
743
|
-
if (!existsSync(contextFile)) {
|
|
744
|
-
// Fallback to session root
|
|
745
|
-
contextFile = join(normalizedPath, 'context-package.json');
|
|
746
|
-
}
|
|
747
|
-
if (existsSync(contextFile)) {
|
|
748
|
-
try {
|
|
749
|
-
result.context = JSON.parse(readFileSync(contextFile, 'utf8'));
|
|
750
|
-
} catch (e) {
|
|
751
|
-
result.context = null;
|
|
752
|
-
}
|
|
753
|
-
}
|
|
754
|
-
}
|
|
755
|
-
|
|
756
|
-
// Load task JSONs from .task/ folder
|
|
757
|
-
if (dataType === 'tasks' || dataType === 'all') {
|
|
758
|
-
const taskDir = join(normalizedPath, '.task');
|
|
759
|
-
result.tasks = [];
|
|
760
|
-
if (existsSync(taskDir)) {
|
|
761
|
-
const files = readdirSync(taskDir).filter(f => f.endsWith('.json') && f.startsWith('IMPL-'));
|
|
762
|
-
for (const file of files) {
|
|
763
|
-
try {
|
|
764
|
-
const content = JSON.parse(readFileSync(join(taskDir, file), 'utf8'));
|
|
765
|
-
result.tasks.push({
|
|
766
|
-
filename: file,
|
|
767
|
-
task_id: file.replace('.json', ''),
|
|
768
|
-
...content
|
|
769
|
-
});
|
|
770
|
-
} catch (e) {
|
|
771
|
-
// Skip unreadable files
|
|
772
|
-
}
|
|
773
|
-
}
|
|
774
|
-
// Sort by task ID
|
|
775
|
-
result.tasks.sort((a, b) => a.task_id.localeCompare(b.task_id));
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
// Load summaries from .summaries/
|
|
780
|
-
if (dataType === 'summary' || dataType === 'all') {
|
|
781
|
-
const summariesDir = join(normalizedPath, '.summaries');
|
|
782
|
-
result.summaries = [];
|
|
783
|
-
if (existsSync(summariesDir)) {
|
|
784
|
-
const files = readdirSync(summariesDir).filter(f => f.endsWith('.md'));
|
|
785
|
-
for (const file of files) {
|
|
786
|
-
try {
|
|
787
|
-
const content = readFileSync(join(summariesDir, file), 'utf8');
|
|
788
|
-
result.summaries.push({ name: file.replace('.md', ''), content });
|
|
789
|
-
} catch (e) {
|
|
790
|
-
// Skip unreadable files
|
|
791
|
-
}
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
// Load plan.json (for lite tasks)
|
|
797
|
-
if (dataType === 'plan' || dataType === 'all') {
|
|
798
|
-
const planFile = join(normalizedPath, 'plan.json');
|
|
799
|
-
if (existsSync(planFile)) {
|
|
800
|
-
try {
|
|
801
|
-
result.plan = JSON.parse(readFileSync(planFile, 'utf8'));
|
|
802
|
-
} catch (e) {
|
|
803
|
-
result.plan = null;
|
|
804
|
-
}
|
|
805
|
-
}
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
// Load explorations (exploration-*.json files) - check .process/ first, then session root
|
|
809
|
-
if (dataType === 'context' || dataType === 'explorations' || dataType === 'all') {
|
|
810
|
-
result.explorations = { manifest: null, data: {} };
|
|
811
|
-
|
|
812
|
-
// Try .process/ first (standard workflow sessions), then session root (lite tasks)
|
|
813
|
-
const searchDirs = [
|
|
814
|
-
join(normalizedPath, '.process'),
|
|
815
|
-
normalizedPath
|
|
816
|
-
];
|
|
817
|
-
|
|
818
|
-
for (const searchDir of searchDirs) {
|
|
819
|
-
if (!existsSync(searchDir)) continue;
|
|
820
|
-
|
|
821
|
-
// Look for explorations-manifest.json
|
|
822
|
-
const manifestFile = join(searchDir, 'explorations-manifest.json');
|
|
823
|
-
if (existsSync(manifestFile)) {
|
|
824
|
-
try {
|
|
825
|
-
result.explorations.manifest = JSON.parse(readFileSync(manifestFile, 'utf8'));
|
|
826
|
-
|
|
827
|
-
// Load each exploration file based on manifest
|
|
828
|
-
const explorations = result.explorations.manifest.explorations || [];
|
|
829
|
-
for (const exp of explorations) {
|
|
830
|
-
const expFile = join(searchDir, exp.file);
|
|
831
|
-
if (existsSync(expFile)) {
|
|
832
|
-
try {
|
|
833
|
-
result.explorations.data[exp.angle] = JSON.parse(readFileSync(expFile, 'utf8'));
|
|
834
|
-
} catch (e) {
|
|
835
|
-
// Skip unreadable exploration files
|
|
836
|
-
}
|
|
837
|
-
}
|
|
838
|
-
}
|
|
839
|
-
break; // Found manifest, stop searching
|
|
840
|
-
} catch (e) {
|
|
841
|
-
result.explorations.manifest = null;
|
|
842
|
-
}
|
|
843
|
-
} else {
|
|
844
|
-
// Fallback: scan for exploration-*.json files directly
|
|
845
|
-
try {
|
|
846
|
-
const files = readdirSync(searchDir).filter(f => f.startsWith('exploration-') && f.endsWith('.json'));
|
|
847
|
-
if (files.length > 0) {
|
|
848
|
-
// Create synthetic manifest
|
|
849
|
-
result.explorations.manifest = {
|
|
850
|
-
exploration_count: files.length,
|
|
851
|
-
explorations: files.map((f, i) => ({
|
|
852
|
-
angle: f.replace('exploration-', '').replace('.json', ''),
|
|
853
|
-
file: f,
|
|
854
|
-
index: i + 1
|
|
855
|
-
}))
|
|
856
|
-
};
|
|
857
|
-
|
|
858
|
-
// Load each file
|
|
859
|
-
for (const file of files) {
|
|
860
|
-
const angle = file.replace('exploration-', '').replace('.json', '');
|
|
861
|
-
try {
|
|
862
|
-
result.explorations.data[angle] = JSON.parse(readFileSync(join(searchDir, file), 'utf8'));
|
|
863
|
-
} catch (e) {
|
|
864
|
-
// Skip unreadable files
|
|
865
|
-
}
|
|
866
|
-
}
|
|
867
|
-
break; // Found explorations, stop searching
|
|
868
|
-
}
|
|
869
|
-
} catch (e) {
|
|
870
|
-
// Directory read failed
|
|
871
|
-
}
|
|
872
|
-
}
|
|
873
|
-
}
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
// Load conflict resolution decisions (conflict-resolution-decisions.json)
|
|
877
|
-
if (dataType === 'context' || dataType === 'conflict' || dataType === 'all') {
|
|
878
|
-
result.conflictResolution = null;
|
|
879
|
-
|
|
880
|
-
// Try .process/ first (standard workflow sessions)
|
|
881
|
-
const conflictFiles = [
|
|
882
|
-
join(normalizedPath, '.process', 'conflict-resolution-decisions.json'),
|
|
883
|
-
join(normalizedPath, 'conflict-resolution-decisions.json')
|
|
884
|
-
];
|
|
885
|
-
|
|
886
|
-
for (const conflictFile of conflictFiles) {
|
|
887
|
-
if (existsSync(conflictFile)) {
|
|
888
|
-
try {
|
|
889
|
-
result.conflictResolution = JSON.parse(readFileSync(conflictFile, 'utf8'));
|
|
890
|
-
break; // Found file, stop searching
|
|
891
|
-
} catch (e) {
|
|
892
|
-
// Skip unreadable file
|
|
893
|
-
}
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
|
-
}
|
|
897
|
-
|
|
898
|
-
// Load IMPL_PLAN.md
|
|
899
|
-
if (dataType === 'impl-plan' || dataType === 'all') {
|
|
900
|
-
const implPlanFile = join(normalizedPath, 'IMPL_PLAN.md');
|
|
901
|
-
if (existsSync(implPlanFile)) {
|
|
902
|
-
try {
|
|
903
|
-
result.implPlan = readFileSync(implPlanFile, 'utf8');
|
|
904
|
-
} catch (e) {
|
|
905
|
-
result.implPlan = null;
|
|
906
|
-
}
|
|
907
|
-
}
|
|
908
|
-
}
|
|
909
|
-
|
|
910
|
-
// Load review data from .review/
|
|
911
|
-
if (dataType === 'review' || dataType === 'all') {
|
|
912
|
-
const reviewDir = join(normalizedPath, '.review');
|
|
913
|
-
result.review = {
|
|
914
|
-
state: null,
|
|
915
|
-
dimensions: [],
|
|
916
|
-
severityDistribution: null,
|
|
917
|
-
totalFindings: 0
|
|
918
|
-
};
|
|
919
|
-
|
|
920
|
-
if (existsSync(reviewDir)) {
|
|
921
|
-
// Load review-state.json
|
|
922
|
-
const stateFile = join(reviewDir, 'review-state.json');
|
|
923
|
-
if (existsSync(stateFile)) {
|
|
924
|
-
try {
|
|
925
|
-
const state = JSON.parse(readFileSync(stateFile, 'utf8'));
|
|
926
|
-
result.review.state = state;
|
|
927
|
-
result.review.severityDistribution = state.severity_distribution || {};
|
|
928
|
-
result.review.totalFindings = state.total_findings || 0;
|
|
929
|
-
result.review.phase = state.phase || 'unknown';
|
|
930
|
-
result.review.dimensionSummaries = state.dimension_summaries || {};
|
|
931
|
-
result.review.crossCuttingConcerns = state.cross_cutting_concerns || [];
|
|
932
|
-
result.review.criticalFiles = state.critical_files || [];
|
|
933
|
-
} catch (e) {
|
|
934
|
-
// Skip unreadable state
|
|
935
|
-
}
|
|
936
|
-
}
|
|
937
|
-
|
|
938
|
-
// Load dimension findings
|
|
939
|
-
const dimensionsDir = join(reviewDir, 'dimensions');
|
|
940
|
-
if (existsSync(dimensionsDir)) {
|
|
941
|
-
const files = readdirSync(dimensionsDir).filter(f => f.endsWith('.json'));
|
|
942
|
-
for (const file of files) {
|
|
943
|
-
try {
|
|
944
|
-
const dimName = file.replace('.json', '');
|
|
945
|
-
const data = JSON.parse(readFileSync(join(dimensionsDir, file), 'utf8'));
|
|
946
|
-
|
|
947
|
-
// Handle array structure: [ { findings: [...] } ]
|
|
948
|
-
let findings = [];
|
|
949
|
-
let summary = null;
|
|
950
|
-
|
|
951
|
-
if (Array.isArray(data) && data.length > 0) {
|
|
952
|
-
const dimData = data[0];
|
|
953
|
-
findings = dimData.findings || [];
|
|
954
|
-
summary = dimData.summary || null;
|
|
955
|
-
} else if (data.findings) {
|
|
956
|
-
findings = data.findings;
|
|
957
|
-
summary = data.summary || null;
|
|
958
|
-
}
|
|
959
|
-
|
|
960
|
-
result.review.dimensions.push({
|
|
961
|
-
name: dimName,
|
|
962
|
-
findings: findings,
|
|
963
|
-
summary: summary,
|
|
964
|
-
count: findings.length
|
|
965
|
-
});
|
|
966
|
-
} catch (e) {
|
|
967
|
-
// Skip unreadable files
|
|
968
|
-
}
|
|
969
|
-
}
|
|
970
|
-
}
|
|
971
|
-
}
|
|
972
|
-
}
|
|
973
|
-
|
|
974
|
-
} catch (error) {
|
|
975
|
-
console.error('Error loading session detail:', error);
|
|
976
|
-
result.error = error.message;
|
|
977
|
-
}
|
|
978
|
-
|
|
979
|
-
return result;
|
|
980
|
-
}
|
|
981
|
-
|
|
982
|
-
/**
|
|
983
|
-
* Update task status in a task JSON file
|
|
984
|
-
* @param {string} sessionPath - Path to session directory
|
|
985
|
-
* @param {string} taskId - Task ID (e.g., IMPL-001)
|
|
986
|
-
* @param {string} newStatus - New status (pending, in_progress, completed)
|
|
987
|
-
* @returns {Promise<Object>}
|
|
988
|
-
*/
|
|
989
|
-
async function updateTaskStatus(sessionPath, taskId, newStatus) {
|
|
990
|
-
// Normalize path (handle both forward and back slashes)
|
|
991
|
-
let normalizedPath = sessionPath.replace(/\\/g, '/');
|
|
992
|
-
|
|
993
|
-
// Handle Windows drive letter format
|
|
994
|
-
if (normalizedPath.match(/^[a-zA-Z]:\//)) {
|
|
995
|
-
// Already in correct format
|
|
996
|
-
} else if (normalizedPath.match(/^\/[a-zA-Z]\//)) {
|
|
997
|
-
// Convert /D/path to D:/path
|
|
998
|
-
normalizedPath = normalizedPath.charAt(1).toUpperCase() + ':' + normalizedPath.slice(2);
|
|
999
|
-
}
|
|
1000
|
-
|
|
1001
|
-
const taskDir = join(normalizedPath, '.task');
|
|
1002
|
-
|
|
1003
|
-
// Check if task directory exists
|
|
1004
|
-
if (!existsSync(taskDir)) {
|
|
1005
|
-
throw new Error(`Task directory not found: ${taskDir}`);
|
|
1006
|
-
}
|
|
1007
|
-
|
|
1008
|
-
// Try to find the task file
|
|
1009
|
-
let taskFile = join(taskDir, `${taskId}.json`);
|
|
1010
|
-
|
|
1011
|
-
if (!existsSync(taskFile)) {
|
|
1012
|
-
// Try without .json if taskId already has it
|
|
1013
|
-
if (taskId.endsWith('.json')) {
|
|
1014
|
-
taskFile = join(taskDir, taskId);
|
|
1015
|
-
}
|
|
1016
|
-
if (!existsSync(taskFile)) {
|
|
1017
|
-
throw new Error(`Task file not found: ${taskId}.json in ${taskDir}`);
|
|
1018
|
-
}
|
|
1019
|
-
}
|
|
1020
|
-
|
|
1021
|
-
try {
|
|
1022
|
-
const content = JSON.parse(readFileSync(taskFile, 'utf8'));
|
|
1023
|
-
const oldStatus = content.status || 'pending';
|
|
1024
|
-
content.status = newStatus;
|
|
1025
|
-
|
|
1026
|
-
// Add status change timestamp
|
|
1027
|
-
if (!content.status_history) {
|
|
1028
|
-
content.status_history = [];
|
|
1029
|
-
}
|
|
1030
|
-
content.status_history.push({
|
|
1031
|
-
from: oldStatus,
|
|
1032
|
-
to: newStatus,
|
|
1033
|
-
changed_at: new Date().toISOString()
|
|
1034
|
-
});
|
|
1035
|
-
|
|
1036
|
-
writeFileSync(taskFile, JSON.stringify(content, null, 2), 'utf8');
|
|
1037
|
-
|
|
1038
|
-
return {
|
|
1039
|
-
success: true,
|
|
1040
|
-
taskId,
|
|
1041
|
-
oldStatus,
|
|
1042
|
-
newStatus,
|
|
1043
|
-
file: taskFile
|
|
1044
|
-
};
|
|
1045
|
-
} catch (error) {
|
|
1046
|
-
throw new Error(`Failed to update task ${taskId}: ${error.message}`);
|
|
1047
|
-
}
|
|
1048
|
-
}
|
|
1049
|
-
|
|
1050
|
-
/**
|
|
1051
|
-
* Generate dashboard HTML for server mode
|
|
1052
|
-
* @param {string} initialPath
|
|
1053
|
-
* @returns {string}
|
|
1054
|
-
*/
|
|
1055
|
-
function generateServerDashboard(initialPath) {
|
|
1056
|
-
let html = readFileSync(TEMPLATE_PATH, 'utf8');
|
|
1057
|
-
|
|
1058
|
-
// Read and concatenate modular CSS files in load order
|
|
1059
|
-
const cssContent = MODULE_CSS_FILES.map(file => {
|
|
1060
|
-
const filePath = join(MODULE_CSS_DIR, file);
|
|
1061
|
-
return existsSync(filePath) ? readFileSync(filePath, 'utf8') : '';
|
|
1062
|
-
}).join('\n\n');
|
|
1063
|
-
|
|
1064
|
-
// Read and concatenate modular JS files in dependency order
|
|
1065
|
-
let jsContent = MODULE_FILES.map(file => {
|
|
1066
|
-
const filePath = join(MODULE_JS_DIR, file);
|
|
1067
|
-
return existsSync(filePath) ? readFileSync(filePath, 'utf8') : '';
|
|
1068
|
-
}).join('\n\n');
|
|
1069
|
-
|
|
1070
|
-
// Inject CSS content
|
|
1071
|
-
html = html.replace('{{CSS_CONTENT}}', cssContent);
|
|
1072
|
-
|
|
1073
|
-
// Prepare JS content with empty initial data (will be loaded dynamically)
|
|
1074
|
-
const emptyData = {
|
|
1075
|
-
generatedAt: new Date().toISOString(),
|
|
1076
|
-
activeSessions: [],
|
|
1077
|
-
archivedSessions: [],
|
|
1078
|
-
liteTasks: { litePlan: [], liteFix: [] },
|
|
1079
|
-
reviewData: { dimensions: {} },
|
|
1080
|
-
projectOverview: null,
|
|
1081
|
-
statistics: { totalSessions: 0, activeSessions: 0, totalTasks: 0, completedTasks: 0, reviewFindings: 0, litePlanCount: 0, liteFixCount: 0 }
|
|
1082
|
-
};
|
|
1083
|
-
|
|
1084
|
-
// Replace JS placeholders
|
|
1085
|
-
jsContent = jsContent.replace('{{WORKFLOW_DATA}}', JSON.stringify(emptyData, null, 2));
|
|
1086
|
-
jsContent = jsContent.replace(/\{\{PROJECT_PATH\}\}/g, normalizePathForDisplay(initialPath).replace(/\\/g, '/'));
|
|
1087
|
-
jsContent = jsContent.replace('{{RECENT_PATHS}}', JSON.stringify(getRecentPaths()));
|
|
1088
|
-
|
|
1089
|
-
// Add server mode flag and dynamic loading functions at the start of JS
|
|
1090
|
-
const serverModeScript = `
|
|
1091
|
-
// Server mode - load data dynamically
|
|
1092
|
-
window.SERVER_MODE = true;
|
|
1093
|
-
window.INITIAL_PATH = '${normalizePathForDisplay(initialPath).replace(/\\/g, '/')}';
|
|
1094
|
-
|
|
1095
|
-
async function loadDashboardData(path) {
|
|
1096
|
-
try {
|
|
1097
|
-
const res = await fetch('/api/data?path=' + encodeURIComponent(path));
|
|
1098
|
-
if (!res.ok) throw new Error('Failed to load data');
|
|
1099
|
-
return await res.json();
|
|
1100
|
-
} catch (err) {
|
|
1101
|
-
console.error('Error loading data:', err);
|
|
1102
|
-
return null;
|
|
1103
|
-
}
|
|
1104
|
-
}
|
|
1105
|
-
|
|
1106
|
-
async function loadRecentPaths() {
|
|
1107
|
-
try {
|
|
1108
|
-
const res = await fetch('/api/recent-paths');
|
|
1109
|
-
if (!res.ok) return [];
|
|
1110
|
-
const data = await res.json();
|
|
1111
|
-
return data.paths || [];
|
|
1112
|
-
} catch (err) {
|
|
1113
|
-
return [];
|
|
1114
|
-
}
|
|
1115
|
-
}
|
|
1116
|
-
|
|
1117
|
-
`;
|
|
1118
|
-
|
|
1119
|
-
// Prepend server mode script to JS content
|
|
1120
|
-
jsContent = serverModeScript + jsContent;
|
|
1121
|
-
|
|
1122
|
-
// Inject JS content
|
|
1123
|
-
html = html.replace('{{JS_CONTENT}}', jsContent);
|
|
1124
|
-
|
|
1125
|
-
// Replace any remaining placeholders in HTML
|
|
1126
|
-
html = html.replace(/\{\{PROJECT_PATH\}\}/g, normalizePathForDisplay(initialPath).replace(/\\/g, '/'));
|
|
1127
|
-
|
|
1128
|
-
return html;
|
|
1129
|
-
}
|
|
1130
|
-
|
|
1131
|
-
// ========================================
|
|
1132
|
-
// MCP Configuration Functions
|
|
1133
|
-
// ========================================
|
|
1134
|
-
|
|
1135
|
-
/**
|
|
1136
|
-
* Safely read and parse JSON file
|
|
1137
|
-
* @param {string} filePath
|
|
1138
|
-
* @returns {Object|null}
|
|
1139
|
-
*/
|
|
1140
|
-
function safeReadJson(filePath) {
|
|
1141
|
-
try {
|
|
1142
|
-
if (!existsSync(filePath)) return null;
|
|
1143
|
-
const content = readFileSync(filePath, 'utf8');
|
|
1144
|
-
return JSON.parse(content);
|
|
1145
|
-
} catch {
|
|
1146
|
-
return null;
|
|
1147
|
-
}
|
|
1148
|
-
}
|
|
1149
|
-
|
|
1150
|
-
/**
|
|
1151
|
-
* Get MCP servers from a JSON file (expects mcpServers key at top level)
|
|
1152
|
-
* @param {string} filePath
|
|
1153
|
-
* @returns {Object} mcpServers object or empty object
|
|
1154
|
-
*/
|
|
1155
|
-
function getMcpServersFromFile(filePath) {
|
|
1156
|
-
const config = safeReadJson(filePath);
|
|
1157
|
-
if (!config) return {};
|
|
1158
|
-
return config.mcpServers || {};
|
|
1159
|
-
}
|
|
1160
|
-
|
|
1161
|
-
/**
|
|
1162
|
-
* Get MCP configuration from multiple sources (per official Claude Code docs):
|
|
1163
|
-
*
|
|
1164
|
-
* Priority (highest to lowest):
|
|
1165
|
-
* 1. Enterprise managed-mcp.json (cannot be overridden)
|
|
1166
|
-
* 2. Local scope (project-specific private in ~/.claude.json)
|
|
1167
|
-
* 3. Project scope (.mcp.json in project root)
|
|
1168
|
-
* 4. User scope (mcpServers in ~/.claude.json)
|
|
1169
|
-
*
|
|
1170
|
-
* Note: ~/.claude/settings.json is for MCP PERMISSIONS, NOT definitions!
|
|
1171
|
-
*
|
|
1172
|
-
* @returns {Object}
|
|
1173
|
-
*/
|
|
1174
|
-
function getMcpConfig() {
|
|
1175
|
-
try {
|
|
1176
|
-
const result = {
|
|
1177
|
-
projects: {},
|
|
1178
|
-
userServers: {}, // User-level servers from ~/.claude.json mcpServers
|
|
1179
|
-
enterpriseServers: {}, // Enterprise managed servers (highest priority)
|
|
1180
|
-
configSources: [] // Track where configs came from for debugging
|
|
1181
|
-
};
|
|
1182
|
-
|
|
1183
|
-
// 1. Read Enterprise managed MCP servers (highest priority)
|
|
1184
|
-
const enterprisePath = getEnterpriseMcpPath();
|
|
1185
|
-
if (existsSync(enterprisePath)) {
|
|
1186
|
-
const enterpriseConfig = safeReadJson(enterprisePath);
|
|
1187
|
-
if (enterpriseConfig?.mcpServers) {
|
|
1188
|
-
result.enterpriseServers = enterpriseConfig.mcpServers;
|
|
1189
|
-
result.configSources.push({ type: 'enterprise', path: enterprisePath, count: Object.keys(enterpriseConfig.mcpServers).length });
|
|
1190
|
-
}
|
|
1191
|
-
}
|
|
1192
|
-
|
|
1193
|
-
// 2. Read from ~/.claude.json
|
|
1194
|
-
if (existsSync(CLAUDE_CONFIG_PATH)) {
|
|
1195
|
-
const claudeConfig = safeReadJson(CLAUDE_CONFIG_PATH);
|
|
1196
|
-
if (claudeConfig) {
|
|
1197
|
-
// 2a. User-level mcpServers (top-level mcpServers key)
|
|
1198
|
-
if (claudeConfig.mcpServers) {
|
|
1199
|
-
result.userServers = claudeConfig.mcpServers;
|
|
1200
|
-
result.configSources.push({ type: 'user', path: CLAUDE_CONFIG_PATH, count: Object.keys(claudeConfig.mcpServers).length });
|
|
1201
|
-
}
|
|
1202
|
-
|
|
1203
|
-
// 2b. Project-specific configurations (projects[path].mcpServers)
|
|
1204
|
-
if (claudeConfig.projects) {
|
|
1205
|
-
result.projects = claudeConfig.projects;
|
|
1206
|
-
}
|
|
1207
|
-
}
|
|
1208
|
-
}
|
|
1209
|
-
|
|
1210
|
-
// 3. For each known project, check for .mcp.json (project-level config)
|
|
1211
|
-
const projectPaths = Object.keys(result.projects);
|
|
1212
|
-
for (const projectPath of projectPaths) {
|
|
1213
|
-
const mcpJsonPath = join(projectPath, '.mcp.json');
|
|
1214
|
-
if (existsSync(mcpJsonPath)) {
|
|
1215
|
-
const mcpJsonConfig = safeReadJson(mcpJsonPath);
|
|
1216
|
-
if (mcpJsonConfig?.mcpServers) {
|
|
1217
|
-
// Merge .mcp.json servers into project config
|
|
1218
|
-
// Project's .mcp.json has lower priority than ~/.claude.json projects[path].mcpServers
|
|
1219
|
-
const existingServers = result.projects[projectPath]?.mcpServers || {};
|
|
1220
|
-
result.projects[projectPath] = {
|
|
1221
|
-
...result.projects[projectPath],
|
|
1222
|
-
mcpServers: {
|
|
1223
|
-
...mcpJsonConfig.mcpServers, // .mcp.json (lower priority)
|
|
1224
|
-
...existingServers // ~/.claude.json projects[path] (higher priority)
|
|
1225
|
-
},
|
|
1226
|
-
mcpJsonPath: mcpJsonPath // Track source for debugging
|
|
1227
|
-
};
|
|
1228
|
-
result.configSources.push({ type: 'project-mcp-json', path: mcpJsonPath, count: Object.keys(mcpJsonConfig.mcpServers).length });
|
|
1229
|
-
}
|
|
1230
|
-
}
|
|
1231
|
-
}
|
|
1232
|
-
|
|
1233
|
-
// Build globalServers by merging user and enterprise servers
|
|
1234
|
-
// Enterprise servers override user servers
|
|
1235
|
-
result.globalServers = {
|
|
1236
|
-
...result.userServers,
|
|
1237
|
-
...result.enterpriseServers
|
|
1238
|
-
};
|
|
1239
|
-
|
|
1240
|
-
return result;
|
|
1241
|
-
} catch (error) {
|
|
1242
|
-
console.error('Error reading MCP config:', error);
|
|
1243
|
-
return { projects: {}, globalServers: {}, userServers: {}, enterpriseServers: {}, configSources: [], error: error.message };
|
|
1244
|
-
}
|
|
1245
|
-
}
|
|
1246
|
-
|
|
1247
|
-
/**
|
|
1248
|
-
* Normalize project path for .claude.json (Windows backslash format)
|
|
1249
|
-
* @param {string} path
|
|
1250
|
-
* @returns {string}
|
|
1251
|
-
*/
|
|
1252
|
-
function normalizeProjectPathForConfig(path) {
|
|
1253
|
-
// Convert forward slashes to backslashes for Windows .claude.json format
|
|
1254
|
-
let normalized = path.replace(/\//g, '\\');
|
|
1255
|
-
|
|
1256
|
-
// Handle /d/path format -> D:\path
|
|
1257
|
-
if (normalized.match(/^\\[a-zA-Z]\\/)) {
|
|
1258
|
-
normalized = normalized.charAt(1).toUpperCase() + ':' + normalized.slice(2);
|
|
1259
|
-
}
|
|
1260
|
-
|
|
1261
|
-
return normalized;
|
|
1262
|
-
}
|
|
1263
|
-
|
|
1264
|
-
/**
|
|
1265
|
-
* Toggle MCP server enabled/disabled
|
|
1266
|
-
* @param {string} projectPath
|
|
1267
|
-
* @param {string} serverName
|
|
1268
|
-
* @param {boolean} enable
|
|
1269
|
-
* @returns {Object}
|
|
1270
|
-
*/
|
|
1271
|
-
function toggleMcpServerEnabled(projectPath, serverName, enable) {
|
|
1272
|
-
try {
|
|
1273
|
-
if (!existsSync(CLAUDE_CONFIG_PATH)) {
|
|
1274
|
-
return { error: '.claude.json not found' };
|
|
1275
|
-
}
|
|
1276
|
-
|
|
1277
|
-
const content = readFileSync(CLAUDE_CONFIG_PATH, 'utf8');
|
|
1278
|
-
const config = JSON.parse(content);
|
|
1279
|
-
|
|
1280
|
-
const normalizedPath = normalizeProjectPathForConfig(projectPath);
|
|
1281
|
-
|
|
1282
|
-
if (!config.projects || !config.projects[normalizedPath]) {
|
|
1283
|
-
return { error: `Project not found: ${normalizedPath}` };
|
|
1284
|
-
}
|
|
1285
|
-
|
|
1286
|
-
const projectConfig = config.projects[normalizedPath];
|
|
1287
|
-
|
|
1288
|
-
// Ensure disabledMcpServers array exists
|
|
1289
|
-
if (!projectConfig.disabledMcpServers) {
|
|
1290
|
-
projectConfig.disabledMcpServers = [];
|
|
1291
|
-
}
|
|
1292
|
-
|
|
1293
|
-
if (enable) {
|
|
1294
|
-
// Remove from disabled list
|
|
1295
|
-
projectConfig.disabledMcpServers = projectConfig.disabledMcpServers.filter(s => s !== serverName);
|
|
1296
|
-
} else {
|
|
1297
|
-
// Add to disabled list if not already there
|
|
1298
|
-
if (!projectConfig.disabledMcpServers.includes(serverName)) {
|
|
1299
|
-
projectConfig.disabledMcpServers.push(serverName);
|
|
1300
|
-
}
|
|
1301
|
-
}
|
|
1302
|
-
|
|
1303
|
-
// Write back to file
|
|
1304
|
-
writeFileSync(CLAUDE_CONFIG_PATH, JSON.stringify(config, null, 2), 'utf8');
|
|
1305
|
-
|
|
1306
|
-
return {
|
|
1307
|
-
success: true,
|
|
1308
|
-
serverName,
|
|
1309
|
-
enabled: enable,
|
|
1310
|
-
disabledMcpServers: projectConfig.disabledMcpServers
|
|
1311
|
-
};
|
|
1312
|
-
} catch (error) {
|
|
1313
|
-
console.error('Error toggling MCP server:', error);
|
|
1314
|
-
return { error: error.message };
|
|
1315
|
-
}
|
|
1316
|
-
}
|
|
1317
|
-
|
|
1318
|
-
/**
|
|
1319
|
-
* Add MCP server to project
|
|
1320
|
-
* @param {string} projectPath
|
|
1321
|
-
* @param {string} serverName
|
|
1322
|
-
* @param {Object} serverConfig
|
|
1323
|
-
* @returns {Object}
|
|
1324
|
-
*/
|
|
1325
|
-
function addMcpServerToProject(projectPath, serverName, serverConfig) {
|
|
1326
|
-
try {
|
|
1327
|
-
if (!existsSync(CLAUDE_CONFIG_PATH)) {
|
|
1328
|
-
return { error: '.claude.json not found' };
|
|
1329
|
-
}
|
|
1330
|
-
|
|
1331
|
-
const content = readFileSync(CLAUDE_CONFIG_PATH, 'utf8');
|
|
1332
|
-
const config = JSON.parse(content);
|
|
1333
|
-
|
|
1334
|
-
const normalizedPath = normalizeProjectPathForConfig(projectPath);
|
|
1335
|
-
|
|
1336
|
-
// Create project entry if it doesn't exist
|
|
1337
|
-
if (!config.projects) {
|
|
1338
|
-
config.projects = {};
|
|
1339
|
-
}
|
|
1340
|
-
|
|
1341
|
-
if (!config.projects[normalizedPath]) {
|
|
1342
|
-
config.projects[normalizedPath] = {
|
|
1343
|
-
allowedTools: [],
|
|
1344
|
-
mcpContextUris: [],
|
|
1345
|
-
mcpServers: {},
|
|
1346
|
-
enabledMcpjsonServers: [],
|
|
1347
|
-
disabledMcpjsonServers: [],
|
|
1348
|
-
hasTrustDialogAccepted: false,
|
|
1349
|
-
projectOnboardingSeenCount: 0,
|
|
1350
|
-
hasClaudeMdExternalIncludesApproved: false,
|
|
1351
|
-
hasClaudeMdExternalIncludesWarningShown: false
|
|
1352
|
-
};
|
|
1353
|
-
}
|
|
1354
|
-
|
|
1355
|
-
const projectConfig = config.projects[normalizedPath];
|
|
1356
|
-
|
|
1357
|
-
// Ensure mcpServers exists
|
|
1358
|
-
if (!projectConfig.mcpServers) {
|
|
1359
|
-
projectConfig.mcpServers = {};
|
|
1360
|
-
}
|
|
1361
|
-
|
|
1362
|
-
// Add the server
|
|
1363
|
-
projectConfig.mcpServers[serverName] = serverConfig;
|
|
1364
|
-
|
|
1365
|
-
// Write back to file
|
|
1366
|
-
writeFileSync(CLAUDE_CONFIG_PATH, JSON.stringify(config, null, 2), 'utf8');
|
|
1367
|
-
|
|
1368
|
-
return {
|
|
1369
|
-
success: true,
|
|
1370
|
-
serverName,
|
|
1371
|
-
serverConfig
|
|
1372
|
-
};
|
|
1373
|
-
} catch (error) {
|
|
1374
|
-
console.error('Error adding MCP server:', error);
|
|
1375
|
-
return { error: error.message };
|
|
1376
|
-
}
|
|
1377
|
-
}
|
|
1378
|
-
|
|
1379
|
-
/**
|
|
1380
|
-
* Remove MCP server from project
|
|
1381
|
-
* @param {string} projectPath
|
|
1382
|
-
* @param {string} serverName
|
|
1383
|
-
* @returns {Object}
|
|
1384
|
-
*/
|
|
1385
|
-
function removeMcpServerFromProject(projectPath, serverName) {
|
|
1386
|
-
try {
|
|
1387
|
-
if (!existsSync(CLAUDE_CONFIG_PATH)) {
|
|
1388
|
-
return { error: '.claude.json not found' };
|
|
1389
|
-
}
|
|
1390
|
-
|
|
1391
|
-
const content = readFileSync(CLAUDE_CONFIG_PATH, 'utf8');
|
|
1392
|
-
const config = JSON.parse(content);
|
|
1393
|
-
|
|
1394
|
-
const normalizedPath = normalizeProjectPathForConfig(projectPath);
|
|
1395
|
-
|
|
1396
|
-
if (!config.projects || !config.projects[normalizedPath]) {
|
|
1397
|
-
return { error: `Project not found: ${normalizedPath}` };
|
|
1398
|
-
}
|
|
1399
|
-
|
|
1400
|
-
const projectConfig = config.projects[normalizedPath];
|
|
1401
|
-
|
|
1402
|
-
if (!projectConfig.mcpServers || !projectConfig.mcpServers[serverName]) {
|
|
1403
|
-
return { error: `Server not found: ${serverName}` };
|
|
1404
|
-
}
|
|
1405
|
-
|
|
1406
|
-
// Remove the server
|
|
1407
|
-
delete projectConfig.mcpServers[serverName];
|
|
1408
|
-
|
|
1409
|
-
// Also remove from disabled list if present
|
|
1410
|
-
if (projectConfig.disabledMcpServers) {
|
|
1411
|
-
projectConfig.disabledMcpServers = projectConfig.disabledMcpServers.filter(s => s !== serverName);
|
|
1412
|
-
}
|
|
1413
|
-
|
|
1414
|
-
// Write back to file
|
|
1415
|
-
writeFileSync(CLAUDE_CONFIG_PATH, JSON.stringify(config, null, 2), 'utf8');
|
|
1416
|
-
|
|
1417
|
-
return {
|
|
1418
|
-
success: true,
|
|
1419
|
-
serverName,
|
|
1420
|
-
removed: true
|
|
1421
|
-
};
|
|
1422
|
-
} catch (error) {
|
|
1423
|
-
console.error('Error removing MCP server:', error);
|
|
1424
|
-
return { error: error.message };
|
|
1425
|
-
}
|
|
1426
|
-
}
|
|
1427
|
-
|
|
1428
|
-
// ========================================
|
|
1429
|
-
// Hook Configuration Functions
|
|
1430
|
-
// ========================================
|
|
1431
|
-
|
|
1432
|
-
const GLOBAL_SETTINGS_PATH = join(homedir(), '.claude', 'settings.json');
|
|
1433
|
-
|
|
1434
|
-
/**
|
|
1435
|
-
* Get project settings path
|
|
1436
|
-
* @param {string} projectPath
|
|
1437
|
-
* @returns {string}
|
|
1438
|
-
*/
|
|
1439
|
-
function getProjectSettingsPath(projectPath) {
|
|
1440
|
-
const normalizedPath = projectPath.replace(/\//g, '\\').replace(/^\\([a-zA-Z])\\/, '$1:\\');
|
|
1441
|
-
return join(normalizedPath, '.claude', 'settings.json');
|
|
1442
|
-
}
|
|
1443
|
-
|
|
1444
|
-
/**
|
|
1445
|
-
* Read settings file safely
|
|
1446
|
-
* @param {string} filePath
|
|
1447
|
-
* @returns {Object}
|
|
1448
|
-
*/
|
|
1449
|
-
function readSettingsFile(filePath) {
|
|
1450
|
-
try {
|
|
1451
|
-
if (!existsSync(filePath)) {
|
|
1452
|
-
return { hooks: {} };
|
|
1453
|
-
}
|
|
1454
|
-
const content = readFileSync(filePath, 'utf8');
|
|
1455
|
-
return JSON.parse(content);
|
|
1456
|
-
} catch (error) {
|
|
1457
|
-
console.error(`Error reading settings file ${filePath}:`, error);
|
|
1458
|
-
return { hooks: {} };
|
|
1459
|
-
}
|
|
1460
|
-
}
|
|
1461
|
-
|
|
1462
|
-
/**
|
|
1463
|
-
* Write settings file safely
|
|
1464
|
-
* @param {string} filePath
|
|
1465
|
-
* @param {Object} settings
|
|
1466
|
-
*/
|
|
1467
|
-
function writeSettingsFile(filePath, settings) {
|
|
1468
|
-
const dirPath = dirname(filePath);
|
|
1469
|
-
// Ensure directory exists
|
|
1470
|
-
if (!existsSync(dirPath)) {
|
|
1471
|
-
mkdirSync(dirPath, { recursive: true });
|
|
1472
|
-
}
|
|
1473
|
-
writeFileSync(filePath, JSON.stringify(settings, null, 2), 'utf8');
|
|
1474
|
-
}
|
|
1475
|
-
|
|
1476
|
-
/**
|
|
1477
|
-
* Get hooks configuration from both global and project settings
|
|
1478
|
-
* @param {string} projectPath
|
|
1479
|
-
* @returns {Object}
|
|
1480
|
-
*/
|
|
1481
|
-
function getHooksConfig(projectPath) {
|
|
1482
|
-
const globalSettings = readSettingsFile(GLOBAL_SETTINGS_PATH);
|
|
1483
|
-
const projectSettingsPath = projectPath ? getProjectSettingsPath(projectPath) : null;
|
|
1484
|
-
const projectSettings = projectSettingsPath ? readSettingsFile(projectSettingsPath) : { hooks: {} };
|
|
1485
|
-
|
|
1486
|
-
return {
|
|
1487
|
-
global: {
|
|
1488
|
-
path: GLOBAL_SETTINGS_PATH,
|
|
1489
|
-
hooks: globalSettings.hooks || {}
|
|
1490
|
-
},
|
|
1491
|
-
project: {
|
|
1492
|
-
path: projectSettingsPath,
|
|
1493
|
-
hooks: projectSettings.hooks || {}
|
|
1494
|
-
}
|
|
1495
|
-
};
|
|
1496
|
-
}
|
|
1497
|
-
|
|
1498
|
-
/**
|
|
1499
|
-
* Save a hook to settings file
|
|
1500
|
-
* @param {string} projectPath
|
|
1501
|
-
* @param {string} scope - 'global' or 'project'
|
|
1502
|
-
* @param {string} event - Hook event type
|
|
1503
|
-
* @param {Object} hookData - Hook configuration
|
|
1504
|
-
* @returns {Object}
|
|
1505
|
-
*/
|
|
1506
|
-
function saveHookToSettings(projectPath, scope, event, hookData) {
|
|
1507
|
-
try {
|
|
1508
|
-
const filePath = scope === 'global' ? GLOBAL_SETTINGS_PATH : getProjectSettingsPath(projectPath);
|
|
1509
|
-
const settings = readSettingsFile(filePath);
|
|
1510
|
-
|
|
1511
|
-
// Ensure hooks object exists
|
|
1512
|
-
if (!settings.hooks) {
|
|
1513
|
-
settings.hooks = {};
|
|
1514
|
-
}
|
|
1515
|
-
|
|
1516
|
-
// Ensure the event array exists
|
|
1517
|
-
if (!settings.hooks[event]) {
|
|
1518
|
-
settings.hooks[event] = [];
|
|
1519
|
-
}
|
|
1520
|
-
|
|
1521
|
-
// Ensure it's an array
|
|
1522
|
-
if (!Array.isArray(settings.hooks[event])) {
|
|
1523
|
-
settings.hooks[event] = [settings.hooks[event]];
|
|
1524
|
-
}
|
|
1525
|
-
|
|
1526
|
-
// Check if we're replacing an existing hook
|
|
1527
|
-
if (hookData.replaceIndex !== undefined) {
|
|
1528
|
-
const index = hookData.replaceIndex;
|
|
1529
|
-
delete hookData.replaceIndex;
|
|
1530
|
-
if (index >= 0 && index < settings.hooks[event].length) {
|
|
1531
|
-
settings.hooks[event][index] = hookData;
|
|
1532
|
-
}
|
|
1533
|
-
} else {
|
|
1534
|
-
// Add new hook
|
|
1535
|
-
settings.hooks[event].push(hookData);
|
|
1536
|
-
}
|
|
1537
|
-
|
|
1538
|
-
// Ensure directory exists and write file
|
|
1539
|
-
const dirPath = dirname(filePath);
|
|
1540
|
-
if (!existsSync(dirPath)) {
|
|
1541
|
-
mkdirSync(dirPath, { recursive: true });
|
|
1542
|
-
}
|
|
1543
|
-
writeFileSync(filePath, JSON.stringify(settings, null, 2), 'utf8');
|
|
1544
|
-
|
|
1545
|
-
return {
|
|
1546
|
-
success: true,
|
|
1547
|
-
event,
|
|
1548
|
-
hookData
|
|
1549
|
-
};
|
|
1550
|
-
} catch (error) {
|
|
1551
|
-
console.error('Error saving hook:', error);
|
|
1552
|
-
return { error: error.message };
|
|
1553
|
-
}
|
|
1554
|
-
}
|
|
1555
|
-
|
|
1556
|
-
/**
|
|
1557
|
-
* Delete a hook from settings file
|
|
1558
|
-
* @param {string} projectPath
|
|
1559
|
-
* @param {string} scope - 'global' or 'project'
|
|
1560
|
-
* @param {string} event - Hook event type
|
|
1561
|
-
* @param {number} hookIndex - Index of hook to delete
|
|
1562
|
-
* @returns {Object}
|
|
1563
|
-
*/
|
|
1564
|
-
function deleteHookFromSettings(projectPath, scope, event, hookIndex) {
|
|
1565
|
-
try {
|
|
1566
|
-
const filePath = scope === 'global' ? GLOBAL_SETTINGS_PATH : getProjectSettingsPath(projectPath);
|
|
1567
|
-
const settings = readSettingsFile(filePath);
|
|
1568
|
-
|
|
1569
|
-
if (!settings.hooks || !settings.hooks[event]) {
|
|
1570
|
-
return { error: 'Hook not found' };
|
|
1571
|
-
}
|
|
1572
|
-
|
|
1573
|
-
// Ensure it's an array
|
|
1574
|
-
if (!Array.isArray(settings.hooks[event])) {
|
|
1575
|
-
settings.hooks[event] = [settings.hooks[event]];
|
|
1576
|
-
}
|
|
1577
|
-
|
|
1578
|
-
if (hookIndex < 0 || hookIndex >= settings.hooks[event].length) {
|
|
1579
|
-
return { error: 'Invalid hook index' };
|
|
1580
|
-
}
|
|
1581
|
-
|
|
1582
|
-
// Remove the hook
|
|
1583
|
-
settings.hooks[event].splice(hookIndex, 1);
|
|
1584
|
-
|
|
1585
|
-
// Remove empty event arrays
|
|
1586
|
-
if (settings.hooks[event].length === 0) {
|
|
1587
|
-
delete settings.hooks[event];
|
|
1588
|
-
}
|
|
1589
|
-
|
|
1590
|
-
writeFileSync(filePath, JSON.stringify(settings, null, 2), 'utf8');
|
|
1591
|
-
|
|
1592
|
-
return {
|
|
1593
|
-
success: true,
|
|
1594
|
-
event,
|
|
1595
|
-
hookIndex
|
|
1596
|
-
};
|
|
1597
|
-
} catch (error) {
|
|
1598
|
-
console.error('Error deleting hook:', error);
|
|
1599
|
-
return { error: error.message };
|
|
1600
|
-
}
|
|
1601
|
-
}
|
|
1602
|
-
|
|
1603
|
-
// ========================================
|
|
1604
|
-
// Explorer View Functions
|
|
1605
|
-
// ========================================
|
|
1606
|
-
|
|
1607
|
-
// Directories to always exclude from file tree
|
|
1608
|
-
const EXPLORER_EXCLUDE_DIRS = [
|
|
1609
|
-
'.git', '__pycache__', 'node_modules', '.venv', 'venv', 'env',
|
|
1610
|
-
'dist', 'build', '.cache', '.pytest_cache', '.mypy_cache',
|
|
1611
|
-
'coverage', '.nyc_output', 'logs', 'tmp', 'temp', '.next',
|
|
1612
|
-
'.nuxt', '.output', '.turbo', '.parcel-cache'
|
|
1613
|
-
];
|
|
1614
|
-
|
|
1615
|
-
// File extensions to language mapping for syntax highlighting
|
|
1616
|
-
const EXT_TO_LANGUAGE = {
|
|
1617
|
-
'.js': 'javascript',
|
|
1618
|
-
'.jsx': 'javascript',
|
|
1619
|
-
'.ts': 'typescript',
|
|
1620
|
-
'.tsx': 'typescript',
|
|
1621
|
-
'.py': 'python',
|
|
1622
|
-
'.rb': 'ruby',
|
|
1623
|
-
'.java': 'java',
|
|
1624
|
-
'.go': 'go',
|
|
1625
|
-
'.rs': 'rust',
|
|
1626
|
-
'.c': 'c',
|
|
1627
|
-
'.cpp': 'cpp',
|
|
1628
|
-
'.h': 'c',
|
|
1629
|
-
'.hpp': 'cpp',
|
|
1630
|
-
'.cs': 'csharp',
|
|
1631
|
-
'.php': 'php',
|
|
1632
|
-
'.swift': 'swift',
|
|
1633
|
-
'.kt': 'kotlin',
|
|
1634
|
-
'.scala': 'scala',
|
|
1635
|
-
'.sh': 'bash',
|
|
1636
|
-
'.bash': 'bash',
|
|
1637
|
-
'.zsh': 'bash',
|
|
1638
|
-
'.ps1': 'powershell',
|
|
1639
|
-
'.sql': 'sql',
|
|
1640
|
-
'.html': 'html',
|
|
1641
|
-
'.htm': 'html',
|
|
1642
|
-
'.css': 'css',
|
|
1643
|
-
'.scss': 'scss',
|
|
1644
|
-
'.sass': 'sass',
|
|
1645
|
-
'.less': 'less',
|
|
1646
|
-
'.json': 'json',
|
|
1647
|
-
'.xml': 'xml',
|
|
1648
|
-
'.yaml': 'yaml',
|
|
1649
|
-
'.yml': 'yaml',
|
|
1650
|
-
'.toml': 'toml',
|
|
1651
|
-
'.ini': 'ini',
|
|
1652
|
-
'.cfg': 'ini',
|
|
1653
|
-
'.conf': 'nginx',
|
|
1654
|
-
'.md': 'markdown',
|
|
1655
|
-
'.markdown': 'markdown',
|
|
1656
|
-
'.txt': 'plaintext',
|
|
1657
|
-
'.log': 'plaintext',
|
|
1658
|
-
'.env': 'bash',
|
|
1659
|
-
'.dockerfile': 'dockerfile',
|
|
1660
|
-
'.vue': 'html',
|
|
1661
|
-
'.svelte': 'html'
|
|
1662
|
-
};
|
|
1663
|
-
|
|
1664
|
-
/**
|
|
1665
|
-
* Parse .gitignore file and return patterns
|
|
1666
|
-
* @param {string} gitignorePath - Path to .gitignore file
|
|
1667
|
-
* @returns {string[]} Array of gitignore patterns
|
|
1668
|
-
*/
|
|
1669
|
-
function parseGitignore(gitignorePath) {
|
|
1670
|
-
try {
|
|
1671
|
-
if (!existsSync(gitignorePath)) return [];
|
|
1672
|
-
const content = readFileSync(gitignorePath, 'utf8');
|
|
1673
|
-
return content
|
|
1674
|
-
.split('\n')
|
|
1675
|
-
.map(line => line.trim())
|
|
1676
|
-
.filter(line => line && !line.startsWith('#'));
|
|
1677
|
-
} catch {
|
|
1678
|
-
return [];
|
|
1679
|
-
}
|
|
1680
|
-
}
|
|
1681
|
-
|
|
1682
|
-
/**
|
|
1683
|
-
* Check if a file/directory should be ignored based on gitignore patterns
|
|
1684
|
-
* Simple pattern matching (supports basic glob patterns)
|
|
1685
|
-
* @param {string} name - File or directory name
|
|
1686
|
-
* @param {string[]} patterns - Gitignore patterns
|
|
1687
|
-
* @param {boolean} isDirectory - Whether the entry is a directory
|
|
1688
|
-
* @returns {boolean}
|
|
1689
|
-
*/
|
|
1690
|
-
function shouldIgnore(name, patterns, isDirectory) {
|
|
1691
|
-
// Always exclude certain directories
|
|
1692
|
-
if (isDirectory && EXPLORER_EXCLUDE_DIRS.includes(name)) {
|
|
1693
|
-
return true;
|
|
1694
|
-
}
|
|
1695
|
-
|
|
1696
|
-
// Skip hidden files/directories (starting with .)
|
|
1697
|
-
if (name.startsWith('.') && name !== '.claude' && name !== '.workflow') {
|
|
1698
|
-
return true;
|
|
1699
|
-
}
|
|
1700
|
-
|
|
1701
|
-
for (const pattern of patterns) {
|
|
1702
|
-
let p = pattern;
|
|
1703
|
-
|
|
1704
|
-
// Handle negation patterns (we skip them for simplicity)
|
|
1705
|
-
if (p.startsWith('!')) continue;
|
|
1706
|
-
|
|
1707
|
-
// Handle directory-only patterns
|
|
1708
|
-
if (p.endsWith('/')) {
|
|
1709
|
-
if (!isDirectory) continue;
|
|
1710
|
-
p = p.slice(0, -1);
|
|
1711
|
-
}
|
|
1712
|
-
|
|
1713
|
-
// Simple pattern matching
|
|
1714
|
-
if (p === name) return true;
|
|
1715
|
-
|
|
1716
|
-
// Handle wildcard patterns
|
|
1717
|
-
if (p.includes('*')) {
|
|
1718
|
-
const regex = new RegExp('^' + p.replace(/\./g, '\\.').replace(/\*/g, '.*') + '$');
|
|
1719
|
-
if (regex.test(name)) return true;
|
|
1720
|
-
}
|
|
1721
|
-
|
|
1722
|
-
// Handle extension patterns like *.log
|
|
1723
|
-
if (p.startsWith('*.')) {
|
|
1724
|
-
const ext = p.slice(1);
|
|
1725
|
-
if (name.endsWith(ext)) return true;
|
|
1726
|
-
}
|
|
1727
|
-
}
|
|
1728
|
-
|
|
1729
|
-
return false;
|
|
1730
|
-
}
|
|
1731
|
-
|
|
1732
|
-
/**
|
|
1733
|
-
* List directory files with .gitignore filtering
|
|
1734
|
-
* @param {string} dirPath - Directory path to list
|
|
1735
|
-
* @returns {Promise<Object>}
|
|
1736
|
-
*/
|
|
1737
|
-
async function listDirectoryFiles(dirPath) {
|
|
1738
|
-
try {
|
|
1739
|
-
// Normalize path
|
|
1740
|
-
let normalizedPath = dirPath.replace(/\\/g, '/');
|
|
1741
|
-
if (normalizedPath.match(/^\/[a-zA-Z]\//)) {
|
|
1742
|
-
normalizedPath = normalizedPath.charAt(1).toUpperCase() + ':' + normalizedPath.slice(2);
|
|
1743
|
-
}
|
|
1744
|
-
|
|
1745
|
-
if (!existsSync(normalizedPath)) {
|
|
1746
|
-
return { error: 'Directory not found', files: [] };
|
|
1747
|
-
}
|
|
1748
|
-
|
|
1749
|
-
if (!statSync(normalizedPath).isDirectory()) {
|
|
1750
|
-
return { error: 'Not a directory', files: [] };
|
|
1751
|
-
}
|
|
1752
|
-
|
|
1753
|
-
// Parse .gitignore patterns
|
|
1754
|
-
const gitignorePath = join(normalizedPath, '.gitignore');
|
|
1755
|
-
const gitignorePatterns = parseGitignore(gitignorePath);
|
|
1756
|
-
|
|
1757
|
-
// Read directory entries
|
|
1758
|
-
const entries = readdirSync(normalizedPath, { withFileTypes: true });
|
|
1759
|
-
|
|
1760
|
-
const files = [];
|
|
1761
|
-
for (const entry of entries) {
|
|
1762
|
-
const isDirectory = entry.isDirectory();
|
|
1763
|
-
|
|
1764
|
-
// Check if should be ignored
|
|
1765
|
-
if (shouldIgnore(entry.name, gitignorePatterns, isDirectory)) {
|
|
1766
|
-
continue;
|
|
1767
|
-
}
|
|
1768
|
-
|
|
1769
|
-
const entryPath = join(normalizedPath, entry.name);
|
|
1770
|
-
const fileInfo = {
|
|
1771
|
-
name: entry.name,
|
|
1772
|
-
type: isDirectory ? 'directory' : 'file',
|
|
1773
|
-
path: entryPath.replace(/\\/g, '/')
|
|
1774
|
-
};
|
|
1775
|
-
|
|
1776
|
-
// Check if directory has CLAUDE.md
|
|
1777
|
-
if (isDirectory) {
|
|
1778
|
-
const claudeMdPath = join(entryPath, 'CLAUDE.md');
|
|
1779
|
-
fileInfo.hasClaudeMd = existsSync(claudeMdPath);
|
|
1780
|
-
}
|
|
1781
|
-
|
|
1782
|
-
files.push(fileInfo);
|
|
1783
|
-
}
|
|
1784
|
-
|
|
1785
|
-
// Sort: directories first, then alphabetically
|
|
1786
|
-
files.sort((a, b) => {
|
|
1787
|
-
if (a.type === 'directory' && b.type !== 'directory') return -1;
|
|
1788
|
-
if (a.type !== 'directory' && b.type === 'directory') return 1;
|
|
1789
|
-
return a.name.localeCompare(b.name);
|
|
1790
|
-
});
|
|
1791
|
-
|
|
1792
|
-
return {
|
|
1793
|
-
path: normalizedPath.replace(/\\/g, '/'),
|
|
1794
|
-
files,
|
|
1795
|
-
gitignorePatterns
|
|
1796
|
-
};
|
|
1797
|
-
} catch (error) {
|
|
1798
|
-
console.error('Error listing directory:', error);
|
|
1799
|
-
return { error: error.message, files: [] };
|
|
1800
|
-
}
|
|
1801
|
-
}
|
|
1802
|
-
|
|
1803
|
-
/**
|
|
1804
|
-
* Get file content for preview
|
|
1805
|
-
* @param {string} filePath - Path to file
|
|
1806
|
-
* @returns {Promise<Object>}
|
|
1807
|
-
*/
|
|
1808
|
-
async function getFileContent(filePath) {
|
|
1809
|
-
try {
|
|
1810
|
-
// Normalize path
|
|
1811
|
-
let normalizedPath = filePath.replace(/\\/g, '/');
|
|
1812
|
-
if (normalizedPath.match(/^\/[a-zA-Z]\//)) {
|
|
1813
|
-
normalizedPath = normalizedPath.charAt(1).toUpperCase() + ':' + normalizedPath.slice(2);
|
|
1814
|
-
}
|
|
1815
|
-
|
|
1816
|
-
if (!existsSync(normalizedPath)) {
|
|
1817
|
-
return { error: 'File not found' };
|
|
1818
|
-
}
|
|
1819
|
-
|
|
1820
|
-
const stats = statSync(normalizedPath);
|
|
1821
|
-
if (stats.isDirectory()) {
|
|
1822
|
-
return { error: 'Cannot read directory' };
|
|
1823
|
-
}
|
|
1824
|
-
|
|
1825
|
-
// Check file size (limit to 1MB for preview)
|
|
1826
|
-
if (stats.size > 1024 * 1024) {
|
|
1827
|
-
return { error: 'File too large for preview (max 1MB)', size: stats.size };
|
|
1828
|
-
}
|
|
1829
|
-
|
|
1830
|
-
// Read file content
|
|
1831
|
-
const content = readFileSync(normalizedPath, 'utf8');
|
|
1832
|
-
const ext = normalizedPath.substring(normalizedPath.lastIndexOf('.')).toLowerCase();
|
|
1833
|
-
const language = EXT_TO_LANGUAGE[ext] || 'plaintext';
|
|
1834
|
-
const isMarkdown = ext === '.md' || ext === '.markdown';
|
|
1835
|
-
const fileName = normalizedPath.split('/').pop();
|
|
1836
|
-
|
|
1837
|
-
return {
|
|
1838
|
-
content,
|
|
1839
|
-
language,
|
|
1840
|
-
isMarkdown,
|
|
1841
|
-
fileName,
|
|
1842
|
-
path: normalizedPath,
|
|
1843
|
-
size: stats.size,
|
|
1844
|
-
lines: content.split('\n').length
|
|
1845
|
-
};
|
|
1846
|
-
} catch (error) {
|
|
1847
|
-
console.error('Error reading file:', error);
|
|
1848
|
-
return { error: error.message };
|
|
1849
|
-
}
|
|
1850
|
-
}
|
|
1851
|
-
|
|
1852
|
-
/**
|
|
1853
|
-
* Trigger update-module-claude tool (async execution)
|
|
1854
|
-
* @param {string} targetPath - Directory path to update
|
|
1855
|
-
* @param {string} tool - CLI tool to use (gemini, qwen, codex)
|
|
1856
|
-
* @param {string} strategy - Update strategy (single-layer, multi-layer)
|
|
1857
|
-
* @returns {Promise<Object>}
|
|
1858
|
-
*/
|
|
1859
|
-
async function triggerUpdateClaudeMd(targetPath, tool, strategy) {
|
|
1860
|
-
const { spawn } = await import('child_process');
|
|
1861
|
-
|
|
1862
|
-
// Normalize path
|
|
1863
|
-
let normalizedPath = targetPath.replace(/\\/g, '/');
|
|
1864
|
-
if (normalizedPath.match(/^\/[a-zA-Z]\//)) {
|
|
1865
|
-
normalizedPath = normalizedPath.charAt(1).toUpperCase() + ':' + normalizedPath.slice(2);
|
|
1866
|
-
}
|
|
1867
|
-
|
|
1868
|
-
if (!existsSync(normalizedPath)) {
|
|
1869
|
-
return { error: 'Directory not found' };
|
|
1870
|
-
}
|
|
1871
|
-
|
|
1872
|
-
if (!statSync(normalizedPath).isDirectory()) {
|
|
1873
|
-
return { error: 'Not a directory' };
|
|
1874
|
-
}
|
|
1875
|
-
|
|
1876
|
-
// Build ccw tool command with JSON parameters
|
|
1877
|
-
const params = JSON.stringify({
|
|
1878
|
-
strategy,
|
|
1879
|
-
path: normalizedPath,
|
|
1880
|
-
tool
|
|
1881
|
-
});
|
|
1882
|
-
|
|
1883
|
-
console.log(`[Explorer] Running async: ccw tool exec update_module_claude with ${tool} (${strategy})`);
|
|
1884
|
-
|
|
1885
|
-
return new Promise((resolve) => {
|
|
1886
|
-
const isWindows = process.platform === 'win32';
|
|
1887
|
-
|
|
1888
|
-
// Spawn the process
|
|
1889
|
-
const child = spawn('ccw', ['tool', 'exec', 'update_module_claude', params], {
|
|
1890
|
-
cwd: normalizedPath,
|
|
1891
|
-
shell: isWindows,
|
|
1892
|
-
stdio: ['ignore', 'pipe', 'pipe']
|
|
1893
|
-
});
|
|
1894
|
-
|
|
1895
|
-
let stdout = '';
|
|
1896
|
-
let stderr = '';
|
|
1897
|
-
|
|
1898
|
-
child.stdout.on('data', (data) => {
|
|
1899
|
-
stdout += data.toString();
|
|
1900
|
-
});
|
|
1901
|
-
|
|
1902
|
-
child.stderr.on('data', (data) => {
|
|
1903
|
-
stderr += data.toString();
|
|
1904
|
-
});
|
|
1905
|
-
|
|
1906
|
-
child.on('close', (code) => {
|
|
1907
|
-
if (code === 0) {
|
|
1908
|
-
// Parse the JSON output from the tool
|
|
1909
|
-
let result;
|
|
1910
|
-
try {
|
|
1911
|
-
result = JSON.parse(stdout);
|
|
1912
|
-
} catch {
|
|
1913
|
-
result = { output: stdout };
|
|
1914
|
-
}
|
|
1915
|
-
|
|
1916
|
-
if (result.success === false || result.error) {
|
|
1917
|
-
resolve({
|
|
1918
|
-
success: false,
|
|
1919
|
-
error: result.error || result.message || 'Update failed',
|
|
1920
|
-
output: stdout
|
|
1921
|
-
});
|
|
1922
|
-
} else {
|
|
1923
|
-
resolve({
|
|
1924
|
-
success: true,
|
|
1925
|
-
message: result.message || `CLAUDE.md updated successfully using ${tool} (${strategy})`,
|
|
1926
|
-
output: stdout,
|
|
1927
|
-
path: normalizedPath
|
|
1928
|
-
});
|
|
1929
|
-
}
|
|
1930
|
-
} else {
|
|
1931
|
-
resolve({
|
|
1932
|
-
success: false,
|
|
1933
|
-
error: stderr || `Process exited with code ${code}`,
|
|
1934
|
-
output: stdout + stderr
|
|
1935
|
-
});
|
|
1936
|
-
}
|
|
1937
|
-
});
|
|
1938
|
-
|
|
1939
|
-
child.on('error', (error) => {
|
|
1940
|
-
console.error('Error spawning process:', error);
|
|
1941
|
-
resolve({
|
|
1942
|
-
success: false,
|
|
1943
|
-
error: error.message,
|
|
1944
|
-
output: ''
|
|
1945
|
-
});
|
|
1946
|
-
});
|
|
1947
|
-
|
|
1948
|
-
// Timeout after 5 minutes
|
|
1949
|
-
setTimeout(() => {
|
|
1950
|
-
child.kill();
|
|
1951
|
-
resolve({
|
|
1952
|
-
success: false,
|
|
1953
|
-
error: 'Timeout: Process took longer than 5 minutes',
|
|
1954
|
-
output: stdout
|
|
1955
|
-
});
|
|
1956
|
-
}, 300000);
|
|
1957
|
-
});
|
|
1958
|
-
}
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
// ========================================
|
|
1962
|
-
// Version Check Functions
|
|
1963
|
-
// ========================================
|
|
1964
|
-
|
|
1965
|
-
// Package name on npm registry
|
|
1966
|
-
const NPM_PACKAGE_NAME = 'claude-code-workflow';
|
|
1967
|
-
|
|
1968
|
-
// Cache for version check (avoid too frequent requests)
|
|
1969
|
-
let versionCheckCache = null;
|
|
1970
|
-
let versionCheckTime = 0;
|
|
1971
|
-
const VERSION_CHECK_CACHE_TTL = 3600000; // 1 hour
|
|
1972
|
-
|
|
1973
|
-
/**
|
|
1974
|
-
* Get current package version from package.json
|
|
1975
|
-
* @returns {string}
|
|
1976
|
-
*/
|
|
1977
|
-
function getCurrentVersion() {
|
|
1978
|
-
try {
|
|
1979
|
-
const packageJsonPath = join(import.meta.dirname, '../../../package.json');
|
|
1980
|
-
if (existsSync(packageJsonPath)) {
|
|
1981
|
-
const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
|
|
1982
|
-
return pkg.version || '0.0.0';
|
|
1983
|
-
}
|
|
1984
|
-
} catch (e) {
|
|
1985
|
-
console.error('Error reading package.json:', e);
|
|
1986
|
-
}
|
|
1987
|
-
return '0.0.0';
|
|
1988
|
-
}
|
|
1989
|
-
|
|
1990
|
-
/**
|
|
1991
|
-
* Check npm registry for latest version
|
|
1992
|
-
* @returns {Promise<Object>}
|
|
1993
|
-
*/
|
|
1994
|
-
async function checkNpmVersion() {
|
|
1995
|
-
// Return cached result if still valid
|
|
1996
|
-
const now = Date.now();
|
|
1997
|
-
if (versionCheckCache && (now - versionCheckTime) < VERSION_CHECK_CACHE_TTL) {
|
|
1998
|
-
return versionCheckCache;
|
|
1999
|
-
}
|
|
2000
|
-
|
|
2001
|
-
const currentVersion = getCurrentVersion();
|
|
2002
|
-
|
|
2003
|
-
try {
|
|
2004
|
-
// Fetch latest version from npm registry
|
|
2005
|
-
const npmUrl = 'https://registry.npmjs.org/' + encodeURIComponent(NPM_PACKAGE_NAME) + '/latest';
|
|
2006
|
-
const response = await fetch(npmUrl, {
|
|
2007
|
-
headers: { 'Accept': 'application/json' }
|
|
2008
|
-
});
|
|
2009
|
-
|
|
2010
|
-
if (!response.ok) {
|
|
2011
|
-
throw new Error('HTTP ' + response.status);
|
|
2012
|
-
}
|
|
2013
|
-
|
|
2014
|
-
const data = await response.json();
|
|
2015
|
-
const latestVersion = data.version;
|
|
2016
|
-
|
|
2017
|
-
// Compare versions
|
|
2018
|
-
const hasUpdate = compareVersions(latestVersion, currentVersion) > 0;
|
|
2019
|
-
|
|
2020
|
-
const result = {
|
|
2021
|
-
currentVersion,
|
|
2022
|
-
latestVersion,
|
|
2023
|
-
hasUpdate,
|
|
2024
|
-
packageName: NPM_PACKAGE_NAME,
|
|
2025
|
-
updateCommand: 'npm update -g ' + NPM_PACKAGE_NAME,
|
|
2026
|
-
checkedAt: new Date().toISOString()
|
|
2027
|
-
};
|
|
2028
|
-
|
|
2029
|
-
// Cache the result
|
|
2030
|
-
versionCheckCache = result;
|
|
2031
|
-
versionCheckTime = now;
|
|
2032
|
-
|
|
2033
|
-
return result;
|
|
2034
|
-
} catch (error) {
|
|
2035
|
-
console.error('Version check failed:', error.message);
|
|
2036
|
-
return {
|
|
2037
|
-
currentVersion,
|
|
2038
|
-
latestVersion: null,
|
|
2039
|
-
hasUpdate: false,
|
|
2040
|
-
error: error.message,
|
|
2041
|
-
checkedAt: new Date().toISOString()
|
|
2042
|
-
};
|
|
2043
|
-
}
|
|
2044
|
-
}
|
|
2045
|
-
|
|
2046
|
-
/**
|
|
2047
|
-
* Compare two semver versions
|
|
2048
|
-
* @param {string} v1
|
|
2049
|
-
* @param {string} v2
|
|
2050
|
-
* @returns {number} 1 if v1 > v2, -1 if v1 < v2, 0 if equal
|
|
2051
|
-
*/
|
|
2052
|
-
function compareVersions(v1, v2) {
|
|
2053
|
-
const parts1 = v1.split('.').map(Number);
|
|
2054
|
-
const parts2 = v2.split('.').map(Number);
|
|
2055
|
-
|
|
2056
|
-
for (let i = 0; i < 3; i++) {
|
|
2057
|
-
const p1 = parts1[i] || 0;
|
|
2058
|
-
const p2 = parts2[i] || 0;
|
|
2059
|
-
if (p1 > p2) return 1;
|
|
2060
|
-
if (p1 < p2) return -1;
|
|
2061
|
-
}
|
|
2062
|
-
return 0;
|
|
2063
|
-
}
|