@reddb-io/red-skills 3.19.4 → 3.20.0

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,19 +1,19 @@
1
1
  import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
2
- import{mkdirSync as $e,readFileSync as Bt,writeFileSync as Kt}from"node:fs";import{dirname as zt,resolve as U}from"node:path";function L(e){let t={app:e,version:Se(b("__RED_BUILD_VERSION__",()=>"3.19.4")??"0.0.0-dev"),gitSha:b("__RED_BUILD_GIT_SHA__",()=>"cbccb19444939c8c3079b4d6bbfe0109662235e7")??"unknown",buildTime:b("__RED_BUILD_TIME__",()=>"2026-08-18T09:27:29-03:00")??"unknown",bundleAsset:b("__RED_BUNDLE_ASSET__",()=>"opencode-host.bundle.min.mjs")??"unknown"},o=b("__REDDB_SDK_VERSION__",()=>""),n=b("__REDDB_BINARY_TAG__",()=>"");return o&&(t.reddbSdkVersion=o),n&&(t.reddbBinaryTag=n),t}function Se(e){return e.startsWith("v")?e.slice(1):e}function V(e){return`${e.app} ${e.version} ${e.gitSha}`}function b(e,t){try{let o=t();return typeof o=="string"&&o.length>0?o:void 0}catch{return process.env[e.replace(/^__|__$/g,"")]}}var X={"=":"data",":=":{to:"data",typed:!0},":":"meta"},Pe=/^[a-z][a-z0-9+.-]*:\/\//i;function Ee(e,t){return typeof t=="string"?{separator:e,to:t,typed:!1,prefix:!1}:{separator:e,to:t.to,typed:t.typed??!1,prefix:t.prefix??!1}}function Re(e=X){return Object.entries(e).map(([t,o])=>Ee(t,o)).sort((t,o)=>o.separator.length-t.separator.length)}function Ce(e){return/^-\d+(\.\d+)?$/.test(e)}function O(e){return!(!e||e.startsWith("-")&&!Ce(e))}function R(e){if(e==="true")return!0;if(e==="false")return!1;if(e==="null")return null;let t=Number(e);return!Number.isNaN(t)&&Number.isFinite(t)&&e.trim()!==""?t:e}function Q(e){if(e==="true")return!0;if(e==="false")return!1;if(e==="null")return null;if(e.startsWith("[")&&e.endsWith("]")||e.startsWith("{")&&e.endsWith("}"))try{return JSON.parse(e)}catch{}let t=Number(e);return!Number.isNaN(t)&&Number.isFinite(t)&&e.trim()!==""?t:e.includes(",")?e.split(",").map(o=>Q(o.trim())):e}function x(e,t){switch(t){case"boolean":return Ae(e);case"number":return Ie(e);case"array":return e.split(",").map(o=>R(o.trim()));case"string":default:return e}}function Ae(e){let t=e.toLowerCase().trim();return t==="true"||t==="yes"||t==="1"||t==="on"}function Ie(e){if(e.trim()==="")throw new TypeError(`Cannot convert "${e}" to number`);let t=Number(e);if(Number.isNaN(t))throw new TypeError(`Cannot convert "${e}" to number`);return t}function w(e){return e.startsWith('"')&&e.endsWith('"')||e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function je(e,t={}){return e.map(o=>{let n=t[o.type];return n?n(o.value):o.value}).join("")}function m(e,t){return{type:e,value:t}}function Fe(e){let t=[],o=Ne(e);if(t.push(m("section-header","Usage:"),m("text"," "),m("usage-text",o),m("newline",`
3
- `),m("newline",`
4
- `)),e.positional&&e.positional.length>0){t.push(m("section-header","Arguments:"),m("newline",`
5
- `));for(let n of e.positional)if(n.description){let s=n.variadic?`${n.name}...`:n.name;t.push(m("indent"," "),m("positional-name",`<${s}>`)),n.required||t.push(m("positional-optional"," (optional)")),t.push(m("newline",`
6
- `),m("indent"," "),m("option-description",n.description),m("newline",`
7
- `))}t.push(m("newline",`
8
- `))}if(e.options&&Object.keys(e.options).length>0){t.push(m("section-header","Options:"),m("newline",`
9
- `));let n=De(e.options);t.push(...n)}return t}function Te(e,t){let o=Fe(e);return je(o,t)}function Ne(e){let t=["[options]"];if(e.positional)for(let o of e.positional)o.variadic?t.push(o.required?`<${o.name}...>`:`[${o.name}...]`):t.push(o.required?`<${o.name}>`:`[${o.name}]`);return t.join(" ")}function De(e,t=!1){let o=[],n=[],s=t?"global-option-flag":"option-flag",i=t?"global-option-type":"option-type",r=t?"global-option-default":"option-default",a=t?"global-option-description":"option-description";for(let[l,u]of Object.entries(e)){if(u.hidden)continue;let f=[],p=h=>{f.includes(h)||f.push(h)};u.short&&p(`-${u.short}`),p(`--${l}`);for(let h of u.aliases??[])h.length===1?p(`-${h}`):p(`--${h}`);let d=f.join(", "),y=u.type&&u.type!=="boolean"?`<${u.type}>`:void 0;n.push({flags:d,type:y,desc:u.description??"",default:u.default!==void 0?String(u.default):void 0})}let c=Math.max(...n.map(l=>l.flags.length+(l.type?l.type.length+1:0)),20);for(let l of n){let u=l.flags.length+(l.type?l.type.length+1:0),f=" ".repeat(c-u+2);o.push(m("indent"," ")),o.push(m(s,l.flags)),l.type&&(o.push(m("text"," ")),o.push(m(i,l.type))),o.push(m("text",f)),o.push(m(a,l.desc)),l.default!==void 0&&(o.push(m("text"," ")),o.push(m(r,`(default: ${l.default})`))),o.push(m("newline",`
10
- `))}return o}function ee(e){let t=qe(e.options??{},e.autoShort??!1),o=Re(e.separators??X);return{schema:e,parse(n){return Ue(n,e,t,o)},help(){return Te(e,e.formatter)}}}function Ue(e,t,o,n){let s={positional:{},options:{},errors:[],rest:[]},i=new Set(n.map(u=>u.to));for(let u of i)s[u]={};let r=0,a=t.positional??[],c=0,l=!1;for(;c<e.length;){let u=e[c];if(t.stopEarly&&r>0){s.rest=e.slice(c);break}if(u==="--"&&!l){l=!0,c++;continue}if(l){if(r<a.length){let p=a[r];if(p.variadic){let d=[];for(;c<e.length;){let y=e[c];d.push(p.type?x(y,p.type):y),c++}s.positional[p.name]=d,r++}else{let d=p.type?x(u,p.type):u;s.positional[p.name]=d,r++,c++}}else t.allowUnknown!==!1&&(s.rest=s.rest??[],s.rest.push(u)),c++;continue}if(u.startsWith("--")){c=We(u,c,e,s,o,t);continue}if(u.startsWith("-")&&u.length>1&&!Je(u)){c=Ge(u,c,e,s,o,t);continue}let f=Me(u,n);if(f){let{key:p,value:d,config:y}=f,h=s,_=h[y.to]??(h[y.to]={});_[p]=y.typed?Q(d):w(d),c++;continue}if(r<a.length){let p=a[r];if(p.variadic){let y=[];for(;c<e.length&&!e[c].startsWith("-");){let h=e[c];y.push(p.type?x(h,p.type):h),c++}s.positional[p.name]=y,r++;continue}let d=p.type?x(u,p.type):u;s.positional[p.name]=d,r++}else t.allowUnknown!==!1?s.rest.push(u):s.errors.push(`Unexpected positional argument: ${u}`);c++}return Be(s,t,o),Ke(s,t,a),ze(s,t,o),s}function Me(e,t){if(Pe.test(e))return null;for(let o of t){if(o.prefix&&e.startsWith(o.separator)){let s=e.slice(o.separator.length),i=s.indexOf(":");if(i>0){let r=s.slice(0,i),a=s.slice(i+1);if(Le(r))return{key:r,value:a,config:o}}continue}let n=e.indexOf(o.separator);if(n>0){let s=e.slice(0,n),i=e.slice(n+o.separator.length);if(Ve(s,i,o))return{key:s,value:i,config:o}}}return null}function Le(e){return e?/^[a-zA-Z_][a-zA-Z0-9_-]*$/.test(e):!1}function Ve(e,t,o){return e?o.separator===":"?e.includes("/")||e.includes(".")||/^\d+$/.test(t)?!1:/^[A-Z][a-zA-Z0-9-]*$/.test(e):!((o.separator==="="||o.separator===":=")&&e.includes("/")):!1}function We(e,t,o,n,s,i){let r=e.slice(2);if(r.startsWith("no-")){let c=r.slice(3),l=s.get(c);if(l?.negatable!==!1&&l?.type==="boolean")return n.options[l.name]=!1,t+1}if(r.includes("=")){let c=r.indexOf("="),l=r.slice(0,c),u=r.slice(c+1);return C(l,u,t+1,n,s,i)}let a=s.get(r);if(a){if(a.type!=="boolean"){let c=o[t+1];return O(c)?C(a.name,c,t+2,n,s,i):(n.errors.push(`Option --${r} requires a value`),t+1)}return n.options[a.name]=!0,t+1}return i.strict?n.errors.push(`Unknown option: --${r}`):i.allowUnknown!==!1&&(n.options[r]=!0),t+1}function Ge(e,t,o,n,s,i){let r=e.slice(1);if(r.includes("=")){let a=r.indexOf("="),c=r.slice(0,a),l=r.slice(a+1),u=W(c,s);return u?C(u.name,l,t+1,n,s,i):(i.strict?n.errors.push(`Unknown option: -${c}`):i.allowUnknown!==!1&&(n.options[c]=R(w(l))),t+1)}if(r.length===1){let a=W(r,s);if(a){if(a.type!=="boolean"){let c=o[t+1];return O(c)?C(a.name,c,t+2,n,s,i):(n.errors.push(`Option -${r} requires a value`),t+1)}return n.options[a.name]=!0,t+1}if(i.strict)n.errors.push(`Unknown option: -${r}`);else if(i.allowUnknown!==!1){let c=o[t+1];if(O(c))return n.options[r]=R(w(c)),t+2;n.options[r]=!0}return t+1}for(let a of r){let c=W(a,s);c?c.type==="boolean"?n.options[c.name]=!0:n.errors.push(`Option -${a} requires a value`):i.strict?n.errors.push(`Unknown option: -${a}`):i.allowUnknown!==!1&&(n.options[a]=!0)}return t+1}function C(e,t,o,n,s,i){let r=s.get(e);if(r){if(r.choices){let c=r.type?x(w(t),r.type):w(t);if(!r.choices.includes(c))return n.errors.push(`Invalid value for '${e}': '${t}'. Allowed: ${r.choices.join(", ")}`),o}let a=r.type?x(w(t),r.type):w(t);if(r.type==="array"){let c=n.options[e];Array.isArray(c)?c.push(...a):n.options[e]=a}else n.options[e]=a}else i.strict?n.errors.push(`Unknown option: --${e}`):i.allowUnknown!==!1&&(n.options[e]=R(w(t)));return o}function qe(e,t=!1){let o=new Map,n=Object.entries(e).sort(([i],[r])=>i.localeCompare(r)),s=new Set;for(let[,i]of n)i.short&&s.add(i.short);for(let[i,r]of n){let a=r.short??"";t&&!a&&(a=He(i,s),a&&s.add(a));let c={name:i,short:a,aliases:r.aliases??[],type:r.type??"string",description:r.description??"",required:r.required??!1,hidden:r.hidden??!1,negatable:r.negatable??!0,default:r.default,choices:r.choices,env:r.env,validate:r.validate};o.set(i,c);for(let l of c.aliases)o.set(l,c)}return o}function He(e,t){for(let o of e){if(!/[a-zA-Z]/.test(o))continue;let n=o.toLowerCase();if(!t.has(n))return n;let s=o.toUpperCase();if(!t.has(s))return s}return""}function W(e,t){for(let o of t.values())if(o.short===e||o.aliases.includes(e))return o}function Be(e,t,o){for(let n of o.values())if(e.options[n.name]===void 0)if(n.env&&process.env[n.env]!==void 0){let s=process.env[n.env];e.options[n.name]=n.type?x(s,n.type):s}else n.default!==void 0&&(e.options[n.name]=n.default);for(let n of t.positional??[])e.positional[n.name]===void 0&&n.default!==void 0&&(e.positional[n.name]=n.default)}function Ke(e,t,o){if(t.options)for(let[n,s]of Object.entries(t.options))s.required&&e.options[n]===void 0&&e.errors.push(`Missing required option: --${n}`);for(let n of o)n.required&&e.positional[n.name]===void 0&&e.errors.push(`Missing required argument: <${n.name}>`)}function ze(e,t,o){for(let n of o.values()){let s=e.options[n.name];if(n.validate&&s!==void 0){let i=n.validate(s);i!==!0&&e.errors.push(i)}}for(let n of t.positional??[]){let s=e.positional[n.name];if(n.validate&&s!==void 0){let i=n.validate(s);i!==!0&&e.errors.push(i)}}}function Je(e){return/^-\d+(\.\d+)?$/.test(e)}var G=class extends Error{flag;known;constructor(t,o){super(`unknown flag '${t}'; expected one of: ${o.join(", ")}`),this.name="UnknownFlagError",this.flag=t,this.known=o}};function Ze(e){let t={};for(let[o,n]of Object.entries(e))t[o]={type:n.kind==="boolean"?"boolean":"string",...o.length===1?{short:o}:{},...n.aliases===void 0?{}:{aliases:n.aliases}};return t}function Ye(e,t){let o=new Map;for(let[s,i]of Object.entries(t))if(!(i.kind!=="value"||i.type!=="array")){o.set(s,s);for(let r of i.aliases??[])o.set(r,s)}let n=new Map;for(let s=0;s<e.length;s+=1){let i=e[s];if(i==="--")break;let r=i.match(/^--([^=]+)(?:=(.*))?$/)??i.match(/^-([^=])(?:=(.*))?$/);if(r===null)continue;let a=o.get(r[1]);if(a===void 0)continue;let c=r[2];if(c===void 0&&O(e[s+1])&&(c=e[s+1],s+=1),c===void 0)continue;let l=n.get(a)??[];l.push(c),n.set(a,l)}return n}function te(e,t,o={}){let s=ee({options:Ze(t),separators:{},allowUnknown:!0}).parse([...e]),i={},r=Ye(e,t),a=s.errors.find(c=>/^Option --?\S+ requires a value$/.test(c));if(a!==void 0)throw new Error(a.replace(/^Option /,""));if(s.errors.length>0)throw new Error(s.errors[0]);if(o.unknownFlags==="error"){let c=new Set(Object.keys(t));for(let l of Object.keys(s.options))if(!c.has(l))throw new G(l.length===1?`-${l}`:`--${l}`,Object.keys(t).map(u=>u.length===1?`-${u}`:`--${u}`))}for(let[c,l]of Object.entries(t)){let u=s.options[c];u!==void 0&&(l.kind==="boolean"?i[c]=u:l.type==="array"?i[c]=(r.get(c)??[]).map(f=>l.coerce(f)):i[c]=l.coerce(String(u)))}return{values:i,positionals:s.rest}}var S=class extends Error{token;known;constructor(t,o){super(`unknown command '${t}'; expected one of: ${o.join(", ")}`),this.name="UnknownCommandError",this.token=t,this.known=o}};function ne(e,t){let[o,...n]=e;if(o!==void 0){for(let[i,r]of Object.entries(t.commands))if(o===i||(r.aliases??[]).includes(o))return{command:i,args:n};if(t.errorOnUnknownCommand&&!o.startsWith("-"))throw new S(o,Object.keys(t.commands))}let s=t.keepArgvOnDefault??!0;return{command:t.default,args:s?[...e]:n}}var Xe={config:{kind:"value",aliases:["c"],coerce:e=>e},out:{kind:"value",aliases:["o"],coerce:e=>e},"out-dir":{kind:"value",aliases:["d"],coerce:e=>e},"plugins-root":{kind:"value",aliases:["p"],coerce:e=>e},plugin:{kind:"value",type:"array",coerce:e=>e},"slice-2":{kind:"boolean",aliases:["with-slice-2"]},copy:{kind:"boolean"},print:{kind:"boolean"},help:{kind:"boolean",aliases:["h"]},version:{kind:"boolean",aliases:["v"]},json:{kind:"boolean"}},v=class extends Error{constructor(t){super(t),this.name="OpencodeHostUsageError"}};function oe(e){return e[0]==="--version"||e[0]==="-v"}function se(e){let t;try{t=ne(e,{commands:{generate:{}},default:"generate",errorOnUnknownCommand:!0})}catch(i){throw i instanceof S?new v(i.message):i}let o;try{o=te(t.args,Xe,{unknownFlags:"error"})}catch(i){throw new v(i.message)}let n=o.positionals[0];if(n!==void 0)throw new v(`unexpected argument '${n}'`);let{values:s}=o;return{command:t.command,configPath:s.config??"./.red/config.yaml",outPath:s.out??"./opencode.json",outDir:s["out-dir"]??"./dist/opencode",pluginsRoot:s["plugins-root"]??"./plugins",showHelp:s.help??!1,showVersion:s.version??!1,versionJson:s.json??!1,printJson:s.print??!1,copySkills:s.copy??!1,pluginFilter:s.plugin??null,slice2:s["slice-2"]??!0}}function re(){return`opencode-host generate \u2014 emit the opencode-host runtime tree
2
+ import{mkdirSync as Ee,readFileSync as tn,writeFileSync as nn}from"node:fs";import{dirname as on,resolve as V}from"node:path";function W(e){let t={app:e,version:Ce($("__RED_BUILD_VERSION__",()=>"3.20.0")??"0.0.0-dev"),gitSha:$("__RED_BUILD_GIT_SHA__",()=>"f870feffaadff0d5b2795b4a9f26d6f183eea5c8")??"unknown",buildTime:$("__RED_BUILD_TIME__",()=>"2026-08-18T23:01:46-03:00")??"unknown",bundleAsset:$("__RED_BUNDLE_ASSET__",()=>"opencode-host.bundle.min.mjs")??"unknown"},n=$("__REDDB_SDK_VERSION__",()=>""),o=$("__REDDB_BINARY_TAG__",()=>"");return n&&(t.reddbSdkVersion=n),o&&(t.reddbBinaryTag=o),t}function Ce(e){return e.startsWith("v")?e.slice(1):e}function G(e){return`${e.app} ${e.version} ${e.gitSha}`}function $(e,t){try{let n=t();return typeof n=="string"&&n.length>0?n:void 0}catch{return process.env[e.replace(/^__|__$/g,"")]}}var ne={"=":"data",":=":{to:"data",typed:!0},":":"meta"},Te=/^[a-z][a-z0-9+.-]*:\/\//i;function Ie(e,t){return typeof t=="string"?{separator:e,to:t,typed:!1,prefix:!1}:{separator:e,to:t.to,typed:t.typed??!1,prefix:t.prefix??!1}}function je(e=ne){return Object.entries(e).map(([t,n])=>Ie(t,n)).sort((t,n)=>n.separator.length-t.separator.length)}function Fe(e){return/^-\d+(\.\d+)?$/.test(e)}function S(e){return!(!e||e.startsWith("-")&&!Fe(e))}function A(e){if(e==="true")return!0;if(e==="false")return!1;if(e==="null")return null;let t=Number(e);return!Number.isNaN(t)&&Number.isFinite(t)&&e.trim()!==""?t:e}function oe(e){if(e==="true")return!0;if(e==="false")return!1;if(e==="null")return null;if(e.startsWith("[")&&e.endsWith("]")||e.startsWith("{")&&e.endsWith("}"))try{return JSON.parse(e)}catch{}let t=Number(e);return!Number.isNaN(t)&&Number.isFinite(t)&&e.trim()!==""?t:e.includes(",")?e.split(",").map(n=>oe(n.trim())):e}function v(e,t){switch(t){case"boolean":return Ne(e);case"number":return De(e);case"array":return e.split(",").map(n=>A(n.trim()));case"string":default:return e}}function Ne(e){let t=e.toLowerCase().trim();return t==="true"||t==="yes"||t==="1"||t==="on"}function De(e){if(e.trim()==="")throw new TypeError(`Cannot convert "${e}" to number`);let t=Number(e);if(Number.isNaN(t))throw new TypeError(`Cannot convert "${e}" to number`);return t}function _(e){return e.startsWith('"')&&e.endsWith('"')||e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function Me(e,t={}){return e.map(n=>{let o=t[n.type];return o?o(n.value):n.value}).join("")}function g(e,t){return{type:e,value:t}}function Le(e){let t=[],n=Ve(e);if(t.push(g("section-header","Usage:"),g("text"," "),g("usage-text",n),g("newline",`
3
+ `),g("newline",`
4
+ `)),e.positional&&e.positional.length>0){t.push(g("section-header","Arguments:"),g("newline",`
5
+ `));for(let o of e.positional)if(o.description){let s=o.variadic?`${o.name}...`:o.name;t.push(g("indent"," "),g("positional-name",`<${s}>`)),o.required||t.push(g("positional-optional"," (optional)")),t.push(g("newline",`
6
+ `),g("indent"," "),g("option-description",o.description),g("newline",`
7
+ `))}t.push(g("newline",`
8
+ `))}if(e.options&&Object.keys(e.options).length>0){t.push(g("section-header","Options:"),g("newline",`
9
+ `));let o=He(e.options);t.push(...o)}return t}function Ue(e,t){let n=Le(e);return Me(n,t)}function Ve(e){let t=["[options]"];if(e.positional)for(let n of e.positional)n.variadic?t.push(n.required?`<${n.name}...>`:`[${n.name}...]`):t.push(n.required?`<${n.name}>`:`[${n.name}]`);return t.join(" ")}function He(e,t=!1){let n=[],o=[],s=t?"global-option-flag":"option-flag",i=t?"global-option-type":"option-type",r=t?"global-option-default":"option-default",a=t?"global-option-description":"option-description";for(let[u,l]of Object.entries(e)){if(l.hidden)continue;let f=[],p=y=>{f.includes(y)||f.push(y)};l.short&&p(`-${l.short}`),p(`--${u}`);for(let y of l.aliases??[])y.length===1?p(`-${y}`):p(`--${y}`);let d=f.join(", "),h=l.type&&l.type!=="boolean"?`<${l.type}>`:void 0;o.push({flags:d,type:h,desc:l.description??"",default:l.default!==void 0?String(l.default):void 0})}let c=Math.max(...o.map(u=>u.flags.length+(u.type?u.type.length+1:0)),20);for(let u of o){let l=u.flags.length+(u.type?u.type.length+1:0),f=" ".repeat(c-l+2);n.push(g("indent"," ")),n.push(g(s,u.flags)),u.type&&(n.push(g("text"," ")),n.push(g(i,u.type))),n.push(g("text",f)),n.push(g(a,u.desc)),u.default!==void 0&&(n.push(g("text"," ")),n.push(g(r,`(default: ${u.default})`))),n.push(g("newline",`
10
+ `))}return n}function se(e){let t=Je(e.options??{},e.autoShort??!1),n=je(e.separators??ne);return{schema:e,parse(o){return We(o,e,t,n)},help(){return Ue(e,e.formatter)}}}function We(e,t,n,o){let s={positional:{},options:{},errors:[],rest:[]},i=new Set(o.map(l=>l.to));for(let l of i)s[l]={};let r=0,a=t.positional??[],c=0,u=!1;for(;c<e.length;){let l=e[c];if(t.stopEarly&&r>0){s.rest=e.slice(c);break}if(l==="--"&&!u){u=!0,c++;continue}if(u){if(r<a.length){let p=a[r];if(p.variadic){let d=[];for(;c<e.length;){let h=e[c];d.push(p.type?v(h,p.type):h),c++}s.positional[p.name]=d,r++}else{let d=p.type?v(l,p.type):l;s.positional[p.name]=d,r++,c++}}else t.allowUnknown!==!1&&(s.rest=s.rest??[],s.rest.push(l)),c++;continue}if(l.startsWith("--")){c=Ke(l,c,e,s,n,t);continue}if(l.startsWith("-")&&l.length>1&&!et(l)){c=ze(l,c,e,s,n,t);continue}let f=Ge(l,o);if(f){let{key:p,value:d,config:h}=f,y=s,b=y[h.to]??(y[h.to]={});b[p]=h.typed?oe(d):_(d),c++;continue}if(r<a.length){let p=a[r];if(p.variadic){let h=[];for(;c<e.length&&!e[c].startsWith("-");){let y=e[c];h.push(p.type?v(y,p.type):y),c++}s.positional[p.name]=h,r++;continue}let d=p.type?v(l,p.type):l;s.positional[p.name]=d,r++}else t.allowUnknown!==!1?s.rest.push(l):s.errors.push(`Unexpected positional argument: ${l}`);c++}return Ye(s,t,n),Xe(s,t,a),Qe(s,t,n),s}function Ge(e,t){if(Te.test(e))return null;for(let n of t){if(n.prefix&&e.startsWith(n.separator)){let s=e.slice(n.separator.length),i=s.indexOf(":");if(i>0){let r=s.slice(0,i),a=s.slice(i+1);if(qe(r))return{key:r,value:a,config:n}}continue}let o=e.indexOf(n.separator);if(o>0){let s=e.slice(0,o),i=e.slice(o+n.separator.length);if(Be(s,i,n))return{key:s,value:i,config:n}}}return null}function qe(e){return e?/^[a-zA-Z_][a-zA-Z0-9_-]*$/.test(e):!1}function Be(e,t,n){return e?n.separator===":"?e.includes("/")||e.includes(".")||/^\d+$/.test(t)?!1:/^[A-Z][a-zA-Z0-9-]*$/.test(e):!((n.separator==="="||n.separator===":=")&&e.includes("/")):!1}function Ke(e,t,n,o,s,i){let r=e.slice(2);if(r.startsWith("no-")){let c=r.slice(3),u=s.get(c);if(u?.negatable!==!1&&u?.type==="boolean")return o.options[u.name]=!1,t+1}if(r.includes("=")){let c=r.indexOf("="),u=r.slice(0,c),l=r.slice(c+1);return C(u,l,t+1,o,s,i)}let a=s.get(r);if(a){if(a.type!=="boolean"){let c=n[t+1];return S(c)?C(a.name,c,t+2,o,s,i):(o.errors.push(`Option --${r} requires a value`),t+1)}return o.options[a.name]=!0,t+1}return i.strict?o.errors.push(`Unknown option: --${r}`):i.allowUnknown!==!1&&(o.options[r]=!0),t+1}function ze(e,t,n,o,s,i){let r=e.slice(1);if(r.includes("=")){let a=r.indexOf("="),c=r.slice(0,a),u=r.slice(a+1),l=q(c,s);return l?C(l.name,u,t+1,o,s,i):(i.strict?o.errors.push(`Unknown option: -${c}`):i.allowUnknown!==!1&&(o.options[c]=A(_(u))),t+1)}if(r.length===1){let a=q(r,s);if(a){if(a.type!=="boolean"){let c=n[t+1];return S(c)?C(a.name,c,t+2,o,s,i):(o.errors.push(`Option -${r} requires a value`),t+1)}return o.options[a.name]=!0,t+1}if(i.strict)o.errors.push(`Unknown option: -${r}`);else if(i.allowUnknown!==!1){let c=n[t+1];if(S(c))return o.options[r]=A(_(c)),t+2;o.options[r]=!0}return t+1}for(let a of r){let c=q(a,s);c?c.type==="boolean"?o.options[c.name]=!0:o.errors.push(`Option -${a} requires a value`):i.strict?o.errors.push(`Unknown option: -${a}`):i.allowUnknown!==!1&&(o.options[a]=!0)}return t+1}function C(e,t,n,o,s,i){let r=s.get(e);if(r){if(r.choices){let c=r.type?v(_(t),r.type):_(t);if(!r.choices.includes(c))return o.errors.push(`Invalid value for '${e}': '${t}'. Allowed: ${r.choices.join(", ")}`),n}let a=r.type?v(_(t),r.type):_(t);if(r.type==="array"){let c=o.options[e];Array.isArray(c)?c.push(...a):o.options[e]=a}else o.options[e]=a}else i.strict?o.errors.push(`Unknown option: --${e}`):i.allowUnknown!==!1&&(o.options[e]=A(_(t)));return n}function Je(e,t=!1){let n=new Map,o=Object.entries(e).sort(([i],[r])=>i.localeCompare(r)),s=new Set;for(let[,i]of o)i.short&&s.add(i.short);for(let[i,r]of o){let a=r.short??"";t&&!a&&(a=Ze(i,s),a&&s.add(a));let c={name:i,short:a,aliases:r.aliases??[],type:r.type??"string",description:r.description??"",required:r.required??!1,hidden:r.hidden??!1,negatable:r.negatable??!0,default:r.default,choices:r.choices,env:r.env,validate:r.validate};n.set(i,c);for(let u of c.aliases)n.set(u,c)}return n}function Ze(e,t){for(let n of e){if(!/[a-zA-Z]/.test(n))continue;let o=n.toLowerCase();if(!t.has(o))return o;let s=n.toUpperCase();if(!t.has(s))return s}return""}function q(e,t){for(let n of t.values())if(n.short===e||n.aliases.includes(e))return n}function Ye(e,t,n){for(let o of n.values())if(e.options[o.name]===void 0)if(o.env&&process.env[o.env]!==void 0){let s=process.env[o.env];e.options[o.name]=o.type?v(s,o.type):s}else o.default!==void 0&&(e.options[o.name]=o.default);for(let o of t.positional??[])e.positional[o.name]===void 0&&o.default!==void 0&&(e.positional[o.name]=o.default)}function Xe(e,t,n){if(t.options)for(let[o,s]of Object.entries(t.options))s.required&&e.options[o]===void 0&&e.errors.push(`Missing required option: --${o}`);for(let o of n)o.required&&e.positional[o.name]===void 0&&e.errors.push(`Missing required argument: <${o.name}>`)}function Qe(e,t,n){for(let o of n.values()){let s=e.options[o.name];if(o.validate&&s!==void 0){let i=o.validate(s);i!==!0&&e.errors.push(i)}}for(let o of t.positional??[]){let s=e.positional[o.name];if(o.validate&&s!==void 0){let i=o.validate(s);i!==!0&&e.errors.push(i)}}}function et(e){return/^-\d+(\.\d+)?$/.test(e)}var B=class extends Error{flag;known;constructor(t,n){super(`unknown flag '${t}'; expected one of: ${n.join(", ")}`),this.name="UnknownFlagError",this.flag=t,this.known=n}};function tt(e){let t={};for(let[n,o]of Object.entries(e))t[n]={type:o.kind==="boolean"?"boolean":"string",...n.length===1?{short:n}:{},...o.aliases===void 0?{}:{aliases:o.aliases}};return t}function nt(e,t){let n=new Map;for(let[s,i]of Object.entries(t))if(!(i.kind!=="value"||i.type!=="array")){n.set(s,s);for(let r of i.aliases??[])n.set(r,s)}let o=new Map;for(let s=0;s<e.length;s+=1){let i=e[s];if(i==="--")break;let r=i.match(/^--([^=]+)(?:=(.*))?$/)??i.match(/^-([^=])(?:=(.*))?$/);if(r===null)continue;let a=n.get(r[1]);if(a===void 0)continue;let c=r[2];if(c===void 0&&S(e[s+1])&&(c=e[s+1],s+=1),c===void 0)continue;let u=o.get(a)??[];u.push(c),o.set(a,u)}return o}function re(e,t,n={}){let s=se({options:tt(t),separators:{},allowUnknown:!0}).parse([...e]),i={},r=nt(e,t),a=s.errors.find(c=>/^Option --?\S+ requires a value$/.test(c));if(a!==void 0)throw new Error(a.replace(/^Option /,""));if(s.errors.length>0)throw new Error(s.errors[0]);if(n.unknownFlags==="error"){let c=new Set(Object.keys(t));for(let u of Object.keys(s.options))if(!c.has(u))throw new B(u.length===1?`-${u}`:`--${u}`,Object.keys(t).map(l=>l.length===1?`-${l}`:`--${l}`))}for(let[c,u]of Object.entries(t)){let l=s.options[c];l!==void 0&&(u.kind==="boolean"?i[c]=l:u.type==="array"?i[c]=(r.get(c)??[]).map(f=>u.coerce(f)):i[c]=u.coerce(String(l)))}return{values:i,positionals:s.rest}}var O=class extends Error{token;known;constructor(t,n){super(`unknown command '${t}'; expected one of: ${n.join(", ")}`),this.name="UnknownCommandError",this.token=t,this.known=n}};function ie(e,t){let[n,...o]=e;if(n!==void 0){for(let[i,r]of Object.entries(t.commands))if(n===i||(r.aliases??[]).includes(n))return{command:i,args:o};if(t.errorOnUnknownCommand&&!n.startsWith("-"))throw new O(n,Object.keys(t.commands))}let s=t.keepArgvOnDefault??!0;return{command:t.default,args:s?[...e]:o}}var K=["opencode","redcode"],ot={opencode:!1,redcode:!0},st=["navigator"];function rt(e){return st.includes(e)}function ce(e){return K.includes(e)}function T(e,t){return{host:e,nativeLsp:t??ot[e]}}function it(e){return e.nativeLsp}function I(e,t){if(!it(t))return{plans:[...e],deferred:[]};let n=[],o=[];for(let s of e)rt(s.name)?o.push(s.name):n.push(s);return{plans:n,deferred:o}}var ct={config:{kind:"value",aliases:["c"],coerce:e=>e},out:{kind:"value",aliases:["o"],coerce:e=>e},"out-dir":{kind:"value",aliases:["d"],coerce:e=>e},"plugins-root":{kind:"value",aliases:["p"],coerce:e=>e},host:{kind:"value",coerce:e=>e},"native-lsp":{kind:"boolean"},plugin:{kind:"value",type:"array",coerce:e=>e},"slice-2":{kind:"boolean",aliases:["with-slice-2"]},copy:{kind:"boolean"},print:{kind:"boolean"},help:{kind:"boolean",aliases:["h"]},version:{kind:"boolean",aliases:["v"]},json:{kind:"boolean"}},w=class extends Error{constructor(t){super(t),this.name="OpencodeHostUsageError"}};function ae(e){return e[0]==="--version"||e[0]==="-v"}function le(e){let t;try{t=ie(e,{commands:{generate:{}},default:"generate",errorOnUnknownCommand:!0})}catch(r){throw r instanceof O?new w(r.message):r}let n;try{n=re(t.args,ct,{unknownFlags:"error"})}catch(r){throw new w(r.message)}let o=n.positionals[0];if(o!==void 0)throw new w(`unexpected argument '${o}'`);let{values:s}=n,i=s.host??"opencode";if(!ce(i))throw new w(`unsupported --host '${i}'; expected one of: ${K.join(", ")}`);return{command:t.command,configPath:s.config??"./.red/config.yaml",outPath:s.out??"./opencode.json",outDir:s["out-dir"]??"./dist/opencode",pluginsRoot:s["plugins-root"]??"./plugins",host:i,nativeLsp:s["native-lsp"],showHelp:s.help??!1,showVersion:s.version??!1,versionJson:s.json??!1,printJson:s.print??!1,copySkills:s.copy??!1,pluginFilter:s.plugin??null,slice2:s["slice-2"]??!0}}function ue(){return`opencode-host generate \u2014 emit the opencode-host runtime tree
11
11
 
