agent-afk 1.8.0 → 1.8.1

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.
Files changed (2) hide show
  1. package/dist/cli.mjs +1 -1
  2. package/package.json +12 -12
package/dist/cli.mjs CHANGED
@@ -1776,7 +1776,7 @@ complete -c afk -l trigger -x -a '${n}' -d 'Trigger type'`}function ud(e){e.comm
1776
1776
  `);return r.length>0&&r[r.length-1]===""&&r.pop(),r.slice(-t)}catch{return[]}}function qw(e){try{if(process.platform==="linux"){let t=`/proc/${e}/stat`;if(!wt(t))return{};let r=no(t,"utf-8").split(" "),o=Number.parseInt(r[21]??"0",10),l=Kw("/proc/1").mtimeMs/1e3+o/100,c=Math.floor(Date.now()/1e3-l),p=no(`/proc/${e}/status`,"utf-8").match(/VmRSS:\s+(\d+)\s+kB/),m=p?Math.round(Number.parseInt(p[1]??"0",10)/1024):void 0;return{uptimeSec:c,memoryMb:m}}if(process.platform==="darwin"){let{execFileSync:t}=kd("child_process"),n=t("ps",["-p",String(e),"-o","etime=,rss="],{encoding:"utf-8",stdio:["ignore","pipe","ignore"]}).trim(),[r,o]=n.split(/\s+/);return{uptimeSec:Yw(r??""),memoryMb:o?Math.round(Number.parseInt(o,10)/1024):void 0}}}catch{}return{}}function Yw(e){if(!e)return;let t=e.split("-"),n=0,r=e;t.length===2&&(n=Number.parseInt(t[0]??"0",10),r=t[1]??"");let o=r.split(":").map(l=>Number.parseInt(l,10));if(o.some(l=>!Number.isFinite(l)))return;let s=0,a=0,i=0;if(o.length===3)[s,a,i]=o;else if(o.length===2)[a,i]=o;else if(o.length===1)[i]=o;else return;return n*86400+s*3600+a*60+i}import{createInterface as Jw}from"readline";import te from"chalk";var fd="https://api.telegram.org";async function md(e){try{let t=await fetch(`${fd}/bot${e}/getMe`);if(!t.ok)return null;let n=await t.json();return!n.ok||!n.result?.id||!n.result?.first_name?null:{id:n.result.id,...n.result.username!==void 0?{username:n.result.username}:{},firstName:n.result.first_name}}catch{return null}}function Xw(e){let t=new Map;for(let n of e){let o=(n.message??n.edited_message)?.chat;!o||typeof o.id!="number"||t.set(o.id,{chatId:o.id,type:o.type??"unknown",...o.username!==void 0?{username:o.username}:{},...o.first_name!==void 0?{firstName:o.first_name}:{}})}return[...t.values()].reverse()}async function Qw(e){try{let t=await fetch(`${fd}/bot${e}/getUpdates`);if(!t.ok)return[];let n=await t.json();return!n.ok||!Array.isArray(n.result)?[]:n.result}catch{return[]}}async function Zw(e,t={}){let n=t.maxAttempts??30,r=t.intervalMs??2e3;for(let o=0;o<n;o++){let s=await Qw(e),a=Xw(s);if(a.length>0)return a;o<n-1&&await new Promise(i=>setTimeout(i,r))}return[]}function Fs(e){let t=Jw({input:process.stdin,output:process.stdout});return new Promise(n=>{t.question(e,r=>{t.close(),n(r.trim())})})}async function gd(){let e=Ne();console.log(""),console.log(te.bold("\u{1F916} Telegram bot setup")),console.log(""),console.log(te.gray(`Config will be written to ${e}`)),console.log("");let t=process.env.TELEGRAM_BOT_TOKEN?.trim()??"",n=null;for(t&&(console.log(te.gray("Validating existing TELEGRAM_BOT_TOKEN...")),n=await md(t),n?console.log(te.green(`\u2713 Token valid for @${n.username??n.firstName} (id ${n.id})`)):(console.log(te.yellow("\u26A0 Existing TELEGRAM_BOT_TOKEN is invalid; prompting for a new one")),t=""));!n;)t=await Fs("Paste your bot token (from @BotFather): "),t||(console.error(te.red("No token provided. Aborting.")),process.exit(1)),n=await md(t),n||console.log(te.red("\u2717 Token rejected by getMe. Try again or Ctrl-C to abort."));Gt(e,"TELEGRAM_BOT_TOKEN",t),console.log(te.green(`\u2713 Saved TELEGRAM_BOT_TOKEN \u2192 ${e}`)),console.log(""),console.log(te.bold("Now DM your bot to authorize your account."));let r=n.username?`@${n.username}`:`"${n.firstName}"`;console.log(` 1. Open Telegram and find ${te.cyan(r)}`),console.log(' 2. Send any message (e.g. "hi")'),console.log(""),console.log(te.gray("Polling for your chat ID (up to 60s)..."));let o=await Zw(t);if(o.length===0){console.error(te.red("\u2717 No chats found after 60s.")),console.error(te.gray(" Send a message to the bot and run `afk telegram setup` again,")),console.error(te.gray(" or paste your chat ID manually:"));let a=await Fs("Chat ID: "),i=Number.parseInt(a,10);return Number.isFinite(i)||(console.error(te.red("Invalid chat ID. Aborting.")),process.exit(1)),Gt(e,"AFK_TELEGRAM_ALLOWED_CHAT_IDS",String(i)),console.log(te.green(`\u2713 Saved AFK_TELEGRAM_ALLOWED_CHAT_IDS=${i}`)),{envPath:e,bot:n,chatId:i}}let s=o[0];if(o.length>1){console.log(te.bold(`
1777
1777
  Multiple chats found:`)),o.forEach((l,c)=>{let u=l.username?`@${l.username}`:l.firstName??l.type;console.log(` [${c+1}] ${u} (id ${l.chatId}, ${l.type})`)});let a=await Fs("Which chat should be allowed? [1]: "),i=Number.parseInt(a||"1",10)-1;Number.isFinite(i)&&i>=0&&i<o.length&&(s=o[i])}else{let a=s.username?`@${s.username}`:s.firstName??s.type;console.log(te.green(`\u2713 Found chat with ${a} (id ${s.chatId})`))}return Gt(e,"AFK_TELEGRAM_ALLOWED_CHAT_IDS",String(s.chatId)),console.log(te.green(`\u2713 Saved AFK_TELEGRAM_ALLOWED_CHAT_IDS=${s.chatId} \u2192 ${e}`)),console.log(""),console.log(te.bold("Setup complete. Start the bot with:")),console.log(te.cyan(" afk telegram start")),console.log(""),{envPath:e,bot:n,chatId:s.chatId}}function hd(e){let t=e.command("telegram").description("Manage the Agent AFK Telegram bot (setup, start, stop, status)");t.command("setup").description("Interactive setup: validate bot token, discover chat ID, persist to ~/.afk/config/afk.env").action(async()=>{try{await gd()}catch(n){console.error(X.red(`Setup failed: ${n.message}`)),process.exit(1)}}),t.command("start").description("Start the bot as a background daemon").action(async()=>{let n=await Os();if(n.kind==="started"){console.log(X.green(`\u2713 Bot started (PID ${n.pid})`)),console.log(X.gray(` Logs: ${n.logFile}`)),console.log(X.gray(" Tail with: afk telegram logs --follow"));return}if(n.kind==="already-running"&&(console.log(X.yellow(`\u26A0 ${n.message}`)),process.exit(1)),n.kind==="exited-immediately"){if(console.error(X.red(`\u2717 ${n.message}`)),n.logTail&&n.logTail.length>0){console.error(""),console.error(X.bold("Last log entries:"));for(let r of n.logTail)console.error(X.gray(` ${r}`))}process.exit(1)}console.error(X.red(`\u2717 ${n.message}`)),process.exit(1)}),t.command("stop").description("Stop the bot (SIGTERM, then SIGKILL after 5s)").action(async()=>{let n=await Ds();if(n.kind==="not-running"){console.log(X.yellow("\u26A0 Bot is not running"));return}if(n.kind==="stopped"){console.log(X.green(`\u2713 Bot stopped (PID ${n.pid})`));return}console.log(X.yellow(`\u26A0 Bot force-killed (PID ${n.pid}); graceful shutdown timed out`))}),t.command("restart").description("Stop and restart the bot").action(async()=>{let n=await Ds();(n.kind==="stopped"||n.kind==="force-killed")&&console.log(X.gray(`Stopped (PID ${n.pid})`));let r=await Os();if(r.kind==="started"){console.log(X.green(`\u2713 Bot restarted (PID ${r.pid})`));return}console.error(X.red(`\u2717 Restart failed: ${r.message}`)),process.exit(1)}),t.command("status").description("Show running state, uptime, memory, and recent log entries").action(()=>{let n=Ls();rS(n)}),t.command("logs").description("Show or follow the bot log").option("-f, --follow","Stream new log entries (like tail -f)",!1).option("-n, --lines <count>","Number of trailing lines to show","50").action(n=>{let{logFile:r}=Ls();if(!tS(r)){console.log(X.yellow(`No log file at ${r}`)),console.log(X.gray("Start the bot first: afk telegram start"));return}let o=Number.parseInt(n.lines??"50",10);if(n.follow){eS("tail",["-n",String(o),"-f",r],{stdio:"inherit"}).on("error",i=>{console.error(X.red(`Failed to spawn tail: ${i.message}`))});return}let s=nS(r,"utf-8").split(`
1778
1778
  `).slice(-o-1);console.log(s.join(`
1779
- `))})}function rS(e){if(console.log(X.bold("\u{1F4CA} Telegram Bot Status")),console.log(""),e.running?(console.log(` ${X.green("\u25CF")} Running (PID ${e.pid})`),e.uptimeSec!==void 0&&console.log(` Uptime: ${oS(e.uptimeSec)}`),e.memoryMb!==void 0&&console.log(` Memory: ${e.memoryMb} MB`)):console.log(` ${X.red("\u25CF")} Stopped`),console.log(` PID: ${e.pidFile}`),console.log(` Logs: ${e.logFile}`),e.logTail&&e.logTail.length>0){console.log(""),console.log(X.bold("Recent log entries:"));for(let t of e.logTail)console.log(X.gray(` ${t}`))}}function oS(e){if(e<60)return`${e}s`;let t=Math.floor(e/60);if(t<60)return`${t}m ${e%60}s`;let n=Math.floor(t/60);return n<24?`${n}h ${t%60}m`:`${Math.floor(n/24)}d ${n%24}h`}import{readFileSync as sS}from"fs";import{dirname as iS,join as aS}from"path";import{fileURLToPath as lS}from"url";function yd(){try{return"1.8.0"}catch{}try{let e=iS(lS(import.meta.url));for(let t of["../../package.json","../package.json"])try{let n=JSON.parse(sS(aS(e,t),"utf-8"));if(typeof n.version=="string")return n.version}catch{}}catch{}return"0.0.0-unknown"}import{realpathSync as dS}from"fs";Ns();Ns({path:Ne(),override:!1});Vs();var ie=new cS;ie.name("afk").description("AI agent CLI. Starts interactive REPL by default; use `afk chat` for one-shot.").version(yd());Ll(ie);Hu(ie);ed(ie);Uu(ie);nd(ie);sd(ie);ad(ie);ju(ie);cd(ie);ud(ie);hd(ie);ie.commands.find(e=>e.name()==="chat")?.alias("c");ie.commands.find(e=>e.name()==="interactive")?.alias("i");ie.commands.find(e=>e.name()==="status")?.alias("s");ie.addHelpText("after",`
1779
+ `))})}function rS(e){if(console.log(X.bold("\u{1F4CA} Telegram Bot Status")),console.log(""),e.running?(console.log(` ${X.green("\u25CF")} Running (PID ${e.pid})`),e.uptimeSec!==void 0&&console.log(` Uptime: ${oS(e.uptimeSec)}`),e.memoryMb!==void 0&&console.log(` Memory: ${e.memoryMb} MB`)):console.log(` ${X.red("\u25CF")} Stopped`),console.log(` PID: ${e.pidFile}`),console.log(` Logs: ${e.logFile}`),e.logTail&&e.logTail.length>0){console.log(""),console.log(X.bold("Recent log entries:"));for(let t of e.logTail)console.log(X.gray(` ${t}`))}}function oS(e){if(e<60)return`${e}s`;let t=Math.floor(e/60);if(t<60)return`${t}m ${e%60}s`;let n=Math.floor(t/60);return n<24?`${n}h ${t%60}m`:`${Math.floor(n/24)}d ${n%24}h`}import{readFileSync as sS}from"fs";import{dirname as iS,join as aS}from"path";import{fileURLToPath as lS}from"url";function yd(){try{return"1.8.1"}catch{}try{let e=iS(lS(import.meta.url));for(let t of["../../package.json","../package.json"])try{let n=JSON.parse(sS(aS(e,t),"utf-8"));if(typeof n.version=="string")return n.version}catch{}}catch{}return"0.0.0-unknown"}import{realpathSync as dS}from"fs";Ns();Ns({path:Ne(),override:!1});Vs();var ie=new cS;ie.name("afk").description("AI agent CLI. Starts interactive REPL by default; use `afk chat` for one-shot.").version(yd());Ll(ie);Hu(ie);ed(ie);Uu(ie);nd(ie);sd(ie);ad(ie);ju(ie);cd(ie);ud(ie);hd(ie);ie.commands.find(e=>e.name()==="chat")?.alias("c");ie.commands.find(e=>e.name()==="interactive")?.alias("i");ie.commands.find(e=>e.name()==="status")?.alias("s");ie.addHelpText("after",`
1780
1780
  Examples:
1781
1781
  $ afk # start interactive REPL
1782
1782
  $ afk --model opus # REPL with specific model
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-afk",
3
- "version": "1.8.0",
3
+ "version": "1.8.1",
4
4
  "description": "CLI tool for interacting with AI agents via multiple interfaces",
5
5
  "main": "dist/index.mjs",
6
6
  "type": "module",
@@ -14,17 +14,17 @@
14
14
  "postinstall": "node dist/postinstall.mjs || true",
15
15
  "build": "tsc && node scripts/copy-prompts.js",
16
16
  "dev": "tsx watch src/cli/index.ts",
17
- "start": "node dist/cli/index.js",
18
- "start:chat": "node dist/cli/index.js chat",
19
- "start:interactive": "node dist/cli/index.js interactive",
20
- "start:status": "node dist/cli/index.js status",
21
- "telegram": "node dist/cli/index.js telegram start",
22
- "telegram:setup": "node dist/cli/index.js telegram setup",
23
- "telegram:start": "node dist/cli/index.js telegram start",
24
- "telegram:stop": "node dist/cli/index.js telegram stop",
25
- "telegram:status": "node dist/cli/index.js telegram status",
26
- "telegram:restart": "node dist/cli/index.js telegram restart",
27
- "telegram:logs": "node dist/cli/index.js telegram logs",
17
+ "start": "node dist/cli.mjs",
18
+ "start:chat": "node dist/cli.mjs chat",
19
+ "start:interactive": "node dist/cli.mjs interactive",
20
+ "start:status": "node dist/cli.mjs status",
21
+ "telegram": "node dist/cli.mjs telegram start",
22
+ "telegram:setup": "node dist/cli.mjs telegram setup",
23
+ "telegram:start": "node dist/cli.mjs telegram start",
24
+ "telegram:stop": "node dist/cli.mjs telegram stop",
25
+ "telegram:status": "node dist/cli.mjs telegram status",
26
+ "telegram:restart": "node dist/cli.mjs telegram restart",
27
+ "telegram:logs": "node dist/cli.mjs telegram logs",
28
28
  "test": "vitest run",
29
29
  "test:integration": "vitest run tests/integration",
30
30
  "test:e2e": "vitest run tests/e2e",