@bysking/b-code 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.mjs +2 -2
  2. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -281,7 +281,7 @@ ${d}`}if(t.kind==="tabs"||t.kind==="grouped"){let c=Array.isArray(t.groups)?t.gr
281
281
 
282
282
  # Available Skills
283
283
  ${t.map(n=>`- /${n.name}: ${n.description}`).join(`
284
- `)}`}var O3=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"];var J3="\r\x1B[K",zI=class{constructor(t=process.stderr,r=!!process.stderr.isTTY){this.stream=t;this.enabled=r}timer=null;frame=0;msg="";active=!1;startedAt=0;start(t){this.msg=t,this.enabled&&(this.stop(),this.active=!0,this.frame=0,this.startedAt=Date.now(),this.render(),this.timer=setInterval(()=>{this.frame++,this.render()},80))}update(t){this.msg=t}stop(){!this.enabled||!this.active||(this.active=!1,this.timer&&(clearInterval(this.timer),this.timer=null),this.stream.write(J3))}render(){let t=Math.max(0,Math.floor((Date.now()-this.startedAt)/1e3)),r=this.startedAt&&t>0?` (${t}s)`:"";this.stream.write(`${J3}${O3[this.frame%O3.length]} ${this.msg}${r}`)}};function Y3(e,t,r){let n=0;for(let i of e)n+=SI(i.text??"");for(let i of t)n+=SI(`${i.name} ${i.description??""} ${JSON.stringify(i.input_schema??{})}`);for(let i of r)n+=SI(typeof i.content=="string"?i.content:JSON.stringify(i.content));return n}var mp=class{messages=[];model=vI();mode="default";call;print;spinner;askUser;events;allowlist=new Set;registry=new UI;ctx;mcpLoaded=!1;constructor(t={}){this.call=t.callModel??a3,this.print=t.print??(r=>process.stdout.write(r)),this.spinner=t.spinner??new zI,this.askUser=t.askUser??(async()=>!1),this.events=t.events,this.mode=t.mode??"default",this.ctx={callModel:this.call,model:this.model,setMode:r=>this.setMode(r),askUser:t.askChoice??(async(r,n)=>n[0]?.value??"no"),askUserText:t.askTextInput??(async()=>null),askGrouped:t.askGroupedInput??(async(r,n)=>`${n[0]?.title??""} / ${n[0]?.options[0]?.label??""}`),askWizard:t.askWizardInput??(async()=>"__cancel__"),fileStore:new Zf},h3(this.registry),U3(this.registry),M3(this.registry),p3(this.registry,{plansDir:BA.plansDir(),runSubAgent:(r,n)=>dS(r,this.ctx,this.registry,n)}),this.registry.register({name:"agent",description:"Fork a sub-agent to investigate a task read-only and return a concise summary. Use for parallelizable exploration.",inputSchema:{type:"object",properties:{task:{type:"string",description:"The sub-task to investigate"}},required:["task"]},mode:"read",kind:"subagent",handler:r=>dS(String(r.task??""),this.ctx,this.registry)})}async initMcp(t=process.cwd()){this.mcpLoaded||(this.mcpLoaded=!0,await B3(this.registry,t))}setMode(t){this.mode=t}interrupted=!1;lastInterrupted=!1;interrupt(){this.interrupted=!0}get interruptedByUser(){return this.lastInterrupted}transcriptText(){return S3(this.messages)}async pursueGoal(t,r,n=5){await this.chat(r);for(let i=0;i<n;i++){let s=await this.evaluateGoal(t);if(s.met){Nn.info(`\u2713 goal met: ${t}`);return}if(s.impossible){Nn.warn(`goal impossible: ${s.reason}`);return}Nn.info(`(goal not met \u2014 ${s.reason}; continuing)`),await this.chat(`The goal "${t}" is not met yet: ${s.reason}. Keep working toward it.`)}Nn.warn(`(gave up after ${n} iterations without meeting: ${t})`)}async evaluateGoal(t){return b3(t,this.transcriptText(),this.model,this.call)}async classify(t,r){return _3(t,r,this.transcriptText(),this.model,this.call)}history(){return this.messages}loadHistory(t){this.messages=t}clearHistory(){this.messages=[]}async chat(t){this.lastInterrupted=!1,this.messages.push({role:"user",content:t});let r=X8({memory:T3(t),skills:H3()});for(;;){if(this.interrupted){this.interrupted=!1,this.lastInterrupted=!0,this.events?.({type:"stream_end"});break}let n=this.registry.toolsSchema(this.mode==="plan"),i=Y3(r,n,this.messages);i>Q3()&&(this.messages=await this.compactIfNeeded(),i=Y3(r,n,this.messages)),this.spinner.start("thinking\u2026"),this.events?.({type:"busy_think"}),this.events?.({type:"busy_tokens",input_tokens:i});let s=await this.call({model:this.model,system:r,tools:n,messages:this.messages,onText:E=>this.print(E),onThinking:E=>this.events?.({type:"thinking",text:E})});s.usage&&(this.events?.({type:"usage",usage:s.usage}),this.events?.({type:"busy_tokens",input_tokens:s.usage.input_tokens})),this.spinner.stop(),this.events?.({type:"stream_end"}),this.messages.push({role:"assistant",content:s.content});let A=s.content.filter(E=>E.type==="tool_use");if(A.length===0){this.interrupted&&(this.interrupted=!1,this.lastInterrupted=!0,this.events?.({type:"stream_end"}));break}this.events?.({type:"tools_planned",tools:A.map(E=>({id:E.id,name:E.name,input:E.input}))});let c=[],u=[];for(let E of A){let f=this.registry.resolve(E.name),g=E.input??{};(f?.mode==="read"?c:u).push({tu:E,mp:f,input:g})}let d=new Map,p=async(E,f,g)=>{if(this.print(` \u2192 ${E.name}(${JSON.stringify(E.input)})
284
+ `)}`}var O3=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"];var J3="\r\x1B[K",zI=class{constructor(t=process.stderr,r=!!process.stderr.isTTY){this.stream=t;this.enabled=r}timer=null;frame=0;msg="";active=!1;startedAt=0;start(t){this.msg=t,this.enabled&&(this.stop(),this.active=!0,this.frame=0,this.startedAt=Date.now(),this.render(),this.timer=setInterval(()=>{this.frame++,this.render()},80))}update(t){this.msg=t}stop(){!this.enabled||!this.active||(this.active=!1,this.timer&&(clearInterval(this.timer),this.timer=null),this.stream.write(J3))}render(){let t=Math.max(0,Math.floor((Date.now()-this.startedAt)/1e3)),r=this.startedAt&&t>0?` (${t}s)`:"";this.stream.write(`${J3}${O3[this.frame%O3.length]} ${this.msg}${r}`)}};function Y3(e,t,r){let n=0;for(let i of e)n+=SI(i.text??"");for(let i of t)n+=SI(`${i.name} ${i.description??""} ${JSON.stringify(i.input_schema??{})}`);for(let i of r)n+=SI(typeof i.content=="string"?i.content:JSON.stringify(i.content));return n}var mp=class{messages=[];model=vI();mode="default";call;print;spinner;askUser;events;allowlist=new Set;registry=new UI;ctx;mcpLoaded=!1;constructor(t={}){this.call=t.callModel??a3,this.print=t.print??(r=>process.stdout.write(r)),this.spinner=t.spinner??new zI,this.askUser=t.askUser??(async()=>!1),this.events=t.events,this.mode=t.mode??"default",this.ctx={callModel:this.call,model:this.model,setMode:r=>this.setMode(r),askUser:t.askChoice??(async(r,n)=>n[0]?.value??"no"),askUserText:t.askTextInput??(async()=>null),askGrouped:t.askGroupedInput??(async(r,n)=>`${n[0]?.title??""} / ${n[0]?.options[0]?.label??""}`),askWizard:t.askWizardInput??(async()=>"__cancel__"),fileStore:new Zf},h3(this.registry),U3(this.registry),M3(this.registry),p3(this.registry,{plansDir:BA.plansDir(),runSubAgent:(r,n)=>dS(r,this.ctx,this.registry,n)}),this.registry.register({name:"agent",description:"Fork a sub-agent to investigate a task read-only and return a concise summary. Use for parallelizable exploration.",inputSchema:{type:"object",properties:{task:{type:"string",description:"The sub-task to investigate"}},required:["task"]},mode:"read",kind:"subagent",handler:r=>dS(String(r.task??""),this.ctx,this.registry)})}async initMcp(t=process.cwd()){this.mcpLoaded||(this.mcpLoaded=!0,await B3(this.registry,t))}setMode(t){this.mode=t}interrupted=!1;lastInterrupted=!1;interrupt(){this.interrupted=!0}get interruptedByUser(){return this.lastInterrupted}transcriptText(){return S3(this.messages)}async pursueGoal(t,r,n=5){await this.chat(r);for(let i=0;i<n;i++){let s=await this.evaluateGoal(t);if(s.met){Nn.info(`\u2713 goal met: ${t}`);return}if(s.impossible){Nn.warn(`goal impossible: ${s.reason}`);return}Nn.info(`(goal not met \u2014 ${s.reason}; continuing)`),await this.chat(`The goal "${t}" is not met yet: ${s.reason}. Keep working toward it.`)}Nn.warn(`(gave up after ${n} iterations without meeting: ${t})`)}async evaluateGoal(t){return b3(t,this.transcriptText(),this.model,this.call)}async classify(t,r){return _3(t,r,this.transcriptText(),this.model,this.call)}history(){return this.messages}loadHistory(t){this.messages=t}clearHistory(){this.messages=[]}async chat(t){this.lastInterrupted=!1,this.messages.push({role:"user",content:t});let r=X8({memory:T3(t),skills:H3()});for(;;){if(this.interrupted){this.interrupted=!1,this.lastInterrupted=!0,this.events?.({type:"stream_end"});break}let n=this.registry.toolsSchema(this.mode==="plan"),i=Y3(r,n,this.messages);i>Q3()&&(this.messages=await this.compactIfNeeded(),i=Y3(r,n,this.messages)),this.spinner.start("thinking\u2026"),this.events?.({type:"busy_think"}),this.events?.({type:"busy_tokens",input_tokens:i});let s;try{s=await this.call({model:this.model,system:r,tools:n,messages:this.messages,onText:E=>this.print(E),onThinking:E=>this.events?.({type:"thinking",text:E})})}catch(E){throw this.spinner.stop(),this.events?.({type:"stream_end"}),E}s.usage&&(this.events?.({type:"usage",usage:s.usage}),this.events?.({type:"busy_tokens",input_tokens:s.usage.input_tokens})),this.spinner.stop(),this.events?.({type:"stream_end"}),this.messages.push({role:"assistant",content:s.content});let A=s.content.filter(E=>E.type==="tool_use");if(A.length===0){this.interrupted&&(this.interrupted=!1,this.lastInterrupted=!0,this.events?.({type:"stream_end"}));break}this.events?.({type:"tools_planned",tools:A.map(E=>({id:E.id,name:E.name,input:E.input}))});let c=[],u=[];for(let E of A){let f=this.registry.resolve(E.name),g=E.input??{};(f?.mode==="read"?c:u).push({tu:E,mp:f,input:g})}let d=new Map,p=async(E,f,g)=>{if(this.print(` \u2192 ${E.name}(${JSON.stringify(E.input)})
285
285
  `),!f){d.set(E.id,`Unknown tool: ${E.name}`);return}let m=await v3(f,g,{mode:this.mode,allowlist:this.allowlist,classify:(B,Q)=>this.classify(B,Q),askUser:B=>(this.spinner.stop(),this.askUser(B))});if(!m.allow){d.set(E.id,m.reason??"Denied");return}m.remember&&this.allowlist.add(CS(f,g)),d.set(E.id,await this.execTool(E.id,f,g))};await Promise.all(c.map(E=>p(E.tu,E.mp,E.input)));for(let E of u)await p(E.tu,E.mp,E.input);let C=A.map(E=>({type:"tool_result",tool_use_id:E.id,content:d.get(E.id)??"(missing output)"}));this.messages.push({role:"user",content:C})}}activeTools=0;async execTool(t,r,n){this.activeTools++,this.activeTools===1&&this.spinner.start(`running ${r.name}\u2026`),this.events?.({type:"tool_start",id:t,name:r.name,input:n});let i=this.ctx.onToolOutput;this.ctx.onToolOutput=A=>this.print(` \u2937 ${A}`);let s;try{let A=await r.handler(n,this.ctx);return s=A==null||String(A).trim()===""?"(empty output)":String(A),y3(s)}catch(A){return s=`Error: ${r.name} failed: ${A.message}`,s}finally{this.ctx.onToolOutput=i,this.activeTools--,this.activeTools===0&&this.spinner.stop(),this.events?.({type:"tool_end",id:t,name:r.name,output:s})}}async compactIfNeeded(){return D3(this.messages,async t=>{let r=w3(t,this.ctx.fileStore),i=(await this.call({model:this.model,system:[{type:"text",text:"Summarize the conversation so far in a few sentences, keeping key facts."}],tools:[],messages:[{role:"user",content:r}]})).content.filter(A=>A.type==="text").map(A=>A.text).join(""),s=this.ctx.fileStore?k3(this.ctx.fileStore):"";return Nn.info(`(compacted ${t.length} messages into a summary)`),i+s},!0)}};import{existsSync as Hue}from"node:fs";import{mkdir as Oue,readFile as P3,rm as HI,writeFile as q3}from"node:fs/promises";import{join as JI}from"node:path";function Cp(e){return String(e).padStart(2,"0")}function QS(){let e=new Date,t=Math.floor(Math.random()*36**2).toString(36).padStart(2,"0");return`${e.getFullYear()}${Cp(e.getMonth()+1)}${Cp(e.getDate())}-${Cp(e.getHours())}${Cp(e.getMinutes())}${Cp(e.getSeconds())}-${t}`}function wS(){return JI(un(),"sessions")}function Bp(e){return JI(wS(),`${e}.json`)}function OI(){return JI(wS(),"current.txt")}function yS(){return JI(un(),"session.json")}async function IA(e,t){try{await Oue(wS(),{recursive:!0}),await q3(Bp(t),JSON.stringify(e,null,2),"utf-8"),await q3(OI(),t,"utf-8")}catch(r){Nn.warn(`session save failed: ${t}`,r.message)}}async function Ip(e){if(e)return IS(Bp(e));let t=await W3(OI());if(t){let r=await IS(Bp(t.trim()));if(r)return r}if(Hue(yS())){let r=await IS(yS());if(r){let n=QS();return await IA(r,n),r}}return null}async function kS(e){try{if(e){await HI(Bp(e),{force:!0});return}await HI(yS(),{force:!0});let t=await W3(OI());t&&await HI(Bp(t.trim()),{force:!0}),await HI(OI(),{force:!0})}catch(t){Nn.warn("session clear failed",t.message)}}function DS(e,t=5){let r=[];e.forEach((A,c)=>{A.role==="user"&&typeof A.content=="string"&&r.push(c)});let n=r.slice(-t);if(n.length===0)return[];let i=n[0]??0,s=[];for(let A=i;A<e.length;A++){let c=e[A];if(c.role==="user")typeof c.content=="string"&&s.push({role:"user",text:c.content,tools:[]});else if(c.role==="assistant"){let u=[],d=[];for(let p of Array.isArray(c.content)?c.content:[])p.type==="text"&&p.text?u.push(p.text):p.type==="tool_use"&&d.push(p.name);s.push({role:"assistant",text:u.join(""),tools:d})}}return s}function V3(e){if(e.length===0)return"";let t=e.filter(n=>n.role==="user").length,r=e.map(n=>{let i=n.role==="user"?"user":"bcode",s=n.tools.length?` [tools: ${n.tools.join(", ")}]`:"",c=n.text.trim().replace(/\s*\n+/g," ").slice(0,160)||"(no text)";return`${i}:${s} ${c}`});return`\u2500\u2500 \u6700\u8FD1 ${t} \u8F6E\u5BF9\u8BDD \u2500\u2500
286
286
  ${r.join(`
287
287
  `)}
@@ -407,7 +407,7 @@ ${n.trim()}
407
407
 
408
408
  `),await i.initMcp(),r.setSlashItems([...NV,...Ep().filter(f=>f.userInvocable).map(f=>({name:f.name,description:f.description}))]);let s=[],A=await(e.session?Ip(e.session):e.resume?Ip():null);if(A&&A.length>0){i.loadHistory(A);let f=DS(A);r.loadTurns(f.map(m=>({role:m.role,text:m.text,tools:m.tools.map((B,Q)=>({id:`r-${Q}`,name:B,input:"",status:"done"})),streaming:!1})));let g=f.filter(m=>m.role==="user").length;s.push(`(resumed ${A.length} messages \xB7 \u6700\u8FD1 ${g} \u8F6E)`)}else(e.resume||e.session)&&s.push("(no session to resume)");e.plan&&s.push("(plan mode: read-only)"),e.auto&&s.push("(auto mode: classifier gates write/shell)"),e.goal&&s.push(`(pursuing goal: ${e.goal})`),e.loop>0&&e.instruction&&s.push(`(loop every ${e.loop}s; Ctrl-C to stop)`);let c=!!e.instruction&&!e.goal&&e.loop<=0,u=!1,d=f=>{XV(t),p?.(),Zl(),process.exit(f)},p=null,{unmount:C}=VV(r,{onExit:()=>d(130),onInterrupt:()=>i.interrupt(),onSubmit:f=>void E(f),onSetMode:f=>{i.setMode(f),r.pushOutput(`(mode \u2192 ${f})`)}},s);p=C;async function E(f){if(!u){u=!0;try{let g=f.trim();if(g==="exit"||g==="quit"){d(0);return}if(g==="/clear"){i.clearHistory(),n=!1,await kS(),r.clearAll(),r.pushOutput("(history cleared)");return}if(g==="/plan"||g==="/yolo"||g==="/default"||g==="/auto"){let B=g.slice(1);i.setMode(B),r.setMode(B),r.pushOutput(`(mode \u2192 ${B})`);return}if(g==="/skills"){let B=Ep().filter(Q=>Q.userInvocable).map(Q=>`/${Q.name}: ${Q.description}`).join(`
409
409
  `);r.pushOutput(B?`Available skills:
410
- ${B}`:"(no skills)");return}if(g==="/mcp"){r.pushOutput(pS(gp(),B=>jV(i.registry,B)));return}if(g.startsWith("/remember ")){let B=g.slice(10).trim(),Q=B.split(/\W+/).filter(Boolean).slice(0,4).join("_").toLowerCase()||"fact";LI(Q,B,"reference",B),r.pushOutput(`(saved to memory: ${Q})`);return}let m=GI(g)??g;if(r.pushUser(g),e.goal){await i.pursueGoal(e.goal,m||"Continue working toward the goal."),await IA(i.history(),t),d(0);return}await i.chat(m),await IA(i.history(),t),i.interruptedByUser&&r.pushOutput("(interrupted \u2014 \u53EF\u4EE5\u8F93\u5165\u65B0\u6307\u4EE4\u6216\u7EE7\u7EED)"),e.loop>0?setTimeout(()=>void E(e.instruction??""),e.loop*1e3):c&&d(0)}finally{u=!1}}}(e.instruction||e.goal)&&await E(e.instruction||"Continue working toward the goal.")}function XV(e){process.stdout.write(`
410
+ ${B}`:"(no skills)");return}if(g==="/mcp"){r.pushOutput(pS(gp(),B=>jV(i.registry,B)));return}if(g.startsWith("/remember ")){let B=g.slice(10).trim(),Q=B.split(/\W+/).filter(Boolean).slice(0,4).join("_").toLowerCase()||"fact";LI(Q,B,"reference",B),r.pushOutput(`(saved to memory: ${Q})`);return}let m=GI(g)??g;if(r.pushUser(g),e.goal){await i.pursueGoal(e.goal,m||"Continue working toward the goal."),await IA(i.history(),t),d(0);return}await i.chat(m),await IA(i.history(),t),i.interruptedByUser&&r.pushOutput("(interrupted \u2014 \u53EF\u4EE5\u8F93\u5165\u65B0\u6307\u4EE4\u6216\u7EE7\u7EED)"),e.loop>0?setTimeout(()=>void E(e.instruction??""),e.loop*1e3):c&&d(0)}catch(g){let m=g instanceof Error?g.message:String(g);r.pushOutput(`(error: ${m})`)}finally{u=!1}}}(e.instruction||e.goal)&&await E(e.instruction||"Continue working toward the goal.")}function XV(e){process.stdout.write(`
411
411
  \u60F3\u6062\u590D\u672C\u6B21\u4F1A\u8BDD\uFF0C\u6267\u884C:
412
412
  bcode --resume --session ${e}
413
413
  `)}async function ZV(e=process.argv.slice(2)){let{resume:t,plan:r,yolo:n,auto:i,goal:s,loop:A,session:c,instruction:u}=TIe(e),d=!u&&!s&&!(A>0),p=QS();if(process.stdout.isTTY&&process.stdin.isTTY){await zIe({resume:t,plan:r,yolo:n,auto:i,goal:s,loop:A,session:c,instruction:u},p);return}let C=null,E=null,f=!1,g=!1,m=W=>{if(!E)return!1;let Z=E;return E=null,Z(/^y(es)?$/i.test(W.trim())),!0},B=()=>{XV(p),process.exit(0)},Q=()=>C,w=W=>{process.stdout.write(`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bysking/b-code",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "从零构建的编码助手 — 你自己的 B-Code,运行在终端里",
5
5
  "type": "module",
6
6
  "main": "dist/cli.mjs",