12
12
  Slice 1: opencode.json (provider block) at <out>
13
13
  Slice 2: dist tree at <out-dir>/<plugin>/{opencode.json, .opencode/...}
14
14
 
15
15
  Usage:
16
- opencode-host [generate] [--config <path>] [--out <path>] [--out-dir <path>] [--plugins-root <path>] [--plugin <name>] [--copy] [--print] [--no-slice-2]
16
+ opencode-host [generate] [--config <path>] [--out <path>] [--out-dir <path>] [--plugins-root <path>] [--host <host>] [--plugin <name>] [--copy] [--print] [--no-slice-2]
17
17
  opencode-host --version [--json]
18
18
  opencode-host --help
19
19
 
@@ -22,6 +22,9 @@ Options:
22
22
  -o, --out <path> Slice 1: path to write opencode.json (default: ./opencode.json)
23
23
  -d, --out-dir <path> Slice 2: dist root (default: ./dist/opencode)
24
24
  -p, --plugins-root <path> path to the plugins/ tree (default: ./plugins)
25
+ --host <host> OpenCode-compatible host: opencode | redcode (default: opencode)
26
+ --native-lsp the host answers navigation natively (default: redcode only)
27
+ --no-native-lsp the host has no LSP of its own \u2014 publish navigator
25
28
  --plugin <name> emit only this plugin (repeatable; Slice 2 only)
