├── .github └── workflows │ └── release.yml ├── .gitignore ├── LICENSE ├── README.md ├── main.ts ├── manifest.json ├── package.json ├── rollup.config.js ├── src ├── SettingsTab.ts ├── context.ts ├── notices.ts ├── openrouter.ts ├── types.ts ├── ui │ ├── SettingsItemView.tsx │ └── StopSequenceInput.tsx └── util.ts ├── tsconfig.json ├── versions.json └── yarn.lock /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release Obsidian Plugin 2 | on: 3 | push: 4 | # Sequence of patterns matched against refs/tags 5 | tags: 6 | - "*" # Push events to matching any tag format, i.e. 1.0, 20.15.10 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | with: 13 | fetch-depth: 0 # otherwise, you will failed to push refs to dest repo 14 | - name: Use Node.js 15 | uses: actions/setup-node@v1 16 | with: 17 | node-version: "14.x" # You might need to adjust this value to your own version 18 | # Get the version number and put it in a variable 19 | - name: Get Version 20 | id: version 21 | run: | 22 | echo "::set-output name=tag::$(git describe --abbrev=0)" 23 | # Build the plugin 24 | - name: Build 25 | id: build 26 | run: | 27 | npm install 28 | npm run build --if-present 29 | # Package the required files into a zip 30 | - name: Package 31 | run: | 32 | mkdir ${{ github.event.repository.name }} 33 | cp main.js manifest.json README.md ${{ github.event.repository.name }} 34 | zip -r ${{ github.event.repository.name }}.zip ${{ github.event.repository.name }} 35 | # Create the release on github 36 | - name: Create Release 37 | id: create_release 38 | uses: actions/create-release@v1 39 | env: 40 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 41 | VERSION: ${{ github.ref }} 42 | with: 43 | tag_name: ${{ github.ref }} 44 | release_name: ${{ github.ref }} 45 | draft: false 46 | prerelease: false 47 | # Upload the packaged release file 48 | - name: Upload zip file 49 | id: upload-zip 50 | uses: actions/upload-release-asset@v1 51 | env: 52 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 53 | with: 54 | upload_url: ${{ steps.create_release.outputs.upload_url }} 55 | asset_path: ./${{ github.event.repository.name }}.zip 56 | asset_name: ${{ github.event.repository.name }}-${{ steps.version.outputs.tag }}.zip 57 | asset_content_type: application/zip 58 | # Upload the main.js 59 | - name: Upload main.js 60 | id: upload-main 61 | uses: actions/upload-release-asset@v1 62 | env: 63 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 64 | with: 65 | upload_url: ${{ steps.create_release.outputs.upload_url }} 66 | asset_path: ./main.js 67 | asset_name: main.js 68 | asset_content_type: text/javascript 69 | # Upload the manifest.json 70 | - name: Upload manifest.json 71 | id: upload-manifest 72 | uses: actions/upload-release-asset@v1 73 | env: 74 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 75 | with: 76 | upload_url: ${{ steps.create_release.outputs.upload_url }} 77 | asset_path: ./manifest.json 78 | asset_name: manifest.json 79 | asset_content_type: application/json 80 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Intellij 2 | *.iml 3 | .idea 4 | 5 | # npm 6 | node_modules 7 | package-lock.json 8 | 9 | # build 10 | main.js 11 | *.js.map 12 | 13 | # obsidian 14 | data.json 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright 2022 Jonathan Miller 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Obsidian GPT 2 | 3 | "Obsidian plugin for getting language model completions from [Openrouter](https://openrouter.ai). Use any supported model, including ChatGPT, Claude, LLaMa, and more. 4 | 5 | ## Setup 6 | 7 | Acquire an API key from [Openrouter](https://openrouter.ai). Open the plugin settings and paste in your API key. 8 | 9 | 10 | ## Usage 11 | 12 | Command `Get Completion` will get a completion for either the current selection if text is selected, or for the current line if no text is selected. The completion will be pasted where the cursor is. 13 | 14 | Model settings can be tuned in the settings panel in the right-hand side pane. Command `Show Model Settings` will open the model settings pane in a leaf on the right-hand sidebar. 15 | 16 | ## Usage Warning 17 | 18 | Please note, AI text completion is unpredictable and should be used responsibly. Text generated via AI text completion should have a disclaimer that it is AI generated if published anywhere. There is also no way to ensure the content will be appropriate, so please use with caution. -------------------------------------------------------------------------------- /main.ts: -------------------------------------------------------------------------------- 1 | import { Editor, Plugin, WorkspaceLeaf } from "obsidian"; 2 | import { 3 | gettingCompletionNotice, 4 | errorGettingCompletionNotice, 5 | } from "src/notices"; 6 | import { getCompletion, refetchModels } from "src/openrouter"; 7 | import GPTSettingTab from "src/SettingsTab"; 8 | import { 9 | CurrentLineContents, 10 | DEFAULT_SETTINGS, 11 | GPTPluginSettings, 12 | ORRequest, 13 | VIEW_TYPE_MODEL_SETTINGS, 14 | } from "src/types"; 15 | import SettingsItemView from "src/ui/SettingsItemView"; 16 | 17 | export default class GPTPlugin extends Plugin { 18 | settings: GPTPluginSettings; 19 | 20 | getSelectedText(editor: Editor) { 21 | let selectedText: string; 22 | 23 | if (editor.somethingSelected()) { 24 | selectedText = editor.getSelection().trim(); 25 | return selectedText; 26 | } 27 | } 28 | 29 | getCurrentLineContents(editor: Editor) { 30 | const lineNumber = editor.getCursor().line; 31 | const lineContents = editor.getLine(lineNumber); 32 | const currentLineContents: CurrentLineContents = { 33 | lineNumber, 34 | lineContents, 35 | }; 36 | return currentLineContents; 37 | } 38 | 39 | getNoteContents(editor: Editor) { 40 | const noteContents = editor.getValue(); 41 | return noteContents; 42 | } 43 | 44 | getSuffix(selection: string) { 45 | if (selection.includes(this.settings.insertToken)) { 46 | const prompt = selection.split(this.settings.insertToken)[0]; 47 | const suffix = selection.split(this.settings.insertToken)[1]; 48 | return { prompt, suffix }; 49 | } 50 | return { prompt: selection }; 51 | } 52 | 53 | async getCompletion(selection: string): Promise { 54 | let completion: string; 55 | const notice = gettingCompletionNotice("test"); 56 | completion = await getCompletion(selection, this.settings); 57 | notice.hide(); 58 | return completion; 59 | } 60 | 61 | handleGetCompletionError() { 62 | errorGettingCompletionNotice(); 63 | } 64 | 65 | formatCompletion(prompt: string, completion: string) { 66 | const { 67 | tagCompletions, 68 | tagCompletionsHandlerTags, 69 | tagPrompts, 70 | tagPromptsHandlerTags, 71 | } = this.settings; 72 | 73 | if (tagCompletions) { 74 | completion = `${tagCompletionsHandlerTags.openingTag}${completion}${tagCompletionsHandlerTags.closingTag}`; 75 | } 76 | 77 | if (tagPrompts) { 78 | prompt = `${tagPromptsHandlerTags.openingTag}${prompt}${tagPromptsHandlerTags.closingTag}`; 79 | } 80 | 81 | return prompt + completion; 82 | } 83 | 84 | async getCompletionHandler(editor: Editor) { 85 | const selection: string = this.getSelectedText(editor); 86 | if (selection) { 87 | const completion = await this.getCompletion(selection); 88 | if (!completion) { 89 | this.handleGetCompletionError(); 90 | return; 91 | } 92 | editor.replaceSelection(this.formatCompletion(selection, completion)); 93 | return; 94 | } 95 | const currentLineContents = this.getCurrentLineContents(editor); 96 | if (currentLineContents) { 97 | const completion = await this.getCompletion( 98 | currentLineContents.lineContents 99 | ); 100 | if (!completion) { 101 | this.handleGetCompletionError(); 102 | return; 103 | } 104 | const formatted = this.formatCompletion( 105 | currentLineContents.lineContents, 106 | completion 107 | ); 108 | editor.setLine(currentLineContents.lineNumber, formatted); 109 | return; 110 | } 111 | } 112 | 113 | initLeaf(): void { 114 | if (this.app.workspace.getLeavesOfType(VIEW_TYPE_MODEL_SETTINGS).length) { 115 | return; 116 | } 117 | this.app.workspace.getRightLeaf(false).setViewState({ 118 | type: VIEW_TYPE_MODEL_SETTINGS, 119 | }); 120 | } 121 | 122 | ensureLeafExists(active: boolean = false): void { 123 | let { workspace } = this.app; 124 | 125 | let preferredSidebar = "right"; 126 | 127 | let leaf: WorkspaceLeaf; 128 | let existingPluginLeaves = workspace.getLeavesOfType( 129 | VIEW_TYPE_MODEL_SETTINGS 130 | ); 131 | 132 | if (existingPluginLeaves.length > 0) { 133 | leaf = existingPluginLeaves[0]; 134 | } else { 135 | leaf = 136 | preferredSidebar === "left" 137 | ? workspace.getLeftLeaf(false) 138 | : workspace.getRightLeaf(false); 139 | workspace.revealLeaf(leaf); 140 | leaf.setViewState({ type: VIEW_TYPE_MODEL_SETTINGS }); 141 | } 142 | 143 | if (active) { 144 | workspace.setActiveLeaf(leaf); 145 | } 146 | } 147 | 148 | async populateSettingDefaults() { 149 | // ensure that each model's default settings are populated 150 | const settings = this.settings; 151 | if (!settings.openRouter) { 152 | console.log("populating default settings for openrouter"); 153 | settings.openRouter = DEFAULT_SETTINGS.openRouter; 154 | } 155 | if (!settings.availableModels || !settings.availableModels.length) { 156 | console.log("populating available models"); 157 | const models = await refetchModels(); 158 | this.settings.availableModels = models; 159 | } 160 | await this.saveData(settings); 161 | } 162 | 163 | async onload() { 164 | await this.loadSettings(); 165 | await this.populateSettingDefaults(); 166 | 167 | this.registerView( 168 | VIEW_TYPE_MODEL_SETTINGS, 169 | (leaf: WorkspaceLeaf) => new SettingsItemView(leaf, this.settings, this) 170 | ); 171 | 172 | this.addCommand({ 173 | id: "get-completion", 174 | name: "Get Completion", 175 | editorCallback: (editor: Editor) => this.getCompletionHandler(editor), 176 | }); 177 | 178 | this.addCommand({ 179 | id: "show-model-settings", 180 | name: "Show Model Settings", 181 | callback: () => { 182 | this.ensureLeafExists(true); 183 | }, 184 | }); 185 | 186 | this.addSettingTab(new GPTSettingTab(this.app, this)); 187 | 188 | this.app.workspace.onLayoutReady(() => { 189 | this.ensureLeafExists(false); 190 | }); 191 | } 192 | 193 | async loadSettings() { 194 | this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); 195 | } 196 | 197 | async saveSettings() { 198 | await this.saveData(this.settings); 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "obsidian-gpt", 3 | "name": "GPT", 4 | "version": "2.0.0", 5 | "minAppVersion": "0.9.12", 6 | "description": "Obsidian plugin for getting language model completions from Openrouter. Use any supported model, including ChatGPT, Claude, LLaMa, and more.", 7 | "author": "Jonathan Miller", 8 | "authorUrl": "https://jmill.dev", 9 | "isDesktopOnly": false 10 | } 11 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "obsidian-gpt", 3 | "version": "2.0.0", 4 | "description": "Obsidian plugin for getting language model completions from Openrouter. Use any supported model, including ChatGPT, Claude, LLaMa, and more.", 5 | "main": "main.js", 6 | "scripts": { 7 | "dev": "rollup --config rollup.config.js -w", 8 | "build": "rollup --config rollup.config.js --environment BUILD:production" 9 | }, 10 | "keywords": [ 11 | "obsidian-plugin" 12 | ], 13 | "author": "Jonathan Miller", 14 | "license": "MIT", 15 | "devDependencies": { 16 | "@rollup/plugin-commonjs": "^18.0.0", 17 | "@rollup/plugin-node-resolve": "^11.2.1", 18 | "@rollup/plugin-replace": "^5.0.1", 19 | "@rollup/plugin-typescript": "^8.2.1", 20 | "@types/node": "^14.14.37", 21 | "@types/react": "^17.0.26", 22 | "@types/react-dom": "^17.0.9", 23 | "obsidian": "^0.12.0", 24 | "rollup": "^2.32.1", 25 | "tslib": "^2.2.0", 26 | "typescript": "^4.2.4" 27 | }, 28 | "dependencies": { 29 | "react": "^17.0.2", 30 | "react-dom": "^17.0.2" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import typescript from "@rollup/plugin-typescript"; 2 | import { nodeResolve } from "@rollup/plugin-node-resolve"; 3 | import replace from "@rollup/plugin-replace"; 4 | import commonjs from "@rollup/plugin-commonjs"; 5 | import { env } from "process"; 6 | 7 | const banner = `/* 8 | THIS IS A GENERATED/BUNDLED FILE BY ROLLUP 9 | if you want to view the source visit the plugins github repository 10 | */ 11 | `; 12 | 13 | export default { 14 | input: "main.ts", 15 | output: { 16 | dir: ".", 17 | format: "cjs", 18 | exports: "default", 19 | banner, 20 | }, 21 | external: ["obsidian", "fs", "os", "path"], 22 | plugins: [ 23 | typescript(), 24 | nodeResolve({ browser: true }), 25 | replace({ 26 | "process.env.NODE_ENV": JSON.stringify(env.NODE_ENV), 27 | }), 28 | commonjs(), 29 | ], 30 | }; 31 | -------------------------------------------------------------------------------- /src/SettingsTab.ts: -------------------------------------------------------------------------------- 1 | import GPTPlugin from "main"; 2 | import { App, PluginSettingTab, Setting } from "obsidian"; 3 | 4 | class GPTSettingTab extends PluginSettingTab { 5 | plugin: GPTPlugin; 6 | 7 | constructor(app: App, plugin: GPTPlugin) { 8 | super(app, plugin); 9 | this.plugin = plugin; 10 | } 11 | 12 | display(): void { 13 | let { containerEl } = this; 14 | 15 | containerEl.empty(); 16 | 17 | containerEl.createEl("h2", { text: "Obsidian GPT settings" }); 18 | 19 | containerEl.createEl("h3", { text: "API Keys" }); 20 | 21 | new Setting(containerEl) 22 | .setName("Openrouter API Key") 23 | .setDesc("Enter your Openrouter API Key") 24 | .addText((text) => 25 | text 26 | .setPlaceholder("Openrouter API Key") 27 | .setValue(this.plugin.settings.openRouter.apiKey) 28 | .onChange(async (value) => { 29 | this.plugin.settings.openRouter.apiKey = value; 30 | await this.plugin.saveSettings(); 31 | }) 32 | ); 33 | 34 | containerEl.createEl("h3", { text: "Completion & Prompt Tags" }); 35 | 36 | new Setting(containerEl) 37 | .setName("Tag Completions?") 38 | .setDesc( 39 | "Optionally put a tag around text which was generated via completion" 40 | ) 41 | .addToggle((toggle) => 42 | toggle 43 | .setValue(this.plugin.settings.tagCompletions) 44 | .onChange(async (value) => { 45 | this.plugin.settings.tagCompletions = value; 46 | await this.plugin.saveSettings(); 47 | }) 48 | ); 49 | 50 | new Setting(containerEl).setName("Opening Completion Tag").addText((text) => 51 | text 52 | .setPlaceholder("") 53 | .setValue(this.plugin.settings.tagCompletionsHandlerTags.openingTag) 54 | .onChange(async (value) => { 55 | this.plugin.settings.tagCompletionsHandlerTags.openingTag = value; 56 | await this.plugin.saveSettings(); 57 | }) 58 | ); 59 | 60 | new Setting(containerEl).setName("Closing Completion Tag").addText((text) => 61 | text 62 | .setPlaceholder("") 63 | .setValue(this.plugin.settings.tagCompletionsHandlerTags.closingTag) 64 | .onChange(async (value) => { 65 | this.plugin.settings.tagCompletionsHandlerTags.closingTag = value; 66 | await this.plugin.saveSettings(); 67 | }) 68 | ); 69 | 70 | new Setting(containerEl) 71 | .setName("Tag Prompts?") 72 | .setDesc("Optionally put a tag around text which was used as prompt") 73 | .addToggle((toggle) => 74 | toggle 75 | .setValue(this.plugin.settings.tagPrompts) 76 | .onChange(async (value) => { 77 | this.plugin.settings.tagPrompts = value; 78 | await this.plugin.saveSettings(); 79 | }) 80 | ); 81 | 82 | new Setting(containerEl).setName("Opening Prompt Tag").addText((text) => 83 | text 84 | .setPlaceholder("") 85 | .setValue(this.plugin.settings.tagPromptsHandlerTags.openingTag) 86 | .onChange(async (value) => { 87 | this.plugin.settings.tagPromptsHandlerTags.openingTag = value; 88 | await this.plugin.saveSettings(); 89 | }) 90 | ); 91 | 92 | new Setting(containerEl).setName("Closing Prompt Tag").addText((text) => 93 | text 94 | .setPlaceholder("") 95 | .setValue(this.plugin.settings.tagPromptsHandlerTags.closingTag) 96 | .onChange(async (value) => { 97 | this.plugin.settings.tagPromptsHandlerTags.closingTag = value; 98 | await this.plugin.saveSettings(); 99 | }) 100 | ); 101 | } 102 | } 103 | 104 | export default GPTSettingTab; 105 | -------------------------------------------------------------------------------- /src/context.ts: -------------------------------------------------------------------------------- 1 | import { App } from "obsidian"; 2 | import * as React from "react"; 3 | import { DEFAULT_SETTINGS, GPTPluginSettings } from "./types"; 4 | 5 | export const AppContext = React.createContext(undefined); 6 | 7 | export const SettingsContext = 8 | React.createContext(DEFAULT_SETTINGS); 9 | -------------------------------------------------------------------------------- /src/notices.ts: -------------------------------------------------------------------------------- 1 | import { Notice } from "obsidian"; 2 | 3 | export const gettingCompletionNotice = (modelName: string) => { 4 | return new Notice(`Getting ${modelName} Completion`, 10000); 5 | }; 6 | 7 | export const errorGettingCompletionNotice = () => { 8 | return new Notice( 9 | "Error getting completion. Check your internet settings or API key." 10 | ); 11 | }; 12 | -------------------------------------------------------------------------------- /src/openrouter.ts: -------------------------------------------------------------------------------- 1 | import { RequestParam, request } from "obsidian"; 2 | import { GPTPluginSettings, ORRequest, ORResponse } from "src/types"; 3 | 4 | const parseResponseText = (response: ORResponse): string => { 5 | const choice = response.choices[0]; 6 | // @ts-ignore 7 | const { text, message } = choice; 8 | if (text) { 9 | return text; 10 | } else if (message) { 11 | return message.content; 12 | } 13 | throw new Error("No text or message found in response"); 14 | }; 15 | 16 | export const getCompletion = async ( 17 | prompt: string, 18 | settings: GPTPluginSettings 19 | ): Promise => { 20 | const apiUrl = "https://openrouter.ai/api/v1/chat/completions"; 21 | const headers = { 22 | Authorization: `Bearer ${settings.openRouter.apiKey}`, 23 | "Content-Type": "application/json", 24 | }; 25 | const { apiKey, ...openRouter } = settings.openRouter; 26 | const data: Partial = { 27 | ...openRouter, 28 | prompt, 29 | }; 30 | const requestParam: RequestParam = { 31 | url: apiUrl, 32 | method: "POST", 33 | contentType: "application/json", 34 | body: JSON.stringify(data), 35 | headers, 36 | }; 37 | const res: ORResponse = await request(requestParam) 38 | .then((response) => { 39 | return JSON.parse(response); 40 | }) 41 | .catch((err) => { 42 | console.error(err); 43 | }); 44 | const text = parseResponseText(res); 45 | return " " + text; 46 | }; 47 | 48 | interface ORModel { 49 | id: string; 50 | } 51 | 52 | interface ORModelsResponse { 53 | data: ORModel[]; 54 | } 55 | 56 | export const refetchModels = async (): Promise => { 57 | const apiUrl = "https://openrouter.ai/api/v1/models"; 58 | const requestParam: RequestParam = { 59 | url: apiUrl, 60 | method: "GET", 61 | contentType: "application/json", 62 | }; 63 | const res: ORModelsResponse = await request(requestParam) 64 | .then((response) => { 65 | return JSON.parse(response); 66 | }) 67 | .catch((err) => { 68 | console.error(err); 69 | }); 70 | const models = res.data.map((model) => model.id).sort(); 71 | return models; 72 | }; 73 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | export const VIEW_TYPE_MODEL_SETTINGS = "gptModelSettings"; 2 | 3 | export interface HandlerTags { 4 | openingTag: string; 5 | closingTag: string; 6 | } 7 | 8 | export interface GPTPluginSettings { 9 | openRouter: { 10 | apiKey: string; 11 | model: string; 12 | max_tokens: number; 13 | temperature: number; 14 | top_p: number; 15 | frequency_penalty: number; 16 | presence_penalty: number; 17 | stop: string[]; 18 | }; 19 | availableModels: string[]; 20 | tagCompletions: boolean; 21 | tagCompletionsHandlerTags: HandlerTags; 22 | tagPrompts: boolean; 23 | tagPromptsHandlerTags: HandlerTags; 24 | insertToken: string; 25 | } 26 | 27 | export const DEFAULT_SETTINGS: GPTPluginSettings = { 28 | openRouter: { 29 | apiKey: "", 30 | model: "openrouter/auto", 31 | max_tokens: 100, 32 | temperature: 1.0, 33 | top_p: 1.0, 34 | frequency_penalty: 0.0, 35 | presence_penalty: 0.0, 36 | stop: [], 37 | }, 38 | availableModels: [], 39 | tagCompletions: false, 40 | tagCompletionsHandlerTags: { 41 | openingTag: "", 42 | closingTag: "", 43 | }, 44 | tagPrompts: false, 45 | tagPromptsHandlerTags: { 46 | openingTag: "", 47 | closingTag: "", 48 | }, 49 | insertToken: "[insert]", 50 | }; 51 | 52 | // Utils 53 | 54 | export interface CurrentLineContents { 55 | lineNumber: number; 56 | lineContents: string; 57 | } 58 | 59 | // OpenRouter 60 | 61 | // Definitions of subtypes are below 62 | 63 | export type ORRequest = { 64 | // Either "messages" or "prompt" is required 65 | messages?: Message[]; 66 | prompt?: string; 67 | 68 | // If "model" is unspecified, uses the user's default 69 | model?: string; // See "Supported Models" section 70 | 71 | // Additional optional parameters 72 | frequency_penalty?: number; 73 | logit_bias?: { [key: number]: number }; // Only available for OpenAI models 74 | max_tokens?: number; // Required for some models, so defaults to 512 75 | n?: number; 76 | presence_penalty?: number; 77 | response_format?: { type: "text" | "json_object" }; 78 | seed?: number; // Only available for OpenAI models 79 | stop?: string | string[]; 80 | stream?: boolean; // Enable streaming 81 | temperature?: number; 82 | top_p?: number; 83 | 84 | // Function-calling 85 | tools?: Tool[]; 86 | tool_choice?: ToolChoice; 87 | 88 | // OpenRouter-only parameters 89 | transforms?: string[]; // See "Prompt Transforms" section 90 | models?: string[]; // See "Fallback Models" section 91 | route?: "fallback"; // See "Fallback Models" section 92 | }; 93 | 94 | // Subtypes: 95 | 96 | type TextContent = { 97 | type: "text"; 98 | text: string; 99 | }; 100 | 101 | type ImageContentPart = { 102 | type: "image_url"; 103 | image_url: { 104 | url: string; // URL or base64 encoded image data 105 | detail?: string; // Optional, defaults to 'auto' 106 | }; 107 | }; 108 | 109 | type ContentPart = TextContent | ImageContentPart; 110 | 111 | type Message = { 112 | role: "user" | "assistant" | "system" | "tool"; 113 | content: string | ContentPart[]; // Only for the 'user' role 114 | name?: string; 115 | }; 116 | 117 | type FunctionDescription = { 118 | description?: string; 119 | name: string; 120 | parameters: object; // JSON Schema object 121 | }; 122 | 123 | type Tool = { 124 | type: "function"; 125 | function: FunctionDescription; 126 | }; 127 | 128 | type ToolChoice = 129 | | "none" 130 | | "auto" 131 | | { 132 | type: "function"; 133 | function: { 134 | name: string; 135 | }; 136 | }; 137 | 138 | // Definitions of subtypes are below 139 | 140 | export type ORResponse = { 141 | id: string; 142 | // Depending on whether you set "stream" to "true" and 143 | // whether you passed in "messages" or a "prompt", you 144 | // will get a different output shape 145 | choices: (NonStreamingChoice | StreamingChoice | NonChatChoice | Error)[]; 146 | created: number; // Unix timestamp 147 | model: string; 148 | object: "chat.completion"; 149 | }; 150 | 151 | // Subtypes: 152 | 153 | type NonChatChoice = { 154 | finish_reason: string | null; 155 | text: string; 156 | }; 157 | 158 | type NonStreamingChoice = { 159 | finish_reason: string | null; // Depends on the model. Ex: 'stop' | 'length' | 'content_filter' | 'tool_calls' | 'function_call' 160 | message: { 161 | content: string | null; 162 | role: string; 163 | tool_calls?: ToolCall[]; 164 | // Deprecated, replaced by tool_calls 165 | function_call?: FunctionCall; 166 | }; 167 | }; 168 | 169 | type StreamingChoice = { 170 | finish_reason: string | null; 171 | delta: { 172 | content: string | null; 173 | role?: string; 174 | tool_calls?: ToolCall[]; 175 | // Deprecated, replaced by tool_calls 176 | function_call?: FunctionCall; 177 | }; 178 | }; 179 | 180 | type Error = { 181 | code: number; // See "Error Handling" section 182 | message: string; 183 | }; 184 | 185 | type FunctionCall = { 186 | name: string; 187 | arguments: string; // JSON format arguments 188 | }; 189 | 190 | type ToolCall = { 191 | id: string; 192 | type: "function"; 193 | function: FunctionCall; 194 | }; 195 | -------------------------------------------------------------------------------- /src/ui/SettingsItemView.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import * as ReactDOM from "react-dom"; 3 | 4 | import { AppContext, SettingsContext } from "src/context"; 5 | import { ItemView, WorkspaceLeaf } from "obsidian"; 6 | import { VIEW_TYPE_MODEL_SETTINGS, GPTPluginSettings } from "../types"; 7 | import GPTPlugin from "main"; 8 | 9 | import StopSequenceInput from "src/ui/StopSequenceInput"; 10 | import { refetchModels } from "src/openrouter"; 11 | 12 | const SettingsForm = ({ plugin }: { plugin: GPTPlugin }) => { 13 | const { settings } = plugin; 14 | const [state, setState] = React.useState(settings.openRouter); 15 | const [availableModels, setAvailableModels] = React.useState( 16 | settings.availableModels 17 | ); 18 | 19 | const handleInputChange = async (e: any) => { 20 | let { name, value } = e.target; 21 | if (parseFloat(value) || value === "0") { 22 | value = parseFloat(value); 23 | } 24 | setState((prevState) => ({ 25 | ...prevState, 26 | [name]: value, 27 | })); 28 | settings.openRouter = { 29 | ...settings.openRouter, 30 | [name]: value, 31 | }; 32 | await plugin.saveSettings(); 33 | }; 34 | 35 | const onStopSequenceChange = async (stopSequences: string[]) => { 36 | setState((prevState) => ({ 37 | ...prevState, 38 | stop: stopSequences, 39 | })); 40 | settings.openRouter.stop = stopSequences; 41 | await plugin.saveSettings(); 42 | }; 43 | 44 | const refetchModelState = async () => { 45 | const models = await refetchModels(); 46 | settings.availableModels = models; 47 | await plugin.saveSettings(); 48 | setAvailableModels(models); 49 | }; 50 | 51 | return ( 52 |
53 |
54 |
61 | 64 | 67 |
68 | 81 |
82 |
83 | 86 | 87 |
88 | 98 |
99 |
100 | 103 | 104 |
105 | 116 |
117 |
118 | 121 | 122 |
123 | 134 |
135 |
136 | 139 | 142 |
143 | 154 |
155 |
156 | 159 | 160 |
161 | 172 |
173 | 177 |
178 |
179 | ); 180 | }; 181 | 182 | export default class SettingsItemView extends ItemView { 183 | settings: GPTPluginSettings; 184 | plugin: GPTPlugin; 185 | constructor( 186 | leaf: WorkspaceLeaf, 187 | settings: GPTPluginSettings, 188 | plugin: GPTPlugin 189 | ) { 190 | super(leaf); 191 | this.settings = settings; 192 | this.plugin = plugin; 193 | } 194 | 195 | getViewType(): string { 196 | return VIEW_TYPE_MODEL_SETTINGS; 197 | } 198 | 199 | getDisplayText(): string { 200 | return "GPT Model Settings"; 201 | } 202 | 203 | getIcon(): string { 204 | return "check-small"; 205 | } 206 | 207 | async onOpen(): Promise { 208 | ReactDOM.render( 209 | 210 | 211 |
212 | 213 |
214 |
215 |
, 216 | this.containerEl.children[1] 217 | ); 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /src/ui/StopSequenceInput.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | interface TagsInputProps { 4 | tags: string[]; 5 | setTags: React.Dispatch>; 6 | } 7 | 8 | const TagsInput: React.FC = ({ tags, setTags }) => { 9 | const removeTag = (i: number): void => { 10 | const newTags = [...tags]; 11 | newTags.splice(i, 1); 12 | setTags(newTags); 13 | }; 14 | 15 | const removeAllTags = (): void => { 16 | setTags([]); 17 | }; 18 | 19 | const inputKeyDown = (e: React.KeyboardEvent): void => { 20 | const val = e.currentTarget.value; 21 | if (e.key === "Enter" && val) { 22 | e.preventDefault(); 23 | if (tags.find((tag) => tag.toLowerCase() === val.toLowerCase())) { 24 | return; 25 | } 26 | setTags([...tags, val]); 27 | e.currentTarget.value = null; 28 | } else if (e.key === "Backspace" && !val) { 29 | removeTag(tags.length - 1); 30 | } 31 | }; 32 | 33 | return ( 34 |
35 |
    36 | {tags.map((tag, i) => ( 37 |
  • 38 | {tag} 39 | 48 |
  • 49 | ))} 50 |
  • 51 | 52 |
  • 53 |
54 | 57 |
58 | ); 59 | }; 60 | 61 | interface StopSequenceInputProps { 62 | stopSequences: string[]; 63 | onChange: (stopSequences: string[]) => void; 64 | } 65 | 66 | const StopSequenceInput: React.FC = ({ 67 | stopSequences, 68 | onChange: onChangeProp, 69 | }) => { 70 | const [tags, setTags] = React.useState(stopSequences); 71 | 72 | const onChange = React.useCallback(onChangeProp, []); 73 | 74 | React.useEffect(() => { 75 | const processedSequences = tags.map((seq) => seq.replace(/\\n/g, "\n")); 76 | onChange(processedSequences); 77 | }, [tags, onChange]); 78 | 79 | return ( 80 | <> 81 | 82 | 83 | 84 | ); 85 | }; 86 | 87 | export default StopSequenceInput; 88 | -------------------------------------------------------------------------------- /src/util.ts: -------------------------------------------------------------------------------- 1 | export const pythonifyKeys = (obj: any) => 2 | Object.keys(obj).reduce((acc, key) => { 3 | const modifiedKey = key.replace(/([A-Z])/g, function f(g) { 4 | return "_" + g.toLowerCase(); 5 | }); 6 | return { 7 | ...acc, 8 | ...{ [modifiedKey]: obj[key] }, 9 | }; 10 | }, {}); 11 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "inlineSourceMap": true, 5 | "inlineSources": true, 6 | "module": "ESNext", 7 | "target": "es6", 8 | "allowJs": true, 9 | "jsx": "react", 10 | "noImplicitAny": true, 11 | "moduleResolution": "node", 12 | "importHelpers": true, 13 | "lib": ["dom", "es5", "scripthost", "es2015"] 14 | }, 15 | "include": ["**/*.ts", "SettingsItemView.tsx"] 16 | } 17 | -------------------------------------------------------------------------------- /versions.json: -------------------------------------------------------------------------------- 1 | { 2 | "2.0.0": "0.9.12", 3 | "1.0.1": "0.9.12", 4 | "1.0.0": "0.9.7" 5 | } 6 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@rollup/plugin-commonjs@^18.0.0": 6 | version "18.1.0" 7 | resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-18.1.0.tgz#5a760d757af168a50727c0ae080251fbfcc5eb02" 8 | integrity sha512-h3e6T9rUxVMAQswpDIobfUHn/doMzM9sgkMrsMWCFLmB84PSoC8mV8tOloAJjSRwdqhXBqstlX2BwBpHJvbhxg== 9 | dependencies: 10 | "@rollup/pluginutils" "^3.1.0" 11 | commondir "^1.0.1" 12 | estree-walker "^2.0.1" 13 | glob "^7.1.6" 14 | is-reference "^1.2.1" 15 | magic-string "^0.25.7" 16 | resolve "^1.17.0" 17 | 18 | "@rollup/plugin-node-resolve@^11.2.1": 19 | version "11.2.1" 20 | resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz#82aa59397a29cd4e13248b106e6a4a1880362a60" 21 | integrity sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg== 22 | dependencies: 23 | "@rollup/pluginutils" "^3.1.0" 24 | "@types/resolve" "1.17.1" 25 | builtin-modules "^3.1.0" 26 | deepmerge "^4.2.2" 27 | is-module "^1.0.0" 28 | resolve "^1.19.0" 29 | 30 | "@rollup/plugin-replace@^5.0.1": 31 | version "5.0.1" 32 | resolved "https://registry.yarnpkg.com/@rollup/plugin-replace/-/plugin-replace-5.0.1.tgz#49a57af3e6df111a9e75dea3f3572741f4c5c83e" 33 | integrity sha512-Z3MfsJ4CK17BfGrZgvrcp/l6WXoKb0kokULO+zt/7bmcyayokDaQ2K3eDJcRLCTAlp5FPI4/gz9MHAsosz4Rag== 34 | dependencies: 35 | "@rollup/pluginutils" "^5.0.1" 36 | magic-string "^0.26.4" 37 | 38 | "@rollup/plugin-typescript@^8.2.1": 39 | version "8.5.0" 40 | resolved "https://registry.yarnpkg.com/@rollup/plugin-typescript/-/plugin-typescript-8.5.0.tgz#7ea11599a15b0a30fa7ea69ce3b791d41b862515" 41 | integrity sha512-wMv1/scv0m/rXx21wD2IsBbJFba8wGF3ErJIr6IKRfRj49S85Lszbxb4DCo8iILpluTjk2GAAu9CoZt4G3ppgQ== 42 | dependencies: 43 | "@rollup/pluginutils" "^3.1.0" 44 | resolve "^1.17.0" 45 | 46 | "@rollup/pluginutils@^3.1.0": 47 | version "3.1.0" 48 | resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-3.1.0.tgz#706b4524ee6dc8b103b3c995533e5ad680c02b9b" 49 | integrity sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg== 50 | dependencies: 51 | "@types/estree" "0.0.39" 52 | estree-walker "^1.0.1" 53 | picomatch "^2.2.2" 54 | 55 | "@rollup/pluginutils@^5.0.1": 56 | version "5.0.2" 57 | resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.0.2.tgz#012b8f53c71e4f6f9cb317e311df1404f56e7a33" 58 | integrity sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA== 59 | dependencies: 60 | "@types/estree" "^1.0.0" 61 | estree-walker "^2.0.2" 62 | picomatch "^2.3.1" 63 | 64 | "@types/codemirror@0.0.108": 65 | version "0.0.108" 66 | resolved "https://registry.yarnpkg.com/@types/codemirror/-/codemirror-0.0.108.tgz#e640422b666bf49251b384c390cdeb2362585bde" 67 | integrity sha512-3FGFcus0P7C2UOGCNUVENqObEb4SFk+S8Dnxq7K6aIsLVs/vDtlangl3PEO0ykaKXyK56swVF6Nho7VsA44uhw== 68 | dependencies: 69 | "@types/tern" "*" 70 | 71 | "@types/estree@*", "@types/estree@^1.0.0": 72 | version "1.0.0" 73 | resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.0.tgz#5fb2e536c1ae9bf35366eed879e827fa59ca41c2" 74 | integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ== 75 | 76 | "@types/estree@0.0.39": 77 | version "0.0.39" 78 | resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" 79 | integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== 80 | 81 | "@types/node-fetch@^2.6.4": 82 | version "2.6.9" 83 | resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.9.tgz#15f529d247f1ede1824f7e7acdaa192d5f28071e" 84 | integrity sha512-bQVlnMLFJ2d35DkPNjEPmd9ueO/rh5EiaZt2bhqiSarPjZIuIV6bPQVqcrEyvNo+AfTrRGVazle1tl597w3gfA== 85 | dependencies: 86 | "@types/node" "*" 87 | form-data "^4.0.0" 88 | 89 | "@types/node@*": 90 | version "18.11.9" 91 | resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.9.tgz#02d013de7058cea16d36168ef2fc653464cfbad4" 92 | integrity sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg== 93 | 94 | "@types/node@^14.14.37": 95 | version "14.18.33" 96 | resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.33.tgz#8c29a0036771569662e4635790ffa9e057db379b" 97 | integrity sha512-qelS/Ra6sacc4loe/3MSjXNL1dNQ/GjxNHVzuChwMfmk7HuycRLVQN2qNY3XahK+fZc5E2szqQSKUyAF0E+2bg== 98 | 99 | "@types/node@^18.11.18": 100 | version "18.19.3" 101 | resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.3.tgz#e4723c4cb385641d61b983f6fe0b716abd5f8fc0" 102 | integrity sha512-k5fggr14DwAytoA/t8rPrIz++lXK7/DqckthCmoZOKNsEbJkId4Z//BqgApXBUGrGddrigYa1oqheo/7YmW4rg== 103 | dependencies: 104 | undici-types "~5.26.4" 105 | 106 | "@types/prop-types@*": 107 | version "15.7.5" 108 | resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" 109 | integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== 110 | 111 | "@types/react-dom@^17.0.9": 112 | version "17.0.18" 113 | resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.18.tgz#8f7af38f5d9b42f79162eea7492e5a1caff70dc2" 114 | integrity sha512-rLVtIfbwyur2iFKykP2w0pl/1unw26b5td16d5xMgp7/yjTHomkyxPYChFoCr/FtEX1lN9wY6lFj1qvKdS5kDw== 115 | dependencies: 116 | "@types/react" "^17" 117 | 118 | "@types/react@^17", "@types/react@^17.0.26": 119 | version "17.0.52" 120 | resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.52.tgz#10d8b907b5c563ac014a541f289ae8eaa9bf2e9b" 121 | integrity sha512-vwk8QqVODi0VaZZpDXQCmEmiOuyjEFPY7Ttaw5vjM112LOq37yz1CDJGrRJwA1fYEq4Iitd5rnjd1yWAc/bT+A== 122 | dependencies: 123 | "@types/prop-types" "*" 124 | "@types/scheduler" "*" 125 | csstype "^3.0.2" 126 | 127 | "@types/resolve@1.17.1": 128 | version "1.17.1" 129 | resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6" 130 | integrity sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw== 131 | dependencies: 132 | "@types/node" "*" 133 | 134 | "@types/scheduler@*": 135 | version "0.16.2" 136 | resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" 137 | integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== 138 | 139 | "@types/tern@*": 140 | version "0.23.4" 141 | resolved "https://registry.yarnpkg.com/@types/tern/-/tern-0.23.4.tgz#03926eb13dbeaf3ae0d390caf706b2643a0127fb" 142 | integrity sha512-JAUw1iXGO1qaWwEOzxTKJZ/5JxVeON9kvGZ/osgZaJImBnyjyn0cjovPsf6FNLmyGY8Vw9DoXZCMlfMkMwHRWg== 143 | dependencies: 144 | "@types/estree" "*" 145 | 146 | abort-controller@^3.0.0: 147 | version "3.0.0" 148 | resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" 149 | integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== 150 | dependencies: 151 | event-target-shim "^5.0.0" 152 | 153 | agentkeepalive@^4.2.1: 154 | version "4.5.0" 155 | resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923" 156 | integrity sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew== 157 | dependencies: 158 | humanize-ms "^1.2.1" 159 | 160 | asynckit@^0.4.0: 161 | version "0.4.0" 162 | resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" 163 | integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== 164 | 165 | balanced-match@^1.0.0: 166 | version "1.0.2" 167 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" 168 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== 169 | 170 | base-64@^0.1.0: 171 | version "0.1.0" 172 | resolved "https://registry.yarnpkg.com/base-64/-/base-64-0.1.0.tgz#780a99c84e7d600260361511c4877613bf24f6bb" 173 | integrity sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA== 174 | 175 | brace-expansion@^1.1.7: 176 | version "1.1.11" 177 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 178 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 179 | dependencies: 180 | balanced-match "^1.0.0" 181 | concat-map "0.0.1" 182 | 183 | builtin-modules@^3.1.0: 184 | version "3.3.0" 185 | resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6" 186 | integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw== 187 | 188 | charenc@0.0.2: 189 | version "0.0.2" 190 | resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" 191 | integrity sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA== 192 | 193 | combined-stream@^1.0.8: 194 | version "1.0.8" 195 | resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" 196 | integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== 197 | dependencies: 198 | delayed-stream "~1.0.0" 199 | 200 | commondir@^1.0.1: 201 | version "1.0.1" 202 | resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" 203 | integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg== 204 | 205 | concat-map@0.0.1: 206 | version "0.0.1" 207 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 208 | integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== 209 | 210 | crypt@0.0.2: 211 | version "0.0.2" 212 | resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" 213 | integrity sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow== 214 | 215 | csstype@^3.0.2: 216 | version "3.1.1" 217 | resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.1.tgz#841b532c45c758ee546a11d5bd7b7b473c8c30b9" 218 | integrity sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw== 219 | 220 | deepmerge@^4.2.2: 221 | version "4.2.2" 222 | resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" 223 | integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== 224 | 225 | delayed-stream@~1.0.0: 226 | version "1.0.0" 227 | resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" 228 | integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== 229 | 230 | digest-fetch@^1.3.0: 231 | version "1.3.0" 232 | resolved "https://registry.yarnpkg.com/digest-fetch/-/digest-fetch-1.3.0.tgz#898e69264d00012a23cf26e8a3e40320143fc661" 233 | integrity sha512-CGJuv6iKNM7QyZlM2T3sPAdZWd/p9zQiRNS9G+9COUCwzWFTs0Xp8NF5iePx7wtvhDykReiRRrSeNb4oMmB8lA== 234 | dependencies: 235 | base-64 "^0.1.0" 236 | md5 "^2.3.0" 237 | 238 | estree-walker@^1.0.1: 239 | version "1.0.1" 240 | resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700" 241 | integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg== 242 | 243 | estree-walker@^2.0.1, estree-walker@^2.0.2: 244 | version "2.0.2" 245 | resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" 246 | integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== 247 | 248 | event-target-shim@^5.0.0: 249 | version "5.0.1" 250 | resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" 251 | integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== 252 | 253 | form-data-encoder@1.7.2: 254 | version "1.7.2" 255 | resolved "https://registry.yarnpkg.com/form-data-encoder/-/form-data-encoder-1.7.2.tgz#1f1ae3dccf58ed4690b86d87e4f57c654fbab040" 256 | integrity sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A== 257 | 258 | form-data@^4.0.0: 259 | version "4.0.0" 260 | resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" 261 | integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== 262 | dependencies: 263 | asynckit "^0.4.0" 264 | combined-stream "^1.0.8" 265 | mime-types "^2.1.12" 266 | 267 | formdata-node@^4.3.2: 268 | version "4.4.1" 269 | resolved "https://registry.yarnpkg.com/formdata-node/-/formdata-node-4.4.1.tgz#23f6a5cb9cb55315912cbec4ff7b0f59bbd191e2" 270 | integrity sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ== 271 | dependencies: 272 | node-domexception "1.0.0" 273 | web-streams-polyfill "4.0.0-beta.3" 274 | 275 | fs.realpath@^1.0.0: 276 | version "1.0.0" 277 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 278 | integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== 279 | 280 | fsevents@~2.3.2: 281 | version "2.3.2" 282 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" 283 | integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== 284 | 285 | function-bind@^1.1.1: 286 | version "1.1.1" 287 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" 288 | integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== 289 | 290 | glob@^7.1.6: 291 | version "7.2.3" 292 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" 293 | integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== 294 | dependencies: 295 | fs.realpath "^1.0.0" 296 | inflight "^1.0.4" 297 | inherits "2" 298 | minimatch "^3.1.1" 299 | once "^1.3.0" 300 | path-is-absolute "^1.0.0" 301 | 302 | has@^1.0.3: 303 | version "1.0.3" 304 | resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" 305 | integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== 306 | dependencies: 307 | function-bind "^1.1.1" 308 | 309 | humanize-ms@^1.2.1: 310 | version "1.2.1" 311 | resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" 312 | integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ== 313 | dependencies: 314 | ms "^2.0.0" 315 | 316 | inflight@^1.0.4: 317 | version "1.0.6" 318 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 319 | integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== 320 | dependencies: 321 | once "^1.3.0" 322 | wrappy "1" 323 | 324 | inherits@2: 325 | version "2.0.4" 326 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 327 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 328 | 329 | is-buffer@~1.1.6: 330 | version "1.1.6" 331 | resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" 332 | integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== 333 | 334 | is-core-module@^2.9.0: 335 | version "2.11.0" 336 | resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144" 337 | integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw== 338 | dependencies: 339 | has "^1.0.3" 340 | 341 | is-module@^1.0.0: 342 | version "1.0.0" 343 | resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" 344 | integrity sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g== 345 | 346 | is-reference@^1.2.1: 347 | version "1.2.1" 348 | resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.2.1.tgz#8b2dac0b371f4bc994fdeaba9eb542d03002d0b7" 349 | integrity sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ== 350 | dependencies: 351 | "@types/estree" "*" 352 | 353 | "js-tokens@^3.0.0 || ^4.0.0": 354 | version "4.0.0" 355 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" 356 | integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== 357 | 358 | loose-envify@^1.1.0: 359 | version "1.4.0" 360 | resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" 361 | integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== 362 | dependencies: 363 | js-tokens "^3.0.0 || ^4.0.0" 364 | 365 | magic-string@^0.25.7: 366 | version "0.25.9" 367 | resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c" 368 | integrity sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ== 369 | dependencies: 370 | sourcemap-codec "^1.4.8" 371 | 372 | magic-string@^0.26.4: 373 | version "0.26.7" 374 | resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.26.7.tgz#caf7daf61b34e9982f8228c4527474dac8981d6f" 375 | integrity sha512-hX9XH3ziStPoPhJxLq1syWuZMxbDvGNbVchfrdCtanC7D13888bMFow61x8axrx+GfHLtVeAx2kxL7tTGRl+Ow== 376 | dependencies: 377 | sourcemap-codec "^1.4.8" 378 | 379 | md5@^2.3.0: 380 | version "2.3.0" 381 | resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f" 382 | integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g== 383 | dependencies: 384 | charenc "0.0.2" 385 | crypt "0.0.2" 386 | is-buffer "~1.1.6" 387 | 388 | mime-db@1.52.0: 389 | version "1.52.0" 390 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" 391 | integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== 392 | 393 | mime-types@^2.1.12: 394 | version "2.1.35" 395 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" 396 | integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== 397 | dependencies: 398 | mime-db "1.52.0" 399 | 400 | minimatch@^3.1.1: 401 | version "3.1.2" 402 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" 403 | integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== 404 | dependencies: 405 | brace-expansion "^1.1.7" 406 | 407 | moment@2.29.1: 408 | version "2.29.1" 409 | resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3" 410 | integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ== 411 | 412 | ms@^2.0.0: 413 | version "2.1.3" 414 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" 415 | integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== 416 | 417 | node-domexception@1.0.0: 418 | version "1.0.0" 419 | resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" 420 | integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== 421 | 422 | node-fetch@^2.6.7: 423 | version "2.7.0" 424 | resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" 425 | integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== 426 | dependencies: 427 | whatwg-url "^5.0.0" 428 | 429 | object-assign@^4.1.1: 430 | version "4.1.1" 431 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 432 | integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== 433 | 434 | obsidian@^0.12.0: 435 | version "0.12.17" 436 | resolved "https://registry.yarnpkg.com/obsidian/-/obsidian-0.12.17.tgz#8efe75310d0e3988cdeccfbb176d3a8ff7b363c7" 437 | integrity sha512-YvCAlRym9D8zNPXt6Ez8QubSTVGoChx6lb58zqI13Dcrz3l1lgUO+pcOGDiD5Qa67nzDZLXo3aV2rqkCCpTvGQ== 438 | dependencies: 439 | "@types/codemirror" "0.0.108" 440 | moment "2.29.1" 441 | 442 | once@^1.3.0: 443 | version "1.4.0" 444 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 445 | integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== 446 | dependencies: 447 | wrappy "1" 448 | 449 | openai@^4.22.1: 450 | version "4.22.1" 451 | resolved "https://registry.yarnpkg.com/openai/-/openai-4.22.1.tgz#ef228d0da42d9a5ae150cc4117a762ba1618b437" 452 | integrity sha512-Igk2FixXiEDQKkS3VJR0tTpO27O48mJqH4ztayATHTvcAmKqrIrYOjUBc7DrJcq+cKcQS5lTQalGZD05ySydHA== 453 | dependencies: 454 | "@types/node" "^18.11.18" 455 | "@types/node-fetch" "^2.6.4" 456 | abort-controller "^3.0.0" 457 | agentkeepalive "^4.2.1" 458 | digest-fetch "^1.3.0" 459 | form-data-encoder "1.7.2" 460 | formdata-node "^4.3.2" 461 | node-fetch "^2.6.7" 462 | web-streams-polyfill "^3.2.1" 463 | 464 | path-is-absolute@^1.0.0: 465 | version "1.0.1" 466 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 467 | integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== 468 | 469 | path-parse@^1.0.7: 470 | version "1.0.7" 471 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" 472 | integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== 473 | 474 | picomatch@^2.2.2, picomatch@^2.3.1: 475 | version "2.3.1" 476 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" 477 | integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== 478 | 479 | react-dom@^17.0.2: 480 | version "17.0.2" 481 | resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" 482 | integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== 483 | dependencies: 484 | loose-envify "^1.1.0" 485 | object-assign "^4.1.1" 486 | scheduler "^0.20.2" 487 | 488 | react-tag-input-component@^2.0.2: 489 | version "2.0.2" 490 | resolved "https://registry.yarnpkg.com/react-tag-input-component/-/react-tag-input-component-2.0.2.tgz#f62f013c6a535141dd1c6c3a88858223170150f1" 491 | integrity sha512-dydI9luVwwv9vrjE5u1TTnkcOVkOVL6mhFti8r6hLi78V2F2EKWQOLptURz79UYbDHLSk6tnbvGl8FE+sMpADg== 492 | 493 | react@^17.0.2: 494 | version "17.0.2" 495 | resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" 496 | integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== 497 | dependencies: 498 | loose-envify "^1.1.0" 499 | object-assign "^4.1.1" 500 | 501 | resolve@^1.17.0, resolve@^1.19.0: 502 | version "1.22.1" 503 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" 504 | integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== 505 | dependencies: 506 | is-core-module "^2.9.0" 507 | path-parse "^1.0.7" 508 | supports-preserve-symlinks-flag "^1.0.0" 509 | 510 | rollup@^2.32.1: 511 | version "2.79.1" 512 | resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.79.1.tgz#bedee8faef7c9f93a2647ac0108748f497f081c7" 513 | integrity sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw== 514 | optionalDependencies: 515 | fsevents "~2.3.2" 516 | 517 | scheduler@^0.20.2: 518 | version "0.20.2" 519 | resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91" 520 | integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== 521 | dependencies: 522 | loose-envify "^1.1.0" 523 | object-assign "^4.1.1" 524 | 525 | sourcemap-codec@^1.4.8: 526 | version "1.4.8" 527 | resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" 528 | integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== 529 | 530 | supports-preserve-symlinks-flag@^1.0.0: 531 | version "1.0.0" 532 | resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" 533 | integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== 534 | 535 | tr46@~0.0.3: 536 | version "0.0.3" 537 | resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" 538 | integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== 539 | 540 | tslib@^2.2.0: 541 | version "2.4.1" 542 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e" 543 | integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA== 544 | 545 | typescript@^4.2.4: 546 | version "4.9.3" 547 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.3.tgz#3aea307c1746b8c384435d8ac36b8a2e580d85db" 548 | integrity sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA== 549 | 550 | undici-types@~5.26.4: 551 | version "5.26.5" 552 | resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" 553 | integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== 554 | 555 | web-streams-polyfill@4.0.0-beta.3: 556 | version "4.0.0-beta.3" 557 | resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz#2898486b74f5156095e473efe989dcf185047a38" 558 | integrity sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug== 559 | 560 | web-streams-polyfill@^3.2.1: 561 | version "3.2.1" 562 | resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6" 563 | integrity sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q== 564 | 565 | webidl-conversions@^3.0.0: 566 | version "3.0.1" 567 | resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" 568 | integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== 569 | 570 | whatwg-url@^5.0.0: 571 | version "5.0.0" 572 | resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" 573 | integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== 574 | dependencies: 575 | tr46 "~0.0.3" 576 | webidl-conversions "^3.0.0" 577 | 578 | wrappy@1: 579 | version "1.0.2" 580 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 581 | integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== 582 | --------------------------------------------------------------------------------