const path = require('path'); const os = require('os'); const fetch = require('node-fetch'); const { GITEA_TOKEN, REPO_URL = 'https://repo.cloud.thinklink.ai/thinklink/kitchen-agent.git', REPO_BRANCH = 'main', PM2_APP = 'kitchen-agent' } = process.env; const repositoryNormalized = REPO_URL.endsWith('.git') ? REPO_URL : `${REPO_URL}.git`; const updaterOptions = { repository: repositoryNormalized, branch: REPO_BRANCH, token: GITEA_TOKEN, // place updates in OS temp dir to avoid permission/self-copy issues tempLocation: path.join(os.tmpdir(), 'kitchen-agent-updates'), // only include files that actually exist in the upstream repo; module uses unlinkSync ignoreFiles: ['.env'], executeOnComplete: process.platform === 'win32' ? `IF EXIST package-lock.json (npm ci --omit=dev) ELSE (npm install --omit=dev) & pm2 reload ${PM2_APP}` : `[ -f package-lock.json ] && npm ci --omit=dev || npm install --omit=dev; pm2 reload ${PM2_APP}`, exitOnComplete: false }; let updaterInstance = null; async function getUpdater() { if (updaterInstance) { return updaterInstance; } const mod = await import('auto-git-update'); const AutoGitUpdate = mod && mod.default ? mod.default : mod; updaterInstance = new AutoGitUpdate(updaterOptions); return updaterInstance; } async function checkAndUpdate() { try { const updater = await getUpdater(); const isGithub = /github\.com/i.test(repositoryNormalized); let needsUpdate = false; if (!isGithub) { // Use Gitea-aware version check to avoid library's GitHub-only path const localVersion = (() => { try { return require('./package.json').version || null; } catch (_) { return null; } })(); const base = repositoryNormalized.replace(/\.git$/i, ''); const rawUrl = `${base}/raw/branch/${REPO_BRANCH}/package.json`; async function tryFetch(url) { const headers = GITEA_TOKEN ? { Authorization: `token ${GITEA_TOKEN}` } : undefined; const r = await fetch(url, { headers }); if (r.ok) return r.json(); return null; } let remotePkg = await tryFetch(rawUrl); if (!remotePkg && GITEA_TOKEN) { remotePkg = (await tryFetch(`${rawUrl}?token=${GITEA_TOKEN}`)) || (await tryFetch(`${rawUrl}?access_token=${GITEA_TOKEN}`)); } const remoteVersion = remotePkg && remotePkg.version ? String(remotePkg.version) : null; if (!remoteVersion) { console.error('[auto-update] Unable to read remote version from Gitea raw endpoint'); } else if (!localVersion || remoteVersion !== String(localVersion)) { console.log(`[auto-update] Update available: ${localVersion || 'unknown'} -> ${remoteVersion}`); needsUpdate = true; } if (needsUpdate) { await updater.forceUpdate(); } else { console.log('[auto-update] Up to date'); } return; } // GitHub-based repos: use library's compareVersions, then forceUpdate to avoid double compare const res = await updater.compareVersions(); if (res && res.upToDate === false) { await updater.forceUpdate(); } else { console.log('[auto-update] Up to date'); } } catch (err) { console.error('[auto-update] failed:', err); } } module.exports = { checkAndUpdate };