@wular/coder 0.1.9 → 0.1.12

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.
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "coder",
2
+ "name": "coder-plugins",
3
3
  "interface": {
4
4
  "displayName": "Coder"
5
5
  },
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "coder",
2
+ "name": "coder-plugins",
3
3
  "owner": {
4
4
  "name": "muzam1l"
5
5
  },
package/README.md CHANGED
@@ -25,7 +25,7 @@ Plugs into Claude Code or Codex to enable the harness with Coder instances.
25
25
  ```
26
26
  /plugin marketplace add muzam1l/coder
27
27
 
28
- /plugin install coder@coder
28
+ /plugin install coder@coder-plugins
29
29
 
30
30
  /reload-plugins
31
31
 
@@ -53,7 +53,7 @@ The work happens in the engine, and your session gets the result. Codex is the p
53
53
 
54
54
  ```
55
55
  codex plugin marketplace add muzam1l/coder
56
- codex plugin add coder@coder
56
+ codex plugin add coder@coder-plugins
57
57
  ```
58
58
 
59
59
  Or from the npm directly:
package/dist/cli.js CHANGED
@@ -86,7 +86,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
86
86
  `)}}function Vb(r,i){let v=r.agent;if(!v&&r.model){if(r.model in J6)v="claude";else if(r.model in $$)v="codex"}if(v=v??i.chain[0]??"codex",v!=="codex"&&v!=="claude"){let g=v in $$||v in J6?` "${v}" is a model; use --model ${v}.`:"";M(`Invalid --agent "${v}". Use codex or claude.${g}`)}let u=i.agents[v]??{},n=r.model??u.model??null,$=r.effort??u.effort??null,t=r.permissions??u.permissions??"auto";if(!(t in jn))M(`Invalid --permissions "${t}". Use one of: ${Object.keys(jn).join(", ")}`);if(v==="codex"&&$&&!S6.has($))M(`Invalid codex --effort "${$}". Use one of: ${[...S6].join(", ")}`);if(v==="claude"&&$&&!P6.has($))M(`Invalid claude --effort "${$}". Use one of: ${[...P6].join(", ")}`);return{agent:v,model:n,effort:$,permissions:t}}function SU(r,i,v,u=null){let n=r.agents.claude??{};return{agent:"claude",action:"spawn-claude-subagent",reason:v,model:n.model??"opus",permissions:u??n.permissions??"auto",note:"Spawn a general-purpose subagent with this model and forward the task verbatim.",task:i}}async function Xb(r,i,{echo:v}){let u=fr(r),n=ir(r,i.id),$=mr(r),t=PU(r,i.id,{echo:v}),g=jn[i.permissions]??jn.auto,I=g.approvalPolicy==="never"?void 0:bU({workspaceRoot:u,jobDir:n,mode:g.approvalMode,escalationTimeoutMs:$.approvals.escalationTimeoutMs,allowedNetworkHosts:$.approvals.allowedNetworkHosts,onEvent:(_)=>{if(Yn(r,i.id,_),v&&_.message)W.stderr.write(`[coder] ${_.message}
87
87
  `)}}),o=await rI(r,{prompt:i.prompt,model:IU(i.model),effort:i.effort,sandbox:g.sandbox,approvalPolicy:g.approvalPolicy,onApprovalRequest:I,resumeThreadId:i.resumeThreadId??null,onProgress:(_)=>{t(_);let b=typeof _==="object"?_.threadId:null,k=typeof _==="object"?_.turnId:null;if(b||k)ur(r,i.id,{status:"running",...b?{threadId:b}:{},...k?{turnId:k}:{}})}}),l=o.status===0?"completed":"failed";return ur(r,i.id,{status:l,threadId:o.threadId,turnId:o.turnId,completedAt:new Date().toISOString()}),C.writeFileSync(x.join(n,"result.json"),`${JSON.stringify(o,null,2)}
88
88
  `,"utf8"),o}async function jb(r,i,{echo:v}){let u=ir(r,i.id),n=PU(r,i.id,{echo:v}),$=await UU(r,{prompt:i.prompt,model:i.model,effort:i.effort,permissions:i.permissions,resumeSessionId:i.resumeThreadId??null,onProgress:(t)=>{if(n(t),t.threadId)ur(r,i.id,{status:"running",threadId:t.threadId})}});return ur(r,i.id,{status:$.status===0?"completed":"failed",threadId:$.threadId,completedAt:new Date().toISOString()}),C.writeFileSync(x.join(u,"result.json"),`${JSON.stringify($,null,2)}
89
- `,"utf8"),$}function WU(r){return r.agent==="claude"?jb:Xb}async function Y6(r){let{options:i,positionals:v}=nr(r,{valueOptions:["agent","model","effort","permissions","resume","cwd","host"],booleanOptions:["background","wait","json"]}),u=i.wait?!1:!0,n=i.cwd?x.resolve(i.cwd):W.cwd(),$=v.join(" ").trim();if(!$)M('Usage: coder task [options] "<task text>"');let t=mr(n),g=Vb(i,t),I=i.host??(W.env.CLAUDECODE?"claude":"codex");if(I!=="claude"&&I!=="codex")M(`Invalid --host "${I}". Use claude or codex.`);if(g.agent==="claude"&&I==="claude")f(SU(t,$,"configured",g.permissions)),W.exit(3);let o=async(N,S)=>{let G=t.chain[t.chain.indexOf(N)+1];if(!G)M(`${N} failed to start: ${S}`);if(G==="claude"&&I==="claude")f({error:`${N} failed to start: ${S}`,fallback:SU(t,$,"codex-failed",g.permissions)}),W.exit(3);W.stderr.write(`[coder] ${N} failed to start (${S}); falling back to ${G}.
89
+ `,"utf8"),$}function WU(r){return r.agent==="claude"?jb:Xb}async function Y6(r){let{options:i,positionals:v}=nr(r,{valueOptions:["agent","model","effort","permissions","resume","cwd","host"],booleanOptions:["background","wait","json"]}),u=i.wait?!1:!0,n=i.cwd?x.resolve(i.cwd):W.cwd(),$=v.join(" ").trim();if(!$)M('Usage: coder task [options] "<task text>"');let t=mr(n),g=Vb(i,t),I=i.host??(W.env.CLAUDECODE?"claude":"codex");if(I!=="claude"&&I!=="codex")M(`Invalid --host "${I}". Use claude or codex.`);if(g.agent==="claude"&&I==="claude")f(SU(t,$,"configured",g.permissions)),W.exit(0);let o=async(N,S)=>{let G=t.chain[t.chain.indexOf(N)+1];if(!G)M(`${N} failed to start: ${S}`);if(G==="claude"&&I==="claude")f({error:`${N} failed to start: ${S}`,fallback:SU(t,$,"codex-failed",g.permissions)}),W.exit(3);W.stderr.write(`[coder] ${N} failed to start (${S}); falling back to ${G}.
90
90
  `),await Y6([$,"--agent",G,"--host",I,"--cwd",n,...i.wait?["--wait"]:[],...i.json?["--json"]:[],...i.permissions?["--permissions",i.permissions]:[]]),W.exit(0)},l=(N)=>{let S="read-only unavailable on this host: the OS sandbox failed to start (Linux/WSL2 needs bubblewrap + socat). Re-dispatch with --permissions auto (or workspace-write) if writes are acceptable, or install the sandbox deps.";if(i.json)f({error:S,code:"read-only-unavailable",detail:N});else W.stderr.write(`[coder] ${S}
91
91
  `);W.exit(1)},_=(N)=>g.permissions==="read-only"&&tU.test(N??"");{let N=g.agent==="codex"?dr(n):u$();if(!N.available)await o(g.agent,N.detail)}let b=null;if(i.resume)b=o$(n,i.resume)?.threadId??i.resume;let k=H6(),P=ur(n,k,{status:"queued",kind:"task",agent:g.agent,host:I,prompt:$,model:g.model,effort:g.effort,permissions:g.permissions,resumeThreadId:b,cwd:n,background:u});if(u){let N=ir(n,k),S=C.openSync(x.join(N,"worker.log"),"a"),G=Gb(W.execPath,[K6,"_worker",k,"--cwd",n],{cwd:n,detached:!0,stdio:["ignore",S,S]});G.unref(),C.closeSync(S),ur(n,k,{pid:G.pid??null});let F=Date.now()+15000,q=P,j=null;while(Date.now()<(j??F)){if(q=Cr(n,k)??q,q.status==="failed"||q.status==="completed")break;if(q.threadId&&!j)j=Date.now()+5000;await new Promise((K)=>setTimeout(K,300))}if(q.status==="failed"){let K=x.join(ir(n,k),"result.json"),Nr=C.existsSync(K)?JSON.parse(C.readFileSync(K,"utf8")).error?.message??"":"",E=I$(n,k,5).map((XU)=>XU.message??"").join(`
92
92
  `),T=Nr||E;if(_(T))l(T);if(j6.test(T))await o(g.agent,T);f({jobId:k,status:"failed",detail:T}),W.exit(1)}f({jobId:k,status:q.status,threadId:q.threadId??null,startupCheck:q.threadId?"passed":"pending",commands:{status:`coder status ${k}`,result:`coder result ${k}`,steer:`coder steer ${k} "<follow-up>"`,stop:`coder stop ${k}`}});return}ur(n,k,{status:"running",pid:W.pid});try{let N=Cr(n,k),S=await WU(N)(n,N,{echo:!i.json}),G=S.error?.message??"";if(S.status!==0&&_(G))l(G);if(S.status!==0&&j6.test(G))await o(g.agent,G);if(i.json)f({jobId:k,status:S.status===0?"completed":"failed",threadId:S.threadId,finalMessage:S.finalMessage});else W.stdout.write(`${S.finalMessage||"(no final message)"}
@@ -96,7 +96,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
96
96
  `)}async function Qb(r){let{options:i,positionals:v}=nr(r,{valueOptions:["cwd","model","effort","permissions"],booleanOptions:["background","wait"]}),u=i.cwd?x.resolve(i.cwd):W.cwd(),[n,...$]=v,t=$.join(" ").trim();if(!n||!t)M('Usage: coder steer <job-id> "<follow-up instructions>" [--wait]');let g=Kn(u,n);if(!g.threadId)M(`Job ${g.id} has no thread to steer yet (status: ${g.status}).`);if(g.status==="running")M(`Job ${g.id} is still running. Stop it first (coder stop ${g.id}) or wait, then steer.`);let I=[t,"--resume",g.id,"--cwd",u,...g.agent?["--agent",g.agent]:[],...g.host&&g.host!=="claude"?["--host",g.host]:[],...i.model?["--model",i.model]:["--model",g.model].filter(()=>g.model),...i.effort?["--effort",i.effort]:g.effort?["--effort",g.effort]:[],...i.permissions?["--permissions",i.permissions]:g.permissions?["--permissions",g.permissions]:[],...i.wait?["--wait"]:[]];await Y6(I)}async function Hb(r){let{options:i,positionals:v}=nr(r,{valueOptions:["cwd"]}),u=i.cwd?x.resolve(i.cwd):W.cwd(),n=Kn(u,v[0]),$=n.agent==="claude"?{detail:"claude worker terminated"}:await s6(u,{threadId:n.threadId,turnId:n.turnId});if(n.pid&&n.status==="running")try{W.kill(n.pid,"SIGTERM")}catch{}ur(u,n.id,{status:"cancelled",completedAt:new Date().toISOString()}),f({jobId:n.id,status:"cancelled",interrupt:$.detail})}async function Ab(r){let{options:i}=nr(r,{valueOptions:["cwd"]}),v=i.cwd?x.resolve(i.cwd):W.cwd();f(g$(v).map((u)=>({jobId:u.id,status:u.status,agent:u.agent,threadId:u.threadId??null,prompt:String(u.prompt??"").slice(0,80),updatedAt:u.updatedAt})))}async function Eb(r){let{options:i,positionals:v}=nr(r,{valueOptions:["cwd"]}),u=i.cwd?x.resolve(i.cwd):W.cwd(),n=Kn(u,v[0]);f(V6(ir(u,n.id)).map(($)=>({id:$.id,summary:$.summary,createdAt:$.createdAt,answered:$.response?.decision??null})))}async function Bb(r){let{options:i,positionals:v}=nr(r,{valueOptions:["cwd"],booleanOptions:["deny"]}),u=i.cwd?x.resolve(i.cwd):W.cwd(),[n,$]=v;if(!n||!$)M("Usage: coder approve <job-id> <approval-id> [--deny]");let t=Kn(u,n);kU(ir(u,t.id),$,i.deny?"decline":"accept"),f({jobId:t.id,approvalId:$,decision:i.deny?"decline":"accept"})}async function Mb(r){let{options:i,positionals:v}=nr(r,{valueOptions:["cwd"],booleanOptions:["workspace"]}),u=i.cwd?x.resolve(i.cwd):W.cwd(),[n="list",$,...t]=v,g=i.workspace?x.join(fr(u),"coder.config.json"):zi(),I=(N,S)=>S.split(".").reduce((G,F)=>G==null?void 0:G[F],N);if(n==="list"){f(mr(u));return}if(n==="get"){if(!$)M("Usage: coder config get <key> (e.g. chain, agents.codex.model)");let N=I(mr(u),$);f(N===void 0?null:N);return}if(n!=="set"&&n!=="unset")M("Usage: coder config [get|set|unset] <key> [value] [--workspace]");if(!$||n==="set"&&t.length===0)M(`Usage: coder config ${n} <key>${n==="set"?" <value>":""}`);let o=t.join(" "),l;try{l=JSON.parse(o)}catch{l=o.includes(",")?o.split(",").map((N)=>N.trim()).filter(Boolean):o}let _=C.existsSync(g)?JSON.parse(C.readFileSync(g,"utf8")):{},b=$.split("."),k=_;for(let N of b.slice(0,-1)){if(typeof k[N]!=="object"||k[N]===null)k[N]={};k=k[N]}if(n==="set")k[b.at(-1)]=l;else delete k[b.at(-1)];let P=L6(_);if(P.length)M(`Refusing to write invalid config:
97
97
  ${P.join(`
98
98
  `)}`);C.mkdirSync(x.dirname(g),{recursive:!0}),C.writeFileSync(g,`${JSON.stringify(_,null,2)}
99
- `,"utf8"),f({file:g,key:$,...n==="set"?{value:l}:{unset:!0},effective:I(mr(u),$)??null})}function LU(){return t$(new URL("..",import.meta.url))}function GU(r){Yr("codex",["plugin","remove","coder@coder"],{encoding:"utf8"}),Yr("codex",["plugin","marketplace","remove","coder"],{encoding:"utf8"});let i=Yr("codex",["plugin","marketplace","add","."],{cwd:r,encoding:"utf8"}),v=Yr("codex",["plugin","add","coder@coder"],{encoding:"utf8"}),u=i.status===0&&v.status===0;return{marketplace:r,installed:u,note:u?"Plugin installed; restart any running codex session to load it.":`Automatic install failed (${(v.stderr||i.stderr||"codex not found").trim()}); run: codex plugin marketplace add "${r}" && codex plugin add coder@coder`}}function VU(r){Yr("claude",["plugin","marketplace","remove","coder"],{encoding:"utf8"});let i=Yr("claude",["plugin","marketplace","add",r],{encoding:"utf8"}),v=Yr("claude",["plugin","install","coder@coder"],{encoding:"utf8"}),u=i.status===0&&v.status===0;return{marketplace:r,installed:u,note:u?"Plugin installed; restart any running Claude Code session to load it.":`Automatic install failed (${(v.stderr||i.stderr||"claude not found").trim()}); run: claude plugin marketplace add "${r}" && claude plugin install coder@coder`}}async function Tb(r){let{options:i}=nr(r,{valueOptions:["cwd"],booleanOptions:["codex","claude","json"]}),v=i.cwd?x.resolve(i.cwd):W.cwd(),u=dr(v),n=u.available?await a6(v):{loggedIn:!1,detail:u.detail},$=u$(),t=zi();if(!C.existsSync(t)){let E=u.available?["codex","claude"]:$.available?["claude","codex"]:["codex","claude"];lU({...O6,chain:E})}let g=LU(),I=i.codex?GU(g):null,o=i.claude?VU(g):null,l=mr(v),_=u.available&&n.loggedIn;if(i.json){f({codex:{available:u.available,detail:u.detail,auth:n.detail,loggedIn:n.loggedIn},claude:{available:$.available,detail:$.detail},configFile:t,runtime:t$(new URL("../bin/coder.mjs",import.meta.url)),...I?{codexPlugin:I}:{},...o?{claudePlugin:o}:{},config:l,ready:_});return}let b=W.stdout.isTTY&&!W.env.NO_COLOR,k=(E,T)=>b?`\x1B[${E}m${T}\x1B[0m`:T,P=(E)=>` ${k("32","✔")} ${E}`,N=(E)=>` ${k("31","✘")} ${E}`,S=(E)=>k("1",E),G=(E)=>k("38;5;245",E),F=[S("Coder setup"),""],q=u.available?n.loggedIn?P(`codex ${G(`${u.detail}; ${n.detail}`)}`):N(`codex not logged in ${G(`(${n.detail})`)} - run: codex login`):N("codex not installed - run: npm install -g @openai/codex"),j=$.available?P(`claude ${G($.detail)}`):N("claude not installed - run: npm install -g @anthropic-ai/claude-code");F.push(S("Available Engines"),q,j,"");let K=(E)=>{let T=l.agents?.[E]??{};return[T.model,T.effort,T.permissions].filter(Boolean).join("/")};F.push(S("Config"),` chain: ${(l.chain??[]).join(" -> ")} codex: ${K("codex")} claude: ${K("claude")}`,` ${G(t)} ${G("(coder config set <key> <value> to change)")}`,"");let Nr=[["codex plugin ",I],["claude plugin",o]];for(let[E,T]of Nr)if(T)F.push(T.installed?P(`${E} ${G(T.note)}`):N(`${E} ${T.note}`),"");F.push(_?P(`ready - try: coder task --wait "explain this repo's layout"`):N("not ready - fix the engine issues above (tasks fall back to the claude engine meanwhile)")),W.stdout.write(`${F.join(`
99
+ `,"utf8"),f({file:g,key:$,...n==="set"?{value:l}:{unset:!0},effective:I(mr(u),$)??null})}function LU(){return t$(new URL("..",import.meta.url))}function GU(r){Yr("codex",["plugin","remove","coder@coder-plugins"],{encoding:"utf8"}),Yr("codex",["plugin","marketplace","remove","coder-plugins"],{encoding:"utf8"});let i=Yr("codex",["plugin","marketplace","add","."],{cwd:r,encoding:"utf8"}),v=Yr("codex",["plugin","add","coder@coder-plugins"],{encoding:"utf8"}),u=i.status===0&&v.status===0;return{marketplace:r,installed:u,note:u?"Plugin installed; restart any running codex session to load it.":`Automatic install failed (${(v.stderr||i.stderr||"codex not found").trim()}); run: codex plugin marketplace add "${r}" && codex plugin add coder@coder-plugins`}}function VU(r){Yr("claude",["plugin","marketplace","remove","coder-plugins"],{encoding:"utf8"});let i=Yr("claude",["plugin","marketplace","add",r],{encoding:"utf8"}),v=Yr("claude",["plugin","install","coder@coder-plugins"],{encoding:"utf8"}),u=i.status===0&&v.status===0;return{marketplace:r,installed:u,note:u?"Plugin installed; restart any running Claude Code session to load it.":`Automatic install failed (${(v.stderr||i.stderr||"claude not found").trim()}); run: claude plugin marketplace add "${r}" && claude plugin install coder@coder-plugins`}}async function Tb(r){let{options:i}=nr(r,{valueOptions:["cwd"],booleanOptions:["codex","claude","json"]}),v=i.cwd?x.resolve(i.cwd):W.cwd(),u=dr(v),n=u.available?await a6(v):{loggedIn:!1,detail:u.detail},$=u$(),t=zi();if(!C.existsSync(t)){let E=u.available?["codex","claude"]:$.available?["claude","codex"]:["codex","claude"];lU({...O6,chain:E})}let g=LU(),I=i.codex?GU(g):null,o=i.claude?VU(g):null,l=mr(v),_=u.available&&n.loggedIn;if(i.json){f({codex:{available:u.available,detail:u.detail,auth:n.detail,loggedIn:n.loggedIn},claude:{available:$.available,detail:$.detail},configFile:t,runtime:t$(new URL("../bin/coder.mjs",import.meta.url)),...I?{codexPlugin:I}:{},...o?{claudePlugin:o}:{},config:l,ready:_});return}let b=W.stdout.isTTY&&!W.env.NO_COLOR,k=(E,T)=>b?`\x1B[${E}m${T}\x1B[0m`:T,P=(E)=>` ${k("32","✔")} ${E}`,N=(E)=>` ${k("31","✘")} ${E}`,S=(E)=>k("1",E),G=(E)=>k("38;5;245",E),F=[S("Coder setup"),""],q=u.available?n.loggedIn?P(`codex ${G(`${u.detail}; ${n.detail}`)}`):N(`codex not logged in ${G(`(${n.detail})`)} - run: codex login`):N("codex not installed - run: npm install -g @openai/codex"),j=$.available?P(`claude ${G($.detail)}`):N("claude not installed - run: npm install -g @anthropic-ai/claude-code");F.push(S("Available Engines"),q,j,"");let K=(E)=>{let T=l.agents?.[E]??{};return[T.model,T.effort,T.permissions].filter(Boolean).join("/")};F.push(S("Config"),` chain: ${(l.chain??[]).join(" -> ")} codex: ${K("codex")} claude: ${K("claude")}`,` ${G(t)} ${G("(coder config set <key> <value> to change)")}`,"");let Nr=[["codex plugin ",I],["claude plugin",o]];for(let[E,T]of Nr)if(T)F.push(T.installed?P(`${E} ${G(T.note)}`):N(`${E} ${T.note}`),"");F.push(_?P(`ready - try: coder task --wait "explain this repo's layout"`):N("not ready - fix the engine issues above (tasks fall back to the claude engine meanwhile)")),W.stdout.write(`${F.join(`
100
100
  `)}
101
101
  `)}async function JU(r){let{options:i}=nr(r,{valueOptions:["pm"],booleanOptions:["cli-only","plugins-only","codex","claude"]}),v=!i["plugins-only"],u=!i["cli-only"],n=W.stdout.isTTY&&!W.env.NO_COLOR,$=(N,S)=>n?`\x1B[${N}m${S}\x1B[0m`:S,t=(N)=>$("1",N),g=(N)=>$("38;5;245",N),I=(N)=>` ${$("32","✔")} ${N}`,o=(N)=>` ${$("31","✘")} ${N}`,l=(N,S)=>S&&N&&S!==N?`${N} ${g("->")} ${t(S)}`:`${S??N??"?"} ${g("(unchanged)")}`,_=LU(),b=x.join(_,"plugins/codex/.codex-plugin/plugin.json"),k=x.join(_,"plugins/claude/.claude-plugin/plugin.json"),P={cli:Si(),codex:q6(b),claude:q6(k)};if(v){let N=OU(K6),[S,...G]=i.pm==="npm"?["npm","install","-g","@wular/coder@latest"]:i.pm==="pnpm"?["pnpm","add","-g","@wular/coder@latest"]:i.pm==="yarn"?["yarn","global","add","@wular/coder@latest"]:i.pm==="bun"?["bun","add","-g","@wular/coder@latest"]:N.command,F=i.pm??N.pm;W.stdout.write(`${t("Updating coder CLI")} ${g(`via ${F}...`)}
102
102
  `);let q=Yr(S,G,{encoding:"utf8"});if(q.error?.code==="ENOENT")M(`${F} not found on PATH. Re-run with --pm <npm|pnpm|yarn|bun>, or update manually: ${S} ${G.join(" ")}`);if(q.status!==0){let K=(q.stderr||q.stdout||"").trim();M(`CLI update failed (${F}).${K?`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wular/coder",
3
- "version": "0.1.9",
3
+ "version": "0.1.12",
4
4
  "description": "Delegating coding-agent runtime",
5
5
  "type": "module",
6
6
  "bin": {
@@ -13,7 +13,8 @@
13
13
  "version-bump:patch": "node scripts/bump.mjs patch",
14
14
  "version-bump:minor": "node scripts/bump.mjs minor",
15
15
  "version-bump:major": "node scripts/bump.mjs major",
16
- "prepublishOnly": "bun run build && bun run typecheck"
16
+ "prepublishOnly": "bun run build && bun run typecheck",
17
+ "npm-publish": "npm publish --access public --tag latest --registry=https://registry.npmjs.org --//registry.npmjs.org/:_authToken=\"$NPM_TOKEN\""
17
18
  },
18
19
  "files": [
19
20
  "bin",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "coder",
3
- "version": "0.1.9",
3
+ "version": "0.1.12",
4
4
  "description": "Delegate coding tasks to a Coder subagent. Codex first, Claude fallback; your main context stays clean.",
5
5
  "author": {
6
6
  "name": "muzam1l"
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: handle
3
- description: Use Coder for any coding, implementation, or investigation task - features, fixes, refactors, debugging, tests, questions about the code. You are the orchestrator - never implement tasks yourself; dispatch them through the `coder` CLI exactly as this skill instructs, never via your own subagents. Give it one focused, self-contained goal with all context - overview, file paths, constraints e.g. read-only, git rules.
3
+ description: Use Coder for any coding, implementation, or investigation task - features, fixes, refactors, debugging, tests, code questions. You orchestrate, never implement yourself; dispatch through the `coder` CLI, one coder per focused goal, fanning out many coders in parallel as the work needs.
4
4
  ---
5
5
 
6
6
  # Coder dispatch
@@ -11,6 +11,7 @@ If `coder` is not on PATH, install it yourself without asking (`npm install -g @
11
11
 
12
12
  ## Dispatching a task
13
13
 
14
+ - One coder per focused goal. When the work splits into independent parts, decompose it and dispatch each part as its own background `coder task` - fan out a wide web of coders running in parallel, not one giant dispatch. Give each coder a self-contained goal with all context - overview, file paths, constraints (read-only, git rules). Run independent tasks concurrently; use `steer` to continue a single coder's thread.
14
15
  - Delegation is a hard gate for anything the engine can do itself: do not read source files, investigate, or write code first - no matter how simple the task. Fold into the task text whatever only you have - conversation context, results from tools the engine lacks.
15
16
  - Compose one self-contained task text (goal, relevant paths, constraints) and run it as a **background Bash call** so you are notified on completion instead of blocking or polling:
16
17
 
@@ -18,14 +19,16 @@ If `coder` is not on PATH, install it yourself without asking (`npm install -g @
18
19
  coder task --wait "<task text>" # Bash run_in_background: true
19
20
  ```
20
21
 
21
- - The harness re-invokes you when the command exits. Exit 0: relay the final message. Exit 1: the engine ran but the turn failed - report it, do not retry or fall back yourself.
22
+ - The harness re-invokes you when the command exits. Exit 0: usually relay the final message, BUT if stdout is a `spawn-claude-subagent` payload (Claude is the configured engine), this is a clean delegation - spawn the subagent as below, do not treat it as a result. Exit 1: the engine ran but the turn failed - report it, do not retry or fall back yourself. Exit 3: Codex failed and handed off to Claude (see below).
22
23
  - Engine, model, and effort come from config; add `--agent` / `--model` / `--effort` when the user asks or it is unambiguous from context (agents: `codex`, `claude`; codex models: `spark`, `5.5`; claude models: `opus`, `sonnet`, `fable`; efforts: `low|medium|high`).
23
24
  - Permissions default to auto mode (workspace-write + policy-answered escalations). Pass `--permissions read-only` when the task is read-only; `--permissions workspace-write` to forbid any escalation beyond the project.
24
25
  - For long jobs the user may want to manage by id, drop `--wait`: the runtime detaches a worker, does its own startup check, and prints a job id plus status/result/steer commands. Relay that and do not poll.
25
26
 
26
- ## Claude engine (exit 3)
27
+ ## Claude engine (spawn-claude-subagent payload)
27
28
 
28
- Exit code 3 means the runtime printed a `spawn-claude-subagent` payload instead of running Codex. Its `reason` field says why: `configured` (Claude is the selected engine) or `codex-failed` (Codex missing, auth, quota, rate limit - mention this to the user, including any limit-reset time).
29
+ The runtime prints a `spawn-claude-subagent` payload instead of running Codex when Claude should handle the task. Its `reason` field says why, and the exit code follows from it:
30
+ - `configured` (Claude is the selected engine): a planned delegation, so the runtime **exits 0** - present it as delegation, not an error.
31
+ - `codex-failed` (Codex missing, auth, quota, rate limit): the runtime **exits 3** and wraps the payload under a `fallback` key alongside an `error` string - mention the failure to the user, including any limit-reset time, then spawn the subagent.
29
32
 
30
33
  Spawn one `general-purpose` subagent via the Agent tool, passing the payload's `model` as the Agent tool's model parameter. Its prompt is the original task text verbatim, prefixed with: "NEVER run git write operations (commit, checkout, stash, reset, push, etc.); leave changes uncommitted." Append the same for the payload's `permissions` if not the default `auto`: `read-only` means investigate and report without modifying anything; `workspace-write` means never touch anything outside the workspace.
31
34
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "coder",
3
- "version": "0.1.9",
3
+ "version": "0.1.12",
4
4
  "interface": {
5
5
  "displayName": "Coder (plugin)"
6
6
  },
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: handle
3
- description: Use Coder for any coding, implementation, or investigation task - features, fixes, refactors, debugging, tests, questions about the code. You are the orchestrator - never implement tasks yourself; dispatch them through the `coder` CLI exactly as this skill instructs, never via your own subagents. Give it one focused, self-contained goal with all context - overview, file paths, constraints e.g. read-only, git rules.
3
+ description: Use Coder for any coding, implementation, or investigation task - features, fixes, refactors, debugging, tests, code questions. You orchestrate, never implement yourself; dispatch through the `coder` CLI, one coder per focused goal, fanning out many coders in parallel as the work needs.
4
4
  ---
5
5
 
6
6
  # Coder dispatch (codex host)
@@ -12,6 +12,7 @@ If `coder` is not on PATH, install it yourself without asking: `npm install -g @
12
12
  ## Dispatching a task
13
13
 
14
14
  - Run every `coder` command with escalated permissions (outside your sandbox), justification: Coder is a supervisor - it spawns engines, keeps state in `~/.coder`, and enforces its own sandbox and approval policy on the task. Never retry a sandbox-blocked `coder` call sandboxed again or with HOME/state env workarounds.
15
+ - One coder per focused goal. When the work splits into independent parts, decompose it and dispatch each part as its own `coder task --host codex` call - fan out a wide web of coders, not one giant dispatch. Give each coder a self-contained goal with all context - overview, file paths, constraints (read-only, git rules); use `steer` to continue a single coder's thread.
15
16
  - Delegation is a hard gate for anything the engine can do itself: do not read source files, investigate, or write code first - no matter how simple the task. Fold into the task text whatever only you have - conversation context, results from tools the engine lacks.
16
17
  - Compose one self-contained task text (goal, relevant paths, constraints) and run:
17
18