@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.
- package/dist/code-nav.bundle.min.mjs +51 -46
- package/dist/opencode-host.bundle.min.mjs +48 -41
- package/dist/redskilled-mcp.bundle.min.mjs +200 -200
- package/dist/redskilled.bundle.min.mjs +214 -214
- package/dist/release.bundle.min.mjs +8 -8
- package/dist/rsp-core.bundle.min.mjs +48 -48
- package/dist/rsp.bundle.min.mjs +1 -1
- package/package.json +1 -1
- package/scripts/install-opencode.sh +32 -1
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
|
|
2
|
-
import{mkdirSync as
|
|
3
|
-
`),
|
|
4
|
-
`)),e.positional&&e.positional.length>0){t.push(
|
|
5
|
-
`));for(let
|
|
6
|
-
`),
|
|
7
|
-
`))}t.push(
|
|
8
|
-
`))}if(e.options&&Object.keys(e.options).length>0){t.push(
|
|
9
|
-
`));let
|
|
10
|
-
`))}return
|
|
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
|
|
46
|
-
`)){let s=
|
|
47
|
-
---`,3);if(t<0)return{};let
|
|
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(),
|
|
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;"," };"]:[],
|
|
58
|
-
`)}function
|
|
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
|
|
62
|
-
`);return e.toolExpression?[` if (${
|
|
63
|
-
`):[" {",
|
|
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
|
|
66
|
-
`)}function
|
|
67
|
-
`)}function
|
|
68
|
-
`)}function
|
|
69
|
-
`)}function
|
|
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
|
|
150
|
-
`,"utf8");for(let f of i.plans){let p=P(
|
|
151
|
-
`:`${
|
|
152
|
-
`)}function
|
|
153
|
-
`),process.exit(2)),
|
|
154
|
-
`),process.exit(1)}
|
|
155
|
-
`),process.exit(1));let
|
|
156
|
-
`)+JSON.stringify(
|
|
157
|
-
`;if(t.printJson){process.stdout.write(
|
|
158
|
-
`),process.exit(1)}for(let
|
|
159
|
-
`);if(
|
|
160
|
-
`)
|
|
161
|
-
`)
|
|
162
|
-
`),process.exit(1)
|
|
163
|
-
`),
|
|
164
|
-
`),
|
|
165
|
-
`)}
|
|
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));
|