@sns-myagent/cli 0.3.2 → 0.3.4
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/bin/snsagent.js +47 -0
- package/dist/cli.js +1 -1
- package/package.json +5 -6
- package/scripts/fetch-binary.mjs +18 -20
- package/scripts/smoke-test.sh +3 -3
- package/src/cli/index.ts +15 -15
- package/bin/snscoder.js +0 -9
package/bin/snsagent.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Auto-generated placeholder. fetch-binary.mjs will overwrite this with
|
|
3
|
+
// the real shim (bin/snsagent.js) that execs the platform binary.
|
|
4
|
+
// This placeholder exists so the npm package tarball always ships a
|
|
5
|
+
// valid shim at this path — npm install -g requires it (bin field).
|
|
6
|
+
// Without it, npm refuses to symlink `snsagent` to PATH.
|
|
7
|
+
import { spawn } from "node:child_process";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
9
|
+
import { dirname, join } from "node:path";
|
|
10
|
+
|
|
11
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
|
|
13
|
+
// Try common platform binary names (in order).
|
|
14
|
+
const candidates = [
|
|
15
|
+
"snsagent-linux-x64",
|
|
16
|
+
"snsagent-linux-arm64",
|
|
17
|
+
"snsagent-darwin-x64",
|
|
18
|
+
"snsagent-darwin-arm64",
|
|
19
|
+
"snsagent-windows-x64.exe",
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
let binary = null;
|
|
23
|
+
for (const c of candidates) {
|
|
24
|
+
try {
|
|
25
|
+
const { statSync } = await import("node:fs");
|
|
26
|
+
statSync(join(here, c));
|
|
27
|
+
binary = join(here, c);
|
|
28
|
+
break;
|
|
29
|
+
} catch {
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (!binary) {
|
|
35
|
+
process.stderr.write(
|
|
36
|
+
`✗ snsagent: platform binary not found.\n` +
|
|
37
|
+
` Expected one of: ${candidates.join(", ")}\n` +
|
|
38
|
+
` in ${here}\n` +
|
|
39
|
+
`\n` +
|
|
40
|
+
` Fix: re-run 'npm rebuild @sns-myagent/cli' to retry postinstall,\n` +
|
|
41
|
+
` or run 'curl -fsSL https://raw.githubusercontent.com/Reihantt6/sns-myagent/main/install.sh | bash'.\n`,
|
|
42
|
+
);
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const r = spawn(binary, process.argv.slice(2), { stdio: "inherit" });
|
|
47
|
+
r.on("exit", (c) => process.exit(c ?? 0));
|
package/dist/cli.js
CHANGED
|
@@ -9798,7 +9798,7 @@ ${k}${W.fg("dim",T)}${W.fg("muted",`line ${O.line}`)}`}return D.split(`
|
|
|
9798
9798
|
`):void 0}}function tg4(f){let $=[];for(let Y of f){let W=g3(Y.link)??g3(Y.url);if(!W)continue;let Z=g3(Y.publish_date)??g3(Y.publishedDate);$.push({title:g3(Y.title)??W,url:W,snippet:g3(Y.content)??void 0,publishedDate:Z??void 0,ageSeconds:H9(Z),author:g3(Y.media)??void 0})}return $}async function Cc2(f){let $=f.authStorage.resolver("zai",{sessionId:f.sessionId}),Y=await Z6($,(q)=>lg4(q,f),{signal:f.signal,missingKeyMessage:"Z.AI credentials not found. Set ZAI_API_KEY or login with 'omp /login zai'."}),W=rg4(Y),Z=tg4(W.results);if(f.num_results&&Z.length>f.num_results)Z=Z.slice(0,f.num_results);return{provider:"zai",answer:W.answer,sources:Z,requestId:W.requestId}}var Fg4="https://api.z.ai/api/mcp/web_search_prime/mcp",Qg4="web_search_prime",mg4=10,Ec2;var xc2=A(()=>{D2();IV();W8();jf();Ec2=class Ec2 extends a6{id="zai";label="Z.AI";isAvailable(f){return f.hasAuth("zai")||!!I2("zai")}search(f){let{fetch:$}=f;return Cc2({query:f.query,num_results:f.numSearchResults??f.limit,signal:f.signal,authStorage:f.authStorage,sessionId:f.sessionId,fetch:$})}}});var yc2={};s0(yc2,{searchAnthropic:()=>Sc2,AnthropicProvider:()=>Ic2});function $x4(){return k0.ANTHROPIC_SEARCH_MODEL??sg4}function Yx4(f,$,Y){let W=f.isOAuth&&!$.startsWith("claude-3-5-haiku"),Z=f.isOAuth?["You are a helpful AI assistant with web search capabilities."]:[];return u$0(Y?[Y]:void 0,{includeClaudeCodeInstruction:W,extraInstructions:Z,cacheControl:{type:"ephemeral"}})}async function Wx4(f,$,Y,W,Z,q,X,w,J=fetch){let K=_s1(f),_=Ks1(f),z=Yx4(f,$,Z),G={model:$,max_tokens:q??eg4,messages:[{role:"user",content:Y}],tools:[{type:fx4,name:Lc2}]};if(W)G.metadata={user_id:W};if(X!==void 0)G.temperature=X;if(z&&z.length>0)G.system=z;let u=await(f.isOAuth?K$0(J):J)(K,{method:"POST",headers:_,body:JSON.stringify(G),signal:S6(w)});if(!u.ok){let D=await u.text(),H=r6("anthropic",u.status,D);if(H)throw H;throw new v2("anthropic",`Anthropic API error (${u.status}): ${D}`,u.status)}return u.json()}function Zx4(f){if(!f)return;let $=f.match(/^(\d+)\s*(s|sec|second|m|min|minute|h|hour|d|day|w|week|mo|month|y|year)s?\s*(ago)?$/i);if(!$)return;let Y=parseInt($[1],10),W=$[2].toLowerCase();return Y*({s:1,sec:1,second:1,m:60,min:60,minute:60,h:3600,hour:3600,d:86400,day:86400,w:604800,week:604800,mo:2592000,month:2592000,y:31536000,year:31536000}[W]??86400)}function qx4(f){let $=[],Y=[],W=[],Z=[];for(let q of f.content)if(q.type==="server_tool_use"&&q.name&&G$0(q.name)===Lc2){if(q.input?.query)Y.push(q.input.query)}else if(q.type==="web_search_tool_result"&&q.content){for(let X of q.content)if(X.type==="web_search_result")W.push({title:X.title,url:X.url,snippet:void 0,publishedDate:X.page_age??void 0,ageSeconds:Zx4(X.page_age)})}else if(q.type==="text"&&q.text){if($.push(q.text),q.citations)for(let X of q.citations)Z.push({url:X.url,title:X.title,citedText:X.cited_text})}return{provider:"anthropic",answer:$.join(`
|
|
9799
9799
|
|
|
9800
9800
|
`)||void 0,sources:W,citations:Z.length>0?Z:void 0,searchQueries:Y.length>0?Y:void 0,usage:{inputTokens:f.usage.input_tokens,outputTokens:f.usage.output_tokens,searchRequests:f.usage.server_tool_use?.web_search_requests},model:f.model,requestId:f.id}}async function Sc2(f,$){let Y=k0.ANTHROPIC_SEARCH_API_KEY,W=k0.ANTHROPIC_SEARCH_BASE_URL,Z=Y?Y:("authStorage"in f)?f.authStorage.resolver("anthropic",{sessionId:f.sessionId}):void 0;if(!Z)throw Error("No Anthropic credentials found. Set ANTHROPIC_SEARCH_API_KEY or ANTHROPIC_API_KEY, or configure Anthropic OAuth.");let q=$x4(),X="authStorage"in f?f.systemPrompt:f.system_prompt,w="authStorage"in f?f.maxOutputTokens:f.max_tokens,J="authStorage"in f?f.sessionId:void 0,K="authStorage"in f?f.authStorage.getOAuthAccountId("anthropic",f.sessionId):void 0,_=await Z6(Z,(j)=>{let u=Js1(j,W),D=z$0(J,u.isOAuth,J,K);return Wx4(u,q,f.query,D,X,w,f.temperature,f.signal,f.fetch)},{signal:f.signal,missingKeyMessage:"No Anthropic credentials found. Set ANTHROPIC_SEARCH_API_KEY or ANTHROPIC_API_KEY, or configure Anthropic OAuth."}),z=qx4(_),G="authStorage"in f?f.numSearchResults??f.limit:f.num_results;if(G&&z.sources.length>G)z.sources=z.sources.slice(0,G);return z}var sg4="claude-haiku-4-5",eg4=4096,Lc2="web_search",fx4="web_search_20250305",Ic2;var Bc2=A(()=>{D2();t();W8();jf();Ic2=class Ic2 extends a6{id="anthropic";label="Anthropic";isAvailable(f){return Boolean(k0.ANTHROPIC_SEARCH_API_KEY)||f.hasAuth("anthropic")}search(f){return Sc2(f)}}});var dc2={};s0(dc2,{searchGemini:()=>Qc2,findGeminiAuth:()=>Fc2,buildGeminiRequestTools:()=>ic2,GeminiProvider:()=>mc2});function ic2(f){let $=[{googleSearch:f.google_search??{}}];if(f.code_execution!==void 0)$.push({codeExecution:f.code_execution});if(f.url_context!==void 0)$.push({urlContext:f.url_context});return $}async function Fc2(f,$,Y){for(let W of nc2){let Z=await f.getOAuthAccess(W,$,{signal:Y});if(!Z?.accessToken||!Z.projectId)continue;return{provider:W,access:Z,projectId:Z.projectId}}return null}function zx4(f){return nc2.some(($)=>f.hasOAuth($))}async function Gx4(f,$,Y,W,Z,q,X,w,J){let K;if(f.isAntigravity){let L=J??"auto";if(L==="sandbox")K=[pc2];else if(L==="production")K=[Uc2];else K=[...wx4]}else K=[Xx4];let _=f.isAntigravity?{"User-Agent":g$()}:Nw(),z=f.isAntigravity?{requestType:"agent",userAgent:"antigravity",requestId:`agent-${crypto.randomUUID()}`}:{userAgent:"pi-coding-agent",requestId:`pi-${Date.now()}-${Math.random().toString(36).slice(2,11)}`},G=Y?.toWellFormed(),j=[...f.isAntigravity?[{text:kE}]:[],...G?[{text:G}]:[]],u={project:f.projectId,model:cc2,request:{contents:[{role:"user",parts:[{text:$}]}],tools:ic2(q),...j.length>0&&{systemInstruction:{...f.isAntigravity?{role:"user"}:{},parts:j}}},...z};if(W!==void 0||Z!==void 0){let L={};if(W!==void 0)L.maxOutputTokens=W;if(Z!==void 0)L.temperature=Z;u.request.generationConfig=L}let D=()=>({method:"POST",headers:{Authorization:`Bearer ${f.accessToken}`,"Content-Type":"application/json",Accept:"text/event-stream",..._},body:JSON.stringify(u),signal:S6(w)}),H;for(let L=0;L<K.length;L++){let E=K[L],S=L===K.length-1;try{if(H=await Tf(()=>`${E}/v1internal:streamGenerateContent?alt=sse`,{...D(),fetch:X,maxAttempts:S?Jx4+1:1,defaultDelayMs:(U)=>Kx4*2**U,maxDelayMs:_x4}),H.ok)break;if(H.status===429||H.status>=500&&H.status<600){if(!S)continue}break}catch(U){if(S)throw U}}if(!H?.ok){let L=H?await H.text():"Network error",E=H?.status??502,S=r6("gemini",E,L);if(S)throw S;throw new v2("gemini",`Gemini Cloud Code API error (${E}): ${L}`,E)}if(!H.ok){let L=await H.text(),E=r6("gemini",H.status,L);if(E)throw E;throw new v2("gemini",`Gemini Cloud Code API error (${H.status}): ${L}`,H.status)}if(!H.body)throw new v2("gemini","Gemini API returned no response body",500);let O=[],k=[],h=[],V=[],T=new Set,N=cc2,M,P=H.body.getReader(),R=new TextDecoder,x="";try{while(!0){let{done:L,value:E}=await P.read();if(L)break;x+=R.decode(E,{stream:!0});let S=x.split(`
|
|
9801
|
-
`);x=S.pop()||"";for(let U of S){if(!U.startsWith("data:"))continue;let c=U.slice(5).trim();if(!c)continue;let C;try{C=JSON.parse(c)}catch{continue}let I=C.response;if(!I)continue;let B=I.candidates?.[0];if(B?.content?.parts){for(let n of B.content.parts)if(n.text)O.push(n.text)}let p=B?.groundingMetadata;if(p){if(p.groundingChunks){for(let n of p.groundingChunks)if(n.web?.uri){let d=n.web.uri;if(!T.has(d))T.add(d),k.push({title:n.web.title??d,url:d})}}if(p.groundingSupports&&p.groundingChunks)for(let n of p.groundingSupports){let d=n.segment?.text,$0=n.groundingChunkIndices??[];for(let Y0 of $0){let K0=p.groundingChunks[Y0];if(K0?.web?.uri)h.push({url:K0.web.uri,title:K0.web.title??K0.web.uri,citedText:d})}}if(p.webSearchQueries){for(let n of p.webSearchQueries)if(!V.includes(n))V.push(n)}}if(I.usageMetadata)M={inputTokens:I.usageMetadata.promptTokenCount??0,outputTokens:I.usageMetadata.candidatesTokenCount??0,totalTokens:I.usageMetadata.totalTokenCount??0};if(I.modelVersion)N=I.modelVersion}}}finally{P.releaseLock()}return{answer:O.join(""),sources:k,citations:h,searchQueries:V,model:N,usage:M}}async function Qc2(f){let $=await Fc2(f.authStorage,f.sessionId,f.signal);if(!$)throw Error("No Gemini OAuth credentials found. Login with 'omp /login google-gemini-cli' or 'omp /login google-antigravity' to enable Gemini web search.");let Y=$.provider==="google-antigravity",W=await _E(f.authStorage,$.provider,(q)=>Gx4({accessToken:q.accessToken,projectId:q.projectId??$.projectId,isAntigravity:Y},f.query,f.system_prompt,f.max_output_tokens,f.temperature,{google_search:f.google_search,code_execution:f.code_execution,url_context:f.url_context},f.fetch,f.signal,f.antigravityEndpointMode),{sessionId:f.sessionId,signal:f.signal,seed:$.access}),Z=W.sources;if(f.num_results&&Z.length>f.num_results)Z=Z.slice(0,f.num_results);return{provider:"gemini",answer:W.answer||void 0,sources:Z,citations:W.citations.length>0?W.citations:void 0,searchQueries:W.searchQueries.length>0?W.searchQueries:void 0,usage:W.usage,model:W.model}}var Xx4="https://cloudcode-pa.googleapis.com",Uc2="https://daily-cloudcode-pa.googleapis.com",pc2="https://daily-cloudcode-pa.sandbox.googleapis.com",wx4,cc2="gemini-2.5-flash",Jx4=3,Kx4=1000,_x4=300000,nc2,mc2;var oc2=A(()=>{D2();mG();t();W8();jf();wx4=[Uc2,pc2],nc2=["google-gemini-cli","google-antigravity"];mc2=class mc2 extends a6{id="gemini";label="Gemini";isAvailable(f){return zx4(f)}search(f){return Qc2({query:f.query,system_prompt:f.systemPrompt,num_results:f.numSearchResults??f.limit,max_output_tokens:f.maxOutputTokens,temperature:f.temperature,google_search:f.googleSearch,code_execution:f.codeExecution,url_context:f.urlContext,signal:f.signal,authStorage:f.authStorage,sessionId:f.sessionId,fetch:f.fetch})}}});var yV;var It=A(()=>{yV={type:"module",name:"@sns-myagent/cli",version:"0.3.
|
|
9801
|
+
`);x=S.pop()||"";for(let U of S){if(!U.startsWith("data:"))continue;let c=U.slice(5).trim();if(!c)continue;let C;try{C=JSON.parse(c)}catch{continue}let I=C.response;if(!I)continue;let B=I.candidates?.[0];if(B?.content?.parts){for(let n of B.content.parts)if(n.text)O.push(n.text)}let p=B?.groundingMetadata;if(p){if(p.groundingChunks){for(let n of p.groundingChunks)if(n.web?.uri){let d=n.web.uri;if(!T.has(d))T.add(d),k.push({title:n.web.title??d,url:d})}}if(p.groundingSupports&&p.groundingChunks)for(let n of p.groundingSupports){let d=n.segment?.text,$0=n.groundingChunkIndices??[];for(let Y0 of $0){let K0=p.groundingChunks[Y0];if(K0?.web?.uri)h.push({url:K0.web.uri,title:K0.web.title??K0.web.uri,citedText:d})}}if(p.webSearchQueries){for(let n of p.webSearchQueries)if(!V.includes(n))V.push(n)}}if(I.usageMetadata)M={inputTokens:I.usageMetadata.promptTokenCount??0,outputTokens:I.usageMetadata.candidatesTokenCount??0,totalTokens:I.usageMetadata.totalTokenCount??0};if(I.modelVersion)N=I.modelVersion}}}finally{P.releaseLock()}return{answer:O.join(""),sources:k,citations:h,searchQueries:V,model:N,usage:M}}async function Qc2(f){let $=await Fc2(f.authStorage,f.sessionId,f.signal);if(!$)throw Error("No Gemini OAuth credentials found. Login with 'omp /login google-gemini-cli' or 'omp /login google-antigravity' to enable Gemini web search.");let Y=$.provider==="google-antigravity",W=await _E(f.authStorage,$.provider,(q)=>Gx4({accessToken:q.accessToken,projectId:q.projectId??$.projectId,isAntigravity:Y},f.query,f.system_prompt,f.max_output_tokens,f.temperature,{google_search:f.google_search,code_execution:f.code_execution,url_context:f.url_context},f.fetch,f.signal,f.antigravityEndpointMode),{sessionId:f.sessionId,signal:f.signal,seed:$.access}),Z=W.sources;if(f.num_results&&Z.length>f.num_results)Z=Z.slice(0,f.num_results);return{provider:"gemini",answer:W.answer||void 0,sources:Z,citations:W.citations.length>0?W.citations:void 0,searchQueries:W.searchQueries.length>0?W.searchQueries:void 0,usage:W.usage,model:W.model}}var Xx4="https://cloudcode-pa.googleapis.com",Uc2="https://daily-cloudcode-pa.googleapis.com",pc2="https://daily-cloudcode-pa.sandbox.googleapis.com",wx4,cc2="gemini-2.5-flash",Jx4=3,Kx4=1000,_x4=300000,nc2,mc2;var oc2=A(()=>{D2();mG();t();W8();jf();wx4=[Uc2,pc2],nc2=["google-gemini-cli","google-antigravity"];mc2=class mc2 extends a6{id="gemini";label="Gemini";isAvailable(f){return zx4(f)}search(f){return Qc2({query:f.query,system_prompt:f.systemPrompt,num_results:f.numSearchResults??f.limit,max_output_tokens:f.maxOutputTokens,temperature:f.temperature,google_search:f.googleSearch,code_execution:f.codeExecution,url_context:f.urlContext,signal:f.signal,authStorage:f.authStorage,sessionId:f.sessionId,fetch:f.fetch})}}});var yV;var It=A(()=>{yV={type:"module",name:"@sns-myagent/cli",version:"0.3.3",description:"SNS-MyAgent \u2014 Pi Agent size, full features. BYOK coding agent CLI.",homepage:"https://github.com/Reihantt6/sns-myagent",author:"Reihantt6",contributors:[],license:"MIT",repository:{type:"git",url:"git+https://github.com/Reihantt6/sns-myagent.git"},bugs:{url:"https://github.com/Reihantt6/sns-myagent/issues"},keywords:["coding-agent","ai","llm","cli","byok","telegram","multi-agent","tui","agent"],main:"./src/index.ts",types:"./dist/types/index.d.ts",bin:{snsagent:"bin/snsagent.js"},scripts:{"fetch-binary":"node scripts/fetch-binary.mjs",postinstall:"node scripts/fetch-binary.mjs && node scripts/apply-pi-natives-patch.js",build:`bun build --compile --define process.env.PI_COMPILED='"true"' --define process.env.PKG_VERSION='"0.3.3"' --no-compile-autoload-bunfig --no-compile-autoload-dotenv --no-compile-autoload-tsconfig --no-compile-autoload-package-json --keep-names --outfile bin/snsagent-linux-x64 ./src/cli/entry.ts && cp bin/snsagent-linux-x64 bin/snsagent`,check:"biome check . && bun run check:types","check:types":"tsgo -p tsconfig.json --noEmit",lint:"biome lint .",test:"bun test --parallel=4 test src",fix:"biome check --write --unsafe . && bun run format-prompts",fmt:"biome format --write . && bun run format-prompts","format-prompts":"bun scripts/format-prompts.ts","generate-docs-index":"bun scripts/generate-docs-index.ts --generate",prepack:"(bun scripts/generate-docs-index.ts --generate 2>/dev/null || echo 'docs index skipped') && (bun --cwd=../collab-web run build:tool-views 2>/dev/null || echo 'collab-web not found, skipping') && (bun scripts/bundle-dist.ts 2>/dev/null || echo 'bundle-dist skipped')",postpack:"bun scripts/generate-docs-index.ts --reset","bench:guard":"bun scripts/bench-guard.ts"},dependencies:{"@agentclientprotocol/sdk":"0.25.0","@babel/parser":"^7.29.7","@mozilla/readability":"^0.6.0","@oh-my-pi/hashline":"^16.1.18","@oh-my-pi/omp-stats":"^16.1.18","@oh-my-pi/pi-agent-core":"^16.1.18","@oh-my-pi/pi-ai":"^16.1.18","@oh-my-pi/pi-catalog":"^16.1.18","@oh-my-pi/pi-mnemopi":"^16.1.18","@oh-my-pi/pi-natives":"^16.1.18","@oh-my-pi/pi-tui":"^16.1.18","@oh-my-pi/pi-utils":"^16.1.18","@oh-my-pi/pi-wire":"^16.1.18","@oh-my-pi/snapcompact":"^16.1.18","@opentelemetry/api":"^1.9.1","@opentelemetry/context-async-hooks":"^2.7.1","@opentelemetry/exporter-trace-otlp-proto":"^0.218.0","@opentelemetry/resources":"^2.7.1","@opentelemetry/sdk-trace-base":"^2.7.1","@opentelemetry/sdk-trace-node":"^2.7.1","@puppeteer/browsers":"^3.0.4","@types/turndown":"5.0.6","@xterm/headless":"^6.0.0",arktype:"^2.2.0",boxen:"^8.0.1",chalk:"^5.6.2","cli-table3":"^0.6.5",diff:"^9.0.0","fast-xml-parser":"^5.9.0","gradient-string":"^3.0.0",grammy:"^1.44.0",handlebars:"^4.7.9","js-yaml":"^5.1.0",linkedom:"^0.18.12","lru-cache":"11.5.1",mammoth:"^1.12.0",mupdf:"^1.27.0",ora:"^9.4.1",picocolors:"^1.1.1","puppeteer-core":"^25.1.0","string-width":"^8.2.1",turndown:"7.2.4","turndown-plugin-gfm":"1.0.2",zod:"^4"},optionalDependencies:{"@huggingface/transformers":"^4.2.0","sherpa-onnx-node":"1.13.2"},devDependencies:{"@types/bun":"^1.3.14","@types/js-yaml":"^4.0.9",typescript:"^6.0.3"},engines:{bun:">=1.3.14"},files:["src","bin","dist/cli.js","dist/*.node","scripts","examples","README.md","CHANGELOG.md","dist/types"]}});var fU2={};s0(fU2,{searchCodex:()=>tc2,hasCodexSearch:()=>sc2,CodexProvider:()=>ec2});import*as ny from"os";function hx4(){let f=k0.PI_CODEX_WEB_SEARCH_MODEL?.trim();return f?f:void 0}function Ax4(){let f=P4("openai-codex"),$=new Set(f.map((Z)=>Z.id)),Y=Ox4.filter((Z)=>$.has(Z));if(Y.length>0)return Y;let W=f.find((Z)=>!Z.id.includes("mini")&&!Z.id.includes("spark"));if(W)return[W.id];return f[0]?.id?[f[0].id]:[Hx4]}function vx4(f){if(!(f instanceof v2))return!1;if(f.provider!=="codex"||f.status!==400)return!1;return/model is not supported|requested model is not supported|not supported when using codex with a chatgpt account/i.test(f.message)}function lc2(f){let $=f.trim().replace(/^[[("'`*_]+/,"").replace(/[\])"'`*_.!?]+$/,"").trim().toLowerCase();return Tx4.has($)}function nj0(f,$){if(!f.some((Y)=>Y.url===$.url))f.push($)}function py(f,$){let Y=0;for(let W of f)if(W===$)Y+=1;return Y}function ac2(f){let $=f.trim();while($.length>0){let Y=$.at(-1);if(!Y)break;if(/[.,!?;:'"]/u.test(Y)){$=$.slice(0,-1);continue}if(Y===")"&&py($,")")>py($,"(")){$=$.slice(0,-1);continue}if(Y==="]"&&py($,"]")>py($,"[")){$=$.slice(0,-1);continue}if(Y==="}"&&py($,"}")>py($,"{")){$=$.slice(0,-1);continue}break}if(!/^https?:\/\//.test($))return null;try{return new URL($).toString()}catch{return null}}function Nx4(f,$){let Y=0;for(let W=$;W<f.length;W+=1){let Z=f[W];if(!Z||Z===`
|
|
9802
9802
|
`)return null;if(Z==="("){Y+=1;continue}if(Z!==")")continue;if(Y-=1,Y===0)return W;if(Y<0)return null}return null}function Mx4(f){let $=[];for(let Y=0;Y<f.length;Y+=1){if(f[Y]!=="[")continue;let W=f.indexOf("]",Y+1);if(W===-1||f[W+1]!=="(")continue;let Z=Nx4(f,W+1);if(Z===null)continue;let q=f.slice(Y+1,W).trim(),X=ac2(f.slice(W+2,Z));if(X)nj0($,{title:q||X,url:X});Y=Z}for(let Y of f.matchAll(/https?:\/\/\S+/g)){let W=ac2(Y[0]??"");if(!W)continue;nj0($,{title:W,url:W})}return $}function rc2(f){let W=V$0(f)?.[kx4]?.chatgpt_account_id;return typeof W==="string"&&W.length>0?W:null}async function Px4(f,$,Y){let W=await f.getOAuthAccess("openai-codex",$,{signal:Y});if(!W)return null;let Z=W.accountId??rc2(W.accessToken);if(!Z)return null;return{access:W,accountId:Z}}function bx4(f,$){return{Authorization:`Bearer ${f}`,"chatgpt-account-id":$,"OpenAI-Beta":"responses=experimental",originator:"pi","User-Agent":`pi/${yV.version} (${ny.platform()} ${ny.release()}; ${ny.arch()})`,Accept:"text/event-stream","Content-Type":"application/json"}}async function Rx4(f,$,Y){let W=`${ux4}${Dx4}`,Z=bx4(f.accessToken,f.accountId),q=Y.modelId,X={model:q,stream:!0,store:!1,input:[{type:"message",role:"user",content:[{type:"input_text",text:$}]}],tools:[{type:"web_search",search_context_size:Y.searchContextSize??"high"}],tool_choice:{type:"web_search"},instructions:Y.systemPrompt??Vx4},J=await(Y.fetch??fetch)(W,{method:"POST",headers:Z,body:JSON.stringify(X),signal:S6(Y.signal)});if(!J.ok){let N=await J.text(),M=r6("codex",J.status,N);if(M)throw M;throw new v2("codex",`Codex API error (${J.status}): ${N}`,J.status)}if(!J.body)throw new v2("codex","Codex API returned no response body",500);let K=[],_=[],z=[],G=q,j="",u;for await(let N of v8(J.body,Y.signal)){let M=typeof N.type==="string"?N.type:"";if(!M)continue;if(M==="response.output_text.delta"){let P=typeof N.delta==="string"?N.delta:"";if(P)_.push(P)}else if(M==="response.output_item.done"){let P=N.item;if(!P)continue;if(P.type==="message"&&P.content){for(let R of P.content)if(R.type==="output_text"&&R.text){if(K.push(R.text),R.annotations){for(let x of R.annotations)if(x.type==="url_citation"&&x.url)nj0(z,{title:x.title??x.url,url:x.url})}}}if(P.type==="reasoning"&&P.summary){for(let R of P.summary)if(R.type==="summary_text"&&R.text)K.push(R.text)}}else if(M==="response.completed"||M==="response.done"){let P=N.response;if(P){if(P.model)G=P.model;if(P.id)j=P.id;if(P.usage){let R=P.usage.input_tokens_details?.cached_tokens??0;u={inputTokens:(P.usage.input_tokens??0)-R,outputTokens:P.usage.output_tokens??0,totalTokens:P.usage.total_tokens??0}}}}else if(M==="error"){let P=N.code??"",R=N.message??"Unknown error";throw new v2("codex",`Codex error (${P}): ${R}`,500)}else if(M==="response.failed"){let R=N.response?.error?.message??"Request failed";throw new v2("codex",`Codex request failed: ${R}`,500)}}let D=K.join(`
|
|
9803
9803
|
|
|
9804
9804
|
`).trim(),H=_.join("").trim(),O=D.length>0&&lc2(D),k=H.length>0&&lc2(H),h=D.length>0&&!O,V=H.length>0&&!k;if(!h&&!V&&z.length===0)throw new v2("codex","Codex returned image-only response",502);let T=h?D:V?H:"";if(z.length===0&&T.length>0)for(let N of Mx4(T))nj0(z,N);return{answer:T,sources:z,model:G,requestId:j,usage:u}}async function tc2(f){let $=await Px4(f.authStorage,f.sessionId,f.signal);if(!$)throw Error("No Codex OAuth credentials found. Login with 'omp /login openai-codex' to enable Codex web search.");let Y=hx4(),W=Y?[Y]:Ax4(),Z=await _E(f.authStorage,"openai-codex",async(w)=>{let J=w.accountId??rc2(w.accessToken);if(!J)throw Error("Codex OAuth credential is missing a ChatGPT account id");let K={accessToken:w.accessToken,accountId:J},_;for(let z=0;z<W.length;z+=1){let G=W[z];if(!G)continue;try{return await Rx4(K,f.query,{signal:f.signal,systemPrompt:f.systemPrompt,searchContextSize:"high",modelId:G,fetch:f.fetch})}catch(j){_=j;let u=z===W.length-1;if(Y||u||!vx4(j))throw j}}throw _??Error("Codex search failed without returning a result")},{sessionId:f.sessionId,signal:f.signal,seed:$.access}),q=Z.sources,X=f.numSearchResults??f.limit;if(X&&q.length>X)q=q.slice(0,X);return{provider:"codex",answer:Z.answer||void 0,sources:q,usage:Z.usage?{inputTokens:Z.usage.inputTokens,outputTokens:Z.usage.outputTokens,totalTokens:Z.usage.totalTokens}:void 0,model:Z.model,requestId:Z.requestId}}async function sc2(f){return f.hasOAuth("openai-codex")}var ux4="https://chatgpt.com/backend-api",Dx4="/codex/responses",Hx4="gpt-5.5",Ox4,kx4="https://api.openai.com/auth",Vx4="You are a helpful assistant with web search capabilities. Search the web to answer the user's question accurately and cite your sources.",Tx4,ec2;var $U2=A(()=>{D2();Ig();W4();t();It();W8();jf();Ox4=["gpt-5.5","gpt-5.4","gpt-5-codex","gpt-5","gpt-5.3-codex","gpt-5.2-codex","gpt-5.1-codex","gpt-5-codex-mini"];Tx4=new Set(["see attached image","attached image","see the attached image","see image","see image above","image above","see image below","image below"]);ec2=class ec2 extends a6{id="codex";label="OpenAI";isAvailable(f){return sc2(f)}search(f){return tc2(f)}}});var JU2={};s0(JU2,{searchTavily:()=>XU2,findApiKey:()=>gx4,buildRequestBody:()=>qU2,TavilyProvider:()=>wU2});function Ex4(f){if(typeof f!=="object"||f===null)return null;return f}function ZU2(f){if(typeof f==="string"){let Y=f.trim();return Y.length>0?Y:null}let $=Ex4(f);if(!$)return null;for(let Y of["detail","error","message"]){let W=ZU2($[Y]);if(W)return W}return null}async function gx4(f,$,Y){return await f.getApiKey("tavily",$,{signal:Y})??null}function qU2(f){let $=IW(f.num_results,YU2,WU2),Y={query:f.query,search_depth:"basic",max_results:$,include_answer:"advanced",include_raw_content:!1};if(f.recency)Y.time_range=f.recency;return Y}async function xx4(f,$){let Y=await($.fetch??fetch)(Cx4,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${f}`},body:JSON.stringify(qU2($)),signal:S6($.signal)});if(!Y.ok){let W=await Y.text(),Z=r6("tavily",Y.status,W);if(Z)throw Z;let q=W.trim();if(q.length===0)q=Y.statusText;else try{q=ZU2(JSON.parse(W))??q}catch{}throw new v2("tavily",`Tavily API error (${Y.status}): ${q}`,Y.status)}return await Y.json()}async function XU2(f){let $={query:f.query,num_results:f.numSearchResults??f.limit,recency:f.recency,signal:f.signal,fetch:f.fetch},Y=f.authStorage.resolver("tavily",{sessionId:f.sessionId}),W=IW($.num_results,YU2,WU2),Z=await Z6(Y,(X)=>xx4(X,$),{signal:f.signal,missingKeyMessage:'Tavily credentials not found. Set TAVILY_API_KEY or configure an API key for provider "tavily".'}),q=[];for(let X of Z.results??[]){if(!X.url)continue;q.push({title:X.title??X.url,url:X.url,snippet:X.content??void 0,publishedDate:X.published_date??void 0,ageSeconds:H9(X.published_date??void 0)})}return{provider:"tavily",answer:Z.answer?.trim()||void 0,sources:q.slice(0,W),requestId:Z.request_id??void 0,authMode:"api_key"}}var Cx4="https://api.tavily.com/search",YU2=5,WU2=20,wU2;var KU2=A(()=>{D2();W8();jf();wU2=class wU2 extends a6{id="tavily";label="Tavily";isAvailable(f){return f.hasAuth("tavily")||!!I2("tavily")}search(f){return XU2(f)}}});function uP(f){return typeof f==="object"&&f!==null}function gu(f,$){return Object.getOwnPropertyDescriptor(f,$)?.value}function O9(f,$){let Y=gu(f,$);return typeof Y==="string"?Y:void 0}function GU2(f,$){let Y=gu(f,$);return typeof Y==="number"&&Number.isFinite(Y)?Y:void 0}function N81(f,$){let Y=gu(f,$);if(!Array.isArray(Y))return[];return Y.filter(uP)}function jU2(f,$){let Y=gu(f,$);if(!Array.isArray(Y))return[];return Y.filter((W)=>typeof W==="string")}function Sx4(f){if(!uP(f))return null;let $=O9(f,"message")??O9(f,"detail")??O9(f,"error");if($&&$.trim().length>0)return $.trim();let Y=gu(f,"error");if(uP(Y)){let W=O9(Y,"message")??O9(Y,"detail");if(W&&W.trim().length>0)return W.trim()}return null}function T81(f,$){return new BV($?`Parallel API error (${f}): ${$}`:`Parallel API error (${f})`,f)}function P81(f,$){let Y=$.trim();if(Y.length===0)return T81(f);try{let W=JSON.parse(Y);return T81(f,Sx4(W)??Y)}catch{return T81(f,Y)}}function Ix4(f){return{Accept:"application/json","Content-Type":"application/json","x-api-key":f,"parallel-beta":M81}}function uU2(f){if(!Array.isArray(f))return[];let $=[];for(let Y of f){if(typeof Y==="string"){$.push(Y);continue}if(!uP(Y))continue;let W=O9(Y,"message")??O9(Y,"warning");if(W)$.push(W)}return $}function DU2(f){if(!Array.isArray(f))return[];let $=[];for(let Y of f){if(!uP(Y))continue;$.push({name:O9(Y,"name"),count:GU2(Y,"count")})}return $}function HU2(f,$){if(!uP(f))throw new BV("Parallel search returned an invalid response payload.");let Y=O9(f,"search_id")??"",W=N81(f,"results"),Z=[];for(let X of W){let w=O9(X,"url");if(!w)continue;let J=jU2(X,"excerpts"),K=J.length>0?J.join(`
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@sns-myagent/cli",
|
|
4
|
-
"version": "0.3.
|
|
5
|
-
"description": "SNS-MyAgent
|
|
4
|
+
"version": "0.3.4",
|
|
5
|
+
"description": "SNS-MyAgent \u2014 Pi Agent size, full features. BYOK coding agent CLI.",
|
|
6
6
|
"homepage": "https://github.com/Reihantt6/sns-myagent",
|
|
7
7
|
"author": "Reihantt6",
|
|
8
8
|
"contributors": [],
|
|
@@ -28,13 +28,12 @@
|
|
|
28
28
|
"main": "./src/index.ts",
|
|
29
29
|
"types": "./dist/types/index.d.ts",
|
|
30
30
|
"bin": {
|
|
31
|
-
"
|
|
32
|
-
"snsagent": "bin/snscoder.js"
|
|
31
|
+
"snsagent": "bin/snsagent.js"
|
|
33
32
|
},
|
|
34
33
|
"scripts": {
|
|
35
34
|
"fetch-binary": "node scripts/fetch-binary.mjs",
|
|
36
35
|
"postinstall": "node scripts/fetch-binary.mjs && node scripts/apply-pi-natives-patch.js",
|
|
37
|
-
"build": "bun build --compile --define process.env.PI_COMPILED='\"true\"' --define process.env.PKG_VERSION='\"0.3.
|
|
36
|
+
"build": "bun build --compile --define process.env.PI_COMPILED='\"true\"' --define process.env.PKG_VERSION='\"0.3.4\"' --no-compile-autoload-bunfig --no-compile-autoload-dotenv --no-compile-autoload-tsconfig --no-compile-autoload-package-json --keep-names --outfile bin/snsagent-linux-x64 ./src/cli/entry.ts && cp bin/snsagent-linux-x64 bin/snsagent",
|
|
38
37
|
"check": "biome check . && bun run check:types",
|
|
39
38
|
"check:types": "tsgo -p tsconfig.json --noEmit",
|
|
40
39
|
"lint": "biome lint .",
|
|
@@ -116,4 +115,4 @@
|
|
|
116
115
|
"CHANGELOG.md",
|
|
117
116
|
"dist/types"
|
|
118
117
|
]
|
|
119
|
-
}
|
|
118
|
+
}
|
package/scripts/fetch-binary.mjs
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// fetch-binary.mjs — Node.js postinstall for @sns-myagent/cli
|
|
3
3
|
//
|
|
4
|
-
// Downloads the prebuilt `
|
|
5
|
-
// into <prefix>/bin/, then symlinks the active one to <prefix>/bin/
|
|
6
|
-
// so `npm install -g @sns-myagent/cli` puts a working `
|
|
4
|
+
// Downloads the prebuilt `snsagent` binary from the latest GitHub release
|
|
5
|
+
// into <prefix>/bin/, then symlinks the active one to <prefix>/bin/snsagent
|
|
6
|
+
// so `npm install -g @sns-myagent/cli` puts a working `snsagent` on PATH.
|
|
7
7
|
//
|
|
8
8
|
// Asset layout matches what .github/workflows/build-release.yml produces:
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
9
|
+
// snsagent-linux-x64 (raw, not zipped)
|
|
10
|
+
// snsagent-linux-arm64
|
|
11
|
+
// snsagent-darwin-x64
|
|
12
|
+
// snsagent-darwin-arm64
|
|
13
|
+
// snsagent-windows-x64.exe
|
|
14
14
|
//
|
|
15
15
|
// Falls back to musl variant on Linux if glibc asset unavailable.
|
|
16
16
|
// Never breaks `npm install` — on any failure prints warning + exits 0.
|
|
@@ -30,9 +30,9 @@ const UA = "sns-myagent-fetch-binary/0.2.0 (npm postinstall)";
|
|
|
30
30
|
const __filename = fileURLToPath(import.meta.url);
|
|
31
31
|
const __dirname = dirname(__filename);
|
|
32
32
|
// npm install -g layout: <prefix>/lib/node_modules/@sns-myagent/cli/scripts/fetch-binary.mjs
|
|
33
|
-
// <prefix>/lib/node_modules/@sns-myagent/cli/node_modules/.bin/
|
|
33
|
+
// <prefix>/lib/node_modules/@sns-myagent/cli/node_modules/.bin/snsagent (npm symlinks bin)
|
|
34
34
|
// We want to download into <prefix>/lib/node_modules/@sns-myagent/cli/bin/
|
|
35
|
-
// so npm auto-symlinks it into <prefix>/bin/
|
|
35
|
+
// so npm auto-symlinks it into <prefix>/bin/snsagent.
|
|
36
36
|
const REPO_ROOT = resolve(__dirname, "..");
|
|
37
37
|
const BIN_DIR = join(REPO_ROOT, "bin");
|
|
38
38
|
|
|
@@ -57,15 +57,15 @@ function pickAssetName(platform, arch, isMusl) {
|
|
|
57
57
|
if (!a) return null;
|
|
58
58
|
// Release ships glibc variant by default. If user is on musl/alpine,
|
|
59
59
|
// try musl fallback (may 404 on releases that don't have it).
|
|
60
|
-
return isMusl ? [`
|
|
60
|
+
return isMusl ? [`snsagent-linux-${a}-musl`, `snsagent-linux-${a}`] : [`snsagent-linux-${a}`];
|
|
61
61
|
}
|
|
62
62
|
if (platform === "darwin") {
|
|
63
63
|
const a = x(arch);
|
|
64
64
|
if (!a) return null;
|
|
65
|
-
return [`
|
|
65
|
+
return [`snsagent-darwin-${a}`];
|
|
66
66
|
}
|
|
67
67
|
if (platform === "win32") {
|
|
68
|
-
return arch === "x64" ? [`
|
|
68
|
+
return arch === "x64" ? [`snsagent-windows-x64.exe`] : null;
|
|
69
69
|
}
|
|
70
70
|
return null;
|
|
71
71
|
}
|
|
@@ -179,7 +179,7 @@ async function main() {
|
|
|
179
179
|
return;
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
-
const tmp = await mkdtemp(join(tmpdir(), "
|
|
182
|
+
const tmp = await mkdtemp(join(tmpdir(), "snsagent-"));
|
|
183
183
|
const tmpFile = join(tmp, asset.name);
|
|
184
184
|
info(`downloading ${asset.name} (${(asset.size / 1024 / 1024).toFixed(2)} MB)`);
|
|
185
185
|
|
|
@@ -216,11 +216,9 @@ async function main() {
|
|
|
216
216
|
await chmod(target, 0o755);
|
|
217
217
|
}
|
|
218
218
|
|
|
219
|
-
//
|
|
220
|
-
//
|
|
221
|
-
|
|
222
|
-
// we create a wrapper file bin/snscoder.js that exec's the platform binary.
|
|
223
|
-
const shim = isWin ? "snscoder.cmd" : "snscoder.js";
|
|
219
|
+
// Shim file (referenced by package.json "bin"): bin/snsagent.js
|
|
220
|
+
// It execs the platform-specific binary that postinstall downloaded.
|
|
221
|
+
const shim = isWin ? "snsagent.cmd" : "snsagent.js";
|
|
224
222
|
const shimPath = join(BIN_DIR, shim);
|
|
225
223
|
|
|
226
224
|
if (isWin) {
|
|
@@ -244,5 +242,5 @@ async function main() {
|
|
|
244
242
|
|
|
245
243
|
main().catch((e) => {
|
|
246
244
|
err(`unexpected: ${e?.stack ?? e?.message ?? e}`);
|
|
247
|
-
process.exit(
|
|
245
|
+
process.exit(1); // hard-fail so user knows postinstall broke
|
|
248
246
|
});
|
package/scripts/smoke-test.sh
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
set -uo pipefail
|
|
11
11
|
|
|
12
|
-
BIN="${1:-./bin/
|
|
12
|
+
BIN="${1:-./bin/snsagent-linux-x64}"
|
|
13
13
|
FAIL=0
|
|
14
14
|
PASS=0
|
|
15
15
|
|
|
@@ -62,8 +62,8 @@ fi
|
|
|
62
62
|
|
|
63
63
|
# Version: pi_natives may be missing on CI runner → JS-only fallback may exit 1
|
|
64
64
|
# but version text still prints. Check substring rather than exit code.
|
|
65
|
-
run_loose "version flag prints version" "
|
|
66
|
-
run_loose "version subcommand prints version" "
|
|
65
|
+
run_loose "version flag prints version" "snsagent " --version
|
|
66
|
+
run_loose "version subcommand prints version" "snsagent " version
|
|
67
67
|
|
|
68
68
|
# Help: help uses only built-in code, should exit 0 reliably
|
|
69
69
|
run_check "help flag" 0 --help
|
package/src/cli/index.ts
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
* SNS-MyAgent Phase 2A CLI — minimal router.
|
|
3
3
|
*
|
|
4
4
|
* Commands:
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
5
|
+
* snsagent version print package version
|
|
6
|
+
* snsagent init create .sns-myagent/config.json with defaults
|
|
7
|
+
* snsagent chat [--stub] start interactive chat (stub for Phase 2B)
|
|
8
|
+
* snsagent config [show|get k|set k v] show / read / write config values
|
|
9
|
+
* snsagent help this help
|
|
10
10
|
*
|
|
11
11
|
* No external parser — manual argv handling, zero new deps.
|
|
12
12
|
*/
|
|
@@ -57,7 +57,7 @@ export const PKG_VERSION = readPackageVersion();
|
|
|
57
57
|
// ---------- command handlers ----------
|
|
58
58
|
|
|
59
59
|
function cmdVersion(): number {
|
|
60
|
-
process.stdout.write(`
|
|
60
|
+
process.stdout.write(`snsagent ${PKG_VERSION}\n`);
|
|
61
61
|
return 0;
|
|
62
62
|
}
|
|
63
63
|
|
|
@@ -143,7 +143,7 @@ function cmdConfigSet(cfg: Config, key: string, valueRaw: string): number {
|
|
|
143
143
|
function cmdConfig(args: string[]): number {
|
|
144
144
|
const cfg = loadConfig();
|
|
145
145
|
if (!cfg) {
|
|
146
|
-
process.stderr.write("✗ no config found, run `
|
|
146
|
+
process.stderr.write("✗ no config found, run `snsagent init` first\n");
|
|
147
147
|
return 1;
|
|
148
148
|
}
|
|
149
149
|
const sub = args[0];
|
|
@@ -153,7 +153,7 @@ function cmdConfig(args: string[]): number {
|
|
|
153
153
|
if (sub === "get") {
|
|
154
154
|
const key = args[1];
|
|
155
155
|
if (!key) {
|
|
156
|
-
process.stderr.write("✗ usage:
|
|
156
|
+
process.stderr.write("✗ usage: snsagent config get <key>\n");
|
|
157
157
|
return 1;
|
|
158
158
|
}
|
|
159
159
|
return cmdConfigGet(cfg, key);
|
|
@@ -162,7 +162,7 @@ function cmdConfig(args: string[]): number {
|
|
|
162
162
|
const key = args[1];
|
|
163
163
|
const value = args[2];
|
|
164
164
|
if (!key || value === undefined) {
|
|
165
|
-
process.stderr.write("✗ usage:
|
|
165
|
+
process.stderr.write("✗ usage: snsagent config set <key> <value>\n");
|
|
166
166
|
return 1;
|
|
167
167
|
}
|
|
168
168
|
return cmdConfigSet(cfg, key, value);
|
|
@@ -195,7 +195,7 @@ async function cmdTelegram(args: string[]): Promise<number> {
|
|
|
195
195
|
if (sub === "status") {
|
|
196
196
|
const cfg = loadConfig();
|
|
197
197
|
if (!cfg) {
|
|
198
|
-
process.stderr.write("✗ no config found, run `
|
|
198
|
+
process.stderr.write("✗ no config found, run `snsagent init` first\n");
|
|
199
199
|
return 1;
|
|
200
200
|
}
|
|
201
201
|
const envToken = process.env.SNS_TELEGRAM_BOT_TOKEN;
|
|
@@ -220,7 +220,7 @@ async function cmdTelegram(args: string[]): Promise<number> {
|
|
|
220
220
|
);
|
|
221
221
|
return 2;
|
|
222
222
|
}
|
|
223
|
-
process.stdout.write(`
|
|
223
|
+
process.stdout.write(`snsagent telegram: starting polling bot...\n`);
|
|
224
224
|
// Probe the token first so a bogus token exits cleanly with a
|
|
225
225
|
// readable error instead of triggering an UnhandledRejection
|
|
226
226
|
// from grammY's internal polling loop.
|
|
@@ -266,7 +266,7 @@ function parseTelegramOpts(args: string[]): TelegramOptions {
|
|
|
266
266
|
return { token: parseFlag(args, "token") };
|
|
267
267
|
}
|
|
268
268
|
|
|
269
|
-
const TG_HELP = `Usage:
|
|
269
|
+
const TG_HELP = `Usage: snsagent telegram <subcommand>
|
|
270
270
|
|
|
271
271
|
Subcommands:
|
|
272
272
|
start [--token <TOKEN>] start the polling bot (token: flag > env > config)
|
|
@@ -333,7 +333,7 @@ function setByPath(obj: Record<string, unknown>, path: string, value: unknown):
|
|
|
333
333
|
|
|
334
334
|
// ---------- router ----------
|
|
335
335
|
|
|
336
|
-
const HELP = `Usage:
|
|
336
|
+
const HELP = `Usage: snsagent [command] [options]
|
|
337
337
|
|
|
338
338
|
If no command is given, starts the full agent interactive mode.
|
|
339
339
|
|
|
@@ -358,7 +358,7 @@ export async function runCliAsync(argv: string[]): Promise<number> {
|
|
|
358
358
|
case undefined:
|
|
359
359
|
case "agent":
|
|
360
360
|
case "launch":
|
|
361
|
-
// No-arg `
|
|
361
|
+
// No-arg `snsagent` (or explicit `agent`/`launch`) → start full agent mode.
|
|
362
362
|
return cmdLaunch(rest);
|
|
363
363
|
case "help":
|
|
364
364
|
case "--help":
|
|
@@ -391,7 +391,7 @@ export async function runCliAsync(argv: string[]): Promise<number> {
|
|
|
391
391
|
async function cmdOrchestrate(args: string[]): Promise<number> {
|
|
392
392
|
if (args.length === 0) {
|
|
393
393
|
process.stderr.write("✗ orchestrate requires a prompt\n");
|
|
394
|
-
process.stderr.write(" usage:
|
|
394
|
+
process.stderr.write(" usage: snsagent orchestrate <prompt>\n");
|
|
395
395
|
process.stderr.write(" flags: --strategy consensus|critic|best_of_n\n");
|
|
396
396
|
process.stderr.write(" --agents role1,role2\n");
|
|
397
397
|
process.stderr.write(" --ensemble <name> (from agents.yaml)\n");
|
package/bin/snscoder.js
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// Auto-generated by fetch-binary.mjs — execs the platform binary.
|
|
3
|
-
import { spawn } from "node:child_process";
|
|
4
|
-
import { fileURLToPath } from "node:url";
|
|
5
|
-
import { dirname, join } from "node:path";
|
|
6
|
-
const here = dirname(fileURLToPath(import.meta.url));
|
|
7
|
-
const bin = join(here, "snscoder-linux-x64");
|
|
8
|
-
const r = spawn(bin, process.argv.slice(2), { stdio: "inherit" });
|
|
9
|
-
r.on("exit", (c) => process.exit(c ?? 0));
|