tg-agent 1.2.5 → 1.2.6

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.
package/dist/cli.js CHANGED
@@ -1,3 +1,40 @@
1
1
  #!/usr/bin/env node
2
- import u from"node:fs";import i from"node:path";import g from"node:readline/promises";import{fileURLToPath as _}from"node:url";import{applyConfigDefaults as d,getDefaultConfigFile as m,loadConfigFile as a,readTelegramToken as T,refreshConfig as v,saveConfigFile as c,setTelegramToken as E}from"./config.js";const p=process.argv.slice(2),l=(e,t)=>p.includes(e)||(t?p.includes(t):!1),h=l("--help","-h"),y=l("--version","-v"),w=["Usage: tg-agent [options]","","Options:"," -h, --help Show help"," -v, --version Show version"].join(`
3
- `),R=()=>{if(process.env.npm_package_version)return process.env.npm_package_version;try{const e=_(import.meta.url),t=i.dirname(e),s=i.join(t,"..","package.json"),n=u.readFileSync(s,"utf8"),o=JSON.parse(n);if(o.version)return o.version}catch{}return"dev"};h&&(console.log(w),process.exit(0)),y&&(console.log(R()),process.exit(0));async function C(){const e=g.createInterface({input:process.stdin,output:process.stdout});try{return(await e.question("Enter TELEGRAM_BOT_TOKEN: ")).trim()}finally{e.close()}}async function O(){const{configPath:e,data:t,exists:s}=a(),n=m(),o=s?t:n,f=d(o,n);if(T(o)){f&&await c(e,o);return}process.stdin.isTTY||(console.error(`Missing telegram.bot_token in ${e}.`),process.exit(1));const r=await C();r||(console.error("Empty TELEGRAM_BOT_TOKEN."),process.exit(1)),E(o,r),await c(e,o),console.log(`Saved config to ${e}.`)}async function k(){const{data:e}=a(),t=typeof e.tls=="object"&&e.tls?e.tls:{},s=typeof t.extra_ca_certs=="string"?t.extra_ca_certs.trim():"";if(s&&(process.env.NODE_EXTRA_CA_CERTS=s),typeof t.reject_unauthorized=="boolean"){process.env.NODE_TLS_REJECT_UNAUTHORIZED=t.reject_unauthorized?"1":"0";return}const n=typeof t.reject_unauthorized=="string"?t.reject_unauthorized.trim():"";n&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED=n)}await O(),await k(),v(),import("./index.js");
2
+ var H=(e,t)=>()=>(e&&(t=e(e=0)),t);import $e from"node:fs/promises";import dn from"node:os";import de from"node:path";import{randomUUID as Ke}from"node:crypto";function N(){return Date.now()}function B(e){return e.startsWith("~")?de.join(dn.homedir(),e.slice(1)):e}async function z(e){await $e.mkdir(e,{recursive:!0})}async function qe(e,t){let n=de.dirname(e),o=`${de.basename(e)}.${Ke()}.tmp`,r=de.join(n,o),s=JSON.stringify(t,null,2);await $e.writeFile(r,s,"utf8"),await $e.rename(r,e)}function se(){return Ke().split("-")[0]}function Je(e,t){if(e.length<=t)return[e];let n=[],o=e;for(;o.length>t;){let r=o.slice(0,t),s=r.lastIndexOf(`
3
+ `);s>t*.6&&(r=r.slice(0,s)),n.push(r),o=o.slice(r.length)}return o.length>0&&n.push(o),n}function Ge(){let e=new Map;return async function(n,o){let s=(e.get(n)??Promise.resolve()).then(o,o);e.set(n,s);try{return await s}finally{e.get(n)===s&&e.delete(n)}}}function Ve(e){let t=0,n=[],o=()=>{if(t>=e)return;let r=n.shift();r&&(t+=1,r())};return async function(s){await new Promise(a=>{n.push(a),o()});try{return await s()}finally{t=Math.max(0,t-1),o()}}}var Y=H(()=>{"use strict"});import Xe from"node:fs";import ge from"node:path";import*as pe from"@iarna/toml";function Ze(){let e=B(Qe);return ge.join(e,mn)}function j(e,t){let n=e[t];return n&&typeof n=="object"&&!Array.isArray(n)?n:{}}function O(e,t){return typeof e=="string"?e:typeof e=="number"||typeof e=="boolean"?String(e):t}function G(e,t){if(typeof e=="number"&&Number.isFinite(e))return e;if(typeof e=="string"){let n=Number.parseInt(e,10);return Number.isNaN(n)?t:n}return t}function Pe(e,t){if(typeof e=="boolean")return e;if(typeof e=="string"){let n=e.trim().toLowerCase();if(n==="true"||n==="1"||n==="yes")return!0;if(n==="false"||n==="0"||n==="no")return!1}return t}function gn(e){return Array.isArray(e)?e.map(t=>typeof t=="string"?t:String(t)).map(t=>t.trim()).filter(Boolean):typeof e=="string"?e.split(",").map(t=>t.trim()).filter(Boolean):[]}function pn(e){return new Set(gn(e))}function fn(e){let t=new Map;for(let[n,o]of Object.entries(e))typeof o=="string"&&o.trim()&&t.set(n,ge.resolve(B(o.trim())));return t}function ie(){let e=Ze();try{let t=Xe.readFileSync(e,"utf8"),n=pe.parse(t);return{configPath:e,data:n,exists:!0}}catch{return{configPath:e,data:{},exists:!1}}}async function Ae(e,t){await z(ge.dirname(e));let n=pe.stringify(t);await Xe.promises.writeFile(e,n,"utf8")}function et(){return{telegram:{bot_token:"",allowed_user_ids:[],parse_mode:""},model:{provider:"openai-codex",model:"gpt-5.2",openai_api_key:""},paths:{workspace_dir:"",session_dir:"~/.tg-agent/tg-sessions"},workspace_mappings:{},limits:{max_sessions:5,max_concurrent:5,max_history_messages:40,max_output_tokens:0},timeouts:{model_timeout_ms:6e4,model_timeout_stream_ms:3e5,fetch_timeout_ms:6e4},fetch:{max_bytes:2e5,proxy_url:""},proxy:{url:""},auth:{codex_home:"~/.codex"},logging:{agent_events:!0,agent_stream:!0},system:{prompt:Ye},tls:{extra_ca_certs:"",reject_unauthorized:""}}}function me(e){return!!(e&&typeof e=="object"&&!Array.isArray(e))}function tt(e,t){let n=!1,o=(r,s)=>{for(let[a,l]of Object.entries(s)){if(!(a in r)){r[a]=l,n=!0;continue}let i=r[a];me(i)&&me(l)&&o(i,l)}};return me(e)&&me(t)&&o(e,t),n}function nt(e){let t=j(e,"telegram");return O(t.bot_token,"").trim()}function ot(e,t){let n=j(e,"telegram");n.bot_token=t.trim(),e.telegram=n}function rt(e){let t=j(e,"telegram"),n=j(e,"model"),o=j(e,"paths"),r=j(e,"limits"),s=j(e,"timeouts"),a=j(e,"fetch"),l=j(e,"proxy"),i=j(e,"auth"),u=j(e,"logging"),c=j(e,"system"),g=j(e,"tls"),m=j(e,"workspace_mappings"),p=O(o.workspace_dir,process.cwd()),h=O(o.session_dir,"~/.tg-agent/tg-sessions"),v=fn(m),M=O(g.reject_unauthorized,""),_=M===""?null:Pe(M,!0);return{telegramToken:O(t.bot_token,"").trim(),telegramAllowedUsers:pn(t.allowed_user_ids),telegramParseMode:O(t.parse_mode,"").trim(),modelProvider:O(n.provider,"openai-codex").trim(),modelRef:O(n.model,"gpt-5.2").trim(),openaiApiKey:O(n.openai_api_key,"").trim(),sessionDir:B(h),agentDir:B(Qe),workspaceDir:ge.resolve(B(p)),workspaceMappings:v,maxSessions:G(r.max_sessions,5),maxConcurrent:G(r.max_concurrent,5),maxHistoryMessages:G(r.max_history_messages,40),maxOutputTokens:G(r.max_output_tokens,0),fetchMaxBytes:G(a.max_bytes,2e5),fetchTimeoutMs:G(s.fetch_timeout_ms,6e4),modelTimeoutMs:G(s.model_timeout_ms,6e4),modelTimeoutStreamingMs:G(s.model_timeout_stream_ms,3e5),systemPrompt:O(c.prompt,Ye),proxyUrl:O(l.url,"").trim(),fetchProxyUrl:O(a.proxy_url,"").trim(),codexHome:B(O(i.codex_home,"~/.codex")),logAgentEvents:Pe(u.agent_events,!0),logAgentStream:Pe(u.agent_stream,!0),tlsExtraCaCerts:O(g.extra_ca_certs,"").trim(),tlsRejectUnauthorized:_}}function st(){let{data:e}=ie();return d=rt(e),d}function it(){let e=[];if(d.telegramToken||e.push("telegram.bot_token"),e.length>0)throw new Error(`Missing config values: ${e.join(", ")} (edit ${Ze()})`)}var Qe,mn,Ye,yn,d,V=H(()=>{"use strict";Y();Qe="~/.tg-agent",mn="config.toml",Ye="You are running in user's personal computer or VPS, using telegram bot to interact with user. Be concise and practical.";({data:yn}=ie()),d=rt(yn)});import{createHash as hn}from"node:crypto";import at from"node:fs";import wn from"node:path";import{execSync as bn}from"node:child_process";function Mn(){return wn.join(d.codexHome,xn)}function vn(e){return`cli|${hn("sha256").update(e).digest("hex").slice(0,16)}`}function kn(){if(process.platform!=="darwin")return null;let e=d.codexHome,t=vn(e);try{let n=bn(`security find-generic-password -s "${Sn}" -a "${t}" -w`,{encoding:"utf8",timeout:5e3,stdio:["pipe","pipe","pipe"]}).trim(),o=JSON.parse(n),r=o.tokens,s=r?.access_token,a=r?.refresh_token;if(typeof s!="string"||!s||typeof a!="string"||!a)return null;let l=o.last_refresh,i=typeof l=="string"||typeof l=="number"?new Date(l).getTime():Date.now(),u=Number.isFinite(i)?i+3600*1e3:Date.now()+3600*1e3;return{accessToken:s,refreshToken:a,expiresAt:u,source:"keychain"}}catch{return null}}function _n(){let e=Mn();try{let t=at.readFileSync(e,"utf8"),o=JSON.parse(t).tokens,r=o?.access_token,s=o?.refresh_token;if(typeof r!="string"||!r||typeof s!="string"||!s)return null;let a=Date.now()+3600*1e3;try{a=at.statSync(e).mtimeMs+3600*1e3}catch{}return{accessToken:r,refreshToken:s,expiresAt:a,source:"file"}}catch{return null}}function Z(){return kn()??_n()}var xn,Sn,fe=H(()=>{"use strict";V();xn="auth.json",Sn="Codex Auth"});function ct(e){let t=e.trim().toLowerCase();if(t==="openai-codex"||t==="codex"){let n=Z();if(n)return{apiKey:n.accessToken,source:`codex:${n.source}`};throw new Error("No Codex OAuth credentials found. Run `codex login`.")}if(d.openaiApiKey)return{apiKey:d.openaiApiKey,source:"config.model.openai_api_key"};throw new Error(`No API key for provider: ${e}`)}function Tn(){return d.proxyUrl?{url:d.proxyUrl,source:"config.proxy.url"}:d.fetchProxyUrl?{url:d.fetchProxyUrl,source:"config.fetch.proxy_url"}:null}function lt(e){let t=e.toLowerCase();return t.startsWith("socks5://")||t.startsWith("socks4://")||t.startsWith("socks://")?"socks":t.startsWith("https://")?"https":"http"}function ut(){let e=Tn();return e?{url:e.url,kind:lt(e.url),source:e.source}:null}function dt(){let e=[{key:"config.fetch.proxy_url",value:d.fetchProxyUrl},{key:"config.proxy.url",value:d.proxyUrl}];for(let t of e){let n=t.value?.trim();if(!n)continue;let o=lt(n);if(o!=="socks")return{url:n,kind:o,source:t.key}}return null}var Ce=H(()=>{"use strict";V();fe()});import{ProxyAgent as $n,setGlobalDispatcher as Pn}from"undici";function gt(){if(mt)return Re;mt=!0;let e=dt();if(!e)return Re=null,null;let t=new $n(e.url);return Pn(t),Re=e,e}var mt,Re,pt=H(()=>{"use strict";Ce();mt=!1,Re=null});import An from"node:fs";import Cn from"node:fs/promises";import Rn from"node:path";import Dn from"node:readline";import{spawn as En}from"node:child_process";import*as yt from"@iarna/toml";function bt(e){return Rn.join(e,"config.toml")}function ye(e){let t=bt(e);try{let n=An.readFileSync(t,"utf8");return vt(n)}catch{return[]}}async function ae(e){let t=bt(e);try{let n=await Cn.readFile(t,"utf8");return vt(n)}catch{return[]}}async function ce(e,t={}){if(ee)return ee;let n=await ae(e);if(n.length===0)return ee="","";let o=t.maxTools??jn,r=t.maxChars??Fn,s=t.timeoutMs??4e3,a=t.maxBytes??ht,l=["MCP catalog (auto-discovered):","Use tool 'mcp' with server=<name> method=<tool> params=<object>."];for(let u of n){let c=await Nn(u,{timeoutMs:s,maxBytes:a});if(l.push(`${u.name} (${u.type})`),c.length===0){l.push(" - tools unavailable");continue}let g=c.slice(0,o);for(let m of g){let p=m.description?`: ${m.description}`:"";l.push(` - ${m.name}${p}`)}c.length>g.length&&l.push(` - ...and ${c.length-g.length} more`)}let i=l.join(`
4
+ `);return i.length>r&&(i=`${i.slice(0,r-20)}...
5
+ (truncated)`),ee=i,i}function Ee(){ee&&(wt=!0)}function xt(){ee=null,wt=!1,I.clear()}function Q(e){if(e.type==="http")return e.url?`url=${e.url}`:"url=(missing)";let t=e.args&&e.args.length>0?` ${e.args.join(" ")}`:"";return e.command?`command=${e.command}${t}`:"command=(missing)"}async function St(e,t=5e3){let n=Date.now();try{return await he(e,"tools/list",{},{timeoutMs:t}),{ok:!0,durationMs:Date.now()-n}}catch(o){let r=o instanceof Error?o.message:String(o);return{ok:!1,durationMs:Date.now()-n,error:r}}}async function he(e,t,n,o={}){let r=ft(o.timeoutMs??On,1e3,12e4),s=ft(o.maxBytes??ht,1024,5e6),a=new AbortController,l=()=>a.abort();o.signal?.addEventListener("abort",l,{once:!0});let i=setTimeout(()=>a.abort(),r);try{return e.type==="http"?(t!=="initialize"&&t!=="notifications/initialized"&&await Un(e,s,a.signal),await Ln(e,t,n,s,a.signal)):await Hn(e,t,n,s,a.signal)}finally{clearTimeout(i),o.signal?.removeEventListener("abort",l)}}function ft(e,t,n){return Number.isNaN(e)?t:Math.min(n,Math.max(t,e))}async function Nn(e,t){try{let n=await he(e,"tools/list",{},t);return In(n.output)}catch(n){let o=n instanceof Error?n.message:String(n);return console.warn(`[tg-agent] mcp tools/list failed server=${e.name} error=${o}`),[]}}function In(e){let t;try{t=JSON.parse(e)}catch{return[]}if(!t||typeof t!="object")return[];let n=t,r=(n.result??n).tools??n.tools;if(!Array.isArray(r))return[];let s=[];for(let a of r){if(!a||typeof a!="object")continue;let l=a,i=typeof l.name=="string"?l.name:"";if(!i)continue;let u=typeof l.description=="string"?l.description:void 0,c=l.inputSchema;s.push({name:i,description:u,inputSchema:c})}return s}async function Ln(e,t,n,o,r){if(!e.url)throw new Error("MCP server url is missing.");let s=Date.now(),a=await De(e,t,n,o,r),l=Mt(a.parsed);if(l)throw new Error(l);let i=a.bodyText;return a.parsed&&(i=JSON.stringify(a.parsed,null,2)),{ok:a.statusCode>=200&&a.statusCode<300,output:i,durationMs:Date.now()-s,bytes:a.bytes,truncated:a.truncated,statusCode:a.statusCode,statusText:a.statusText,contentType:a.contentType}}async function De(e,t,n,o,r){if(!e.url)throw new Error("MCP server url is missing.");let s=I.get(e.name),a={jsonrpc:"2.0",id:`tg-agent-${Date.now()}`,method:t,params:n??{}},l={"content-type":"application/json"};e.auth&&(l.authorization=e.auth.startsWith("Bearer ")?e.auth:`Bearer ${e.auth}`),s?.cookie&&(l.cookie=s.cookie),s?.sessionId&&(l["mcp-session-id"]=s.sessionId);let i=await fetch(e.url,{method:"POST",headers:l,body:JSON.stringify(a),signal:r});Bn(e.name,i);let u=await Kn(i,o,r),c;try{c=JSON.parse(u.text)}catch{c=void 0}return Wn(e.name,c),{statusCode:i.status,statusText:i.statusText,contentType:i.headers.get("content-type"),bodyText:u.text,parsed:c,bytes:u.bytes,truncated:u.truncated}}function Mt(e){if(!e||typeof e!="object")return null;let t=e;if(t.error&&typeof t.error=="object"){let n=t.error;if(typeof n.message=="string")return n.message}return typeof t.error_description=="string"?t.error_description:typeof t.error=="string"?t.error:null}async function Un(e,t,n){let o=I.get(e.name);if(o?.initializedAt)return;if(o?.inFlight){await o.inFlight;return}let r=(async()=>{let s=await De(e,"initialize",{protocolVersion:"2024-11-05",clientInfo:{name:"tg-agent",version:process.env.npm_package_version??"dev"},capabilities:{}},t,n),a=Mt(s.parsed);if(a){let u=a.toLowerCase();if(u.includes("method")&&u.includes("not"))return;throw new Error(a)}let l=new AbortController,i=setTimeout(()=>l.abort(),zn);try{await De(e,"notifications/initialized",{},t,l.signal)}catch{}finally{clearTimeout(i)}})();I.set(e.name,{initializedAt:Date.now(),inFlight:r});try{await r;let s=I.get(e.name);I.set(e.name,{initializedAt:Date.now(),cookie:s?.cookie,sessionId:s?.sessionId})}catch(s){throw I.delete(e.name),s}}function Bn(e,t){let o=I.get(e)??{initializedAt:0},r=t.headers.get("set-cookie"),s=t.headers.getSetCookie?.(),a=s&&s.length>0?s.join("; "):r;a&&I.set(e,{...o,cookie:a});let l=t.headers.get("mcp-session-id")??t.headers.get("x-mcp-session-id");l&&I.set(e,{...o,sessionId:l})}function Wn(e,t){if(!t||typeof t!="object")return;let o=t.result;if(!o)return;let r=typeof o.sessionId=="string"&&o.sessionId||typeof o.session_id=="string"&&o.session_id;if(!r)return;let s=I.get(e)??{initializedAt:0};I.set(e,{...s,sessionId:r})}async function Hn(e,t,n,o,r){if(!e.command)throw new Error("MCP server command is missing.");let s=Date.now(),a=En(e.command,e.args??[],{stdio:["pipe","pipe","pipe"]}),l=()=>{a.killed||a.kill("SIGTERM")};if(r.aborted)throw l(),new Error("MCP request aborted.");let i=new Map,u=!1,c="",g=new Error("MCP request aborted."),m=Dn.createInterface({input:a.stdout,terminal:!1});m.on("line",b=>{if(b.length>o){u=!0;return}let S=null;try{S=JSON.parse(b)}catch{return}let k=typeof S.id=="string"?S.id:typeof S.id=="number"?String(S.id):"";if(!k)return;let P=i.get(k);P&&(i.delete(k),P.resolve(S))}),a.stderr?.on("data",b=>{let S=b.toString();if(c.length+S.length>o){u=!0;return}c+=S});let p=()=>{for(let b of i.values())b.reject(g);i.clear(),l()};r.addEventListener("abort",p,{once:!0});let h=b=>{let S=b===0?"MCP stdio exited.":c.trim()||"MCP stdio exited with error.";for(let k of i.values())k.reject(new Error(S));i.clear()};a.once("exit",b=>h(b));let v=async(b,S)=>{let k=`tg-agent-${Date.now()}-${Math.random().toString(16).slice(2,8)}`,P={jsonrpc:"2.0",id:k,method:b,params:S??{}};return await new Promise((y,w)=>{i.set(k,{resolve:y,reject:w}),a.stdin?.write(`${JSON.stringify(P)}
6
+ `)})};fetch("http://127.0.0.1:7243/ingest/9e452bb4-cc67-4519-89fa-8fb51d810231",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({location:"mcp.ts:callStdioMcp:beforeInit",message:"sending initialize request",data:{elapsed:Date.now()-s},timestamp:Date.now(),sessionId:"debug-session",hypothesisId:"B,C"})}).catch(()=>{});let M=await v("initialize",{protocolVersion:"2024-11-05",clientInfo:{name:"tg-agent",version:process.env.npm_package_version??"dev"},capabilities:{}});if(fetch("http://127.0.0.1:7243/ingest/9e452bb4-cc67-4519-89fa-8fb51d810231",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({location:"mcp.ts:callStdioMcp:afterInit",message:"initialize response received",data:{elapsed:Date.now()-s,hasError:!!M.error},timestamp:Date.now(),sessionId:"debug-session",hypothesisId:"B,C"})}).catch(()=>{}),M.error&&typeof M.error=="object"){let b=M.error.message??"MCP initialize failed.";throw l(),new Error(String(b))}let _={jsonrpc:"2.0",method:"notifications/initialized"};a.stdin?.write(`${JSON.stringify(_)}
7
+ `),fetch("http://127.0.0.1:7243/ingest/9e452bb4-cc67-4519-89fa-8fb51d810231",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({location:"mcp.ts:callStdioMcp:beforeMethod",message:"sending method request",data:{method:t,elapsed:Date.now()-s},timestamp:Date.now(),sessionId:"debug-session",hypothesisId:"C"})}).catch(()=>{});let E=await v(t,n);r.removeEventListener("abort",p),m.close(),a.stdin?.end(),l();let $=new Promise(b=>{a.once("exit",()=>b())});if(await Promise.race([$,new Promise(b=>setTimeout(b,500))]),E.error&&typeof E.error=="object"){let b=E.error.message??"MCP request failed.";throw new Error(String(b))}let T=JSON.stringify(E,null,2),W=T.length>o?T.slice(0,o):T;return T.length>o&&(u=!0),{ok:!0,output:W,durationMs:Date.now()-s,bytes:Math.min(T.length,o),truncated:u}}async function Kn(e,t,n){let o=e.body?.getReader?.();if(!o){let g=await e.text(),m=Math.min(g.length,t);return{text:g.slice(0,t),bytes:m,truncated:g.length>t}}let r=new TextDecoder("utf-8"),s=[],a=0,l=!1;for(;;){if(n.aborted){try{await o.cancel()}catch{}throw new Error("MCP request aborted.")}let{done:g,value:m}=await o.read();if(g)break;if(!m)continue;let p=a+m.byteLength;if(p>t){let h=Math.max(0,t-a);h>0&&(s.push(m.slice(0,h)),a+=h),l=!0;try{await o.cancel()}catch{}break}s.push(m),a=p}let i=new Uint8Array(a),u=0;for(let g of s)i.set(g,u),u+=g.byteLength;return{text:r.decode(i),bytes:a,truncated:l}}function vt(e){let t=[],n;try{n=yt.parse(e)}catch{return t}let o=n.mcp_servers;if(!o||typeof o!="object")return t;for(let[r,s]of Object.entries(o)){if(!s||typeof s!="object")continue;let a=s,l=typeof a.type=="string"?a.type.toLowerCase():void 0,i=typeof a.url=="string"?a.url:void 0,u=typeof a.command=="string"?a.command:void 0,c=l==="http"||l==="stdio"?l:i?"http":u?"stdio":void 0;if(!c||c==="http"&&!i||c==="stdio"&&!u)continue;let g;Array.isArray(a.args)&&(g=a.args.filter(p=>typeof p=="string").map(p=>p.trim()));let m=typeof a.auth=="string"?a.auth:typeof a.authorization=="string"?a.authorization:typeof a.token=="string"?a.token:void 0;t.push({name:r,type:c,url:i,command:u,args:g,auth:m})}return t}var On,ht,jn,Fn,ee,wt,I,zn,we=H(()=>{"use strict";On=6e4,ht=2e5,jn=40,Fn=3500,ee=null,wt=!1,I=new Map,zn=1500});import J from"node:path";import qn from"node:fs/promises";import{Type as x}from"@sinclair/typebox";function be(e,t,n){return Number.isNaN(e)?t:Math.min(n,Math.max(t,e))}function Vn(e){if(!e)return{};let t={};if(Array.isArray(e)){for(let n of e)n?.name&&(t[n.name]=n.value??"");return t}for(let[n,o]of Object.entries(e))n&&(t[n]=o);return t}function kt(e){let t=d.fetchTimeoutMs>0?d.fetchTimeoutMs:Gn;return be(e||t,1e3,12e4)}function _t(e){let t=d.fetchMaxBytes>0?d.fetchMaxBytes:Jn;return be(e||t,1024,5e6)}function Tt(e,t,n){let o=e.trim();if(!o)return null;let r=B(o),s=J.isAbsolute(r)?r:J.join(n,r),a=J.resolve(s);for(let l of t){let i=J.resolve(l);if(a===i||a.startsWith(`${i}${J.sep}`))return a}return null}async function $t(e){try{let t=await qn.stat(e);return t.isFile()?{bytes:t.size}:null}catch{return null}}function Xn(e){try{let t=new URL(e);return t.protocol==="http:"||t.protocol==="https:"}catch{return!1}}function Qn(e,t){let n=new Uint8Array(t),o=0;for(let r of e)n.set(r,o),o+=r.byteLength;return n}async function Yn(e,t,n){let o=e.body?.getReader?.();if(!o){let c=await e.text?.()??"",g=Math.min(c.length,t),m=c.length>t;return{text:c.slice(0,t),bytes:g,truncated:m}}let r=new TextDecoder("utf-8"),s=[],a=0,l=!1;for(;;){if(n?.aborted){try{await o.cancel?.()}catch{}throw new Error("Fetch aborted")}let{done:c,value:g}=await o.read();if(c)break;if(!g)continue;let m=a+g.byteLength;if(m>t){let p=Math.max(0,t-a);p>0&&(s.push(g.slice(0,p)),a+=p),l=!0;try{await o.cancel?.()}catch{}break}s.push(g),a=m}let i=Qn(s,a);return{text:r.decode(i),bytes:a,truncated:l}}function Zn(e,t){let n=`HTTP ${e.status} ${e.statusText}`.trim(),o=[`url: ${e.url}`,`bytes: ${e.bytes}${e.truncated?" (truncated)":""}`,`content-type: ${e.contentType??"unknown"}`];return`${n}
8
+ ${o.join(`
9
+ `)}
10
+
11
+ ${t}`}function to(){return{name:"fetch",label:"fetch",description:"Fetch a URL via HTTP(S) and return the response body.",parameters:eo,execute:async(e,t,n,o,r)=>{if(!Xn(t.url))return{content:[{type:"text",text:"Invalid URL. Only http(s) is allowed."}],details:{url:t.url,status:0,statusText:"invalid_url",bytes:0,truncated:!1,contentType:null}};let s=kt(t.timeoutMs),a=_t(t.maxBytes),l=new AbortController,i=()=>l.abort();r?.addEventListener("abort",i,{once:!0});let u=setTimeout(()=>l.abort(),s);try{n?.({content:[{type:"text",text:`Fetching ${t.url}...`}],details:{url:t.url,status:0,statusText:"pending",bytes:0,truncated:!1,contentType:null}});let c=await fetch(t.url,{method:t.method?.toUpperCase()??"GET",headers:Vn(t.headers),body:t.body,signal:l.signal}),g=await Yn(c,a,r),m=c.headers.get("content-type");return{content:[{type:"text",text:Zn({url:c.url,status:c.status,statusText:c.statusText,bytes:g.bytes,truncated:g.truncated,contentType:m},g.text)}],details:{url:c.url,status:c.status,statusText:c.statusText,bytes:g.bytes,truncated:g.truncated,contentType:m}}}catch(c){return{content:[{type:"text",text:`Fetch failed: ${c instanceof Error?c.message:String(c)}`}],details:{url:t.url,status:0,statusText:"error",bytes:0,truncated:!1,contentType:null}}}finally{clearTimeout(u),r?.removeEventListener("abort",i)}}}}function oo(e,t,n){let o=t.status>0?`HTTP ${t.status} ${t.statusText}`.trim():t.statusText,r=[`server: ${e.name}`,`type: ${e.type}`,`target: ${t.target}`,`bytes: ${t.bytes}${t.truncated?" (truncated)":""}`,`content-type: ${t.contentType??"unknown"}`];return`${o}
12
+ ${r.join(`
13
+ `)}
14
+
15
+ ${n}`}function ro(e){return{name:"mcp",label:"mcp",description:"Call an MCP endpoint via JSON-RPC.",parameters:no,execute:async(t,n,o,r,s)=>{let a=await e();if(a.length===0)return{content:[{type:"text",text:"MCP is not configured. Add [mcp_servers.*] to ~/.tg-agent/config.toml."}],details:{server:"",type:"http",target:"",status:0,statusText:"not_configured",bytes:0,truncated:!1,contentType:null}};let l=n.server?.trim()??"";if(!l)if(a.length===1)l=a[0]?.name??"";else return{content:[{type:"text",text:`Multiple MCP servers configured. Provide server name. Available: ${a.map(u=>u.name).join(", ")}`}],details:{server:"",type:"http",target:"",status:0,statusText:"server_required",bytes:0,truncated:!1,contentType:null}};let i=a.find(u=>u.name===l);if(!i)return{content:[{type:"text",text:`MCP server not found: ${l}. Available: ${a.map(u=>u.name).join(", ")}`}],details:{server:l,type:"http",target:"",status:0,statusText:"server_not_found",bytes:0,truncated:!1,contentType:null}};try{o?.({content:[{type:"text",text:`Calling MCP ${i.name} ${n.method}...`}],details:{server:i.name,type:i.type,target:Q(i),status:0,statusText:"pending",bytes:0,truncated:!1,contentType:null}});let u=await he(i,n.method,n.params??{},{timeoutMs:kt(void 0),maxBytes:_t(void 0),signal:s});return{content:[{type:"text",text:oo(i,{server:i.name,type:i.type,target:Q(i),status:u.statusCode??0,statusText:u.statusText??(u.ok?"ok":"error"),bytes:u.bytes,truncated:u.truncated,contentType:u.contentType??null},u.output)}],details:{server:i.name,type:i.type,target:Q(i),status:u.statusCode??0,statusText:u.statusText??(u.ok?"ok":"error"),bytes:u.bytes,truncated:u.truncated,contentType:u.contentType??null}}}catch(u){return{content:[{type:"text",text:`MCP failed: ${u instanceof Error?u.message:String(u)}`}],details:{server:i.name,type:i.type,target:Q(i),status:0,statusText:"error",bytes:0,truncated:!1,contentType:null}}}}}}function ao(e){let t=[d.workspaceDir,J.join(d.agentDir,"uploads")];return{name:"send_photo",label:"send_photo",description:"Send an image file to the current Telegram chat.",parameters:so,execute:async(n,o)=>{let r=Tt(o.path,t,d.workspaceDir);if(!r)return{content:[{type:"text",text:"Invalid path. Only workspace or uploads are allowed."}],details:{path:o.path,bytes:0}};let s=await $t(r);return s?(await e.sendPhoto(r,o.caption?.trim()||void 0),{content:[{type:"text",text:`Photo sent: ${J.basename(r)}`}],details:{path:r,bytes:s.bytes}}):{content:[{type:"text",text:`File not found: ${r}`}],details:{path:r,bytes:0}}}}}function co(e){let t=[d.workspaceDir,J.join(d.agentDir,"uploads")];return{name:"send_file",label:"send_file",description:"Send a file to the current Telegram chat.",parameters:io,execute:async(n,o)=>{let r=Tt(o.path,t,d.workspaceDir);if(!r)return{content:[{type:"text",text:"Invalid path. Only workspace or uploads are allowed."}],details:{path:o.path,bytes:0}};let s=await $t(r);return s?(await e.sendDocument(r,o.caption?.trim()||void 0),{content:[{type:"text",text:`File sent: ${J.basename(r)}`}],details:{path:r,bytes:s.bytes}}):{content:[{type:"text",text:`File not found: ${r}`}],details:{path:r,bytes:0}}}}}function Pt(e){let t=[to()];return e?.telegram&&(t.push(ao(e.telegram)),t.push(co(e.telegram))),ye(d.agentDir).length>0&&t.push(ro(()=>ae(d.agentDir))),t}var Jn,Gn,eo,no,so,io,At=H(()=>{"use strict";V();we();Y();Jn=2e5,Gn=6e4;eo=x.Object({url:x.String({description:"HTTP or HTTPS URL"}),method:x.Optional(x.String({description:"HTTP method (default: GET)"})),headers:x.Optional(x.Array(x.Object({name:x.String({description:"Header name"}),value:x.String({description:"Header value"})}),{description:"Request headers as name/value pairs"})),body:x.Optional(x.String({description:"Request body (string)"})),timeoutMs:x.Optional(x.Integer({description:"Timeout in milliseconds",minimum:1e3,maximum:12e4})),maxBytes:x.Optional(x.Integer({description:"Max response bytes",minimum:1024,maximum:5e6}))});no=x.Object({server:x.Optional(x.String({description:"MCP server name"})),method:x.String({description:"MCP method name"}),params:x.Optional(x.Any({description:"MCP params payload"}))});so=x.Object({path:x.String({description:"Image file path (relative to workspace or uploads)."}),caption:x.Optional(x.String({description:"Caption text (plain text)."}))}),io=x.Object({path:x.String({description:"File path (relative to workspace or uploads)."}),caption:x.Optional(x.String({description:"Caption text (plain text)."}))})});import Dt from"node:fs/promises";import Et from"node:path";function Ot(e){return Et.join(d.sessionDir,`${e}.json`)}function Ct(e){return e.replace(/[^a-zA-Z0-9_-]/g,"_")}function Oe(e,t){let n=Ct(e),o=Ct(t);return Et.join(d.sessionDir,`${n}-${o}.jsonl`)}async function le(e,t){let n=Oe(e,t);try{await Dt.unlink(n)}catch(o){if(o.code==="ENOENT")return;throw o}}function Rt(e,t){let n=t?.sessions??{},o=t?.activeSessionId??null,r=t?.workspaceDir,s={chatId:e,workspaceDir:r,activeSessionId:o,sessions:n};return(!o||!n[o])&&(s.activeSessionId=null),s}async function je(e){await z(d.sessionDir);let t=xe.get(e);if(t)return t;let n=Ot(e);try{let o=await Dt.readFile(n,"utf8"),r=JSON.parse(o),s=Rt(e,r);return xe.set(e,s),s}catch(o){if(o.code==="ENOENT"){let r=Rt(e,{});return xe.set(e,r),r}throw o}}async function D(e){await z(d.sessionDir);let t=Ot(e.chatId);await qe(t,e),xe.set(e.chatId,e)}function Fe(e){return Object.values(e.sessions).sort((t,n)=>n.updatedAt-t.updatedAt)}function ze(e){return[]}function Se(e,t){if(Object.keys(e.sessions).length>=d.maxSessions)throw new Error("Max sessions reached");let o=se(),r=N(),s={id:o,title:t&&t.length>0?t:`session-${o}`,messages:[],createdAt:r,updatedAt:r};return e.sessions[o]=s,e.activeSessionId=o,s}function jt(e,t){return e.sessions[t]?(e.activeSessionId=t,!0):!1}function te(e){return e.activeSessionId?e.sessions[e.activeSessionId]??null:null}function Ft(e,t){return e.sessions[t]?(delete e.sessions[t],e.activeSessionId===t&&(e.activeSessionId=null),!0):!1}function zt(e){e.messages=[],e.updatedAt=N()}function Ne(e,t,n){e.messages.push(t),e.messages.length>n&&(e.messages=e.messages.slice(-n)),e.updatedAt=N()}function Nt(e,t){e.workspaceDir=t}var xe,Ie=H(()=>{"use strict";V();Y();xe=new Map});import{createAgentSession as lo,discoverAuthStorage as uo,discoverModels as mo,SessionManager as go,SettingsManager as po}from"@mariozechner/pi-coding-agent";import Me from"node:fs/promises";import It from"node:path";function Lt(e){let t=e.trim().toLowerCase();return t==="codex"?"openai-codex":t}function yo(e,t){let n=e.trim();if(!n)return{provider:t,modelId:""};if(n.includes("/")){let[o,r]=n.split("/",2);return{provider:o.trim()||t,modelId:r.trim()}}return{provider:t,modelId:n}}function ho(e,t){return e!=="openai-codex"?t:fo[t]??t}function wo(e,t){let n=e.getAvailable().filter(r=>r.provider===t);return n.length>0?n[0]:e.getAll().filter(r=>r.provider===t)[0]}function bo(e,t){let n=!!t?.provider?.trim(),o=!!t?.modelId?.trim(),r=Lt(t?.provider||d.modelProvider||"openai-codex"),s=n||o?"":d.modelRef||"",{provider:a,modelId:l}=yo(s,r),i=t?.provider?r:Lt(a),u=o?t?.modelId?.trim()||"":l;if(!u){let m=wo(e,i);return m?{model:m,provider:i,modelId:m.id}:{model:void 0,provider:i,modelId:""}}let c=ho(i,u);return{model:e.find(i,c),provider:i,modelId:c}}function xo(e){let t=Z();return t?(e.setRuntimeApiKey("openai-codex",t.accessToken),{source:t.source,expiresAt:t.expiresAt}):null}function So(e){if(e?.role!=="assistant")return"";let n=e.content;if(typeof n=="string")return n.trim();if(!Array.isArray(n))return"";let o=n.filter(s=>typeof s=="object"&&s&&s.type==="text").map(s=>s.text??"").map(s=>s.trim()).filter(Boolean);if(o.length>0)return o.join(`
16
+
17
+ `);let r=n.filter(s=>typeof s=="object"&&s&&s.type==="thinking").map(s=>s.thinking??"").map(s=>s.trim()).filter(Boolean);return r.length>0?r.join(`
18
+
19
+ `):""}function Mo(e){if(e.length===0)return"messages=0";let t=e.slice(-6).map(n=>{let o=n?.role??"unknown",r=n.content,s=n?.stopReason,a=n?.errorMessage;if(typeof r=="string")return`${o}(text:${r.length}${s?`,stop=${s}`:""})`;if(Array.isArray(r)){let i=[`blocks:${r.map(u=>typeof u=="object"&&u&&"type"in u?String(u.type||"unknown"):typeof u).join(",")||"none"}`,s?`stop=${s}`:null,a?"error=1":null].filter(Boolean).join(",");return`${o}(${i})`}if(r==null){let l=["empty",s?`stop=${s}`:null,a?"error=1":null].filter(Boolean).join(",");return`${o}(${l})`}return`${o}(${typeof r}${s?`,stop=${s}`:""})`});return`messages=${e.length} last=[${t.join(" ")}]`}function vo(e){let t=e.trim();return t.toLowerCase().includes("usage limit")?`${t}
20
+
21
+ Suggestion: wait for the limit to reset or switch to another provider/model.`:t}function ko(e,t){let n=t?.getLastAssistantText?.();if(n?.trim())return n.trim();for(let o=e.length-1;o>=0;o-=1){let r=So(e[o]);if(r)return r}return""}function _o(e){for(let t=e.length-1;t>=0;t-=1)if(e[t]?.role==="assistant")return e[t]}async function Ut(e){let t=e.workspaceDir||d.workspaceDir;await z(d.sessionDir),await z(d.agentDir),await z(t);let n=Oe(e.chatId,e.sessionId),o=uo(d.agentDir),r=xo(o);r&&console.log(`[tg-agent] codex oauth source=${r.source} expiresAt=${new Date(r.expiresAt).toISOString()}`);let s=mo(o,d.agentDir),{model:a,provider:l,modelId:i}=bo(s,{provider:e.modelProvider,modelId:e.modelId});i&&!a&&console.warn(`[tg-agent] model not found: ${l}/${i}`);let u=go.open(n),c=po.create(t,d.agentDir);try{let y=It.join(d.agentDir,"skills"),w=It.join(t,".pi","skills"),A=await Me.access(y).then(()=>!0).catch(()=>!1),C=await Me.access(w).then(()=>!0).catch(()=>!1);if(A){let q=(await Me.readdir(y,{withFileTypes:!0})).filter(U=>U.isDirectory()).map(U=>U.name);console.log(`[tg-agent] skills directory found at ${y} with ${q.length} skill(s): ${q.join(", ")}`)}else console.log(`[tg-agent] skills directory not found at ${y}`);if(C){let q=(await Me.readdir(w,{withFileTypes:!0})).filter(U=>U.isDirectory()).map(U=>U.name);console.log(`[tg-agent] workspace skills directory found at ${w} with ${q.length} skill(s): ${q.join(", ")}`)}let L=c.getSettings?.();if(L){let q=L.skills?.enabled!==!1;console.log(`[tg-agent] skills enabled in settings: ${q}`)}}catch(y){let w=y instanceof Error?y.message:String(y);console.warn(`[tg-agent] skills check failed: ${w}`)}let g="";try{g=await ce(d.agentDir,{timeoutMs:4e3,maxBytes:d.fetchMaxBytes,maxChars:3e3})}catch(y){let w=y instanceof Error?y.message:String(y);console.warn(`[tg-agent] mcp catalog error: ${w}`)}let{session:m,modelFallbackMessage:p}=await lo({cwd:t,agentDir:d.agentDir,authStorage:o,modelRegistry:s,model:a??void 0,sessionManager:u,settingsManager:c,customTools:Pt({telegram:e.telegram}),systemPrompt:y=>{let w=e.systemPrompt?.trim(),A=[y];return w&&A.push(w),g&&A.push(g),A.join(`
22
+
23
+ `)}});try{let y=m.messages,w=y.some(R=>{let q=R.role,U=R.content;return q==="system"&&typeof U=="string"?U.toLowerCase().includes("compaction")||U.toLowerCase().includes("compact"):R.type==="compaction"||R.compaction!==void 0});console.log(`[tg-agent] session manager type: ${typeof u}`),console.log(`[tg-agent] session messages count: ${y.length}`),console.log(`[tg-agent] compacting support detected: ${w||"unknown (will be detected during runtime)"}`);let C=typeof u.compact=="function",L=typeof u.appendCompaction=="function";console.log(`[tg-agent] SessionManager.compact method: ${C}`),console.log(`[tg-agent] SessionManager.appendCompaction method: ${L}`)}catch(y){let w=y instanceof Error?y.message:String(y);console.warn(`[tg-agent] compacting check failed: ${w}`)}p&&console.warn(`[tg-agent] modelFallback=${p}`);let h=!1,v=()=>{h=!0,m.abort()};e.onAbortReady?.(v);let M=d.logAgentEvents,_=d.logAgentStream,E=new Map,$=m.subscribe(y=>{switch(y.type){case"agent_start":M&&console.log(`[tg-agent] agent start session=${e.sessionId}`),P=Date.now(),e.onStatus?.({type:"agent_start"});break;case"agent_end":M&&console.log(`[tg-agent] agent end session=${e.sessionId}`),e.onStatus?.({type:"agent_end"});break;case"turn_start":M&&console.log(`[tg-agent] turn start session=${e.sessionId}`),P=Date.now(),e.onStatus?.({type:"turn_start"});break;case"turn_end":M&&console.log(`[tg-agent] turn end session=${e.sessionId} toolResults=${y.toolResults.length}`),P=Date.now(),e.onStatus?.({type:"turn_end",toolResults:y.toolResults.length});break;case"message_start":{if(M){let w=y.message.role??"unknown";console.log(`[tg-agent] message start session=${e.sessionId} role=${w}`)}P=Date.now();{let w=y.message.role??"unknown";e.onStatus?.({type:"message_start",role:w})}break}case"message_end":{if(M){let w=y.message.role??"unknown";console.log(`[tg-agent] message end session=${e.sessionId} role=${w}`)}P=Date.now();{let w=y.message.role??"unknown";e.onStatus?.({type:"message_end",role:w})}break}case"message_update":{if(!_)break;if(y.assistantMessageEvent.type==="text_delta"){let A=(y.assistantMessageEvent.delta??"").length;A>0&&console.log(`[tg-agent] stream delta session=${e.sessionId} chars=${A}`),P=Date.now()}y.assistantMessageEvent.type==="thinking_delta"&&(P=Date.now());break}case"tool_execution_start":{E.set(y.toolCallId,Date.now()),console.log(`[tg-agent] tool start name=${y.toolName} id=${y.toolCallId}`),re+=1,P=Date.now(),e.onStatus?.({type:"tool_start",name:y.toolName,id:y.toolCallId,args:y.args});break}case"tool_execution_end":{let w=E.get(y.toolCallId),A=w?Date.now()-w:0;console.log(`[tg-agent] tool end name=${y.toolName} id=${y.toolCallId} ok=${!y.isError} durationMs=${A}`),E.delete(y.toolCallId),re=Math.max(0,re-1),P=Date.now(),e.onStatus?.({type:"tool_end",name:y.toolName,id:y.toolCallId,ok:!y.isError,durationMs:A});break}case"auto_compaction_start":{let w=y.reason??"unknown";console.log(`[tg-agent] auto compaction started session=${e.sessionId} reason=${w}`),P=Date.now();break}case"auto_compaction_end":{let w=y.willRetry??!1;console.log(`[tg-agent] auto compaction ended session=${e.sessionId} willRetry=${w}`),P=Date.now();break}default:break}}),T=null,W=null,b=!1,S=0,k=!1,P=Date.now(),re=0;try{let y=Date.now();T=setInterval(()=>{let C=Date.now()-y;console.log(`[tg-agent] prompt running session=${e.sessionId} elapsedMs=${C} streaming=${m.isStreaming}`),e.onStatus?.({type:"heartbeat",elapsedMs:C,streaming:m.isStreaming})},15e3),W=setInterval(()=>{if(b||re>0)return;let C=Date.now()-P,L=m.isStreaming?d.modelTimeoutStreamingMs:d.modelTimeoutMs,R=Math.max(1e3,L);C>=R&&(b=!0,S=R,k=m.isStreaming,console.warn(`[tg-agent] model timeout session=${e.sessionId} elapsedMs=${C}`),m.abort())},2e3);try{if(await m.prompt(e.prompt,e.images&&e.images.length>0?{images:e.images}:void 0),b)throw new Error(`Model request timed out after ${d.modelTimeoutMs}ms`)}catch(C){if(h)throw new Error("Cancelled by user.");if(b){let L=k?" (streaming)":"",R=S||d.modelTimeoutMs;throw new Error(`Model request timed out after ${R}ms${L}`)}throw C}T&&clearInterval(T);let w=_o(m.messages);if(w){let C=w?.stopReason,L=w?.errorMessage;if(C==="error"){let R=L?vo(L):"Model error without details.";throw console.warn(`[tg-agent] model error session=${e.sessionId} error=${R}`),new Error(R)}}let A=ko(m.messages,m);if(!A){let C=Mo(m.messages);throw console.warn(`[tg-agent] empty response session=${e.sessionId} ${C}`),new Error("No assistant response.")}return{text:A,sessionFile:n,sessionId:m.sessionId,modelProvider:m.model?.provider??l,modelId:m.model?.id??i,modelFallbackMessage:p}}finally{T&&clearInterval(T),W&&clearInterval(W),$(),u.flushPendingToolResults?.(),m.dispose()}}var fo,Bt=H(()=>{"use strict";V();fe();At();we();Y();Ie();fo={"codex-mini-latest":"gpt-5.1-codex-mini","codex-max-latest":"gpt-5.1-codex-max","codex-latest":"gpt-5.2-codex"}});var Sr={};import ke from"node:path";import Wt from"node:fs/promises";import To from"node-telegram-bot-api";import{discoverAuthStorage as $o,discoverModels as Po}from"@mariozechner/pi-coding-agent";import{getOAuthProviders as Ao}from"@mariozechner/pi-ai";function Ro(e,t){We.set(e,t)}function Do(e){We.delete(e)}function Eo(e){let t=e.trim();if(t){if(t==="Markdown"||t==="MarkdownV2"||t==="HTML")return t;console.warn(`[tg-agent] invalid TELEGRAM_PARSE_MODE=${t}, ignoring`)}}function jo(){return ke.join(d.agentDir,"uploads")}function Fo(e){return e.length===0?null:e.reduce((t,n)=>{let o=t.file_size??t.width*t.height;return(n.file_size??n.width*n.height)>o?n:t})}function zo(e){return!!e?.startsWith("image/")}function No(e){switch(ke.extname(e).toLowerCase()){case".png":return"image/png";case".jpg":case".jpeg":return"image/jpeg";case".webp":return"image/webp";case".gif":return"image/gif";default:return}}function Io(e){if(!Number.isFinite(e)||e<=0)return"0 B";let t=["B","KB","MB","GB"],n=e,o=0;for(;n>=1024&&o<t.length-1;)n/=1024,o+=1;return`${n.toFixed(n>=10||o===0?0:1)} ${t[o]}`}function Lo(e){return e.length===0?"":e.map(t=>{let n=[];t.mimeType&&n.push(t.mimeType),t.bytes>0&&n.push(Io(t.bytes));let o=n.length>0?` (${n.join(", ")})`:"";return`Attachment saved: ${t.path}${o}`}).join(`
24
+ `)}function Uo(e){let t=[];if(e.photo&&e.photo.length>0){let n=Fo(e.photo);n&&t.push({kind:"photo",fileId:n.file_id,fileSize:n.file_size})}if(e.document&&t.push({kind:"document",fileId:e.document.file_id,fileName:e.document.file_name,mimeType:e.document.mime_type,fileSize:e.document.file_size}),e.audio){let n=e.audio.mime_type?.split("/")[1]??"mp3",o=e.audio.title??e.audio.performer??"audio";t.push({kind:"document",fileId:e.audio.file_id,fileName:`${o}.${n}`,mimeType:e.audio.mime_type,fileSize:e.audio.file_size})}if(e.voice&&t.push({kind:"document",fileId:e.voice.file_id,fileName:`voice.${e.voice.mime_type?.split("/")[1]??"ogg"}`,mimeType:e.voice.mime_type,fileSize:e.voice.file_size}),e.video){let n=e.video.mime_type?.split("/")[1]??"mp4";t.push({kind:"document",fileId:e.video.file_id,fileName:`video.${n}`,mimeType:e.video.mime_type,fileSize:e.video.file_size})}return e.video_note&&t.push({kind:"document",fileId:e.video_note.file_id,fileName:"video_note.mp4",mimeType:"video/mp4",fileSize:e.video_note.file_size}),t}async function Bo(e){if(e.length===0)return{resolved:[],images:[]};let t=jo();await z(t);let n=[],o=[];for(let r of e)try{let s=await F.downloadFile(r.fileId,t),a=await Wt.stat(s),l=r.fileName??ke.basename(s),i=r.mimeType??No(s),u=r.kind==="photo"||zo(i),c={path:s,name:l,mimeType:i,bytes:a.size,isImage:u};if(n.push(c),u){let g=await Wt.readFile(s);o.push({type:"image",data:g.toString("base64"),mimeType:i??Oo})}}catch(s){console.warn("[tg-agent] attachment download failed",s)}return{resolved:n,images:o}}function ue(e,t){let n=0;for(let o=0;o<e.length;o+=1){let r=e[o];if(r==="\\"){o+=1;continue}r===t&&(n+=1)}return n}function Ho(e){if(ue(e,"*")%2!==0||ue(e,"_")%2!==0||ue(e,"`")%2!==0)return!1;let r=ue(e,"["),s=ue(e,"]");return r===s}function Ko(e){for(let t=0;t<e.length;t+=1){let n=e[t];if(n==="\\"){t+=1;continue}if(Wo.has(n))return!1}return!0}function Xt(e){let t=Eo(d.telegramParseMode);return t?[t]:Ko(e)?["MarkdownV2","Markdown"]:Ho(e)?["Markdown"]:[]}function oe(e){let t=e.trim().toLowerCase();return Jo.get(t)??t}function Vo(e,t){return e!=="openai-codex"?t:Go[t]??t}async function ne(){await z(d.agentDir);let e=$o(d.agentDir),t=Z();t&&e.setRuntimeApiKey("openai-codex",t.accessToken);let n=Po(e,d.agentDir);return{authStorage:e,modelRegistry:n}}function Qt(e){let t=X.get(e);t&&(clearTimeout(t.timeoutId),X.delete(e))}function Xo(e,t){let n=X.get(e);n&&(clearTimeout(n.timeoutId),X.delete(e),n.reject(new Error(t)))}async function Ht(e,t,n,o){if(X.has(e))throw new Error("Login is already awaiting input.");let r=n.placeholder?`${n.message} (${n.placeholder})`:n.message;return await f(t,r,o),await new Promise((s,a)=>{let l=setTimeout(()=>{X.delete(e),a(new Error("Login prompt timed out."))},qo);X.set(e,{resolve:s,reject:a,timeoutId:l,chatId:t})})}async function Yt(e,t,n){let o=We.get(t);if(!o){await f(e,"No active request to stop.",n);return}o.cancelRequested=!0,o.abortRequested=!0,o.status&&o.status.update("Cancelled by user.",!0),o.abort&&o.abort(),(!o.status||o.chatId!==e)&&await f(e,"Stopping current request...",n)}function Qo(){console.log(`[tg-agent] modelProvider=${d.modelProvider} modelRef=${d.modelRef} sessionDir=${d.sessionDir} maxConcurrent=${d.maxConcurrent}`),console.log(`[tg-agent] agentDir=${d.agentDir} workspaceDir=${d.workspaceDir}`);let e=ye(d.agentDir),t=e.length>0?`on (${e.length})`:"off";console.log(`[tg-agent] tools fetchMaxBytes=${d.fetchMaxBytes} fetchTimeoutMs=${d.fetchTimeoutMs} mcp=${t}`),console.log(`[tg-agent] proxy url=${d.proxyUrl||"(none)"} fetchProxy=${d.fetchProxyUrl||"(none)"}`),console.log(`[tg-agent] tls extra_ca=${d.tlsExtraCaCerts||"(empty)"} reject_unauthorized=${d.tlsRejectUnauthorized===null?"(unset)":String(d.tlsRejectUnauthorized)}`);try{let{source:o}=ct(d.modelProvider);console.log(`[tg-agent] authSource=${o}`)}catch(o){let r=o instanceof Error?o.message:String(o);console.warn(`[tg-agent] authSource=missing (${r})`)}let n=ut();console.log(n?`[tg-agent] proxyUrl=${n.url} kind=${n.kind} source=${n.source}`:"[tg-agent] proxyUrl=(none)")}function He(e){if(!e.startsWith("/"))return null;let t=e.trim(),[n,...o]=t.split(" ");return{command:n.split("@")[0].slice(1).toLowerCase(),args:o.join(" ").trim()}}async function Kt(e,t,n){let o=te(e);return o||(o=Se(e,""),await D(e),await f(t,`Created session ${o.id}.`,n)),o}function Yo(e,t){let n=e.getAll(),o=new Map;for(let r of n){let s=o.get(r.provider)??{count:0,auth:t.hasAuth(r.provider)};s.count+=1,o.set(r.provider,s)}return Array.from(o.entries()).sort((r,s)=>r[0].localeCompare(s[0])).map(([r,s])=>({label:`${r} (${s.count}, ${s.auth?"ok":"no auth"})`,command:`/provider ${r}`}))}function Zo(e,t,n=[]){let o=e.getAll().filter(l=>l.provider===t).sort((l,i)=>l.id.localeCompare(i.id));if(n.length===0)return o.map(l=>({label:l.id,command:`/model ${t}/${l.id}`}));let r=new Map(o.map(l=>[l.id,l])),s=new Set,a=[];for(let l of n){let i=r.get(l);!i||s.has(i.id)||(s.add(i.id),a.push(i))}for(let l of o)s.has(l.id)||a.push(l);return a.map(l=>({label:l.id,command:`/model ${t}/${l.id}`}))}function er(e,t,n=3){let o=new Set,r=[],s=Fe(e);for(let a of s){if(a.modelProvider!==t)continue;let l=a.modelId;if(!(!l||o.has(l))&&(o.add(l),r.push(l),r.length>=n))break}return r}function tr(e){let t=e.trim();if(!t)return null;if(t.includes("/")){let[n,o]=t.split("/",2);return!n||!o?null:{provider:oe(n),modelId:o.trim()}}return{modelId:t}}function Zt(e,t){let n=Date.now(),o=qt.get(e)??0;n-o<nr||(qt.set(e,n),console.warn(`[tg-agent] unauthorized user=${e} chat=${t}`))}function en(e){let t=d.telegramAllowedUsers;return!t||t.size===0?!0:t.has(e)}function or(e){return e.length===0?"No sessions found.":["Sessions:",...e.map(n=>{let o=new Date(n.updatedAt).toISOString();return`- ${n.id} | ${n.title} | updated ${o}`})].join(`
25
+ `)}function _e(e,t,n){let o=String(e);return t!==void 0&&!n?null:t!==void 0&&n?`${o}_${t}`:o}function Be(e,t){if(t.workspaceDir)return t.workspaceDir;let n=d.workspaceMappings.get(e);return n||d.workspaceDir}async function tn(e,t,n,o){let r={};return n&&(r.parse_mode=n),o!==void 0&&(r.message_thread_id=o),await F.sendMessage(e,t,r)}async function nn(e,t,n,o,r){let s={chat_id:e,message_id:t};o&&(s.parse_mode=o),r!==void 0&&(s.message_thread_id=r),await F.editMessageText(n,s)}async function on(e,t){let n;for(let o of t)try{return await e(o)}catch(r){n=r;let s=r instanceof Error?r.message:String(r);console.warn(`[tg-agent] parse_mode ${o} failed, trying fallback: ${s}`)}try{return await e(void 0)}catch(o){if(n){let r=o instanceof Error?o.message:String(o);console.warn(`[tg-agent] parse_mode fallback to plain failed: ${r}`)}throw o}}async function rr(e,t,n){return await on(o=>tn(e,t,o,n),Xt(t))}async function sr(e,t,n,o){await on(r=>nn(e,t,n,r,o),Xt(n))}async function f(e,t,n){let o=Je(t,3900);for(let r of o)await rr(e,r,n)}function ar(){let e=N()-rn;for(let[o,r]of K)r.createdAt<e&&K.delete(o);if(K.size<=Jt)return;let t=Array.from(K.entries()).sort((o,r)=>o[1].createdAt-r[1].createdAt),n=K.size-Jt;for(let o=0;o<n;o+=1)K.delete(t[o][0])}function cr(e){ar();let t=se();for(;K.has(t);)t=se();return K.set(t,{command:e,createdAt:N()}),t}function lr(e){if(!e.startsWith("cmd:"))return null;let t=e.slice(4),n=K.get(t);return n?N()-n.createdAt>rn?(K.delete(t),null):n.command:null}function ur(e,t){if(e.length<=t)return[e];let n=[];for(let o=0;o<e.length;o+=t)n.push(e.slice(o,o+t));return n}function dr(e,t){let n=[],o=[];for(let r of e){let s=cr(r.command);o.push({text:r.label,callback_data:`cmd:${s}`}),o.length>=t&&(n.push(o),o=[])}return o.length>0&&n.push(o),n}async function mr(e,t,n,o){let r={reply_markup:{inline_keyboard:n}};return o!==void 0&&(r.message_thread_id=o),await F.sendMessage(e,t,r)}async function Gt(e,t,n,o){let r=o?.perRow??1,s=o?.pageSize??ir,a=o?.footer,l=o?.messageThreadId,i=ur(n,s);for(let u=0;u<i.length;u+=1){let c=i[u],g=i.length>1?` (page ${u+1}/${i.length})`:"",m=[`${t}${g}`];a&&m.push(a);let p=dr(c,r);await mr(e,m.join(`
26
+ `),p,l)}}function Ue(e,t=gr){return e.length<=t?{text:e,truncated:!1}:{text:`${e.slice(0,Math.max(0,t-15))}...
27
+
28
+ [truncated]`,truncated:!0}}async function fr(e,t){let n="Working...",r=(await tn(e,n,void 0,t)).message_id,s=n,a=0,l=Promise.resolve(),i=(c,g=!1)=>{let m=Date.now();!g&&m-a<pr||c!==s&&(s=c,a=m,l=l.then(async()=>{await nn(e,r,c,void 0,t)}).catch(p=>{console.warn("[tg-agent] status edit failed",p)}))},u=c=>{s=c,a=Date.now(),l=l.then(async()=>{await sr(e,r,c,t)}).catch(g=>{console.warn("[tg-agent] status edit failed",g)})};return{update:(c,g=!1)=>{let m=Ue(c).text;i(m,g)},finalize:async c=>{let g=Ue(c).text;u(g),await l},fail:async c=>{let g=Ue(c).text;u(g),await l}}}function yr(e){switch(e.type){case"agent_start":return"Working...";case"tool_start":return`Running tool: ${e.name}
29
+ args: ${hr(e.args)}`;case"tool_end":return e.ok?`Tool finished: ${e.name} (${e.durationMs}ms)`:`Tool failed: ${e.name} (${e.durationMs}ms)`;case"message_start":return e.role==="assistant"?"Generating reply...":null;case"message_end":return e.role==="assistant"?"Finalizing reply...":null;case"heartbeat":return`Working... ${Math.max(1,Math.round(e.elapsedMs/1e3))}s`;default:return null}}function hr(e){try{let t=new WeakSet,n=200,o=12,r=12,s=3,a=(u,c)=>{if(u==null)return u;if(typeof u=="string")return u.length>n?`${u.slice(0,n)}...`:u;if(typeof u=="number"||typeof u=="boolean")return u;if(typeof u=="bigint")return u.toString();if(typeof u=="function")return"[function]";if(typeof u!="object")return String(u);if(t.has(u))return"[circular]";if(c>=s)return"[truncated]";if(t.add(u),Array.isArray(u)){let p=u.slice(0,r).map(h=>a(h,c+1));return u.length>r&&p.push("[truncated]"),p}let g=Object.entries(u),m={};for(let[p,h]of g.slice(0,o))m[p]=a(h,c+1);return g.length>o&&(m._truncated=!0),m},l=a(e,0),i=JSON.stringify(l);return i?i.length>700?`${i.slice(0,700)}...`:i:"null"}catch{return"[unavailable]"}}function Te(e){let t=e instanceof Error?e.message:String(e),n=e?.cause;return n instanceof Error?`${t} (${n.message})`:n?`${t} (${String(n)})`:t}function wr(e,t=140){return e.length<=t?e:`${e.slice(0,t-3)}...`}async function br(){let e=await ae(d.agentDir);if(e.length===0)return"No MCP servers configured. Add [mcp_servers.*] to ~/.tg-agent/config.toml.";let t=await Promise.all(e.map(o=>St(o))),n=["MCP servers:"];for(let o=0;o<e.length;o+=1){let r=e[o],s=t[o],a=s.ok?"ok":`error: ${wr(s.error??"unknown")}`;n.push(`- ${r.name} (${r.type}) ${Q(r)} status=${a} (${s.durationMs}ms)`)}return n.join(`
30
+ `)}async function sn(e,t,n,o,r){let s=r,l=_e(e,s,s!==void 0);if(!l)return;let i=await je(l),u=ze(i);switch(u.length>0&&(await D(i),await Promise.all(u.map(c=>le(l,c).catch(g=>{console.warn(`[tg-agent] cleanup session file failed id=${c}`,g)})))),n){case"start":case"help":{let c=["Commands:","/new [title] - create a new session","/list - list sessions","/use <id> - switch active session","/close [id] - close a session (default: active)","/reset - clear active session history","/workspace [path] - view or set workspace directory","/providers - list available providers","/models [provider] - list models for provider","/provider <name> - set provider for current session","/model <provider>/<model> - set model for current session","/mcp - list configured MCP servers","/mcp refresh - reload MCP catalog","/status - show session and workspace settings","/login <provider> - login to OAuth provider","/logout <provider> - logout from provider","/stop - stop the current running request","","Tips:","Send images or files to attach them to the prompt."].join(`
31
+ `);await f(e,c,r);return}case"new":{try{let g=Se(i,o||"");await D(i),await f(e,`Created session ${g.id} (${g.title}).`,r)}catch(c){await f(e,c.message,r)}return}case"list":{await D(i),await f(e,or(Fe(i)),r);return}case"use":{if(!o){await f(e,"Usage: /use <id>",r);return}if(!jt(i,o)){await f(e,`Session not found: ${o}`,r);return}await D(i),await f(e,`Active session set to ${o}.`,r);return}case"close":{let c=o||i.activeSessionId;if(!c){await f(e,"No active session to close.",r);return}if(!Ft(i,c)){await f(e,`Session not found: ${c}`,r);return}await D(i),await le(l,c).catch(m=>{console.warn(`[tg-agent] delete session file failed id=${c}`,m)}),await f(e,`Closed session ${c}.`,r);return}case"reset":{let c=te(i);if(!c){await f(e,"No active session.",r);return}zt(c),await D(i),await le(l,c.id).catch(g=>{console.warn(`[tg-agent] reset session file failed id=${c.id}`,g)}),await f(e,`Reset session ${c.id}.`,r);return}case"workspace":{if(!o){let g=Be(l,i),m=i.workspaceDir?"chat":d.workspaceMappings.has(l)?"config":"default";await f(e,`Workspace: ${g} (source: ${m})`,r);return}let c=ke.resolve(B(o.trim()));Nt(i,c),await D(i),await f(e,`Workspace set to: ${c}`,r);return}case"providers":{let{authStorage:c,modelRegistry:g}=await ne(),m=g.getError(),p=Yo(g,c);if(p.length===0){let v=m?`Warning: ${m}
32
+
33
+ No providers found.`:"No providers found.";await f(e,v,r);return}let h=[];m&&h.push(`Warning: ${m}`),h.push("Providers:"),await Gt(e,h.join(`
34
+ `),p,{perRow:1,footer:"Tap a provider to set it. Use /models <provider> to list models.",messageThreadId:r});return}case"models":{let{authStorage:c,modelRegistry:g}=await ne(),m=o?oe(o):"";if(!m){let M=te(i);if(!M?.modelProvider){await f(e,"Usage: /models <provider>",r);return}m=M.modelProvider}let p=c.hasAuth(m),h=er(i,m),v=Zo(g,m,h);if(v.length===0){await f(e,`No models found for provider ${m}.`,r);return}await Gt(e,`Models for ${m} (auth: ${p?"ok":"missing"}):`,v,{perRow:1,footer:"Tap a model to set it.",messageThreadId:r});return}case"provider":{if(!o){await f(e,"Usage: /provider <name>",r);return}let c=oe(o),{modelRegistry:g}=await ne();if(!g.getAll().some(h=>h.provider===c)){await f(e,`Unknown provider: ${c}`,r);return}let p=await Kt(i,e,r);p.modelProvider=c,p.modelId=void 0,p.updatedAt=N(),await D(i),await f(e,`Session ${p.id} provider set to ${c}.`,r);return}case"model":{let c=tr(o);if(!c){await f(e,"Usage: /model <provider>/<model>",r);return}let g=await Kt(i,e,r),m=oe(c.provider??g.modelProvider??"");if(!m){await f(e,"Usage: /model <provider>/<model>",r);return}let{modelRegistry:p}=await ne(),h=Vo(m,c.modelId);if(!p.find(m,h)){await f(e,`Model not found: ${m}/${h}`,r);return}g.modelProvider=m,g.modelId=h,g.updatedAt=N(),await D(i),await f(e,`Session ${g.id} model set to ${m}/${h}.`,r);return}case"status":{let c=te(i);if(!c){await f(e,"No active session.",r);return}let g=d.modelRef.includes("/")?d.modelRef:`${d.modelProvider}/${d.modelRef}`,m=c.modelProvider||c.modelId?`Model: ${c.modelProvider??"?"}/${c.modelId??"?"}`:`Model: ${g} (default)`,p=Be(l,i),h=i.workspaceDir?"chat":d.workspaceMappings.has(l)?"config":"default",v=[`Session: ${c.id} (${c.title})`,m,`Workspace: ${p} (${h})`].join(`
35
+ `);await f(e,v,r);return}case"mcp":{if(o.trim().toLowerCase()==="refresh"){xt(),await ce(d.agentDir,{timeoutMs:5e3,maxBytes:d.fetchMaxBytes,maxChars:3e3}),Ee(),await f(e,"MCP catalog refreshed.",r);return}let c=await br();await f(e,c,r);return}case"login":{let c=Ao();if(!o){let p=c.map(h=>`- ${h.id} (${h.name})`);await f(e,["OAuth providers:",...p].join(`
36
+ `),r);return}let g=oe(o);if(Le.has(t)){await f(e,"Login already in progress.",r);return}let m=c.find(p=>p.id===g);if(!m){await f(e,`Unknown OAuth provider: ${g}`,r);return}Le.add(t);try{let{authStorage:p}=await ne();await f(e,`Starting login for ${m.id}...`,r),await p.login(m.id,{onAuth:({url:h,instructions:v})=>{let M=["Open this URL in your browser:",h];v&&M.push("",v),f(e,M.join(`
37
+ `),r)},onPrompt:h=>Ht(t,e,h,r),onProgress:h=>{f(e,h,r)},onManualCodeInput:()=>Ht(t,e,{message:"Paste the authorization code:"},r)}),await f(e,`Login completed for ${m.id}.`,r)}catch(p){let h=Te(p);await f(e,`Login failed: ${h}`,r)}finally{Le.delete(t),Qt(t)}return}case"logout":{if(!o){await f(e,"Usage: /logout <provider>",r);return}let c=oe(o),{authStorage:g}=await ne();g.logout(c),await f(e,`Logged out from ${c}.`,r);return}default:await f(e,`Unknown command: ${n}`,r)}}async function xr(e,t,n,o=[],r){let s=He(n);if(s){await sn(e,t,s.command,s.args,r);return}let l=_e(e,r,r!==void 0);if(!l)return;let i=await je(l),u=ze(i);u.length>0&&(await D(i),await Promise.all(u.map($=>le(l,$).catch(T=>{console.warn(`[tg-agent] cleanup session file failed id=${$}`,T)}))));let c=te(i);if(!c)try{c=Se(i,""),await D(i),await f(e,`Created session ${c.id}.`,r)}catch($){await f(e,$.message,r);return}let{resolved:g,images:m}=await Bo(o);if(o.length>0&&g.length===0&&!n.trim()){await f(e,"Failed to download attachments.",r);return}let p=Lo(g),h=[];n.trim()&&h.push(n.trim()),p&&h.push(p);let v=h.join(`
38
+
39
+ `)||"Attachment received.",M={role:"user",content:v,ts:N()};Ne(c,M,d.maxHistoryMessages),await D(i),console.log(`[tg-agent] request user=${t} chat=${l} session=${c.id} messages=${c.messages.length} textLen=${v.length} attachments=${g.length} provider=${c.modelProvider??"-"} model=${c.modelId??"-"}`);let _=null;try{_=await fr(e,r)}catch($){console.warn("[tg-agent] status message failed",$)}let E={sessionId:c.id,chatId:e,messageThreadId:r,status:_,abortRequested:!1,cancelRequested:!1};Ro(l,E);try{let $=await Co(async()=>{let W=await Ut({chatId:l,sessionId:c.id,prompt:v,images:m,systemPrompt:d.systemPrompt,modelProvider:c.modelProvider,modelId:c.modelId,workspaceDir:Be(l,i),telegram:{chatId:e,sendPhoto:async(b,S)=>{let k={};S&&(k.caption=S),r!==void 0&&(k.message_thread_id=r),await F.sendPhoto(e,b,k)},sendDocument:async(b,S)=>{let k={};S&&(k.caption=S),r!==void 0&&(k.message_thread_id=r),await F.sendDocument(e,b,k)}},onAbortReady:b=>{E.abort=b,E.abortRequested&&b()},onStatus:_?b=>{let S=yr(b);S&&_?.update(S)}:void 0});return console.log(`[tg-agent] response session=${c.id} model=${W.modelProvider}/${W.modelId} file=${W.sessionFile}`),W.text});if(E.cancelRequested){_?await _.finalize("Cancelled by user."):await f(e,"Cancelled by user.",r);return}let T={role:"assistant",content:$,ts:N()};Ne(c,T,d.maxHistoryMessages),await D(i),_?await _.finalize($):await f(e,$,r)}catch($){if(console.error("[tg-agent] runModel error",$),E.cancelRequested){_?await _.fail("Cancelled by user."):await f(e,"Cancelled by user.",r);return}let T=Te($);_?await _.fail(`Error: ${T}`):await f(e,`Error: ${T}`,r)}finally{Do(l)}}var F,Vt,Co,We,Oo,Wo,qo,X,Le,Jo,Go,ve,nr,qt,rn,Jt,ir,K,gr,pr,an=H(()=>{"use strict";V();Ce();pt();Bt();fe();we();Ie();Y();it();F=new To(d.telegramToken,{polling:!0}),Vt=Ge(),Co=Ve(d.maxConcurrent),We=new Map;Oo="image/jpeg";Wo=new Set(["_","*","[","]","(",")","~","`",">","#","+","-","=","|","{","}",".","!"]);qo=600*1e3,X=new Map,Le=new Set,Jo=new Map([["codex","openai-codex"],["antigravity","google-antigravity"],["gemini","google-gemini-cli"],["gemini-cli","google-gemini-cli"]]),Go={"codex-mini-latest":"gpt-5.1-codex-mini","codex-max-latest":"gpt-5.1-codex-max","codex-latest":"gpt-5.2-codex"};Qo();z(d.agentDir).catch(e=>{console.warn(`[tg-agent] ensure agentDir failed: ${e instanceof Error?e.message:String(e)}`)});(async()=>{try{await ce(d.agentDir,{timeoutMs:3e3,maxBytes:d.fetchMaxBytes,maxChars:2e3}),Ee()}catch(e){let t=e instanceof Error?e.message:String(e);console.warn(`[tg-agent] mcp catalog warmup failed: ${t}`)}})();ve=gt();console.log(ve?`[tg-agent] fetchProxy=${ve.url} kind=${ve.kind} source=${ve.source}`:"[tg-agent] fetchProxy=(none)");nr=6e4,qt=new Map;rn=1800*1e3,Jt=2e3,ir=60,K=new Map;gr=3900,pr=1200;F.on("callback_query",e=>{let t=e.data??"",n=e.message?.chat.id;if(!e.from?.id||!n){F.answerCallbackQuery(e.id);return}let o=String(e.from.id);if(!en(o)){Zt(o,n),F.answerCallbackQuery(e.id);return}if(!t.startsWith("cmd:")){F.answerCallbackQuery(e.id);return}let r=lr(t);if(!r){F.answerCallbackQuery(e.id,{text:"Command expired."});return}F.answerCallbackQuery(e.id);let s=e.message?.message_thread_id,a=e.message?.is_topic_message??!1,l=_e(n,s,a);l&&Vt(l,async()=>{let i=He(r);if(!i){await f(n,"Invalid command.",s);return}if(i.command==="stop"){await Yt(n,l,s);return}await sn(n,o,i.command,i.args,s)}).catch(async i=>{console.error("[tg-agent] runModel error",i);let u=Te(i);await f(n,`Error: ${u}`,s)})});F.on("message",e=>{if(!e.from?.id)return;let t=String(e.from.id),n=e.chat.id;if(!en(t)){Zt(t,n);return}let o=e.message_thread_id,r=e.is_topic_message??!1,s=_e(n,o,r);if(!s)return;let a=(e.text??e.caption??"").trim(),l=Uo(e);if(!a&&l.length===0)return;let i=X.get(t);if(i){if(a==="/stop"||a==="/cancel"){Xo(t,"Login cancelled by user."),f(n,"Login cancelled.",o);return}if(!a){f(n,"Login expects a text response.",o);return}Qt(t),i.resolve(a);return}if(He(a)?.command==="stop"){Yt(n,s,o);return}Vt(s,()=>xr(n,t,a,l,o)).catch(async c=>{console.error("[tg-agent] runModel error",c);let g=Te(c);await f(n,`Error: ${g}`,o)})});F.on("polling_error",e=>{console.error("Polling error",e)});console.log("tg-agent started")});V();import Mr from"node:fs";import cn from"node:path";import vr from"node:readline/promises";import{fileURLToPath as kr}from"node:url";var ln=process.argv.slice(2),un=(e,t)=>ln.includes(e)||(t?ln.includes(t):!1),_r=un("--help","-h"),Tr=un("--version","-v"),$r=["Usage: tg-agent [options]","","Options:"," -h, --help Show help"," -v, --version Show version"].join(`
40
+ `),Pr=()=>{if(process.env.npm_package_version)return process.env.npm_package_version;try{let e=kr(import.meta.url),t=cn.dirname(e),n=cn.join(t,"..","package.json"),o=Mr.readFileSync(n,"utf8"),r=JSON.parse(o);if(r.version)return r.version}catch{}return"dev"};_r&&(console.log($r),process.exit(0));Tr&&(console.log(Pr()),process.exit(0));async function Ar(){let e=vr.createInterface({input:process.stdin,output:process.stdout});try{return(await e.question("Enter TELEGRAM_BOT_TOKEN: ")).trim()}finally{e.close()}}async function Cr(){let{configPath:e,data:t,exists:n}=ie(),o=et(),r=n?t:o,s=tt(r,o);if(nt(r)){s&&await Ae(e,r);return}process.stdin.isTTY||(console.error(`Missing telegram.bot_token in ${e}.`),process.exit(1));let l=await Ar();l||(console.error("Empty TELEGRAM_BOT_TOKEN."),process.exit(1)),ot(r,l),await Ae(e,r),console.log(`Saved config to ${e}.`)}async function Rr(){let{data:e}=ie(),t=typeof e.tls=="object"&&e.tls?e.tls:{},n=typeof t.extra_ca_certs=="string"?t.extra_ca_certs.trim():"";if(n&&(process.env.NODE_EXTRA_CA_CERTS=n),typeof t.reject_unauthorized=="boolean"){process.env.NODE_TLS_REJECT_UNAUTHORIZED=t.reject_unauthorized?"1":"0";return}let o=typeof t.reject_unauthorized=="string"?t.reject_unauthorized.trim():"";o&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED=o)}await Cr();await Rr();st();Promise.resolve().then(()=>an());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tg-agent",
3
- "version": "1.2.5",
3
+ "version": "1.2.6",
4
4
  "description": "Telegram Agent Bot",