26
29
  --copy copy SKILL.md instead of symlinking
27
30
  --with-slice-2 emit the Slice 2 dist tree (default; kept for compatibility)
@@ -40,12 +43,15 @@ Notes:
40
43
  - The ADR 0067 strict opt-in gate applies: plugins.dev.enabled: true must be set.
41
44
  - Slice 1 (--out) is unaffected by --plugin/--no-slice-2; it is the standalone
42
45
  provider-block JSON file.
46
+ - A host with native LSP (redcode) omits the navigator MCP rather than
47
+ birthing a second language-server stack over the same tree. --no-native-lsp
48
+ puts it back.
43
49
  - Planner errors (bad name, missing frontmatter) are reported on stderr but
44
50
  do NOT fail the build. The events the generator can map are emitted.
45
- `}function Qe(e){let t=e.indexOf(" #");return(t>=0?e.slice(0,t):e).trim()}function q(e,t){let o=[];for(let n of e.split(`
46
- `)){let s=n.replace(/\r$/,""),i=s.trim();if(!i||i.startsWith("#"))continue;let r=s.indexOf(":");if(r<0)continue;let a=s.length-s.trimStart().length,c=s.slice(0,r).trim();if(!c)continue;let l=s.slice(r+1).trim();for(;o.length&&o[o.length-1].indent>=a;)o.pop();if(o.push({indent:a,key:c}),l&&o.map(f=>f.key).join(".")===t)return Qe(l)}}function ie(e,t){return q(e,`plugins.${t}.enabled`)==="true"}var et=Object.freeze({openrouter:{npm:"@openrouter/ai-sdk-provider",name:"OpenRouter"},minimax:{npm:"@ai-sdk/openai-compatible",name:"MiniMax",options:{baseURL:"https://api.minimax.chat/v1"}},openai:{npm:"@ai-sdk/openai",name:"OpenAI"}}),tt=Object.freeze([{env:"OPENAI_API_KEY",provider:"openai"},{env:"MINIMAX_API_KEY",provider:"minimax"},{env:"OPENROUTER_API_KEY",provider:"openrouter"}]);function H(e){for(let t of tt){let o=e[t.env];if(typeof o=="string"&&o.length>0)return t.provider}}function nt(e,t="think"){let o=q(e,`plugins.dev.afk.models.opencode.${t}.model`);return typeof o=="string"&&o.length>0?o:void 0}function ce(e){return ie(e,"dev")}var ot="openrouter/anthropic/claude-3.5-sonnet";function A(e){let t=H(e.env)??"openrouter",n=e.modelOverride??nt(e.configText)??ot,s={};for(let[r,a]of Object.entries(et))s[r]=a;let i={};i[t]=s[t];for(let[r,a]of Object.entries(s))r!==t&&(i[r]=a);return{$schema:"https://opencode.ai/config.json",provider:i,model:n}}import{mkdirSync as T,symlinkSync as Lt,writeFileSync as N,copyFileSync as we,readFileSync as Vt}from"node:fs";import{dirname as D,join as P,relative as Wt}from"node:path";import{existsSync as st,readdirSync as rt,readFileSync as it,statSync as ct}from"node:fs";import{basename as K,dirname as B,join as z,relative as at}from"node:path";var lt=/^[a-z0-9]+(-[a-z0-9]+)*$/,ae=1024,ut=new Set(["in-progress"]);function pt(e){return e.split(/[\\/]/)}function ft(e){if(!e.startsWith("---"))return{};let t=e.indexOf(`
47
- ---`,3);if(t<0)return{};let o=e.slice(3,t),n,s;for(let i of o.split(`
48
- `)){let r=i.trim();if(!r||r.startsWith("#"))continue;let a=r.indexOf(":");if(a<0)continue;let c=r.slice(0,a).trim(),l=r.slice(a+1).trim();(l.startsWith('"')&&l.endsWith('"')||l.startsWith("'")&&l.endsWith("'"))&&(l=l.slice(1,-1)),c==="name"?n=l:c==="description"&&(s=l)}return{name:n,description:s}}function dt(e,t){let o=z(e,t,"skills");if(!st(o))return[];let n=[],s=[o];for(;s.length>0;){let i=s.pop(),r;try{r=rt(i)}catch{continue}for(let a of r){let c=z(i,a),l;try{l=ct(c)}catch{continue}if(l.isDirectory()){if(ut.has(K(c)))continue;s.push(c)}else l.isFile()&&a==="SKILL.md"&&n.push(c)}}return n}function gt(e,t,o){let n=[],s=K(B(e)),i=K(B(B(e))),r=at(z(t,o,"skills"),e),a=pt(r);if(a.length!==3||a[2]!=="SKILL.md")return n.push({path:e,name:s,code:"name-not-valid",message:`${r} is not in the expected <bucket>/<name>/SKILL.md layout`}),{errors:n};if(!lt.test(s)||s.length>64)return n.push({path:e,name:s,code:"name-not-valid",message:`name "${s}" violates opencode's name rule: 1-64 chars, lowercase alphanumeric with single-hyphen separators (regex ^[a-z0-9]+(-[a-z0-9]+)*$)`}),{errors:n};let c;try{c=it(e,"utf8")}catch(f){return n.push({path:e,name:s,code:"frontmatter-missing",message:`could not read ${e}: ${f.message}`}),{errors:n}}let{name:l,description:u}=ft(c);return l?l!==s&&n.push({path:e,name:s,code:"name-not-equal-to-dir",message:`frontmatter name "${l}" does not match directory name "${s}" \u2014 opencode will refuse to load this skill`}):n.push({path:e,name:s,code:"name-missing",message:"frontmatter is missing the required `name:` field"}),u?u.length>ae&&n.push({path:e,name:s,code:"description-missing-or-too-long",message:`frontmatter description is ${u.length} chars, opencode's budget is ${ae}`}):n.push({path:e,name:s,code:"description-missing-or-too-long",message:"frontmatter is missing the required `description:` field"}),n.length>0?{errors:n}:{plan:{source:e,target:`skills/${s}/SKILL.md`,name:s,bucket:i},errors:[]}}function mt(e,t){let o=[],n=[];for(let s of dt(e,t)){let{plan:i,errors:r}=gt(s,e,t);i&&o.push(i),n.push(...r)}return o.sort((s,i)=>s.target.localeCompare(i.target)),{plans:o,errors:n}}function le(e,t){let o=t.map(n=>({plugin:n,result:mt(e,n)}));return ht(o),o}function ht(e){let t=new Map;for(let{plugin:o,result:n}of e)for(let s of n.plans)t.has(s.name)||t.set(s.name,new Set),t.get(s.name).add(o);for(let{plugin:o,result:n}of e){for(let s of n.plans){if((t.get(s.name)?.size??0)<2)continue;let i=`${o}-${s.name}`;s.renamedFrom=s.name,s.name=i,s.target=`skills/${i}/SKILL.md`}n.plans.sort((s,i)=>s.target.localeCompare(i.target))}}function ue(e,t){let o=e.match(/^---\r?\n([\s\S]*?)\r?\n---/);if(!o)return e;let n=o[1],s=n.replace(/^name:.*$/m,`name: ${t}`);return e.replace(n,s)}import{existsSync as yt,readFileSync as _t}from"node:fs";import{join as pe}from"node:path";var fe=Object.freeze({SessionStart:"config",PreToolUse:"tool.execute.before",PostToolUse:"tool.execute.after",Stop:"session.idle",PreCompact:"experimental.session.compacting",UserPromptSubmit:"chat.message"}),wt=Object.freeze({SessionStart:"plugin/session-start.ts",PreToolUse:"plugin/pre-tool-use.ts",PostToolUse:"plugin/post-tool-use.ts",Stop:"plugin/stop.ts",PreCompact:"plugin/pre-compact.ts",UserPromptSubmit:"plugin/user-prompt-submit.ts"}),kt=["codex.hooks.json","claude.hooks.json"];function xt(e,t){let o=pe(e,t,"hooks");return kt.map(n=>pe(o,n)).filter(n=>yt(n))}function vt(e,t){return e.replace(/\$\{CLAUDE_PLUGIN_ROOT\}/g,"${__pluginRoot}").replace(/\$\{CODEX_PLUGIN_ROOT\}/g,"${__pluginRoot}").replace(/\brsp-instructions --runner (claude|codex) --hook\b/g,"rsp-instructions --runner opencode --hook")}function $t(e){let t=e.hookGroups.some(s=>de(s.command.replace(/^sh -c\s*'/,"").replace(/'$/,""))),o=e.hookGroups.map(s=>{let i=me(s.matcher),r=s.command.replace(/^sh -c\s*'/,"").replace(/'$/,"");return de(r)?` if (${i}.test(input.tool)) {
51
+ `}function at(e){let t=e.indexOf(" #");return(t>=0?e.slice(0,t):e).trim()}function z(e,t){let n=[];for(let o of e.split(`
52
+ `)){let s=o.replace(/\r$/,""),i=s.trim();if(!i||i.startsWith("#"))continue;let r=s.indexOf(":");if(r<0)continue;let a=s.length-s.trimStart().length,c=s.slice(0,r).trim();if(!c)continue;let u=s.slice(r+1).trim();for(;n.length&&n[n.length-1].indent>=a;)n.pop();if(n.push({indent:a,key:c}),u&&n.map(f=>f.key).join(".")===t)return at(u)}}function pe(e,t){return z(e,`plugins.${t}.enabled`)==="true"}var lt=Object.freeze({openrouter:{npm:"@openrouter/ai-sdk-provider",name:"OpenRouter"},minimax:{npm:"@ai-sdk/openai-compatible",name:"MiniMax",options:{baseURL:"https://api.minimax.chat/v1"}},openai:{npm:"@ai-sdk/openai",name:"OpenAI"}}),ut=Object.freeze([{env:"OPENAI_API_KEY",provider:"openai"},{env:"MINIMAX_API_KEY",provider:"minimax"},{env:"OPENROUTER_API_KEY",provider:"openrouter"}]);function J(e){for(let t of ut){let n=e[t.env];if(typeof n=="string"&&n.length>0)return t.provider}}function pt(e,t="think"){let n=z(e,`plugins.dev.afk.models.opencode.${t}.model`);return typeof n=="string"&&n.length>0?n:void 0}function fe(e){return pe(e,"dev")}var ft="openrouter/anthropic/claude-3.5-sonnet";function j(e){let t=J(e.env)??"openrouter",o=e.modelOverride??pt(e.configText)??ft,s={};for(let[r,a]of Object.entries(lt))s[r]=a;let i={};i[t]=s[t];for(let[r,a]of Object.entries(s))r!==t&&(i[r]=a);return{$schema:"https://opencode.ai/config.json",provider:i,model:o}}import{mkdirSync as M,symlinkSync as Jt,writeFileSync as L,copyFileSync as $e,readFileSync as Zt}from"node:fs";import{dirname as U,join as P,relative as Yt}from"node:path";import{existsSync as dt,readdirSync as mt,readFileSync as gt,statSync as ht}from"node:fs";import{basename as Y,dirname as Z,join as X,relative as yt}from"node:path";var _t=/^[a-z0-9]+(-[a-z0-9]+)*$/,de=1024,wt=new Set(["in-progress"]);function kt(e){return e.split(/[\\/]/)}function vt(e){if(!e.startsWith("---"))return{};let t=e.indexOf(`
53
+ ---`,3);if(t<0)return{};let n=e.slice(3,t),o,s;for(let i of n.split(`
54
+ `)){let r=i.trim();if(!r||r.startsWith("#"))continue;let a=r.indexOf(":");if(a<0)continue;let c=r.slice(0,a).trim(),u=r.slice(a+1).trim();(u.startsWith('"')&&u.endsWith('"')||u.startsWith("'")&&u.endsWith("'"))&&(u=u.slice(1,-1)),c==="name"?o=u:c==="description"&&(s=u)}return{name:o,description:s}}function xt(e,t){let n=X(e,t,"skills");if(!dt(n))return[];let o=[],s=[n];for(;s.length>0;){let i=s.pop(),r;try{r=mt(i)}catch{continue}for(let a of r){let c=X(i,a),u;try{u=ht(c)}catch{continue}if(u.isDirectory()){if(wt.has(Y(c)))continue;s.push(c)}else u.isFile()&&a==="SKILL.md"&&o.push(c)}}return o}function bt(e,t,n){let o=[],s=Y(Z(e)),i=Y(Z(Z(e))),r=yt(X(t,n,"skills"),e),a=kt(r);if(a.length!==3||a[2]!=="SKILL.md")return o.push({path:e,name:s,code:"name-not-valid",message:`${r} is not in the expected <bucket>/<name>/SKILL.md layout`}),{errors:o};if(!_t.test(s)||s.length>64)return o.push({path:e,name:s,code:"name-not-valid",message:`name "${s}" violates opencode's name rule: 1-64 chars, lowercase alphanumeric with single-hyphen separators (regex ^[a-z0-9]+(-[a-z0-9]+)*$)`}),{errors:o};let c;try{c=gt(e,"utf8")}catch(f){return o.push({path:e,name:s,code:"frontmatter-missing",message:`could not read ${e}: ${f.message}`}),{errors:o}}let{name:u,description:l}=vt(c);return u?u!==s&&o.push({path:e,name:s,code:"name-not-equal-to-dir",message:`frontmatter name "${u}" does not match directory name "${s}" \u2014 opencode will refuse to load this skill`}):o.push({path:e,name:s,code:"name-missing",message:"frontmatter is missing the required `name:` field"}),l?l.length>de&&o.push({path:e,name:s,code:"description-missing-or-too-long",message:`frontmatter description is ${l.length} chars, opencode's budget is ${de}`}):o.push({path:e,name:s,code:"description-missing-or-too-long",message:"frontmatter is missing the required `description:` field"}),o.length>0?{errors:o}:{plan:{source:e,target:`skills/${s}/SKILL.md`,name:s,bucket:i},errors:[]}}function $t(e,t){let n=[],o=[];for(let s of xt(e,t)){let{plan:i,errors:r}=bt(s,e,t);i&&n.push(i),o.push(...r)}return n.sort((s,i)=>s.target.localeCompare(i.target)),{plans:n,errors:o}}function me(e,t){let n=t.map(o=>({plugin:o,result:$t(e,o)}));return St(n),n}function St(e){let t=new Map;for(let{plugin:n,result:o}of e)for(let s of o.plans)t.has(s.name)||t.set(s.name,new Set),t.get(s.name).add(n);for(let{plugin:n,result:o}of e){for(let s of o.plans){if((t.get(s.name)?.size??0)<2)continue;let i=`${n}-${s.name}`;s.renamedFrom=s.name,s.name=i,s.target=`skills/${i}/SKILL.md`}o.plans.sort((s,i)=>s.target.localeCompare(i.target))}}function ge(e,t){let n=e.match(/^---\r?\n([\s\S]*?)\r?\n---/);if(!n)return e;let o=n[1],s=o.replace(/^name:.*$/m,`name: ${t}`);return e.replace(o,s)}import{existsSync as Ot,readFileSync as Pt}from"node:fs";import{join as he}from"node:path";var ye=Object.freeze({SessionStart:"config",PreToolUse:"tool.execute.before",PostToolUse:"tool.execute.after",Stop:"session.idle",PreCompact:"experimental.session.compacting",UserPromptSubmit:"chat.message"}),Et=Object.freeze({SessionStart:"plugin/session-start.ts",PreToolUse:"plugin/pre-tool-use.ts",PostToolUse:"plugin/post-tool-use.ts",Stop:"plugin/stop.ts",PreCompact:"plugin/pre-compact.ts",UserPromptSubmit:"plugin/user-prompt-submit.ts"}),Rt=["codex.hooks.json","claude.hooks.json"];function At(e,t){let n=he(e,t,"hooks");return Rt.map(o=>he(n,o)).filter(o=>Ot(o))}function Ct(e,t){return e.replace(/\$\{CLAUDE_PLUGIN_ROOT\}/g,"${__pluginRoot}").replace(/\$\{CODEX_PLUGIN_ROOT\}/g,"${__pluginRoot}").replace(/\brsp-instructions --runner (claude|codex) --hook\b/g,"rsp-instructions --runner opencode --hook")}function Tt(e){let t=e.hookGroups.some(s=>_e(s.command.replace(/^sh -c\s*'/,"").replace(/'$/,""))),n=e.hookGroups.map(s=>{let i=ke(s.matcher),r=s.command.replace(/^sh -c\s*'/,"").replace(/'$/,"");return _e(r)?` if (${i}.test(input.tool)) {
49
55
  const __rewritten = await __runRspRewrite(${JSON.stringify(r)});
50
56
  if (__rewritten !== null && output.args && typeof output.args === "object" && "command" in output.args) {
51
57
  output.args = { ...output.args, command: __rewritten };
@@ -54,19 +60,19 @@ Notes:
54
60
  const __blocked = await __runHook(${JSON.stringify(r)});
55
61
  if (__blocked) return;
56
62
  }`}).join(`
57
- `);return["// generated by @reddb-io/red-skills \u2014 slice 2 (hooks \u2192 events)","// ADR 0077: PreToolUse \u2192 tool.execute.before","// do not edit by hand \u2014 re-run the generator to refresh.","",'import type { Plugin } from "@opencode-ai/plugin";',"","export const PreToolUse: Plugin = async (context) => {"," return {",' "tool.execute.before": async (input: { tool: string; sessionID?: string; callID?: string }, output: { args: Record<string, unknown> }) => {'," const __encoder = new TextEncoder();"," const __decoder = new TextDecoder();"," const __pluginRoot = context.directory;"," const __cwd = context.worktree;"," const __payload = JSON.stringify({",' hook_event_name: "PreToolUse",'," tool_name: input.tool,"," tool_input: output.args ?? {},"," cwd: __cwd,"," workspace: { current_dir: __cwd },"," });",` const __shellQuote = (value: string): string => \`'\${value.replaceAll("'", "'\\\\''")}'\`;`," const __denyCommand = (reason: string, code: number): string => `printf '%s\\\\n' ${__shellQuote(reason)} >&2; exit ${code}`;"," const __runHook = async (inner: string): Promise<boolean> => {"," const proc = Bun.$`sh -c ${inner}`.env({ __pluginRoot, CLAUDE_PLUGIN_ROOT: __pluginRoot, CODEX_PLUGIN_ROOT: __pluginRoot, OPENCODE_PLUGIN_ROOT: __pluginRoot }).quiet().nothrow();"," try {"," const writer = proc.stdin.getWriter();"," await writer.write(__encoder.encode(__payload));"," await writer.close();"," } catch { /* hook exited before draining stdin (EPIPE) */ }"," const result = await proc;"," const stdout = __decoder.decode(result.stdout).trim();",' let structuredReason = "";'," if (stdout.length > 0) {"," try {"," const parsed = JSON.parse(stdout) as { decision?: string; reason?: string; hookSpecificOutput?: { permissionDecision?: string; permissionDecisionReason?: string } };",' if (parsed.decision === "block" || parsed.hookSpecificOutput?.permissionDecision === "deny") {'," structuredReason = parsed.hookSpecificOutput?.permissionDecisionReason || parsed.reason || `RedSkills PreToolUse hook denied ${input.tool}.`;"," }"," } catch { /* non-JSON stdout is ignored */ }"," }"," if (result.exitCode === 0 && structuredReason.length === 0) return false;"," const stderr = __decoder.decode(result.stderr).trim();"," const reason = structuredReason || (stderr.length > 0 ? stderr : `RedSkills PreToolUse hook denied ${input.tool}.`);",' if (output.args && typeof output.args === "object" && "command" in output.args) {'," output.args = { ...output.args, command: __denyCommand(reason, result.exitCode) };"," return true;"," }"," throw new Error(reason);"," };",...t?[" const __runRspRewrite = async (inner: string): Promise<string | null> => {"," const proc = Bun.$`sh -c ${inner}`.env({ __pluginRoot, CLAUDE_PLUGIN_ROOT: __pluginRoot, CODEX_PLUGIN_ROOT: __pluginRoot, OPENCODE_PLUGIN_ROOT: __pluginRoot }).quiet().nothrow();"," try {"," const writer = proc.stdin.getWriter();"," await writer.write(__encoder.encode(__payload));"," await writer.close();"," } catch { /* hook exited before draining stdin (EPIPE) */ }"," const result = await proc;"," if (result.exitCode !== 0) return null;"," const rewritten = __decoder.decode(result.stdout).trim();"," return rewritten.length > 0 ? rewritten : null;"," };"]:[],o," },"," };","};",""].join(`
58
- `)}function bt(e){return["// generated by @reddb-io/red-skills \u2014 slice 2 (hooks \u2192 events)","// ADR 0077: SessionStart \u2192 config + chat system context","// do not edit by hand \u2014 re-run the generator to refresh.","",'import type { Plugin } from "@opencode-ai/plugin";',"","export const SessionStart: Plugin = async (context) => {"," let __ran = false;"," const __sessionContext: string[] = [];"," const __encoder = new TextEncoder();"," const __decoder = new TextDecoder();"," const __pluginRoot = context.directory;"," const __cwd = context.worktree;"," const __payload = JSON.stringify({",' hook_event_name: "SessionStart",'," cwd: __cwd,"," workspace: { current_dir: __cwd },"," });"," const __extractContext = (stdout: string): string | null => {"," const text = stdout.trim();",' if (!text || text === "{}") return null;'," try {"," const parsed = JSON.parse(text) as { systemMessage?: unknown; hookSpecificOutput?: { additionalContext?: unknown } };",' const direct = typeof parsed.systemMessage === "string" ? parsed.systemMessage : null;',' const claude = typeof parsed.hookSpecificOutput?.additionalContext === "string" ? parsed.hookSpecificOutput.additionalContext : null;'," return direct ?? claude;"," } catch {"," return text;"," }"," };"," const __runSessionStart = async (inner: string): Promise<void> => {"," try {"," const proc = Bun.$`sh -c ${inner}`.env({ __pluginRoot, CLAUDE_PLUGIN_ROOT: __pluginRoot, CODEX_PLUGIN_ROOT: __pluginRoot, OPENCODE_PLUGIN_ROOT: __pluginRoot }).quiet().nothrow();"," try {"," const writer = proc.stdin.getWriter();"," await writer.write(__encoder.encode(__payload));"," await writer.close();"," } catch { /* hook exited before draining stdin (EPIPE) */ }"," const result = await proc;"," const ctx = __extractContext(__decoder.decode(result.stdout));"," if (ctx && !__sessionContext.includes(ctx)) __sessionContext.push(ctx);"," } catch { /* best-effort */ }"," };"," const __runOnce = async (): Promise<void> => {"," if (__ran) return;"," __ran = true;",e.commands.map(o=>{let n=o.replace(/^sh -c\s*'/,"").replace(/'$/,"");return[` await __runSessionStart(${JSON.stringify(n)});`].join(`
63
+ `);return["// generated by @reddb-io/red-skills \u2014 slice 2 (hooks \u2192 events)","// ADR 0077: PreToolUse \u2192 tool.execute.before","// do not edit by hand \u2014 re-run the generator to refresh.","",'import type { Plugin } from "@opencode-ai/plugin";',"","export const PreToolUse: Plugin = async (context) => {"," return {",' "tool.execute.before": async (input: { tool: string; sessionID?: string; callID?: string }, output: { args: Record<string, unknown> }) => {'," const __encoder = new TextEncoder();"," const __decoder = new TextDecoder();"," const __pluginRoot = context.directory;"," const __cwd = context.worktree;"," const __payload = JSON.stringify({",' hook_event_name: "PreToolUse",'," tool_name: input.tool,"," tool_input: output.args ?? {},"," cwd: __cwd,"," workspace: { current_dir: __cwd },"," });",` const __shellQuote = (value: string): string => \`'\${value.replaceAll("'", "'\\\\''")}'\`;`," const __denyCommand = (reason: string, code: number): string => `printf '%s\\\\n' ${__shellQuote(reason)} >&2; exit ${code}`;"," const __runHook = async (inner: string): Promise<boolean> => {"," const proc = Bun.$`sh -c ${inner}`.env({ __pluginRoot, CLAUDE_PLUGIN_ROOT: __pluginRoot, CODEX_PLUGIN_ROOT: __pluginRoot, OPENCODE_PLUGIN_ROOT: __pluginRoot }).quiet().nothrow();"," try {"," const writer = proc.stdin.getWriter();"," await writer.write(__encoder.encode(__payload));"," await writer.close();"," } catch { /* hook exited before draining stdin (EPIPE) */ }"," const result = await proc;"," const stdout = __decoder.decode(result.stdout).trim();",' let structuredReason = "";'," if (stdout.length > 0) {"," try {"," const parsed = JSON.parse(stdout) as { decision?: string; reason?: string; hookSpecificOutput?: { permissionDecision?: string; permissionDecisionReason?: string } };",' if (parsed.decision === "block" || parsed.hookSpecificOutput?.permissionDecision === "deny") {'," structuredReason = parsed.hookSpecificOutput?.permissionDecisionReason || parsed.reason || `RedSkills PreToolUse hook denied ${input.tool}.`;"," }"," } catch { /* non-JSON stdout is ignored */ }"," }"," if (result.exitCode === 0 && structuredReason.length === 0) return false;"," const stderr = __decoder.decode(result.stderr).trim();"," const reason = structuredReason || (stderr.length > 0 ? stderr : `RedSkills PreToolUse hook denied ${input.tool}.`);",' if (output.args && typeof output.args === "object" && "command" in output.args) {'," output.args = { ...output.args, command: __denyCommand(reason, result.exitCode) };"," return true;"," }"," throw new Error(reason);"," };",...t?[" const __runRspRewrite = async (inner: string): Promise<string | null> => {"," const proc = Bun.$`sh -c ${inner}`.env({ __pluginRoot, CLAUDE_PLUGIN_ROOT: __pluginRoot, CODEX_PLUGIN_ROOT: __pluginRoot, OPENCODE_PLUGIN_ROOT: __pluginRoot }).quiet().nothrow();"," try {"," const writer = proc.stdin.getWriter();"," await writer.write(__encoder.encode(__payload));"," await writer.close();"," } catch { /* hook exited before draining stdin (EPIPE) */ }"," const result = await proc;"," if (result.exitCode !== 0) return null;"," const rewritten = __decoder.decode(result.stdout).trim();"," return rewritten.length > 0 ? rewritten : null;"," };"]:[],n," },"," };","};",""].join(`
64
+ `)}function It(e){return["// generated by @reddb-io/red-skills \u2014 slice 2 (hooks \u2192 events)","// ADR 0077: SessionStart \u2192 config + chat system context","// do not edit by hand \u2014 re-run the generator to refresh.","",'import type { Plugin } from "@opencode-ai/plugin";',"","export const SessionStart: Plugin = async (context) => {"," let __ran = false;"," const __sessionContext: string[] = [];"," const __encoder = new TextEncoder();"," const __decoder = new TextDecoder();"," const __pluginRoot = context.directory;"," const __cwd = context.worktree;"," const __payload = JSON.stringify({",' hook_event_name: "SessionStart",'," cwd: __cwd,"," workspace: { current_dir: __cwd },"," });"," const __extractContext = (stdout: string): string | null => {"," const text = stdout.trim();",' if (!text || text === "{}") return null;'," try {"," const parsed = JSON.parse(text) as { systemMessage?: unknown; hookSpecificOutput?: { additionalContext?: unknown } };",' const direct = typeof parsed.systemMessage === "string" ? parsed.systemMessage : null;',' const claude = typeof parsed.hookSpecificOutput?.additionalContext === "string" ? parsed.hookSpecificOutput.additionalContext : null;'," return direct ?? claude;"," } catch {"," return text;"," }"," };"," const __runSessionStart = async (inner: string): Promise<void> => {"," try {"," const proc = Bun.$`sh -c ${inner}`.env({ __pluginRoot, CLAUDE_PLUGIN_ROOT: __pluginRoot, CODEX_PLUGIN_ROOT: __pluginRoot, OPENCODE_PLUGIN_ROOT: __pluginRoot }).quiet().nothrow();"," try {"," const writer = proc.stdin.getWriter();"," await writer.write(__encoder.encode(__payload));"," await writer.close();"," } catch { /* hook exited before draining stdin (EPIPE) */ }"," const result = await proc;"," const ctx = __extractContext(__decoder.decode(result.stdout));"," if (ctx && !__sessionContext.includes(ctx)) __sessionContext.push(ctx);"," } catch { /* best-effort */ }"," };"," const __runOnce = async (): Promise<void> => {"," if (__ran) return;"," __ran = true;",e.commands.map(n=>{let o=n.replace(/^sh -c\s*'/,"").replace(/'$/,"");return[` await __runSessionStart(${JSON.stringify(o)});`].join(`
59
65
  `)}).join(`
60
66
  `)," };"," return {"," config: async () => {"," await __runOnce();"," },",' "experimental.chat.system.transform": async (_input: { sessionID?: string }, output: { system: string[] }) => {'," await __runOnce();"," for (const ctx of __sessionContext) output.system.push(ctx);"," },"," };","};",""].join(`
61
- `)}function I(e){return[" const __encoder = new TextEncoder();"," const __decoder = new TextDecoder();"," const __pluginRoot = context.directory;"," const __cwd = context.worktree;"," const __runHook = async (inner: string, payload: Record<string, unknown>): Promise<string | null> => {"," try {"," const proc = Bun.$`sh -c ${inner}`.env({ __pluginRoot, CLAUDE_PLUGIN_ROOT: __pluginRoot, CODEX_PLUGIN_ROOT: __pluginRoot, OPENCODE_PLUGIN_ROOT: __pluginRoot }).quiet().nothrow();"," try {"," const writer = proc.stdin.getWriter();"," await writer.write(__encoder.encode(JSON.stringify(payload)));"," await writer.close();"," } catch { /* hook exited before draining stdin (EPIPE) */ }"," const result = await proc;"," return __decoder.decode(result.stdout).trim();"," } catch {"," return null;"," }"," };"," const __extractContext = (stdout: string | null): string | null => {",' const text = (stdout ?? "").trim();',' if (!text || text === "{}") return null;'," try {"," const parsed = JSON.parse(text) as { systemMessage?: unknown; hookSpecificOutput?: { additionalContext?: unknown } };",' const direct = typeof parsed.systemMessage === "string" ? parsed.systemMessage : null;',' const claude = typeof parsed.hookSpecificOutput?.additionalContext === "string" ? parsed.hookSpecificOutput.additionalContext : null;'," return direct ?? claude;"," } catch {"," return text;"," }"," };",` const __sourceEvent = ${JSON.stringify(e)};`]}function j(e){return e.hookGroups.map(t=>{let o=t.command.replace(/^sh -c\s*'/,"").replace(/'$/,""),n=[` const __stdout = await __runHook(${JSON.stringify(o)}, ${e.payloadExpression});`,e.contextSink?` const __ctx = __extractContext(__stdout); if (__ctx) ${e.contextSink};`:""].filter(Boolean).join(`
62
- `);return e.toolExpression?[` if (${me(t.matcher)}.test(${e.toolExpression})) {`,n," }"].join(`
63
- `):[" {",n," }"].join(`
67
+ `)}function F(e){return[" const __encoder = new TextEncoder();"," const __decoder = new TextDecoder();"," const __pluginRoot = context.directory;"," const __cwd = context.worktree;"," const __runHook = async (inner: string, payload: Record<string, unknown>): Promise<string | null> => {"," try {"," const proc = Bun.$`sh -c ${inner}`.env({ __pluginRoot, CLAUDE_PLUGIN_ROOT: __pluginRoot, CODEX_PLUGIN_ROOT: __pluginRoot, OPENCODE_PLUGIN_ROOT: __pluginRoot }).quiet().nothrow();"," try {"," const writer = proc.stdin.getWriter();"," await writer.write(__encoder.encode(JSON.stringify(payload)));"," await writer.close();"," } catch { /* hook exited before draining stdin (EPIPE) */ }"," const result = await proc;"," return __decoder.decode(result.stdout).trim();"," } catch {"," return null;"," }"," };"," const __extractContext = (stdout: string | null): string | null => {",' const text = (stdout ?? "").trim();',' if (!text || text === "{}") return null;'," try {"," const parsed = JSON.parse(text) as { systemMessage?: unknown; hookSpecificOutput?: { additionalContext?: unknown } };",' const direct = typeof parsed.systemMessage === "string" ? parsed.systemMessage : null;',' const claude = typeof parsed.hookSpecificOutput?.additionalContext === "string" ? parsed.hookSpecificOutput.additionalContext : null;'," return direct ?? claude;"," } catch {"," return text;"," }"," };",` const __sourceEvent = ${JSON.stringify(e)};`]}function N(e){return e.hookGroups.map(t=>{let n=t.command.replace(/^sh -c\s*'/,"").replace(/'$/,""),o=[` const __stdout = await __runHook(${JSON.stringify(n)}, ${e.payloadExpression});`,e.contextSink?` const __ctx = __extractContext(__stdout); if (__ctx) ${e.contextSink};`:""].filter(Boolean).join(`
68
+ `);return e.toolExpression?[` if (${ke(t.matcher)}.test(${e.toolExpression})) {`,o," }"].join(`
69
+ `):[" {",o," }"].join(`
64
70
  `)}).join(`
65
- `)}function Ot(e){return["// generated by @reddb-io/red-skills \u2014 slice 2 (hooks \u2192 events)","// ADR 0077: PostToolUse \u2192 tool.execute.after","// do not edit by hand \u2014 re-run the generator to refresh.","",'import type { Plugin } from "@opencode-ai/plugin";',"","export const PostToolUse: Plugin = async (context) => {"," return {",' "tool.execute.after": async (input: { tool: string; sessionID?: string; callID?: string; args?: Record<string, unknown> }, output: { title?: string; output?: string; metadata?: unknown }) => {',...I("PostToolUse")," const __payload = {"," hook_event_name: __sourceEvent,"," session_id: input.sessionID,"," tool_name: input.tool,"," tool_input: input.args ?? {},"," tool_response: { title: output.title, output: output.output, metadata: output.metadata },"," cwd: __cwd,"," workspace: { current_dir: __cwd },"," };",j({hookGroups:e.hookGroups,toolExpression:"input.tool",payloadExpression:"__payload",contextSink:'output.output = [__ctx, output.output].filter(Boolean).join("\\n\\n")'})," },"," };","};",""].join(`
66
- `)}function ge(){return[" const __textParts = (value: unknown, out: string[] = []): string[] => {",' if (typeof value === "string") return out;',' if (!value || typeof value !== "object") return out;'," if (Array.isArray(value)) { for (const item of value) __textParts(item, out); return out; }"," const record = value as Record<string, unknown>;",' for (const key of ["text", "content", "message", "output"] as const) {',' if (typeof record[key] === "string") out.push(record[key] as string);'," }"," for (const child of Object.values(record)) __textParts(child, out);"," return out;"," };"," const __readSessionTranscript = async (sessionID?: string): Promise<string | undefined> => {"," if (!sessionID) return undefined;"," const sessionApi = (context.client as unknown as { session?: { messages?: (input: unknown) => Promise<unknown> } }).session;"," if (!sessionApi?.messages) return undefined;"," const attempts = [{ path: { id: sessionID } }, { path: { sessionID } }, { id: sessionID }, { sessionID }];"," for (const attempt of attempts) {"," try {"," const response = await sessionApi.messages(attempt);"," const data = (response as { data?: unknown })?.data ?? response;",' const text = __textParts(data).join("\\n").trim();'," if (text.length > 0) return text;"," return JSON.stringify(data);"," } catch { /* try the next SDK shape */ }"," }"," return undefined;"," };"]}function St(e){return["// generated by @reddb-io/red-skills \u2014 slice 2 (hooks \u2192 events)","// ADR 0077: Stop \u2192 session.idle","// do not edit by hand \u2014 re-run the generator to refresh.","",'import type { Plugin } from "@opencode-ai/plugin";',"","export const Stop: Plugin = async (context) => {"," return {",' "session.idle": async (input: { sessionID?: string }) => {',...I("Stop"),...ge()," const __transcript = await __readSessionTranscript(input.sessionID);"," const __payload = {"," hook_event_name: __sourceEvent,"," session_id: input.sessionID,"," transcript_text: __transcript,"," transcriptText: __transcript,"," cwd: __cwd,"," workspace: { current_dir: __cwd },"," };",j({hookGroups:e.hookGroups,payloadExpression:"__payload"})," },"," };","};",""].join(`
67
- `)}function Pt(e){return["// generated by @reddb-io/red-skills \u2014 slice 2 (hooks \u2192 events)","// ADR 0077: PreCompact \u2192 experimental.session.compacting","// do not edit by hand \u2014 re-run the generator to refresh.","",'import type { Plugin } from "@opencode-ai/plugin";',"","export const PreCompact: Plugin = async (context) => {"," return {",' "experimental.session.compacting": async (input: { sessionID?: string }, output: { context: string[]; prompt?: string }) => {',...I("PreCompact"),...ge()," const __transcript = await __readSessionTranscript(input.sessionID);"," const __payload = {"," hook_event_name: __sourceEvent,"," session_id: input.sessionID,"," transcript_text: __transcript,"," transcriptText: __transcript,"," cwd: __cwd,"," workspace: { current_dir: __cwd },"," };",j({hookGroups:e.hookGroups,payloadExpression:"__payload",contextSink:"output.context.push(__ctx)"})," },"," };","};",""].join(`
68
- `)}function Et(e){return["// generated by @reddb-io/red-skills \u2014 slice 2 (hooks \u2192 events)","// ADR 0077: UserPromptSubmit \u2192 chat.message","// do not edit by hand \u2014 re-run the generator to refresh.","",'import type { Plugin } from "@opencode-ai/plugin";',"","export const UserPromptSubmit: Plugin = async (context) => {"," return {",' "chat.message": async (input: { sessionID?: string; messageID?: string }, output: { message?: unknown; parts: unknown[] }) => {',...I("UserPromptSubmit")," const __payload = {"," hook_event_name: __sourceEvent,"," session_id: input.sessionID,"," message_id: input.messageID,"," prompt: output.message,"," cwd: __cwd,"," workspace: { current_dir: __cwd },"," };",j({hookGroups:e.hookGroups,payloadExpression:"__payload",contextSink:'output.parts.unshift({ type: "text", text: __ctx } as never)'})," },"," };","};",""].join(`
69
- `)}function de(e){return e.includes("hook claude-pre-exec")||e.includes("rsp-hook.sh")&&e.includes("claude-pre-exec")}function me(e){if(e==="*"||e==="")return"/.*/";let t=e.split("|").map(n=>n.trim()).filter(Boolean);return t.length===0?"/.*/":`/^(${t.map(n=>n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")).join("|")})$/i`}function he(e,t){let o=xt(e,t);if(o.length===0)return[];let n=new Map,s=[];for(let r of o){let a;try{a=JSON.parse(_t(r,"utf8"))}catch(c){s.push(`could not parse ${r}: ${c.message}`);continue}for(let[c,l]of Object.entries(a.hooks??{})){if(!fe[c]){s.push(`event "${c}" from ${r} has no known OpenCode plugin event equivalent (warn-and-continue)`);continue}let f=n.get(c)??[];for(let p of l){let d=p.matcher??"*";for(let y of p.hooks){if(y.type!=="command")continue;let h=vt(y.command,t);f.push({matcher:d,command:h,sourceFile:r})}}n.set(c,f)}}let i=[];for(let[r,a]of n){let c=fe[r],l=wt[r];!c||!l||(r==="SessionStart"?i.push({sourceEvent:r,opencodeEvent:c,target:l,source:bt({sourceFiles:a.map(u=>u.sourceFile),commands:a.map(u=>u.command)}),sourceFiles:a.map(u=>u.sourceFile),warnings:s}):r==="PreToolUse"?i.push({sourceEvent:r,opencodeEvent:c,target:l,source:$t({sourceFiles:a.map(u=>u.sourceFile),hookGroups:a}),sourceFiles:a.map(u=>u.sourceFile),warnings:s}):r==="PostToolUse"?i.push({sourceEvent:r,opencodeEvent:c,target:l,source:Ot({sourceFiles:a.map(u=>u.sourceFile),hookGroups:a}),sourceFiles:a.map(u=>u.sourceFile),warnings:s}):r==="Stop"?i.push({sourceEvent:r,opencodeEvent:c,target:l,source:St({sourceFiles:a.map(u=>u.sourceFile),hookGroups:a}),sourceFiles:a.map(u=>u.sourceFile),warnings:s}):r==="PreCompact"?i.push({sourceEvent:r,opencodeEvent:c,target:l,source:Pt({sourceFiles:a.map(u=>u.sourceFile),hookGroups:a}),sourceFiles:a.map(u=>u.sourceFile),warnings:s}):r==="UserPromptSubmit"&&i.push({sourceEvent:r,opencodeEvent:c,target:l,source:Et({sourceFiles:a.map(u=>u.sourceFile),hookGroups:a}),sourceFiles:a.map(u=>u.sourceFile),warnings:s}))}return i}import{existsSync as J,readFileSync as Rt,statSync as Ct}from"node:fs";import{homedir as ye}from"node:os";import{join as $}from"node:path";function At(e,t){let o=$(e,t,".mcp.json");if(!J(o))return null;try{return JSON.parse(Rt(o,"utf8"))}catch{return null}}function It(e,t,o){let n=[$(e,t,o),$(e,t,"hooks",o.split("/").pop()??""),$(e,"..",o),$(e,"..","..",".codex",".tmp","marketplaces","red-skills","plugins",t,o),$(ye(),".codex","plugins","cache","red-skills",t,o)];for(let s of n.slice(0,3))if(J(s))return{path:s,candidate:s};for(let s of n.slice(3))if(J(s))return{path:s,candidate:s};return{path:null,candidate:n[0]??null}}function jt(e,t=ye()){for(let o of e.matchAll(/\$HOME\/([\w./-]+)/g)){let n=$(t,o[1]);try{if(Ct(n).isFile())return n}catch{}}return null}function Ft(e,t,o,n){let s=[],i=n.command??"sh",r=n.args??[],a=n.env;if(i==="sh"&&r[0]==="-c"&&typeof r[1]=="string")return Tt(e,t,o,r[1],a);let c={type:"local",command:[i,...r],enabled:!0};return a&&(c.environment=a),{entry:c,warnings:s}}function Tt(e,t,o,n,s){let i=[],r=[/\$\{?CODEX_PLUGIN_ROOT\}?\/(?:\$\{?CLAUDE_PLUGIN_ROOT\}?\/)?([\w./-]+)/,/\$\{?CLAUDE_PLUGIN_ROOT\}?\/(?:\$\{?CODEX_PLUGIN_ROOT\}?\/)?([\w./-]+)/,/\$root\/([\w./-]+)/g],a=[];for(let p of r)if(p.flags&&p.flags.includes("g")){let d=n.matchAll(p);for(let y of d)a.push(y[1])}else{let d=n.match(p);d&&d[1]&&a.push(d[1])}let c=null;for(let p of a){let{path:d}=It(e,t,p);if(d){c=d;break}}if(c||(c=jt(n)),!c){i.push(`${o}: could not resolve any of the script paths referenced by the source hooks (${a.slice(0,3).join(", ")}) \u2014 the plugin checkout or a Codex cache must exist for this MCP to start`);let p={type:"local",command:["sh","-c",n],enabled:!0};return s&&(p.environment=s),{entry:p,warnings:i}}let l=c.endsWith(".mjs")?"node":c.endsWith(".sh")?"bash":"sh",u=n.match(/mcp(?=['"\s;|&]|$)/)?["mcp"]:[],f={type:"local",command:[l,c,...u],cwd:e,enabled:!0};return s&&(f.environment=s),{entry:f,warnings:i}}function F(e,t){let o=At(e,t);if(!o?.mcpServers)return[];let n=[];for(let[s,i]of Object.entries(o.mcpServers)){let{entry:r,warnings:a}=Ft(e,t,s,i);n.push({name:s,entry:r,warnings:a})}return n.sort((s,i)=>s.name.localeCompare(i.name)),n}import{existsSync as Nt}from"node:fs";import{join as Dt}from"node:path";function Ut(e){let t=[Dt(e,"dev","skills","engineering","afk","bin","afk.mjs")];for(let o of t)if(Nt(o))return{path:o};return{path:null}}function _e(e,t){if(t!=="dev")return[];let{path:o}=Ut(e),n=[];return o||n.push("dev: AFK launcher not found at plugins/dev/skills/engineering/afk/bin/afk.mjs \u2014 the session-status module will be a silent no-op until the launcher is built"),[{plugin:t,target:"plugin/session-status.ts",source:Mt,warnings:n}]}var Mt=`// generated by @reddb-io/red-skills \u2014 slice 4 (statusline + toasts)
71
+ `)}function jt(e){return["// generated by @reddb-io/red-skills \u2014 slice 2 (hooks \u2192 events)","// ADR 0077: PostToolUse \u2192 tool.execute.after","// do not edit by hand \u2014 re-run the generator to refresh.","",'import type { Plugin } from "@opencode-ai/plugin";',"","export const PostToolUse: Plugin = async (context) => {"," return {",' "tool.execute.after": async (input: { tool: string; sessionID?: string; callID?: string; args?: Record<string, unknown> }, output: { title?: string; output?: string; metadata?: unknown }) => {',...F("PostToolUse")," const __payload = {"," hook_event_name: __sourceEvent,"," session_id: input.sessionID,"," tool_name: input.tool,"," tool_input: input.args ?? {},"," tool_response: { title: output.title, output: output.output, metadata: output.metadata },"," cwd: __cwd,"," workspace: { current_dir: __cwd },"," };",N({hookGroups:e.hookGroups,toolExpression:"input.tool",payloadExpression:"__payload",contextSink:'output.output = [__ctx, output.output].filter(Boolean).join("\\n\\n")'})," },"," };","};",""].join(`
72
+ `)}function we(){return[" const __textParts = (value: unknown, out: string[] = []): string[] => {",' if (typeof value === "string") return out;',' if (!value || typeof value !== "object") return out;'," if (Array.isArray(value)) { for (const item of value) __textParts(item, out); return out; }"," const record = value as Record<string, unknown>;",' for (const key of ["text", "content", "message", "output"] as const) {',' if (typeof record[key] === "string") out.push(record[key] as string);'," }"," for (const child of Object.values(record)) __textParts(child, out);"," return out;"," };"," const __readSessionTranscript = async (sessionID?: string): Promise<string | undefined> => {"," if (!sessionID) return undefined;"," const sessionApi = (context.client as unknown as { session?: { messages?: (input: unknown) => Promise<unknown> } }).session;"," if (!sessionApi?.messages) return undefined;"," const attempts = [{ path: { id: sessionID } }, { path: { sessionID } }, { id: sessionID }, { sessionID }];"," for (const attempt of attempts) {"," try {"," const response = await sessionApi.messages(attempt);"," const data = (response as { data?: unknown })?.data ?? response;",' const text = __textParts(data).join("\\n").trim();'," if (text.length > 0) return text;"," return JSON.stringify(data);"," } catch { /* try the next SDK shape */ }"," }"," return undefined;"," };"]}function Ft(e){return["// generated by @reddb-io/red-skills \u2014 slice 2 (hooks \u2192 events)","// ADR 0077: Stop \u2192 session.idle","// do not edit by hand \u2014 re-run the generator to refresh.","",'import type { Plugin } from "@opencode-ai/plugin";',"","export const Stop: Plugin = async (context) => {"," return {",' "session.idle": async (input: { sessionID?: string }) => {',...F("Stop"),...we()," const __transcript = await __readSessionTranscript(input.sessionID);"," const __payload = {"," hook_event_name: __sourceEvent,"," session_id: input.sessionID,"," transcript_text: __transcript,"," transcriptText: __transcript,"," cwd: __cwd,"," workspace: { current_dir: __cwd },"," };",N({hookGroups:e.hookGroups,payloadExpression:"__payload"})," },"," };","};",""].join(`
73
+ `)}function Nt(e){return["// generated by @reddb-io/red-skills \u2014 slice 2 (hooks \u2192 events)","// ADR 0077: PreCompact \u2192 experimental.session.compacting","// do not edit by hand \u2014 re-run the generator to refresh.","",'import type { Plugin } from "@opencode-ai/plugin";',"","export const PreCompact: Plugin = async (context) => {"," return {",' "experimental.session.compacting": async (input: { sessionID?: string }, output: { context: string[]; prompt?: string }) => {',...F("PreCompact"),...we()," const __transcript = await __readSessionTranscript(input.sessionID);"," const __payload = {"," hook_event_name: __sourceEvent,"," session_id: input.sessionID,"," transcript_text: __transcript,"," transcriptText: __transcript,"," cwd: __cwd,"," workspace: { current_dir: __cwd },"," };",N({hookGroups:e.hookGroups,payloadExpression:"__payload",contextSink:"output.context.push(__ctx)"})," },"," };","};",""].join(`
74
+ `)}function Dt(e){return["// generated by @reddb-io/red-skills \u2014 slice 2 (hooks \u2192 events)","// ADR 0077: UserPromptSubmit \u2192 chat.message","// do not edit by hand \u2014 re-run the generator to refresh.","",'import type { Plugin } from "@opencode-ai/plugin";',"","export const UserPromptSubmit: Plugin = async (context) => {"," return {",' "chat.message": async (input: { sessionID?: string; messageID?: string }, output: { message?: unknown; parts: unknown[] }) => {',...F("UserPromptSubmit")," const __payload = {"," hook_event_name: __sourceEvent,"," session_id: input.sessionID,"," message_id: input.messageID,"," prompt: output.message,"," cwd: __cwd,"," workspace: { current_dir: __cwd },"," };",N({hookGroups:e.hookGroups,payloadExpression:"__payload",contextSink:'output.parts.unshift({ type: "text", text: __ctx } as never)'})," },"," };","};",""].join(`
75
+ `)}function _e(e){return e.includes("hook claude-pre-exec")||e.includes("rsp-hook.sh")&&e.includes("claude-pre-exec")}function ke(e){if(e==="*"||e==="")return"/.*/";let t=e.split("|").map(o=>o.trim()).filter(Boolean);return t.length===0?"/.*/":`/^(${t.map(o=>o.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")).join("|")})$/i`}function ve(e,t){let n=At(e,t);if(n.length===0)return[];let o=new Map,s=[];for(let r of n){let a;try{a=JSON.parse(Pt(r,"utf8"))}catch(c){s.push(`could not parse ${r}: ${c.message}`);continue}for(let[c,u]of Object.entries(a.hooks??{})){if(!ye[c]){s.push(`event "${c}" from ${r} has no known OpenCode plugin event equivalent (warn-and-continue)`);continue}let f=o.get(c)??[];for(let p of u){let d=p.matcher??"*";for(let h of p.hooks){if(h.type!=="command")continue;let y=Ct(h.command,t);f.push({matcher:d,command:y,sourceFile:r})}}o.set(c,f)}}let i=[];for(let[r,a]of o){let c=ye[r],u=Et[r];!c||!u||(r==="SessionStart"?i.push({sourceEvent:r,opencodeEvent:c,target:u,source:It({sourceFiles:a.map(l=>l.sourceFile),commands:a.map(l=>l.command)}),sourceFiles:a.map(l=>l.sourceFile),warnings:s}):r==="PreToolUse"?i.push({sourceEvent:r,opencodeEvent:c,target:u,source:Tt({sourceFiles:a.map(l=>l.sourceFile),hookGroups:a}),sourceFiles:a.map(l=>l.sourceFile),warnings:s}):r==="PostToolUse"?i.push({sourceEvent:r,opencodeEvent:c,target:u,source:jt({sourceFiles:a.map(l=>l.sourceFile),hookGroups:a}),sourceFiles:a.map(l=>l.sourceFile),warnings:s}):r==="Stop"?i.push({sourceEvent:r,opencodeEvent:c,target:u,source:Ft({sourceFiles:a.map(l=>l.sourceFile),hookGroups:a}),sourceFiles:a.map(l=>l.sourceFile),warnings:s}):r==="PreCompact"?i.push({sourceEvent:r,opencodeEvent:c,target:u,source:Nt({sourceFiles:a.map(l=>l.sourceFile),hookGroups:a}),sourceFiles:a.map(l=>l.sourceFile),warnings:s}):r==="UserPromptSubmit"&&i.push({sourceEvent:r,opencodeEvent:c,target:u,source:Dt({sourceFiles:a.map(l=>l.sourceFile),hookGroups:a}),sourceFiles:a.map(l=>l.sourceFile),warnings:s}))}return i}import{existsSync as Q,readFileSync as Mt,statSync as Lt}from"node:fs";import{homedir as xe}from"node:os";import{join as x}from"node:path";function Ut(e,t){let n=x(e,t,".mcp.json");if(!Q(n))return null;try{return JSON.parse(Mt(n,"utf8"))}catch{return null}}function Vt(e,t,n){let o=[x(e,t,n),x(e,t,"hooks",n.split("/").pop()??""),x(e,"..",n),x(e,"..","..",".codex",".tmp","marketplaces","red-skills","plugins",t,n),x(xe(),".codex","plugins","cache","red-skills",t,n)];for(let s of o.slice(0,3))if(Q(s))return{path:s,candidate:s};for(let s of o.slice(3))if(Q(s))return{path:s,candidate:s};return{path:null,candidate:o[0]??null}}function Ht(e,t=xe()){for(let n of e.matchAll(/\$HOME\/([\w./-]+)/g)){let o=x(t,n[1]);try{if(Lt(o).isFile())return o}catch{}}return null}function Wt(e,t,n,o){let s=[],i=o.command??"sh",r=o.args??[],a=o.env;if(i==="sh"&&r[0]==="-c"&&typeof r[1]=="string")return Gt(e,t,n,r[1],a);let c={type:"local",command:[i,...r],enabled:!0};return a&&(c.environment=a),{entry:c,warnings:s}}function Gt(e,t,n,o,s){let i=[],r=[/\$\{?CODEX_PLUGIN_ROOT\}?\/(?:\$\{?CLAUDE_PLUGIN_ROOT\}?\/)?([\w./-]+)/,/\$\{?CLAUDE_PLUGIN_ROOT\}?\/(?:\$\{?CODEX_PLUGIN_ROOT\}?\/)?([\w./-]+)/,/\$root\/([\w./-]+)/g],a=[];for(let p of r)if(p.flags&&p.flags.includes("g")){let d=o.matchAll(p);for(let h of d)a.push(h[1])}else{let d=o.match(p);d&&d[1]&&a.push(d[1])}let c=null;for(let p of a){let{path:d}=Vt(e,t,p);if(d){c=d;break}}if(c||(c=Ht(o)),!c){i.push(`${n}: could not resolve any of the script paths referenced by the source hooks (${a.slice(0,3).join(", ")}) \u2014 the plugin checkout or a Codex cache must exist for this MCP to start`);let p={type:"local",command:["sh","-c",o],enabled:!0};return s&&(p.environment=s),{entry:p,warnings:i}}let u=c.endsWith(".mjs")?"node":c.endsWith(".sh")?"bash":"sh",l=o.match(/mcp(?=['"\s;|&]|$)/)?["mcp"]:[],f={type:"local",command:[u,c,...l],cwd:e,enabled:!0};return s&&(f.environment=s),{entry:f,warnings:i}}function D(e,t){let n=Ut(e,t);if(!n?.mcpServers)return[];let o=[];for(let[s,i]of Object.entries(n.mcpServers)){let{entry:r,warnings:a}=Wt(e,t,s,i);o.push({name:s,entry:r,warnings:a})}return o.sort((s,i)=>s.name.localeCompare(i.name)),o}import{existsSync as qt}from"node:fs";import{join as Bt}from"node:path";function Kt(e){let t=[Bt(e,"dev","skills","engineering","afk","bin","afk.mjs")];for(let n of t)if(qt(n))return{path:n};return{path:null}}function be(e,t){if(t!=="dev")return[];let{path:n}=Kt(e),o=[];return n||o.push("dev: AFK launcher not found at plugins/dev/skills/engineering/afk/bin/afk.mjs \u2014 the session-status module will be a silent no-op until the launcher is built"),[{plugin:t,target:"plugin/session-status.ts",source:zt,warnings:o}]}var zt=`// generated by @reddb-io/red-skills \u2014 slice 4 (statusline + toasts)
70
76
  // ADR 0080: session.idle / session.error / session.created /
71
77
  // experimental.session.compacting \u2192 AFK statusline
72
78
  // do not edit by hand \u2014 re-run the generator to refresh.
@@ -146,20 +152,21 @@ export const AFKStatusline: Plugin = async (ctx) => {
146
152
  },
147
153
  };
148
154
  };
149
- `;function ke(e){let t=le(e.pluginsRoot,e.plugins);return{byPlugin:e.plugins.map(n=>{let s=t.find(l=>l.plugin===n)?.result??{plans:[],errors:[]},i=he(e.pluginsRoot,n),r=F(e.pluginsRoot,n),a=_e(e.pluginsRoot,n),c=A({configText:e.configText,env:e.env});return{plugin:n,provider:c,skills:s,hooks:i,mcp:r,statusline:a}})}}function xe(e,t){for(let o of e.byPlugin){let{plugin:n,provider:s,skills:i,hooks:r,mcp:a,statusline:c}=o,l=P(t.outRoot,n);T(l,{recursive:!0});let u={...s};a.length>0&&(u.mcp=Gt(a)),N(P(l,"opencode.json"),JSON.stringify(u,null,2)+`
150
- `,"utf8");for(let f of i.plans){let p=P(l,".opencode",f.target);if(T(D(p),{recursive:!0}),f.renamedFrom)N(p,ue(Vt(f.source,"utf8"),f.name),"utf8");else if(t.copySkills)we(f.source,p);else{let d=Wt(D(p),f.source),h=!d.startsWith("..")||d.split("/").filter(_=>_==="..").length<=4?d:f.source;try{Lt(h,p)}catch{we(f.source,p)}}}for(let f of r){let p=P(l,".opencode",f.target);T(D(p),{recursive:!0}),N(p,f.source,"utf8")}for(let f of c){let p=P(l,".opencode",f.target);T(D(p),{recursive:!0}),N(p,f.source,"utf8")}}}function Gt(e){let t={};for(let o of e)t[o.name]=o.entry;return t}import{existsSync as Z,readdirSync as qt,statSync as Ht}from"node:fs";import{join as Y}from"node:path";function ve(e){if(!Z(e))return[];let t;try{t=qt(e)}catch{return[]}let o=[];for(let n of t){let s=Y(e,n),i;try{i=Ht(s)}catch{continue}if(!i.isDirectory())continue;let r=Z(Y(s,".claude-plugin","plugin.json")),a=Z(Y(s,".codex-plugin","plugin.json"));(r||a)&&o.push({name:n,source:s})}return o.sort((n,s)=>n.name.localeCompare(s.name)),o}function Jt(e,t){let o=[],n=[];for(let r of t)for(let a of F(e,r)){o.push(a);for(let c of a.warnings)n.push(`[${r}] ${c}`)}let s=new Set;return{mcps:o.filter(r=>s.has(r.name)?!1:(s.add(r.name),!0)),warnings:n}}function Zt(e){let t={};for(let o of e)t[o.name]=o.entry;return t}function be(e){let t=L("opencode-host");process.stdout.write(e?`${JSON.stringify(t)}
151
- `:`${V(t)}
152
- `)}function Yt(e){if(oe(e)){be(e.includes("--json"));return}let t;try{t=se(e)}catch(g){throw g instanceof v&&(process.stderr.write(`opencode-host: ${g.message}
153
- `),process.exit(2)),g}if(t.showVersion){be(t.versionJson);return}if(t.showHelp){process.stdout.write(re());return}let o=L("opencode-host"),n=V(o),s=U(t.configPath),i=U(t.pluginsRoot),r=U(t.outPath),a=U(t.outDir),c;try{c=Bt(s,"utf8")}catch(g){process.stderr.write(`opencode-host: could not read config at ${s}: ${g.message}
154
- `),process.exit(1)}ce(c)||(process.stderr.write(`opencode-host: refusing to emit \u2014 plugins.dev.enabled is not true in .red/config.yaml (ADR 0067 strict opt-in). Run /red-setup to enable the dev plugin.
155
- `),process.exit(1));let l=H(process.env);l===void 0&&process.stderr.write("opencode-host: no auth env-var set (OPENAI_API_KEY / MINIMAX_API_KEY / OPENROUTER_API_KEY). Run `/connect` inside opencode to pick a provider, or export one of the env vars.\n");let u=A({configText:c,env:process.env}),f=ve(i),p=Jt(i,f.map(g=>g.name)),d={...u};p.mcps.length>0&&(d.mcp=Zt(p.mcps));let h=["// generated by @reddb-io/red-skills",`// version: ${n}`,p.mcps.length>0?`// slice: 1+3 (provider block + ${p.mcps.length} MCP server(s))`:"// slice: 1 (provider block only)","// do not edit by hand \u2014 re-run the generator to refresh.",""].join(`
156
- `)+JSON.stringify(d,null,2)+`
157
- `;if(t.printJson){process.stdout.write(h);return}try{$e(zt(r),{recursive:!0}),Kt(r,h,"utf8")}catch(g){process.stderr.write(`opencode-host: could not write ${t.outPath}: ${g.message}
158
- `),process.exit(1)}for(let g of p.warnings)process.stderr.write(`opencode-host: mcp warning \u2014 ${g}
159
- `);if(!t.slice2){process.stdout.write(`opencode-host: wrote ${t.outPath} (slice 1+3; provider=${l??"openrouter"} via precedence, model=${u.model}, mcps=${p.mcps.length})
160
- `);return}let _=t.pluginFilter&&t.pluginFilter.length>0?f.filter(g=>t.pluginFilter.includes(g.name)).map(g=>g.name):f.map(g=>g.name);_.length===0&&(process.stderr.write(`opencode-host: no plugins discovered under ${i} (expected directories like dev/, memory/, brain/)
161
- `),process.exit(1));let E=ke({pluginsRoot:i,plugins:_,configText:c,env:process.env});try{$e(a,{recursive:!0}),xe(E,{outRoot:a,pluginsRoot:i,plugins:_,configText:c,env:process.env,copySkills:t.copySkills,version:n})}catch(g){process.stderr.write(`opencode-host: could not write ${r}: ${g.message}
162
- `),process.exit(1)}let M=0;for(let g of E.byPlugin){for(let k of g.skills.errors)process.stderr.write(`opencode-host: skill error in ${g.plugin}: ${k.message}
163
- `),M++;for(let k of g.hooks)for(let Oe of k.warnings)process.stderr.write(`opencode-host: hook warning in ${g.plugin}: ${Oe}
164
- `),M++}process.stdout.write(`opencode-host: wrote ${t.outPath} (slice 1 provider block) + ${a} (slice 2 dist tree; plugins=${_.length}, skills=${E.byPlugin.reduce((g,k)=>g+k.skills.plans.length,0)}, hooks=${E.byPlugin.reduce((g,k)=>g+k.hooks.length,0)}, warnings=${M}, provider=${l??"openrouter"} via precedence)
165
- `)}Yt(process.argv.slice(2));
155
+ `;function Se(e){let t=e.semanticAuthority??T("opencode"),n=me(e.pluginsRoot,e.plugins);return{byPlugin:e.plugins.map(s=>{let i=n.find(f=>f.plugin===s)?.result??{plans:[],errors:[]},r=ve(e.pluginsRoot,s),{plans:a,deferred:c}=I(D(e.pluginsRoot,s),t),u=be(e.pluginsRoot,s),l=j({configText:e.configText,env:e.env});return{plugin:s,provider:l,skills:i,hooks:r,mcp:a,deferredMcp:c,statusline:u}}),semanticAuthority:t}}function Oe(e,t){for(let n of e.byPlugin){let{plugin:o,provider:s,skills:i,hooks:r,mcp:a,statusline:c}=n,u=P(t.outRoot,o);M(u,{recursive:!0});let l={...s};a.length>0&&(l.mcp=Xt(a)),L(P(u,"opencode.json"),JSON.stringify(l,null,2)+`
156
+ `,"utf8");for(let f of i.plans){let p=P(u,".opencode",f.target);if(M(U(p),{recursive:!0}),f.renamedFrom)L(p,ge(Zt(f.source,"utf8"),f.name),"utf8");else if(t.copySkills)$e(f.source,p);else{let d=Yt(U(p),f.source),y=!d.startsWith("..")||d.split("/").filter(b=>b==="..").length<=4?d:f.source;try{Jt(y,p)}catch{$e(f.source,p)}}}for(let f of r){let p=P(u,".opencode",f.target);M(U(p),{recursive:!0}),L(p,f.source,"utf8")}for(let f of c){let p=P(u,".opencode",f.target);M(U(p),{recursive:!0}),L(p,f.source,"utf8")}}}function Xt(e){let t={};for(let n of e)t[n.name]=n.entry;return t}import{existsSync as ee,readdirSync as Qt,statSync as en}from"node:fs";import{join as te}from"node:path";function Pe(e){if(!ee(e))return[];let t;try{t=Qt(e)}catch{return[]}let n=[];for(let o of t){let s=te(e,o),i;try{i=en(s)}catch{continue}if(!i.isDirectory())continue;let r=ee(te(s,".claude-plugin","plugin.json")),a=ee(te(s,".codex-plugin","plugin.json"));(r||a)&&n.push({name:o,source:s})}return n.sort((o,s)=>o.name.localeCompare(s.name)),n}function sn(e,t,n){let o=[],s=[],i=[];for(let c of t){let u=I(D(e,c),n);for(let l of u.deferred)i.push(l);for(let l of u.plans){o.push(l);for(let f of l.warnings)s.push(`[${c}] ${f}`)}}let r=new Set;return{mcps:o.filter(c=>r.has(c.name)?!1:(r.add(c.name),!0)),warnings:s,deferred:[...new Set(i)]}}function rn(e){let t={};for(let n of e)t[n.name]=n.entry;return t}function Re(e){let t=W("opencode-host");process.stdout.write(e?`${JSON.stringify(t)}
157
+ `:`${G(t)}
158
+ `)}function cn(e){if(ae(e)){Re(e.includes("--json"));return}let t;try{t=le(e)}catch(m){throw m instanceof w&&(process.stderr.write(`opencode-host: ${m.message}
159
+ `),process.exit(2)),m}if(t.showVersion){Re(t.versionJson);return}if(t.showHelp){process.stdout.write(ue());return}let n=W("opencode-host"),o=G(n),s=V(t.configPath),i=V(t.pluginsRoot),r=V(t.outPath),a=V(t.outDir),c;try{c=tn(s,"utf8")}catch(m){process.stderr.write(`opencode-host: could not read config at ${s}: ${m.message}
160
+ `),process.exit(1)}fe(c)||(process.stderr.write(`opencode-host: refusing to emit \u2014 plugins.dev.enabled is not true in .red/config.yaml (ADR 0067 strict opt-in). Run /red-setup to enable the dev plugin.
161
+ `),process.exit(1));let u=J(process.env);u===void 0&&process.stderr.write("opencode-host: no auth env-var set (OPENAI_API_KEY / MINIMAX_API_KEY / OPENROUTER_API_KEY). Run `/connect` inside opencode to pick a provider, or export one of the env vars.\n");let l=j({configText:c,env:process.env}),f=T(t.host,t.nativeLsp),p=Pe(i),d=sn(i,p.map(m=>m.name),f),h={...l};d.mcps.length>0&&(h.mcp=rn(d.mcps));let b=["// generated by @reddb-io/red-skills",`// version: ${o}`,d.mcps.length>0?`// slice: 1+3 (provider block + ${d.mcps.length} MCP server(s))`:"// slice: 1 (provider block only)","// do not edit by hand \u2014 re-run the generator to refresh.",""].join(`
162
+ `)+JSON.stringify(h,null,2)+`
163
+ `;if(t.printJson){process.stdout.write(b);return}try{Ee(on(r),{recursive:!0}),nn(r,b,"utf8")}catch(m){process.stderr.write(`opencode-host: could not write ${t.outPath}: ${m.message}
164
+ `),process.exit(1)}for(let m of d.warnings)process.stderr.write(`opencode-host: mcp warning \u2014 ${m}
165
+ `);if(d.deferred.length>0&&process.stdout.write(`opencode-host: ${d.deferred.join(", ")} deferred to ${f.host} native LSP (--no-native-lsp to publish it anyway)
166
+ `),!t.slice2){process.stdout.write(`opencode-host: wrote ${t.outPath} (slice 1+3; provider=${u??"openrouter"} via precedence, model=${l.model}, mcps=${d.mcps.length})
167
+ `);return}let E=t.pluginFilter&&t.pluginFilter.length>0?p.filter(m=>t.pluginFilter.includes(m.name)).map(m=>m.name):p.map(m=>m.name);E.length===0&&(process.stderr.write(`opencode-host: no plugins discovered under ${i} (expected directories like dev/, memory/, brain/)
168
+ `),process.exit(1));let R=Se({pluginsRoot:i,plugins:E,configText:c,env:process.env,semanticAuthority:f});try{Ee(a,{recursive:!0}),Oe(R,{outRoot:a,pluginsRoot:i,plugins:E,configText:c,env:process.env,copySkills:t.copySkills,version:o,semanticAuthority:f})}catch(m){process.stderr.write(`opencode-host: could not write ${r}: ${m.message}
169
+ `),process.exit(1)}let H=0;for(let m of R.byPlugin){for(let k of m.skills.errors)process.stderr.write(`opencode-host: skill error in ${m.plugin}: ${k.message}
170
+ `),H++;for(let k of m.hooks)for(let Ae of k.warnings)process.stderr.write(`opencode-host: hook warning in ${m.plugin}: ${Ae}
171
+ `),H++}process.stdout.write(`opencode-host: wrote ${t.outPath} (slice 1 provider block) + ${a} (slice 2 dist tree; plugins=${E.length}, skills=${R.byPlugin.reduce((m,k)=>m+k.skills.plans.length,0)}, hooks=${R.byPlugin.reduce((m,k)=>m+k.hooks.length,0)}, warnings=${H}, provider=${u??"openrouter"} via precedence)
172
+ `)}cn(process.argv.slice(2));