chore: update project version to 0.0.11 and enhance project management features
- Added new project initialization route to register git projects from a specified root directory. - Enhanced project management to support project status (active, inactive, unlive) and conditional listening. - Updated project listener to handle non-existent paths gracefully. - Improved project store to manage project documents with optional fields. - Refactored git utility functions for better pathname extraction from URLs. - Added command-line interface support for project management. - Updated project routes to handle new project types and improved error handling.
This commit is contained in:
125
bun.lock
125
bun.lock
@@ -6,14 +6,15 @@
|
||||
"name": "@kevisual/project-search",
|
||||
"dependencies": {
|
||||
"@parcel/watcher": "^2.5.6",
|
||||
"es-toolkit": "^1.45.1",
|
||||
"eventemitter3": "^5.0.4",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@kevisual/code-builder": "^0.0.6",
|
||||
"@kevisual/context": "^0.0.8",
|
||||
"@kevisual/dts": "^0.0.4",
|
||||
"@kevisual/remote-app": "^0.0.7",
|
||||
"@kevisual/router": "^0.1.1",
|
||||
"es-toolkit": "^1.45.1",
|
||||
"eventemitter3": "^5.0.4",
|
||||
"fast-glob": "^3.3.3",
|
||||
"meilisearch": "^0.55.0",
|
||||
"zod": "^4.3.6",
|
||||
@@ -21,10 +22,26 @@
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"@babel/code-frame": ["@babel/code-frame@7.29.0", "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.29.0.tgz", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="],
|
||||
|
||||
"@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
|
||||
|
||||
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "https://registry.npmmirror.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
|
||||
|
||||
"@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "https://registry.npmmirror.com/@jridgewell/remapping/-/remapping-2.3.5.tgz", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="],
|
||||
|
||||
"@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
|
||||
|
||||
"@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
|
||||
|
||||
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
|
||||
|
||||
"@kevisual/code-builder": ["@kevisual/code-builder@0.0.6", "https://registry.npmmirror.com/@kevisual/code-builder/-/code-builder-0.0.6.tgz", { "bin": { "code-builder": "bin/code.js", "builder": "bin/code.js" } }, "sha512-0aqATB31/yw4k4s5/xKnfr4DKbUnx8e3Z3BmKbiXTrc+CqWiWTdlGe9bKI9dZ2Df+xNp6g11W4xM2NICNyyCCw=="],
|
||||
|
||||
"@kevisual/context": ["@kevisual/context@0.0.8", "https://registry.npmmirror.com/@kevisual/context/-/context-0.0.8.tgz", {}, "sha512-DTJpyHI34NE76B7g6f+QlIqiCCyqI2qkBMQE736dzeRDGxOjnbe2iQY9W+Rt2PE6kmymM3qyOmSfNovyWyWrkA=="],
|
||||
|
||||
"@kevisual/dts": ["@kevisual/dts@0.0.4", "https://registry.npmmirror.com/@kevisual/dts/-/dts-0.0.4.tgz", { "dependencies": { "@rollup/plugin-commonjs": "^29.0.0", "@rollup/plugin-node-resolve": "^16.0.3", "@rollup/plugin-typescript": "^12.3.0", "rollup": "^4.57.1", "rollup-plugin-dts": "^6.3.0", "tslib": "^2.8.1" }, "bin": { "dts": "bin/dts.mjs" } }, "sha512-FVUaH/0nyhbHWpEVjFTGP54PLMm4Hf06aqWLdHOYHNPIgr1aK1C26kOH7iumklGFGk9w93IGxj8Zxe5fap5N2A=="],
|
||||
|
||||
"@kevisual/remote-app": ["@kevisual/remote-app@0.0.7", "https://registry.npmmirror.com/@kevisual/remote-app/-/remote-app-0.0.7.tgz", {}, "sha512-d0P8uyxoMnmyT8x1J9XC9ecDBbqW+jOP0ZM5fCgQRDUhWw35V/MnbCD4hNG4b6EmvoiS6a/PBC7RC5JGm3wpCg=="],
|
||||
|
||||
"@kevisual/router": ["@kevisual/router@0.1.1", "https://registry.npmmirror.com/@kevisual/router/-/router-0.1.1.tgz", { "dependencies": { "es-toolkit": "^1.45.1" } }, "sha512-+uaJc+Bf/T1mfxyfy9PmwuxJGPOLhVqrmsli2xUPqkkFvizrFIGB1vBTITuo5XP/FnwGqxgbjsitG57AMubm3w=="],
|
||||
@@ -63,28 +80,116 @@
|
||||
|
||||
"@parcel/watcher-win32-x64": ["@parcel/watcher-win32-x64@2.5.6", "https://registry.npmmirror.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz", { "os": "win32", "cpu": "x64" }, "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw=="],
|
||||
|
||||
"@rollup/plugin-commonjs": ["@rollup/plugin-commonjs@29.0.2", "https://registry.npmmirror.com/@rollup/plugin-commonjs/-/plugin-commonjs-29.0.2.tgz", { "dependencies": { "@rollup/pluginutils": "^5.0.1", "commondir": "^1.0.1", "estree-walker": "^2.0.2", "fdir": "^6.2.0", "is-reference": "1.2.1", "magic-string": "^0.30.3", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^2.68.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-S/ggWH1LU7jTyi9DxZOKyxpVd4hF/OZ0JrEbeLjXk/DFXwRny0tjD2c992zOUYQobLrVkRVMDdmHP16HKP7GRg=="],
|
||||
|
||||
"@rollup/plugin-node-resolve": ["@rollup/plugin-node-resolve@16.0.3", "https://registry.npmmirror.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.3.tgz", { "dependencies": { "@rollup/pluginutils": "^5.0.1", "@types/resolve": "1.20.2", "deepmerge": "^4.2.2", "is-module": "^1.0.0", "resolve": "^1.22.1" }, "peerDependencies": { "rollup": "^2.78.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg=="],
|
||||
|
||||
"@rollup/plugin-typescript": ["@rollup/plugin-typescript@12.3.0", "https://registry.npmmirror.com/@rollup/plugin-typescript/-/plugin-typescript-12.3.0.tgz", { "dependencies": { "@rollup/pluginutils": "^5.1.0", "resolve": "^1.22.1" }, "peerDependencies": { "rollup": "^2.14.0||^3.0.0||^4.0.0", "tslib": "*", "typescript": ">=3.7.0" }, "optionalPeers": ["rollup", "tslib"] }, "sha512-7DP0/p7y3t67+NabT9f8oTBFE6gGkto4SA6Np2oudYmZE/m1dt8RB0SjL1msMxFpLo631qjRCcBlAbq1ml/Big=="],
|
||||
|
||||
"@rollup/pluginutils": ["@rollup/pluginutils@5.3.0", "https://registry.npmmirror.com/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q=="],
|
||||
|
||||
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.59.0", "https://registry.npmmirror.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", { "os": "android", "cpu": "arm" }, "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg=="],
|
||||
|
||||
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.59.0", "https://registry.npmmirror.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", { "os": "android", "cpu": "arm64" }, "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q=="],
|
||||
|
||||
"@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.59.0", "https://registry.npmmirror.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", { "os": "darwin", "cpu": "arm64" }, "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg=="],
|
||||
|
||||
"@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.59.0", "https://registry.npmmirror.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", { "os": "darwin", "cpu": "x64" }, "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w=="],
|
||||
|
||||
"@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.59.0", "https://registry.npmmirror.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", { "os": "freebsd", "cpu": "arm64" }, "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA=="],
|
||||
|
||||
"@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.59.0", "https://registry.npmmirror.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", { "os": "freebsd", "cpu": "x64" }, "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg=="],
|
||||
|
||||
"@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.59.0", "https://registry.npmmirror.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", { "os": "linux", "cpu": "arm" }, "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw=="],
|
||||
|
||||
"@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.59.0", "https://registry.npmmirror.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", { "os": "linux", "cpu": "arm" }, "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA=="],
|
||||
|
||||
"@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.59.0", "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", { "os": "linux", "cpu": "arm64" }, "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA=="],
|
||||
|
||||
"@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.59.0", "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", { "os": "linux", "cpu": "arm64" }, "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA=="],
|
||||
|
||||
"@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.59.0", "https://registry.npmmirror.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", { "os": "linux", "cpu": "none" }, "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg=="],
|
||||
|
||||
"@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.59.0", "https://registry.npmmirror.com/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", { "os": "linux", "cpu": "none" }, "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q=="],
|
||||
|
||||
"@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.59.0", "https://registry.npmmirror.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", { "os": "linux", "cpu": "ppc64" }, "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA=="],
|
||||
|
||||
"@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.59.0", "https://registry.npmmirror.com/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", { "os": "linux", "cpu": "ppc64" }, "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA=="],
|
||||
|
||||
"@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.59.0", "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", { "os": "linux", "cpu": "none" }, "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg=="],
|
||||
|
||||
"@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.59.0", "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", { "os": "linux", "cpu": "none" }, "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg=="],
|
||||
|
||||
"@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.59.0", "https://registry.npmmirror.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", { "os": "linux", "cpu": "s390x" }, "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w=="],
|
||||
|
||||
"@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.59.0", "https://registry.npmmirror.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", { "os": "linux", "cpu": "x64" }, "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg=="],
|
||||
|
||||
"@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.59.0", "https://registry.npmmirror.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", { "os": "linux", "cpu": "x64" }, "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg=="],
|
||||
|
||||
"@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.59.0", "https://registry.npmmirror.com/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", { "os": "openbsd", "cpu": "x64" }, "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ=="],
|
||||
|
||||
"@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.59.0", "https://registry.npmmirror.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", { "os": "none", "cpu": "arm64" }, "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA=="],
|
||||
|
||||
"@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.59.0", "https://registry.npmmirror.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", { "os": "win32", "cpu": "arm64" }, "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A=="],
|
||||
|
||||
"@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.59.0", "https://registry.npmmirror.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", { "os": "win32", "cpu": "ia32" }, "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA=="],
|
||||
|
||||
"@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.59.0", "https://registry.npmmirror.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", { "os": "win32", "cpu": "x64" }, "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA=="],
|
||||
|
||||
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.59.0", "https://registry.npmmirror.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", { "os": "win32", "cpu": "x64" }, "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA=="],
|
||||
|
||||
"@types/estree": ["@types/estree@1.0.8", "https://registry.npmmirror.com/@types/estree/-/estree-1.0.8.tgz", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
|
||||
|
||||
"@types/resolve": ["@types/resolve@1.20.2", "https://registry.npmmirror.com/@types/resolve/-/resolve-1.20.2.tgz", {}, "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q=="],
|
||||
|
||||
"braces": ["braces@3.0.3", "https://registry.npmmirror.com/braces/-/braces-3.0.3.tgz", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
|
||||
|
||||
"commondir": ["commondir@1.0.1", "https://registry.npmmirror.com/commondir/-/commondir-1.0.1.tgz", {}, "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg=="],
|
||||
|
||||
"convert-source-map": ["convert-source-map@2.0.0", "https://registry.npmmirror.com/convert-source-map/-/convert-source-map-2.0.0.tgz", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="],
|
||||
|
||||
"deepmerge": ["deepmerge@4.3.1", "https://registry.npmmirror.com/deepmerge/-/deepmerge-4.3.1.tgz", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="],
|
||||
|
||||
"detect-libc": ["detect-libc@2.1.2", "https://registry.npmmirror.com/detect-libc/-/detect-libc-2.1.2.tgz", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
|
||||
|
||||
"es-toolkit": ["es-toolkit@1.45.1", "https://registry.npmmirror.com/es-toolkit/-/es-toolkit-1.45.1.tgz", {}, "sha512-/jhoOj/Fx+A+IIyDNOvO3TItGmlMKhtX8ISAHKE90c4b/k1tqaqEZ+uUqfpU8DMnW5cgNJv606zS55jGvza0Xw=="],
|
||||
|
||||
"estree-walker": ["estree-walker@2.0.2", "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
|
||||
|
||||
"eventemitter3": ["eventemitter3@5.0.4", "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-5.0.4.tgz", {}, "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw=="],
|
||||
|
||||
"fast-glob": ["fast-glob@3.3.3", "https://registry.npmmirror.com/fast-glob/-/fast-glob-3.3.3.tgz", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="],
|
||||
|
||||
"fastq": ["fastq@1.20.1", "https://registry.npmmirror.com/fastq/-/fastq-1.20.1.tgz", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw=="],
|
||||
|
||||
"fdir": ["fdir@6.5.0", "https://registry.npmmirror.com/fdir/-/fdir-6.5.0.tgz", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
|
||||
|
||||
"fill-range": ["fill-range@7.1.1", "https://registry.npmmirror.com/fill-range/-/fill-range-7.1.1.tgz", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
|
||||
|
||||
"fsevents": ["fsevents@2.3.3", "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
|
||||
|
||||
"function-bind": ["function-bind@1.1.2", "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
|
||||
|
||||
"glob-parent": ["glob-parent@5.1.2", "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
||||
|
||||
"hasown": ["hasown@2.0.2", "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
|
||||
|
||||
"is-core-module": ["is-core-module@2.16.1", "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.16.1.tgz", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="],
|
||||
|
||||
"is-extglob": ["is-extglob@2.1.1", "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
|
||||
|
||||
"is-glob": ["is-glob@4.0.3", "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
|
||||
|
||||
"is-module": ["is-module@1.0.0", "https://registry.npmmirror.com/is-module/-/is-module-1.0.0.tgz", {}, "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g=="],
|
||||
|
||||
"is-number": ["is-number@7.0.0", "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
|
||||
|
||||
"is-reference": ["is-reference@1.2.1", "https://registry.npmmirror.com/is-reference/-/is-reference-1.2.1.tgz", { "dependencies": { "@types/estree": "*" } }, "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ=="],
|
||||
|
||||
"js-tokens": ["js-tokens@4.0.0", "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
|
||||
|
||||
"magic-string": ["magic-string@0.30.21", "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.21.tgz", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
|
||||
|
||||
"meilisearch": ["meilisearch@0.55.0", "https://registry.npmmirror.com/meilisearch/-/meilisearch-0.55.0.tgz", {}, "sha512-qSMeiezfDgIqciIeYzh5E4pXDZZD7CtHeWDCs43kN3trLgl5FtfmBAIkljL3huFaOx08feYtC8FfIFUpVwq6rg=="],
|
||||
|
||||
"merge2": ["merge2@1.4.1", "https://registry.npmmirror.com/merge2/-/merge2-1.4.1.tgz", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="],
|
||||
@@ -93,16 +198,32 @@
|
||||
|
||||
"node-addon-api": ["node-addon-api@7.1.1", "https://registry.npmmirror.com/node-addon-api/-/node-addon-api-7.1.1.tgz", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="],
|
||||
|
||||
"path-parse": ["path-parse@1.0.7", "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="],
|
||||
|
||||
"picocolors": ["picocolors@1.1.1", "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
|
||||
|
||||
"picomatch": ["picomatch@4.0.3", "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.3.tgz", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
|
||||
|
||||
"queue-microtask": ["queue-microtask@1.2.3", "https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
|
||||
|
||||
"resolve": ["resolve@1.22.11", "https://registry.npmmirror.com/resolve/-/resolve-1.22.11.tgz", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="],
|
||||
|
||||
"reusify": ["reusify@1.1.0", "https://registry.npmmirror.com/reusify/-/reusify-1.1.0.tgz", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="],
|
||||
|
||||
"rollup": ["rollup@4.59.0", "https://registry.npmmirror.com/rollup/-/rollup-4.59.0.tgz", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.59.0", "@rollup/rollup-android-arm64": "4.59.0", "@rollup/rollup-darwin-arm64": "4.59.0", "@rollup/rollup-darwin-x64": "4.59.0", "@rollup/rollup-freebsd-arm64": "4.59.0", "@rollup/rollup-freebsd-x64": "4.59.0", "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", "@rollup/rollup-linux-arm-musleabihf": "4.59.0", "@rollup/rollup-linux-arm64-gnu": "4.59.0", "@rollup/rollup-linux-arm64-musl": "4.59.0", "@rollup/rollup-linux-loong64-gnu": "4.59.0", "@rollup/rollup-linux-loong64-musl": "4.59.0", "@rollup/rollup-linux-ppc64-gnu": "4.59.0", "@rollup/rollup-linux-ppc64-musl": "4.59.0", "@rollup/rollup-linux-riscv64-gnu": "4.59.0", "@rollup/rollup-linux-riscv64-musl": "4.59.0", "@rollup/rollup-linux-s390x-gnu": "4.59.0", "@rollup/rollup-linux-x64-gnu": "4.59.0", "@rollup/rollup-linux-x64-musl": "4.59.0", "@rollup/rollup-openbsd-x64": "4.59.0", "@rollup/rollup-openharmony-arm64": "4.59.0", "@rollup/rollup-win32-arm64-msvc": "4.59.0", "@rollup/rollup-win32-ia32-msvc": "4.59.0", "@rollup/rollup-win32-x64-gnu": "4.59.0", "@rollup/rollup-win32-x64-msvc": "4.59.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg=="],
|
||||
|
||||
"rollup-plugin-dts": ["rollup-plugin-dts@6.4.0", "https://registry.npmmirror.com/rollup-plugin-dts/-/rollup-plugin-dts-6.4.0.tgz", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "@jridgewell/sourcemap-codec": "^1.5.5", "convert-source-map": "^2.0.0", "magic-string": "^0.30.21" }, "optionalDependencies": { "@babel/code-frame": "^7.29.0" }, "peerDependencies": { "rollup": "^3.29.4 || ^4", "typescript": "^4.5 || ^5.0 || ^6.0" } }, "sha512-2i00A5UoPCoDecLEs13Eu105QegSGfrbp1sDeUj/54LKGmv6XFHDxWKC6Wsb4BobGUWYVCWWjmjAc8bXXbXH/Q=="],
|
||||
|
||||
"run-parallel": ["run-parallel@1.2.0", "https://registry.npmmirror.com/run-parallel/-/run-parallel-1.2.0.tgz", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
|
||||
|
||||
"supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "https://registry.npmmirror.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="],
|
||||
|
||||
"to-regex-range": ["to-regex-range@5.0.1", "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
|
||||
|
||||
"tslib": ["tslib@2.8.1", "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
|
||||
"typescript": ["typescript@5.9.3", "https://registry.npmmirror.com/typescript/-/typescript-5.9.3.tgz", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
||||
|
||||
"zod": ["zod@4.3.6", "https://registry.npmmirror.com/zod/-/zod-4.3.6.tgz", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="],
|
||||
|
||||
"micromatch/picomatch": ["picomatch@2.3.1", "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@kevisual/project-search",
|
||||
"version": "0.0.9",
|
||||
"version": "0.0.11",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
||||
4
src/commander.ts
Normal file
4
src/commander.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import { parse } from '@kevisual/router/commander'
|
||||
import { app } from './index'
|
||||
|
||||
parse({ app: app as any });
|
||||
@@ -8,6 +8,8 @@ import './routes/auth';
|
||||
import './routes/project';
|
||||
import './routes/search';
|
||||
import './routes/file';
|
||||
import './routes/project-init';
|
||||
|
||||
import { manager } from './app';
|
||||
|
||||
if (import.meta.main) {
|
||||
|
||||
@@ -8,25 +8,11 @@ import path from 'node:path';
|
||||
import { CustomError } from "@kevisual/router";
|
||||
|
||||
type Project = {
|
||||
name?: string;
|
||||
path: string;
|
||||
/**
|
||||
* 用 git remote url 唯一标识项目,方便搜索结果展示和过滤
|
||||
*/
|
||||
repo: string;
|
||||
listener: ProjectListener;
|
||||
};
|
||||
} & ProjectDoc;
|
||||
|
||||
export type ProjectInput = Omit<Project, "listener">;
|
||||
export type ProjectInfo = Omit<Project, "listener"> & {
|
||||
status: "active" | "inactive";
|
||||
id?: string;
|
||||
title?: string;
|
||||
tags?: string[];
|
||||
summary?: string;
|
||||
description?: string;
|
||||
link?: string;
|
||||
};
|
||||
export type ProjectInput = ProjectDoc;
|
||||
export type ProjectInfo = ProjectDoc
|
||||
|
||||
type ProjectManagerOpt = {
|
||||
meiliSearchOptions?: {
|
||||
@@ -58,7 +44,8 @@ export class ProjectManager implements ProjectManagerInterface {
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化:从 store 加载已持久化的项目,检查本地目录存在后启动监听
|
||||
* 初始化:从 store 加载已持久化的项目,检查本地目录存在后
|
||||
* 只对 status 为 active 的项目启动监听,inactive 的只加载不监听
|
||||
*/
|
||||
async init(): Promise<void> {
|
||||
await this.projectStore.init();
|
||||
@@ -68,8 +55,13 @@ export class ProjectManager implements ProjectManagerInterface {
|
||||
console.log(`[ProjectManager] init: skip missing path ${doc.path}`);
|
||||
continue;
|
||||
}
|
||||
// 只对 active 状态的项目启动监听
|
||||
const shouldWatch = doc.status === 'active';
|
||||
try {
|
||||
await this.addProject({ name: doc.name, path: doc.path, repo: doc.repo });
|
||||
await this.addProject(
|
||||
{ name: doc.name, path: doc.path, repo: doc.repo },
|
||||
{ startListening: shouldWatch }
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(`[ProjectManager] init: failed to add project ${doc.path}`, err);
|
||||
}
|
||||
@@ -78,32 +70,46 @@ export class ProjectManager implements ProjectManagerInterface {
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加项目:创建监听器、启动监听、触发全量初始同步
|
||||
* 添加项目:创建监听器、可选启动监听、触发全量初始同步
|
||||
*/
|
||||
async addProject(input: ProjectInput): Promise<ProjectInfo> {
|
||||
async addProject(input: ProjectDoc, options: { startListening?: boolean } = {}): Promise<ProjectInfo> {
|
||||
const { startListening = true } = options;
|
||||
// 检查本地目录是否存在
|
||||
if (!fs.existsSync(input.path)) {
|
||||
if (!fs.existsSync(input.path!)) {
|
||||
throw new CustomError(`[ProjectManager] addProject: path does not exist: ${input.path}`);
|
||||
}
|
||||
// 若已存在则先停止旧监听
|
||||
if (this.projects.has(input.path)) {
|
||||
await this.stopProject(input.path);
|
||||
if (this.projects.has(input.path!)) {
|
||||
await this.stopProject(input.path!);
|
||||
}
|
||||
const listener = new ProjectListener({ projectPath: input.path, emitter: this.emitter });
|
||||
const listener = new ProjectListener({ projectPath: input.path!, emitter: this.emitter });
|
||||
const project: Project = { ...input, listener };
|
||||
|
||||
this.projects.set(input.path, project);
|
||||
|
||||
// 持久化存储项目信息
|
||||
this.projects.set(input.path!, project);
|
||||
const readmePath = path.join(input.path!, 'README.md');
|
||||
let description = '';
|
||||
if (!input.description && fs.existsSync(readmePath)) {
|
||||
const readmeContent = fs.readFileSync(readmePath, 'utf-8');
|
||||
description = readmeContent;
|
||||
}
|
||||
// 持久化存储项目信息(默认 active)
|
||||
this.projectStore.ensureIndex().then(() =>
|
||||
this.projectStore.addProject({ name: input.name, path: input.path, repo: input.repo })
|
||||
this.projectStore.addProject({
|
||||
name: input.name,
|
||||
path: input.path,
|
||||
repo: input.repo,
|
||||
status: startListening ? 'active' : 'inactive',
|
||||
description: input?.description || description,
|
||||
})
|
||||
).catch(err => {
|
||||
console.error('[ProjectManager] projectStore.addProject failed:', err);
|
||||
});
|
||||
|
||||
// 启动文件监听
|
||||
await listener.startListening();
|
||||
console.log(`[ProjectManager] watching: ${input.path}`);
|
||||
// 根据选项启动文件监听
|
||||
if (startListening) {
|
||||
await listener.startListening();
|
||||
console.log(`[ProjectManager] watching: ${input.path}`);
|
||||
}
|
||||
|
||||
// 触发全量初始同步(不阻塞返回)
|
||||
this.projectSearch.initialSync(input.path, input.repo).catch(err => {
|
||||
@@ -137,15 +143,37 @@ export class ProjectManager implements ProjectManagerInterface {
|
||||
const project = this.projects.get(projectPath);
|
||||
if (!project) return;
|
||||
await project.listener.stopListening();
|
||||
// 更新 store 中的 status
|
||||
this.projectStore.updateProject(projectPath, { status: 'inactive' }).catch(err => {
|
||||
console.error('[ProjectManager] updateProject status failed:', err);
|
||||
});
|
||||
console.log(`[ProjectManager] stopped: ${projectPath}`);
|
||||
}
|
||||
|
||||
/** 启动项目文件监听 */
|
||||
async startProject(projectPath: string): Promise<void> {
|
||||
const project = this.projects.get(projectPath);
|
||||
if (!project) return;
|
||||
await project.listener.startListening();
|
||||
// 更新 store 中的 status
|
||||
this.projectStore.updateProject(projectPath, { status: 'active' }).catch(err => {
|
||||
console.error('[ProjectManager] updateProject status failed:', err);
|
||||
});
|
||||
console.log(`[ProjectManager] started: ${projectPath}`);
|
||||
}
|
||||
|
||||
async getProjectInfo(project: Project): Promise<ProjectInfo> {
|
||||
const { listener, ...info } = project;
|
||||
const storeDoc: ProjectDoc | null = await this.projectStore.getProject(info.path).catch(() => null);
|
||||
// 优先从 store 读取 status,确保与 store 保持一致
|
||||
let status: any = storeDoc?.status === 'active' ? 'active' : 'inactive';
|
||||
const exists = fileIsExist(info.path);
|
||||
if (!exists) {
|
||||
status = 'unlive';
|
||||
}
|
||||
return {
|
||||
...info,
|
||||
status: listener.isWatching ? "active" : "inactive",
|
||||
status,
|
||||
id: storeDoc?.id,
|
||||
title: storeDoc?.title,
|
||||
tags: storeDoc?.tags,
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import ParcelWatcher, { subscribe } from '@parcel/watcher';
|
||||
import path from 'node:path';
|
||||
import fs from 'node:fs';
|
||||
import fs, { existsSync } from 'node:fs';
|
||||
import { EventEmitter } from "eventemitter3";
|
||||
import { normalizeIgnorePattern, defaultIgnorePatterns } from '../utils';
|
||||
import { CustomError } from '@kevisual/router';
|
||||
|
||||
export class ProjectListener {
|
||||
projectPath: string;
|
||||
@@ -26,6 +27,10 @@ export class ProjectListener {
|
||||
.map(line => line.trim())
|
||||
.filter(line => line && !line.startsWith('#'));
|
||||
}
|
||||
if (!existsSync(projectPath)) {
|
||||
console.warn(`[ProjectListener] Project path does not exist: ${projectPath}`);
|
||||
throw new CustomError(`Project path does not exist: ${projectPath}`);
|
||||
}
|
||||
const allIgnore = [...defaultIgnorePatterns, ...ignorePatterns];
|
||||
const sub = await subscribe(
|
||||
this.projectPath, // 监听路径(支持数组)
|
||||
|
||||
@@ -6,7 +6,7 @@ export type ProjectDoc = {
|
||||
/**
|
||||
* 文档 ID,使用 path 的 base64url 编码
|
||||
*/
|
||||
id: string;
|
||||
id?: string;
|
||||
name?: string;
|
||||
path: string;
|
||||
/**
|
||||
@@ -23,9 +23,9 @@ export type ProjectDoc = {
|
||||
description?: string;
|
||||
link?: string;
|
||||
/**
|
||||
* 项目状态:active 活动中 | inactive 非活动
|
||||
* 项目状态:active 活动中 | inactive 非活动 | unlive 未初始化
|
||||
*/
|
||||
status?: 'active' | 'inactive';
|
||||
status?: 'active' | 'inactive' | 'unlive';
|
||||
};
|
||||
|
||||
function projectId(projectPath: string): string {
|
||||
@@ -59,8 +59,8 @@ export class ProjectStore {
|
||||
async init() {
|
||||
await this.ensureIndex();
|
||||
}
|
||||
async addProject(input: { name?: string; path: string; repo: string; status?: 'active' | 'inactive' }): Promise<void> {
|
||||
const id = projectId(input.path);
|
||||
async addProject(input: Partial<ProjectDoc>): Promise<void> {
|
||||
const id = projectId(input.path!);
|
||||
|
||||
// 先查询是否已存在
|
||||
let existingDoc: ProjectDoc | null = null;
|
||||
@@ -74,14 +74,14 @@ export class ProjectStore {
|
||||
const doc: ProjectDoc = {
|
||||
id,
|
||||
name: input.name,
|
||||
path: input.path,
|
||||
repo: input.repo,
|
||||
path: input.path!,
|
||||
repo: input.repo!,
|
||||
// 保留原有字段
|
||||
title: existingDoc?.title,
|
||||
tags: existingDoc?.tags,
|
||||
summary: existingDoc?.summary,
|
||||
description: existingDoc?.description,
|
||||
link: existingDoc?.link,
|
||||
title: input.title ?? existingDoc?.title,
|
||||
tags: input.tags ?? existingDoc?.tags,
|
||||
summary: input.summary ?? existingDoc?.summary,
|
||||
description: input.description ?? existingDoc?.description,
|
||||
link: input.link ?? existingDoc?.link,
|
||||
status: input.status ?? existingDoc?.status ?? 'active',
|
||||
};
|
||||
|
||||
@@ -109,7 +109,7 @@ export class ProjectStore {
|
||||
}
|
||||
}
|
||||
|
||||
async updateProject(projectPath: string, opts: { name?: string; repo?: string; title?: string; tags?: string[]; summary?: string; description?: string; link?: string; status?: 'active' | 'inactive' }): Promise<void> {
|
||||
async updateProject(projectPath: string, opts: { name?: string; repo?: string; title?: string; tags?: string[]; summary?: string; description?: string; link?: string; status?: 'active' | 'inactive' | 'unlive' }): Promise<void> {
|
||||
const partial: Record<string, any> = { id: projectId(projectPath) };
|
||||
if (opts.name !== undefined) partial.name = opts.name;
|
||||
if (opts.repo !== undefined) partial.repo = opts.repo;
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
import { execSync } from 'node:child_process'
|
||||
import path from 'node:path';
|
||||
|
||||
export const getGitPathname = (repoPath: string): string | null => {
|
||||
export const getPathnameFromGitUrl = (url: string): string => {
|
||||
const _url = new URL(url.replace(/\.git$/, ''));
|
||||
const pathname = _url.pathname.replace(/^\/+/, '').replace(/\/+$/, ''); // 去除开头和结尾的斜杠
|
||||
return pathname;
|
||||
}
|
||||
export const getGitPathname = (repoPath: string): { url: string, pathname: string } | null => {
|
||||
try {
|
||||
const url = execSync('git config --get remote.origin.url', { cwd: repoPath, encoding: 'utf-8' }).trim();
|
||||
if (url) {
|
||||
const _url = new URL(url.replace(/\.git$/, ''));
|
||||
const pathname = _url.pathname.replace(/^\/+/, '').replace(/\/+$/, ''); // 去除开头和结尾的斜杠
|
||||
return pathname;
|
||||
return {
|
||||
url,
|
||||
pathname: getPathnameFromGitUrl(url),
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} catch (err) {
|
||||
console.warn(`[getGitPathname] Failed to get git remote url for ${repoPath}:`);
|
||||
console.warn(`[getGitPathname] Failed to get git remote url for ${repoPath}:`, err);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
135
src/routes/project-init.ts
Normal file
135
src/routes/project-init.ts
Normal file
@@ -0,0 +1,135 @@
|
||||
import { z } from 'zod'
|
||||
import { app, manager } from '../app.ts';
|
||||
import { getGitPathname, getPathnameFromGitUrl } from '../project/util/git';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { execSync } from 'node:child_process';
|
||||
export const DEFAULT_ROOT_PATH = '/workspace/projects';
|
||||
const getProjectPaths = (ctx: any): { rootPath: string; projectPaths: string[] } => {
|
||||
const rootPath = path.resolve(ctx.query.rootPath || DEFAULT_ROOT_PATH);
|
||||
// 1. 检测文件夹是否存在
|
||||
if (!fs.existsSync(rootPath)) {
|
||||
ctx.throw(400, 'rootPath 指定的目录不存在');
|
||||
}
|
||||
// 2. 搜索第一层子目录,找到包含 .git 的目录, 如果存在把这个子目录的路径和 git 远程地址注册到系统中
|
||||
const projectPaths: string[] = [];
|
||||
|
||||
// 搜索第一层子目录中包含 .git 的目录
|
||||
try {
|
||||
const entries = fs.readdirSync(rootPath, { withFileTypes: true });
|
||||
for (const entry of entries) {
|
||||
if (!entry.isDirectory()) continue;
|
||||
const fullPath = path.join(rootPath, entry.name);
|
||||
// 跳过 node_modules 和隐藏目录
|
||||
if (entry.name === 'node_modules' || entry.name.startsWith('.')) continue;
|
||||
|
||||
// 如果包含 .git 目录,则认为是 git 项目
|
||||
if (fs.existsSync(path.join(fullPath, '.git'))) {
|
||||
projectPaths.push(fullPath);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn(`[project-init] Failed to read root directory ${rootPath}:`, err);
|
||||
}
|
||||
return {
|
||||
rootPath,
|
||||
projectPaths
|
||||
};
|
||||
}
|
||||
app.route({
|
||||
path: 'project',
|
||||
key: 'init',
|
||||
description: '初始化项目,通过root目录,搜索当前有git的项目列表,并将其注册到系统中',
|
||||
middleware: ['auth-admin'],
|
||||
metadata: {
|
||||
args: {
|
||||
rootPath: z.string().optional().describe('搜索项目的根目录绝对路径,默认为 /workspace/projects'),
|
||||
}
|
||||
}
|
||||
}).define(async (ctx) => {
|
||||
const { rootPath, projectPaths } = getProjectPaths(ctx);
|
||||
// 3. 注册项目到系统中
|
||||
const results: Array<{ path: string; repo: string | null; success: boolean; error?: string }> = [];
|
||||
|
||||
for (const projectPath of projectPaths) {
|
||||
try {
|
||||
const gitRepo = getGitPathname(projectPath);
|
||||
const repo = gitRepo?.pathname || path.basename(projectPath);
|
||||
const name = path.basename(projectPath);
|
||||
await manager.addProject({ path: projectPath, repo, name, link: gitRepo?.url });
|
||||
results.push({ path: projectPath, repo: repo, success: true });
|
||||
console.log(`[project-init] Added project: ${projectPath}, repo: ${repo}`);
|
||||
} catch (err) {
|
||||
const error = err instanceof Error ? err.message : String(err);
|
||||
results.push({ path: projectPath, repo: null, success: false, error });
|
||||
console.error(`[project-init] Failed to add project ${projectPath}:`, err);
|
||||
}
|
||||
}
|
||||
|
||||
ctx.body = {
|
||||
rootPath,
|
||||
totalFound: projectPaths.length,
|
||||
results
|
||||
};
|
||||
}).addTo(app);
|
||||
|
||||
app.route({
|
||||
path: 'project',
|
||||
key: 'list-projects',
|
||||
description: '列出当前工作区已注册的项目',
|
||||
middleware: ['auth-admin'],
|
||||
metadata: {
|
||||
args: {
|
||||
rootPath: z.string().optional().describe('项目根目录绝对路径,默认为 /workspace/projects,指定后只列出该目录下的项目'),
|
||||
}
|
||||
}
|
||||
}).define(async (ctx) => {
|
||||
const { rootPath, projectPaths } = getProjectPaths(ctx);
|
||||
ctx.body = {
|
||||
rootPath,
|
||||
list: projectPaths
|
||||
};
|
||||
}).addTo(app);
|
||||
|
||||
app.route({
|
||||
path: 'project',
|
||||
key: 'clone-cnb',
|
||||
description: 'clone 一个项目到projects目录下,并注册到系统中。',
|
||||
middleware: ['auth-admin'],
|
||||
metadata: {
|
||||
args: {
|
||||
filepath: z.string().optional().describe('新项目根目录的绝对路径,默认在 /workspace/projects 下以仓库名创建子目录'),
|
||||
repo: z.string().describe('代码仓库标识,用于搜索结果展示和过滤,格式如 owner/repo,例如 kevisual/cnb,必填'),
|
||||
}
|
||||
}
|
||||
}).define(async (ctx) => {
|
||||
const { filepath = DEFAULT_ROOT_PATH, repo = '' } = ctx.query as { filepath: string; repo?: string; };
|
||||
let cloneRepoUrl = ''
|
||||
if (repo?.startsWith('http')) {
|
||||
cloneRepoUrl = repo;
|
||||
} else if (repo) {
|
||||
cloneRepoUrl = `https://cnb.cool/${repo}`;
|
||||
} else {
|
||||
ctx.throw(400, 'repo 参数不能为空,且必须是完整的 URL 或者 owner/repo 格式');
|
||||
}
|
||||
const name = getPathnameFromGitUrl(cloneRepoUrl);
|
||||
if (!name) {
|
||||
ctx.throw(400, '无法从 repo 参数解析出项目名称,请检查 repo 格式是否正确');
|
||||
}
|
||||
const targetPath = path.join(filepath, name);
|
||||
if (fs.existsSync(targetPath)) {
|
||||
ctx.throw(400, `目标路径已存在: ${targetPath}`);
|
||||
}
|
||||
const cloneCmd = `git clone ${cloneRepoUrl} ${targetPath}`;
|
||||
try {
|
||||
console.log(`[project-clone] Cloning repo ${cloneRepoUrl} to ${targetPath}...`);
|
||||
execSync(cloneCmd, { stdio: 'inherit' });
|
||||
console.log(`[project-clone] Clone successful, adding project...`);
|
||||
const info = await manager.addProject({ path: targetPath, repo: name, name, link: cloneRepoUrl });
|
||||
ctx.body = info;
|
||||
} catch (err) {
|
||||
const error = err instanceof Error ? err.message : String(err);
|
||||
console.error(`[project-clone] Failed to clone and add project from ${cloneRepoUrl}:`, err);
|
||||
ctx.throw(500, `Failed to clone and add project: ${error}`);
|
||||
}
|
||||
}).addTo(app);
|
||||
@@ -17,22 +17,34 @@ app
|
||||
filepath: z.string().describe('项目根目录的绝对路径,必填'),
|
||||
repo: z.string().optional().describe('代码仓库标识,用于搜索结果展示和过滤,格式如 owner/repo,例如 kevisual/cnb,选填(默认自动从 git 配置读取)'),
|
||||
name: z.string().optional().describe('项目显示名称,用于搜索结果展示,选填(默认使用目录名)'),
|
||||
type: z.string().optional().describe('项目类型,filepath或cnb-repo,默认为filepath'),
|
||||
}
|
||||
}
|
||||
})
|
||||
.define(async (ctx) => {
|
||||
let { filepath, repo, name } = ctx.query as { filepath: string; repo?: string; name?: string };
|
||||
let { filepath, repo, name, type = 'filepath' } = ctx.query as { filepath: string; repo?: string; name?: string; type?: string };
|
||||
if (!filepath) ctx.throw(400, 'filepath 不能为空');
|
||||
if (type === 'cnb-repo') {
|
||||
const msg = {
|
||||
path: 'project',
|
||||
key: 'clone-cnb',
|
||||
}
|
||||
const res = await app.run({ ...msg, payload: { repo: filepath } }, { state: ctx.state });
|
||||
ctx.forward(res);
|
||||
return
|
||||
}
|
||||
let link = '';
|
||||
if (!repo) {
|
||||
const gitPathname = getGitPathname(filepath);
|
||||
if (gitPathname) {
|
||||
repo = gitPathname;
|
||||
repo = gitPathname.pathname;
|
||||
link = gitPathname.url;
|
||||
} else {
|
||||
const pathParts = filepath.split('/');
|
||||
repo = pathParts[pathParts.length - 1];
|
||||
}
|
||||
}
|
||||
const info = await manager.addProject({ path: filepath, repo, name });
|
||||
const info = await manager.addProject({ path: filepath, repo, name, link: link || (repo ? `https://cnb.cool/${repo}` : undefined) });
|
||||
ctx.body = { success: true, data: info };
|
||||
})
|
||||
.addTo(app);
|
||||
|
||||
Reference in New Issue
Block a user