5
5
  "type": "module",
6
6
  "bin": {
@@ -13,7 +13,8 @@
13
13
  ],
14
14
  "scripts": {
15
15
  "dev": "tsx src/cli.ts",
16
- "build": "tsc -p tsconfig.json && node scripts/minify.mjs && node scripts/add-shebang.mjs",
16
+ "build": "node scripts/bundle.mjs",
17
+ "build:legacy": "tsc -p tsconfig.json && node scripts/minify.mjs && node scripts/add-shebang.mjs",
17
18
  "minify": "node scripts/minify.mjs",
18
19
  "prepublishOnly": "npm run build",
19
20
  "start": "node dist/cli.js"
package/dist/auth.js DELETED
@@ -1 +0,0 @@
1
- import{config as e}from"./config.js";import{readCodexOAuth as i}from"./codexAuth.js";function f(r){const o=r.trim().toLowerCase();if(o==="openai-codex"||o==="codex"){const t=i();if(t)return{apiKey:t.accessToken,source:`codex:${t.source}`};throw new Error("No Codex OAuth credentials found. Run `codex login`.")}if(e.openaiApiKey)return{apiKey:e.openaiApiKey,source:"config.model.openai_api_key"};throw new Error(`No API key for provider: ${r}`)}function s(){return e.proxyUrl?{url:e.proxyUrl,source:"config.proxy.url"}:e.fetchProxyUrl?{url:e.fetchProxyUrl,source:"config.fetch.proxy_url"}:null}function c(r){const o=r.toLowerCase();return o.startsWith("socks5://")||o.startsWith("socks4://")||o.startsWith("socks://")?"socks":o.startsWith("https://")?"https":"http"}function p(){const r=s();return r?{url:r.url,kind:c(r.url),source:r.source}:null}function y(){const r=[{key:"config.fetch.proxy_url",value:e.fetchProxyUrl},{key:"config.proxy.url",value:e.proxyUrl}];for(const o of r){const t=o.value?.trim();if(!t)continue;const n=c(t);if(n!=="socks")return{url:t,kind:n,source:o.key}}return null}export{f as resolveApiKeyForProvider,y as resolveFetchProxyInfo,p as resolveProxyInfo};
package/dist/codexAuth.js DELETED
@@ -1 +0,0 @@
1
- import{createHash as h}from"node:crypto";import u from"node:fs";import l from"node:path";import{execSync as m}from"node:child_process";import{config as f}from"./config.js";const d="auth.json",y="Codex Auth";function k(){return l.join(f.codexHome,d)}function x(t){return`cli|${h("sha256").update(t).digest("hex").slice(0,16)}`}function g(){if(process.platform!=="darwin")return null;const t=f.codexHome,s=x(t);try{const i=m(`security find-generic-password -s "${y}" -a "${s}" -w`,{encoding:"utf8",timeout:5e3,stdio:["pipe","pipe","pipe"]}).trim(),r=JSON.parse(i),n=r.tokens,e=n?.access_token,o=n?.refresh_token;if(typeof e!="string"||!e||typeof o!="string"||!o)return null;const c=r.last_refresh,a=typeof c=="string"||typeof c=="number"?new Date(c).getTime():Date.now(),p=Number.isFinite(a)?a+3600*1e3:Date.now()+3600*1e3;return{accessToken:e,refreshToken:o,expiresAt:p,source:"keychain"}}catch{return null}}function w(){const t=k();try{const s=u.readFileSync(t,"utf8"),r=JSON.parse(s).tokens,n=r?.access_token,e=r?.refresh_token;if(typeof n!="string"||!n||typeof e!="string"||!e)return null;let o=Date.now()+3600*1e3;try{o=u.statSync(t).mtimeMs+3600*1e3}catch{}return{accessToken:n,refreshToken:e,expiresAt:o,source:"file"}}catch{return null}}function F(){return g()??w()}export{F as readCodexOAuth};
package/dist/config.js DELETED
@@ -1 +0,0 @@
1
- import w from"node:fs";import f from"node:path";import*as k from"@iarna/toml";import{ensureDir as R,expandHome as c}from"./utils.js";const b="~/.tg-agent",z="config.toml",S="You are running in user's personal computer or VPS, using telegram bot to interact with user. Be concise and practical.";function T(){const t=c(b);return f.join(t,z)}function o(t,e){const r=t[e];return r&&typeof r=="object"&&!Array.isArray(r)?r:{}}function n(t,e){return typeof t=="string"?t:typeof t=="number"||typeof t=="boolean"?String(t):e}function a(t,e){if(typeof t=="number"&&Number.isFinite(t))return t;if(typeof t=="string"){const r=Number.parseInt(t,10);return Number.isNaN(r)?e:r}return e}function l(t,e){if(typeof t=="boolean")return t;if(typeof t=="string"){const r=t.trim().toLowerCase();if(r==="true"||r==="1"||r==="yes")return!0;if(r==="false"||r==="0"||r==="no")return!1}return e}function B(t){return Array.isArray(t)?t.map(e=>typeof e=="string"?e:String(e)).map(e=>e.trim()).filter(Boolean):typeof t=="string"?t.split(",").map(e=>e.trim()).filter(Boolean):[]}function O(t){return new Set(B(t))}function U(t){const e=new Map;for(const[r,s]of Object.entries(t))typeof s=="string"&&s.trim()&&e.set(r,f.resolve(c(s.trim())));return e}function A(){const t=T();try{const e=w.readFileSync(t,"utf8"),r=k.parse(e);return{configPath:t,data:r,exists:!0}}catch{return{configPath:t,data:{},exists:!1}}}async function G(t,e){await R(f.dirname(t));const r=k.stringify(e);await w.promises.writeFile(t,r,"utf8")}function Y(){return{telegram:{bot_token:"",allowed_user_ids:[],parse_mode:""},model:{provider:"openai-codex",model:"gpt-5.2",openai_api_key:""},paths:{workspace_dir:"",session_dir:"~/.tg-agent/tg-sessions"},workspace_mappings:{},limits:{max_sessions:5,max_concurrent:5,max_history_messages:40,max_output_tokens:0},timeouts:{model_timeout_ms:6e4,model_timeout_stream_ms:3e5,fetch_timeout_ms:6e4},fetch:{max_bytes:2e5,proxy_url:""},proxy:{url:""},auth:{codex_home:"~/.codex"},logging:{agent_events:!0,agent_stream:!0},system:{prompt:S},tls:{extra_ca_certs:"",reject_unauthorized:""}}}function _(t){return!!(t&&typeof t=="object"&&!Array.isArray(t))}function $(t,e){let r=!1;const s=(i,p)=>{for(const[m,u]of Object.entries(p)){if(!(m in i)){i[m]=u,r=!0;continue}const g=i[m];_(g)&&_(u)&&s(g,u)}};return _(t)&&_(e)&&s(t,e),r}function K(t){const e=o(t,"telegram");return n(e.bot_token,"").trim()}function q(t,e){const r=o(t,"telegram");r.bot_token=e.trim(),t.telegram=r}function M(t){const e=o(t,"telegram"),r=o(t,"model"),s=o(t,"paths"),i=o(t,"limits"),p=o(t,"timeouts"),m=o(t,"fetch"),u=o(t,"proxy"),g=o(t,"auth"),y=o(t,"logging"),C=o(t,"system"),x=o(t,"tls"),j=o(t,"workspace_mappings"),D=n(s.workspace_dir,process.cwd()),E=n(s.session_dir,"~/.tg-agent/tg-sessions"),N=U(j),h=n(x.reject_unauthorized,""),P=h===""?null:l(h,!0);return{telegramToken:n(e.bot_token,"").trim(),telegramAllowedUsers:O(e.allowed_user_ids),telegramParseMode:n(e.parse_mode,"").trim(),modelProvider:n(r.provider,"openai-codex").trim(),modelRef:n(r.model,"gpt-5.2").trim(),openaiApiKey:n(r.openai_api_key,"").trim(),sessionDir:c(E),agentDir:c(b),workspaceDir:f.resolve(c(D)),workspaceMappings:N,maxSessions:a(i.max_sessions,5),maxConcurrent:a(i.max_concurrent,5),maxHistoryMessages:a(i.max_history_messages,40),maxOutputTokens:a(i.max_output_tokens,0),fetchMaxBytes:a(m.max_bytes,2e5),fetchTimeoutMs:a(p.fetch_timeout_ms,6e4),modelTimeoutMs:a(p.model_timeout_ms,6e4),modelTimeoutStreamingMs:a(p.model_timeout_stream_ms,3e5),systemPrompt:n(C.prompt,S),proxyUrl:n(u.url,"").trim(),fetchProxyUrl:n(m.proxy_url,"").trim(),codexHome:c(n(g.codex_home,"~/.codex")),logAgentEvents:l(y.agent_events,!0),logAgentStream:l(y.agent_stream,!0),tlsExtraCaCerts:n(x.extra_ca_certs,"").trim(),tlsRejectUnauthorized:P}}const{data:L}=A();let d=M(L);function J(){const{data:t}=A();return d=M(t),d}function Q(){const t=[];if(d.telegramToken||t.push("telegram.bot_token"),t.length>0)throw new Error(`Missing config values: ${t.join(", ")} (edit ${T()})`)}export{$ as applyConfigDefaults,Q as assertConfig,d as config,T as getConfigPath,Y as getDefaultConfigFile,A as loadConfigFile,K as readTelegramToken,J as refreshConfig,G as saveConfigFile,q as setTelegramToken};
@@ -1,9 +0,0 @@
1
- import f from"node:path";import $ from"node:fs/promises";import{Type as o}from"@sinclair/typebox";import{config as y}from"./config.js";import{callMcpServer as w,formatMcpTarget as x,loadMcpServers as S,loadMcpServersSync as _}from"./mcp.js";import{expandHome as P}from"./utils.js";const C=2e5,k=6e4;function b(e,t,r){return Number.isNaN(e)?t:Math.min(r,Math.max(t,e))}function O(e){if(!e)return{};const t={};if(Array.isArray(e)){for(const r of e)r?.name&&(t[r.name]=r.value??"");return t}for(const[r,s]of Object.entries(e))r&&(t[r]=s);return t}function T(e){const t=y.fetchTimeoutMs>0?y.fetchTimeoutMs:k;return b(e||t,1e3,12e4)}function g(e){const t=y.fetchMaxBytes>0?y.fetchMaxBytes:C;return b(e||t,1024,5e6)}function v(e,t,r){const s=e.trim();if(!s)return null;const n=P(s),l=f.isAbsolute(n)?n:f.join(r,n),u=f.resolve(l);for(const d of t){const c=f.resolve(d);if(u===c||u.startsWith(`${c}${f.sep}`))return u}return null}async function M(e){try{const t=await $.stat(e);return t.isFile()?{bytes:t.size}:null}catch{return null}}function F(e){try{const t=new URL(e);return t.protocol==="http:"||t.protocol==="https:"}catch{return!1}}function A(e,t){const r=new Uint8Array(t);let s=0;for(const n of e)r.set(n,s),s+=n.byteLength;return r}async function j(e,t,r){const s=e.body?.getReader?.();if(!s){const i=await e.text?.()??"",p=Math.min(i.length,t),m=i.length>t;return{text:i.slice(0,t),bytes:p,truncated:m}}const n=new TextDecoder("utf-8"),l=[];let u=0,d=!1;for(;;){if(r?.aborted){try{await s.cancel?.()}catch{}throw new Error("Fetch aborted")}const{done:i,value:p}=await s.read();if(i)break;if(!p)continue;const m=u+p.byteLength;if(m>t){const h=Math.max(0,t-u);h>0&&(l.push(p.slice(0,h)),u+=h),d=!0;try{await s.cancel?.()}catch{}break}l.push(p),u=m}const c=A(l,u);return{text:n.decode(c),bytes:u,truncated:d}}function L(e,t){const r=`HTTP ${e.status} ${e.statusText}`.trim(),s=[`url: ${e.url}`,`bytes: ${e.bytes}${e.truncated?" (truncated)":""}`,`content-type: ${e.contentType??"unknown"}`];return`${r}
2
- ${s.join(`
3
- `)}
4
-
5
- ${t}`}const D=o.Object({url:o.String({description:"HTTP or HTTPS URL"}),method:o.Optional(o.String({description:"HTTP method (default: GET)"})),headers:o.Optional(o.Array(o.Object({name:o.String({description:"Header name"}),value:o.String({description:"Header value"})}),{description:"Request headers as name/value pairs"})),body:o.Optional(o.String({description:"Request body (string)"})),timeoutMs:o.Optional(o.Integer({description:"Timeout in milliseconds",minimum:1e3,maximum:12e4})),maxBytes:o.Optional(o.Integer({description:"Max response bytes",minimum:1024,maximum:5e6}))});function E(){return{name:"fetch",label:"fetch",description:"Fetch a URL via HTTP(S) and return the response body.",parameters:D,execute:async(e,t,r,s,n)=>{if(!F(t.url))return{content:[{type:"text",text:"Invalid URL. Only http(s) is allowed."}],details:{url:t.url,status:0,statusText:"invalid_url",bytes:0,truncated:!1,contentType:null}};const l=T(t.timeoutMs),u=g(t.maxBytes),d=new AbortController,c=()=>d.abort();n?.addEventListener("abort",c,{once:!0});const a=setTimeout(()=>d.abort(),l);try{r?.({content:[{type:"text",text:`Fetching ${t.url}...`}],details:{url:t.url,status:0,statusText:"pending",bytes:0,truncated:!1,contentType:null}});const i=await fetch(t.url,{method:t.method?.toUpperCase()??"GET",headers:O(t.headers),body:t.body,signal:d.signal}),p=await j(i,u,n),m=i.headers.get("content-type");return{content:[{type:"text",text:L({url:i.url,status:i.status,statusText:i.statusText,bytes:p.bytes,truncated:p.truncated,contentType:m},p.text)}],details:{url:i.url,status:i.status,statusText:i.statusText,bytes:p.bytes,truncated:p.truncated,contentType:m}}}catch(i){return{content:[{type:"text",text:`Fetch failed: ${i instanceof Error?i.message:String(i)}`}],details:{url:t.url,status:0,statusText:"error",bytes:0,truncated:!1,contentType:null}}}finally{clearTimeout(a),n?.removeEventListener("abort",c)}}}}const H=o.Object({server:o.Optional(o.String({description:"MCP server name"})),method:o.String({description:"MCP method name"}),params:o.Optional(o.Any({description:"MCP params payload"}))});function I(e,t,r){const s=t.status>0?`HTTP ${t.status} ${t.statusText}`.trim():t.statusText,n=[`server: ${e.name}`,`type: ${e.type}`,`target: ${t.target}`,`bytes: ${t.bytes}${t.truncated?" (truncated)":""}`,`content-type: ${t.contentType??"unknown"}`];return`${s}
6
- ${n.join(`
7
- `)}
8
-
9
- ${r}`}function R(e){return{name:"mcp",label:"mcp",description:"Call an MCP endpoint via JSON-RPC.",parameters:H,execute:async(t,r,s,n,l)=>{const u=await e();if(u.length===0)return{content:[{type:"text",text:"MCP is not configured. Add [mcp_servers.*] to ~/.tg-agent/config.toml."}],details:{server:"",type:"http",target:"",status:0,statusText:"not_configured",bytes:0,truncated:!1,contentType:null}};let d=r.server?.trim()??"";if(!d)if(u.length===1)d=u[0]?.name??"";else return{content:[{type:"text",text:`Multiple MCP servers configured. Provide server name. Available: ${u.map(a=>a.name).join(", ")}`}],details:{server:"",type:"http",target:"",status:0,statusText:"server_required",bytes:0,truncated:!1,contentType:null}};const c=u.find(a=>a.name===d);if(!c)return{content:[{type:"text",text:`MCP server not found: ${d}. Available: ${u.map(a=>a.name).join(", ")}`}],details:{server:d,type:"http",target:"",status:0,statusText:"server_not_found",bytes:0,truncated:!1,contentType:null}};try{s?.({content:[{type:"text",text:`Calling MCP ${c.name} ${r.method}...`}],details:{server:c.name,type:c.type,target:x(c),status:0,statusText:"pending",bytes:0,truncated:!1,contentType:null}});const a=await w(c,r.method,r.params??{},{timeoutMs:T(void 0),maxBytes:g(void 0),signal:l});return{content:[{type:"text",text:I(c,{server:c.name,type:c.type,target:x(c),status:a.statusCode??0,statusText:a.statusText??(a.ok?"ok":"error"),bytes:a.bytes,truncated:a.truncated,contentType:a.contentType??null},a.output)}],details:{server:c.name,type:c.type,target:x(c),status:a.statusCode??0,statusText:a.statusText??(a.ok?"ok":"error"),bytes:a.bytes,truncated:a.truncated,contentType:a.contentType??null}}}catch(a){return{content:[{type:"text",text:`MCP failed: ${a instanceof Error?a.message:String(a)}`}],details:{server:c.name,type:c.type,target:x(c),status:0,statusText:"error",bytes:0,truncated:!1,contentType:null}}}}}}const U=o.Object({path:o.String({description:"Image file path (relative to workspace or uploads)."}),caption:o.Optional(o.String({description:"Caption text (plain text)."}))}),B=o.Object({path:o.String({description:"File path (relative to workspace or uploads)."}),caption:o.Optional(o.String({description:"Caption text (plain text)."}))});function N(e){const t=[y.workspaceDir,f.join(y.agentDir,"uploads")];return{name:"send_photo",label:"send_photo",description:"Send an image file to the current Telegram chat.",parameters:U,execute:async(r,s)=>{const n=v(s.path,t,y.workspaceDir);if(!n)return{content:[{type:"text",text:"Invalid path. Only workspace or uploads are allowed."}],details:{path:s.path,bytes:0}};const l=await M(n);return l?(await e.sendPhoto(n,s.caption?.trim()||void 0),{content:[{type:"text",text:`Photo sent: ${f.basename(n)}`}],details:{path:n,bytes:l.bytes}}):{content:[{type:"text",text:`File not found: ${n}`}],details:{path:n,bytes:0}}}}}function z(e){const t=[y.workspaceDir,f.join(y.agentDir,"uploads")];return{name:"send_file",label:"send_file",description:"Send a file to the current Telegram chat.",parameters:B,execute:async(r,s)=>{const n=v(s.path,t,y.workspaceDir);if(!n)return{content:[{type:"text",text:"Invalid path. Only workspace or uploads are allowed."}],details:{path:s.path,bytes:0}};const l=await M(n);return l?(await e.sendDocument(n,s.caption?.trim()||void 0),{content:[{type:"text",text:`File sent: ${f.basename(n)}`}],details:{path:n,bytes:l.bytes}}):{content:[{type:"text",text:`File not found: ${n}`}],details:{path:n,bytes:0}}}}}function K(e){const t=[E()];return e?.telegram&&(t.push(N(e.telegram)),t.push(z(e.telegram))),_(y.agentDir).length>0&&t.push(R(()=>S(y.agentDir))),t}export{K as createCustomTools};
package/dist/index.js DELETED
@@ -1,17 +0,0 @@
1
- import U from"node:path";import X from"node:fs/promises";import $e from"node-telegram-bot-api";import{discoverAuthStorage as ve,discoverModels as he}from"@mariozechner/pi-coding-agent";import{getOAuthProviders as Me}from"@mariozechner/pi-ai";import{config as m,assertConfig as Se}from"./config.js";import{resolveApiKeyForProvider as _e,resolveProxyInfo as ke}from"./auth.js";import{applyFetchProxy as Ae}from"./proxy.js";import{runPiAgentPrompt as xe}from"./piAgentRunner.js";import{readCodexOAuth as Pe}from"./codexAuth.js";import{formatMcpTarget as Ce,freezeMcpCatalog as J,getMcpCatalog as Z,loadMcpServers as be,loadMcpServersSync as Ee,probeMcpServer as Re,refreshMcpCatalog as De}from"./mcp.js";import{appendMessage as Y,closeSession as ze,createSession as F,deleteSessionFile as j,getActiveSession as z,listSessions as T,loadChatState as I,pruneExpiredSessions as ee,resetSession as Le,saveChatState as $,setActiveSession as Ne,setWorkspaceDir as Ue}from"./sessionStore.js";import{chunkText as je,createQueueMap as We,createSemaphore as Oe,ensureDir as K,expandHome as Be,nowMs as C,shortId as te}from"./utils.js";Se();const v=new $e(m.telegramToken,{polling:!0}),ne=We(),Fe=Oe(m.maxConcurrent),G=new Map;function Ke(e,t){G.set(e,t)}function Ge(e){G.delete(e)}function Qe(e){const t=e.trim();if(t){if(t==="Markdown"||t==="MarkdownV2"||t==="HTML")return t;console.warn(`[tg-agent] invalid TELEGRAM_PARSE_MODE=${t}, ignoring`)}}const Ve="image/jpeg";function qe(){return U.join(m.agentDir,"uploads")}function He(e){return e.length===0?null:e.reduce((t,o)=>{const n=t.file_size??t.width*t.height;return(o.file_size??o.width*o.height)>n?o:t})}function Xe(e){return!!e?.startsWith("image/")}function Je(e){switch(U.extname(e).toLowerCase()){case".png":return"image/png";case".jpg":case".jpeg":return"image/jpeg";case".webp":return"image/webp";case".gif":return"image/gif";default:return}}function Ze(e){if(!Number.isFinite(e)||e<=0)return"0 B";const t=["B","KB","MB","GB"];let o=e,n=0;for(;o>=1024&&n<t.length-1;)o/=1024,n+=1;return`${o.toFixed(o>=10||n===0?0:1)} ${t[n]}`}function Ye(e){return e.length===0?"":e.map(t=>{const o=[];t.mimeType&&o.push(t.mimeType),t.bytes>0&&o.push(Ze(t.bytes));const n=o.length>0?` (${o.join(", ")})`:"";return`Attachment saved: ${t.path}${n}`}).join(`
2
- `)}function Te(e){const t=[];if(e.photo&&e.photo.length>0){const o=He(e.photo);o&&t.push({kind:"photo",fileId:o.file_id,fileSize:o.file_size})}if(e.document&&t.push({kind:"document",fileId:e.document.file_id,fileName:e.document.file_name,mimeType:e.document.mime_type,fileSize:e.document.file_size}),e.audio){const o=e.audio.mime_type?.split("/")[1]??"mp3",n=e.audio.title??e.audio.performer??"audio";t.push({kind:"document",fileId:e.audio.file_id,fileName:`${n}.${o}`,mimeType:e.audio.mime_type,fileSize:e.audio.file_size})}if(e.voice&&t.push({kind:"document",fileId:e.voice.file_id,fileName:`voice.${e.voice.mime_type?.split("/")[1]??"ogg"}`,mimeType:e.voice.mime_type,fileSize:e.voice.file_size}),e.video){const o=e.video.mime_type?.split("/")[1]??"mp4";t.push({kind:"document",fileId:e.video.file_id,fileName:`video.${o}`,mimeType:e.video.mime_type,fileSize:e.video.file_size})}return e.video_note&&t.push({kind:"document",fileId:e.video_note.file_id,fileName:"video_note.mp4",mimeType:"video/mp4",fileSize:e.video_note.file_size}),t}async function Ie(e){if(e.length===0)return{resolved:[],images:[]};const t=qe();await K(t);const o=[],n=[];for(const i of e)try{const c=await v.downloadFile(i.fileId,t),p=await X.stat(c),a=i.fileName??U.basename(c),s=i.mimeType??Je(c),d=i.kind==="photo"||Xe(s),r={path:c,name:a,mimeType:s,bytes:p.size,isImage:d};if(o.push(r),d){const u=await X.readFile(c);n.push({type:"image",data:u.toString("base64"),mimeType:s??Ve})}}catch(c){console.warn("[tg-agent] attachment download failed",c)}return{resolved:o,images:n}}const et=new Set(["_","*","[","]","(",")","~","`",">","#","+","-","=","|","{","}",".","!"]);function L(e,t){let o=0;for(let n=0;n<e.length;n+=1){const i=e[n];if(i==="\\"){n+=1;continue}i===t&&(o+=1)}return o}function tt(e){if(L(e,"*")%2!==0||L(e,"_")%2!==0||L(e,"`")%2!==0)return!1;const i=L(e,"["),c=L(e,"]");return i===c}function nt(e){for(let t=0;t<e.length;t+=1){const o=e[t];if(o==="\\"){t+=1;continue}if(et.has(o))return!1}return!0}function oe(e){const t=Qe(m.telegramParseMode);return t?[t]:nt(e)?["MarkdownV2","Markdown"]:tt(e)?["Markdown"]:[]}const ot=600*1e3,A=new Map,Q=new Set,it=new Map([["codex","openai-codex"],["antigravity","google-antigravity"],["gemini","google-gemini-cli"],["gemini-cli","google-gemini-cli"]]),rt={"codex-mini-latest":"gpt-5.1-codex-mini","codex-max-latest":"gpt-5.1-codex-max","codex-latest":"gpt-5.2-codex"};function E(e){const t=e.trim().toLowerCase();return it.get(t)??t}function st(e,t){return e!=="openai-codex"?t:rt[t]??t}async function R(){await K(m.agentDir);const e=ve(m.agentDir),t=Pe();t&&e.setRuntimeApiKey("openai-codex",t.accessToken);const o=he(e,m.agentDir);return{authStorage:e,modelRegistry:o}}function ie(e){const t=A.get(e);t&&(clearTimeout(t.timeoutId),A.delete(e))}function at(e,t){const o=A.get(e);o&&(clearTimeout(o.timeoutId),A.delete(e),o.reject(new Error(t)))}async function re(e,t,o,n){if(A.has(e))throw new Error("Login is already awaiting input.");const i=o.placeholder?`${o.message} (${o.placeholder})`:o.message;return await l(t,i,n),await new Promise((c,p)=>{const a=setTimeout(()=>{A.delete(e),p(new Error("Login prompt timed out."))},ot);A.set(e,{resolve:c,reject:p,timeoutId:a,chatId:t})})}async function se(e,t,o){const n=G.get(t);if(!n){await l(e,"No active request to stop.",o);return}n.cancelRequested=!0,n.abortRequested=!0,n.status&&n.status.update("Cancelled by user.",!0),n.abort&&n.abort(),(!n.status||n.chatId!==e)&&await l(e,"Stopping current request...",o)}function ct(){console.log(`[tg-agent] modelProvider=${m.modelProvider} modelRef=${m.modelRef} sessionDir=${m.sessionDir} maxConcurrent=${m.maxConcurrent}`),console.log(`[tg-agent] agentDir=${m.agentDir} workspaceDir=${m.workspaceDir}`);const e=Ee(m.agentDir),t=e.length>0?`on (${e.length})`:"off";console.log(`[tg-agent] tools fetchMaxBytes=${m.fetchMaxBytes} fetchTimeoutMs=${m.fetchTimeoutMs} mcp=${t}`),console.log(`[tg-agent] proxy url=${m.proxyUrl||"(none)"} fetchProxy=${m.fetchProxyUrl||"(none)"}`),console.log(`[tg-agent] tls extra_ca=${m.tlsExtraCaCerts||"(empty)"} reject_unauthorized=${m.tlsRejectUnauthorized===null?"(unset)":String(m.tlsRejectUnauthorized)}`);try{const{source:n}=_e(m.modelProvider);console.log(`[tg-agent] authSource=${n}`)}catch(n){const i=n instanceof Error?n.message:String(n);console.warn(`[tg-agent] authSource=missing (${i})`)}const o=ke();console.log(o?`[tg-agent] proxyUrl=${o.url} kind=${o.kind} source=${o.source}`:"[tg-agent] proxyUrl=(none)")}ct(),K(m.agentDir).catch(e=>{console.warn(`[tg-agent] ensure agentDir failed: ${e instanceof Error?e.message:String(e)}`)}),(async()=>{try{await Z(m.agentDir,{timeoutMs:3e3,maxBytes:m.fetchMaxBytes,maxChars:2e3}),J()}catch(e){const t=e instanceof Error?e.message:String(e);console.warn(`[tg-agent] mcp catalog warmup failed: ${t}`)}})();const W=Ae();console.log(W?`[tg-agent] fetchProxy=${W.url} kind=${W.kind} source=${W.source}`:"[tg-agent] fetchProxy=(none)");function V(e){if(!e.startsWith("/"))return null;const t=e.trim(),[o,...n]=t.split(" ");return{command:o.split("@")[0].slice(1).toLowerCase(),args:n.join(" ").trim()}}async function ae(e,t,o){let n=z(e);return n||(n=F(e,""),await $(e),await l(t,`Created session ${n.id}.`,o)),n}function lt(e,t){const o=e.getAll(),n=new Map;for(const i of o){const c=n.get(i.provider)??{count:0,auth:t.hasAuth(i.provider)};c.count+=1,n.set(i.provider,c)}return Array.from(n.entries()).sort((i,c)=>i[0].localeCompare(c[0])).map(([i,c])=>({label:`${i} (${c.count}, ${c.auth?"ok":"no auth"})`,command:`/provider ${i}`}))}function ut(e,t,o=[]){const n=e.getAll().filter(a=>a.provider===t).sort((a,s)=>a.id.localeCompare(s.id));if(o.length===0)return n.map(a=>({label:a.id,command:`/model ${t}/${a.id}`}));const i=new Map(n.map(a=>[a.id,a])),c=new Set,p=[];for(const a of o){const s=i.get(a);!s||c.has(s.id)||(c.add(s.id),p.push(s))}for(const a of n)c.has(a.id)||p.push(a);return p.map(a=>({label:a.id,command:`/model ${t}/${a.id}`}))}function ft(e,t,o=3){const n=new Set,i=[],c=T(e);for(const p of c){if(p.modelProvider!==t)continue;const a=p.modelId;if(!(!a||n.has(a))&&(n.add(a),i.push(a),i.length>=o))break}return i}function dt(e){const t=e.trim();if(!t)return null;if(t.includes("/")){const[o,n]=t.split("/",2);return!o||!n?null:{provider:E(o),modelId:n.trim()}}return{modelId:t}}const mt=6e4,ce=new Map;function le(e,t){const o=Date.now(),n=ce.get(e)??0;o-n<mt||(ce.set(e,o),console.warn(`[tg-agent] unauthorized user=${e} chat=${t}`))}function ue(e){const t=m.telegramAllowedUsers;return!t||t.size===0?!0:t.has(e)}function pt(e){return e.length===0?"No sessions found.":["Sessions:",...e.map(o=>{const n=new Date(o.updatedAt).toISOString();return`- ${o.id} | ${o.title} | updated ${n}`})].join(`
3
- `)}function O(e,t,o){const n=String(e);return t!==void 0&&!o?null:t!==void 0&&o?`${n}_${t}`:n}function q(e,t){if(t.workspaceDir)return t.workspaceDir;const o=m.workspaceMappings.get(e);return o||m.workspaceDir}async function fe(e,t,o,n){const i={};return o&&(i.parse_mode=o),n!==void 0&&(i.message_thread_id=n),await v.sendMessage(e,t,i)}async function de(e,t,o,n,i){const c={chat_id:e,message_id:t};n&&(c.parse_mode=n),i!==void 0&&(c.message_thread_id=i),await v.editMessageText(o,c)}async function me(e,t){let o;for(const n of t)try{return await e(n)}catch(i){o=i;const c=i instanceof Error?i.message:String(i);console.warn(`[tg-agent] parse_mode ${n} failed, trying fallback: ${c}`)}try{return await e(void 0)}catch(n){if(o){const i=n instanceof Error?n.message:String(n);console.warn(`[tg-agent] parse_mode fallback to plain failed: ${i}`)}throw n}}async function gt(e,t,o){return await me(n=>fe(e,t,n,o),oe(t))}async function wt(e,t,o,n){await me(i=>de(e,t,o,i,n),oe(o))}async function l(e,t,o){const n=je(t,3900);for(const i of n)await gt(e,i,o)}const pe=1800*1e3,ge=2e3,yt=60,S=new Map;function $t(){const e=C()-pe;for(const[n,i]of S)i.createdAt<e&&S.delete(n);if(S.size<=ge)return;const t=Array.from(S.entries()).sort((n,i)=>n[1].createdAt-i[1].createdAt),o=S.size-ge;for(let n=0;n<o;n+=1)S.delete(t[n][0])}function vt(e){$t();let t=te();for(;S.has(t);)t=te();return S.set(t,{command:e,createdAt:C()}),t}function ht(e){if(!e.startsWith("cmd:"))return null;const t=e.slice(4),o=S.get(t);return o?C()-o.createdAt>pe?(S.delete(t),null):o.command:null}function Mt(e,t){if(e.length<=t)return[e];const o=[];for(let n=0;n<e.length;n+=t)o.push(e.slice(n,n+t));return o}function St(e,t){const o=[];let n=[];for(const i of e){const c=vt(i.command);n.push({text:i.label,callback_data:`cmd:${c}`}),n.length>=t&&(o.push(n),n=[])}return n.length>0&&o.push(n),o}async function _t(e,t,o,n){const i={reply_markup:{inline_keyboard:o}};return n!==void 0&&(i.message_thread_id=n),await v.sendMessage(e,t,i)}async function we(e,t,o,n){const i=n?.perRow??1,c=n?.pageSize??yt,p=n?.footer,a=n?.messageThreadId,s=Mt(o,c);for(let d=0;d<s.length;d+=1){const r=s[d],u=s.length>1?` (page ${d+1}/${s.length})`:"",f=[`${t}${u}`];p&&f.push(p);const g=St(r,i);await _t(e,f.join(`
4
- `),g,a)}}const kt=3900,At=1200;function H(e,t=kt){return e.length<=t?{text:e,truncated:!1}:{text:`${e.slice(0,Math.max(0,t-15))}...
5
-
6
- [truncated]`,truncated:!0}}async function xt(e,t){const o="Working...",i=(await fe(e,o,void 0,t)).message_id;let c=o,p=0,a=Promise.resolve();const s=(r,u=!1)=>{const f=Date.now();!u&&f-p<At||r!==c&&(c=r,p=f,a=a.then(async()=>{await de(e,i,r,void 0,t)}).catch(g=>{console.warn("[tg-agent] status edit failed",g)}))},d=r=>{c=r,p=Date.now(),a=a.then(async()=>{await wt(e,i,r,t)}).catch(u=>{console.warn("[tg-agent] status edit failed",u)})};return{update:(r,u=!1)=>{const f=H(r).text;s(f,u)},finalize:async r=>{const u=H(r).text;d(u),await a},fail:async r=>{const u=H(r).text;d(u),await a}}}function Pt(e){switch(e.type){case"agent_start":return"Working...";case"tool_start":return`Running tool: ${e.name}
7
- args: ${Ct(e.args)}`;case"tool_end":return e.ok?`Tool finished: ${e.name} (${e.durationMs}ms)`:`Tool failed: ${e.name} (${e.durationMs}ms)`;case"message_start":return e.role==="assistant"?"Generating reply...":null;case"message_end":return e.role==="assistant"?"Finalizing reply...":null;case"heartbeat":return`Working... ${Math.max(1,Math.round(e.elapsedMs/1e3))}s`;default:return null}}function Ct(e){try{const t=new WeakSet,o=200,n=12,i=12,c=3,p=(d,r)=>{if(d==null)return d;if(typeof d=="string")return d.length>o?`${d.slice(0,o)}...`:d;if(typeof d=="number"||typeof d=="boolean")return d;if(typeof d=="bigint")return d.toString();if(typeof d=="function")return"[function]";if(typeof d!="object")return String(d);if(t.has(d))return"[circular]";if(r>=c)return"[truncated]";if(t.add(d),Array.isArray(d)){const g=d.slice(0,i).map(w=>p(w,r+1));return d.length>i&&g.push("[truncated]"),g}const u=Object.entries(d),f={};for(const[g,w]of u.slice(0,n))f[g]=p(w,r+1);return u.length>n&&(f._truncated=!0),f},a=p(e,0),s=JSON.stringify(a);return s?s.length>700?`${s.slice(0,700)}...`:s:"null"}catch{return"[unavailable]"}}function B(e){const t=e instanceof Error?e.message:String(e),o=e?.cause;return o instanceof Error?`${t} (${o.message})`:o?`${t} (${String(o)})`:t}function bt(e,t=140){return e.length<=t?e:`${e.slice(0,t-3)}...`}async function Et(){const e=await be(m.agentDir);if(e.length===0)return"No MCP servers configured. Add [mcp_servers.*] to ~/.tg-agent/config.toml.";const t=await Promise.all(e.map(n=>Re(n))),o=["MCP servers:"];for(let n=0;n<e.length;n+=1){const i=e[n],c=t[n],p=c.ok?"ok":`error: ${bt(c.error??"unknown")}`;o.push(`- ${i.name} (${i.type}) ${Ce(i)} status=${p} (${c.durationMs}ms)`)}return o.join(`
8
- `)}async function ye(e,t,o,n,i){const c=i,a=O(e,c,c!==void 0);if(!a)return;const s=await I(a),d=ee(s);switch(d.length>0&&(await $(s),await Promise.all(d.map(r=>j(a,r).catch(u=>{console.warn(`[tg-agent] cleanup session file failed id=${r}`,u)})))),o){case"start":case"help":{const r=["Commands:","/new [title] - create a new session","/list - list sessions","/use <id> - switch active session","/close [id] - close a session (default: active)","/reset - clear active session history","/workspace [path] - view or set workspace directory","/providers - list available providers","/models [provider] - list models for provider","/provider <name> - set provider for current session","/model <provider>/<model> - set model for current session","/mcp - list configured MCP servers","/mcp refresh - reload MCP catalog","/status - show session and workspace settings","/login <provider> - login to OAuth provider","/logout <provider> - logout from provider","/stop - stop the current running request","","Tips:","Send images or files to attach them to the prompt."].join(`
9
- `);await l(e,r,i);return}case"new":{try{const u=F(s,n||"");await $(s),await l(e,`Created session ${u.id} (${u.title}).`,i)}catch(r){await l(e,r.message,i)}return}case"list":{await $(s),await l(e,pt(T(s)),i);return}case"use":{if(!n){await l(e,"Usage: /use <id>",i);return}if(!Ne(s,n)){await l(e,`Session not found: ${n}`,i);return}await $(s),await l(e,`Active session set to ${n}.`,i);return}case"close":{const r=n||s.activeSessionId;if(!r){await l(e,"No active session to close.",i);return}if(!ze(s,r)){await l(e,`Session not found: ${r}`,i);return}await $(s),await j(a,r).catch(f=>{console.warn(`[tg-agent] delete session file failed id=${r}`,f)}),await l(e,`Closed session ${r}.`,i);return}case"reset":{const r=z(s);if(!r){await l(e,"No active session.",i);return}Le(r),await $(s),await j(a,r.id).catch(u=>{console.warn(`[tg-agent] reset session file failed id=${r.id}`,u)}),await l(e,`Reset session ${r.id}.`,i);return}case"workspace":{if(!n){const u=q(a,s),f=s.workspaceDir?"chat":m.workspaceMappings.has(a)?"config":"default";await l(e,`Workspace: ${u} (source: ${f})`,i);return}const r=U.resolve(Be(n.trim()));Ue(s,r),await $(s),await l(e,`Workspace set to: ${r}`,i);return}case"providers":{const{authStorage:r,modelRegistry:u}=await R(),f=u.getError(),g=lt(u,r);if(g.length===0){const y=f?`Warning: ${f}
10
-
11
- No providers found.`:"No providers found.";await l(e,y,i);return}const w=[];f&&w.push(`Warning: ${f}`),w.push("Providers:"),await we(e,w.join(`
12
- `),g,{perRow:1,footer:"Tap a provider to set it. Use /models <provider> to list models.",messageThreadId:i});return}case"models":{const{authStorage:r,modelRegistry:u}=await R();let f=n?E(n):"";if(!f){const x=z(s);if(!x?.modelProvider){await l(e,"Usage: /models <provider>",i);return}f=x.modelProvider}const g=r.hasAuth(f),w=ft(s,f),y=ut(u,f,w);if(y.length===0){await l(e,`No models found for provider ${f}.`,i);return}await we(e,`Models for ${f} (auth: ${g?"ok":"missing"}):`,y,{perRow:1,footer:"Tap a model to set it.",messageThreadId:i});return}case"provider":{if(!n){await l(e,"Usage: /provider <name>",i);return}const r=E(n),{modelRegistry:u}=await R();if(!u.getAll().some(w=>w.provider===r)){await l(e,`Unknown provider: ${r}`,i);return}const g=await ae(s,e,i);g.modelProvider=r,g.modelId=void 0,g.updatedAt=C(),await $(s),await l(e,`Session ${g.id} provider set to ${r}.`,i);return}case"model":{const r=dt(n);if(!r){await l(e,"Usage: /model <provider>/<model>",i);return}const u=await ae(s,e,i),f=E(r.provider??u.modelProvider??"");if(!f){await l(e,"Usage: /model <provider>/<model>",i);return}const{modelRegistry:g}=await R(),w=st(f,r.modelId);if(!g.find(f,w)){await l(e,`Model not found: ${f}/${w}`,i);return}u.modelProvider=f,u.modelId=w,u.updatedAt=C(),await $(s),await l(e,`Session ${u.id} model set to ${f}/${w}.`,i);return}case"status":{const r=z(s);if(!r){await l(e,"No active session.",i);return}const u=m.modelRef.includes("/")?m.modelRef:`${m.modelProvider}/${m.modelRef}`,f=r.modelProvider||r.modelId?`Model: ${r.modelProvider??"?"}/${r.modelId??"?"}`:`Model: ${u} (default)`,g=q(a,s),w=s.workspaceDir?"chat":m.workspaceMappings.has(a)?"config":"default",y=[`Session: ${r.id} (${r.title})`,f,`Workspace: ${g} (${w})`].join(`
13
- `);await l(e,y,i);return}case"mcp":{if(n.trim().toLowerCase()==="refresh"){De(),await Z(m.agentDir,{timeoutMs:5e3,maxBytes:m.fetchMaxBytes,maxChars:3e3}),J(),await l(e,"MCP catalog refreshed.",i);return}const r=await Et();await l(e,r,i);return}case"login":{const r=Me();if(!n){const g=r.map(w=>`- ${w.id} (${w.name})`);await l(e,["OAuth providers:",...g].join(`
14
- `),i);return}const u=E(n);if(Q.has(t)){await l(e,"Login already in progress.",i);return}const f=r.find(g=>g.id===u);if(!f){await l(e,`Unknown OAuth provider: ${u}`,i);return}Q.add(t);try{const{authStorage:g}=await R();await l(e,`Starting login for ${f.id}...`,i),await g.login(f.id,{onAuth:({url:w,instructions:y})=>{const x=["Open this URL in your browser:",w];y&&x.push("",y),l(e,x.join(`
15
- `),i)},onPrompt:w=>re(t,e,w,i),onProgress:w=>{l(e,w,i)},onManualCodeInput:()=>re(t,e,{message:"Paste the authorization code:"},i)}),await l(e,`Login completed for ${f.id}.`,i)}catch(g){const w=B(g);await l(e,`Login failed: ${w}`,i)}finally{Q.delete(t),ie(t)}return}case"logout":{if(!n){await l(e,"Usage: /logout <provider>",i);return}const r=E(n),{authStorage:u}=await R();u.logout(r),await l(e,`Logged out from ${r}.`,i);return}default:await l(e,`Unknown command: ${o}`,i)}}async function Rt(e,t,o,n=[],i){const c=V(o);if(c){await ye(e,t,c.command,c.args,i);return}const a=O(e,i,i!==void 0);if(!a)return;const s=await I(a),d=ee(s);d.length>0&&(await $(s),await Promise.all(d.map(h=>j(a,h).catch(b=>{console.warn(`[tg-agent] cleanup session file failed id=${h}`,b)}))));let r=z(s);if(!r)try{r=F(s,""),await $(s),await l(e,`Created session ${r.id}.`,i)}catch(h){await l(e,h.message,i);return}const{resolved:u,images:f}=await Ie(n);if(n.length>0&&u.length===0&&!o.trim()){await l(e,"Failed to download attachments.",i);return}const g=Ye(u),w=[];o.trim()&&w.push(o.trim()),g&&w.push(g);const y=w.join(`
16
-
17
- `)||"Attachment received.",x={role:"user",content:y,ts:C()};Y(r,x,m.maxHistoryMessages),await $(s),console.log(`[tg-agent] request user=${t} chat=${a} session=${r.id} messages=${r.messages.length} textLen=${y.length} attachments=${u.length} provider=${r.modelProvider??"-"} model=${r.modelId??"-"}`);let M=null;try{M=await xt(e,i)}catch(h){console.warn("[tg-agent] status message failed",h)}const D={sessionId:r.id,chatId:e,messageThreadId:i,status:M,abortRequested:!1,cancelRequested:!1};Ke(a,D);try{const h=await Fe(async()=>{const N=await xe({chatId:a,sessionId:r.id,prompt:y,images:f,systemPrompt:m.systemPrompt,modelProvider:r.modelProvider,modelId:r.modelId,workspaceDir:q(a,s),telegram:{chatId:e,sendPhoto:async(_,k)=>{const P={};k&&(P.caption=k),i!==void 0&&(P.message_thread_id=i),await v.sendPhoto(e,_,P)},sendDocument:async(_,k)=>{const P={};k&&(P.caption=k),i!==void 0&&(P.message_thread_id=i),await v.sendDocument(e,_,P)}},onAbortReady:_=>{D.abort=_,D.abortRequested&&_()},onStatus:M?_=>{const k=Pt(_);k&&M?.update(k)}:void 0});return console.log(`[tg-agent] response session=${r.id} model=${N.modelProvider}/${N.modelId} file=${N.sessionFile}`),N.text});if(D.cancelRequested){M?await M.finalize("Cancelled by user."):await l(e,"Cancelled by user.",i);return}const b={role:"assistant",content:h,ts:C()};Y(r,b,m.maxHistoryMessages),await $(s),M?await M.finalize(h):await l(e,h,i)}catch(h){if(console.error("[tg-agent] runModel error",h),D.cancelRequested){M?await M.fail("Cancelled by user."):await l(e,"Cancelled by user.",i);return}const b=B(h);M?await M.fail(`Error: ${b}`):await l(e,`Error: ${b}`,i)}finally{Ge(a)}}v.on("callback_query",e=>{const t=e.data??"",o=e.message?.chat.id;if(!e.from?.id||!o){v.answerCallbackQuery(e.id);return}const n=String(e.from.id);if(!ue(n)){le(n,o),v.answerCallbackQuery(e.id);return}if(!t.startsWith("cmd:")){v.answerCallbackQuery(e.id);return}const i=ht(t);if(!i){v.answerCallbackQuery(e.id,{text:"Command expired."});return}v.answerCallbackQuery(e.id);const c=e.message?.message_thread_id,p=e.message?.is_topic_message??!1,a=O(o,c,p);a&&ne(a,async()=>{const s=V(i);if(!s){await l(o,"Invalid command.",c);return}if(s.command==="stop"){await se(o,a,c);return}await ye(o,n,s.command,s.args,c)}).catch(async s=>{console.error("[tg-agent] runModel error",s);const d=B(s);await l(o,`Error: ${d}`,c)})}),v.on("message",e=>{if(!e.from?.id)return;const t=String(e.from.id),o=e.chat.id;if(!ue(t)){le(t,o);return}const n=e.message_thread_id,i=e.is_topic_message??!1,c=O(o,n,i);if(!c)return;const p=(e.text??e.caption??"").trim(),a=Te(e);if(!p&&a.length===0)return;const s=A.get(t);if(s){if(p==="/stop"||p==="/cancel"){at(t,"Login cancelled by user."),l(o,"Login cancelled.",n);return}if(!p){l(o,"Login expects a text response.",n);return}ie(t),s.resolve(p);return}if(V(p)?.command==="stop"){se(o,c,n);return}ne(c,()=>Rt(o,t,p,a,n)).catch(async r=>{console.error("[tg-agent] runModel error",r);const u=B(r);await l(o,`Error: ${u}`,n)})}),v.on("polling_error",e=>{console.error("Polling error",e)}),console.log("tg-agent started");
package/dist/mcp.js DELETED
@@ -1,5 +0,0 @@
1
- import J from"node:fs";import R from"node:fs/promises";import W from"node:path";import q from"node:readline";import{spawn as H}from"node:child_process";import*as U from"@iarna/toml";const G=6e4,A=2e5,Q=40,X=3500;let w=null,_=!1;const m=new Map,V=1500;function I(t){return W.join(t,"config.toml")}function lt(t){const e=I(t);try{const r=J.readFileSync(e,"utf8");return O(r)}catch{return[]}}async function Y(t){const e=I(t);try{const r=await R.readFile(e,"utf8");return O(r)}catch{return[]}}async function ft(t,e={}){if(w)return w;const r=await Y(t);if(r.length===0)return w="","";const o=e.maxTools??Q,a=e.maxChars??X,i=e.timeoutMs??4e3,n=e.maxBytes??A,s=["MCP catalog (auto-discovered):","Use tool 'mcp' with server=<name> method=<tool> params=<object>."];for(const u of r){const l=await B(u,{timeoutMs:i,maxBytes:n});if(s.push(`${u.name} (${u.type})`),l.length===0){s.push(" - tools unavailable");continue}const d=l.slice(0,o);for(const p of d){const g=p.description?`: ${p.description}`:"";s.push(` - ${p.name}${g}`)}l.length>d.length&&s.push(` - ...and ${l.length-d.length} more`)}let c=s.join(`
2
- `);return c.length>a&&(c=`${c.slice(0,a-20)}...
3
- (truncated)`),w=c,c}function dt(){w&&(_=!0)}function pt(){w=null,_=!1,m.clear()}function ht(t){if(t.type==="http")return t.url?`url=${t.url}`:"url=(missing)";const e=t.args&&t.args.length>0?` ${t.args.join(" ")}`:"";return t.command?`command=${t.command}${e}`:"command=(missing)"}async function mt(t,e=5e3){const r=Date.now();try{return await P(t,"tools/list",{},{timeoutMs:e}),{ok:!0,durationMs:Date.now()-r}}catch(o){const a=o instanceof Error?o.message:String(o);return{ok:!1,durationMs:Date.now()-r,error:a}}}async function P(t,e,r,o={}){const a=k(o.timeoutMs??G,1e3,12e4),i=k(o.maxBytes??A,1024,5e6),n=new AbortController,s=()=>n.abort();o.signal?.addEventListener("abort",s,{once:!0});const c=setTimeout(()=>n.abort(),a);try{return t.type==="http"?(e!=="initialize"&&e!=="notifications/initialized"&&await v(t,i,n.signal),await Z(t,e,r,i,n.signal)):await nt(t,e,r,i,n.signal)}finally{clearTimeout(c),o.signal?.removeEventListener("abort",s)}}function k(t,e,r){return Number.isNaN(t)?e:Math.min(r,Math.max(e,t))}async function B(t,e){try{const r=await P(t,"tools/list",{},e);return K(r.output)}catch(r){const o=r instanceof Error?r.message:String(r);return console.warn(`[tg-agent] mcp tools/list failed server=${t.name} error=${o}`),[]}}function K(t){let e;try{e=JSON.parse(t)}catch{return[]}if(!e||typeof e!="object")return[];const r=e,a=(r.result??r).tools??r.tools;if(!Array.isArray(a))return[];const i=[];for(const n of a){if(!n||typeof n!="object")continue;const s=n,c=typeof s.name=="string"?s.name:"";if(!c)continue;const u=typeof s.description=="string"?s.description:void 0,l=s.inputSchema;i.push({name:c,description:u,inputSchema:l})}return i}async function Z(t,e,r,o,a){if(!t.url)throw new Error("MCP server url is missing.");const i=Date.now(),n=await x(t,e,r,o,a),s=j(n.parsed);if(s)throw new Error(s);let c=n.bodyText;return n.parsed&&(c=JSON.stringify(n.parsed,null,2)),{ok:n.statusCode>=200&&n.statusCode<300,output:c,durationMs:Date.now()-i,bytes:n.bytes,truncated:n.truncated,statusCode:n.statusCode,statusText:n.statusText,contentType:n.contentType}}async function x(t,e,r,o,a){if(!t.url)throw new Error("MCP server url is missing.");const i=m.get(t.name),n={jsonrpc:"2.0",id:`tg-agent-${Date.now()}`,method:e,params:r??{}},s={"content-type":"application/json"};t.auth&&(s.authorization=t.auth.startsWith("Bearer ")?t.auth:`Bearer ${t.auth}`),i?.cookie&&(s.cookie=i.cookie),i?.sessionId&&(s["mcp-session-id"]=i.sessionId);const c=await fetch(t.url,{method:"POST",headers:s,body:JSON.stringify(n),signal:a});tt(t.name,c);const u=await ot(c,o,a);let l;try{l=JSON.parse(u.text)}catch{l=void 0}return et(t.name,l),{statusCode:c.status,statusText:c.statusText,contentType:c.headers.get("content-type"),bodyText:u.text,parsed:l,bytes:u.bytes,truncated:u.truncated}}function j(t){if(!t||typeof t!="object")return null;const e=t;if(e.error&&typeof e.error=="object"){const r=e.error;if(typeof r.message=="string")return r.message}return typeof e.error_description=="string"?e.error_description:typeof e.error=="string"?e.error:null}async function v(t,e,r){const o=m.get(t.name);if(o?.initializedAt)return;if(o?.inFlight){await o.inFlight;return}const a=(async()=>{const i=await x(t,"initialize",{protocolVersion:"2024-11-05",clientInfo:{name:"tg-agent",version:process.env.npm_package_version??"dev"},capabilities:{}},e,r),n=j(i.parsed);if(n){const u=n.toLowerCase();if(u.includes("method")&&u.includes("not"))return;throw new Error(n)}const s=new AbortController,c=setTimeout(()=>s.abort(),V);try{await x(t,"notifications/initialized",{},e,s.signal)}catch{}finally{clearTimeout(c)}})();m.set(t.name,{initializedAt:Date.now(),inFlight:a});try{await a;const i=m.get(t.name);m.set(t.name,{initializedAt:Date.now(),cookie:i?.cookie,sessionId:i?.sessionId})}catch(i){throw m.delete(t.name),i}}function tt(t,e){const o=m.get(t)??{initializedAt:0},a=e.headers.get("set-cookie"),i=e.headers.getSetCookie?.(),n=i&&i.length>0?i.join("; "):a;n&&m.set(t,{...o,cookie:n});const s=e.headers.get("mcp-session-id")??e.headers.get("x-mcp-session-id");s&&m.set(t,{...o,sessionId:s})}function et(t,e){if(!e||typeof e!="object")return;const o=e.result;if(!o)return;const a=typeof o.sessionId=="string"&&o.sessionId||typeof o.session_id=="string"&&o.session_id;if(!a)return;const i=m.get(t)??{initializedAt:0};m.set(t,{...i,sessionId:a})}async function nt(t,e,r,o,a){if(!t.command)throw new Error("MCP server command is missing.");const i=Date.now(),n=H(t.command,t.args??[],{stdio:["pipe","pipe","pipe"]}),s=()=>{n.killed||n.kill("SIGTERM")};if(a.aborted)throw s(),new Error("MCP request aborted.");const c=new Map;let u=!1,l="";const d=new Error("MCP request aborted."),p=q.createInterface({input:n.stdout,terminal:!1});p.on("line",f=>{if(f.length>o){u=!0;return}let h=null;try{h=JSON.parse(f)}catch{return}const y=typeof h.id=="string"?h.id:typeof h.id=="number"?String(h.id):"";if(!y)return;const C=c.get(y);C&&(c.delete(y),C.resolve(h))}),n.stderr?.on("data",f=>{const h=f.toString();if(l.length+h.length>o){u=!0;return}l+=h});const g=()=>{for(const f of c.values())f.reject(d);c.clear(),s()};a.addEventListener("abort",g,{once:!0});const b=f=>{const h=f===0?"MCP stdio exited.":l.trim()||"MCP stdio exited with error.";for(const y of c.values())y.reject(new Error(h));c.clear()};n.once("exit",f=>b(f));const E=async(f,h)=>{const y=`tg-agent-${Date.now()}-${Math.random().toString(16).slice(2,8)}`,C={jsonrpc:"2.0",id:y,method:f,params:h??{}};return await new Promise((F,N)=>{c.set(y,{resolve:F,reject:N}),n.stdin?.write(`${JSON.stringify(C)}
4
- `)})};fetch("http://127.0.0.1:7243/ingest/9e452bb4-cc67-4519-89fa-8fb51d810231",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({location:"mcp.ts:callStdioMcp:beforeInit",message:"sending initialize request",data:{elapsed:Date.now()-i},timestamp:Date.now(),sessionId:"debug-session",hypothesisId:"B,C"})}).catch(()=>{});const T=await E("initialize",{protocolVersion:"2024-11-05",clientInfo:{name:"tg-agent",version:process.env.npm_package_version??"dev"},capabilities:{}});if(fetch("http://127.0.0.1:7243/ingest/9e452bb4-cc67-4519-89fa-8fb51d810231",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({location:"mcp.ts:callStdioMcp:afterInit",message:"initialize response received",data:{elapsed:Date.now()-i,hasError:!!T.error},timestamp:Date.now(),sessionId:"debug-session",hypothesisId:"B,C"})}).catch(()=>{}),T.error&&typeof T.error=="object"){const f=T.error.message??"MCP initialize failed.";throw s(),new Error(String(f))}const D={jsonrpc:"2.0",method:"notifications/initialized"};n.stdin?.write(`${JSON.stringify(D)}
5
- `),fetch("http://127.0.0.1:7243/ingest/9e452bb4-cc67-4519-89fa-8fb51d810231",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({location:"mcp.ts:callStdioMcp:beforeMethod",message:"sending method request",data:{method:e,elapsed:Date.now()-i},timestamp:Date.now(),sessionId:"debug-session",hypothesisId:"C"})}).catch(()=>{});const S=await E(e,r);a.removeEventListener("abort",g),p.close(),n.stdin?.end(),s();const $=new Promise(f=>{n.once("exit",()=>f())});if(await Promise.race([$,new Promise(f=>setTimeout(f,500))]),S.error&&typeof S.error=="object"){const f=S.error.message??"MCP request failed.";throw new Error(String(f))}const M=JSON.stringify(S,null,2),L=M.length>o?M.slice(0,o):M;return M.length>o&&(u=!0),{ok:!0,output:L,durationMs:Date.now()-i,bytes:Math.min(M.length,o),truncated:u}}async function ot(t,e,r){const o=t.body?.getReader?.();if(!o){const d=await t.text(),p=Math.min(d.length,e);return{text:d.slice(0,e),bytes:p,truncated:d.length>e}}const a=new TextDecoder("utf-8"),i=[];let n=0,s=!1;for(;;){if(r.aborted){try{await o.cancel()}catch{}throw new Error("MCP request aborted.")}const{done:d,value:p}=await o.read();if(d)break;if(!p)continue;const g=n+p.byteLength;if(g>e){const b=Math.max(0,e-n);b>0&&(i.push(p.slice(0,b)),n+=b),s=!0;try{await o.cancel()}catch{}break}i.push(p),n=g}const c=new Uint8Array(n);let u=0;for(const d of i)c.set(d,u),u+=d.byteLength;return{text:a.decode(c),bytes:n,truncated:s}}function O(t){const e=[];let r;try{r=U.parse(t)}catch{return e}const o=r.mcp_servers;if(!o||typeof o!="object")return e;for(const[a,i]of Object.entries(o)){if(!i||typeof i!="object")continue;const n=i,s=typeof n.type=="string"?n.type.toLowerCase():void 0,c=typeof n.url=="string"?n.url:void 0,u=typeof n.command=="string"?n.command:void 0,l=s==="http"||s==="stdio"?s:c?"http":u?"stdio":void 0;if(!l||l==="http"&&!c||l==="stdio"&&!u)continue;let d;Array.isArray(n.args)&&(d=n.args.filter(g=>typeof g=="string").map(g=>g.trim()));const p=typeof n.auth=="string"?n.auth:typeof n.authorization=="string"?n.authorization:typeof n.token=="string"?n.token:void 0;e.push({name:a,type:l,url:c,command:u,args:d,auth:p})}return e}function z(t){return t.startsWith('"')&&t.endsWith('"')||t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1):t}function gt(t){const e=t.trim();return e?e.startsWith('"')&&e.endsWith('"')?e.slice(1,-1).replace(/\\\\/g,"\\").replace(/\\"/g,'"'):e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e:""}function yt(t){const e=t.trim();if(!e.startsWith("[")||!e.endsWith("]"))return[];const r=e.slice(1,-1).trim();if(!r)return[];const o=[];let a="",i=!1,n="";for(let c=0;c<r.length;c+=1){const u=r[c];if(!i&&(u==='"'||u==="'")){i=!0,n=u;continue}if(i&&u===n){i=!1;continue}if(!i&&u===","){const l=a.trim();l&&o.push(z(l)),a="";continue}a+=u}const s=a.trim();return s&&o.push(z(s)),o}function wt(t){let e=!1,r="";for(let o=0;o<t.length;o+=1){const a=t[o];if(!e&&(a==='"'||a==="'")){e=!0,r=a;continue}if(e&&a===r){e=!1;continue}if(!e&&(a==="#"||a===";"))return t.slice(0,o)}return t}export{P as callMcpServer,ht as formatMcpTarget,dt as freezeMcpCatalog,ft as getMcpCatalog,I as getMcpConfigPath,Y as loadMcpServers,lt as loadMcpServersSync,mt as probeMcpServer,pt as refreshMcpCatalog};
@@ -1,9 +0,0 @@
1
- import{createAgentSession as z,discoverAuthStorage as N,discoverModels as q,SessionManager as K,SettingsManager as X}from"@mariozechner/pi-coding-agent";import b from"node:fs/promises";import v from"node:path";import{config as c}from"./config.js";import{readCodexOAuth as G}from"./codexAuth.js";import{createCustomTools as H}from"./customTools.js";import{getMcpCatalog as J}from"./mcp.js";import{ensureDir as T}from"./utils.js";import{sessionFilePath as Q}from"./sessionStore.js";const U={"codex-mini-latest":"gpt-5.1-codex-mini","codex-max-latest":"gpt-5.1-codex-max","codex-latest":"gpt-5.2-codex"};function P(e){const o=e.trim().toLowerCase();return o==="codex"?"openai-codex":o}function V(e,o){const s=e.trim();if(!s)return{provider:o,modelId:""};if(s.includes("/")){const[a,i]=s.split("/",2);return{provider:a.trim()||o,modelId:i.trim()}}return{provider:o,modelId:s}}function W(e,o){return e!=="openai-codex"?o:U[o]??o}function Y(e,o){const s=e.getAvailable().filter(i=>i.provider===o);return s.length>0?s[0]:e.getAll().filter(i=>i.provider===o)[0]}function Z(e,o){const s=!!o?.provider?.trim(),a=!!o?.modelId?.trim(),i=P(o?.provider||c.modelProvider||"openai-codex"),r=s||a?"":c.modelRef||"",{provider:y,modelId:M}=V(r,i),f=o?.provider?i:P(y);let m=a?o?.modelId?.trim()||"":M;if(!m){const l=Y(e,f);return l?{model:l,provider:f,modelId:l.id}:{model:void 0,provider:f,modelId:""}}const I=W(f,m);return{model:e.find(f,I),provider:f,modelId:I}}function ee(e){const o=G();return o?(e.setRuntimeApiKey("openai-codex",o.accessToken),{source:o.source,expiresAt:o.expiresAt}):null}function te(e){if(e?.role!=="assistant")return"";const s=e.content;if(typeof s=="string")return s.trim();if(!Array.isArray(s))return"";const a=s.filter(r=>typeof r=="object"&&r&&r.type==="text").map(r=>r.text??"").map(r=>r.trim()).filter(Boolean);if(a.length>0)return a.join(`
2
-
3
- `);const i=s.filter(r=>typeof r=="object"&&r&&r.type==="thinking").map(r=>r.thinking??"").map(r=>r.trim()).filter(Boolean);return i.length>0?i.join(`
4
-
5
- `):""}function oe(e){if(e.length===0)return"messages=0";const o=e.slice(-6).map(s=>{const a=s?.role??"unknown",i=s.content,r=s?.stopReason,y=s?.errorMessage;if(typeof i=="string")return`${a}(text:${i.length}${r?`,stop=${r}`:""})`;if(Array.isArray(i)){const f=[`blocks:${i.map(m=>typeof m=="object"&&m&&"type"in m?String(m.type||"unknown"):typeof m).join(",")||"none"}`,r?`stop=${r}`:null,y?"error=1":null].filter(Boolean).join(",");return`${a}(${f})`}if(i==null){const M=["empty",r?`stop=${r}`:null,y?"error=1":null].filter(Boolean).join(",");return`${a}(${M})`}return`${a}(${typeof i}${r?`,stop=${r}`:""})`});return`messages=${e.length} last=[${o.join(" ")}]`}function ne(e){const o=e.trim();return o.toLowerCase().includes("usage limit")?`${o}
6
-
7
- Suggestion: wait for the limit to reset or switch to another provider/model.`:o}function se(e,o){const s=o?.getLastAssistantText?.();if(s?.trim())return s.trim();for(let a=e.length-1;a>=0;a-=1){const i=te(e[a]);if(i)return i}return""}function re(e){for(let o=e.length-1;o>=0;o-=1)if(e[o]?.role==="assistant")return e[o]}async function pe(e){const o=e.workspaceDir||c.workspaceDir;await T(c.sessionDir),await T(c.agentDir),await T(o);const s=Q(e.chatId,e.sessionId),a=N(c.agentDir),i=ee(a);i&&console.log(`[tg-agent] codex oauth source=${i.source} expiresAt=${new Date(i.expiresAt).toISOString()}`);const r=q(a,c.agentDir),{model:y,provider:M,modelId:f}=Z(r,{provider:e.modelProvider,modelId:e.modelId});f&&!y&&console.warn(`[tg-agent] model not found: ${M}/${f}`);const m=K.open(s),I=X.create(o,c.agentDir);try{const t=v.join(c.agentDir,"skills"),n=v.join(o,".pi","skills"),d=await b.access(t).then(()=>!0).catch(()=>!1),g=await b.access(n).then(()=>!0).catch(()=>!1);if(d){const h=(await b.readdir(t,{withFileTypes:!0})).filter($=>$.isDirectory()).map($=>$.name);console.log(`[tg-agent] skills directory found at ${t} with ${h.length} skill(s): ${h.join(", ")}`)}else console.log(`[tg-agent] skills directory not found at ${t}`);if(g){const h=(await b.readdir(n,{withFileTypes:!0})).filter($=>$.isDirectory()).map($=>$.name);console.log(`[tg-agent] workspace skills directory found at ${n} with ${h.length} skill(s): ${h.join(", ")}`)}const w=I.getSettings?.();if(w){const h=w.skills?.enabled!==!1;console.log(`[tg-agent] skills enabled in settings: ${h}`)}}catch(t){const n=t instanceof Error?t.message:String(t);console.warn(`[tg-agent] skills check failed: ${n}`)}let D="";try{D=await J(c.agentDir,{timeoutMs:4e3,maxBytes:c.fetchMaxBytes,maxChars:3e3})}catch(t){const n=t instanceof Error?t.message:String(t);console.warn(`[tg-agent] mcp catalog error: ${n}`)}const{session:l,modelFallbackMessage:_}=await z({cwd:o,agentDir:c.agentDir,authStorage:a,modelRegistry:r,model:y??void 0,sessionManager:m,settingsManager:I,customTools:H({telegram:e.telegram}),systemPrompt:t=>{const n=e.systemPrompt?.trim(),d=[t];return n&&d.push(n),D&&d.push(D),d.join(`
8
-
9
- `)}});try{const t=l.messages,n=t.some(u=>{const h=u.role,$=u.content;return h==="system"&&typeof $=="string"?$.toLowerCase().includes("compaction")||$.toLowerCase().includes("compact"):u.type==="compaction"||u.compaction!==void 0});console.log(`[tg-agent] session manager type: ${typeof m}`),console.log(`[tg-agent] session messages count: ${t.length}`),console.log(`[tg-agent] compacting support detected: ${n||"unknown (will be detected during runtime)"}`);const g=typeof m.compact=="function",w=typeof m.appendCompaction=="function";console.log(`[tg-agent] SessionManager.compact method: ${g}`),console.log(`[tg-agent] SessionManager.appendCompaction method: ${w}`)}catch(t){const n=t instanceof Error?t.message:String(t);console.warn(`[tg-agent] compacting check failed: ${n}`)}_&&console.warn(`[tg-agent] modelFallback=${_}`);let R=!1;const B=()=>{R=!0,l.abort()};e.onAbortReady?.(B);const k=c.logAgentEvents,F=c.logAgentStream,C=new Map,L=l.subscribe(t=>{switch(t.type){case"agent_start":k&&console.log(`[tg-agent] agent start session=${e.sessionId}`),p=Date.now(),e.onStatus?.({type:"agent_start"});break;case"agent_end":k&&console.log(`[tg-agent] agent end session=${e.sessionId}`),e.onStatus?.({type:"agent_end"});break;case"turn_start":k&&console.log(`[tg-agent] turn start session=${e.sessionId}`),p=Date.now(),e.onStatus?.({type:"turn_start"});break;case"turn_end":k&&console.log(`[tg-agent] turn end session=${e.sessionId} toolResults=${t.toolResults.length}`),p=Date.now(),e.onStatus?.({type:"turn_end",toolResults:t.toolResults.length});break;case"message_start":{if(k){const n=t.message.role??"unknown";console.log(`[tg-agent] message start session=${e.sessionId} role=${n}`)}p=Date.now();{const n=t.message.role??"unknown";e.onStatus?.({type:"message_start",role:n})}break}case"message_end":{if(k){const n=t.message.role??"unknown";console.log(`[tg-agent] message end session=${e.sessionId} role=${n}`)}p=Date.now();{const n=t.message.role??"unknown";e.onStatus?.({type:"message_end",role:n})}break}case"message_update":{if(!F)break;if(t.assistantMessageEvent.type==="text_delta"){const d=(t.assistantMessageEvent.delta??"").length;d>0&&console.log(`[tg-agent] stream delta session=${e.sessionId} chars=${d}`),p=Date.now()}t.assistantMessageEvent.type==="thinking_delta"&&(p=Date.now());break}case"tool_execution_start":{C.set(t.toolCallId,Date.now()),console.log(`[tg-agent] tool start name=${t.toolName} id=${t.toolCallId}`),A+=1,p=Date.now(),e.onStatus?.({type:"tool_start",name:t.toolName,id:t.toolCallId,args:t.args});break}case"tool_execution_end":{const n=C.get(t.toolCallId),d=n?Date.now()-n:0;console.log(`[tg-agent] tool end name=${t.toolName} id=${t.toolCallId} ok=${!t.isError} durationMs=${d}`),C.delete(t.toolCallId),A=Math.max(0,A-1),p=Date.now(),e.onStatus?.({type:"tool_end",name:t.toolName,id:t.toolCallId,ok:!t.isError,durationMs:d});break}case"auto_compaction_start":{const n=t.reason??"unknown";console.log(`[tg-agent] auto compaction started session=${e.sessionId} reason=${n}`),p=Date.now();break}case"auto_compaction_end":{const n=t.willRetry??!1;console.log(`[tg-agent] auto compaction ended session=${e.sessionId} willRetry=${n}`),p=Date.now();break}default:break}});let x=null,E=null,S=!1,j=0,O=!1,p=Date.now(),A=0;try{const t=Date.now();x=setInterval(()=>{const g=Date.now()-t;console.log(`[tg-agent] prompt running session=${e.sessionId} elapsedMs=${g} streaming=${l.isStreaming}`),e.onStatus?.({type:"heartbeat",elapsedMs:g,streaming:l.isStreaming})},15e3),E=setInterval(()=>{if(S||A>0)return;const g=Date.now()-p,w=l.isStreaming?c.modelTimeoutStreamingMs:c.modelTimeoutMs,u=Math.max(1e3,w);g>=u&&(S=!0,j=u,O=l.isStreaming,console.warn(`[tg-agent] model timeout session=${e.sessionId} elapsedMs=${g}`),l.abort())},2e3);try{if(await l.prompt(e.prompt,e.images&&e.images.length>0?{images:e.images}:void 0),S)throw new Error(`Model request timed out after ${c.modelTimeoutMs}ms`)}catch(g){if(R)throw new Error("Cancelled by user.");if(S){const w=O?" (streaming)":"",u=j||c.modelTimeoutMs;throw new Error(`Model request timed out after ${u}ms${w}`)}throw g}x&&clearInterval(x);const n=re(l.messages);if(n){const g=n?.stopReason,w=n?.errorMessage;if(g==="error"){const u=w?ne(w):"Model error without details.";throw console.warn(`[tg-agent] model error session=${e.sessionId} error=${u}`),new Error(u)}}const d=se(l.messages,l);if(!d){const g=oe(l.messages);throw console.warn(`[tg-agent] empty response session=${e.sessionId} ${g}`),new Error("No assistant response.")}return{text:d,sessionFile:s,sessionId:l.sessionId,modelProvider:l.model?.provider??M,modelId:l.model?.id??f,modelFallbackMessage:_}}finally{x&&clearInterval(x),E&&clearInterval(E),L(),m.flushPendingToolResults?.(),l.dispose()}}export{pe as runPiAgentPrompt};
@@ -1,5 +0,0 @@
1
- import{completeSimple as u,getModel as x}from"@mariozechner/pi-ai";import{config as p}from"./config.js";import{resolveApiKeyForProvider as f}from"./auth.js";const g={"codex-mini-latest":"gpt-5.1-codex-mini","codex-max-latest":"gpt-5.1-codex-max","codex-latest":"gpt-5.2-codex"};function h(n,e){const t=n.trim();if(!t)return{provider:e,modelId:""};if(t.includes("/")){const[i,r]=t.split("/",2);return{provider:i.trim()||e,modelId:r.trim()}}return{provider:e,modelId:t}}function k(n,e){return n!=="openai-codex"?e:g[e]??e}function v(n,e,t){return{role:"assistant",content:[{type:"text",text:n}],api:e.api,provider:e.provider,model:e.id,usage:{input:0,output:0,cacheRead:0,cacheWrite:0,totalTokens:0,cost:{input:0,output:0,cacheRead:0,cacheWrite:0,total:0}},stopReason:"stop",timestamp:t}}function y(n,e){return n.map(t=>t.role==="user"?{role:"user",content:t.content,timestamp:t.ts}:v(t.content,e,t.ts))}function I(n){const t=n.content.filter(o=>o.type==="text").map(o=>o.text.trim()).filter(Boolean).join(`
2
-
3
- `);return t||n.content.filter(o=>o.type==="thinking").map(o=>o.type==="thinking"?o.thinking.trim():"").filter(Boolean).join(`
4
-
5
- `)||"Empty response."}async function A(n,e,t){const i=p.modelProvider||"openai-codex",r=p.modelRef||"gpt-5.2",{provider:o,modelId:d}=h(r,i),m=k(o,d||"gpt-5.2"),c=x(o,m),{apiKey:a}=f(o),l={systemPrompt:e,messages:y(n,c)},s=await u(c,l,{apiKey:a,sessionId:t,maxTokens:p.maxOutputTokens||void 0});return{text:I(s),assistant:s,provider:o,modelId:c.id}}export{A as runPiCompletion};
package/dist/proxy.js DELETED
@@ -1 +0,0 @@
1
- import{ProxyAgent as o,setGlobalDispatcher as n}from"undici";import{resolveFetchProxyInfo as p}from"./auth.js";let t=!1,e=null;function f(){if(t)return e;t=!0;const r=p();if(!r)return e=null,null;const l=new o(r.url);return n(l),e=r,r}export{f as applyFetchProxy};
@@ -1 +0,0 @@
1
- import u from"node:fs/promises";import f from"node:path";import{config as i}from"./config.js";import{atomicWriteJson as h,ensureDir as p,nowMs as a,shortId as m}from"./utils.js";const c=new Map;function l(e){return f.join(i.sessionDir,`${e}.json`)}function d(e){return e.replace(/[^a-zA-Z0-9_-]/g,"_")}function x(e,s){const n=d(e),t=d(s);return f.join(i.sessionDir,`${n}-${t}.jsonl`)}async function j(e,s){const n=x(e,s);try{await u.unlink(n)}catch(t){if(t.code==="ENOENT")return;throw t}}function S(e,s){const n=s?.sessions??{},t=s?.activeSessionId??null,o=s?.workspaceDir,r={chatId:e,workspaceDir:o,activeSessionId:t,sessions:n};return(!t||!n[t])&&(r.activeSessionId=null),r}async function g(e){await p(i.sessionDir);const s=c.get(e);if(s)return s;const n=l(e);try{const t=await u.readFile(n,"utf8"),o=JSON.parse(t),r=S(e,o);return c.set(e,r),r}catch(t){if(t.code==="ENOENT"){const o=S(e,{});return c.set(e,o),o}throw t}}async function w(e){await p(i.sessionDir);const s=l(e.chatId);await h(s,e),c.set(e.chatId,e)}function E(e){return Object.values(e.sessions).sort((s,n)=>n.updatedAt-s.updatedAt)}function y(e){return[]}function z(e,s){if(Object.keys(e.sessions).length>=i.maxSessions)throw new Error("Max sessions reached");const t=m(),o=a(),r={id:t,title:s&&s.length>0?s:`session-${t}`,messages:[],createdAt:o,updatedAt:o};return e.sessions[t]=r,e.activeSessionId=t,r}function N(e,s){return e.sessions[s]?(e.activeSessionId=s,!0):!1}function O(e){return e.activeSessionId?e.sessions[e.activeSessionId]??null:null}function P(e,s){return e.sessions[s]?(delete e.sessions[s],e.activeSessionId===s&&(e.activeSessionId=null),!0):!1}function F(e){e.messages=[],e.updatedAt=a()}function I(e,s,n){e.messages.push(s),e.messages.length>n&&(e.messages=e.messages.slice(-n)),e.updatedAt=a()}function $(e,s){e.workspaceDir=s}function C(e){return e.workspaceDir}const M=g,W=w;export{I as appendMessage,P as closeSession,z as createSession,j as deleteSessionFile,O as getActiveSession,C as getWorkspaceDir,E as listSessions,g as loadChatState,M as loadUserState,y as pruneExpiredSessions,F as resetSession,w as saveChatState,W as saveUserState,x as sessionFilePath,N as setActiveSession,$ as setWorkspaceDir};
package/dist/types.js DELETED
File without changes
package/dist/utils.js DELETED
@@ -1,2 +0,0 @@
1
- import c from"node:fs/promises";import f from"node:os";import s from"node:path";import{randomUUID as u}from"node:crypto";function w(){return Date.now()}function d(e){return e.startsWith("~")?s.join(f.homedir(),e.slice(1)):e}async function x(e){await c.mkdir(e,{recursive:!0})}async function g(e,o){const n=s.dirname(e),t=`${s.basename(e)}.${u()}.tmp`,r=s.join(n,t),i=JSON.stringify(o,null,2);await c.writeFile(r,i,"utf8"),await c.rename(r,e)}function v(){return u().split("-")[0]}function y(e,o){if(e.length<=o)return[e];const n=[];let t=e;for(;t.length>o;){let r=t.slice(0,o);const i=r.lastIndexOf(`
2
- `);i>o*.6&&(r=r.slice(0,i)),n.push(r),t=t.slice(r.length)}return t.length>0&&n.push(t),n}function M(){const e=new Map;return async function(n,t){const i=(e.get(n)??Promise.resolve()).then(t,t);e.set(n,i);try{return await i}finally{e.get(n)===i&&e.delete(n)}}}function j(e){let o=0;const n=[],t=()=>{if(o>=e)return;const r=n.shift();r&&(o+=1,r())};return async function(i){await new Promise(a=>{n.push(a),t()});try{return await i()}finally{o=Math.max(0,o-1),t()}}}export{g as atomicWriteJson,y as chunkText,M as createQueueMap,j as createSemaphore,x as ensureDir,d as expandHome,w as nowMs,v as shortId};