@paytaca/opencode-plugin 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,2 @@
1
- export declare const WRAPPER_SCRIPT_CONTENT = "#!/usr/bin/env node\n/**\n * Paytaca Pay Wrapper \u2014 handles large request bodies by reading from a file.\n * Imports paytaca-cli modules directly (avoids CLI argument size limits).\n */\n\nimport { readFileSync } from 'fs';\nimport { execSync } from 'child_process';\nimport { fileURLToPath } from 'url';\nimport { dirname, join } from 'path';\n\n// How long to wait for the server to respond before treating the payment as timed out.\n// Default 240s so heavy non-streaming generations (large context / long output) can\n// complete; override with PAYTACA_PAY_TIMEOUT_MS.\nconst PAY_TIMEOUT_MS = Number(process.env.PAYTACA_PAY_TIMEOUT_MS || 240000);\n\n// Find paytaca-cli installation\nfunction findPaytacaCliPath() {\n const possiblePaths = [];\n \n // Try to get global npm root\n try {\n const globalPath = execSync('npm root -g', { encoding: 'utf8' }).trim();\n possiblePaths.push(\n join(globalPath, 'paytaca-cli'),\n join(globalPath, 'opencode-plugin', 'node_modules', 'paytaca-cli'),\n );\n } catch {}\n \n // Common global locations\n possiblePaths.push(\n '/usr/lib/node_modules/paytaca-cli',\n '/usr/local/lib/node_modules/paytaca-cli',\n '/opt/homebrew/lib/node_modules/paytaca-cli',\n );\n \n // Try current file's node_modules (for bundled installs)\n try {\n const currentFile = fileURLToPath(import.meta.url);\n const currentDir = dirname(currentFile);\n possiblePaths.push(\n join(currentDir, '..', 'node_modules', 'paytaca-cli'),\n join(currentDir, '..', '..', 'node_modules', 'paytaca-cli'),\n );\n } catch {}\n \n // Find first valid path\n for (const basePath of possiblePaths) {\n try {\n const walletPath = join(basePath, 'dist', 'wallet', 'index.js');\n readFileSync(walletPath);\n return basePath;\n } catch {}\n }\n \n throw new Error('paytaca-cli not found. Try reinstalling opencode-plugin: npm install @paytaca/opencode-plugin');\n}\n\n// Load paytaca-cli modules\nlet loadMnemonic, loadWallet, LibauthHDWallet, X402Payer, parsePaymentRequiredJson, selectBchPaymentRequirements, BCH_DERIVATION_PATH;\n\ntry {\n const basePath = findPaytacaCliPath();\n \n ({ loadMnemonic, loadWallet } = await import(join(basePath, 'dist', 'wallet', 'index.js')));\n ({ LibauthHDWallet } = await import(join(basePath, 'dist', 'wallet', 'keys.js')));\n ({ X402Payer } = await import(join(basePath, 'dist', 'wallet', 'x402.js')));\n ({ parsePaymentRequiredJson, selectBchPaymentRequirements } = await import(join(basePath, 'dist', 'utils', 'x402.js')));\n ({ BCH_DERIVATION_PATH } = await import(join(basePath, 'dist', 'utils', 'network.js')));\n} catch (err) {\n console.log(JSON.stringify({ success: false, error: 'Failed to load paytaca-cli: ' + err.message }));\n process.exit(1);\n}\n\nasync function main() {\n const configPath = process.argv[2];\n if (!configPath) {\n console.log(JSON.stringify({ success: false, error: 'Usage: node paytaca-pay-wrapper.mjs <config.json>' }));\n process.exit(1);\n }\n\n const config = JSON.parse(readFileSync(configPath, 'utf8'));\n const { url, method, headers, bodyFile, chipnet, confirmed } = config;\n\n const body = readFileSync(bodyFile, 'utf8');\n\n const data = loadMnemonic();\n if (!data) {\n console.log(JSON.stringify({ success: false, error: 'No wallet found. Run paytaca wallet create first.' }));\n process.exit(1);\n }\n\n const wallet = loadWallet();\n const isChipnet = Boolean(chipnet);\n const bchWallet = wallet.forNetwork(isChipnet);\n const hdWallet = new LibauthHDWallet(data.mnemonic, BCH_DERIVATION_PATH, isChipnet ? 'chipnet' : 'mainnet');\n const x402Payer = new X402Payer({ hdWallet, addressIndex: 0 });\n\n try {\n const result = await executePay(url, method, headers, body, bchWallet, x402Payer, isChipnet, confirmed);\n console.log(JSON.stringify(result, null, 2));\n } catch (err) {\n console.log(JSON.stringify({ success: false, error: err.message || String(err) }, null, 2));\n process.exit(1);\n }\n}\n\nasync function executePay(url, method, headers, body, bchWallet, x402Payer, isChipnet, confirmed) {\n const response = await fetch(url, {\n method,\n headers,\n body: ['POST', 'PUT', 'PATCH'].includes(method) ? body : undefined,\n signal: AbortSignal.timeout(PAY_TIMEOUT_MS),\n });\n\n const responseHeaders = {};\n response.headers.forEach((value, key) => { responseHeaders[key] = value; });\n const responseText = await response.text();\n let responseData;\n try { responseData = JSON.parse(responseText); } catch { responseData = responseText; }\n\n if (response.status === 402) {\n const paymentRequired = parsePaymentRequiredJson(responseData);\n if (!paymentRequired) {\n return { success: false, status: 402, error: 'Could not parse PaymentRequired from 402 response body' };\n }\n const requirements = selectBchPaymentRequirements(paymentRequired, isChipnet ? 'chipnet' : 'mainnet');\n if (!requirements) {\n return {\n success: false, status: 402, error: 'Server does not accept BCH payment',\n data: { acceptedSchemes: paymentRequired.accepts.map(a => ({ scheme: a.scheme, network: a.network })) },\n };\n }\n\n const payerAddress = x402Payer.getPayerAddress();\n const address = requirements.payTo;\n const amountBch = Number(requirements.amount) / 1e8;\n const changeAddressSet = bchWallet.getAddressSetAt(0);\n const changeAddress = changeAddressSet.change;\n\n if (!confirmed) {\n return {\n success: false, status: 402, error: 'Payment not confirmed.',\n payment: { required: true, amount: requirements.amount, payTo: address },\n };\n }\n\n const sendResult = await bchWallet.sendBch(amountBch, address, changeAddress);\n if (!sendResult.success) {\n return { success: false, status: 402, payment: { required: true, error: sendResult.error }, error: sendResult.error };\n }\n\n const txid = sendResult.txid;\n const paymentPayload = await x402Payer.createPaymentPayload(requirements, paymentRequired.resource.url, txid, 0, requirements.amount);\n headers['PAYMENT-SIGNATURE'] = JSON.stringify(paymentPayload);\n\n let retryResponse;\n try {\n retryResponse = await fetch(url, {\n method,\n headers,\n body: ['POST', 'PUT', 'PATCH'].includes(method) ? body : undefined,\n signal: AbortSignal.timeout(PAY_TIMEOUT_MS),\n });\n } catch (e) {\n if (e.name === 'AbortError') {\n return { success: false, timeout: true, error: 'Response timed out from server.' };\n }\n throw e;\n }\n const retryResponseHeaders = {};\n retryResponse.headers.forEach((value, key) => { retryResponseHeaders[key] = value; });\n const retryResponseText = await retryResponse.text();\n let retryResponseData;\n try { retryResponseData = JSON.parse(retryResponseText); } catch { retryResponseData = retryResponseText; }\n\n return {\n success: retryResponse.ok,\n status: retryResponse.status,\n statusText: retryResponse.statusText,\n headers: retryResponseHeaders,\n data: retryResponseData,\n payment: { required: true, txid, recipientAddress: address },\n };\n }\n\n return {\n success: response.ok,\n status: response.status,\n statusText: response.statusText,\n headers: responseHeaders,\n data: responseData,\n payment: { required: false },\n };\n}\n\nmain();\n";
1
+ export declare const WRAPPER_SCRIPT_CONTENT = "#!/usr/bin/env node\n/**\n * Paytaca Pay Wrapper \u2014 handles large request bodies by reading from a file.\n * Imports paytaca-cli modules directly (avoids CLI argument size limits).\n */\n\nimport { readFileSync } from 'fs';\nimport { execSync } from 'child_process';\nimport { fileURLToPath } from 'url';\nimport { dirname, join } from 'path';\n\n// How long to wait for the server to respond before treating the payment as timed out.\n// Default 240s so heavy non-streaming generations (large context / long output) can\n// complete; override with PAYTACA_PAY_TIMEOUT_MS.\nconst PAY_TIMEOUT_MS = Number(process.env.PAYTACA_PAY_TIMEOUT_MS || 240000);\n\n// Find paytaca-cli installation\nfunction findPaytacaCliPath() {\n const possiblePaths = [];\n \n // Try to get global npm root\n try {\n const globalPath = execSync('npm root -g', { encoding: 'utf8' }).trim();\n possiblePaths.push(\n join(globalPath, 'paytaca-cli'),\n join(globalPath, 'opencode-plugin', 'node_modules', 'paytaca-cli'),\n );\n } catch {}\n \n // Common global locations\n possiblePaths.push(\n '/usr/lib/node_modules/paytaca-cli',\n '/usr/local/lib/node_modules/paytaca-cli',\n '/opt/homebrew/lib/node_modules/paytaca-cli',\n );\n \n // Try current file's node_modules (for bundled installs)\n try {\n const currentFile = fileURLToPath(import.meta.url);\n const currentDir = dirname(currentFile);\n possiblePaths.push(\n join(currentDir, '..', 'node_modules', 'paytaca-cli'),\n join(currentDir, '..', '..', 'node_modules', 'paytaca-cli'),\n );\n } catch {}\n \n // Find first valid path\n for (const basePath of possiblePaths) {\n try {\n const walletPath = join(basePath, 'dist', 'wallet', 'index.js');\n readFileSync(walletPath);\n return basePath;\n } catch {}\n }\n \n throw new Error('paytaca-cli not found. Try reinstalling opencode-plugin: npm install @paytaca/opencode-plugin');\n}\n\n// Load paytaca-cli modules\nlet loadMnemonic, loadWallet, LibauthHDWallet, X402Payer, parsePaymentRequiredJson, selectBchPaymentRequirements, BCH_DERIVATION_PATH;\n\ntry {\n const basePath = findPaytacaCliPath();\n \n ({ loadMnemonic, loadWallet } = await import(join(basePath, 'dist', 'wallet', 'index.js')));\n ({ LibauthHDWallet } = await import(join(basePath, 'dist', 'wallet', 'keys.js')));\n ({ X402Payer } = await import(join(basePath, 'dist', 'wallet', 'x402.js')));\n ({ parsePaymentRequiredJson, selectBchPaymentRequirements } = await import(join(basePath, 'dist', 'utils', 'x402.js')));\n ({ BCH_DERIVATION_PATH } = await import(join(basePath, 'dist', 'utils', 'network.js')));\n} catch (err) {\n console.log(JSON.stringify({ success: false, error: 'Failed to load paytaca-cli: ' + err.message }));\n process.exit(1);\n}\n\n// Cauldron payment support (opt-in via config.paymentMethod === 'lift').\n// The LIFT token is sold in a single swap transaction whose output pays the\n// x402 payTo address directly. Uses the same machinery as paytaca-cli's\n// \"paytaca swap\" command, imported via absolute paths because the wrapper runs\n// outside any node_modules tree.\nconst LIFT_TOKEN_ID = process.env.PAYTACA_PAYMENT_TOKEN_ID || '5932b2fd4915d6a75d3ec53282cd49118149a2176ee67ed68b1111ff0786f7fc';\nlet cauldronLoaded = false;\nlet fetchPoolsForToken, apiPoolToMicroPool, microPoolToPoolV0, attemptTrade, watchtowerUtxosToSpendableCoins, ExchangeLab, PayoutAmountRuleType, cashAddressToLockingBytecode, binToHex;\ntry {\n const basePath = findPaytacaCliPath();\n const cauldronDir = join(basePath, 'dist', 'wallet', 'cauldron');\n const cashlabDir = join(basePath, 'node_modules', '@cashlab');\n ({ fetchPoolsForToken } = await import(join(cauldronDir, 'api.js')));\n ({ apiPoolToMicroPool, microPoolToPoolV0 } = await import(join(cauldronDir, 'pools.js')));\n ({ attemptTrade, watchtowerUtxosToSpendableCoins } = await import(join(cauldronDir, 'transact.js')));\n ({ default: ExchangeLab } = await import(join(cashlabDir, 'cauldron', 'out', 'exchange-lab.js')));\n ({ PayoutAmountRuleType } = await import(join(cashlabDir, 'common', 'out', 'constants.js')));\n ({ cashAddressToLockingBytecode, binToHex } = await import(join(cashlabDir, 'common', 'out', 'libauth.js')));\n cauldronLoaded = true;\n} catch (err) {\n // Cauldron modules are only needed for LIFT payments; BCH payments still work.\n cauldronLoaded = false;\n}\n\nasync function main() {\n const configPath = process.argv[2];\n if (!configPath) {\n console.log(JSON.stringify({ success: false, error: 'Usage: node paytaca-pay-wrapper.mjs <config.json>' }));\n process.exit(1);\n }\n\n const config = JSON.parse(readFileSync(configPath, 'utf8'));\n const { url, method, headers, bodyFile, chipnet, confirmed, paymentMethod } = config;\n\n const body = readFileSync(bodyFile, 'utf8');\n\n const data = loadMnemonic();\n if (!data) {\n console.log(JSON.stringify({ success: false, error: 'No wallet found. Run paytaca wallet create first.' }));\n process.exit(1);\n }\n\n const wallet = loadWallet();\n const isChipnet = Boolean(chipnet);\n const bchWallet = wallet.forNetwork(isChipnet);\n const hdWallet = new LibauthHDWallet(data.mnemonic, BCH_DERIVATION_PATH, isChipnet ? 'chipnet' : 'mainnet');\n const x402Payer = new X402Payer({ hdWallet, addressIndex: 0 });\n\n try {\n const result = await executePay(url, method, headers, body, bchWallet, hdWallet, x402Payer, isChipnet, confirmed, paymentMethod);\n console.log(JSON.stringify(result, null, 2));\n } catch (err) {\n console.log(JSON.stringify({ success: false, error: err.message || String(err) }, null, 2));\n process.exit(1);\n }\n}\n\n// Sell LIFT tokens via Cauldron in a single swap transaction that pays the\n// x402 payTo address directly. Returns { txid, vout } for the payment payload.\nasync function payWithLift(bchWallet, hdWallet, requirements, changeAddress) {\n if (!cauldronLoaded) {\n throw new Error('Cauldron payment modules unavailable. Update paytaca-cli to 0.5.0+ to pay with LIFT.');\n }\n const tokenId = LIFT_TOKEN_ID;\n const amountSats = BigInt(requirements.amount);\n\n const [apiPools, allUtxos, tokenUtxos] = await Promise.all([\n fetchPoolsForToken(tokenId),\n bchWallet.getUtxos(),\n bchWallet.getUtxos({ category: tokenId }),\n ]);\n if (!apiPools || apiPools.length === 0) {\n throw new Error('No active Cauldron pools for the payment token.');\n }\n const pools = apiPools.map(apiPoolToMicroPool).map(microPoolToPoolV0);\n\n const tokenBalance = (tokenUtxos || []).reduce((sum, u) => sum + BigInt(u.amount || 0), 0n);\n if (tokenBalance <= 0n) {\n throw new Error('No LIFT tokens in the wallet. Add LIFT to pay this plan with tokens, or pay with BCH.');\n }\n\n const bchUtxos = allUtxos.filter((utxo) => !utxo.is_cashtoken);\n const spendableCoins = watchtowerUtxosToSpendableCoins({\n utxos: [...bchUtxos, ...(tokenUtxos || [])],\n wallet: hdWallet,\n });\n if (spendableCoins.length === 0) {\n throw new Error('No spendable UTXOs available.');\n }\n\n const payToDecoded = cashAddressToLockingBytecode(requirements.payTo);\n if (!payToDecoded || typeof payToDecoded === 'string' || !payToDecoded.bytecode) {\n throw new Error('Invalid payment address: ' + requirements.payTo);\n }\n const changeDecoded = cashAddressToLockingBytecode(changeAddress);\n if (!changeDecoded || typeof changeDecoded === 'string' || !changeDecoded.bytecode) {\n throw new Error('Invalid change address: ' + changeAddress);\n }\n\n const exlab = new ExchangeLab();\n const payoutRules = [\n { type: PayoutAmountRuleType.FIXED, locking_bytecode: payToDecoded.bytecode, amount: amountSats },\n { type: PayoutAmountRuleType.CHANGE, locking_bytecode: changeDecoded.bytecode, allow_mixing_native_and_token: false, allow_mixing_native_and_token_when_bch_change_is_dust: false, add_change_to_txfee_when_bch_change_is_dust: true },\n ];\n\n // Back-compute the token supply for a demand target slightly above the plan\n // cost so the received BCH covers the fixed payout plus fees (excess becomes\n // change). Retry with a bigger buffer if the first target leaves no change.\n let trade = null;\n let tradeTx = null;\n let lastError = null;\n for (const buffer of [2000n, 20000n, 100000n]) {\n try {\n trade = attemptTrade({ pools, isBuyingToken: false, supply: undefined, demand: amountSats + buffer });\n tradeTx = exlab.createTradeTx(trade.entries, spendableCoins, payoutRules, null, 1n);\n exlab.verifyTradeTx(tradeTx);\n break;\n } catch (e) {\n lastError = e;\n }\n }\n if (!tradeTx) {\n const supply = trade?.summary?.supply;\n if (supply && tokenBalance < supply) {\n throw new Error('Insufficient LIFT balance: this payment needs ' + supply + ' base units but the wallet has ' + tokenBalance + '.');\n }\n throw new Error('Could not fund the payment by selling LIFT: ' + (lastError?.message || 'unknown error'));\n }\n\n const tx = tradeTx.libauth_generated_transaction;\n const payToHex = binToHex(payToDecoded.bytecode);\n const vout = tx.outputs.findIndex((o) => binToHex(o.lockingBytecode) === payToHex);\n if (vout === -1) {\n throw new Error('Payment output missing from built transaction.');\n }\n\n const txHex = binToHex(tradeTx.txbin);\n const broadcastResponse = await bchWallet.watchtower.BCH._api.post('broadcast/', { transaction: txHex });\n const data = broadcastResponse.data;\n if (data?.result) {\n data[data.success ? 'txid' : 'error'] = data.result;\n delete data.result;\n }\n if (!data?.success || !data?.txid) {\n throw new Error(data?.error || 'Broadcast failed');\n }\n return { txid: data.txid, vout };\n}\n\nasync function executePay(url, method, headers, body, bchWallet, hdWallet, x402Payer, isChipnet, confirmed, paymentMethod) {\n const response = await fetch(url, {\n method,\n headers,\n body: ['POST', 'PUT', 'PATCH'].includes(method) ? body : undefined,\n signal: AbortSignal.timeout(PAY_TIMEOUT_MS),\n });\n\n const responseHeaders = {};\n response.headers.forEach((value, key) => { responseHeaders[key] = value; });\n const responseText = await response.text();\n let responseData;\n try { responseData = JSON.parse(responseText); } catch { responseData = responseText; }\n\n if (response.status === 402) {\n const paymentRequired = parsePaymentRequiredJson(responseData);\n if (!paymentRequired) {\n return { success: false, status: 402, error: 'Could not parse PaymentRequired from 402 response body' };\n }\n const requirements = selectBchPaymentRequirements(paymentRequired, isChipnet ? 'chipnet' : 'mainnet');\n if (!requirements) {\n return {\n success: false, status: 402, error: 'Server does not accept BCH payment',\n data: { acceptedSchemes: paymentRequired.accepts.map(a => ({ scheme: a.scheme, network: a.network })) },\n };\n }\n\n const payerAddress = x402Payer.getPayerAddress();\n const address = requirements.payTo;\n const amountBch = Number(requirements.amount) / 1e8;\n const changeAddressSet = bchWallet.getAddressSetAt(0);\n const changeAddress = changeAddressSet.change;\n\n if (!confirmed) {\n return {\n success: false, status: 402, error: 'Payment not confirmed.',\n payment: { required: true, amount: requirements.amount, payTo: address },\n };\n }\n\n let txid, vout = 0;\n if (paymentMethod === 'lift') {\n // Sell LIFT via Cauldron; the swap transaction pays the plan directly.\n const liftPayment = await payWithLift(bchWallet, hdWallet, requirements, changeAddress);\n txid = liftPayment.txid;\n vout = liftPayment.vout;\n } else {\n const sendResult = await bchWallet.sendBch(amountBch, address, changeAddress);\n if (!sendResult.success) {\n return { success: false, status: 402, payment: { required: true, error: sendResult.error }, error: sendResult.error };\n }\n txid = sendResult.txid;\n }\n\n const paymentPayload = await x402Payer.createPaymentPayload(requirements, paymentRequired.resource.url, txid, vout, requirements.amount);\n headers['PAYMENT-SIGNATURE'] = JSON.stringify(paymentPayload);\n\n let retryResponse;\n try {\n retryResponse = await fetch(url, {\n method,\n headers,\n body: ['POST', 'PUT', 'PATCH'].includes(method) ? body : undefined,\n signal: AbortSignal.timeout(PAY_TIMEOUT_MS),\n });\n } catch (e) {\n if (e.name === 'AbortError') {\n return { success: false, timeout: true, error: 'Response timed out from server.' };\n }\n throw e;\n }\n const retryResponseHeaders = {};\n retryResponse.headers.forEach((value, key) => { retryResponseHeaders[key] = value; });\n const retryResponseText = await retryResponse.text();\n let retryResponseData;\n try { retryResponseData = JSON.parse(retryResponseText); } catch { retryResponseData = retryResponseText; }\n\n return {\n success: retryResponse.ok,\n status: retryResponse.status,\n statusText: retryResponse.statusText,\n headers: retryResponseHeaders,\n data: retryResponseData,\n payment: { required: true, txid, recipientAddress: address, method: paymentMethod === 'lift' ? 'lift' : 'bch' },\n };\n }\n\n return {\n success: response.ok,\n status: response.status,\n statusText: response.statusText,\n headers: responseHeaders,\n data: responseData,\n payment: { required: false },\n };\n}\n\nmain();\n";
2
2
  //# sourceMappingURL=wrapper.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"wrapper.d.ts","sourceRoot":"","sources":["../../src/bundled/wrapper.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,sBAAsB,ozOAqMlC,CAAC"}
