{"version":3,"file":"update-command.mjs","names":[],"sources":["../../../src/commands/update-command.ts"],"sourcesContent":["/**\n * /update + /restart — Update and restart the bot from Telegram.\n *\n * /update  — Clone latest, build, install, restart. Verbose progress.\n * /restart — Just restart the Fly machine (no code update).\n *\n * Both commands send live progress messages to the user's chat via\n * the channel sender so they can see each step happening.\n *\n * Requires: FLY_API_TOKEN (already used by /flykeys, /flystatus, etc.)\n */\n\nimport { checkForUpdates, performUpdate, getCurrentCommit } from '../services/update-service.js';\nimport { isFlyControlAvailable, restartAllMachines } from '../services/fly-control-service.js';\nimport type { ChannelSender } from '../services/channel-sender.js';\nimport { parseSessionKey } from '../services/channel-sender.js';\n\n// ─── Dependency injection ────────────────────────────────────────────────\n// The channel sender is created in index.ts during plugin registration.\n// We store a reference here so the command handlers can send progress.\n\nlet _sender: ChannelSender | null = null;\n\nexport function setUpdateCommandSender(sender: ChannelSender): void {\n  _sender = sender;\n}\n\n// ─── /update ─────────────────────────────────────────────────────────────\n\nexport const updateCommand = {\n  name: 'update',\n  description: 'Update to latest OpenClawnch and restart',\n  acceptsArgs: false,\n  requireAuth: true,\n\n  handler: async (ctx: any) => {\n    const sessionKey = ctx?.sessionKey ?? '';\n    const chatId = ctx?.conversationId ?? ctx?.senderId ?? '';\n    const parsed = sessionKey ? parseSessionKey(sessionKey) : null;\n    const channel = parsed?.channel ?? 'telegram';\n\n    // Create a progress function that sends messages to the user\n    const progress = async (msg: string) => {\n      if (_sender && chatId) {\n        try {\n          await _sender.send(channel, String(chatId), msg);\n        } catch { /* non-critical */ }\n      }\n    };\n\n    // ── Preflight checks ─────────────────────────────────────────────\n    if (!isFlyControlAvailable()) {\n      return {\n        text: 'Fly.io not configured — /update requires FLY_API_TOKEN.\\n\\n'\n          + 'Set it up:\\n'\n          + '```\\nfly secrets set FLY_API_TOKEN=\"$(fly tokens create deploy -a <app>)\" -a <app>\\n```',\n      };\n    }\n\n    const current = getCurrentCommit();\n    await progress(\n      `Starting update...\\n`\n      + `Current: ${current ?? 'unknown'}\\n`\n      + `This will take 1-2 minutes. You'll see progress below.`\n    );\n\n    // ── Run the update ───────────────────────────────────────────────\n    const result = await performUpdate(progress);\n\n    if (result.success) {\n      // This message may not arrive if the machine restarts fast\n      return {\n        text: `Update complete.\\n${result.message}\\n\\nBot is restarting — back in ~30s.`,\n      };\n    }\n\n    return { text: `Update failed.\\n\\n${result.message}` };\n  },\n};\n\n// ─── /restart ────────────────────────────────────────────────────────────\n\nexport const restartCommand = {\n  name: 'restart',\n  description: 'Restart the bot (no code update, just restart the machine)',\n  acceptsArgs: false,\n  requireAuth: true,\n\n  handler: async (ctx: any) => {\n    if (!isFlyControlAvailable()) {\n      return {\n        text: 'Fly.io not configured — /restart requires FLY_API_TOKEN.\\n\\n'\n          + 'Set it up:\\n'\n          + '```\\nfly secrets set FLY_API_TOKEN=\"$(fly tokens create deploy -a <app>)\" -a <app>\\n```',\n      };\n    }\n\n    const sessionKey = ctx?.sessionKey ?? '';\n    const chatId = ctx?.conversationId ?? ctx?.senderId ?? '';\n    const parsed = sessionKey ? parseSessionKey(sessionKey) : null;\n    const channel = parsed?.channel ?? 'telegram';\n\n    // Send a heads-up\n    if (_sender && chatId) {\n      try {\n        await _sender.send(channel, String(chatId), 'Restarting machine...');\n      } catch { /* */ }\n    }\n\n    try {\n      const restarted = await restartAllMachines();\n      // This may not arrive if the machine restarts fast\n      return {\n        text: `Restarting ${restarted.length} machine(s). Back in ~30s.`,\n      };\n    } catch (err) {\n      return {\n        text: `Restart failed: ${err instanceof Error ? err.message : String(err)}`,\n      };\n    }\n  },\n};\n"],"mappings":";;;;;;;;;;;;;;;AAqBA,IAAI,UAAgC;AAEpC,SAAgB,uBAAuB,QAA6B;AAClE,WAAU;;AAKZ,MAAa,gBAAgB;CAC3B,MAAM;CACN,aAAa;CACb,aAAa;CACb,aAAa;CAEb,SAAS,OAAO,QAAa;EAC3B,MAAM,aAAa,KAAK,cAAc;EACtC,MAAM,SAAS,KAAK,kBAAkB,KAAK,YAAY;EAEvD,MAAM,WADS,aAAa,gBAAgB,WAAW,GAAG,OAClC,WAAW;EAGnC,MAAM,WAAW,OAAO,QAAgB;AACtC,OAAI,WAAW,OACb,KAAI;AACF,UAAM,QAAQ,KAAK,SAAS,OAAO,OAAO,EAAE,IAAI;WAC1C;;AAKZ,MAAI,CAAC,uBAAuB,CAC1B,QAAO,EACL,MAAM,oKAGP;AAIH,QAAM,SACJ,gCAFc,kBAAkB,IAGP,UAAU,0DAEpC;EAGD,MAAM,SAAS,MAAM,cAAc,SAAS;AAE5C,MAAI,OAAO,QAET,QAAO,EACL,MAAM,qBAAqB,OAAO,QAAQ,wCAC3C;AAGH,SAAO,EAAE,MAAM,qBAAqB,OAAO,WAAW;;CAEzD;AAID,MAAa,iBAAiB;CAC5B,MAAM;CACN,aAAa;CACb,aAAa;CACb,aAAa;CAEb,SAAS,OAAO,QAAa;AAC3B,MAAI,CAAC,uBAAuB,CAC1B,QAAO,EACL,MAAM,qKAGP;EAGH,MAAM,aAAa,KAAK,cAAc;EACtC,MAAM,SAAS,KAAK,kBAAkB,KAAK,YAAY;EAEvD,MAAM,WADS,aAAa,gBAAgB,WAAW,GAAG,OAClC,WAAW;AAGnC,MAAI,WAAW,OACb,KAAI;AACF,SAAM,QAAQ,KAAK,SAAS,OAAO,OAAO,EAAE,wBAAwB;UAC9D;AAGV,MAAI;AAGF,UAAO,EACL,MAAM,eAHU,MAAM,oBAAoB,EAGZ,OAAO,6BACtC;WACM,KAAK;AACZ,UAAO,EACL,MAAM,mBAAmB,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,IAC1E;;;CAGN"}