diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..d7c081aa --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,35 @@ +--- +name: πŸ› Bug Report +about: Report a bug or unexpected behavior in the library +title: "[Bug]: " +labels: bug +assignees: '' +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Use '...' +3. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots or logs to help explain your problem. + +**Environment (please complete the following information):** +- Library Version: [e.g., 1.2.0] +- Node Version: [e.g., 18.x] +- Wallet Provider: [e.g., UniSat, Xverse] +- Operating System: [e.g., macOS, Windows] +- Framework: [e.g., React, Angular] +- Framework Version: [e.g., 1.2.0] +- Browser: [e.g., Chrome, Safari] +- Browser Version: [e.g., 88.0.4324.150] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/documentation_improvement.md b/.github/ISSUE_TEMPLATE/documentation_improvement.md new file mode 100644 index 00000000..d545bcd0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/documentation_improvement.md @@ -0,0 +1,16 @@ +--- +name: πŸ“š Documentation Improvement +about: Suggest changes or improvements to the documentation +title: "[Docs]: " +labels: documentation +assignees: '' +--- + +**Describe the improvement** +What specific part of the documentation could be improved? + +**Suggestion for Improvement** +Provide a description of the improvement or addition you are proposing. + +**Additional context** +Is there any other relevant information or context? diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..a35e7ab7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,19 @@ +--- +name: πŸš€ Feature Request +about: Suggest an idea or enhancement for the library +title: "[Feature]: " +labels: enhancement +assignees: '' +--- + +**Is your feature request related to a problem?** +Please describe the problem you’re trying to solve. + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +Any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/security_vulnerability.md b/.github/ISSUE_TEMPLATE/security_vulnerability.md new file mode 100644 index 00000000..6b3b7c2e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/security_vulnerability.md @@ -0,0 +1,31 @@ +--- +name: πŸ”’ Security Vulnerability +about: Report a security vulnerability in the library +title: "[Security]: " +labels: security +assignees: '' +--- + +**Describe the vulnerability** +A clear and concise description of the security vulnerability. + +**Potential Impact** +Describe the potential impact of this vulnerability if exploited. + +**Steps to Reproduce** +Steps to reproduce the behavior, if possible: +1. ... +2. ... + +**Environment (please complete the following information):** +- Library Version: [e.g., 1.2.0] +- Node Version: [e.g., 18.x] +- Wallet Provider: [e.g., UniSat, Xverse] +- Operating System: [e.g., macOS, Windows] +- Framework: [e.g., React, Angular] +- Framework Version: [e.g., 1.2.0] +- Browser: [e.g., Chrome, Safari] +- Browser Version: [e.g., 88.0.4324.150] + +**Additional context** +Add any other context, logs, or details here. diff --git a/.github/ISSUE_TEMPLATE/support_question.md b/.github/ISSUE_TEMPLATE/support_question.md new file mode 100644 index 00000000..91169a50 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/support_question.md @@ -0,0 +1,16 @@ +--- +name: ❓ Support/Question +about: Ask a question or request guidance about using the library +title: "[Support]: " +labels: question +assignees: '' +--- + +**Question** +Please describe your question or the guidance you need. + +**Context** +Provide any relevant code snippets or configuration information to help explain your question. + +**Additional context** +Add any other context or screenshots that may help explain your question. diff --git a/apps/demo.lasereyes.build/app/page.tsx b/apps/demo.lasereyes.build/app/page.tsx index dfd23744..c14fc209 100644 --- a/apps/demo.lasereyes.build/app/page.tsx +++ b/apps/demo.lasereyes.build/app/page.tsx @@ -3,6 +3,7 @@ import { FRACTAL_MAINNET, FRACTAL_TESTNET, MAINNET, + NetworkType, SIGNET, TESTNET, TESTNET4, @@ -10,7 +11,7 @@ import { import dynamic from 'next/dynamic' import App from '@/components/App' -import { useState } from 'react' +import { useEffect, useState } from 'react' import { UtxoProvider } from '@/hooks/useUtxos' const DynamicLasereyesProvider = dynamic( @@ -19,7 +20,7 @@ const DynamicLasereyesProvider = dynamic( ) export default function Home() { - const [network] = useState< + const [network, setNetwork] = useState< | typeof MAINNET | typeof TESTNET | typeof TESTNET4 @@ -27,10 +28,41 @@ export default function Home() { | typeof FRACTAL_MAINNET | typeof FRACTAL_TESTNET >(MAINNET) + + const [mounted, setMounted] = useState(false) + + const switchNet = () => { + if (network === MAINNET) { + setNetwork(TESTNET4) + } else if (network === TESTNET4) { + setNetwork(TESTNET) + } else if (network === TESTNET) { + setNetwork(SIGNET) + } else if (network === SIGNET) { + setNetwork(FRACTAL_MAINNET) + } else if (network === FRACTAL_MAINNET) { + setNetwork(FRACTAL_TESTNET) + } else { + setNetwork(MAINNET) + } + } + + useEffect(() => { + setMounted(true) + }, []) + + if (!mounted) { + return null + } + return ( - - - + + + ) diff --git a/apps/demo.lasereyes.build/components/App.tsx b/apps/demo.lasereyes.build/components/App.tsx index 86ef9674..b5983605 100644 --- a/apps/demo.lasereyes.build/components/App.tsx +++ b/apps/demo.lasereyes.build/components/App.tsx @@ -3,20 +3,17 @@ import WalletCard from '@/components/WalletCard' import { useEffect, useState } from 'react' import { clsx } from 'clsx' import { - LEATHER, - MAGIC_EDEN, - OKX, - OYL, - PHANTOM, - UNISAT, - WIZZ, - ORANGE, - XVERSE, + FRACTAL_MAINNET, + FRACTAL_TESTNET, + MAINNET, + NetworkType, + ProviderType, + SIGNET, + SUPPORTED_WALLETS, + TESTNET, + TESTNET4, useLaserEyes, WalletIcon, - OP_NET, - SUPPORTED_WALLETS, - ProviderType, } from '@omnisat/lasereyes' import { satoshisToBTC } from '@/lib/btc' import { cn, truncateString } from '@/lib/utils' @@ -30,8 +27,9 @@ import { FaExternalLinkAlt } from 'react-icons/fa' import { RxReload } from 'react-icons/rx' import { ClickToCopyNpmInstallPill } from '@/components/ClickToCopyNpmInstallPill' import { ImNewTab } from 'react-icons/im' +import { toast } from 'sonner' -const App = () => { +const App = ({ setNetwork }: { setNetwork: (n: NetworkType) => void }) => { const { address, paymentAddress, @@ -56,6 +54,32 @@ const App = () => { | undefined >() + const switchN = () => { + try { + if (network === MAINNET) { + switchNetwork(TESTNET4) + setNetwork(TESTNET4) + } else if (network === TESTNET4) { + switchNetwork(TESTNET) + setNetwork(TESTNET) + } else if (network === TESTNET) { + switchNetwork(SIGNET) + setNetwork(SIGNET) + } else if (network === SIGNET) { + switchNetwork(FRACTAL_MAINNET) + setNetwork(FRACTAL_MAINNET) + } else if (network === FRACTAL_MAINNET) { + switchNetwork(FRACTAL_TESTNET) + setNetwork(FRACTAL_TESTNET) + } else { + switchNetwork(MAINNET) + setNetwork(MAINNET) + } + } catch (e: any) { + toast.error(e.message) + } + } + useEffect(() => { getPackageVersion().then((version) => { setPkgVersion(version) @@ -71,15 +95,6 @@ const App = () => { // @ts-ignore const total = satoshisToBTC(balance) - // const NETWORKS = [ - // MAINNET, - // TESTNET, - // TESTNET4, - // SIGNET, - // FRACTAL_TESTNET, - // FRACTAL_MAINNET, - // ] - return (
{ src={ address ? '/lasereyes_connected.svg' : '/lasereyes_disconnected.svg' } + className={'w-auto h-auto'} + priority alt={address ? 'Laser Eyes Connected' : 'Laser Eyes Disconnected'} width={300} height={47} @@ -132,7 +149,14 @@ const App = () => {
-
{network}
+
switchN()} + > + {network} +
(undefined) export const UtxoProvider: React.FC<{ - network: NetworkType children: React.ReactNode -}> = ({ children, network }) => { - const { paymentAddress } = useLaserEyes() +}> = ({ children }) => { + const { paymentAddress, network } = useLaserEyes() const mempoolUrl = `${getMempoolSpaceUrl(network)}/api/address/${paymentAddress}/utxo` const [utxos, setUtxos] = useState([]) const fetcher = useCallback(async (url: string) => { - const response = await fetch(url) - if (!response.ok) { - throw new Error('Failed to fetch UTXOs') - } - return response.json() + try { + const response = await fetch(url) + if (!response.ok) { + throw new Error('Failed to fetch UTXOs') + } + return response.json() + } catch (e) {} }, []) const { data: utxosData, error } = useSWR( diff --git a/packages/lasereyes-core/package.json b/packages/lasereyes-core/package.json index 4ad487cd..e2a85397 100644 --- a/packages/lasereyes-core/package.json +++ b/packages/lasereyes-core/package.json @@ -1,7 +1,7 @@ { "name": "@omnisat/lasereyes-core", "private": false, - "version": "0.0.43", + "version": "0.0.44-rc.1", "type": "module", "main": "./dist/index.umd.cjs", "module": "./dist/index.js", diff --git a/packages/lasereyes-core/src/client/index.ts b/packages/lasereyes-core/src/client/index.ts index 0b2f9bae..0a5cd43f 100644 --- a/packages/lasereyes-core/src/client/index.ts +++ b/packages/lasereyes-core/src/client/index.ts @@ -114,7 +114,6 @@ export class LaserEyesClient { await provider?.connect(defaultWallet) this.$store.setKey('connected', true) } catch (error) { - console.error(error) this.$store.setKey('isConnecting', false) this.disconnect() throw error @@ -128,9 +127,9 @@ export class LaserEyesClient { throw new Error('No wallet provider connected') } - if (!this.$providerMap[this.$store.get().provider!]) { - throw new Error("The connected wallet doesn't support this method") - } + // if (!this.$providerMap[this.$store.get().provider!]) { + // throw new Error("The connected wallet doesn't support request accounts") + // } try { return await this.$providerMap[ @@ -332,7 +331,7 @@ export class LaserEyesClient { } catch (error) { if (error instanceof Error) { if (error.message.toLowerCase().includes('not implemented')) { - throw new Error("The connected wallet doesn't support this method") + throw new Error("The connected wallet doesn't support getPublicKey") } } throw error @@ -351,7 +350,7 @@ export class LaserEyesClient { } catch (error) { if (error instanceof Error) { if (error.message.toLowerCase().includes('not implemented')) { - throw new Error("The connected wallet doesn't support this method") + throw new Error("The connected wallet doesn't support getBalance") } } throw error diff --git a/packages/lasereyes-core/src/client/providers/magic-eden.ts b/packages/lasereyes-core/src/client/providers/magic-eden.ts index 8a5a4f4d..fffea0f6 100644 --- a/packages/lasereyes-core/src/client/providers/magic-eden.ts +++ b/packages/lasereyes-core/src/client/providers/magic-eden.ts @@ -1,30 +1,32 @@ import * as bitcoin from 'bitcoinjs-lib' import { - GetAddressOptions, + BitcoinNetworkType, getAddress, - signMessage, + GetAddressOptions, + MessageSigningProtocols, sendBtcTransaction, - BitcoinNetworkType, SendBtcTransactionOptions, - MessageSigningProtocols, + signMessage, signTransaction, } from 'sats-connect' import { WalletProvider } from '.' import { - ProviderType, - NetworkType, - MAGIC_EDEN, getSatsConnectNetwork, - MAINNET, LaserEyesStoreType, + MAGIC_EDEN, + MAINNET, + NetworkType, + ProviderType, } from '../..' import { findOrdinalsAddress, findPaymentAddress, - getBTCBalance, getBitcoinNetwork, + getBTCBalance, + isMainnetNetwork, + isTestnetNetwork, } from '../../lib/helpers' -import { MapStore, listenKeys } from 'nanostores' +import { listenKeys, MapStore } from 'nanostores' import { persistentMap } from '@nanostores/persistent' import { fromOutputScript } from 'bitcoinjs-lib/src/address' import { keysToPersist, PersistedKey } from '../utils' @@ -123,18 +125,27 @@ export default class MagicEdenProvider extends WalletProvider { try { if (address) { - this.restorePersistedValues() - getBTCBalance(paymentAddress, this.network).then((totalBalance) => { - this.$store.setKey('balance', totalBalance) - }) - return + if (address.startsWith('tb1') && isMainnetNetwork(this.network)) { + this.disconnect() + } else { + this.restorePersistedValues() + getBTCBalance(paymentAddress, this.network).then((totalBalance) => { + this.$store.setKey('balance', totalBalance) + }) + return + } } + + if (isTestnetNetwork(this.network)) { + throw new Error(`${this.network} is not supported by ${MAGIC_EDEN}`) + } + let magicEdenNetwork = getSatsConnectNetwork(this.network || MAINNET) const getAddressOptions = { getProvider: async () => this.library, payload: { purposes: ['ordinals', 'payment'], - message: 'Address for receiving Ordinals and payments', + message: 'Connecting with lasereyes', network: { type: magicEdenNetwork, }, diff --git a/packages/lasereyes-core/src/client/providers/oyl.ts b/packages/lasereyes-core/src/client/providers/oyl.ts index 42ee9e9e..fd41c7f5 100644 --- a/packages/lasereyes-core/src/client/providers/oyl.ts +++ b/packages/lasereyes-core/src/client/providers/oyl.ts @@ -1,7 +1,11 @@ import * as bitcoin from 'bitcoinjs-lib' import { UNSUPPORTED_PROVIDER_METHOD_ERROR, WalletProvider } from '.' import { ProviderType, NetworkType } from '../../types' -import { createSendBtcPsbt, getBTCBalance } from '../../lib/helpers' +import { + createSendBtcPsbt, + getBTCBalance, + isTestnetNetwork, +} from '../../lib/helpers' import { OYL } from '../../constants/wallets' import { listenKeys, MapStore } from 'nanostores' import { persistentMap } from '@nanostores/persistent' @@ -98,6 +102,10 @@ export default class OylProvider extends WalletProvider { async connect(_: ProviderType): Promise { if (!this.library) throw new Error("Oyl isn't installed") + if (isTestnetNetwork(this.network)) { + throw new Error(`${this.network} is not supported by Oyl`) + } + const { nativeSegwit, taproot } = await this.library.getAddresses() if (!nativeSegwit || !taproot) throw new Error('No accounts found') this.$store.setKey('address', taproot.address) diff --git a/packages/lasereyes-core/src/client/providers/phantom.ts b/packages/lasereyes-core/src/client/providers/phantom.ts index f94ec5d2..118ad77b 100644 --- a/packages/lasereyes-core/src/client/providers/phantom.ts +++ b/packages/lasereyes-core/src/client/providers/phantom.ts @@ -6,6 +6,7 @@ import { createSendBtcPsbt, getBitcoinNetwork, getBTCBalance, + isTestnetNetwork, } from '../../lib/helpers' import { listenKeys } from 'nanostores' import { fromOutputScript } from 'bitcoinjs-lib/src/address' @@ -73,6 +74,10 @@ export default class PhantomProvider extends WalletProvider { async connect(_: ProviderType): Promise { if (!this.library) throw new Error("Phantom isn't installed") + if (isTestnetNetwork(this.network)) { + throw new Error(`${this.network} is not supported by ${PHANTOM}`) + } + const phantomAccounts = await this.library.requestAccounts() if (!phantomAccounts) throw new Error('No accounts found') this.$store.setKey('accounts', phantomAccounts) diff --git a/packages/lasereyes-core/src/client/providers/unisat.ts b/packages/lasereyes-core/src/client/providers/unisat.ts index fb83db96..a9c3a159 100644 --- a/packages/lasereyes-core/src/client/providers/unisat.ts +++ b/packages/lasereyes-core/src/client/providers/unisat.ts @@ -82,7 +82,7 @@ export default class UnisatProvider extends WalletProvider { this.parent.disconnect() } } - private handleNetworkChanged(network: NetworkType) { + private handleNetworkChanged(network: string) { const foundNetwork = getNetworkForUnisat(network) if (this.network !== foundNetwork) { this.switchNetwork(foundNetwork) @@ -94,6 +94,12 @@ export default class UnisatProvider extends WalletProvider { if (!this.library) throw new Error("Unisat isn't installed") const unisatAccounts = await this.library.requestAccounts() if (!unisatAccounts) throw new Error('No accounts found') + await this.getNetwork().then((network) => { + if (this.network !== network) { + console.log('Network changed') + this.switchNetwork(this.network) + } + }) const unisatPubKey = await this.library.getPublicKey() if (!unisatPubKey) throw new Error('No public key found') this.$store.setKey('accounts', unisatAccounts) @@ -102,12 +108,8 @@ export default class UnisatProvider extends WalletProvider { this.$store.setKey('publicKey', unisatPubKey) this.$store.setKey('paymentPublicKey', unisatPubKey) this.$store.setKey('provider', UNISAT) - await this.getNetwork().then((network) => { - if (this.config?.network !== network) { - this.switchNetwork(network) - } - }) - // TODO: Confirm if this is necessary and why + + // TODO: Confirm if this i necessary and why getBTCBalance(unisatAccounts[0], this.network).then((totalBalance) => { this.$store.setKey('balance', totalBalance) }) @@ -192,6 +194,5 @@ export default class UnisatProvider extends WalletProvider { const wantedNetwork = getUnisatNetwork(network) await this.library?.switchChain(wantedNetwork) this.$network.set(network) - await this.getBalance() } } diff --git a/packages/lasereyes-core/src/client/providers/xverse.ts b/packages/lasereyes-core/src/client/providers/xverse.ts index f1953ca6..35fe9382 100644 --- a/packages/lasereyes-core/src/client/providers/xverse.ts +++ b/packages/lasereyes-core/src/client/providers/xverse.ts @@ -25,6 +25,7 @@ import { findPaymentAddress, getBTCBalance, getBitcoinNetwork, + isMainnetNetwork, } from '../../lib/helpers' import { MapStore, listenKeys } from 'nanostores' import { persistentMap } from '@nanostores/persistent' @@ -122,17 +123,22 @@ export default class XVerseProvider extends WalletProvider { try { if (address) { - this.restorePersistedValues() - getBTCBalance(paymentAddress, this.network).then((totalBalance) => { - this.$store.setKey('balance', totalBalance) - }) - return + if (address.startsWith('tb1') && isMainnetNetwork(this.network)) { + this.disconnect() + } else { + this.restorePersistedValues() + getBTCBalance(paymentAddress, this.network).then((totalBalance) => { + this.$store.setKey('balance', totalBalance) + }) + return + } } + let xverseNetwork = getSatsConnectNetwork(this.network || MAINNET) const getAddressOptions = { payload: { purposes: ['ordinals', 'payment'], - message: 'Address for receiving Ordinals and payments', + message: 'Connecting with lasereyes', network: { type: xverseNetwork, }, diff --git a/packages/lasereyes-core/src/constants/networks.ts b/packages/lasereyes-core/src/constants/networks.ts index a7e916fd..ec5490f6 100644 --- a/packages/lasereyes-core/src/constants/networks.ts +++ b/packages/lasereyes-core/src/constants/networks.ts @@ -39,7 +39,10 @@ export const REGTEST = 'regtest' export const getSatsConnectNetwork = (network: string) => { if (network === MAINNET) return XVERSE_MAINNET if (network === TESTNET) return XVERSE_TESTNET + if (network === TESTNET4) return XVERSE_TESTNET if (network === SIGNET) return XVERSE_SIGNET + if (network === FRACTAL_MAINNET) return XVERSE_MAINNET + if (network === FRACTAL_TESTNET) return XVERSE_MAINNET return XVERSE_MAINNET } @@ -72,6 +75,10 @@ export const getWizzNetwork = (network: string) => { export const getOrangeNetwork = (network: string): BitcoinNetworkType => { if (network === MAINNET) return ORANGE_MAINNET as BitcoinNetworkType if (network === TESTNET) return ORANGE_TESTNET as BitcoinNetworkType + if (network === TESTNET4) return ORANGE_TESTNET as BitcoinNetworkType + if (network === SIGNET) return ORANGE_TESTNET as BitcoinNetworkType + if (network === FRACTAL_MAINNET) return ORANGE_MAINNET as BitcoinNetworkType + if (network === FRACTAL_TESTNET) return ORANGE_MAINNET as BitcoinNetworkType return ORANGE_MAINNET as BitcoinNetworkType } diff --git a/packages/lasereyes-core/src/lib/helpers.ts b/packages/lasereyes-core/src/lib/helpers.ts index 7d7ce428..105def65 100644 --- a/packages/lasereyes-core/src/lib/helpers.ts +++ b/packages/lasereyes-core/src/lib/helpers.ts @@ -270,3 +270,15 @@ export const getAddressType = ( return 'unknown' } + +export const isTestnetNetwork = (network: NetworkType) => { + return network === TESTNET || network === TESTNET4 || network === SIGNET +} + +export const isMainnetNetwork = (network: NetworkType) => { + return ( + network === MAINNET || + network === FRACTAL_MAINNET || + network === FRACTAL_TESTNET + ) +} diff --git a/packages/lasereyes-react/package.json b/packages/lasereyes-react/package.json index 83eadd68..f1a7271a 100644 --- a/packages/lasereyes-react/package.json +++ b/packages/lasereyes-react/package.json @@ -1,7 +1,7 @@ { "name": "@omnisat/lasereyes-react", "private": false, - "version": "0.0.35", + "version": "0.0.36-rc.0", "type": "module", "main": "./dist/index.umd.cjs", "module": "./dist/index.js", diff --git a/packages/lasereyes-vue/package.json b/packages/lasereyes-vue/package.json index 610fa9b3..219ce07a 100644 --- a/packages/lasereyes-vue/package.json +++ b/packages/lasereyes-vue/package.json @@ -1,7 +1,7 @@ { "name": "@omnisat/lasereyes-vue", "private": false, - "version": "0.0.4", + "version": "0.0.5-rc.0", "type": "module", "files": [ "dist" diff --git a/packages/lasereyes/package.json b/packages/lasereyes/package.json index 20165587..9f1005fb 100644 --- a/packages/lasereyes/package.json +++ b/packages/lasereyes/package.json @@ -20,7 +20,7 @@ "url": "https://github.com/omnisat/lasereyes-mono.git" }, "private": false, - "version": "0.0.118", + "version": "0.0.119-rc.1", "type": "module", "main": "./dist/index.umd.cjs", "module": "./dist/index.js", @@ -48,8 +48,8 @@ "vite-plugin-dts": "^4.2.1" }, "dependencies": { - "@omnisat/lasereyes-core": "0.0.43", - "@omnisat/lasereyes-react": "0.0.35", + "@omnisat/lasereyes-core": "workspace:*", + "@omnisat/lasereyes-react": "workspace:*", "bip39": "^3.1.0" }, "license": "MIT", diff --git a/scripts/generate_release_notes.py b/scripts/generate_release_notes.py index e449cc1e..d9c82799 100644 --- a/scripts/generate_release_notes.py +++ b/scripts/generate_release_notes.py @@ -16,7 +16,7 @@ response = openai.ChatCompletion.create( model="gpt-4", messages=[ - {"role": "system", "content": "You are a passive aggressive release note generator. Create detailed, sometimes hilarious release notes based on the git diff provided. Always ensure you are informative and helpful. On a humor scale of 1-10, you're a 1. Don't mention anything about the lock file or about anything ot her then the main version changes."}, + {"role": "system", "content": "You are a passive aggressive release note generator. Create detailed, sometimes hilarious release notes based on the git diff provided. Always ensure you are informative and helpful. On a humor scale of 1-10, you're a 3, but you don't share it very often.. YOU MUST BE INFORMATIVE, please. remember these are release notes. Don't mention anything about the lock file or about anything ot her then the main version changes."}, {"role": "user", "content": f"Version: {version}\n{diff_content}"} ] )