tg-agent 1.2.7 → 1.2.9
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 +48 -25
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,40 +1,63 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var
|
|
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
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
var W=(e,t)=>()=>(e&&(t=e(e=0)),t);import Oe from"node:fs/promises";import $n from"node:os";import ye from"node:path";import{randomUUID as Qe}from"node:crypto";function F(){return Date.now()}function H(e){return e.startsWith("~")?ye.join($n.homedir(),e.slice(1)):e}async function D(e){await Oe.mkdir(e,{recursive:!0})}async function Ze(e,t){let n=ye.dirname(e),o=`${ye.basename(e)}.${Qe()}.tmp`,r=ye.join(n,o),s=JSON.stringify(t,null,2);await Oe.writeFile(r,s,"utf8"),await Oe.rename(r,e)}function ce(){return Qe().split("-")[0]}function et(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 tt(){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 nt(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(l=>{n.push(l),o()});try{return await s()}finally{t=Math.max(0,t-1),o()}}}var Z=W(()=>{"use strict"});import ot from"node:fs";import be from"node:path";import*as ve from"@iarna/toml";function it(){let e=H(rt);return be.join(e,_n)}function O(e,t){let n=e[t];return n&&typeof n=="object"&&!Array.isArray(n)?n:{}}function T(e,t){return typeof e=="string"?e:typeof e=="number"||typeof e=="boolean"?String(e):t}function K(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 he(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 at(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 An(e){return new Set(at(e))}function Pn(e){let t=new Map;for(let[n,o]of Object.entries(e))typeof o=="string"&&o.trim()&&t.set(n,be.resolve(H(o.trim())));return t}function le(){let e=it();try{let t=ot.readFileSync(e,"utf8"),n=ve.parse(t);return{configPath:e,data:n,exists:!0}}catch{return{configPath:e,data:{},exists:!1}}}async function Ie(e,t){await D(be.dirname(e));let n=ve.stringify(t);await ot.promises.writeFile(e,n,"utf8")}function ct(){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:st},tls:{extra_ca_certs:"",reject_unauthorized:""},security_audit:{enabled:!1,model_provider:"",model_id:"",whitelist_patterns:[],confirm_timeout_ms:12e4}}}function we(e){return!!(e&&typeof e=="object"&&!Array.isArray(e))}function lt(e,t){let n=!1,o=(r,s)=>{for(let[l,a]of Object.entries(s)){if(!(l in r)){r[l]=a,n=!0;continue}let i=r[l];we(i)&&we(a)&&o(i,a)}};return we(e)&&we(t)&&o(e,t),n}function ut(e){let t=O(e,"telegram");return T(t.bot_token,"").trim()}function dt(e,t){let n=O(e,"telegram");n.bot_token=t.trim(),e.telegram=n}function mt(e){let t=O(e,"telegram"),n=O(e,"model"),o=O(e,"paths"),r=O(e,"limits"),s=O(e,"timeouts"),l=O(e,"fetch"),a=O(e,"proxy"),i=O(e,"auth"),u=O(e,"logging"),c=O(e,"system"),m=O(e,"tls"),g=O(e,"workspace_mappings"),p=O(e,"security_audit"),h=T(o.workspace_dir,process.cwd()),k=T(o.session_dir,"~/.tg-agent/tg-sessions"),P=Pn(g),S=T(m.reject_unauthorized,""),I=S===""?null:he(S,!0);return{telegramToken:T(t.bot_token,"").trim(),telegramAllowedUsers:An(t.allowed_user_ids),telegramParseMode:T(t.parse_mode,"").trim(),modelProvider:T(n.provider,"openai-codex").trim(),modelRef:T(n.model,"gpt-5.2").trim(),openaiApiKey:T(n.openai_api_key,"").trim(),sessionDir:H(k),agentDir:H(rt),workspaceDir:be.resolve(H(h)),workspaceMappings:P,maxSessions:K(r.max_sessions,5),maxConcurrent:K(r.max_concurrent,5),maxHistoryMessages:K(r.max_history_messages,40),maxOutputTokens:K(r.max_output_tokens,0),fetchMaxBytes:K(l.max_bytes,2e5),fetchTimeoutMs:K(s.fetch_timeout_ms,6e4),modelTimeoutMs:K(s.model_timeout_ms,6e4),modelTimeoutStreamingMs:K(s.model_timeout_stream_ms,3e5),systemPrompt:T(c.prompt,st),proxyUrl:T(a.url,"").trim(),fetchProxyUrl:T(l.proxy_url,"").trim(),codexHome:H(T(i.codex_home,"~/.codex")),logAgentEvents:he(u.agent_events,!0),logAgentStream:he(u.agent_stream,!0),tlsExtraCaCerts:T(m.extra_ca_certs,"").trim(),tlsRejectUnauthorized:I,audit:{enabled:he(p.enabled,!1),modelProvider:T(p.model_provider,"").trim(),modelId:T(p.model_id,"").trim(),whitelistPatterns:at(p.whitelist_patterns),confirmTimeoutMs:K(p.confirm_timeout_ms,6e4)}}}function gt(){let{data:e}=le();return d=mt(e),d}function pt(){let e=[];if(d.telegramToken||e.push("telegram.bot_token"),e.length>0)throw new Error(`Missing config values: ${e.join(", ")} (edit ${it()})`)}var rt,_n,st,Tn,d,G=W(()=>{"use strict";Z();rt="~/.tg-agent",_n="config.toml",st=`You are running in user's personal computer or VPS, using telegram bot to interact with user.
|
|
4
|
+
|
|
5
|
+
Important behavioral rules:
|
|
6
|
+
- Do NOT mention the name of your underlying framework, technical implementation, or any package names
|
|
7
|
+
- Do NOT refer to yourself as "pi", "pi-coding-agent", or any other framework/tool name
|
|
8
|
+
- When users ask about your identity or implementation, simply say you are a coding assistant
|
|
9
|
+
- Focus on helping with tasks rather than discussing your technical stack or architecture
|
|
10
|
+
- Do not mention documentation paths or framework-specific resources unless directly relevant to the task
|
|
11
|
+
|
|
12
|
+
Be concise and practical in all responses.`;({data:Tn}=le()),d=mt(Tn)});import{createHash as Cn}from"node:crypto";import ft from"node:fs";import Rn from"node:path";import{execSync as En}from"node:child_process";function In(){return Rn.join(d.codexHome,Dn)}function Ln(e){return`cli|${Cn("sha256").update(e).digest("hex").slice(0,16)}`}function jn(){if(process.platform!=="darwin")return null;let e=d.codexHome,t=Ln(e);try{let n=En(`security find-generic-password -s "${On}" -a "${t}" -w`,{encoding:"utf8",timeout:5e3,stdio:["pipe","pipe","pipe"]}).trim(),o=JSON.parse(n),r=o.tokens,s=r?.access_token,l=r?.refresh_token;if(typeof s!="string"||!s||typeof l!="string"||!l)return null;let a=o.last_refresh,i=typeof a=="string"||typeof a=="number"?new Date(a).getTime():Date.now(),u=Number.isFinite(i)?i+3600*1e3:Date.now()+3600*1e3;return{accessToken:s,refreshToken:l,expiresAt:u,source:"keychain"}}catch{return null}}function Nn(){let e=In();try{let t=ft.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 l=Date.now()+3600*1e3;try{l=ft.statSync(e).mtimeMs+3600*1e3}catch{}return{accessToken:r,refreshToken:s,expiresAt:l,source:"file"}}catch{return null}}function oe(){return jn()??Nn()}var Dn,On,xe=W(()=>{"use strict";G();Dn="auth.json",On="Codex Auth"});function yt(e){let t=e.trim().toLowerCase();if(t==="openai-codex"||t==="codex"){let n=oe();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 Fn(){return d.proxyUrl?{url:d.proxyUrl,source:"config.proxy.url"}:d.fetchProxyUrl?{url:d.fetchProxyUrl,source:"config.fetch.proxy_url"}:null}function ht(e){let t=e.toLowerCase();return t.startsWith("socks5://")||t.startsWith("socks4://")||t.startsWith("socks://")?"socks":t.startsWith("https://")?"https":"http"}function wt(){let e=Fn();return e?{url:e.url,kind:ht(e.url),source:e.source}:null}function bt(){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=ht(n);if(o!=="socks")return{url:n,kind:o,source:t.key}}return null}var Le=W(()=>{"use strict";G();xe()});import{ProxyAgent as zn,setGlobalDispatcher as Un}from"undici";function xt(){if(vt)return je;vt=!0;let e=bt();if(!e)return je=null,null;let t=new zn(e.url);return Un(t),je=e,e}var vt,je,St=W(()=>{"use strict";Le();vt=!1,je=null});import Bn from"node:fs";import Wn from"node:fs/promises";import Hn from"node:path";import qn from"node:readline";import{spawn as Jn}from"node:child_process";import*as Mt from"@iarna/toml";function At(e){return Hn.join(e,"config.toml")}function Se(e){let t=At(e);try{let n=Bn.readFileSync(t,"utf8");return Rt(n)}catch{return[]}}async function ue(e){let t=At(e);try{let n=await Wn.readFile(t,"utf8");return Rt(n)}catch{return[]}}async function de(e,t={}){if(re)return re;let n=await ue(e);if(n.length===0)return re="","";let o=t.maxTools??Gn,r=t.maxChars??Vn,s=t.timeoutMs??4e3,l=t.maxBytes??$t,a=["MCP catalog (auto-discovered):","Use tool 'mcp' with server=<name> method=<tool> params=<object>."];for(let u of n){let c=await Xn(u,{timeoutMs:s,maxBytes:l});if(a.push(`${u.name} (${u.type})`),c.length===0){a.push(" - tools unavailable");continue}let m=c.slice(0,o);for(let g of m){let p=g.description?`: ${g.description}`:"";a.push(` - ${g.name}${p}`)}c.length>m.length&&a.push(` - ...and ${c.length-m.length} more`)}let i=a.join(`
|
|
13
|
+
`);return i.length>r&&(i=`${i.slice(0,r-20)}...
|
|
14
|
+
(truncated)`),re=i,i}function Fe(){re&&(_t=!0)}function Pt(){re=null,_t=!1,z.clear()}function ee(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 Tt(e,t=5e3){let n=Date.now();try{return await ke(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 ke(e,t,n,o={}){let r=kt(o.timeoutMs??Kn,1e3,12e4),s=kt(o.maxBytes??$t,1024,5e6),l=new AbortController,a=()=>l.abort();o.signal?.addEventListener("abort",a,{once:!0});let i=setTimeout(()=>l.abort(),r);try{return e.type==="http"?(t!=="initialize"&&t!=="notifications/initialized"&&await eo(e,s,l.signal),await Zn(e,t,n,s,l.signal)):await oo(e,t,n,s,l.signal)}finally{clearTimeout(i),o.signal?.removeEventListener("abort",a)}}function kt(e,t,n){return Number.isNaN(e)?t:Math.min(n,Math.max(t,e))}async function Xn(e,t){try{let n=await ke(e,"tools/list",{},t);return Qn(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 Qn(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 l of r){if(!l||typeof l!="object")continue;let a=l,i=typeof a.name=="string"?a.name:"";if(!i)continue;let u=typeof a.description=="string"?a.description:void 0,c=a.inputSchema;s.push({name:i,description:u,inputSchema:c})}return s}async function Zn(e,t,n,o,r){if(!e.url)throw new Error("MCP server url is missing.");let s=Date.now(),l=await Ne(e,t,n,o,r),a=Ct(l.parsed);if(a)throw new Error(a);let i=l.bodyText;return l.parsed&&(i=JSON.stringify(l.parsed,null,2)),{ok:l.statusCode>=200&&l.statusCode<300,output:i,durationMs:Date.now()-s,bytes:l.bytes,truncated:l.truncated,statusCode:l.statusCode,statusText:l.statusText,contentType:l.contentType}}async function Ne(e,t,n,o,r){if(!e.url)throw new Error("MCP server url is missing.");let s=z.get(e.name),l={jsonrpc:"2.0",id:`tg-agent-${Date.now()}`,method:t,params:n??{}},a={"content-type":"application/json"};e.auth&&(a.authorization=e.auth.startsWith("Bearer ")?e.auth:`Bearer ${e.auth}`),s?.cookie&&(a.cookie=s.cookie),s?.sessionId&&(a["mcp-session-id"]=s.sessionId);let i=await fetch(e.url,{method:"POST",headers:a,body:JSON.stringify(l),signal:r});to(e.name,i);let u=await ro(i,o,r),c;try{c=JSON.parse(u.text)}catch{c=void 0}return no(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 Ct(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 eo(e,t,n){let o=z.get(e.name);if(o?.initializedAt)return;if(o?.inFlight){await o.inFlight;return}let r=(async()=>{let s=await Ne(e,"initialize",{protocolVersion:"2024-11-05",clientInfo:{name:"tg-agent",version:process.env.npm_package_version??"dev"},capabilities:{}},t,n),l=Ct(s.parsed);if(l){let u=l.toLowerCase();if(u.includes("method")&&u.includes("not"))return;throw new Error(l)}let a=new AbortController,i=setTimeout(()=>a.abort(),Yn);try{await Ne(e,"notifications/initialized",{},t,a.signal)}catch{}finally{clearTimeout(i)}})();z.set(e.name,{initializedAt:Date.now(),inFlight:r});try{await r;let s=z.get(e.name);z.set(e.name,{initializedAt:Date.now(),cookie:s?.cookie,sessionId:s?.sessionId})}catch(s){throw z.delete(e.name),s}}function to(e,t){let o=z.get(e)??{initializedAt:0},r=t.headers.get("set-cookie"),s=t.headers.getSetCookie?.(),l=s&&s.length>0?s.join("; "):r;l&&z.set(e,{...o,cookie:l});let a=t.headers.get("mcp-session-id")??t.headers.get("x-mcp-session-id");a&&z.set(e,{...o,sessionId:a})}function no(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=z.get(e)??{initializedAt:0};z.set(e,{...s,sessionId:r})}async function oo(e,t,n,o,r){if(!e.command)throw new Error("MCP server command is missing.");let s=Date.now(),l=Jn(e.command,e.args??[],{stdio:["pipe","pipe","pipe"]}),a=()=>{l.killed||l.kill("SIGTERM")};if(r.aborted)throw a(),new Error("MCP request aborted.");let i=new Map,u=!1,c="",m=new Error("MCP request aborted."),g=qn.createInterface({input:l.stdout,terminal:!1});g.on("line",w=>{if(w.length>o){u=!0;return}let v=null;try{v=JSON.parse(w)}catch{return}let $=typeof v.id=="string"?v.id:typeof v.id=="number"?String(v.id):"";if(!$)return;let Q=i.get($);Q&&(i.delete($),Q.resolve(v))}),l.stderr?.on("data",w=>{let v=w.toString();if(c.length+v.length>o){u=!0;return}c+=v});let p=()=>{for(let w of i.values())w.reject(m);i.clear(),a()};r.addEventListener("abort",p,{once:!0});let h=w=>{let v=w===0?"MCP stdio exited.":c.trim()||"MCP stdio exited with error.";for(let $ of i.values())$.reject(new Error(v));i.clear()};l.once("exit",w=>h(w));let k=async(w,v)=>{let $=`tg-agent-${Date.now()}-${Math.random().toString(16).slice(2,8)}`,Q={jsonrpc:"2.0",id:$,method:w,params:v??{}};return await new Promise((ne,y)=>{i.set($,{resolve:ne,reject:y}),l.stdin?.write(`${JSON.stringify(Q)}
|
|
15
|
+
`)})};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 P=await k("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:!!P.error},timestamp:Date.now(),sessionId:"debug-session",hypothesisId:"B,C"})}).catch(()=>{}),P.error&&typeof P.error=="object"){let w=P.error.message??"MCP initialize failed.";throw a(),new Error(String(w))}let S={jsonrpc:"2.0",method:"notifications/initialized"};l.stdin?.write(`${JSON.stringify(S)}
|
|
16
|
+
`),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 I=await k(t,n);r.removeEventListener("abort",p),g.close(),l.stdin?.end(),a();let M=new Promise(w=>{l.once("exit",()=>w())});if(await Promise.race([M,new Promise(w=>setTimeout(w,500))]),I.error&&typeof I.error=="object"){let w=I.error.message??"MCP request failed.";throw new Error(String(w))}let L=JSON.stringify(I,null,2),N=L.length>o?L.slice(0,o):L;return L.length>o&&(u=!0),{ok:!0,output:N,durationMs:Date.now()-s,bytes:Math.min(L.length,o),truncated:u}}async function ro(e,t,n){let o=e.body?.getReader?.();if(!o){let m=await e.text(),g=Math.min(m.length,t);return{text:m.slice(0,t),bytes:g,truncated:m.length>t}}let r=new TextDecoder("utf-8"),s=[],l=0,a=!1;for(;;){if(n.aborted){try{await o.cancel()}catch{}throw new Error("MCP request aborted.")}let{done:m,value:g}=await o.read();if(m)break;if(!g)continue;let p=l+g.byteLength;if(p>t){let h=Math.max(0,t-l);h>0&&(s.push(g.slice(0,h)),l+=h),a=!0;try{await o.cancel()}catch{}break}s.push(g),l=p}let i=new Uint8Array(l),u=0;for(let m of s)i.set(m,u),u+=m.byteLength;return{text:r.decode(i),bytes:l,truncated:a}}function Rt(e){let t=[],n;try{n=Mt.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 l=s,a=typeof l.type=="string"?l.type.toLowerCase():void 0,i=typeof l.url=="string"?l.url:void 0,u=typeof l.command=="string"?l.command:void 0,c=a==="http"||a==="stdio"?a:i?"http":u?"stdio":void 0;if(!c||c==="http"&&!i||c==="stdio"&&!u)continue;let m;Array.isArray(l.args)&&(m=l.args.filter(p=>typeof p=="string").map(p=>p.trim()));let g=typeof l.auth=="string"?l.auth:typeof l.authorization=="string"?l.authorization:typeof l.token=="string"?l.token:void 0;t.push({name:r,type:c,url:i,command:u,args:m,auth:g})}return t}var Kn,$t,Gn,Vn,re,_t,z,Yn,Me=W(()=>{"use strict";Kn=6e4,$t=2e5,Gn=40,Vn=3500,re=null,_t=!1,z=new Map,Yn=1500});import V from"node:path";import so from"node:fs/promises";import{Type as x}from"@sinclair/typebox";function $e(e,t,n){return Number.isNaN(e)?t:Math.min(n,Math.max(t,e))}function co(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 Et(e){let t=d.fetchTimeoutMs>0?d.fetchTimeoutMs:ao;return $e(e||t,1e3,12e4)}function Dt(e){let t=d.fetchMaxBytes>0?d.fetchMaxBytes:io;return $e(e||t,1024,5e6)}function Ot(e,t,n){let o=e.trim();if(!o)return null;let r=H(o),s=V.isAbsolute(r)?r:V.join(n,r),l=V.resolve(s);for(let a of t){let i=V.resolve(a);if(l===i||l.startsWith(`${i}${V.sep}`))return l}return null}async function It(e){try{let t=await so.stat(e);return t.isFile()?{bytes:t.size}:null}catch{return null}}function lo(e){try{let t=new URL(e);return t.protocol==="http:"||t.protocol==="https:"}catch{return!1}}function uo(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 mo(e,t,n){let o=e.body?.getReader?.();if(!o){let c=await e.text?.()??"",m=Math.min(c.length,t),g=c.length>t;return{text:c.slice(0,t),bytes:m,truncated:g}}let r=new TextDecoder("utf-8"),s=[],l=0,a=!1;for(;;){if(n?.aborted){try{await o.cancel?.()}catch{}throw new Error("Fetch aborted")}let{done:c,value:m}=await o.read();if(c)break;if(!m)continue;let g=l+m.byteLength;if(g>t){let p=Math.max(0,t-l);p>0&&(s.push(m.slice(0,p)),l+=p),a=!0;try{await o.cancel?.()}catch{}break}s.push(m),l=g}let i=uo(s,l);return{text:r.decode(i),bytes:l,truncated:a}}function go(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
17
|
${o.join(`
|
|
9
18
|
`)}
|
|
10
19
|
|
|
11
|
-
${t}`}function
|
|
20
|
+
${t}`}function fo(){return{name:"fetch",label:"fetch",description:"Fetch a URL via HTTP(S) and return the response body.",parameters:po,execute:async(e,t,n,o,r)=>{if(!lo(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=Et(t.timeoutMs),l=Dt(t.maxBytes),a=new AbortController,i=()=>a.abort();r?.addEventListener("abort",i,{once:!0});let u=setTimeout(()=>a.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:co(t.headers),body:t.body,signal:a.signal}),m=await mo(c,l,r),g=c.headers.get("content-type");return{content:[{type:"text",text:go({url:c.url,status:c.status,statusText:c.statusText,bytes:m.bytes,truncated:m.truncated,contentType:g},m.text)}],details:{url:c.url,status:c.status,statusText:c.statusText,bytes:m.bytes,truncated:m.truncated,contentType:g}}}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 ho(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
21
|
${r.join(`
|
|
13
22
|
`)}
|
|
14
23
|
|
|
15
|
-
${n}`}function
|
|
24
|
+
${n}`}function wo(e){return{name:"mcp",label:"mcp",description:"Call an MCP endpoint via JSON-RPC.",parameters:yo,execute:async(t,n,o,r,s)=>{let l=await e();if(l.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 a=n.server?.trim()??"";if(!a)if(l.length===1)a=l[0]?.name??"";else return{content:[{type:"text",text:`Multiple MCP servers configured. Provide server name. Available: ${l.map(u=>u.name).join(", ")}`}],details:{server:"",type:"http",target:"",status:0,statusText:"server_required",bytes:0,truncated:!1,contentType:null}};let i=l.find(u=>u.name===a);if(!i)return{content:[{type:"text",text:`MCP server not found: ${a}. Available: ${l.map(u=>u.name).join(", ")}`}],details:{server:a,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:ee(i),status:0,statusText:"pending",bytes:0,truncated:!1,contentType:null}});let u=await ke(i,n.method,n.params??{},{timeoutMs:Et(void 0),maxBytes:Dt(void 0),signal:s});return{content:[{type:"text",text:ho(i,{server:i.name,type:i.type,target:ee(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:ee(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:ee(i),status:0,statusText:"error",bytes:0,truncated:!1,contentType:null}}}}}}function xo(e){let t=[d.workspaceDir,V.join(d.agentDir,"uploads")];return{name:"send_photo",label:"send_photo",description:"Send an image file to the current Telegram chat.",parameters:bo,execute:async(n,o)=>{let r=Ot(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 It(r);return s?(await e.sendPhoto(r,o.caption?.trim()||void 0),{content:[{type:"text",text:`Photo sent: ${V.basename(r)}`}],details:{path:r,bytes:s.bytes}}):{content:[{type:"text",text:`File not found: ${r}`}],details:{path:r,bytes:0}}}}}function So(e){let t=[d.workspaceDir,V.join(d.agentDir,"uploads")];return{name:"send_file",label:"send_file",description:"Send a file to the current Telegram chat.",parameters:vo,execute:async(n,o)=>{let r=Ot(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 It(r);return s?(await e.sendDocument(r,o.caption?.trim()||void 0),{content:[{type:"text",text:`File sent: ${V.basename(r)}`}],details:{path:r,bytes:s.bytes}}):{content:[{type:"text",text:`File not found: ${r}`}],details:{path:r,bytes:0}}}}}function Lt(e){let t=[fo()];return e?.telegram&&(t.push(xo(e.telegram)),t.push(So(e.telegram))),Se(d.agentDir).length>0&&t.push(wo(()=>ue(d.agentDir))),t}var io,ao,po,yo,bo,vo,jt=W(()=>{"use strict";G();Me();Z();io=2e5,ao=6e4;po=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}))});yo=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"}))});bo=x.Object({path:x.String({description:"Image file path (relative to workspace or uploads)."}),caption:x.Optional(x.String({description:"Caption text (plain text)."}))}),vo=x.Object({path:x.String({description:"File path (relative to workspace or uploads)."}),caption:x.Optional(x.String({description:"Caption text (plain text)."}))})});import zt from"node:fs/promises";import Ut from"node:path";function Bt(e){return Ut.join(d.sessionDir,`${e}.json`)}function Nt(e){return e.replace(/[^a-zA-Z0-9_-]/g,"_")}function ze(e,t){let n=Nt(e),o=Nt(t);return Ut.join(d.sessionDir,`${n}-${o}.jsonl`)}async function se(e,t){let n=ze(e,t);try{await zt.unlink(n)}catch(o){if(o.code==="ENOENT")return;throw o}}function Ft(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 Ae(e){await D(d.sessionDir);let t=_e.get(e);if(t)return t;let n=Bt(e);try{let o=await zt.readFile(n,"utf8"),r=JSON.parse(o),s=Ft(e,r);return _e.set(e,s),s}catch(o){if(o.code==="ENOENT"){let r=Ft(e,{});return _e.set(e,r),r}throw o}}async function C(e){await D(d.sessionDir);let t=Bt(e.chatId);await Ze(t,e),_e.set(e.chatId,e)}function Ue(e){return Object.values(e.sessions).sort((t,n)=>n.updatedAt-t.updatedAt)}function Be(e){return[]}function Pe(e,t){if(Object.keys(e.sessions).length>=d.maxSessions)throw new Error("Max sessions reached");let o=ce(),r=F(),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 Wt(e,t){return e.sessions[t]?(e.activeSessionId=t,!0):!1}function te(e){return e.activeSessionId?e.sessions[e.activeSessionId]??null:null}function We(e,t){return e.sessions[t]?(delete e.sessions[t],e.activeSessionId===t&&(e.activeSessionId=null),!0):!1}function Ht(e){e.messages=[],e.updatedAt=F()}function He(e,t,n){e.messages.push(t),e.messages.length>n&&(e.messages=e.messages.slice(-n)),e.updatedAt=F()}function qt(e,t){e.workspaceDir=t}var _e,qe=W(()=>{"use strict";G();Z();_e=new Map});import ko from"node:fs/promises";import Kt from"node:path";import{completeSimple as Mo}from"@mariozechner/pi-ai";function Po(e,t){let n=e==="bash"&&typeof t.command=="string"?t.command:`${e}: ${JSON.stringify(t)}`;return Ao.replace("{{command}}",n)}function To(e){let t=e.trim();console.log(`[audit] AI response: ${t.slice(0,200)}`);try{let n=JSON.parse(t),o=n.riskLevel?.toLowerCase();if(o==="none"||o==="low"||o==="critical")return{riskLevel:o,reason:n.reason??"No reason"}}catch{}try{let n=t.match(/\{[^{}]*"riskLevel"\s*:\s*"[^"]*"[^{}]*\}/);if(n){let r=JSON.parse(n[0]),s=r.riskLevel?.toLowerCase();if(s==="none"||s==="low"||s==="critical")return{riskLevel:s,reason:r.reason??"No reason"}}let o=t.toLowerCase();return o.includes('"critical"')||o.includes("critical risk")?{riskLevel:"critical",reason:"AI indicated critical risk"}:o.includes('"none"')||o.includes("no risk")?{riskLevel:"none",reason:"AI indicated no risk"}:(console.warn("[audit] could not parse response, defaulting to low"),{riskLevel:"low",reason:"Could not parse AI response"})}catch(n){return console.warn("[audit] parse error:",n),{riskLevel:"low",reason:"Failed to parse AI response"}}}async function Co(e,t,n,o){let r=Po(n,o);try{let l=(await Mo(e,{messages:[{role:"user",content:r,timestamp:Date.now()}]},{apiKey:t,maxTokens:500,temperature:0})).content.find(i=>i.type==="text"),a=l?.type==="text"?l.text:"";return To(a)}catch(s){let l=s instanceof Error?s.message:String(s);return console.error("[audit] AI analysis failed:",l),{riskLevel:"low",reason:`AI analysis failed: ${l}`}}}function Ro(e,t){let n=e.trim();return t.some(o=>o.test(n))}function Eo(e){let t=[];for(let n of e)try{t.push(new RegExp(n,"i"))}catch{console.warn(`[audit] invalid whitelist pattern: ${n}`)}return t}async function Y(e,t,n){try{await D(Jt);let o=Kt.join(Jt,`${e}-${t}.log`),r=JSON.stringify(n)+`
|
|
25
|
+
`;await ko.appendFile(o,r,"utf8")}catch(o){let r=o instanceof Error?o.message:String(o);console.error(`[audit] failed to write audit log: ${r}`)}}function Do(e){let t=e.toolName==="bash"?e.input.command??JSON.stringify(e.input):JSON.stringify(e.input,null,2);return["[Security Alert]",`Tool: ${e.toolName}`,`Command: ${t.slice(0,300)}`,`Risk: ${e.riskLevel.toUpperCase()} - ${e.analysis}`,"",'Press "Approve" to continue or "Stop" to block.'].join(`
|
|
26
|
+
`)}function Gt(e,t){let n=d.audit,o=Eo(n.whitelistPatterns);return r=>{r.on("tool_call",async(s,l)=>{let{toolName:a,toolCallId:i,input:u}=s,c={timestamp:new Date().toISOString(),sessionId:e.sessionId,toolName:a,toolCallId:i,input:u,riskLevel:"none",analysis:"",action:"passed"};if($o.has(a)){c.analysis="Read-only tool",await Y(e.chatId,e.sessionId,c),console.log(`[audit] tool=${a} id=${i} action=passed (read-only)`);return}if(!_o.has(a)){c.analysis="Tool not in analysis scope",await Y(e.chatId,e.sessionId,c),console.log(`[audit] tool=${a} id=${i} action=passed (not analyzed)`);return}if(a==="bash"){let g=u.command??"";if(Ro(g,o)){c.analysis="Whitelisted bash command",await Y(e.chatId,e.sessionId,c),console.log(`[audit] tool=${a} id=${i} action=passed (whitelisted)`);return}}if(!t){c.analysis="No audit model configured",await Y(e.chatId,e.sessionId,c),console.log(`[audit] tool=${a} id=${i} action=passed (no audit model)`);return}console.log(`[audit] analyzing tool=${a} id=${i}`);let m=await Co(t.model,t.apiKey,a,u);if(c.riskLevel=m.riskLevel,c.analysis=m.reason,m.riskLevel==="none"||m.riskLevel==="low"){c.action="passed",await Y(e.chatId,e.sessionId,c),console.log(`[audit] tool=${a} id=${i} risk=${m.riskLevel} action=passed`);return}console.log(`[audit] CRITICAL tool=${a} id=${i} reason=${m.reason}`);try{let g=Do(c);if(await e.requestConfirmation(g,n.confirmTimeoutMs)){c.action="approved",await Y(e.chatId,e.sessionId,c),console.log(`[audit] tool=${a} id=${i} action=approved`);return}return c.action="blocked",await Y(e.chatId,e.sessionId,c),console.log(`[audit] tool=${a} id=${i} action=blocked (user rejected)`),l.abort(),{block:!0,reason:"Operation blocked by user due to security risk."}}catch(g){let p=g instanceof Error?g.message:String(g);return c.action="blocked",c.analysis=`${m.reason} (confirmation failed: ${p})`,await Y(e.chatId,e.sessionId,c),console.log(`[audit] tool=${a} id=${i} action=blocked (${p})`),l.abort(),{block:!0,reason:`Security confirmation failed: ${p}`}}})}}var $o,_o,Ao,Jt,Vt=W(()=>{"use strict";G();Z();$o=new Set(["read","ls","find","grep"]),_o=new Set(["bash"]),Ao=`Analyze this command for security risks. Reply with ONLY a JSON object, no other text.
|
|
27
|
+
|
|
28
|
+
Command: {{command}}
|
|
29
|
+
|
|
30
|
+
Risk levels:
|
|
31
|
+
- "none": Safe (read-only, standard dev tools)
|
|
32
|
+
- "low": Minor risk (file writes, package installs)
|
|
33
|
+
- "critical": High risk (secrets exposure, destructive ops, network attacks, privilege escalation)
|
|
34
|
+
|
|
35
|
+
Reply format (ONLY this JSON, nothing else):
|
|
36
|
+
{"riskLevel":"none|low|critical","reason":"brief explanation"}`;Jt=Kt.join(d.sessionDir,"audit-logs")});import{createAgentSession as Oo,discoverAuthStorage as Io,discoverModels as Lo,SessionManager as jo,SettingsManager as No}from"@mariozechner/pi-coding-agent";import Te from"node:fs/promises";import Yt from"node:path";function Xt(e){let t=e.trim().toLowerCase();return t==="codex"?"openai-codex":t}function zo(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 Uo(e,t){return e!=="openai-codex"?t:Fo[t]??t}function Bo(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 Wo(e,t){let n=!!t?.provider?.trim(),o=!!t?.modelId?.trim(),r=Xt(t?.provider||d.modelProvider||"openai-codex"),s=n||o?"":d.modelRef||"",{provider:l,modelId:a}=zo(s,r),i=t?.provider?r:Xt(l),u=o?t?.modelId?.trim()||"":a;if(!u){let g=Bo(e,i);return g?{model:g,provider:i,modelId:g.id}:{model:void 0,provider:i,modelId:""}}let c=Uo(i,u);return{model:e.find(i,c),provider:i,modelId:c}}function Ho(e){let t=oe();return t?(e.setRuntimeApiKey("openai-codex",t.accessToken),{source:t.source,expiresAt:t.expiresAt}):null}function qo(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
37
|
|
|
17
38
|
`);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
39
|
|
|
19
|
-
`):""}function
|
|
40
|
+
`):""}function Jo(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,l=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,l?"error=1":null].filter(Boolean).join(",");return`${o}(${i})`}if(r==null){let a=["empty",s?`stop=${s}`:null,l?"error=1":null].filter(Boolean).join(",");return`${o}(${a})`}return`${o}(${typeof r}${s?`,stop=${s}`:""})`});return`messages=${e.length} last=[${t.join(" ")}]`}function Ko(e){let t=e.trim();return t.toLowerCase().includes("usage limit")?`${t}
|
|
41
|
+
|
|
42
|
+
Suggestion: wait for the limit to reset or switch to another provider/model.`:t}function Go(e,t){let n=t?.getLastAssistantText?.();if(n?.trim())return n.trim();for(let o=e.length-1;o>=0;o-=1){let r=qo(e[o]);if(r)return r}return""}function Vo(e){for(let t=e.length-1;t>=0;t-=1)if(e[t]?.role==="assistant")return e[t]}async function Qt(e){let t=e.workspaceDir||d.workspaceDir;await D(d.sessionDir),await D(d.agentDir),await D(t);let n=ze(e.chatId,e.sessionId),o=Io(d.agentDir),r=Ho(o);r&&console.log(`[tg-agent] codex oauth source=${r.source} expiresAt=${new Date(r.expiresAt).toISOString()}`);let s=Lo(o,d.agentDir),{model:l,provider:a,modelId:i}=Wo(s,{provider:e.modelProvider,modelId:e.modelId});i&&!l&&console.warn(`[tg-agent] model not found: ${a}/${i}`);let u=jo.open(n),c=No.create(t,d.agentDir);try{let y=Yt.join(d.agentDir,"skills"),b=Yt.join(t,".pi","skills"),_=await Te.access(y).then(()=>!0).catch(()=>!1),A=await Te.access(b).then(()=>!0).catch(()=>!1);if(_){let J=(await Te.readdir(y,{withFileTypes:!0})).filter(B=>B.isDirectory()).map(B=>B.name);console.log(`[tg-agent] skills directory found at ${y} with ${J.length} skill(s): ${J.join(", ")}`)}else console.log(`[tg-agent] skills directory not found at ${y}`);if(A){let J=(await Te.readdir(b,{withFileTypes:!0})).filter(B=>B.isDirectory()).map(B=>B.name);console.log(`[tg-agent] workspace skills directory found at ${b} with ${J.length} skill(s): ${J.join(", ")}`)}let U=c.getSettings?.();if(U){let J=U.skills?.enabled!==!1;console.log(`[tg-agent] skills enabled in settings: ${J}`)}}catch(y){let b=y instanceof Error?y.message:String(y);console.warn(`[tg-agent] skills check failed: ${b}`)}let m="";try{m=await de(d.agentDir,{timeoutMs:4e3,maxBytes:d.fetchMaxBytes,maxChars:3e3})}catch(y){let b=y instanceof Error?y.message:String(y);console.warn(`[tg-agent] mcp catalog error: ${b}`)}let g=[];if(d.audit.enabled&&e.auditContext){let y={...e.auditContext,sessionId:e.sessionId},b;if(d.audit.modelProvider&&d.audit.modelId){let _=s.find(d.audit.modelProvider,d.audit.modelId);if(_){let A=await o.getApiKey(d.audit.modelProvider);b={provider:d.audit.modelProvider,model:_,apiKey:A??void 0},console.log(`[tg-agent] audit model: ${d.audit.modelProvider}/${d.audit.modelId} apiKey=${A?"present":"missing"}`)}else console.warn(`[tg-agent] audit model not found: ${d.audit.modelProvider}/${d.audit.modelId}`)}g.push(Gt(y,b)),console.log(`[tg-agent] security audit enabled for session ${e.sessionId}`)}let{session:p,modelFallbackMessage:h}=await Oo({cwd:t,agentDir:d.agentDir,authStorage:o,modelRegistry:s,model:l??void 0,sessionManager:u,settingsManager:c,customTools:Lt({telegram:e.telegram}),extensions:g.length>0?g:void 0,systemPrompt:y=>{let b=e.systemPrompt?.trim(),_=[y];return b&&_.push(b),m&&_.push(m),_.join(`
|
|
20
43
|
|
|
21
|
-
|
|
44
|
+
`)}});try{let y=p.messages,b=y.some(E=>{let J=E.role,B=E.content;return J==="system"&&typeof B=="string"?B.toLowerCase().includes("compaction")||B.toLowerCase().includes("compact"):E.type==="compaction"||E.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: ${b||"unknown (will be detected during runtime)"}`);let A=typeof u.compact=="function",U=typeof u.appendCompaction=="function";console.log(`[tg-agent] SessionManager.compact method: ${A}`),console.log(`[tg-agent] SessionManager.appendCompaction method: ${U}`)}catch(y){let b=y instanceof Error?y.message:String(y);console.warn(`[tg-agent] compacting check failed: ${b}`)}h&&console.warn(`[tg-agent] modelFallback=${h}`);let k=!1,P=()=>{k=!0,p.abort()};e.onAbortReady?.(P);let S=d.logAgentEvents,I=d.logAgentStream,M=new Map,L=p.subscribe(y=>{switch(y.type){case"agent_start":S&&console.log(`[tg-agent] agent start session=${e.sessionId}`),j=Date.now(),e.onStatus?.({type:"agent_start"});break;case"agent_end":S&&console.log(`[tg-agent] agent end session=${e.sessionId}`),e.onStatus?.({type:"agent_end"});break;case"turn_start":S&&console.log(`[tg-agent] turn start session=${e.sessionId}`),j=Date.now(),e.onStatus?.({type:"turn_start"});break;case"turn_end":S&&console.log(`[tg-agent] turn end session=${e.sessionId} toolResults=${y.toolResults.length}`),j=Date.now(),e.onStatus?.({type:"turn_end",toolResults:y.toolResults.length});break;case"message_start":{if(S){let b=y.message.role??"unknown";console.log(`[tg-agent] message start session=${e.sessionId} role=${b}`)}j=Date.now();{let b=y.message.role??"unknown";e.onStatus?.({type:"message_start",role:b})}break}case"message_end":{if(S){let b=y.message.role??"unknown";console.log(`[tg-agent] message end session=${e.sessionId} role=${b}`)}j=Date.now();{let b=y.message.role??"unknown";e.onStatus?.({type:"message_end",role:b})}break}case"message_update":{if(!I)break;if(y.assistantMessageEvent.type==="text_delta"){let _=(y.assistantMessageEvent.delta??"").length;_>0&&console.log(`[tg-agent] stream delta session=${e.sessionId} chars=${_}`),j=Date.now()}y.assistantMessageEvent.type==="thinking_delta"&&(j=Date.now());break}case"tool_execution_start":{M.set(y.toolCallId,Date.now()),console.log(`[tg-agent] tool start name=${y.toolName} id=${y.toolCallId}`),ne+=1,j=Date.now(),e.onStatus?.({type:"tool_start",name:y.toolName,id:y.toolCallId,args:y.args});break}case"tool_execution_end":{let b=M.get(y.toolCallId),_=b?Date.now()-b:0;console.log(`[tg-agent] tool end name=${y.toolName} id=${y.toolCallId} ok=${!y.isError} durationMs=${_}`),M.delete(y.toolCallId),ne=Math.max(0,ne-1),j=Date.now(),e.onStatus?.({type:"tool_end",name:y.toolName,id:y.toolCallId,ok:!y.isError,durationMs:_});break}case"auto_compaction_start":{let b=y.reason??"unknown";console.log(`[tg-agent] auto compaction started session=${e.sessionId} reason=${b}`),j=Date.now();break}case"auto_compaction_end":{let b=y.willRetry??!1;console.log(`[tg-agent] auto compaction ended session=${e.sessionId} willRetry=${b}`),j=Date.now();break}default:break}}),N=null,w=null,v=!1,$=0,Q=!1,j=Date.now(),ne=0;try{let y=Date.now();N=setInterval(()=>{let A=Date.now()-y;console.log(`[tg-agent] prompt running session=${e.sessionId} elapsedMs=${A} streaming=${p.isStreaming}`),e.onStatus?.({type:"heartbeat",elapsedMs:A,streaming:p.isStreaming})},15e3),w=setInterval(()=>{if(v||ne>0)return;let A=Date.now()-j,U=p.isStreaming?d.modelTimeoutStreamingMs:d.modelTimeoutMs,E=Math.max(1e3,U);A>=E&&(v=!0,$=E,Q=p.isStreaming,console.warn(`[tg-agent] model timeout session=${e.sessionId} elapsedMs=${A}`),p.abort())},2e3);try{if(await p.prompt(e.prompt,e.images&&e.images.length>0?{images:e.images}:void 0),v)throw new Error(`Model request timed out after ${d.modelTimeoutMs}ms`)}catch(A){if(k)throw new Error("Cancelled by user.");if(v){let U=Q?" (streaming)":"",E=$||d.modelTimeoutMs;throw new Error(`Model request timed out after ${E}ms${U}`)}throw A}N&&clearInterval(N);let b=Vo(p.messages);if(b){let A=b?.stopReason,U=b?.errorMessage;if(A==="error"){let E=U?Ko(U):"Model error without details.";throw console.warn(`[tg-agent] model error session=${e.sessionId} error=${E}`),new Error(E)}}let _=Go(p.messages,p);if(!_){let A=Jo(p.messages);throw console.warn(`[tg-agent] empty response session=${e.sessionId} ${A}`),new Error("No assistant response.")}return{text:_,sessionFile:n,sessionId:p.sessionId,modelProvider:p.model?.provider??a,modelId:p.model?.id??i,modelFallbackMessage:h}}finally{N&&clearInterval(N),w&&clearInterval(w),L(),u.flushPendingToolResults?.(),p.dispose()}}var Fo,Zt=W(()=>{"use strict";G();xe();jt();Me();Z();qe();Vt();Fo={"codex-mini-latest":"gpt-5.1-codex-mini","codex-max-latest":"gpt-5.1-codex-max","codex-latest":"gpt-5.2-codex"}});var Wr={};import Re from"node:path";import en from"node:fs/promises";import Yo from"node-telegram-bot-api";import{discoverAuthStorage as Xo,discoverModels as Qo}from"@mariozechner/pi-coding-agent";import{getOAuthProviders as Zo}from"@mariozechner/pi-ai";function tr(e,t){fe.set(e,t)}function Ve(e){fe.delete(e)}function nr(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 rr(){return Re.join(d.agentDir,"uploads")}function sr(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 ir(e){return!!e?.startsWith("image/")}function ar(e){switch(Re.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 cr(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 lr(e){return e.length===0?"":e.map(t=>{let n=[];t.mimeType&&n.push(t.mimeType),t.bytes>0&&n.push(cr(t.bytes));let o=n.length>0?` (${n.join(", ")})`:"";return`Attachment saved: ${t.path}${o}`}).join(`
|
|
45
|
+
`)}function ur(e){let t=[];if(e.photo&&e.photo.length>0){let n=sr(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 dr(e){if(e.length===0)return{resolved:[],images:[]};let t=rr();await D(t);let n=[],o=[];for(let r of e)try{let s=await R.downloadFile(r.fileId,t),l=await en.stat(s),a=r.fileName??Re.basename(s),i=r.mimeType??ar(s),u=r.kind==="photo"||ir(i),c={path:s,name:a,mimeType:i,bytes:l.size,isImage:u};if(n.push(c),u){let m=await en.readFile(s);o.push({type:"image",data:m.toString("base64"),mimeType:i??or})}}catch(s){console.warn("[tg-agent] attachment download failed",s)}return{resolved:n,images:o}}function me(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 gr(e){if(me(e,"*")%2!==0||me(e,"_")%2!==0||me(e,"`")%2!==0)return!1;let r=me(e,"["),s=me(e,"]");return r===s}function pr(e){for(let t=0;t<e.length;t+=1){let n=e[t];if(n==="\\"){t+=1;continue}if(mr.has(n))return!1}return!0}function ln(e){let t=nr(d.telegramParseMode);return t?[t]:pr(e)?["MarkdownV2","Markdown"]:gr(e)?["Markdown"]:[]}function pe(e,t){let n=ge.get(e);return n?(clearTimeout(n.timeoutId),ge.delete(e),n.messageId&&R.editMessageReplyMarkup({inline_keyboard:[]},{chat_id:n.chatId,message_id:n.messageId}).catch(()=>{}),n.resolve(t),!0):!1}async function tn(e,t,n,o,r){if(ge.has(e))throw new Error("Audit confirmation already pending.");let s=bn([{label:"Approve",command:"/approve"},{label:"Stop",command:"/stop"}],2),l=await vn(t,n,s,r);return await new Promise((a,i)=>{let u=setTimeout(()=>{ge.delete(e),R.editMessageText(`${n}
|
|
22
46
|
|
|
23
|
-
|
|
24
|
-
`)}function
|
|
25
|
-
`)
|
|
26
|
-
`),p,l)}}function We(e,t=pr){return e.length<=t?{text:e,truncated:!1}:{text:`${e.slice(0,Math.max(0,t-15))}...
|
|
47
|
+
[Timed out - Operation blocked]`,{chat_id:t,message_id:l.message_id}).catch(()=>{}),i(new Error("Audit confirmation timed out."))},o);ge.set(e,{resolve:a,reject:i,timeoutId:u,chatId:t,messageThreadId:r,messageId:l.message_id})})}function ae(e){let t=e.trim().toLowerCase();return yr.get(t)??t}function wr(e,t){return e!=="openai-codex"?t:hr[t]??t}async function ie(){await D(d.agentDir);let e=Xo(d.agentDir),t=oe();t&&e.setRuntimeApiKey("openai-codex",t.accessToken);let n=Qo(e,d.agentDir);return{authStorage:e,modelRegistry:n}}function un(e){let t=X.get(e);t&&(clearTimeout(t.timeoutId),X.delete(e))}function br(e,t){let n=X.get(e);n&&(clearTimeout(n.timeoutId),X.delete(e),n.reject(new Error(t)))}async function nn(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,l)=>{let a=setTimeout(()=>{X.delete(e),l(new Error("Login prompt timed out."))},fr);X.set(e,{resolve:s,reject:l,timeoutId:a,chatId:t})})}async function dn(e,t,n){let o=fe.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)}async function mn(e,t,n,o){let r=await Ae(t),s=n||r.activeSessionId;if(!s){await f(e,"No active session to close.",o);return}let l=fe.get(t);if(l){if(l.cancelRequested=!0,l.abortRequested=!0,l.status&&l.status.update("Cancelled by user.",!0),l.abort)try{l.abort()}catch(u){console.warn("[tg-agent] abort callback failed during force close",u)}Ve(t)}if(!We(r,s)){await f(e,`Session not found: ${s}`,o);return}await C(r),await se(t,s).catch(u=>{console.warn(`[tg-agent] delete session file failed id=${s}`,u)});let i=l?`Force-closed session ${s} (interrupted running task).`:`Closed session ${s}.`;await f(e,i,o)}function vr(){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=Se(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}=yt(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=wt();console.log(n?`[tg-agent] proxyUrl=${n.url} kind=${n.kind} source=${n.source}`:"[tg-agent] proxyUrl=(none)")}function Ye(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 on(e,t,n){let o=te(e);return o||(o=Pe(e,""),await C(e),await f(t,`Created session ${o.id}.`,n)),o}function Sr(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()).filter(([r])=>xr.has(r)).sort((r,s)=>r[0].localeCompare(s[0])).map(([r,s])=>({label:`${r} (${s.count}, ${s.auth?"ok":"no auth"})`,command:`/provider ${r}`}))}function kr(e,t,n=[]){let o=e.getAll().filter(a=>a.provider===t).sort((a,i)=>a.id.localeCompare(i.id));if(n.length===0)return o.map(a=>({label:a.id,command:`/model ${t}/${a.id}`}));let r=new Map(o.map(a=>[a.id,a])),s=new Set,l=[];for(let a of n){let i=r.get(a);!i||s.has(i.id)||(s.add(i.id),l.push(i))}for(let a of o)s.has(a.id)||l.push(a);return l.map(a=>({label:a.id,command:`/model ${t}/${a.id}`}))}function Mr(e,t,n=3){let o=new Set,r=[],s=Ue(e);for(let l of s){if(l.modelProvider!==t)continue;let a=l.modelId;if(!(!a||o.has(a))&&(o.add(a),r.push(a),r.length>=n))break}return r}function $r(e){let t=e.trim();if(!t)return null;if(t.includes("/")){let[n,o]=t.split("/",2);return!n||!o?null:{provider:ae(n),modelId:o.trim()}}return{modelId:t}}function gn(e,t){let n=Date.now(),o=rn.get(e)??0;n-o<_r||(rn.set(e,n),console.warn(`[tg-agent] unauthorized user=${e} chat=${t}`))}function pn(e){let t=d.telegramAllowedUsers;return!t||t.size===0?!0:t.has(e)}function Ar(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(`
|
|
48
|
+
`)}function Ee(e,t,n){let o=String(e);return t!==void 0&&!n?null:t!==void 0&&n?`${o}_${t}`:o}function Ge(e,t){if(t.workspaceDir)return t.workspaceDir;let n=d.workspaceMappings.get(e);return n||d.workspaceDir}async function fn(e,t,n,o){let r={};return n&&(r.parse_mode=n),o!==void 0&&(r.message_thread_id=o),await R.sendMessage(e,t,r)}async function yn(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 R.editMessageText(n,s)}async function hn(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 Pr(e,t,n){return await hn(o=>fn(e,t,o,n),ln(t))}async function Tr(e,t,n,o){await hn(r=>yn(e,t,n,r,o),ln(n))}async function f(e,t,n){let o=et(t,3900);for(let r of o)await Pr(e,r,n)}function Rr(){let e=F()-wn;for(let[o,r]of q)r.createdAt<e&&q.delete(o);if(q.size<=sn)return;let t=Array.from(q.entries()).sort((o,r)=>o[1].createdAt-r[1].createdAt),n=q.size-sn;for(let o=0;o<n;o+=1)q.delete(t[o][0])}function Er(e){Rr();let t=ce();for(;q.has(t);)t=ce();return q.set(t,{command:e,createdAt:F()}),t}function Dr(e){if(!e.startsWith("cmd:"))return null;let t=e.slice(4),n=q.get(t);return n?F()-n.createdAt>wn?(q.delete(t),null):n.command:null}function Or(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 bn(e,t){let n=[],o=[];for(let r of e){let s=Er(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 vn(e,t,n,o){let r={reply_markup:{inline_keyboard:n}};return o!==void 0&&(r.message_thread_id=o),await R.sendMessage(e,t,r)}async function an(e,t,n,o){let r=o?.perRow??1,s=o?.pageSize??Cr,l=o?.footer,a=o?.messageThreadId,i=Or(n,s);for(let u=0;u<i.length;u+=1){let c=i[u],m=i.length>1?` (page ${u+1}/${i.length})`:"",g=[`${t}${m}`];l&&g.push(l);let p=bn(c,r);await vn(e,g.join(`
|
|
49
|
+
`),p,a)}}function Ke(e,t=Ir){return e.length<=t?{text:e,truncated:!1}:{text:`${e.slice(0,Math.max(0,t-15))}...
|
|
27
50
|
|
|
28
|
-
[truncated]`,truncated:!0}}async function
|
|
29
|
-
args: ${
|
|
30
|
-
`)}async function
|
|
31
|
-
`);await f(e,c,r);return}case"new":{try{let
|
|
51
|
+
[truncated]`,truncated:!0}}async function jr(e,t){let n="Working...",r=(await fn(e,n,void 0,t)).message_id,s=n,l=0,a=Promise.resolve(),i=(c,m=!1)=>{let g=Date.now();!m&&g-l<Lr||c!==s&&(s=c,l=g,a=a.then(async()=>{await yn(e,r,c,void 0,t)}).catch(p=>{console.warn("[tg-agent] status edit failed",p)}))},u=c=>{s=c,l=Date.now(),a=a.then(async()=>{await Tr(e,r,c,t)}).catch(m=>{console.warn("[tg-agent] status edit failed",m)})};return{update:(c,m=!1)=>{let g=Ke(c).text;i(g,m)},finalize:async c=>{let m=Ke(c).text;u(m),await a},fail:async c=>{let m=Ke(c).text;u(m),await a}}}function Nr(e){switch(e.type){case"agent_start":return"Working...";case"tool_start":return`Running tool: ${e.name}
|
|
52
|
+
args: ${Fr(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 Fr(e){try{let t=new WeakSet,n=200,o=12,r=12,s=3,l=(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=>l(h,c+1));return u.length>r&&p.push("[truncated]"),p}let m=Object.entries(u),g={};for(let[p,h]of m.slice(0,o))g[p]=l(h,c+1);return m.length>o&&(g._truncated=!0),g},a=l(e,0),i=JSON.stringify(a);return i?i.length>700?`${i.slice(0,700)}...`:i:"null"}catch{return"[unavailable]"}}function De(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 zr(e,t=140){return e.length<=t?e:`${e.slice(0,t-3)}...`}async function Ur(){let e=await ue(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=>Tt(o))),n=["MCP servers:"];for(let o=0;o<e.length;o+=1){let r=e[o],s=t[o],l=s.ok?"ok":`error: ${zr(s.error??"unknown")}`;n.push(`- ${r.name} (${r.type}) ${ee(r)} status=${l} (${s.durationMs}ms)`)}return n.join(`
|
|
53
|
+
`)}async function Xe(e,t,n,o,r){let s=r,a=Ee(e,s,s!==void 0);if(!a)return;let i=await Ae(a),u=Be(i);switch(u.length>0&&(await C(i),await Promise.all(u.map(c=>se(a,c).catch(m=>{console.warn(`[tg-agent] cleanup session file failed id=${c}`,m)})))),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","/approve - approve a pending security audit confirmation","","Tips:","Send images or files to attach them to the prompt."].join(`
|
|
54
|
+
`);await f(e,c,r);return}case"new":{try{let c=o||"",m=te(i),g=m?.modelProvider,p=m?.modelId,h=Pe(i,c);g&&(h.modelProvider=g,p&&(h.modelId=p)),await C(i),await f(e,`Created session ${h.id} (${h.title}).`,r)}catch(c){await f(e,c.message,r)}return}case"list":{await C(i),await f(e,Ar(Ue(i)),r);return}case"use":{if(!o){await f(e,"Usage: /use <id>",r);return}if(!Wt(i,o)){await f(e,`Session not found: ${o}`,r);return}await C(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}let m=fe.get(a);if(m){if(m.cancelRequested=!0,m.abortRequested=!0,m.status&&m.status.update("Cancelled by user.",!0),m.abort)try{m.abort()}catch(h){console.warn("[tg-agent] abort callback failed during force close",h)}Ve(a)}if(!We(i,c)){await f(e,`Session not found: ${c}`,r);return}await C(i),await se(a,c).catch(h=>{console.warn(`[tg-agent] delete session file failed id=${c}`,h)});let p=m?`Force-closed session ${c} (interrupted running task).`:`Closed session ${c}.`;await f(e,p,r);return}case"reset":{let c=te(i);if(!c){await f(e,"No active session.",r);return}Ht(c),await C(i),await se(a,c.id).catch(m=>{console.warn(`[tg-agent] reset session file failed id=${c.id}`,m)}),await f(e,`Reset session ${c.id}.`,r);return}case"workspace":{if(!o){let m=Ge(a,i),g=i.workspaceDir?"chat":d.workspaceMappings.has(a)?"config":"default";await f(e,`Workspace: ${m} (source: ${g})`,r);return}let c=Re.resolve(H(o.trim()));qt(i,c),await C(i),await f(e,`Workspace set to: ${c}`,r);return}case"providers":{let{authStorage:c,modelRegistry:m}=await ie(),g=m.getError(),p=Sr(m,c);if(p.length===0){let k=g?`Warning: ${g}
|
|
32
55
|
|
|
33
|
-
No providers found.`:"No providers found.";await f(e,
|
|
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:
|
|
35
|
-
`);await f(e,
|
|
36
|
-
`),r);return}let
|
|
37
|
-
`),r)},onPrompt:h=>
|
|
56
|
+
No providers found.`:"No providers found.";await f(e,k,r);return}let h=[];g&&h.push(`Warning: ${g}`),h.push("Providers:"),await an(e,h.join(`
|
|
57
|
+
`),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:m}=await ie(),g=o?ae(o):"";if(!g){let P=te(i);if(!P?.modelProvider){await f(e,"Usage: /models <provider>",r);return}g=P.modelProvider}let p=c.hasAuth(g),h=Mr(i,g),k=kr(m,g,h);if(k.length===0){await f(e,`No models found for provider ${g}.`,r);return}await an(e,`Models for ${g} (auth: ${p?"ok":"missing"}):`,k,{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=ae(o),{modelRegistry:m}=await ie();if(!m.getAll().some(h=>h.provider===c)){await f(e,`Unknown provider: ${c}`,r);return}let p=await on(i,e,r);p.modelProvider=c,p.modelId=void 0,p.updatedAt=F(),await C(i),await f(e,`Session ${p.id} provider set to ${c}.`,r),await Xe(e,t,"models",c,r);return}case"model":{let c=$r(o);if(!c){await f(e,"Usage: /model <provider>/<model>",r);return}let m=await on(i,e,r),g=ae(c.provider??m.modelProvider??"");if(!g){await f(e,"Usage: /model <provider>/<model>",r);return}let{modelRegistry:p}=await ie(),h=wr(g,c.modelId);if(!p.find(g,h)){await f(e,`Model not found: ${g}/${h}`,r);return}m.modelProvider=g,m.modelId=h,m.updatedAt=F(),await C(i),await f(e,`Session ${m.id} model set to ${g}/${h}.`,r);return}case"status":{let c=te(i);if(!c){await f(e,"No active session.",r);return}let m=d.modelRef.includes("/")?d.modelRef:`${d.modelProvider}/${d.modelRef}`,g=c.modelProvider||c.modelId?`Model: ${c.modelProvider??"?"}/${c.modelId??"?"}`:`Model: ${m} (default)`,p=Ge(a,i),h=i.workspaceDir?"chat":d.workspaceMappings.has(a)?"config":"default",k=[`Session: ${c.id} (${c.title})`,g,`Workspace: ${p} (${h})`].join(`
|
|
58
|
+
`);await f(e,k,r);return}case"mcp":{if(o.trim().toLowerCase()==="refresh"){Pt(),await de(d.agentDir,{timeoutMs:5e3,maxBytes:d.fetchMaxBytes,maxChars:3e3}),Fe(),await f(e,"MCP catalog refreshed.",r);return}let c=await Ur();await f(e,c,r);return}case"login":{let c=Zo();if(!o){let p=c.map(h=>`- ${h.id} (${h.name})`);await f(e,["OAuth providers:",...p].join(`
|
|
59
|
+
`),r);return}let m=ae(o);if(Je.has(t)){await f(e,"Login already in progress.",r);return}let g=c.find(p=>p.id===m);if(!g){await f(e,`Unknown OAuth provider: ${m}`,r);return}Je.add(t);try{let{authStorage:p}=await ie();await f(e,`Starting login for ${g.id}...`,r),await p.login(g.id,{onAuth:({url:h,instructions:k})=>{let P=["Open this URL in your browser:",h];k&&P.push("",k),f(e,P.join(`
|
|
60
|
+
`),r)},onPrompt:h=>nn(t,e,h,r),onProgress:h=>{f(e,h,r)},onManualCodeInput:()=>nn(t,e,{message:"Paste the authorization code:"},r)}),await f(e,`Login completed for ${g.id}.`,r)}catch(p){let h=De(p);await f(e,`Login failed: ${h}`,r)}finally{Je.delete(t),un(t)}return}case"logout":{if(!o){await f(e,"Usage: /logout <provider>",r);return}let c=ae(o),{authStorage:m}=await ie();m.logout(c),await f(e,`Logged out from ${c}.`,r);return}default:await f(e,`Unknown command: ${n}`,r)}}async function Br(e,t,n,o=[],r){let s=Ye(n);if(s){await Xe(e,t,s.command,s.args,r);return}let a=Ee(e,r,r!==void 0);if(!a)return;let i=await Ae(a),u=Be(i);u.length>0&&(await C(i),await Promise.all(u.map(M=>se(a,M).catch(L=>{console.warn(`[tg-agent] cleanup session file failed id=${M}`,L)}))));let c=te(i);if(!c)try{c=Pe(i,""),await C(i),await f(e,`Created session ${c.id}.`,r)}catch(M){await f(e,M.message,r);return}let{resolved:m,images:g}=await dr(o);if(o.length>0&&m.length===0&&!n.trim()){await f(e,"Failed to download attachments.",r);return}let p=lr(m),h=[];n.trim()&&h.push(n.trim()),p&&h.push(p);let k=h.join(`
|
|
38
61
|
|
|
39
|
-
`)||"Attachment received.",
|
|
40
|
-
`),
|
|
62
|
+
`)||"Attachment received.",P={role:"user",content:k,ts:F()};He(c,P,d.maxHistoryMessages),await C(i),console.log(`[tg-agent] request user=${t} chat=${a} session=${c.id} messages=${c.messages.length} textLen=${k.length} attachments=${m.length} provider=${c.modelProvider??"-"} model=${c.modelId??"-"}`);let S=null;try{S=await jr(e,r)}catch(M){console.warn("[tg-agent] status message failed",M)}let I={sessionId:c.id,chatId:e,messageThreadId:r,status:S,abortRequested:!1,cancelRequested:!1};tr(a,I);try{let M=await er(async()=>{let N=await Qt({chatId:a,sessionId:c.id,prompt:k,images:g,systemPrompt:d.systemPrompt,modelProvider:c.modelProvider,modelId:c.modelId,workspaceDir:Ge(a,i),telegram:{chatId:e,sendPhoto:async(w,v)=>{let $={};v&&($.caption=v),r!==void 0&&($.message_thread_id=r),await R.sendPhoto(e,w,$)},sendDocument:async(w,v)=>{let $={};v&&($.caption=v),r!==void 0&&($.message_thread_id=r),await R.sendDocument(e,w,$)},sendMessage:async w=>{await f(e,w,r)},requestConfirmation:async(w,v)=>await tn(a,e,w,v,r)},auditContext:d.audit.enabled?{chatId:a,requestConfirmation:async(w,v)=>await tn(a,e,w,v,r),sendNotification:async w=>{await f(e,w,r)}}:void 0,onAbortReady:w=>{I.abort=w,I.abortRequested&&w()},onStatus:S?w=>{let v=Nr(w);v&&S?.update(v)}:void 0});return console.log(`[tg-agent] response session=${c.id} model=${N.modelProvider}/${N.modelId} file=${N.sessionFile}`),N.text});if(I.cancelRequested){S?await S.finalize("Cancelled by user."):await f(e,"Cancelled by user.",r);return}let L={role:"assistant",content:M,ts:F()};He(c,L,d.maxHistoryMessages),await C(i),S?await S.finalize(M):await f(e,M,r)}catch(M){if(console.error("[tg-agent] runModel error",M),I.cancelRequested){S?await S.fail("Cancelled by user."):await f(e,"Cancelled by user.",r);return}let L=De(M);S?await S.fail(`Error: ${L}`):await f(e,`Error: ${L}`,r)}finally{Ve(a)}}var R,cn,er,fe,or,mr,fr,X,Je,ge,yr,hr,Ce,xr,_r,rn,wn,sn,Cr,q,Ir,Lr,xn=W(()=>{"use strict";G();Le();St();Zt();xe();Me();qe();Z();pt();R=new Yo(d.telegramToken,{polling:!0}),cn=tt(),er=nt(d.maxConcurrent),fe=new Map;or="image/jpeg";mr=new Set(["_","*","[","]","(",")","~","`",">","#","+","-","=","|","{","}",".","!"]);fr=600*1e3,X=new Map,Je=new Set,ge=new Map;yr=new Map([["codex","openai-codex"],["antigravity","google-antigravity"],["gemini","google-gemini-cli"],["gemini-cli","google-gemini-cli"]]),hr={"codex-mini-latest":"gpt-5.1-codex-mini","codex-max-latest":"gpt-5.1-codex-max","codex-latest":"gpt-5.2-codex"};vr();D(d.agentDir).catch(e=>{console.warn(`[tg-agent] ensure agentDir failed: ${e instanceof Error?e.message:String(e)}`)});(async()=>{try{await de(d.agentDir,{timeoutMs:3e3,maxBytes:d.fetchMaxBytes,maxChars:2e3}),Fe()}catch(e){let t=e instanceof Error?e.message:String(e);console.warn(`[tg-agent] mcp catalog warmup failed: ${t}`)}})();Ce=xt();console.log(Ce?`[tg-agent] fetchProxy=${Ce.url} kind=${Ce.kind} source=${Ce.source}`:"[tg-agent] fetchProxy=(none)");xr=new Set(["openai-codex","google-antigravity","anthropic"]);_r=6e4,rn=new Map;wn=1800*1e3,sn=2e3,Cr=60,q=new Map;Ir=3900,Lr=1200;R.on("callback_query",e=>{let t=e.data??"",n=e.message?.chat.id;if(!e.from?.id||!n){R.answerCallbackQuery(e.id);return}let o=String(e.from.id);if(!pn(o)){gn(o,n),R.answerCallbackQuery(e.id);return}if(!t.startsWith("cmd:")){R.answerCallbackQuery(e.id);return}let r=Dr(t);if(!r){R.answerCallbackQuery(e.id,{text:"Command expired."});return}R.answerCallbackQuery(e.id);let s=e.message?.message_thread_id,l=e.message?.is_topic_message??!1,a=Ee(n,s,l);if(!a)return;let i=Ye(r);if(i?.command==="stop"){pe(a,!1)?f(n,"Operation blocked.",s):dn(n,a,s);return}if(i?.command==="close"){mn(n,a,i.args,s);return}if(i?.command==="approve"){pe(a,!0)?f(n,"Operation approved.",s):f(n,"No pending audit confirmation.",s);return}cn(a,async()=>{if(!i){await f(n,"Invalid command.",s);return}await Xe(n,o,i.command,i.args,s)}).catch(async u=>{console.error("[tg-agent] runModel error",u);let c=De(u);await f(n,`Error: ${c}`,s)})});R.on("message",e=>{if(!e.from?.id)return;let t=String(e.from.id),n=e.chat.id;if(!pn(t)){gn(t,n);return}let o=e.message_thread_id,r=e.is_topic_message??!1,s=Ee(n,o,r);if(!s)return;let l=(e.text??e.caption??"").trim(),a=ur(e);if(!l&&a.length===0)return;let i=X.get(t);if(i){if(l==="/stop"||l==="/cancel"){br(t,"Login cancelled by user."),f(n,"Login cancelled.",o);return}if(!l){f(n,"Login expects a text response.",o);return}un(t),i.resolve(l);return}let u=Ye(l);if(u?.command==="stop"){pe(s,!1),dn(n,s,o);return}if(u?.command==="close"){pe(s,!1),mn(n,s,u.args,o);return}if(u?.command==="approve"){pe(s,!0)?f(n,"Operation approved.",o):f(n,"No pending audit confirmation.",o);return}cn(s,()=>Br(n,t,l,a,o)).catch(async c=>{console.error("[tg-agent] runModel error",c);let m=De(c);await f(n,`Error: ${m}`,o)})});R.on("polling_error",e=>{console.error("Polling error",e)});console.log("tg-agent started")});G();import Hr from"node:fs";import Sn from"node:path";import qr from"node:readline/promises";import{fileURLToPath as Jr}from"node:url";var kn=process.argv.slice(2),Mn=(e,t)=>kn.includes(e)||(t?kn.includes(t):!1),Kr=Mn("--help","-h"),Gr=Mn("--version","-v"),Vr=["Usage: tg-agent [options]","","Options:"," -h, --help Show help"," -v, --version Show version"].join(`
|
|
63
|
+
`),Yr=()=>{if(process.env.npm_package_version)return process.env.npm_package_version;try{let e=Jr(import.meta.url),t=Sn.dirname(e),n=Sn.join(t,"..","package.json"),o=Hr.readFileSync(n,"utf8"),r=JSON.parse(o);if(r.version)return r.version}catch{}return"dev"};Kr&&(console.log(Vr),process.exit(0));Gr&&(console.log(Yr()),process.exit(0));async function Xr(){let e=qr.createInterface({input:process.stdin,output:process.stdout});try{return(await e.question("Enter TELEGRAM_BOT_TOKEN: ")).trim()}finally{e.close()}}async function Qr(){let{configPath:e,data:t,exists:n}=le(),o=ct(),r=n?t:o,s=lt(r,o);if(ut(r)){s&&await Ie(e,r);return}process.stdin.isTTY||(console.error(`Missing telegram.bot_token in ${e}.`),process.exit(1));let a=await Xr();a||(console.error("Empty TELEGRAM_BOT_TOKEN."),process.exit(1)),dt(r,a),await Ie(e,r),console.log(`Saved config to ${e}.`)}async function Zr(){let{data:e}=le(),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 Qr();await Zr();gt();Promise.resolve().then(()=>xn());
|