mirror of
https://github.com/logancyang/obsidian-copilot.git
synced 2026-07-22 07:50:24 +00:00
Refactor Settings, add formatting (#518)
* Refactor settings components * Save setting without reload, and formatting * Add prettier config and enforce style * Make default indexing strategy ON_MODE_SWITCH * Add prettier pre-commit hook
This commit is contained in:
parent
526573f571
commit
7e499073af
18 changed files with 1171 additions and 408 deletions
3
.husky/pre-commit
Normal file
3
.husky/pre-commit
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# .husky/pre-commit
|
||||
prettier $(git diff --cached --name-only --diff-filter=ACMR | sed 's| |\\ |g') --write --ignore-unknown
|
||||
git update-index --again
|
||||
8
.prettierrc
Normal file
8
.prettierrc
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"endOfLine": "lf",
|
||||
"printWidth": 100,
|
||||
"tabWidth": 2,
|
||||
"semi": true,
|
||||
"singleQuote": false,
|
||||
"trailingComma": "es5"
|
||||
}
|
||||
|
|
@ -44,8 +44,12 @@ In the case of Copilot for Obsidian, you will need to:
|
|||
1. Fork the repo.
|
||||
2. Create a vault just for development.
|
||||
3. Clone the forked repo into your vault's `plugins` folder.
|
||||
4. Run `npm run dev` in your repo to see the effect of your changes.
|
||||
5. When you are ready to make a pull request, ensure to make your changes in **a branch on your fork**, and then submit a pull request to the **main repo**.
|
||||
4. Run `npm install` to install all dependencies.
|
||||
5. Install the recommended VS Code extensions (Prettier and ESLint).
|
||||
6. Ensure your editor respects the `.editorconfig` and Prettier settings.
|
||||
7. Run `npm run dev` in your repo to see the effect of your changes.
|
||||
8. Before committing, run `npm run format` to ensure all files are properly formatted.
|
||||
9. When you are ready to make a pull request, ensure to make your changes in **a branch on your fork**, and then submit a pull request to the **main repo**.
|
||||
|
||||
Try to be descriptive in your branch names and pull requests. Happy coding!
|
||||
|
||||
|
|
@ -55,4 +59,3 @@ Try to be descriptive in your branch names and pull requests. Happy coding!
|
|||
- **Email**: logan@brevilabs.com
|
||||
|
||||
Thank you for contributing to Copilot for Obsidian!
|
||||
|
||||
|
|
|
|||
713
package-lock.json
generated
713
package-lock.json
generated
|
|
@ -53,8 +53,10 @@
|
|||
"electron": "^27.3.2",
|
||||
"esbuild": "0.17.3",
|
||||
"eslint": "^8.57.0",
|
||||
"husky": "^9.1.5",
|
||||
"jest": "^29.7.0",
|
||||
"jest-environment-jsdom": "^29.5.0",
|
||||
"lint-staged": "^15.2.9",
|
||||
"obsidian": "latest",
|
||||
"prettier": "^3.3.3",
|
||||
"ts-jest": "^29.1.0",
|
||||
|
|
@ -4347,6 +4349,87 @@
|
|||
"integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/cli-cursor": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz",
|
||||
"integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"restore-cursor": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/cli-truncate": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz",
|
||||
"integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"slice-ansi": "^5.0.0",
|
||||
"string-width": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/cli-truncate/node_modules/ansi-regex": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
|
||||
"integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-regex?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/cli-truncate/node_modules/emoji-regex": {
|
||||
"version": "10.3.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz",
|
||||
"integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/cli-truncate/node_modules/string-width": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
|
||||
"integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"emoji-regex": "^10.3.0",
|
||||
"get-east-asian-width": "^1.0.0",
|
||||
"strip-ansi": "^7.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/cli-truncate/node_modules/strip-ansi": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
|
||||
"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-regex": "^6.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/strip-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/client-only": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
|
||||
|
|
@ -4432,6 +4515,12 @@
|
|||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/colorette": {
|
||||
"version": "2.0.20",
|
||||
"resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz",
|
||||
"integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
|
|
@ -4681,9 +4770,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"version": "4.3.6",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz",
|
||||
"integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==",
|
||||
"dependencies": {
|
||||
"ms": "2.1.2"
|
||||
},
|
||||
|
|
@ -5154,6 +5243,18 @@
|
|||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/environment": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz",
|
||||
"integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/errno": {
|
||||
"version": "0.1.8",
|
||||
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz",
|
||||
|
|
@ -6036,6 +6137,18 @@
|
|||
"node": "6.* || 8.* || >= 10.*"
|
||||
}
|
||||
},
|
||||
"node_modules/get-east-asian-width": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz",
|
||||
"integrity": "sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/get-intrinsic": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
|
||||
|
|
@ -6544,6 +6657,21 @@
|
|||
"ms": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/husky": {
|
||||
"version": "9.1.5",
|
||||
"resolved": "https://registry.npmjs.org/husky/-/husky-9.1.5.tgz",
|
||||
"integrity": "sha512-rowAVRUBfI0b4+niA4SJMhfQwc107VLkBUgEYYAOQAbqDCnra1nYh83hF/MDmhYs9t9n1E3DuKOrs2LYNC+0Ag==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"husky": "bin.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/typicode"
|
||||
}
|
||||
},
|
||||
"node_modules/i18next": {
|
||||
"version": "22.4.15",
|
||||
"resolved": "https://registry.npmjs.org/i18next/-/i18next-22.4.15.tgz",
|
||||
|
|
@ -8970,12 +9098,308 @@
|
|||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lilconfig": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz",
|
||||
"integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antonk52"
|
||||
}
|
||||
},
|
||||
"node_modules/lines-and-columns": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
|
||||
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/lint-staged": {
|
||||
"version": "15.2.9",
|
||||
"resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.9.tgz",
|
||||
"integrity": "sha512-BZAt8Lk3sEnxw7tfxM7jeZlPRuT4M68O0/CwZhhaw6eeWu0Lz5eERE3m386InivXB64fp/mDID452h48tvKlRQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"chalk": "~5.3.0",
|
||||
"commander": "~12.1.0",
|
||||
"debug": "~4.3.6",
|
||||
"execa": "~8.0.1",
|
||||
"lilconfig": "~3.1.2",
|
||||
"listr2": "~8.2.4",
|
||||
"micromatch": "~4.0.7",
|
||||
"pidtree": "~0.6.0",
|
||||
"string-argv": "~0.3.2",
|
||||
"yaml": "~2.5.0"
|
||||
},
|
||||
"bin": {
|
||||
"lint-staged": "bin/lint-staged.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.12.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/lint-staged"
|
||||
}
|
||||
},
|
||||
"node_modules/lint-staged/node_modules/chalk": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz",
|
||||
"integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^12.17.0 || ^14.13 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/lint-staged/node_modules/commander": {
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz",
|
||||
"integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/lint-staged/node_modules/execa": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz",
|
||||
"integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"cross-spawn": "^7.0.3",
|
||||
"get-stream": "^8.0.1",
|
||||
"human-signals": "^5.0.0",
|
||||
"is-stream": "^3.0.0",
|
||||
"merge-stream": "^2.0.0",
|
||||
"npm-run-path": "^5.1.0",
|
||||
"onetime": "^6.0.0",
|
||||
"signal-exit": "^4.1.0",
|
||||
"strip-final-newline": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.17"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sindresorhus/execa?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/lint-staged/node_modules/get-stream": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz",
|
||||
"integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/lint-staged/node_modules/human-signals": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz",
|
||||
"integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=16.17.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lint-staged/node_modules/is-stream": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz",
|
||||
"integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/lint-staged/node_modules/mimic-fn": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
|
||||
"integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/lint-staged/node_modules/npm-run-path": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz",
|
||||
"integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"path-key": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/lint-staged/node_modules/onetime": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz",
|
||||
"integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"mimic-fn": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/lint-staged/node_modules/path-key": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
|
||||
"integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/lint-staged/node_modules/signal-exit": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
|
||||
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/lint-staged/node_modules/strip-final-newline": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz",
|
||||
"integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/listr2": {
|
||||
"version": "8.2.4",
|
||||
"resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.4.tgz",
|
||||
"integrity": "sha512-opevsywziHd3zHCVQGAj8zu+Z3yHNkkoYhWIGnq54RrCVwLz0MozotJEDnKsIBLvkfLGN6BLOyAeRrYI0pKA4g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"cli-truncate": "^4.0.0",
|
||||
"colorette": "^2.0.20",
|
||||
"eventemitter3": "^5.0.1",
|
||||
"log-update": "^6.1.0",
|
||||
"rfdc": "^1.4.1",
|
||||
"wrap-ansi": "^9.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/listr2/node_modules/ansi-regex": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
|
||||
"integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-regex?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/listr2/node_modules/ansi-styles": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
|
||||
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/listr2/node_modules/emoji-regex": {
|
||||
"version": "10.3.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz",
|
||||
"integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/listr2/node_modules/eventemitter3": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
|
||||
"integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/listr2/node_modules/string-width": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
|
||||
"integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"emoji-regex": "^10.3.0",
|
||||
"get-east-asian-width": "^1.0.0",
|
||||
"strip-ansi": "^7.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/listr2/node_modules/strip-ansi": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
|
||||
"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-regex": "^6.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/strip-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/listr2/node_modules/wrap-ansi": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz",
|
||||
"integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-styles": "^6.2.1",
|
||||
"string-width": "^7.0.0",
|
||||
"strip-ansi": "^7.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/locate-path": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
||||
|
|
@ -9009,6 +9433,150 @@
|
|||
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/log-update": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz",
|
||||
"integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-escapes": "^7.0.0",
|
||||
"cli-cursor": "^5.0.0",
|
||||
"slice-ansi": "^7.1.0",
|
||||
"strip-ansi": "^7.1.0",
|
||||
"wrap-ansi": "^9.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/log-update/node_modules/ansi-escapes": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz",
|
||||
"integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"environment": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/log-update/node_modules/ansi-regex": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
|
||||
"integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-regex?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/log-update/node_modules/ansi-styles": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
|
||||
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/log-update/node_modules/emoji-regex": {
|
||||
"version": "10.3.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz",
|
||||
"integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/log-update/node_modules/is-fullwidth-code-point": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz",
|
||||
"integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"get-east-asian-width": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/log-update/node_modules/slice-ansi": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz",
|
||||
"integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-styles": "^6.2.1",
|
||||
"is-fullwidth-code-point": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/slice-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/log-update/node_modules/string-width": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
|
||||
"integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"emoji-regex": "^10.3.0",
|
||||
"get-east-asian-width": "^1.0.0",
|
||||
"strip-ansi": "^7.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/log-update/node_modules/strip-ansi": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
|
||||
"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-regex": "^6.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/strip-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/log-update/node_modules/wrap-ansi": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz",
|
||||
"integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-styles": "^6.2.1",
|
||||
"string-width": "^7.0.0",
|
||||
"strip-ansi": "^7.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
|
|
@ -9642,12 +10210,12 @@
|
|||
]
|
||||
},
|
||||
"node_modules/micromatch": {
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
|
||||
"integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
|
||||
"version": "4.0.7",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz",
|
||||
"integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"braces": "^3.0.2",
|
||||
"braces": "^3.0.3",
|
||||
"picomatch": "^2.3.1"
|
||||
},
|
||||
"engines": {
|
||||
|
|
@ -9682,6 +10250,18 @@
|
|||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/mimic-function": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz",
|
||||
"integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/mimic-response": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz",
|
||||
|
|
@ -10469,6 +11049,18 @@
|
|||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/pidtree": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz",
|
||||
"integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"pidtree": "bin/pidtree.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/pirates": {
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz",
|
||||
|
|
@ -11148,6 +11740,49 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/restore-cursor": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz",
|
||||
"integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"onetime": "^7.0.0",
|
||||
"signal-exit": "^4.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/restore-cursor/node_modules/onetime": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz",
|
||||
"integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"mimic-function": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/restore-cursor/node_modules/signal-exit": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
|
||||
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/retry": {
|
||||
"version": "0.13.1",
|
||||
"resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz",
|
||||
|
|
@ -11166,6 +11801,12 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/rfdc": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
|
||||
"integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/rimraf": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
||||
|
|
@ -11415,6 +12056,46 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/slice-ansi": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz",
|
||||
"integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-styles": "^6.0.0",
|
||||
"is-fullwidth-code-point": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/slice-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/slice-ansi/node_modules/ansi-styles": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
|
||||
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/slice-ansi/node_modules/is-fullwidth-code-point": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz",
|
||||
"integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
|
|
@ -11529,6 +12210,15 @@
|
|||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
|
||||
"integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ=="
|
||||
},
|
||||
"node_modules/string-argv": {
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz",
|
||||
"integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.6.19"
|
||||
}
|
||||
},
|
||||
"node_modules/string-length": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz",
|
||||
|
|
@ -12499,9 +13189,12 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/yaml": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz",
|
||||
"integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==",
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.0.tgz",
|
||||
"integrity": "sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==",
|
||||
"bin": {
|
||||
"yaml": "bin.mjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
|
|
|
|||
20
package.json
20
package.json
|
|
@ -8,11 +8,25 @@
|
|||
"build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production",
|
||||
"lint": "eslint . --ext .js,.jsx,.ts,.tsx",
|
||||
"lint:fix": "eslint . --ext .js,.jsx,.ts,.tsx --fix",
|
||||
"format": "prettier --write .",
|
||||
"format:check": "prettier --check .",
|
||||
"version": "node version-bump.mjs && git add manifest.json versions.json",
|
||||
"test": "jest"
|
||||
"test": "jest",
|
||||
"prepare": "husky"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"author": "Logan Yang",
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged"
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,jsx,ts,tsx,json,css,md}": [
|
||||
"prettier --write",
|
||||
"git add"
|
||||
]
|
||||
},
|
||||
"license": "AGPL-3.0",
|
||||
"devDependencies": {
|
||||
"@testing-library/jest-dom": "^5.16.5",
|
||||
|
|
@ -32,8 +46,10 @@
|
|||
"electron": "^27.3.2",
|
||||
"esbuild": "0.17.3",
|
||||
"eslint": "^8.57.0",
|
||||
"husky": "^9.1.5",
|
||||
"jest": "^29.7.0",
|
||||
"jest-environment-jsdom": "^29.5.0",
|
||||
"lint-staged": "^15.2.9",
|
||||
"obsidian": "latest",
|
||||
"prettier": "^3.3.3",
|
||||
"ts-jest": "^29.1.0",
|
||||
|
|
|
|||
|
|
@ -52,9 +52,7 @@ export const GOOGLE_MODELS = new Set([
|
|||
|
||||
export const ANTHROPIC_MODELS = new Set([ChatModelDisplayNames.CLAUDE]);
|
||||
|
||||
export const OPENROUTERAI_MODELS = new Set([
|
||||
ChatModelDisplayNames.OPENROUTERAI,
|
||||
]);
|
||||
export const OPENROUTERAI_MODELS = new Set([ChatModelDisplayNames.OPENROUTERAI]);
|
||||
|
||||
export const OLLAMA_MODELS = new Set([ChatModelDisplayNames.OLLAMA]);
|
||||
|
||||
|
|
@ -198,7 +196,7 @@ export const DEFAULT_SETTINGS: CopilotSettings = {
|
|||
lmStudioBaseUrl: "http://localhost:1234/v1",
|
||||
stream: true,
|
||||
defaultSaveFolder: "copilot-conversations",
|
||||
indexVaultToVectorStore: VAULT_VECTOR_STORE_STRATEGY.NEVER,
|
||||
indexVaultToVectorStore: VAULT_VECTOR_STORE_STRATEGY.ON_MODE_SWITCH,
|
||||
qaExclusionPaths: "",
|
||||
chatNoteContextPath: "",
|
||||
chatNoteContextTags: [],
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import CopilotPlugin from "@/main";
|
||||
import { App, Notice, PluginSettingTab, Setting } from "obsidian";
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import SettingsMain from "./components/SettingsMain";
|
||||
import { SettingsProvider } from "./contexts/SettingsContext";
|
||||
|
||||
export interface CopilotSettings {
|
||||
openAIApiKey: string;
|
||||
|
|
@ -29,7 +30,7 @@ export interface CopilotSettings {
|
|||
contextTurns: number;
|
||||
userSystemPrompt: string;
|
||||
openAIProxyBaseUrl: string;
|
||||
useOpenAILocalProxy: boolean
|
||||
useOpenAILocalProxy: boolean;
|
||||
openAIProxyModelName: string;
|
||||
openAIEmbeddingProxyBaseUrl: string;
|
||||
openAIEmbeddingProxyModelName: string;
|
||||
|
|
@ -47,7 +48,7 @@ export interface CopilotSettings {
|
|||
qaExclusionPaths: string;
|
||||
groqModel: string;
|
||||
groqApiKey: string;
|
||||
enabledCommands: Record<string, { enabled: boolean; name: string; }>;
|
||||
enabledCommands: Record<string, { enabled: boolean; name: string }>;
|
||||
}
|
||||
|
||||
export class CopilotSettingTab extends PluginSettingTab {
|
||||
|
|
@ -65,31 +66,33 @@ export class CopilotSettingTab extends PluginSettingTab {
|
|||
|
||||
// Reload the plugin
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const app = (this.plugin.app as any);
|
||||
const app = this.plugin.app as any;
|
||||
await app.plugins.disablePlugin("copilot");
|
||||
await app.plugins.enablePlugin("copilot");
|
||||
|
||||
app.setting.openTabById("copilot").display();
|
||||
new Notice('Plugin reloaded successfully.');
|
||||
new Notice("Plugin reloaded successfully.");
|
||||
} catch (error) {
|
||||
new Notice('Failed to reload the plugin. Please reload manually.');
|
||||
console.error('Error reloading plugin:', error);
|
||||
new Notice("Failed to reload the plugin. Please reload manually.");
|
||||
console.error("Error reloading plugin:", error);
|
||||
}
|
||||
}
|
||||
|
||||
display(): void {
|
||||
const { containerEl } = this;
|
||||
containerEl.empty();
|
||||
containerEl.style.userSelect = 'text';
|
||||
const div = containerEl.createDiv("div")
|
||||
containerEl.style.userSelect = "text";
|
||||
const div = containerEl.createDiv("div");
|
||||
const sections = createRoot(div);
|
||||
|
||||
sections.render(
|
||||
<SettingsMain plugin={this.plugin} reloadPlugin={this.reloadPlugin.bind(this)} />
|
||||
<SettingsProvider plugin={this.plugin} reloadPlugin={this.reloadPlugin.bind(this)}>
|
||||
<SettingsMain plugin={this.plugin} reloadPlugin={this.reloadPlugin.bind(this)} />
|
||||
</SettingsProvider>
|
||||
);
|
||||
|
||||
const devModeHeader = containerEl.createEl('h1', { text: 'Additional Settings' });
|
||||
devModeHeader.style.marginTop = '40px';
|
||||
const devModeHeader = containerEl.createEl("h1", { text: "Additional Settings" });
|
||||
devModeHeader.style.marginTop = "40px";
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Enable Encryption")
|
||||
|
|
@ -98,9 +101,8 @@ export class CopilotSettingTab extends PluginSettingTab {
|
|||
frag.appendText("Enable encryption for the API keys.");
|
||||
})
|
||||
)
|
||||
.addToggle(toggle => toggle
|
||||
.setValue(this.plugin.settings.enableEncryption)
|
||||
.onChange(async (value) => {
|
||||
.addToggle((toggle) =>
|
||||
toggle.setValue(this.plugin.settings.enableEncryption).onChange(async (value) => {
|
||||
this.plugin.settings.enableEncryption = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
|
|
@ -113,9 +115,8 @@ export class CopilotSettingTab extends PluginSettingTab {
|
|||
frag.appendText("Debug mode will log all API requests and prompts to the console.");
|
||||
})
|
||||
)
|
||||
.addToggle(toggle => toggle
|
||||
.setValue(this.plugin.settings.debug)
|
||||
.onChange(async (value) => {
|
||||
.addToggle((toggle) =>
|
||||
toggle.setValue(this.plugin.settings.debug).onChange(async (value) => {
|
||||
this.plugin.settings.debug = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,9 +1,5 @@
|
|||
import React from 'react';
|
||||
import {
|
||||
TextAreaComponent,
|
||||
TextComponent,
|
||||
ToggleComponent,
|
||||
} from './SettingBlocks';
|
||||
import React from "react";
|
||||
import { TextAreaComponent, TextComponent, ToggleComponent } from "./SettingBlocks";
|
||||
|
||||
interface AdvancedSettingsProps {
|
||||
openAIProxyBaseUrl: string;
|
||||
|
|
@ -40,7 +36,8 @@ const AdvancedSettings: React.FC<AdvancedSettingsProps> = ({
|
|||
<br />
|
||||
<h1>Advanced Settings</h1>
|
||||
<div className="warning-message">
|
||||
OpenAI Proxy settings override the default OpenAI parameters, meaning now your OpenAI models are routed to this provider instead! Clear these fields to use OpenAI again.
|
||||
OpenAI Proxy settings override the default OpenAI parameters, meaning now your OpenAI models
|
||||
are routed to this provider instead! Clear these fields to use OpenAI again.
|
||||
<br />
|
||||
This is in effect only when you pick any OpenAI model in the model dropdown.
|
||||
<br />
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import { TextComponent } from './SettingBlocks';
|
||||
import React from "react";
|
||||
import { TextComponent } from "./SettingBlocks";
|
||||
|
||||
const ApiSetting: React.FC<{
|
||||
title: string;
|
||||
|
|
@ -17,8 +17,8 @@ const ApiSetting: React.FC<{
|
|||
value={value}
|
||||
// @ts-ignore
|
||||
onChange={setValue}
|
||||
placeholder={placeholder || ''}
|
||||
type={type || 'password'}
|
||||
placeholder={placeholder || ""}
|
||||
type={type || "password"}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { DEFAULT_SETTINGS } from "@/constants";
|
||||
import React from 'react';
|
||||
import ApiSetting from './ApiSetting';
|
||||
import Collapsible from './Collapsible';
|
||||
import React from "react";
|
||||
import ApiSetting from "./ApiSetting";
|
||||
import Collapsible from "./Collapsible";
|
||||
|
||||
interface ApiSettingsProps {
|
||||
openAIApiKey: string;
|
||||
|
|
@ -77,13 +77,12 @@ const ApiSettings: React.FC<ApiSettingsProps> = ({
|
|||
<br />
|
||||
<br />
|
||||
<h1>API Settings</h1>
|
||||
<p>
|
||||
All your API keys are stored locally.
|
||||
</p>
|
||||
<p>All your API keys are stored locally.</p>
|
||||
<div className="warning-message">
|
||||
Make sure you have access to the model and the correct API key.
|
||||
<br />
|
||||
If errors occur, please re-enter the API key, save and reload the plugin to see if it resolves the issue.
|
||||
If errors occur, please re-enter the API key, save and reload the plugin to see if it
|
||||
resolves the issue.
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
|
|
@ -94,8 +93,12 @@ const ApiSettings: React.FC<ApiSettingsProps> = ({
|
|||
placeholder="Enter OpenAI API Key"
|
||||
/>
|
||||
<p>
|
||||
You can find your API key at{' '}
|
||||
<a href="https://platform.openai.com/api-keys" target="_blank" rel="noopener noreferrer">
|
||||
You can find your API key at{" "}
|
||||
<a
|
||||
href="https://platform.openai.com/api-keys"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
https://platform.openai.com/api-keys
|
||||
</a>
|
||||
</p>
|
||||
|
|
@ -116,7 +119,11 @@ const ApiSettings: React.FC<ApiSettingsProps> = ({
|
|||
</div>
|
||||
<div className="warning-message">
|
||||
<span>If you are a new user, try </span>
|
||||
<a href="https://platform.openai.com/playground?mode=chat" target="_blank" rel="noopener noreferrer">
|
||||
<a
|
||||
href="https://platform.openai.com/playground?mode=chat"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
OpenAI playground
|
||||
</a>
|
||||
<span> to see if you have correct API access first.</span>
|
||||
|
|
@ -132,10 +139,15 @@ const ApiSettings: React.FC<ApiSettingsProps> = ({
|
|||
placeholder="Enter Google API Key"
|
||||
/>
|
||||
<p>
|
||||
If you have Google Cloud, you can get Gemini API key {' '}
|
||||
<a href="https://makersuite.google.com/app/apikey" target="_blank" rel="noopener noreferrer">
|
||||
If you have Google Cloud, you can get Gemini API key{" "}
|
||||
<a
|
||||
href="https://makersuite.google.com/app/apikey"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
here
|
||||
</a>.
|
||||
</a>
|
||||
.
|
||||
<br />
|
||||
Your API key is stored locally and is only used to make requests to Google's services.
|
||||
</p>
|
||||
|
|
@ -167,12 +179,18 @@ const ApiSettings: React.FC<ApiSettingsProps> = ({
|
|||
type="text"
|
||||
/>
|
||||
<p>
|
||||
If you have Anthropic API access, you can get the API key {' '}
|
||||
<a href="https://console.anthropic.com/settings/keys" target="_blank" rel="noopener noreferrer">
|
||||
If you have Anthropic API access, you can get the API key{" "}
|
||||
<a
|
||||
href="https://console.anthropic.com/settings/keys"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
here
|
||||
</a>.
|
||||
</a>
|
||||
.
|
||||
<br />
|
||||
Your API key is stored locally and is only used to make requests to Anthropic's services.
|
||||
Your API key is stored locally and is only used to make requests to Anthropic's
|
||||
services.
|
||||
</p>
|
||||
</div>
|
||||
</Collapsible>
|
||||
|
|
@ -194,14 +212,17 @@ const ApiSettings: React.FC<ApiSettingsProps> = ({
|
|||
type="text"
|
||||
/>
|
||||
<p>
|
||||
You can get your OpenRouterAI key {' '}
|
||||
You can get your OpenRouterAI key{" "}
|
||||
<a href="https://openrouter.ai/keys" target="_blank" rel="noopener noreferrer">
|
||||
here
|
||||
</a>.
|
||||
</a>
|
||||
.
|
||||
<br />
|
||||
Find models <a href="https://openrouter.ai/models" target="_blank" rel="noopener noreferrer">
|
||||
Find models{" "}
|
||||
<a href="https://openrouter.ai/models" target="_blank" rel="noopener noreferrer">
|
||||
here
|
||||
</a>.
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
</div>
|
||||
</Collapsible>
|
||||
|
|
@ -263,10 +284,11 @@ const ApiSettings: React.FC<ApiSettingsProps> = ({
|
|||
type="text"
|
||||
/>
|
||||
<p>
|
||||
If you have Groq API access, you can get the API key {' '}
|
||||
If you have Groq API access, you can get the API key{" "}
|
||||
<a href="https://console.groq.com/keys" target="_blank" rel="noopener noreferrer">
|
||||
here
|
||||
</a>.
|
||||
</a>
|
||||
.
|
||||
<br />
|
||||
Your API key is stored locally and is only used to make requests to Groq's services.
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { ReactNode, useState } from 'react';
|
||||
import React, { ReactNode, useState } from "react";
|
||||
|
||||
interface CollapsibleProps {
|
||||
title: ReactNode;
|
||||
|
|
@ -9,44 +9,60 @@ const Collapsible: React.FC<CollapsibleProps> = ({ title, children }) => {
|
|||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const titleStyle = {
|
||||
fontWeight: 'bold',
|
||||
cursor: 'pointer',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
marginBottom: '10px',
|
||||
borderRadius: '5px',
|
||||
fontWeight: "bold",
|
||||
cursor: "pointer",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
marginBottom: "10px",
|
||||
borderRadius: "5px",
|
||||
};
|
||||
|
||||
const contentStyle = {
|
||||
padding: '10px 10px',
|
||||
borderRadius: '8px',
|
||||
marginTop: '10px',
|
||||
padding: "10px 10px",
|
||||
borderRadius: "8px",
|
||||
marginTop: "10px",
|
||||
};
|
||||
|
||||
const ChevronDown = () => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
<polyline points="6 9 12 15 18 9"></polyline>
|
||||
</svg>
|
||||
);
|
||||
|
||||
const ChevronRight = () => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
<polyline points="9 18 15 12 9 6"></polyline>
|
||||
</svg>
|
||||
);
|
||||
|
||||
return (
|
||||
<div style={{ padding: '20px' }}>
|
||||
<div style={{ padding: "20px" }}>
|
||||
<div style={titleStyle} onClick={() => setIsOpen(!isOpen)}>
|
||||
{title}
|
||||
{isOpen ? <ChevronDown /> : <ChevronRight />}
|
||||
</div>
|
||||
{isOpen && (
|
||||
<div style={contentStyle}>
|
||||
{children}
|
||||
</div>
|
||||
)}
|
||||
{isOpen && <div style={contentStyle}>{children}</div>}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useState } from 'react';
|
||||
import { ToggleComponent } from './SettingBlocks';
|
||||
import React, { useState } from "react";
|
||||
import { ToggleComponent } from "./SettingBlocks";
|
||||
|
||||
interface CommandToggleSettingsProps {
|
||||
enabledCommands: Record<string, { enabled: boolean; name: string }>;
|
||||
|
|
@ -15,14 +15,14 @@ const CommandToggleSettings: React.FC<CommandToggleSettingsProps> = ({
|
|||
const toggleCommand = (commandId: string, enabled: boolean) => {
|
||||
setEnabledCommands({
|
||||
...enabledCommands,
|
||||
[commandId]: { ...enabledCommands[commandId], enabled }
|
||||
[commandId]: { ...enabledCommands[commandId], enabled },
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2 onClick={() => setIsExpanded(!isExpanded)} style={{ cursor: 'pointer' }}>
|
||||
Command Settings {isExpanded ? '▼' : '▶'}
|
||||
<h2 onClick={() => setIsExpanded(!isExpanded)} style={{ cursor: "pointer" }}>
|
||||
Command Settings {isExpanded ? "▼" : "▶"}
|
||||
</h2>
|
||||
{isExpanded && (
|
||||
<div>
|
||||
|
|
|
|||
75
src/settings/components/GeneralSettings.tsx
Normal file
75
src/settings/components/GeneralSettings.tsx
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
import { ChatModelDisplayNames } from "@/constants";
|
||||
import React from "react";
|
||||
import { useSettingsContext } from "../contexts/SettingsContext";
|
||||
import CommandToggleSettings from "./CommandToggleSettings";
|
||||
import { DropdownComponent, SliderComponent, TextComponent } from "./SettingBlocks";
|
||||
|
||||
const GeneralSettings: React.FC = () => {
|
||||
const { settings, updateSettings } = useSettingsContext();
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2>General Settings</h2>
|
||||
<DropdownComponent
|
||||
name="Default Model"
|
||||
options={Object.values(ChatModelDisplayNames)}
|
||||
value={settings.defaultModelDisplayName}
|
||||
onChange={(value) => updateSettings({ defaultModelDisplayName: value })}
|
||||
/>
|
||||
<TextComponent
|
||||
name="Default Conversation Folder Name"
|
||||
description="The default folder name where chat conversations will be saved. Default is 'copilot-conversations'"
|
||||
placeholder="copilot-conversations"
|
||||
value={settings.defaultSaveFolder}
|
||||
onChange={(value) => updateSettings({ defaultSaveFolder: value })}
|
||||
/>
|
||||
<h6>
|
||||
Please be mindful of the number of tokens and context conversation turns you set here, as
|
||||
they will affect the cost of your API requests.
|
||||
</h6>
|
||||
<SliderComponent
|
||||
name="Temperature"
|
||||
description="Default is 0.1. Higher values will result in more creativeness, but also more mistakes. Set to 0 for no randomness."
|
||||
min={0}
|
||||
max={2}
|
||||
step={0.05}
|
||||
value={settings.temperature}
|
||||
onChange={(value) => updateSettings({ temperature: value })}
|
||||
/>
|
||||
<SliderComponent
|
||||
name="Token limit"
|
||||
description={
|
||||
<>
|
||||
<p>
|
||||
The maximum number of <em>output tokens</em> to generate. Default is 1000.
|
||||
</p>
|
||||
<em>
|
||||
This number plus the length of your prompt (input tokens) must be smaller than the
|
||||
context window of the model.
|
||||
</em>
|
||||
</>
|
||||
}
|
||||
min={0}
|
||||
max={16000}
|
||||
step={100}
|
||||
value={settings.maxTokens}
|
||||
onChange={(value) => updateSettings({ maxTokens: value })}
|
||||
/>
|
||||
<SliderComponent
|
||||
name="Conversation turns in context"
|
||||
description="The number of previous conversation turns to include in the context. Default is 15 turns, i.e. 30 messages."
|
||||
min={1}
|
||||
max={50}
|
||||
step={1}
|
||||
value={settings.contextTurns}
|
||||
onChange={(value) => updateSettings({ contextTurns: value })}
|
||||
/>
|
||||
<CommandToggleSettings
|
||||
enabledCommands={settings.enabledCommands}
|
||||
setEnabledCommands={(value) => updateSettings({ enabledCommands: value })}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default GeneralSettings;
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import { TextComponent } from './SettingBlocks';
|
||||
import React from "react";
|
||||
import { TextComponent } from "./SettingBlocks";
|
||||
|
||||
interface LocalCopilotSettingsProps {
|
||||
lmStudioBaseUrl: string;
|
||||
|
|
@ -20,18 +20,23 @@ const LocalCopilotSettings: React.FC<LocalCopilotSettingsProps> = ({
|
|||
}) => {
|
||||
return (
|
||||
<div>
|
||||
<br/>
|
||||
<br />
|
||||
<h1>Local Copilot (No Internet Required!)</h1>
|
||||
<div className="warning-message">
|
||||
Please check the doc to set up LM Studio or Ollama server on your device.
|
||||
</div>
|
||||
<p>
|
||||
Local models can be limited in capabilities and may not work for some use cases at this time. Keep in mind that it is still in early experimental phase. But some 13B even 7B models are already quite capable!
|
||||
Local models can be limited in capabilities and may not work for some use cases at this
|
||||
time. Keep in mind that it is still in early experimental phase. But some 13B even 7B models
|
||||
are already quite capable!
|
||||
</p>
|
||||
<h3>LM Studio</h3>
|
||||
<p>
|
||||
To use Local Copilot with LM Studio:<br />
|
||||
1. Start LM Studio server with CORS on. Default port is 1234 but if you change it, you can provide it below.<br />
|
||||
To use Local Copilot with LM Studio:
|
||||
<br />
|
||||
1. Start LM Studio server with CORS on. Default port is 1234 but if you change it, you can
|
||||
provide it below.
|
||||
<br />
|
||||
2. Pick LM Studio in the Copilot Chat model selection dropdown to chat with it!
|
||||
</p>
|
||||
<TextComponent
|
||||
|
|
@ -42,9 +47,13 @@ const LocalCopilotSettings: React.FC<LocalCopilotSettingsProps> = ({
|
|||
placeholder="http://localhost:1234/v1"
|
||||
/>
|
||||
<h3>Ollama</h3>
|
||||
<p>To use Local Copilot with Ollama, pick Ollama in the Copilot Chat model selection dropdown.</p>
|
||||
<p>
|
||||
To use Local Copilot with Ollama, pick Ollama in the Copilot Chat model selection dropdown.
|
||||
</p>
|
||||
<p>Run the local Ollama server by running this in your terminal:</p>
|
||||
<p><strong>OLLAMA_ORIGINS=app://obsidian.md* ollama serve</strong></p>
|
||||
<p>
|
||||
<strong>OLLAMA_ORIGINS=app://obsidian.md* ollama serve</strong>
|
||||
</p>
|
||||
<TextComponent
|
||||
name="Ollama model"
|
||||
description="Default is llama2 (7b)."
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { EmbeddingModels, VAULT_VECTOR_STORE_STRATEGIES } from '@/constants';
|
||||
import React from 'react';
|
||||
import ApiSetting from './ApiSetting';
|
||||
import Collapsible from './Collapsible';
|
||||
import { DropdownComponent, SliderComponent } from './SettingBlocks';
|
||||
import { EmbeddingModels, VAULT_VECTOR_STORE_STRATEGIES } from "@/constants";
|
||||
import React from "react";
|
||||
import ApiSetting from "./ApiSetting";
|
||||
import Collapsible from "./Collapsible";
|
||||
import { DropdownComponent, SliderComponent } from "./SettingBlocks";
|
||||
|
||||
interface QASettingsProps {
|
||||
embeddingModel: string;
|
||||
|
|
@ -35,13 +35,26 @@ const QASettings: React.FC<QASettingsProps> = ({
|
|||
<br />
|
||||
<h1>QA Settings</h1>
|
||||
<div className="warning-message">
|
||||
Vault QA is in BETA and may not be stable. If you have issues please report in the github repo.
|
||||
Vault QA is in BETA and may not be stable. If you have issues please report in the github
|
||||
repo.
|
||||
</div>
|
||||
<p>QA mode relies a <em>local</em> vector index.</p>
|
||||
<p>
|
||||
QA mode relies a <em>local</em> vector index.
|
||||
</p>
|
||||
<h2>Long Note QA vs. Vault QA (BETA)</h2>
|
||||
<p>Long Note QA mode uses the Active Note as context. Vault QA (BETA) uses your entire vault as context. Please ask questions as specific as possible, avoid vague questions to get better results.</p>
|
||||
<p>
|
||||
Long Note QA mode uses the Active Note as context. Vault QA (BETA) uses your entire vault as
|
||||
context. Please ask questions as specific as possible, avoid vague questions to get better
|
||||
results.
|
||||
</p>
|
||||
<h2>Local Embedding Model</h2>
|
||||
<p>Check the <a href='https://github.com/logancyang/obsidian-copilot/blob/master/local_copilot.md'>local copilot</a> setup guide to setup Ollama's local embedding model (requires Ollama v0.1.26 or above).</p>
|
||||
<p>
|
||||
Check the{" "}
|
||||
<a href="https://github.com/logancyang/obsidian-copilot/blob/master/local_copilot.md">
|
||||
local copilot
|
||||
</a>{" "}
|
||||
setup guide to setup Ollama's local embedding model (requires Ollama v0.1.26 or above).
|
||||
</p>
|
||||
<DropdownComponent
|
||||
name="Embedding Models"
|
||||
description="The embedding API/model to use"
|
||||
|
|
@ -54,9 +67,11 @@ const QASettings: React.FC<QASettingsProps> = ({
|
|||
If you are using a paid embedding provider, beware of costs for large vaults!
|
||||
</div>
|
||||
<p>
|
||||
When you switch to <strong>Long Note QA</strong> mode, your active note is indexed automatically upon mode switch.
|
||||
When you switch to <strong>Long Note QA</strong> mode, your active note is indexed
|
||||
automatically upon mode switch.
|
||||
<br />
|
||||
When you switch to <strong>Vault QA</strong> mode, your vault is indexed <em>based on the auto-index strategy you select below</em>.
|
||||
When you switch to <strong>Vault QA</strong> mode, your vault is indexed{" "}
|
||||
<em>based on the auto-index strategy you select below</em>.
|
||||
<br />
|
||||
</p>
|
||||
<DropdownComponent
|
||||
|
|
@ -68,14 +83,26 @@ const QASettings: React.FC<QASettingsProps> = ({
|
|||
/>
|
||||
<br />
|
||||
<p>
|
||||
<strong>NEVER</strong>: Notes are never indexed to the vector store unless users run the command <em>Index vault for QA</em> explicitly, or hit the <em>Refresh Index</em> button.
|
||||
<br /><br />
|
||||
<strong>NEVER</strong>: Notes are never indexed to the vector store unless users run the
|
||||
command <em>Index vault for QA</em> explicitly, or hit the <em>Refresh Index</em> button.
|
||||
<br />
|
||||
<br />
|
||||
<strong>ON STARTUP</strong>: Vault index is refreshed on plugin load/reload.
|
||||
<br /><br />
|
||||
<strong>ON MODE SWITCH (Recommended)</strong>: Vault index is refreshed when switching to Vault QA mode.
|
||||
<br /><br />
|
||||
By "refreshed", it means the vault index is not rebuilt from scratch but rather updated incrementally with new/modified notes since the last index. If you need a complete rebuild, run the commands "Clear vector store" and "Force re-index for QA" manually. This helps reduce costs when using paid embedding models.<br /><br />
|
||||
Beware of the cost if you are using a paid embedding model and have a large vault! You can run Copilot command <em>Count total tokens in your vault</em> and refer to your selected embedding model pricing to estimate indexing costs.
|
||||
<br />
|
||||
<br />
|
||||
<strong>ON MODE SWITCH (Recommended)</strong>: Vault index is refreshed when switching to
|
||||
Vault QA mode.
|
||||
<br />
|
||||
<br />
|
||||
By "refreshed", it means the vault index is not rebuilt from scratch but rather updated
|
||||
incrementally with new/modified notes since the last index. If you need a complete rebuild,
|
||||
run the commands "Clear vector store" and "Force re-index for QA" manually. This helps
|
||||
reduce costs when using paid embedding models.
|
||||
<br />
|
||||
<br />
|
||||
Beware of the cost if you are using a paid embedding model and have a large vault! You can
|
||||
run Copilot command <em>Count total tokens in your vault</em> and refer to your selected
|
||||
embedding model pricing to estimate indexing costs.
|
||||
</p>
|
||||
<br />
|
||||
<SliderComponent
|
||||
|
|
@ -98,12 +125,8 @@ const QASettings: React.FC<QASettingsProps> = ({
|
|||
placeholder="Enter Cohere API Key"
|
||||
/>
|
||||
<p>
|
||||
Get your free Cohere API key{' '}
|
||||
<a
|
||||
href="https://dashboard.cohere.ai/api-keys"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
Get your free Cohere API key{" "}
|
||||
<a href="https://dashboard.cohere.ai/api-keys" target="_blank" rel="noreferrer">
|
||||
here
|
||||
</a>
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React from 'react';
|
||||
import React from "react";
|
||||
|
||||
type DropdownComponentProps = {
|
||||
name: string;
|
||||
|
|
@ -40,9 +40,15 @@ type ToggleComponentProps = {
|
|||
description?: string;
|
||||
value: boolean;
|
||||
onChange: (value: boolean) => void;
|
||||
}
|
||||
};
|
||||
|
||||
const DropdownComponent: React.FC<DropdownComponentProps> = ({ name, description, options, value, onChange }) => {
|
||||
const DropdownComponent: React.FC<DropdownComponentProps> = ({
|
||||
name,
|
||||
description,
|
||||
options,
|
||||
value,
|
||||
onChange,
|
||||
}) => {
|
||||
return (
|
||||
<div className="copilot-setting-item">
|
||||
<div className="copilot-setting-item-name">{name}</div>
|
||||
|
|
@ -62,13 +68,20 @@ const DropdownComponent: React.FC<DropdownComponentProps> = ({ name, description
|
|||
);
|
||||
};
|
||||
|
||||
const TextComponent: React.FC<TextComponentProps> = ({ name, description, placeholder, value, type, onChange }) => {
|
||||
const TextComponent: React.FC<TextComponentProps> = ({
|
||||
name,
|
||||
description,
|
||||
placeholder,
|
||||
value,
|
||||
type,
|
||||
onChange,
|
||||
}) => {
|
||||
return (
|
||||
<div className="copilot-setting-item">
|
||||
<div className="copilot-setting-item-name">{name}</div>
|
||||
<div className="copilot-setting-item-description">{description}</div>
|
||||
<input
|
||||
type={type || 'text'}
|
||||
type={type || "text"}
|
||||
className="copilot-setting-item-control"
|
||||
placeholder={placeholder}
|
||||
value={value}
|
||||
|
|
@ -78,7 +91,13 @@ const TextComponent: React.FC<TextComponentProps> = ({ name, description, placeh
|
|||
);
|
||||
};
|
||||
|
||||
const TextAreaComponent: React.FC<TextAreaComponentProps> = ({ name, description, placeholder, value, onChange }) => {
|
||||
const TextAreaComponent: React.FC<TextAreaComponentProps> = ({
|
||||
name,
|
||||
description,
|
||||
placeholder,
|
||||
value,
|
||||
onChange,
|
||||
}) => {
|
||||
return (
|
||||
<div className="copilot-setting-item">
|
||||
<div className="copilot-setting-item-name">{name}</div>
|
||||
|
|
@ -93,13 +112,20 @@ const TextAreaComponent: React.FC<TextAreaComponentProps> = ({ name, description
|
|||
);
|
||||
};
|
||||
|
||||
|
||||
const SliderComponent: React.FC<SliderComponentProps> = ({ name, description, min, max, step, value, onChange }) => {
|
||||
const SliderComponent: React.FC<SliderComponentProps> = ({
|
||||
name,
|
||||
description,
|
||||
min,
|
||||
max,
|
||||
step,
|
||||
value,
|
||||
onChange,
|
||||
}) => {
|
||||
return (
|
||||
<div className="copilot-setting-item">
|
||||
<div className="copilot-setting-item-name">{name}</div>
|
||||
<div className="copilot-setting-item-description">{description}</div>
|
||||
<div style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<div style={{ display: "flex", alignItems: "center" }}>
|
||||
<input
|
||||
type="range"
|
||||
className="copilot-setting-item-control"
|
||||
|
|
@ -109,23 +135,28 @@ const SliderComponent: React.FC<SliderComponentProps> = ({ name, description, mi
|
|||
value={value}
|
||||
onChange={(e) => onChange(parseFloat(e.target.value))}
|
||||
/>
|
||||
<span style={{ marginLeft: '20px', fontWeight: 'bold', color: 'var(--inline-title-color)' }}>{value}</span>
|
||||
<span
|
||||
style={{ marginLeft: "20px", fontWeight: "bold", color: "var(--inline-title-color)" }}
|
||||
>
|
||||
{value}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const ToggleComponent: React.FC<ToggleComponentProps> = ({ name, description, value, onChange }) => {
|
||||
const ToggleComponent: React.FC<ToggleComponentProps> = ({
|
||||
name,
|
||||
description,
|
||||
value,
|
||||
onChange,
|
||||
}) => {
|
||||
return (
|
||||
<div className="copilot-setting-item">
|
||||
<div className="copilot-setting-item-name">{name}</div>
|
||||
<div className="copilot-setting-item-description">{description}</div>
|
||||
<label className="switch">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={value}
|
||||
onChange={(e) => onChange(e.target.checked)}
|
||||
/>
|
||||
<input type="checkbox" checked={value} onChange={(e) => onChange(e.target.checked)} />
|
||||
<span className="slider round"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
|
@ -133,4 +164,3 @@ const ToggleComponent: React.FC<ToggleComponentProps> = ({ name, description, va
|
|||
};
|
||||
|
||||
export { DropdownComponent, SliderComponent, TextAreaComponent, TextComponent, ToggleComponent };
|
||||
|
||||
|
|
|
|||
|
|
@ -1,279 +1,88 @@
|
|||
import CopilotPlugin from "@/main";
|
||||
import { Notice } from 'obsidian';
|
||||
import React, { Fragment, useState } from 'react';
|
||||
import { ChatModelDisplayNames, DEFAULT_SETTINGS, DISPLAY_NAME_TO_MODEL } from '../../constants';
|
||||
import AdvancedSettings from './AdvancedSettings';
|
||||
import ApiSettings from './ApiSettings';
|
||||
import CommandToggleSettings from './CommandToggleSettings';
|
||||
import LocalCopilotSettings from './LocalCopilotSettings';
|
||||
import QASettings from './QASettings';
|
||||
import { DropdownComponent, SliderComponent, TextComponent } from './SettingBlocks';
|
||||
import React from "react";
|
||||
import { useSettingsContext } from "../contexts/SettingsContext";
|
||||
import AdvancedSettings from "./AdvancedSettings";
|
||||
import ApiSettings from "./ApiSettings";
|
||||
import GeneralSettings from "./GeneralSettings";
|
||||
import LocalCopilotSettings from "./LocalCopilotSettings";
|
||||
import QASettings from "./QASettings";
|
||||
|
||||
interface SettingsMainProps {
|
||||
plugin: CopilotPlugin;
|
||||
reloadPlugin: () => Promise<void>;
|
||||
}
|
||||
|
||||
export default function SettingsMain({ plugin, reloadPlugin }: SettingsMainProps) {
|
||||
const [defaultModelDisplayName, setDefaultModelDisplayName] = useState(plugin.settings.defaultModelDisplayName);
|
||||
const [defaultSaveFolder, setDefaultSaveFolder] = useState(plugin.settings.defaultSaveFolder);
|
||||
const [temperature, setTemperature] = useState(plugin.settings.temperature);
|
||||
const [maxTokens, setMaxTokens] = useState(plugin.settings.maxTokens);
|
||||
const [contextTurns, setContextTurns] = useState(plugin.settings.contextTurns);
|
||||
|
||||
// API settings
|
||||
const [openAIApiKey, setOpenAIApiKey] = useState(plugin.settings.openAIApiKey);
|
||||
const [openAIOrgId, setOpenAIOrgId] = useState(plugin.settings.openAIOrgId);
|
||||
const [openAICustomModel, setOpenAICustomModel] = useState(plugin.settings.openAICustomModel);
|
||||
|
||||
const [googleApiKey, setGoogleApiKey] = useState(plugin.settings.googleApiKey);
|
||||
const [googleCustomModel, setGoogleCustomModel] = useState(plugin.settings.googleCustomModel);
|
||||
|
||||
const [anthropicApiKey, setAnthropicApiKey] = useState(plugin.settings.anthropicApiKey);
|
||||
const [anthropicModel, setAnthropicModel] = useState(plugin.settings.anthropicModel);
|
||||
|
||||
const [openRouterAiApiKey, setOpenRouterAiApiKey] = useState(plugin.settings.openRouterAiApiKey);
|
||||
const [openRouterModel, setOpenRouterModel] = useState(plugin.settings.openRouterModel);
|
||||
|
||||
const [azureOpenAIApiKey, setAzureOpenAIApiKey] = useState(plugin.settings.azureOpenAIApiKey);
|
||||
const [azureOpenAIApiInstanceName, setAzureOpenAIApiInstanceName] = useState(plugin.settings.azureOpenAIApiInstanceName);
|
||||
const [azureOpenAIApiDeploymentName, setAzureOpenAIApiDeploymentName] = useState(plugin.settings.azureOpenAIApiDeploymentName);
|
||||
const [azureOpenAIApiVersion, setAzureOpenAIApiVersion] = useState(plugin.settings.azureOpenAIApiVersion);
|
||||
const [azureOpenAIApiEmbeddingDeploymentName, setAzureOpenAIApiEmbeddingDeploymentName] = useState(plugin.settings.azureOpenAIApiEmbeddingDeploymentName);
|
||||
|
||||
const [groqApiKey, setGroqApiKey] = useState(plugin.settings.groqApiKey);
|
||||
const [groqModel, setGroqModel] = useState(plugin.settings.groqModel);
|
||||
|
||||
// QA settings
|
||||
const [embeddingModel, setEmbeddingModel] = useState(plugin.settings.embeddingModel);
|
||||
const [cohereApiKey, setCohereApiKey] = useState(plugin.settings.cohereApiKey);
|
||||
const [huggingfaceApiKey, setHuggingfaceApiKey] = useState(plugin.settings.huggingfaceApiKey);
|
||||
const [indexVaultToVectorStore, setIndexVaultToVectorStore] = useState(plugin.settings.indexVaultToVectorStore);
|
||||
const [maxSourceChunks, setMaxSourceChunks] = useState(plugin.settings.maxSourceChunks);
|
||||
|
||||
// Advanced settings
|
||||
const [userSystemPrompt, setUserSystemPrompt] = useState(plugin.settings.userSystemPrompt);
|
||||
const [openAIProxyBaseUrl, setOpenAIProxyBaseUrl] = useState(plugin.settings.openAIProxyBaseUrl);
|
||||
const [useOpenAILocalProxy, setUseOpenAILocalProxy] = useState(plugin.settings.useOpenAILocalProxy);
|
||||
const [openAIProxyModelName, setOpenAIProxyModelName] = useState(plugin.settings.openAIProxyModelName);
|
||||
const [openAIEmbeddingProxyBaseUrl, setOpenAIEmbeddingProxyBaseUrl] = useState(plugin.settings.openAIEmbeddingProxyBaseUrl);
|
||||
const [openAIEmbeddingProxyModelName, setOpenAIEmbeddingProxyModelName] = useState(plugin.settings.openAIEmbeddingProxyModelName);
|
||||
|
||||
// Local Copilot Settings
|
||||
const [lmStudioBaseUrl, setlmStudioBaseUrl] = useState(plugin.settings.lmStudioBaseUrl);
|
||||
const [ollamaModel, setOllamaModel] = useState(plugin.settings.ollamaModel);
|
||||
const [ollamaBaseUrl, setOllamaBaseUrl] = useState(plugin.settings.ollamaBaseUrl);
|
||||
|
||||
// Built-in Command Toggles
|
||||
const [enabledCommands, setEnabledCommands] = useState(plugin.settings.enabledCommands);
|
||||
|
||||
// NOTE: When new settings are added, make sure to add them to saveAllSettings
|
||||
const saveAllSettings = async () => {
|
||||
plugin.settings.defaultModelDisplayName = defaultModelDisplayName;
|
||||
plugin.settings.defaultModel = DISPLAY_NAME_TO_MODEL[defaultModelDisplayName];
|
||||
plugin.settings.defaultSaveFolder = defaultSaveFolder;
|
||||
plugin.settings.temperature = temperature;
|
||||
plugin.settings.maxTokens = maxTokens;
|
||||
plugin.settings.contextTurns = contextTurns;
|
||||
|
||||
// API settings
|
||||
plugin.settings.openAIApiKey = openAIApiKey;
|
||||
plugin.settings.openAIOrgId = openAIOrgId;
|
||||
plugin.settings.openAICustomModel = openAICustomModel;
|
||||
|
||||
plugin.settings.googleApiKey = googleApiKey;
|
||||
plugin.settings.googleCustomModel = googleCustomModel;
|
||||
|
||||
plugin.settings.anthropicApiKey = anthropicApiKey;
|
||||
plugin.settings.anthropicModel = anthropicModel;
|
||||
plugin.settings.openRouterAiApiKey = openRouterAiApiKey;
|
||||
plugin.settings.openRouterModel = openRouterModel;
|
||||
plugin.settings.azureOpenAIApiKey = azureOpenAIApiKey;
|
||||
plugin.settings.azureOpenAIApiInstanceName = azureOpenAIApiInstanceName;
|
||||
plugin.settings.azureOpenAIApiDeploymentName = azureOpenAIApiDeploymentName;
|
||||
plugin.settings.azureOpenAIApiVersion = azureOpenAIApiVersion;
|
||||
plugin.settings.azureOpenAIApiEmbeddingDeploymentName = azureOpenAIApiEmbeddingDeploymentName;
|
||||
plugin.settings.groqApiKey = groqApiKey;
|
||||
plugin.settings.groqModel = groqModel;
|
||||
|
||||
// QA settings
|
||||
plugin.settings.embeddingModel = embeddingModel;
|
||||
plugin.settings.cohereApiKey = cohereApiKey;
|
||||
plugin.settings.huggingfaceApiKey = huggingfaceApiKey;
|
||||
plugin.settings.indexVaultToVectorStore = indexVaultToVectorStore;
|
||||
plugin.settings.maxSourceChunks = maxSourceChunks;
|
||||
|
||||
// Advanced settings
|
||||
plugin.settings.userSystemPrompt = userSystemPrompt;
|
||||
plugin.settings.openAIProxyBaseUrl = openAIProxyBaseUrl;
|
||||
plugin.settings.useOpenAILocalProxy = useOpenAILocalProxy;
|
||||
plugin.settings.openAIProxyModelName = openAIProxyModelName;
|
||||
plugin.settings.openAIEmbeddingProxyBaseUrl = openAIEmbeddingProxyBaseUrl;
|
||||
plugin.settings.openAIEmbeddingProxyModelName = openAIEmbeddingProxyModelName;
|
||||
|
||||
// Local Copilot Settings
|
||||
plugin.settings.lmStudioBaseUrl = lmStudioBaseUrl;
|
||||
plugin.settings.ollamaModel = ollamaModel;
|
||||
plugin.settings.ollamaBaseUrl = ollamaBaseUrl;
|
||||
|
||||
plugin.settings.enabledCommands = enabledCommands;
|
||||
|
||||
await plugin.saveSettings();
|
||||
await reloadPlugin();
|
||||
new Notice('Settings have been saved and the plugin has been reloaded.');
|
||||
};
|
||||
|
||||
const resetToDefaultSettings = async () => {
|
||||
plugin.settings = DEFAULT_SETTINGS;
|
||||
await plugin.saveSettings();
|
||||
await reloadPlugin();
|
||||
new Notice('Settings have been reset to their default values.');
|
||||
};
|
||||
const SettingsMain: React.FC<{ plugin: CopilotPlugin; reloadPlugin: () => Promise<void> }> = ({
|
||||
plugin,
|
||||
reloadPlugin,
|
||||
}) => {
|
||||
const { settings, updateSettings, saveSettings, resetSettings } = useSettingsContext();
|
||||
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
<h2>Copilot Settings</h2>
|
||||
<div className="button-container">
|
||||
<button className="mod-cta" onClick={saveAllSettings}>
|
||||
Save and Reload
|
||||
</button>
|
||||
<button className="mod-cta" onClick={resetToDefaultSettings}>
|
||||
Reset to Default Settings
|
||||
</button>
|
||||
</div>
|
||||
<div className="warning-message">
|
||||
Please Save and Reload the plugin when you change any setting below!
|
||||
</div>
|
||||
|
||||
<DropdownComponent
|
||||
name="Default Model"
|
||||
options={Object.values(ChatModelDisplayNames)}
|
||||
value={defaultModelDisplayName}
|
||||
onChange={setDefaultModelDisplayName}
|
||||
/>
|
||||
<TextComponent
|
||||
name="Default Conversation Folder Name"
|
||||
description="The default folder name where chat conversations will be saved. Default is 'copilot-conversations'"
|
||||
placeholder="copilot-conversations"
|
||||
value={defaultSaveFolder}
|
||||
onChange={setDefaultSaveFolder}
|
||||
/>
|
||||
<h6>
|
||||
Please be mindful of the number of tokens and context conversation turns you set here, as they will affect the cost of your API requests.
|
||||
</h6>
|
||||
<SliderComponent
|
||||
name="Temperature"
|
||||
description="Default is 0.1. Higher values will result in more creativeness, but also more mistakes. Set to 0 for no randomness."
|
||||
min={0}
|
||||
max={2}
|
||||
step={0.05}
|
||||
value={temperature}
|
||||
onChange={async (value) => {
|
||||
setTemperature(value);
|
||||
}}
|
||||
/>
|
||||
<SliderComponent
|
||||
name="Token limit"
|
||||
description={
|
||||
<Fragment>
|
||||
<p>The maximum number of <em>output tokens</em> to generate. Default is 1000.</p>
|
||||
<em>This number plus the length of your prompt (input tokens) must be smaller than the context window of the model.</em>
|
||||
</Fragment>
|
||||
}
|
||||
min={0}
|
||||
max={10000}
|
||||
step={100}
|
||||
value={maxTokens}
|
||||
onChange={async (value) => {
|
||||
setMaxTokens(value);
|
||||
}}
|
||||
/>
|
||||
<SliderComponent
|
||||
name="Conversation turns in context"
|
||||
description="The number of previous conversation turns to include in the context. Default is 15 turns, i.e. 30 messages."
|
||||
min={1}
|
||||
max={30}
|
||||
step={1}
|
||||
value={contextTurns}
|
||||
onChange={async (value) => {
|
||||
setContextTurns(value);
|
||||
}}
|
||||
/>
|
||||
<CommandToggleSettings
|
||||
enabledCommands={enabledCommands}
|
||||
setEnabledCommands={setEnabledCommands}
|
||||
/>
|
||||
<h2>Copilot Settings</h2>
|
||||
<div className="button-container">
|
||||
<button className="mod-cta" onClick={saveSettings}>
|
||||
Save and Reload
|
||||
</button>
|
||||
<button className="mod-cta" onClick={resetSettings}>
|
||||
Reset to Default Settings
|
||||
</button>
|
||||
</div>
|
||||
<div className="warning-message">
|
||||
Please Save and Reload the plugin when you change any setting below!
|
||||
</div>
|
||||
|
||||
<GeneralSettings />
|
||||
<ApiSettings
|
||||
openAIApiKey={openAIApiKey}
|
||||
setOpenAIApiKey={setOpenAIApiKey}
|
||||
openAIOrgId={openAIOrgId}
|
||||
setOpenAIOrgId={setOpenAIOrgId}
|
||||
openAICustomModel={openAICustomModel}
|
||||
setOpenAICustomModel={setOpenAICustomModel}
|
||||
googleApiKey={googleApiKey}
|
||||
setGoogleApiKey={setGoogleApiKey}
|
||||
googleCustomModel={googleCustomModel}
|
||||
setGoogleCustomModel={setGoogleCustomModel}
|
||||
anthropicApiKey={anthropicApiKey}
|
||||
setAnthropicApiKey={setAnthropicApiKey}
|
||||
anthropicModel={anthropicModel}
|
||||
setAnthropicModel={setAnthropicModel}
|
||||
openRouterAiApiKey={openRouterAiApiKey}
|
||||
setOpenRouterAiApiKey={setOpenRouterAiApiKey}
|
||||
openRouterModel={openRouterModel}
|
||||
setOpenRouterModel={setOpenRouterModel}
|
||||
azureOpenAIApiKey={azureOpenAIApiKey}
|
||||
setAzureOpenAIApiKey={setAzureOpenAIApiKey}
|
||||
azureOpenAIApiInstanceName={azureOpenAIApiInstanceName}
|
||||
setAzureOpenAIApiInstanceName={setAzureOpenAIApiInstanceName}
|
||||
azureOpenAIApiDeploymentName={azureOpenAIApiDeploymentName}
|
||||
setAzureOpenAIApiDeploymentName={setAzureOpenAIApiDeploymentName}
|
||||
azureOpenAIApiVersion={azureOpenAIApiVersion}
|
||||
setAzureOpenAIApiVersion={setAzureOpenAIApiVersion}
|
||||
azureOpenAIApiEmbeddingDeploymentName={azureOpenAIApiEmbeddingDeploymentName}
|
||||
setAzureOpenAIApiEmbeddingDeploymentName={setAzureOpenAIApiEmbeddingDeploymentName}
|
||||
groqApiKey={groqApiKey}
|
||||
setGroqApiKey={setGroqApiKey}
|
||||
groqModel={groqModel}
|
||||
setGroqModel={setGroqModel}
|
||||
{...settings}
|
||||
setOpenAIApiKey={(value) => updateSettings({ openAIApiKey: value })}
|
||||
setOpenAIOrgId={(value) => updateSettings({ openAIOrgId: value })}
|
||||
setOpenAICustomModel={(value) => updateSettings({ openAICustomModel: value })}
|
||||
setGoogleApiKey={(value) => updateSettings({ googleApiKey: value })}
|
||||
setGoogleCustomModel={(value) => updateSettings({ googleCustomModel: value })}
|
||||
setAnthropicApiKey={(value) => updateSettings({ anthropicApiKey: value })}
|
||||
setAnthropicModel={(value) => updateSettings({ anthropicModel: value })}
|
||||
setOpenRouterAiApiKey={(value) => updateSettings({ openRouterAiApiKey: value })}
|
||||
setOpenRouterModel={(value) => updateSettings({ openRouterModel: value })}
|
||||
setAzureOpenAIApiKey={(value) => updateSettings({ azureOpenAIApiKey: value })}
|
||||
setAzureOpenAIApiInstanceName={(value) =>
|
||||
updateSettings({ azureOpenAIApiInstanceName: value })
|
||||
}
|
||||
setAzureOpenAIApiDeploymentName={(value) =>
|
||||
updateSettings({ azureOpenAIApiDeploymentName: value })
|
||||
}
|
||||
setAzureOpenAIApiVersion={(value) => updateSettings({ azureOpenAIApiVersion: value })}
|
||||
setAzureOpenAIApiEmbeddingDeploymentName={(value) =>
|
||||
updateSettings({ azureOpenAIApiEmbeddingDeploymentName: value })
|
||||
}
|
||||
setGroqApiKey={(value) => updateSettings({ groqApiKey: value })}
|
||||
setGroqModel={(value) => updateSettings({ groqModel: value })}
|
||||
/>
|
||||
<QASettings
|
||||
embeddingModel={embeddingModel}
|
||||
setEmbeddingModel={setEmbeddingModel}
|
||||
cohereApiKey={cohereApiKey}
|
||||
setCohereApiKey={setCohereApiKey}
|
||||
huggingfaceApiKey={huggingfaceApiKey}
|
||||
setHuggingfaceApiKey={setHuggingfaceApiKey}
|
||||
indexVaultToVectorStore={indexVaultToVectorStore}
|
||||
setIndexVaultToVectorStore={setIndexVaultToVectorStore}
|
||||
maxSourceChunks={maxSourceChunks}
|
||||
setMaxSourceChunks={setMaxSourceChunks}
|
||||
{...settings}
|
||||
setEmbeddingModel={(value) => updateSettings({ embeddingModel: value })}
|
||||
setCohereApiKey={(value) => updateSettings({ cohereApiKey: value })}
|
||||
setHuggingfaceApiKey={(value) => updateSettings({ huggingfaceApiKey: value })}
|
||||
setIndexVaultToVectorStore={(value) => updateSettings({ indexVaultToVectorStore: value })}
|
||||
setMaxSourceChunks={(value) => updateSettings({ maxSourceChunks: value })}
|
||||
/>
|
||||
<AdvancedSettings
|
||||
openAIProxyBaseUrl={openAIProxyBaseUrl}
|
||||
setOpenAIProxyBaseUrl={setOpenAIProxyBaseUrl}
|
||||
useOpenAILocalProxy={useOpenAILocalProxy}
|
||||
setUseOpenAILocalProxy={setUseOpenAILocalProxy}
|
||||
openAIProxyModelName={openAIProxyModelName}
|
||||
setOpenAIProxyModelName={setOpenAIProxyModelName}
|
||||
openAIEmbeddingProxyBaseUrl={openAIEmbeddingProxyBaseUrl}
|
||||
setOpenAIEmbeddingProxyBaseUrl={setOpenAIEmbeddingProxyBaseUrl}
|
||||
openAIEmbeddingProxyModelName={openAIEmbeddingProxyModelName}
|
||||
setOpenAIEmbeddingProxyModelName={setOpenAIEmbeddingProxyModelName}
|
||||
userSystemPrompt={userSystemPrompt}
|
||||
setUserSystemPrompt={setUserSystemPrompt}
|
||||
{...settings}
|
||||
setOpenAIProxyBaseUrl={(value) => updateSettings({ openAIProxyBaseUrl: value })}
|
||||
setUseOpenAILocalProxy={(value) => updateSettings({ useOpenAILocalProxy: value })}
|
||||
setOpenAIProxyModelName={(value) => updateSettings({ openAIProxyModelName: value })}
|
||||
setOpenAIEmbeddingProxyBaseUrl={(value) =>
|
||||
updateSettings({ openAIEmbeddingProxyBaseUrl: value })
|
||||
}
|
||||
setOpenAIEmbeddingProxyModelName={(value) =>
|
||||
updateSettings({ openAIEmbeddingProxyModelName: value })
|
||||
}
|
||||
setUserSystemPrompt={(value) => updateSettings({ userSystemPrompt: value })}
|
||||
/>
|
||||
<LocalCopilotSettings
|
||||
lmStudioBaseUrl={lmStudioBaseUrl}
|
||||
setlmStudioBaseUrl={setlmStudioBaseUrl}
|
||||
ollamaModel={ollamaModel}
|
||||
setOllamaModel={setOllamaModel}
|
||||
ollamaBaseUrl={ollamaBaseUrl}
|
||||
setOllamaBaseUrl={setOllamaBaseUrl}
|
||||
{...settings}
|
||||
setlmStudioBaseUrl={(value) => updateSettings({ lmStudioBaseUrl: value })}
|
||||
setOllamaModel={(value) => updateSettings({ ollamaModel: value })}
|
||||
setOllamaBaseUrl={(value) => updateSettings({ ollamaBaseUrl: value })}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default React.memo(SettingsMain);
|
||||
|
|
|
|||
60
src/settings/contexts/SettingsContext.tsx
Normal file
60
src/settings/contexts/SettingsContext.tsx
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
import { DEFAULT_SETTINGS } from "@/constants";
|
||||
import CopilotPlugin from "@/main";
|
||||
import { CopilotSettings } from "@/settings/SettingsPage";
|
||||
import React, { createContext, useCallback, useContext, useState } from "react";
|
||||
|
||||
interface SettingsContextType {
|
||||
settings: CopilotSettings;
|
||||
updateSettings: (newSettings: Partial<CopilotSettings>) => void;
|
||||
saveSettings: () => Promise<void>;
|
||||
resetSettings: () => Promise<void>;
|
||||
reloadPlugin: () => Promise<void>;
|
||||
}
|
||||
|
||||
const SettingsContext = createContext<SettingsContextType | undefined>(undefined);
|
||||
|
||||
export const SettingsProvider: React.FC<{
|
||||
plugin: CopilotPlugin;
|
||||
reloadPlugin: () => Promise<void>;
|
||||
children: React.ReactNode;
|
||||
}> = ({ plugin, reloadPlugin, children }) => {
|
||||
const [settings, setSettings] = useState<CopilotSettings>(plugin.settings);
|
||||
|
||||
const updateSettings = useCallback(
|
||||
async (newSettings: Partial<CopilotSettings>) => {
|
||||
const updatedSettings = { ...settings, ...newSettings };
|
||||
setSettings(updatedSettings);
|
||||
plugin.settings = updatedSettings;
|
||||
await plugin.saveSettings();
|
||||
},
|
||||
[plugin, settings]
|
||||
);
|
||||
|
||||
const saveSettings = useCallback(async () => {
|
||||
await plugin.saveSettings();
|
||||
await reloadPlugin();
|
||||
}, [plugin, reloadPlugin]);
|
||||
|
||||
const resetSettings = useCallback(async () => {
|
||||
plugin.settings = DEFAULT_SETTINGS;
|
||||
setSettings(DEFAULT_SETTINGS);
|
||||
await plugin.saveSettings();
|
||||
await reloadPlugin();
|
||||
}, [plugin]);
|
||||
|
||||
return (
|
||||
<SettingsContext.Provider
|
||||
value={{ settings, updateSettings, saveSettings, resetSettings, reloadPlugin }}
|
||||
>
|
||||
{children}
|
||||
</SettingsContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useSettingsContext = () => {
|
||||
const context = useContext(SettingsContext);
|
||||
if (context === undefined) {
|
||||
throw new Error("useSettingsContext must be used within a SettingsProvider");
|
||||
}
|
||||
return context;
|
||||
};
|
||||
Loading…
Reference in a new issue