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