1
+ {"version":3,"file":"wrapper.d.ts","sourceRoot":"","sources":["../../src/bundled/wrapper.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,sBAAsB,oyaAiUlC,CAAC"}
@@ -78,6 +78,30 @@ try {
78
78
  process.exit(1);
79
79
  }
80
80
 
81
+ // Cauldron payment support (opt-in via config.paymentMethod === 'lift').
82
+ // The LIFT token is sold in a single swap transaction whose output pays the
83
+ // x402 payTo address directly. Uses the same machinery as paytaca-cli's
84
+ // "paytaca swap" command, imported via absolute paths because the wrapper runs
85
+ // outside any node_modules tree.
86
+ const LIFT_TOKEN_ID = process.env.PAYTACA_PAYMENT_TOKEN_ID || '5932b2fd4915d6a75d3ec53282cd49118149a2176ee67ed68b1111ff0786f7fc';
87
+ let cauldronLoaded = false;
88
+ let fetchPoolsForToken, apiPoolToMicroPool, microPoolToPoolV0, attemptTrade, watchtowerUtxosToSpendableCoins, ExchangeLab, PayoutAmountRuleType, cashAddressToLockingBytecode, binToHex;
89
+ try {
90
+ const basePath = findPaytacaCliPath();
91
+ const cauldronDir = join(basePath, 'dist', 'wallet', 'cauldron');
92
+ const cashlabDir = join(basePath, 'node_modules', '@cashlab');
93
+ ({ fetchPoolsForToken } = await import(join(cauldronDir, 'api.js')));
94
+ ({ apiPoolToMicroPool, microPoolToPoolV0 } = await import(join(cauldronDir, 'pools.js')));
95
+ ({ attemptTrade, watchtowerUtxosToSpendableCoins } = await import(join(cauldronDir, 'transact.js')));
96
+ ({ default: ExchangeLab } = await import(join(cashlabDir, 'cauldron', 'out', 'exchange-lab.js')));
97
+ ({ PayoutAmountRuleType } = await import(join(cashlabDir, 'common', 'out', 'constants.js')));
98
+ ({ cashAddressToLockingBytecode, binToHex } = await import(join(cashlabDir, 'common', 'out', 'libauth.js')));
99
+ cauldronLoaded = true;
100
+ } catch (err) {
101
+ // Cauldron modules are only needed for LIFT payments; BCH payments still work.
102
+ cauldronLoaded = false;
103
+ }
104
+
81
105
  async function main() {
82
106
  const configPath = process.argv[2];
83
107
  if (!configPath) {
@@ -86,7 +110,7 @@ async function main() {
86
110
  }
87
111
 
88
112
  const config = JSON.parse(readFileSync(configPath, 'utf8'));
89
- const { url, method, headers, bodyFile, chipnet, confirmed } = config;
113
+ const { url, method, headers, bodyFile, chipnet, confirmed, paymentMethod } = config;
90
114
 
91
115
  const body = readFileSync(bodyFile, 'utf8');
92
116
 
@@ -103,7 +127,7 @@ async function main() {
103
127
  const x402Payer = new X402Payer({ hdWallet, addressIndex: 0 });
104
128
 
105
129
  try {
106
- const result = await executePay(url, method, headers, body, bchWallet, x402Payer, isChipnet, confirmed);
130
+ const result = await executePay(url, method, headers, body, bchWallet, hdWallet, x402Payer, isChipnet, confirmed, paymentMethod);
107
131
  console.log(JSON.stringify(result, null, 2));
108
132
  } catch (err) {
109
133
  console.log(JSON.stringify({ success: false, error: err.message || String(err) }, null, 2));
@@ -111,7 +135,99 @@ async function main() {
111
135
  }
112
136
  }
113
137
 
114
- async function executePay(url, method, headers, body, bchWallet, x402Payer, isChipnet, confirmed) {
138
+ // Sell LIFT tokens via Cauldron in a single swap transaction that pays the
139
+ // x402 payTo address directly. Returns { txid, vout } for the payment payload.
140
+ async function payWithLift(bchWallet, hdWallet, requirements, changeAddress) {
141
+ if (!cauldronLoaded) {
142
+ throw new Error('Cauldron payment modules unavailable. Update paytaca-cli to 0.5.0+ to pay with LIFT.');
143
+ }
144
+ const tokenId = LIFT_TOKEN_ID;
145
+ const amountSats = BigInt(requirements.amount);
146
+
147
+ const [apiPools, allUtxos, tokenUtxos] = await Promise.all([
148
+ fetchPoolsForToken(tokenId),
149
+ bchWallet.getUtxos(),
150
+ bchWallet.getUtxos({ category: tokenId }),
151
+ ]);
152
+ if (!apiPools || apiPools.length === 0) {
153
+ throw new Error('No active Cauldron pools for the payment token.');
154
+ }
155
+ const pools = apiPools.map(apiPoolToMicroPool).map(microPoolToPoolV0);
156
+
157
+ const tokenBalance = (tokenUtxos || []).reduce((sum, u) => sum + BigInt(u.amount || 0), 0n);
158
+ if (tokenBalance <= 0n) {
159
+ throw new Error('No LIFT tokens in the wallet. Add LIFT to pay this plan with tokens, or pay with BCH.');
160
+ }
161
+
162
+ const bchUtxos = allUtxos.filter((utxo) => !utxo.is_cashtoken);
163
+ const spendableCoins = watchtowerUtxosToSpendableCoins({
164
+ utxos: [...bchUtxos, ...(tokenUtxos || [])],
165
+ wallet: hdWallet,
166
+ });
167
+ if (spendableCoins.length === 0) {
168
+ throw new Error('No spendable UTXOs available.');
169
+ }
170
+
171
+ const payToDecoded = cashAddressToLockingBytecode(requirements.payTo);
172
+ if (!payToDecoded || typeof payToDecoded === 'string' || !payToDecoded.bytecode) {
173
+ throw new Error('Invalid payment address: ' + requirements.payTo);
174
+ }
175
+ const changeDecoded = cashAddressToLockingBytecode(changeAddress);
176
+ if (!changeDecoded || typeof changeDecoded === 'string' || !changeDecoded.bytecode) {
177
+ throw new Error('Invalid change address: ' + changeAddress);
178
+ }
179
+
180
+ const exlab = new ExchangeLab();
181
+ const payoutRules = [
182
+ { type: PayoutAmountRuleType.FIXED, locking_bytecode: payToDecoded.bytecode, amount: amountSats },
183
+ { type: PayoutAmountRuleType.CHANGE, locking_bytecode: changeDecoded.bytecode, allow_mixing_native_and_token: false, allow_mixing_native_and_token_when_bch_change_is_dust: false, add_change_to_txfee_when_bch_change_is_dust: true },
184
+ ];
185
+
186
+ // Back-compute the token supply for a demand target slightly above the plan
187
+ // cost so the received BCH covers the fixed payout plus fees (excess becomes
188
+ // change). Retry with a bigger buffer if the first target leaves no change.
189
+ let trade = null;
190
+ let tradeTx = null;
191
+ let lastError = null;
192
+ for (const buffer of [2000n, 20000n, 100000n]) {
193
+ try {
194
+ trade = attemptTrade({ pools, isBuyingToken: false, supply: undefined, demand: amountSats + buffer });
195
+ tradeTx = exlab.createTradeTx(trade.entries, spendableCoins, payoutRules, null, 1n);
196
+ exlab.verifyTradeTx(tradeTx);
197
+ break;
198
+ } catch (e) {
199
+ lastError = e;
200
+ }
201
+ }
202
+ if (!tradeTx) {
203
+ const supply = trade?.summary?.supply;
204
+ if (supply && tokenBalance < supply) {
205
+ throw new Error('Insufficient LIFT balance: this payment needs ' + supply + ' base units but the wallet has ' + tokenBalance + '.');
206
+ }
207
+ throw new Error('Could not fund the payment by selling LIFT: ' + (lastError?.message || 'unknown error'));
208
+ }
209
+
210
+ const tx = tradeTx.libauth_generated_transaction;
211
+ const payToHex = binToHex(payToDecoded.bytecode);
212
+ const vout = tx.outputs.findIndex((o) => binToHex(o.lockingBytecode) === payToHex);
213
+ if (vout === -1) {
214
+ throw new Error('Payment output missing from built transaction.');
215
+ }
216
+
217
+ const txHex = binToHex(tradeTx.txbin);
218
+ const broadcastResponse = await bchWallet.watchtower.BCH._api.post('broadcast/', { transaction: txHex });
219
+ const data = broadcastResponse.data;
220
+ if (data?.result) {
221
+ data[data.success ? 'txid' : 'error'] = data.result;
222
+ delete data.result;
223
+ }
224
+ if (!data?.success || !data?.txid) {
225
+ throw new Error(data?.error || 'Broadcast failed');
226
+ }
227
+ return { txid: data.txid, vout };
228
+ }
229
+
230
+ async function executePay(url, method, headers, body, bchWallet, hdWallet, x402Payer, isChipnet, confirmed, paymentMethod) {
115
231
  const response = await fetch(url, {
116
232
  method,
117
233
  headers,
@@ -151,13 +267,21 @@ async function executePay(url, method, headers, body, bchWallet, x402Payer, isCh
151
267
  };
152
268
  }
153
269
 
154
- const sendResult = await bchWallet.sendBch(amountBch, address, changeAddress);
155
- if (!sendResult.success) {
156
- return { success: false, status: 402, payment: { required: true, error: sendResult.error }, error: sendResult.error };
270
+ let txid, vout = 0;
271
+ if (paymentMethod === 'lift') {
272
+ // Sell LIFT via Cauldron; the swap transaction pays the plan directly.
273
+ const liftPayment = await payWithLift(bchWallet, hdWallet, requirements, changeAddress);
274
+ txid = liftPayment.txid;
275
+ vout = liftPayment.vout;
276
+ } else {
277
+ const sendResult = await bchWallet.sendBch(amountBch, address, changeAddress);
278
+ if (!sendResult.success) {
279
+ return { success: false, status: 402, payment: { required: true, error: sendResult.error }, error: sendResult.error };
280
+ }
281
+ txid = sendResult.txid;
157
282
  }
158
283
 
159
- const txid = sendResult.txid;
160
- const paymentPayload = await x402Payer.createPaymentPayload(requirements, paymentRequired.resource.url, txid, 0, requirements.amount);
284
+ const paymentPayload = await x402Payer.createPaymentPayload(requirements, paymentRequired.resource.url, txid, vout, requirements.amount);
161
285
  headers['PAYMENT-SIGNATURE'] = JSON.stringify(paymentPayload);
162
286
 
163
287
  let retryResponse;
@@ -186,7 +310,7 @@ async function executePay(url, method, headers, body, bchWallet, x402Payer, isCh
186
310
  statusText: retryResponse.statusText,
187
311
  headers: retryResponseHeaders,
188
312
  data: retryResponseData,
189
- payment: { required: true, txid, recipientAddress: address },
313
+ payment: { required: true, txid, recipientAddress: address, method: paymentMethod === 'lift' ? 'lift' : 'bch' },
190
314
  };
191
315
  }
192
316
 
@@ -1 +1 @@
1
- {"version":3,"file":"wrapper.js","sourceRoot":"","sources":["../../src/bundled/wrapper.ts"],"names":[],"mappings":";AAAA,oEAAoE;AACpE,4EAA4E;AAC5E,mFAAmF;;;AAEtE,QAAA,sBAAsB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqMrC,CAAC"}
1
+ {"version":3,"file":"wrapper.js","sourceRoot":"","sources":["../../src/bundled/wrapper.ts"],"names":[],"mappings":";AAAA,oEAAoE;AACpE,4EAA4E;AAC5E,mFAAmF;;;AAEtE,QAAA,sBAAsB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiUrC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAGjC,eAAO,MAAM,mBAAmB,2BAA2B,CAAC;AAC5D,eAAO,MAAM,kBAAkB,OAAO,CAAC;AAGvC,wBAAgB,YAAY,IAAI,MAAM,CAGrC;AAED,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAIvD;AAED,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAkCpD;AAED,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAIlE;AAED,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEtD"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAGjC,eAAO,MAAM,mBAAmB,2BAA2B,CAAC;AAC5D,eAAO,MAAM,kBAAkB,OAAO,CAAC;AAGvC,wBAAgB,YAAY,IAAI,MAAM,CAGrC;AAED,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAIvD;AAED,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAkCpD;AAED,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAIlE;AAED,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEtD"}
package/dist/config.js CHANGED
@@ -45,14 +45,15 @@ exports.getLogFile = getLogFile;
45
45
  exports.getWrapperScript = getWrapperScript;
46
46
  exports.getMcpScript = getMcpScript;
47
47
  const fs = __importStar(require("fs"));
48
+ const os = __importStar(require("os"));
48
49
  const path = __importStar(require("path"));
49
50
  // Default production backend
50
51
  exports.DEFAULT_BACKEND_URL = 'https://api.paytaca.ai';
51
52
  exports.DEFAULT_PROXY_PORT = 8001;
52
53
  // Config directory: ~/.opencode-paytaca/
53
54
  function getConfigDir() {
54
- const home = process.env.HOME || process.env.USERPROFILE || '.';
55
- return path.join(home, '.opencode-paytaca');
55
+ // os.homedir() resolves HOME/USERPROFILE correctly on all platforms.
56
+ return path.join(os.homedir(), '.opencode-paytaca');
56
57
  }
57
58
  function ensureConfigDir(configDir) {
58
59
  if (!fs.existsSync(configDir)) {
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,iBAAe,cAAc,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,QAAQ,CAAC,EAAE,GAAG;;;;;kBA2HlC,GAAG;6BAkFQ,GAAG,UAAU,GAAG;qDA6BQ,GAAG,UAAU,GAAG;GAiB1E;;;;;AAED,kBAAoE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,iBAAe,cAAc,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,QAAQ,CAAC,EAAE,GAAG;;;;;kBA+HlC,GAAG;6BAsFQ,GAAG,UAAU,GAAG;qDA6BQ,GAAG,UAAU,GAAG;GAiB1E;;;;;AAED,kBAAoE"}
package/dist/index.js CHANGED
@@ -37,6 +37,7 @@ const wallet_1 = require("./wallet");
37
37
  const proxy_1 = require("./proxy");
38
38
  const mcp_1 = require("./bundled/mcp");
39
39
  const context_1 = require("./context");
40
+ const selfheal_1 = require("./selfheal");
40
41
  const fs = __importStar(require("fs"));
41
42
  const path = __importStar(require("path"));
42
43
  const os = __importStar(require("os"));
@@ -44,6 +45,9 @@ async function OpencodePlugin(_input, _options) {
44
45
  const configDir = (0, config_1.getConfigDir)();
45
46
  (0, config_1.ensureConfigDir)(configDir);
46
47
  let config = (0, config_1.loadConfig)(configDir);
48
+ // Best-effort: if a newer version is published, clear stale pins/caches so
49
+ // the next install or session picks it up. Never blocks startup.
50
+ void (0, selfheal_1.runSelfHeal)();
47
51
  // Ensure paytaca binary is on PATH for internal use
48
52
  (0, wallet_1.ensurePaytacaOnPath)();
49
53
  // Check if paytaca-cli is installed
@@ -224,13 +228,17 @@ async function OpencodePlugin(_input, _options) {
224
228
  },
225
229
  enabled: true,
226
230
  };
227
- // The MCP send tool moves real funds — make opencode prompt the user
228
- // before it runs (tool name is <server>_<tool> = 'paytaca_send'). A user
229
- // configured choice is respected; only the unset default becomes 'ask'.
231
+ // The MCP send and buy_plan tools move real funds — make opencode
232
+ // prompt the user before they run (tool names are <server>_<tool> =
233
+ // 'paytaca_send' / 'paytaca_buy_plan'). A user configured choice is
234
+ // respected; only unset defaults become 'ask'.
230
235
  const permissions = (cfg.permission || {});
231
236
  if (permissions['paytaca_send'] === undefined) {
232
237
  permissions['paytaca_send'] = 'ask';
233
238
  }
239
+ if (permissions['paytaca_buy_plan'] === undefined) {
240
+ permissions['paytaca_buy_plan'] = 'ask';
241
+ }
234
242
  cfg.permission = permissions;
235
243
  },
236
244
  "chat.headers": async (_input, output) => {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export interface SelfHealOptions {
2
+ home?: string;
3
+ cwd?: string;
4
+ registryUrl?: string;
5
+ latestVersion?: string;
6
+ }
7
+ export declare function compareVersions(a: string, b: string): number;
8
+ export declare function readOwnVersion(packageRoot: string): string | null;
9
+ export declare function updateDependencySpecs(exactVersion: string, opts: SelfHealOptions): string[];
10
+ export declare function deleteStaleLockfiles(opts: SelfHealOptions): string[];
11
+ export declare function cleanStaleCaches(targetVersion: string, opts: SelfHealOptions): string[];
12
+ export declare function runSelfHeal(opts?: SelfHealOptions): Promise<void>;
13
+ //# sourceMappingURL=selfheal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selfheal.d.ts","sourceRoot":"","sources":["../src/selfheal.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAS5D;AAYD,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOjE;AAsBD,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,GAAG,MAAM,EAAE,CAuB3F;AAKD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM,EAAE,CAqBpE;AAKD,wBAAgB,gBAAgB,CAAC,aAAa,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,GAAG,MAAM,EAAE,CA6BvF;AAQD,wBAAsB,WAAW,CAAC,IAAI,GAAE,eAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmB3E"}
@@ -0,0 +1,229 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.compareVersions = compareVersions;
37
+ exports.readOwnVersion = readOwnVersion;
38
+ exports.updateDependencySpecs = updateDependencySpecs;
39
+ exports.deleteStaleLockfiles = deleteStaleLockfiles;
40
+ exports.cleanStaleCaches = cleanStaleCaches;
41
+ exports.runSelfHeal = runSelfHeal;
42
+ const fs = __importStar(require("fs"));
43
+ const os = __importStar(require("os"));
44
+ const path = __importStar(require("path"));
45
+ const PACKAGE_NAME = '@paytaca/opencode-plugin';
46
+ const DEFAULT_REGISTRY = 'https://registry.npmjs.org';
47
+ function compareVersions(a, b) {
48
+ const pa = String(a || '').split('-')[0].split('.');
49
+ const pb = String(b || '').split('-')[0].split('.');
50
+ for (let i = 0; i < 3; i++) {
51
+ const na = parseInt(pa[i] || '0', 10) || 0;
52
+ const nb = parseInt(pb[i] || '0', 10) || 0;
53
+ if (na !== nb)
54
+ return na < nb ? -1 : 1;
55
+ }
56
+ return 0;
57
+ }
58
+ function configDir(home) {
59
+ const xdg = process.env.XDG_CONFIG_HOME;
60
+ return xdg ? path.join(xdg, 'opencode') : path.join(home, '.config', 'opencode');
61
+ }
62
+ function cacheBase(home) {
63
+ const xdg = process.env.XDG_CACHE_HOME;
64
+ return xdg ? path.join(xdg, 'opencode', 'packages', '@paytaca') : path.join(home, '.cache', 'opencode', 'packages', '@paytaca');
65
+ }
66
+ function readOwnVersion(packageRoot) {
67
+ try {
68
+ const pkg = JSON.parse(fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf8'));
69
+ return pkg.version || null;
70
+ }
71
+ catch {
72
+ return null;
73
+ }
74
+ }
75
+ async function fetchLatestVersion(registryUrl) {
76
+ try {
77
+ const controller = new AbortController();
78
+ const timer = setTimeout(() => controller.abort(), 5000);
79
+ const res = await fetch(`${registryUrl}/${encodeURIComponent(PACKAGE_NAME)}/latest`, {
80
+ signal: controller.signal,
81
+ headers: { accept: 'application/json' },
82
+ });
83
+ clearTimeout(timer);
84
+ if (!res.ok)
85
+ return null;
86
+ const data = await res.json();
87
+ return data && data.version ? String(data.version) : null;
88
+ }
89
+ catch {
90
+ return null;
91
+ }
92
+ }
93
+ // Pin the dependency spec to an exact version in every opencode scope that
94
+ // references the plugin. Exact pins (not ^ranges) avoid the 0.x semver trap
95
+ // where ^0.1.1 excludes 0.2.0 entirely.
96
+ function updateDependencySpecs(exactVersion, opts) {
97
+ const home = opts.home || os.homedir();
98
+ const cwd = opts.cwd || process.cwd();
99
+ const changed = [];
100
+ const candidates = [
101
+ path.join(configDir(home), 'package.json'),
102
+ path.join(cwd, '.opencode', 'package.json'),
103
+ ];
104
+ for (const file of candidates) {
105
+ try {
106
+ if (!fs.existsSync(file))
107
+ continue;
108
+ const json = JSON.parse(fs.readFileSync(file, 'utf8'));
109
+ const deps = json.dependencies || {};
110
+ if (typeof deps[PACKAGE_NAME] !== 'string' || deps[PACKAGE_NAME] === exactVersion)
111
+ continue;
112
+ deps[PACKAGE_NAME] = exactVersion;
113
+ json.dependencies = deps;
114
+ fs.writeFileSync(file, JSON.stringify(json, null, 2) + '\n');
115
+ changed.push(file);
116
+ }
117
+ catch {
118
+ // best effort
119
+ }
120
+ }
121
+ return changed;
122
+ }
123
+ // Remove lockfiles that pin an old version of the plugin — they regenerate on
124
+ // the next install. A stale pin (with its old integrity hash) would make the
125
+ // next install fail verification instead of fetching the new version.
126
+ function deleteStaleLockfiles(opts) {
127
+ const home = opts.home || os.homedir();
128
+ const cwd = opts.cwd || process.cwd();
129
+ const removed = [];
130
+ const lockfiles = [
131
+ path.join(configDir(home), 'package-lock.json'),
132
+ path.join(configDir(home), 'bun.lock'),
133
+ path.join(cwd, '.opencode', 'package-lock.json'),
134
+ path.join(cwd, '.opencode', 'bun.lock'),
135
+ ];
136
+ for (const file of lockfiles) {
137
+ try {
138
+ if (!fs.existsSync(file))
139
+ continue;
140
+ if (fs.readFileSync(file, 'utf8').indexOf(PACKAGE_NAME) === -1)
141
+ continue;
142
+ fs.rmSync(file, { force: true });
143
+ removed.push(file);
144
+ }
145
+ catch {
146
+ // best effort
147
+ }
148
+ }
149
+ return removed;
150
+ }
151
+ // Drop opencode plugin-cache entries for other versions of the plugin. The
152
+ // running instance's code is already loaded in memory, so removing its files
153
+ // is safe on unix; failures (e.g. Windows file locks) are ignored.
154
+ function cleanStaleCaches(targetVersion, opts) {
155
+ const home = opts.home || os.homedir();
156
+ const base = cacheBase(home);
157
+ const removed = [];
158
+ let entries = [];
159
+ try {
160
+ entries = fs.readdirSync(base);
161
+ }
162
+ catch {
163
+ return removed;
164
+ }
165
+ for (const entry of entries) {
166
+ if (entry.indexOf('opencode-plugin') === -1)
167
+ continue;
168
+ const dir = path.join(base, entry);
169
+ let version = null;
170
+ try {
171
+ const pkg = JSON.parse(fs.readFileSync(path.join(dir, 'node_modules', PACKAGE_NAME, 'package.json'), 'utf8'));
172
+ version = pkg.version || null;
173
+ }
174
+ catch {
175
+ // unreadable/corrupt entry — treat as stale
176
+ }
177
+ if (version === targetVersion)
178
+ continue;
179
+ try {
180
+ fs.rmSync(dir, { recursive: true, force: true });
181
+ removed.push(dir);
182
+ }
183
+ catch {
184
+ // best effort — e.g. file locked while running from this directory
185
+ }
186
+ }
187
+ return removed;
188
+ }
189
+ let healRan = false;
190
+ // Runs once per process, without blocking startup: if a newer version is
191
+ // published, clear everything that would keep opencode resolving the old one
192
+ // (semver-pinned spec, stale lockfiles, stale plugin cache). The next
193
+ // `opencode plugin` install or session start then picks up the new version.
194
+ async function runSelfHeal(opts = {}) {
195
+ if (healRan)
196
+ return;
197
+ healRan = true;
198
+ if (process.env.PAYTACA_SELF_UPDATE === '0')
199
+ return;
200
+ try {
201
+ const packageRoot = path.resolve(__dirname, '..');
202
+ const own = readOwnVersion(packageRoot);
203
+ if (!own)
204
+ return;
205
+ const registryUrl = opts.registryUrl || process.env.PAYTACA_NPM_REGISTRY || DEFAULT_REGISTRY;
206
+ const latest = opts.latestVersion || (await fetchLatestVersion(registryUrl));
207
+ if (!latest || compareVersions(latest, own) <= 0)
208
+ return;
209
+ const specs = updateDependencySpecs(latest, opts);
210
+ const locks = deleteStaleLockfiles(opts);
211
+ const caches = cleanStaleCaches(latest, opts);
212
+ selfHealLog(`update available: ${own} -> ${latest}; specs updated: ${specs.length}, lockfiles removed: ${locks.length}, stale caches removed: ${caches.length}`);
213
+ }
214
+ catch {
215
+ // never let the self-heal break the plugin
216
+ }
217
+ }
218
+ function selfHealLog(message) {
219
+ try {
220
+ const home = os.homedir();
221
+ const dir = process.env.PAYTACA_CONFIG_DIR || path.join(home, '.opencode-paytaca');
222
+ fs.mkdirSync(dir, { recursive: true });
223
+ fs.appendFileSync(path.join(dir, 'selfheal.log'), `${new Date().toISOString()} ${message}\n`);
224
+ }
225
+ catch {
226
+ // best effort
227
+ }
228
+ }
229
+ //# sourceMappingURL=selfheal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selfheal.js","sourceRoot":"","sources":["../src/selfheal.ts"],"names":[],"mappings":"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"}