alchemylab-opencode 1.0.26 → 2.0.1
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/NODE_COMPAT.md +23 -174
- package/dist/20260127222353_familiar_lady_ursula-KV747FJX.js +14 -0
- package/dist/{chunk-LTCXIXYM.js → 20260211171708_add_project_commands-GDOHPDPF.js} +3 -1
- package/dist/20260213144116_wakeful_the_professor-ZVDD54AK.js +14 -0
- package/dist/20260225215848_workspace-ZMSOZSPA.js +14 -0
- package/dist/20260227213759_add_session_workspace_id-ROENWPKA.js +14 -0
- package/dist/20260228203230_blue_harpoon-IW3Z4TQZ.js +14 -0
- package/dist/20260303231226_add_workspace_fields-OUVZMNAG.js +14 -0
- package/dist/20260309230000_move_org_to_state-NOXAPU5V.js +14 -0
- package/dist/20260312043431_session_message_cursor-DJ4T3T4R.js +14 -0
- package/dist/20260323234822_events-72GIKJ2A.js +14 -0
- package/dist/20260410174513_workspace-name-JXSWFBJN.js +14 -0
- package/dist/20260413175956_chief_energizer-4HEWZ6U3.js +14 -0
- package/dist/20260423070820_add_icon_url_override-X5SHFGTI.js +14 -0
- package/dist/20260427172553_slow_nightmare-PS5T2AH2.js +14 -0
- package/dist/{chunk-PWFRMDDF.js → 20260428004200_add_session_path-LGW75WYA.js} +3 -0
- package/dist/{valibot--1zFm7rT-FSYJNYJ6.js → 20260501142318_next_venus-J3TLVXZ6.js} +3 -1
- package/dist/20260504145000_add_sync_owner-3R52GB4C.js +14 -0
- package/dist/20260507164347_add_workspace_time-JHDRCZAR.js +14 -0
- package/dist/20260510033149_session_usage-UGBVOXZB.js +53 -0
- package/dist/20260511000411_data_migration_state-FB4LBFSE.js +14 -0
- package/dist/20260511173437_session-metadata-T2XHGWHS.js +14 -0
- package/dist/20260601010001_normalize_storage_paths-5MAY5GT3.js +14 -0
- package/dist/{chunk-YRY5Y3QL.js → 20260601202201_amazing_prowler-PET224YG.js} +3 -1
- package/dist/20260602002951_lowly_union_jack-PG6XDMGL.js +14 -0
- package/dist/20260602182828_add_project_directories-ZCH2ACGG.js +14 -0
- package/dist/20260603001617_session_message_projection_indexes-XVLJTUF2.js +14 -0
- package/dist/20260603040000_session_message_projection_order-XG6RACZQ.js +14 -0
- package/dist/20260603141458_session_input_inbox-K2VQ7V6E.js +14 -0
- package/dist/20260603160727_jittery_ezekiel_stane-WKJLRDO7.js +14 -0
- package/dist/20260604172448_event_sourced_session_input-NTXOECR7.js +14 -0
- package/dist/20260605003541_add_session_context_snapshot-DXMQEXMT.js +14 -0
- package/dist/{zod-Bwrt9trS-HVDOFWRP.js → 20260605042240_add_context_epoch_agent-W6IQYZXE.js} +3 -1
- package/dist/20260611035744_credential-XTMSYTJD.js +14 -0
- package/dist/20260611192811_lush_chimera-XPLIQMJD.js +14 -0
- package/dist/20260612174303_project_dir_strategy-FR2NGQKK.js +14 -0
- package/dist/20260622142730_simplify_session_context_epoch-NTQZR3RE.js +14 -0
- package/dist/20260622170816_reset_v2_session_state-5JPHJTZG.js +14 -0
- package/dist/20260622202450_simplify_session_input-2EXF2HMV.js +14 -0
- package/dist/app-runtime-HQBOCDV5.js +14 -0
- package/dist/chunk-4FEBIOI5.js +865 -0
- package/dist/chunk-4K2RXRZL.js +14 -0
- package/dist/chunk-4RFMKEKM.js +1455 -0
- package/dist/chunk-BM2C7NHL.js +41 -0
- package/dist/chunk-MKEMZFJI.js +393 -0
- package/dist/chunk-OMDJ6ZZ2.js +684 -0
- package/dist/chunk-OWMG4NNF.js +186 -0
- package/dist/chunk-QRABYJKL.js +14 -0
- package/dist/chunk-RHIWAYN5.js +14 -0
- package/dist/{arktype-aI7TBD0R-TFNARRIP.js → chunk-VURLSDCB.js} +3 -1
- package/dist/chunk-Z5TLIUAI.js +28 -0
- package/dist/code-mode-7BQJUARW.js +40 -0
- package/dist/copilot-provider-TX4YFKJZ.js +14 -0
- package/dist/photon-VQS5F5BI.js +14 -0
- package/dist/pty.node-Y3N2XKYG.js +14 -0
- package/dist/run.js +3 -1
- package/dist/serve.js +3 -1
- package/dist/server-BFUQR7MX.js +17 -0
- package/dist/session-6RNXZNG6.js +14 -0
- package/dist/{chunk-2ANK3QEN.js → worktree-QHQHX3SG.js} +3 -1
- package/package.json +83 -50
- package/patches/@ai-sdk%2Famazon-bedrock@4.0.166.patch +164 -0
- package/patches/@ai-sdk%2Fanthropic@3.0.111.patch +528 -0
- package/patches/@ai-sdk%2Fgoogle@3.0.73.patch +69 -0
- package/patches/@ai-sdk%2Fgroq@3.0.31.patch +79 -0
- package/patches/@ai-sdk%2Fmistral@3.0.51.patch +714 -0
- package/patches/@ai-sdk%2Fopenai-compatible@2.0.41.patch +39 -0
- package/patches/@ai-sdk%2Fopenai@3.0.88.patch +280 -0
- package/patches/@ai-sdk%2Fxai@3.0.139.patch +296 -0
- package/patches/@modelcontextprotocol%2Fsdk@1.29.0.patch +647 -0
- package/patches/@npmcli%2Fagent@4.0.2.patch +13 -0
- package/patches/@silvia-odwyer%2Fphoton-node@0.3.4.patch +285 -0
- package/patches/effect@4.0.0-beta.83.patch +57 -0
- package/patches/gcp-metadata@8.1.2.patch +14 -0
- package/patches/pacote@21.5.0.patch +18 -0
- package/postinstall.cjs +146 -0
- package/dist/chunk-5P5WLADX.js +0 -18
- package/dist/chunk-7KKA6WBY.js +0 -12
- package/dist/chunk-A7EXZZPC.js +0 -12
- package/dist/chunk-CZVKIDQZ.js +0 -12
- package/dist/chunk-FXLFZ5DL.js +0 -12
- package/dist/chunk-G752V4OP.js +0 -2187
- package/dist/chunk-GBXMNWYD.js +0 -18
- package/dist/chunk-IR6PDN4W.js +0 -13
- package/dist/chunk-M4CB72HE.js +0 -13
- package/dist/chunk-MBZTOEAD.js +0 -12
- package/dist/default-u_dwuiYb-652AQZKX.js +0 -12
- package/dist/effect-QlVUlMFu-JVYEXAZL.js +0 -12
- package/dist/log-MVJ7H4K5.js +0 -12
- package/dist/pty.node-X2EITEZ4.js +0 -12
- package/dist/registry-ISXIFNPG.js +0 -12
- package/dist/run-AUCA7EKA.js +0 -20
- package/dist/run-service-MT3LOWLS.js +0 -12
- package/dist/schema-YWIVP7UR.js +0 -12
- package/dist/server-PIYRZLBG.js +0 -12
- package/dist/session-ACBIJ2VE.js +0 -12
- package/dist/share-next-MPGA7EO4.js +0 -12
- package/dist/sury-CWZTCd75-3YHH6KVI.js +0 -12
- package/dist/typebox-Dei93FPO-GLI7OCTY.js +0 -12
- package/dist/valibot-D_HTw1Gn-E5NKVIOV.js +0 -12
- package/dist/worktree-E4DGSBLJ.js +0 -12
- package/dist/zod-DSgpEGAE-DSH6V7MG.js +0 -12
- package/packages/opencode/migration/20260127222353_familiar_lady_ursula/migration.sql +0 -90
- package/packages/opencode/migration/20260127222353_familiar_lady_ursula/snapshot.json +0 -796
- package/packages/opencode/migration/20260211171708_add_project_commands/migration.sql +0 -1
- package/packages/opencode/migration/20260211171708_add_project_commands/snapshot.json +0 -806
- package/packages/opencode/migration/20260213144116_wakeful_the_professor/migration.sql +0 -11
- package/packages/opencode/migration/20260213144116_wakeful_the_professor/snapshot.json +0 -897
- package/packages/opencode/migration/20260225215848_workspace/migration.sql +0 -7
- package/packages/opencode/migration/20260225215848_workspace/snapshot.json +0 -959
- package/packages/opencode/migration/20260227213759_add_session_workspace_id/migration.sql +0 -2
- package/packages/opencode/migration/20260227213759_add_session_workspace_id/snapshot.json +0 -983
- package/packages/opencode/migration/20260228203230_blue_harpoon/migration.sql +0 -17
- package/packages/opencode/migration/20260228203230_blue_harpoon/snapshot.json +0 -1102
- package/packages/opencode/migration/20260303231226_add_workspace_fields/migration.sql +0 -5
- package/packages/opencode/migration/20260303231226_add_workspace_fields/snapshot.json +0 -1013
- package/packages/opencode/migration/20260309230000_move_org_to_state/migration.sql +0 -3
- package/packages/opencode/migration/20260309230000_move_org_to_state/snapshot.json +0 -1156
- package/packages/opencode/migration/20260312043431_session_message_cursor/migration.sql +0 -4
- package/packages/opencode/migration/20260312043431_session_message_cursor/snapshot.json +0 -1168
- package/packages/opencode/migration/20260323234822_events/migration.sql +0 -13
- package/packages/opencode/migration/20260323234822_events/snapshot.json +0 -1271
- package/packages/opencode/migration/20260409000000_add_session_metadata/migration.sql +0 -1
|
@@ -0,0 +1,865 @@
|
|
|
1
|
+
// Built by esbuild from opencode-server source
|
|
2
|
+
if (typeof globalThis.Bun === 'undefined') {
|
|
3
|
+
globalThis.Bun = {
|
|
4
|
+
version: '0.0.0-node-compat',
|
|
5
|
+
stdin: { async text() { const chunks = []; for await (const c of process.stdin) chunks.push(c); return Buffer.concat(chunks).toString(); } },
|
|
6
|
+
which(cmd) { try { return require('child_process').execFileSync('which', [cmd], { encoding: 'utf8' }).trim(); } catch { return null; } },
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
if (typeof globalThis.__name === 'undefined') { globalThis.__name = (t, n) => { Object.defineProperty(t, 'name', { value: n, configurable: true }); return t; }; }
|
|
10
|
+
if (typeof globalThis.__export === 'undefined') { globalThis.__export = (t, a) => { for (const k in a) Object.defineProperty(t, k, { get: a[k], enumerable: true }); }; }
|
|
11
|
+
import { createRequire as __alchemyCreateRequire } from 'node:module';
|
|
12
|
+
const require = __alchemyCreateRequire(import.meta.url);
|
|
13
|
+
|
|
14
|
+
import{e as So}from"./chunk-QRABYJKL.js";import{Ca as Fi,Sa as jt,Wa as Ze,Ya as er,_ as Qo,aa as Ni,b as W,ba as Vt,ca as Nt,ha as Fe,ia as ji,k as Eo,oa as yt,pa as it,sa as An,u as Ye,va as j,xa as qi,za as $i}from"./chunk-OMDJ6ZZ2.js";import{A as bi,B as xi,C as Ee,Cc as se,D as De,Dc as We,E as _,F as oe,Fc as $e,Gc as N,H as Ii,Hc as Je,I as Jo,Ia as Pi,Ic as Oi,Ja as rt,Jc as _i,K as ht,Kc as Mi,L as H,M as Te,Ma as G,N as wi,Na as Ri,P as Yo,Pc as Li,Qc as Ui,Rc as Vi,S as Ci,Sc as ie,U as ko,a as Ae,b as ot,c as Se,e as gi,h as ne,i as le,j as hi,l as yi,o as vi,ob as Ai,pb as Zo,r as Lt,s as Ut,t as qe,tb as Di,ub as Ti,x as ki,xb as Xo,y as Si,yb as pe,z as Ei}from"./chunk-BM2C7NHL.js";import{a as r,d as T}from"./chunk-RHIWAYN5.js";var He={};T(He,{CatalogModelStatus:()=>zi,Event:()=>Ji,Model:()=>Wi,ModelsDev:()=>He,Provider:()=>Xc,Service:()=>qt,node:()=>ed});import Bc from"path";import{Context as Kc,Duration as tr,Effect as F,Layer as zc,Option as Wc,Schedule as nr,Schema as k}from"effect";import{HttpClient as or,HttpClientRequest as Gi}from"effect/unstable/http";var Dn={};T(Dn,{Event:()=>Gc,ModelsDev:()=>Dn});var Hi=Lt({type:"models-dev.refreshed",schema:{}}),Gc={Refreshed:Hi,Definitions:Ut(Hi)};var zi=k.Literals(["alpha","beta","deprecated"]),Bi=k.Union([k.Literals(["reasoning","reasoning_content","reasoning_text"]),k.String]),Jc=`opencode/${wi}/${Te}/${ht.OPENCODE_CLIENT}`,Yc=k.Struct({input:k.Finite,output:k.Finite,cache_read:k.optional(k.Finite),cache_write:k.optional(k.Finite),tier:k.Struct({type:k.Literal("context"),size:k.Finite})}),Ki=k.Struct({input:k.Finite,output:k.Finite,cache_read:k.optional(k.Finite),cache_write:k.optional(k.Finite),tiers:k.optional(k.Array(Yc)),context_over_200k:k.optional(k.Struct({input:k.Finite,output:k.Finite,cache_read:k.optional(k.Finite),cache_write:k.optional(k.Finite)}))}),Zc=k.Union([k.Struct({type:k.Literal("effort"),values:k.Array(k.NullOr(k.String))}),k.Struct({type:k.Literal("toggle")}),k.Struct({type:k.Literal("budget_tokens"),min:k.optional(k.Finite),max:k.optional(k.Finite)})]),Wi=k.Struct({id:k.String,name:k.String,family:k.optional(k.String),release_date:k.String,attachment:k.Boolean,reasoning:k.Boolean,temperature:k.Boolean,tool_call:k.Boolean,reasoning_options:k.optional(k.Array(Zc)),interleaved:k.optional(k.Union([k.Boolean,Bi,k.Struct({field:Bi})])),cost:k.optional(Ki),limit:k.Struct({context:k.Finite,input:k.optional(k.Finite),output:k.Finite}),modalities:k.optional(k.Struct({input:k.Array(k.Literals(["text","audio","image","video","pdf"])),output:k.Array(k.Literals(["text","audio","image","video","pdf"]))})),experimental:k.optional(k.Struct({modes:k.optional(k.Record(k.String,k.Struct({cost:k.optional(Ki),provider:k.optional(k.Struct({body:k.optional(k.Record(k.String,k.MutableJson)),headers:k.optional(k.Record(k.String,k.String))}))})))})),status:k.optional(zi),provider:k.optional(k.Struct({npm:k.optional(k.String),api:k.optional(k.String)}))}),Xc=k.Struct({api:k.optional(k.String),name:k.String,env:k.Array(k.String),id:k.String,npm:k.optional(k.String),models:k.Record(k.String,Wi)}),Ji=Dn.Event,qt=class extends Kc.Service()("@opencode/ModelsDev"){static{r(this,"Service")}},Qc=zc.effect(qt,F.gen(function*(){let t=yield*G.Service,e=yield*se.Service,n=or.filterStatusOk((yield*or.HttpClient).pipe(or.retryTransient({retryOn:"errors-and-responses",times:2,schedule:nr.exponential(200).pipe(nr.jittered)}))),o=ht.OPENCODE_MODELS_URL||"https://models.opencode.ai",i=Bc.join(H.Path.cache,o==="https://models.opencode.ai"?"models.json":`models-${Ii.fast(o)}.json`),s=tr.minutes(5),d=`models-dev:${i}`,c=F.fnUntraced(function*(){let C=yield*t.stat(i).pipe(F.catch(()=>F.succeed(void 0)));if(!C)return!1;let A=Wc.getOrElse(C.mtime,()=>new Date(0)).getTime();return Date.now()-A<tr.toMillis(s)}),a=F.fn("ModelsDev.fetchApi")(function*(){return yield*Gi.get(`${o}/api.json`).pipe(Gi.setHeader("User-Agent",Jc),n.execute,F.flatMap(C=>C.text),F.timeout("10 seconds"))}),l=t.readJson(ht.OPENCODE_MODELS_PATH??i).pipe(F.catch(C=>ht.OPENCODE_MODELS_PATH===void 0&&C._tag==="FileSystemError"&&C.method==="readJson"?t.remove(i,{force:!0}).pipe(F.ignore,F.as(void 0)):F.succeed(void 0)),F.map(C=>C)),f=F.sync(()=>typeof OPENCODE_MODELS_DEV>"u"?void 0:OPENCODE_MODELS_DEV),p=F.fn("ModelsDev.fetchAndWrite")(function*(){let C=yield*a(),A=`${i}.${process.pid}.${Date.now()}.tmp`;return yield*t.writeWithDirs(A,C).pipe(F.andThen(t.rename(A,i)),F.catch(S=>F.gen(function*(){return yield*t.remove(A,{force:!0}).pipe(F.ignore),yield*F.fail(S)}))),C}),m=F.gen(function*(){let C=yield*l;if(C)return C;let A=yield*f;if(A)return A;if(ht.OPENCODE_DISABLE_MODELS_FETCH)return{};let S=yield*F.scoped(F.gen(function*(){return yield*Jo.effect(d),yield*p()}));return JSON.parse(S)}).pipe(F.withSpan("ModelsDev.populate"),F.orDie),[y,g]=yield*F.cachedInvalidateWithTTL(m,tr.infinity),b=r(()=>y,"get"),P=F.fn("ModelsDev.refresh")(function*(C=!1){!C&&(yield*c())||(yield*F.scoped(F.gen(function*(){yield*Jo.effect(d),!(!C&&(yield*c()))&&(yield*p(),yield*g,yield*e.publish(Ji.Refreshed,{}))})).pipe(F.tapCause(A=>F.logError("Failed to fetch models.dev",{cause:A})),F.ignore))});return!ht.OPENCODE_DISABLE_MODELS_FETCH&&!process.argv.includes("--get-yargs-completions")&&(yield*F.forkScoped(P().pipe(F.repeat(nr.spaced("60 minutes")),F.ignore))),qt.of({get:b,refresh:P})})),ed=ot({service:qt,layer:Qc,deps:[G.node,se.node,rt]});import{Effect as bo,Fiber as td,Layer as Nm,ManagedRuntime as jm}from"effect";import*as rr from"effect/Context";function xo(t,e){return!e.instance&&!e.workspace?t:e.instance?e.workspace?t.pipe(bo.provideService(yt,e.instance),bo.provideService(it,e.workspace)):t.pipe(bo.provideService(yt,e.instance)):t.pipe(bo.provideService(it,e.workspace))}r(xo,"attachWith");function Hm(t){let e=An.workspaceID,n=td.getCurrent();return xo(t,{instance:n?rr.getReferenceUnsafe(n.context,yt):void 0,workspace:e??(n?rr.getReferenceUnsafe(n.context,it):void 0)})}r(Hm,"attach");var On={};T(On,{Event:()=>Tn,Permission:()=>On,Service:()=>$t,disabled:()=>Yi,evaluate:()=>ir,fromConfig:()=>sd,merge:()=>ad,node:()=>dd,visibleTools:()=>cd});import{Deferred as vt,Effect as Ne,Layer as nd,Context as od}from"effect";import Io from"os";var Tn=Ye.Event;function ir(t,e,...n){return n.flat().findLast(o=>We.match(t,o.permission)&&We.match(e,o.pattern))??{action:"ask",permission:t,pattern:"*"}}r(ir,"evaluate");var $t=class extends od.Service()("@opencode/Permission"){static{r(this,"Service")}},rd=nd.effect($t,Ne.gen(function*(){let t=yield*Ze.Service,e=yield*j.make(Ne.fn("Permission.state")(function*(s){let d={pending:new Map,approved:[]};return yield*Ne.addFinalizer(()=>Ne.gen(function*(){for(let c of d.pending.values())yield*vt.fail(c.deferred,new Ye.RejectedError);d.pending.clear()})),d})),n=Ne.fn("Permission.ask")(function*(s){let{approved:d,pending:c}=yield*j.get(e),{ruleset:a,...l}=s,f=!1;for(let g of l.patterns){let b=ir(l.permission,g,a,d);if(yield*Ne.logInfo("evaluated",{permission:l.permission,pattern:g,action:b}),b.action==="deny")return yield*new Ye.DeniedError({ruleset:a.filter(P=>We.match(l.permission,P.permission))});b.action!=="allow"&&(f=!0)}if(!f)return;let p=l.id??Ye.ID.ascending(),m={id:p,sessionID:l.sessionID,permission:l.permission,patterns:l.patterns,metadata:l.metadata,always:l.always,tool:l.tool};yield*Ne.logInfo("asking",{id:p,permission:m.permission,patterns:m.patterns});let y=yield*vt.make();return c.set(p,{info:m,deferred:y}),yield*t.publish(Tn.Asked,m),yield*Ne.ensuring(vt.await(y),Ne.sync(()=>{c.delete(p)}))}),o=Ne.fn("Permission.reply")(function*(s){let{approved:d,pending:c}=yield*j.get(e),a=c.get(s.requestID);if(!a)return yield*new Ye.NotFoundError({requestID:s.requestID});if(c.delete(s.requestID),yield*t.publish(Tn.Replied,{sessionID:a.info.sessionID,requestID:a.info.id,reply:s.reply}),s.reply==="reject"){yield*vt.fail(a.deferred,s.message?new Ye.CorrectedError({feedback:s.message}):new Ye.RejectedError);for(let[l,f]of c.entries())f.info.sessionID===a.info.sessionID&&(c.delete(l),yield*t.publish(Tn.Replied,{sessionID:f.info.sessionID,requestID:f.info.id,reply:"reject"}),yield*vt.fail(f.deferred,new Ye.RejectedError));return}if(yield*vt.succeed(a.deferred,void 0),s.reply!=="once"){for(let l of a.info.always)d.push({permission:a.info.permission,pattern:l,action:"allow"});for(let[l,f]of c.entries())f.info.sessionID!==a.info.sessionID||!f.info.patterns.every(m=>ir(f.info.permission,m,d).action==="allow")||(c.delete(l),yield*t.publish(Tn.Replied,{sessionID:f.info.sessionID,requestID:f.info.id,reply:"always"}),yield*vt.succeed(f.deferred,void 0))}}),i=Ne.fn("Permission.list")(function*(){let s=(yield*j.get(e)).pending;return Array.from(s.values(),d=>d.info)});return $t.of({ask:n,reply:o,list:i})}));function id(t){return t.startsWith("~/")?Io.homedir()+t.slice(1):t==="~"?Io.homedir():t.startsWith("$HOME/")?Io.homedir()+t.slice(5):t.startsWith("$HOME")?Io.homedir()+t.slice(5):t}r(id,"expand");function sd(t){let e=[];for(let[n,o]of Object.entries(t)){if(typeof o=="string"){e.push({permission:n,action:o,pattern:"*"});continue}e.push(...Object.entries(o).map(([i,s])=>({permission:n,pattern:id(i),action:s})))}return e}r(sd,"fromConfig");function ad(...t){return t.flat()}r(ad,"merge");function Yi(t,e){let n=["edit","write","apply_patch"],o=["list_mcp_resources","list_mcp_resource_templates","read_mcp_resource"];return new Set(t.filter(i=>{let s=n.includes(i)?"edit":o.includes(i)?"read":i,d=e.findLast(c=>We.match(s,c.permission));return d?.pattern==="*"&&d.action==="deny"}))}r(Yi,"disabled");function cd(t,e){let n=Yi(Object.keys(t),e);return Object.fromEntries(Object.entries(t).filter(([o])=>!n.has(o)))}r(cd,"visibleTools");var dd=Ae.make({service:$t,layer:rd,deps:[Ze.node]});var Ht={};T(Ht,{Discovery:()=>Ht,Service:()=>Ft,node:()=>hd});import"@effect/platform-node";import{Effect as U,Layer as ld,Path as fd,Schema as st,Context as pd}from"effect";import{HttpClient as Zi,HttpClientRequest as sr,HttpClientResponse as ud}from"effect/unstable/http";var md=4,Xi=8,ar=class extends st.Class("IndexSkill")({name:st.String,files:st.Array(st.String),version:st.optional(st.String)}){static{r(this,"IndexSkill")}},cr=class extends st.Class("Index")({skills:st.Array(ar)}){static{r(this,"Index")}},Ft=class extends pd.Service()("@opencode/SkillDiscovery"){static{r(this,"Service")}},gd=ld.effect(Ft,U.gen(function*(){let t=yield*G.Service,e=yield*fd.Path,n=Zi.filterStatusOk(ji(yield*Zi.HttpClient)),o=e.join(H.Path.cache,"skills"),i=U.fn("Discovery.download")(function*(d,c){return(yield*t.exists(c).pipe(U.orDie))?!0:yield*sr.get(d).pipe(n.execute,U.flatMap(a=>a.arrayBuffer),U.flatMap(a=>t.writeWithDirs(c,new Uint8Array(a))),U.as(!0),U.catch(a=>U.logError("failed to download",{url:d,error:a}).pipe(U.as(!1))))}),s=U.fn("Discovery.pull")(function*(d){let c=d.endsWith("/")?d:`${d}/`,a=new URL("index.json",c).href,l=c.slice(0,-1);yield*U.logInfo("fetching index",{url:a});let f=yield*sr.get(a).pipe(sr.acceptJson,n.execute,U.flatMap(ud.schemaBodyJson(cr)),U.catch(g=>U.logError("failed to fetch index",{url:a,error:g}).pipe(U.as(null))));if(!f)return[];let p=f.skills.filter(g=>!g.files.includes("SKILL.md"));yield*U.forEach(p,g=>U.logWarning("skill entry missing SKILL.md",{url:a,skill:g.name}),{discard:!0});let m=f.skills.filter(g=>g.files.includes("SKILL.md"));return(yield*U.forEach(m,g=>U.gen(function*(){let b=e.join(o,g.name),P=e.join(b,".opencode-version"),C=g.version,A=C===void 0?void 0:yield*t.readFileStringSafe(P).pipe(U.catch(()=>U.succeed(void 0)));if(C===void 0||A===C)yield*U.forEach(g.files,S=>i(new URL(S,`${l}/${g.name}/`).href,e.join(b,S)),{concurrency:Xi,discard:!0});else{let S=crypto.randomUUID(),w=`${b}.tmp-${S}`,q=`${b}.old-${S}`;yield*U.gen(function*(){(yield*U.forEach(g.files,K=>i(new URL(K,`${l}/${g.name}/`).href,e.join(w,K)),{concurrency:Xi})).every(Boolean)&&(yield*t.exists(e.join(w,"SKILL.md")).pipe(U.orDie))&&(yield*t.writeFileString(e.join(w,".opencode-version"),C),yield*U.uninterruptible(U.gen(function*(){let K=yield*t.exists(b).pipe(U.orDie);K&&(yield*t.rename(b,q)),yield*t.rename(w,b).pipe(U.catch(Ue=>U.gen(function*(){return K&&(yield*t.rename(q,b).pipe(U.ignore)),yield*U.fail(Ue)}))),K&&(yield*t.remove(q,{recursive:!0,force:!0}).pipe(U.ignore))})))}).pipe(U.catch(B=>U.logError("failed to refresh skill",{skill:g.name,error:B})),U.ensuring(t.remove(w,{recursive:!0,force:!0}).pipe(U.ignore)))}return(yield*t.exists(e.join(b,"SKILL.md")).pipe(U.orDie))?b:null}),{concurrency:md})).filter(g=>g!==null)});return Ft.of({pull:s})})),hd=Ae.make({service:Ft,layer:gd,deps:[G.node,Pi,rt]});var ri={};T(ri,{Info:()=>Gp,InvalidError:()=>ni,NameMismatchError:()=>oi,NotFoundError:()=>Ho,Service:()=>yn,Skill:()=>ri,fmt:()=>Zp,node:()=>Xp});import hn from"path";import{Effect as Z,Layer as Vp,Context as Np,Schema as X}from"effect";var Rt={};T(Rt,{CustomizeOpencodeContent:()=>Xa,Plugin:()=>Up,SkillPlugin:()=>Rt});var ti={};T(ti,{PluginInternal:()=>ti,define:()=>M,locationLayer:()=>_p,node:()=>Mp});import{Effect as de,Layer as ei}from"effect";var Oe={};T(Oe,{CommandV2:()=>Oe,Info:()=>Sd,Service:()=>Bt,locationLayer:()=>Ed,node:()=>bd});import{Context as vd,Effect as dr,Layer as kd}from"effect";var _n={};T(_n,{Command:()=>_n,Info:()=>yd});import{Schema as Gt}from"effect";var yd=Gt.Struct({name:Gt.String,template:Gt.String,description:Gt.String.pipe(le),agent:Gt.String.pipe(le),model:ki.Ref.pipe(le),subtask:Gt.Boolean.pipe(le)}).annotate({identifier:"CommandV2.Info"});var Sd=_n.Info,Bt=class extends vd.Service()("@opencode/v2/Command"){static{r(this,"Service")}},Qi=kd.effect(Bt,dr.sync(()=>{let t=De.create({initial:r(()=>({commands:new Map}),"initial"),draft:r(e=>({list:r(()=>Array.from(e.commands.values()),"list"),get:r(n=>e.commands.get(n),"get"),update:r((n,o)=>{let i=e.commands.get(n)??{name:n,template:""};e.commands.has(n)||e.commands.set(n,i),o(i),i.name=n},"update"),remove:r(n=>{e.commands.delete(n)},"remove")}),"draft")});return Bt.of({reload:t.reload,transform:t.transform,get:dr.fn("CommandV2.get")(function*(e){return t.get().commands.get(e)}),list:dr.fn("CommandV2.list")(function*(){return Array.from(t.get().commands.values())})})})),Ed=Qi,bd=Se({service:Bt,layer:Qi,deps:[]});var Un={};T(Un,{ConfigAgentPlugin:()=>Un,Plugin:()=>Zd});import Gd from"path";import{Effect as ue,Option as lr,Schema as fr}from"effect";var Ce={};T(Ce,{AskResult:()=>qd,AssertInput:()=>Nd,BlockedError:()=>Ro,CorrectedError:()=>Po,DeclinedError:()=>Zt,Effect:()=>Ei,Event:()=>Ln,ID:()=>Qt,NotFoundError:()=>Ao,PermissionV2:()=>Ce,Reply:()=>rs,ReplyInput:()=>jd,Request:()=>Vd,Rule:()=>bi,Ruleset:()=>xi,Service:()=>Xt,Source:()=>Ld,evaluate:()=>Co,locationLayer:()=>Fd,merge:()=>$d,node:()=>Hd});import{Context as _d,Deferred as St,Effect as J,Layer as os,Schema as _e}from"effect";var Yt={};T(Yt,{AddInput:()=>Dd,ID:()=>ns,Info:()=>Rd,ListInput:()=>Ad,PermissionSaved:()=>Yt,Service:()=>Jt,node:()=>Od});import{eq as ts}from"drizzle-orm";import{Context as Cd,Effect as kt,Layer as Pd,Schema as Wt}from"effect";import{sqliteTable as xd,text as wo,uniqueIndex as Id}from"drizzle-orm/sqlite-core";var Kt=xd("permission",{id:wo().$type().primaryKey(),project_id:wo().$type().notNull().references(()=>Ti.id,{onDelete:"cascade"}),action:wo().notNull(),resource:wo().notNull(),...Di},t=>[Id("permission_project_action_resource_idx").on(t.project_id,t.action,t.resource)]);var zt={};T(zt,{ID:()=>es,Info:()=>wd,PermissionSaved:()=>zt});import{Schema as Mn}from"effect";var es=Mn.String.pipe(Mn.brand("PermissionSaved.ID"),hi(t=>({create:r(()=>t.make("psv_"+yi()),"create")}))),wd=Mn.Struct({id:es,projectID:vi,action:Mn.String,resource:Mn.String}).annotate({identifier:"PermissionSaved.Info"});var ns=zt.ID,Rd=zt.Info,Ad=Wt.Struct({projectID:Xo.ID.pipe(Wt.optional)}).annotate({identifier:"PermissionSaved.ListInput"}),Dd=Wt.Struct({projectID:Xo.ID,action:Wt.String,resources:Wt.Array(Wt.String)}).annotate({identifier:"PermissionSaved.AddInput"}),Jt=class extends Cd.Service()("@opencode/v2/PermissionSaved"){static{r(this,"Service")}},Td=Pd.effect(Jt,kt.gen(function*(){let{db:t}=yield*Yo.Service,e=kt.fn("PermissionSaved.list")(function*(i){return(yield*t.select().from(Kt).where(i?.projectID?ts(Kt.project_id,i.projectID):void 0).all().pipe(kt.orDie)).map(d=>({id:d.id,projectID:d.project_id,action:d.action,resource:d.resource}))}),n=kt.fn("PermissionSaved.add")(function*(i){i.resources.length&&(yield*t.insert(Kt).values(i.resources.map(s=>({id:ns.create(),project_id:i.projectID,action:i.action,resource:s}))).onConflictDoNothing().run().pipe(kt.orDie))}),o=kt.fn("PermissionSaved.remove")(function*(i){yield*t.delete(Kt).where(ts(Kt.id,i)).run().pipe(kt.orDie)});return Jt.of({list:e,add:n,remove:o})})),Od=ot({service:Jt,layer:Td,deps:[Yo.node]});var Md=[{action:"*",resource:"*",effect:"deny"}],Qt=Ee.ID,Ld=Ee.Source,Ud={sessionID:Ee.Request.fields.sessionID,action:Ee.Request.fields.action,resources:Ee.Request.fields.resources,save:Ee.Request.fields.save,metadata:Ee.Request.fields.metadata,source:Ee.Request.fields.source},Vd=Ee.Request,rs=Ee.Reply,Nd=_e.Struct({id:Qt.pipe(_e.optional),...Ud,agent:W.ID.pipe(_e.optional)}).annotate({identifier:"PermissionV2.AssertInput"}),jd=_e.Struct({requestID:Qt,reply:rs,message:_e.String.pipe(_e.optional)}).annotate({identifier:"PermissionV2.ReplyInput"}),qd=_e.Struct({id:Qt,effect:Ee.Effect}).annotate({identifier:"PermissionV2.AskResult"}),Ln=Ee.Event,Zt=class extends _e.TaggedErrorClass()("PermissionV2.DeclinedError",{}){static{r(this,"DeclinedError")}},Po=class extends _e.TaggedErrorClass()("PermissionV2.CorrectedError",{feedback:_e.String}){static{r(this,"CorrectedError")}},Ro=class extends _e.TaggedErrorClass()("PermissionV2.BlockedError",{rules:Ee.Ruleset}){static{r(this,"BlockedError")}},Ao=class extends _e.TaggedErrorClass()("PermissionV2.NotFoundError",{requestID:Qt}){static{r(this,"NotFoundError")}};function Co(t,e,...n){return n.flat().findLast(o=>We.match(t,o.action)&&We.match(e,o.resource))??{action:t,resource:"*",effect:"ask"}}r(Co,"evaluate");function $d(...t){return t.flat()}r($d,"merge");var Xt=class extends _d.Service()("@opencode/v2/Permission"){static{r(this,"Service")}},is=os.effect(Xt,J.gen(function*(){let t=yield*se.Service,e=yield*pe.Service,n=yield*W.Service,o=yield*Qo.Service,i=yield*Yt.Service,s=new Map;yield*J.addFinalizer(()=>J.forEach(s.values(),S=>St.fail(S.deferred,new Zt),{discard:!0}).pipe(J.ensuring(J.sync(()=>{s.clear()}))));let d=J.fnUntraced(function*(){return(yield*i.list({projectID:e.project.id})).map(S=>({action:S.action,resource:S.resource,effect:"allow"}))}),c=J.fn("PermissionV2.configured")(function*(S,w){let q=yield*o.get(S);return q?(yield*n.resolve(w??q.agent))?.permissions??Md:yield*new Ni.NotFoundError({sessionID:S})});function a(S,w){return S.resources.some(q=>Co(S.action,q,w).effect==="deny")}r(a,"denied");function l(S,w){return w.filter(q=>We.match(S.action,q.action))}r(l,"relevant");let f=J.fnUntraced(function*(S){let w=yield*c(S.sessionID,S.agent);if(a(S,w))return{effect:"deny",rules:w};let q=[...w,...yield*d()],B=S.resources.map(Ue=>Co(S.action,Ue,q).effect);return{effect:B.includes("deny")?"deny":B.includes("ask")?"ask":"allow",rules:q}});function p(S){return{id:S.id??Qt.create(),sessionID:S.sessionID,action:S.action,resources:S.resources,save:S.save,metadata:S.metadata,source:S.source}}r(p,"request");let m=r((S,w)=>J.uninterruptible(J.gen(function*(){let q=yield*St.make(),B={request:S,agent:w,deferred:q};return s.has(S.id)?yield*J.die(`Duplicate pending permission ID: ${S.id}`):(s.set(S.id,B),yield*t.publish(Ln.Asked,S).pipe(J.onError(()=>J.sync(()=>s.delete(S.id)))),B)})),"create"),y=J.fn("PermissionV2.ask")(function*(S){let w=yield*f(S),q=p(S);return w.effect==="ask"&&(yield*m(q,S.agent)),{id:q.id,effect:w.effect}}),g=J.fn("PermissionV2.assert")(S=>J.uninterruptibleMask(w=>J.gen(function*(){let q=yield*f(S);if(q.effect==="deny")return yield*new Ro({rules:l(S,q.rules)});if(q.effect==="allow")return;let B=yield*m(p(S),S.agent);return yield*w(St.await(B.deferred)).pipe(J.catchTag("PermissionV2.DeclinedError",K=>J.die(K)),J.ensuring(J.sync(()=>{s.delete(B.request.id)})))}))),b=J.fn("PermissionV2.reply")(S=>J.uninterruptible(J.gen(function*(){let w=s.get(S.requestID);if(!w)return yield*new Ao({requestID:S.requestID});if(yield*t.publish(Ln.Replied,{sessionID:w.request.sessionID,requestID:w.request.id,reply:S.reply}),S.reply==="reject"){yield*St.fail(w.deferred,S.message?new Po({feedback:S.message}):new Zt),s.delete(S.requestID);for(let[B,K]of s)K.request.sessionID===w.request.sessionID&&(yield*t.publish(Ln.Replied,{sessionID:K.request.sessionID,requestID:K.request.id,reply:"reject"}),yield*St.fail(K.deferred,new Zt),s.delete(B));return}if(S.reply==="always"&&w.request.save?.length&&(yield*i.add({projectID:e.project.id,action:w.request.action,resources:w.request.save})),yield*St.succeed(w.deferred,void 0),s.delete(S.requestID),S.reply!=="always"||!w.request.save?.length)return;let q=yield*d();for(let[B,K]of s){let Ue={...K.request},Pn=yield*c(K.request.sessionID,K.agent).pipe(J.catchTag("Session.NotFoundError",()=>J.succeed(void 0)));if(!Pn||a(Ue,Pn))continue;let Rn=[...Pn,...q];K.request.resources.every(Wo=>Co(K.request.action,Wo,Rn).effect==="allow")&&(yield*t.publish(Ln.Replied,{sessionID:K.request.sessionID,requestID:K.request.id,reply:"always"}),yield*St.succeed(K.deferred,void 0),s.delete(B))}}))),P=J.fn("PermissionV2.list")(function*(){return Array.from(s.values(),S=>S.request)}),C=J.fn("PermissionV2.get")(function*(S){return s.get(S)?.request}),A=J.fn("PermissionV2.forSession")(function*(S){return Array.from(s.values(),w=>w.request).filter(w=>w.sessionID===S)});return Xt.of({ask:y,assert:g,reply:b,get:C,forSession:A,list:P})})),Fd=is.pipe(os.provideMerge(W.locationLayer)),Hd=Se({service:Xt,layer:is,deps:[se.node,pe.node,W.node,Qo.node,Yt.node]});var Bd=[{pattern:"{agent,agents}/**/*.md",primary:!1},{pattern:"{mode,modes}/*.md",primary:!0}],Kd=fr.decodeUnknownOption(Oi.Info),zd=fr.decodeUnknownOption(Mi.Info),Wd=fr.decodeUnknownOption(ie.Info),Jd=["external_directory","read","edit"],Yd=new Set(["model","variant","request","system","description","mode","hidden","color","steps","disabled","permissions"]),Zd={id:"config-agent",effect:ue.fn(function*(t){let e=yield*ie.Service,n=yield*G.Service,o=yield*H.Service;yield*t.agent.transform(ue.fn(function*(i){let s=yield*ue.forEach(yield*e.entries(),a=>a.type==="document"?ue.succeed([a]):ue.gen(function*(){let l=yield*el(n,a.path);return yield*ue.forEach(l,f=>n.readFileStringSafe(f.filepath).pipe(ue.map(p=>p&&tl(f,p)),ue.catch(()=>ue.succeed(void 0)))).pipe(ue.map(f=>f.filter(p=>p!==void 0)))})).pipe(ue.map(a=>a.flat())),d=ss(s.flatMap(a=>a.info.permissions??[]),o.home),c=ie.latest(s,"default_agent");c!==void 0&&i.default(W.ID.make(c));for(let a of i.list())i.update(a.id,l=>l.permissions.push(...d));for(let a of s)for(let[l,f]of Object.entries(a.info.agents??{})){let p=W.ID.make(l);if(f.disabled){i.remove(p);continue}let m=i.get(p)!==void 0;i.update(p,y=>{if(m||y.permissions.push(...d),f.model!==void 0){let g=oe.parse(f.model);y.model={id:g.modelID,providerID:g.providerID,variant:y.model?.variant}}f.variant!==void 0&&y.model!==void 0&&(y.model.variant=oe.VariantID.make(f.variant)),f.request!==void 0&&(Object.assign(y.request.headers,f.request.headers??{}),Object.assign(y.request.body,f.request.body??{})),f.system!==void 0&&(y.system=f.system),f.description!==void 0&&(y.description=f.description),f.mode!==void 0&&(y.mode=f.mode),f.hidden!==void 0&&(y.hidden=f.hidden),f.color!==void 0&&(y.color=f.color),f.steps!==void 0&&(y.steps=f.steps),f.permissions!==void 0&&y.permissions.push(...ss(f.permissions,o.home))})}}))})};function ss(t,e){return t.map(n=>Xd(n.action)?{...n,resource:Qd(n.resource,e)}:n)}r(ss,"expandPermissions");function Xd(t){return Jd.some(e=>e===t)}r(Xd,"isPathAction");function Qd(t,e){return t.startsWith("~/")?e+t.slice(1):t==="~"||t==="$HOME"?e:t.startsWith("$HOME/")||t.startsWith("$HOME\\")?e+t.slice(5):t}r(Qd,"expandHome");function el(t,e){return ue.forEach(Bd,n=>t.glob(n.pattern,{cwd:e,absolute:!0,dot:!0,symlink:!0}).pipe(ue.map(o=>o.toSorted().map(i=>({directory:e,filepath:i,primary:n.primary}))))).pipe(ue.map(n=>n.flat()),ue.catch(()=>ue.succeed([])))}r(el,"discover");function tl(t,e){let n=Nt.parseOption(e);if(!n)return;let o=Gd.relative(t.directory,t.filepath).replaceAll("\\","/").replace(/^(agent|agents|mode|modes)\//,"").replace(/\.md$/,""),i=n.content.trim(),s=Object.keys(n.data).some(a=>!Yd.has(a)),d=lr.getOrUndefined(s?lr.map(zd({name:o,...n.data,prompt:i},{errors:"all",propertyOrder:"original"}),Vi.migrateAgent):Kd({...n.data,system:i},{errors:"all",propertyOrder:"original"}));if(!d)return;let c=lr.getOrUndefined(Wd({agents:{[o]:t.primary?{...d,mode:"primary"}:d}}));if(c)return new ie.Document({type:"document",path:t.filepath,info:c})}r(tl,"decode");var Vn={};T(Vn,{ConfigCommandPlugin:()=>Vn,Plugin:()=>sl});import nl from"path";import{Effect as be,Option as ol,Schema as rl}from"effect";var il=rl.decodeUnknownOption(_i.Info),sl={id:"config-command",effect:be.fn(function*(t){let e=yield*ie.Service,n=yield*G.Service;yield*t.command.transform(be.fn(function*(o){let i=yield*be.forEach(yield*e.entries(),s=>s.type==="document"?be.succeed([{commands:s.info.commands}]):al(n,s.path).pipe(be.map(d=>[{commands:Object.fromEntries(d.map(c=>[c.name,c.info]))}]))).pipe(be.map(s=>s.flat()));for(let s of i)for(let[d,c]of Object.entries(s.commands??{}))o.update(d,a=>{if(a.template=c.template,c.description!==void 0&&(a.description=c.description),c.agent!==void 0&&(a.agent=c.agent),c.model!==void 0){let l=oe.parse(c.model);a.model={id:l.modelID,providerID:l.providerID,variant:a.model?.variant}}c.variant!==void 0&&a.model!==void 0&&(a.model.variant=oe.VariantID.make(c.variant)),c.subtask!==void 0&&(a.subtask=c.subtask)})}))})};function al(t,e){return be.gen(function*(){let n=yield*t.glob("{command,commands}/**/*.md",{cwd:e,absolute:!0,dot:!0,symlink:!0}).pipe(be.catch(()=>be.succeed([])));return yield*be.forEach(n.toSorted(),o=>t.readFileStringSafe(o).pipe(be.map(i=>i===void 0?void 0:cl(e,o,i)),be.catch(()=>be.succeed(void 0)))).pipe(be.map(o=>o.filter(i=>i!==void 0)))})}r(al,"loadDirectory");function cl(t,e,n){let o=Nt.parseOption(n);if(!o)return;let i=ol.getOrUndefined(il({...o.data,template:o.content.trim()}));if(i)return{name:nl.relative(t,e).replaceAll("\\","/").replace(/^(command|commands)\//,"").replace(/\.md$/,""),info:i}}r(cl,"decode");var jn={};T(jn,{ConfigExternalPlugin:()=>jn,Plugin:()=>pl});import{Effect as Et,Schema as Xe}from"effect";import ur from"path";import{fileURLToPath as dl,pathToFileURL as ll}from"url";var Nn={};T(Nn,{PluginPromise:()=>Nn,fromPromise:()=>cs});import{Effect as je,Scope as as}from"effect";function cs(t){return{id:t.id,effect:r(e=>je.gen(function*(){let n=yield*as.Scope,o=yield*je.context(),i=r(a=>je.runPromiseWith(o)(as.provide(n)(a)).then(l=>({dispose:r(()=>je.runPromiseWith(o)(l.dispose),"dispose")})),"register"),s=r(a=>je.runPromiseWith(o)(a),"run"),d=r(a=>l=>i(a.transform(f=>je.promise(()=>Promise.resolve(l(f))))),"transform"),c={options:e.options,agent:{transform:d(e.agent),reload:r(()=>s(e.agent.reload()),"reload")},aisdk:{sdk:r(a=>i(e.aisdk.sdk(l=>je.promise(()=>Promise.resolve(a(l))))),"sdk"),language:r(a=>i(e.aisdk.language(l=>je.promise(()=>Promise.resolve(a(l))))),"language")},catalog:{transform:d(e.catalog),reload:r(()=>s(e.catalog.reload()),"reload")},command:{transform:d(e.command),reload:r(()=>s(e.command.reload()),"reload")},integration:{transform:d(e.integration),reload:r(()=>s(e.integration.reload()),"reload"),connection:{active:r(a=>je.runPromiseWith(o)(e.integration.connection.active(a)),"active"),resolve:r(a=>je.runPromiseWith(o)(e.integration.connection.resolve(a)),"resolve")}},plugin:{add:r(a=>{let l=cs(a);return s(e.plugin.add(l))},"add"),remove:r(a=>s(e.plugin.remove(a)),"remove")},reference:{transform:d(e.reference),reload:r(()=>s(e.reference.reload()),"reload")},skill:{transform:d(e.skill),reload:r(()=>s(e.skill.reload()),"reload")}};yield*je.promise(()=>Promise.resolve(t.setup(c)))}),"effect")}}r(cs,"fromPromise");var fl=Xe.Struct({default:Xe.Union([Xe.Struct({id:Xe.String,effect:Xe.declare(t=>typeof t=="function")}),Xe.Struct({id:Xe.String,setup:Xe.declare(t=>typeof t=="function")})])}),pl={id:"config-plugin",effect:Et.fn(function*(t){let e=yield*ie.Service,n=yield*G.Service,o=yield*pe.Service,i=yield*Fe.Service;yield*Et.gen(function*(){let s=[];for(let d of yield*e.entries()){if(d.type==="document"){let c=d.path?ur.dirname(d.path):o.directory;for(let a of d.info.plugins??[]){let l=typeof a=="string"?{package:a}:a,f=l.package.startsWith("file://")?dl(l.package):l.package.startsWith("./")||l.package.startsWith("../")?ur.resolve(c,l.package):l.package;s.push({package:f,options:l.options})}}if(d.type==="directory"){let c=yield*n.glob("{plugin,plugins}/*.{ts,js}",{cwd:d.path,absolute:!0,include:"file",dot:!0,symlink:!0}).pipe(Et.orElseSucceed(()=>[]));c.sort();for(let a of c)s.push({package:a})}}for(let d of s)yield*Et.gen(function*(){let c=ur.isAbsolute(d.package)?ll(d.package).href:(yield*i.add(d.package)).entrypoint;if(!c)return;let a=yield*Et.promise(()=>import(c)),l=(yield*Xe.decodeUnknownEffect(fl)(a)).default,f="effect"in l?l:Nn.fromPromise(l);yield*t.plugin.add({id:f.id,effect:r(p=>f.effect({...p,options:d.options??{}}),"effect")})}).pipe(Et.ignoreCause)}).pipe(Et.forkScoped({startImmediately:!0}))})};var qn={};T(qn,{ConfigProviderPlugin:()=>qn,Plugin:()=>ul});import{Effect as mr}from"effect";var ul={id:"config-provider",effect:mr.fn(function*(t){let e=yield*ie.Service;yield*t.integration.transform(mr.fn(function*(n){let o=(yield*e.entries()).filter(s=>s.type==="document"),i=new Set(o.flatMap(s=>Object.entries(s.info.providers??{}).flatMap(([d,c])=>c.env===void 0?[]:[d])));for(let s of o)for(let[d,c]of Object.entries(s.info.providers??{})){let a=d;!i.has(d)&&!n.get(a)||(n.update(a,l=>{l.name=c.name??l.name}),c.env!==void 0&&n.method.update({integrationID:a,method:{type:"env",names:[...c.env]}}))}})),yield*t.catalog.transform(mr.fn(function*(n){let o=yield*e.entries(),i=o.filter(d=>d.type==="document"),s=ie.latest(o,"model");if(s!==void 0){let d=oe.parse(s);n.model.default.set(d.providerID,d.modelID)}for(let d of i)for(let[c,a]of Object.entries(d.info.providers??{})){let l=c;n.provider.update(l,f=>{a.name!==void 0&&(f.name=a.name),a.api!==void 0&&(f.api={...a.api}),a.request!==void 0&&(Object.assign(f.request.headers,a.request.headers),Object.assign(f.request.body,a.request.body))});for(let[f,p]of Object.entries(a.models??{}))n.model.update(l,f,m=>{if(p.family!==void 0&&(m.family=p.family),p.name!==void 0&&(m.name=p.name),p.api!==void 0&&(m.api={...m.api,...p.api}),p.capabilities!==void 0&&(m.capabilities={tools:p.capabilities.tools,input:[...p.capabilities.input],output:[...p.capabilities.output]}),p.request!==void 0&&(Object.assign(m.request.headers,p.request.headers),Object.assign(m.request.body,p.request.body),p.request.variant!==void 0&&(m.request.variant=p.request.variant)),p.variants!==void 0)for(let y of p.variants){let g=m.variants.find(b=>b.id===y.id);g||(g={id:y.id,headers:{},body:{}},m.variants.push(g)),Object.assign(g.headers,y.headers),Object.assign(g.body,y.body)}p.cost!==void 0&&(m.cost=(Array.isArray(p.cost)?p.cost:[p.cost]).map(y=>({tier:y.tier&&{...y.tier},input:y.input,output:y.output,cache:{read:y.cache?.read??0,write:y.cache?.write??0}}))),p.disabled!==void 0&&(m.enabled=!p.disabled),p.limit!==void 0&&(m.limit={...m.limit,...p.limit})})}}))})};var Xn={};T(Xn,{ConfigReferencePlugin:()=>Xn,Plugin:()=>$l});import To from"path";import{Effect as xs}from"effect";var ge={};T(ge,{Event:()=>Es,GitSource:()=>Vl,Info:()=>kr,LocalSource:()=>Ul,Reference:()=>ge,Service:()=>on,Source:()=>Nl,locationLayer:()=>jl,node:()=>ql});import{Context as _l,Effect as nn,Layer as Ml,Scope as Ll}from"effect";var Qe={};T(Qe,{Event:()=>ml,GitSource:()=>fs,Info:()=>gr,LocalSource:()=>ls,Reference:()=>Qe,Source:()=>ps});import{Schema as me}from"effect";var ds=Lt({type:"reference.updated",schema:{}}),ml={Updated:ds,Definitions:Ut(ds)},ls=me.Struct({type:me.Literal("local"),path:ne,description:me.String.pipe(le),hidden:me.Boolean.pipe(le)}).annotate({identifier:"Reference.LocalSource"}),fs=me.Struct({type:me.Literal("git"),repository:me.String,branch:me.String.pipe(le),description:me.String.pipe(le),hidden:me.Boolean.pipe(le)}).annotate({identifier:"Reference.GitSource"}),ps=me.Union([ls,fs]).pipe(me.toTaggedUnion("type")).annotate({identifier:"Reference.Source"}),gr=class extends me.Class("Reference.Info")({name:me.String,path:ne,description:me.String.pipe(le),hidden:me.Boolean.pipe(le),source:ps}){static{r(this,"Info")}};var ye={};T(ye,{InvalidBranchError:()=>Gn,InvalidReferenceError:()=>Fn,Repository:()=>ye,UnsupportedLocalRepositoryError:()=>Hn,cacheIdentity:()=>yr,cachePath:()=>kl,isError:()=>hl,isFile:()=>gs,isRemote:()=>hs,parse:()=>ms,parseRemote:()=>yl,same:()=>Sl,validateBranch:()=>vl});import us from"path";import{fileURLToPath as gl}from"url";import{Schema as et}from"effect";var Fn=class extends et.TaggedErrorClass()("RepositoryInvalidReferenceError",{repository:et.String,message:et.String}){static{r(this,"InvalidReferenceError")}},Hn=class extends et.TaggedErrorClass()("RepositoryUnsupportedLocalRepositoryError",{repository:et.String,message:et.String}){static{r(this,"UnsupportedLocalRepositoryError")}},Gn=class extends et.TaggedErrorClass()("RepositoryInvalidBranchError",{branch:et.String,message:et.String}){static{r(this,"InvalidBranchError")}};function hl(t){return t instanceof Fn||t instanceof Hn||t instanceof Gn}r(hl,"isError");function ms(t){let e=El(t);if(!e)return;let n=e.match(/^github:([^/\s]+)\/([^/\s]+)$/);if(n)return $n({host:"github.com",segments:[n[1],n[2]]});if(!e.includes("://")){let o=e.match(/^(?:[^@/\s]+@)?([^:/\s]+):(.+)$/);if(o)return $n({host:o[1],segments:hr(o[2]),remote:e});let i=hr(e);if(i.length>=2&&Il(i[0]))return $n({host:i[0],segments:i.slice(1)});if(i.length===2)return $n({host:"github.com",segments:i})}try{let o=new URL(e);if(o.protocol==="file:")return Cl({url:o,remote:e});let i=hr(o.pathname);return $n({host:o.host,segments:i,remote:o.host==="github.com"?ys(i.join("/")):e,protocol:o.protocol})}catch{return}}r(ms,"parse");function yl(t){let e=ms(t);if(!e)throw new Fn({repository:t,message:"Repository must be a git URL, host/path reference, or GitHub owner/repo shorthand"});if(!hs(e))throw new Hn({repository:t,message:"Local file repositories are not supported"});return e}r(yl,"parseRemote");function vl(t){if(!(/^[A-Za-z0-9/_.-]+$/.test(t)&&!t.startsWith("-")&&!t.includes("..")))throw new Gn({branch:t,message:"Branch must contain only alphanumeric characters, /, _, ., and -, and cannot start with - or contain .."})}r(vl,"validateBranch");function gs(t){return t.protocol==="file:"}r(gs,"isFile");function hs(t){return!gs(t)}r(hs,"isRemote");function kl(t,e,n){let o=us.join(t,...e.host.split(":"),...e.segments);return n?`${o}@${encodeURIComponent(n)}`:o}r(kl,"cachePath");function yr(t){return`${t.host}/${t.path}`}r(yr,"cacheIdentity");function Sl(t,e){return yr(t)===yr(e)}r(Sl,"same");function El(t){return t.trim().replace(/^git\+/,"").replace(/#.*$/,"").replace(/\/+$/,"")}r(El,"normalizeInput");function vr(t){return t.replace(/\.git$/,"")}r(vr,"trimGitSuffix");function hr(t){return t.split("/").map(e=>vr(e.trim())).filter(Boolean)}r(hr,"parts");function bl(t){return!!t&&!t.startsWith("-")&&!/[\s/\\]/.test(t)}r(bl,"safeHost");function xl(t){return t!=="."&&t!==".."&&!t.includes(":")&&!/[\s/\\]/.test(t)}r(xl,"safeSegment");function Il(t){return t.includes(".")||t.includes(":")||t==="localhost"}r(Il,"hostLike");function wl(t){return t.endsWith("/")?t:`${t}/`}r(wl,"withSlash");function ys(t){let e=process.env.OPENCODE_REPO_CLONE_GITHUB_BASE_URL;return e?new URL(`${t}.git`,wl(e)).href:`https://github.com/${t}.git`}r(ys,"githubRemote");function $n(t){let e=t.segments.map(vr).filter(Boolean);if(!bl(t.host)||!e.length||e.some(i=>!xl(i)))return;let n=e.join("/"),o=t.host.toLowerCase();return{host:o,path:n,segments:e,owner:e.length===2?e[0]:void 0,repo:e[e.length-1],remote:t.remote??(o==="github.com"?ys(n):`https://${o}/${n}.git`),label:o==="github.com"&&e.length===2?n:`${o}/${n}`,protocol:t.protocol}}r($n,"buildRemote");function Cl(t){let e=us.normalize(gl(t.url)),n=e.split(/[\\/]+/).filter(Boolean);if(n.length)return{host:"file",path:e,segments:n.map(o=>o.replace(/:$/,"")),owner:void 0,repo:vr(n[n.length-1]),remote:t.remote,label:e,protocol:"file:"}}r(Cl,"buildFile");var tn={};T(tn,{CacheOperationError:()=>Zn,CheckoutFailedError:()=>Wn,CloneFailedError:()=>zn,FetchFailedError:()=>bt,InvalidBranchError:()=>Kn,InvalidRepositoryError:()=>Bn,LockFailedError:()=>Yn,RepositoryCache:()=>tn,ResetFailedError:()=>Jn,Service:()=>en,isError:()=>ks,node:()=>Ol,parseRemote:()=>Dl,validateBranch:()=>Ss});import Pl from"path";import{Context as Rl,Effect as xe,Layer as Al,Schema as ee}from"effect";var Bn=class extends ee.TaggedErrorClass()("RepositoryCacheInvalidRepositoryError",{repository:ee.String,message:ee.String}){static{r(this,"InvalidRepositoryError")}},Kn=class extends ee.TaggedErrorClass()("RepositoryCacheInvalidBranchError",{branch:ee.String,message:ee.String}){static{r(this,"InvalidBranchError")}},zn=class extends ee.TaggedErrorClass()("RepositoryCacheCloneFailedError",{repository:ee.String,message:ee.String}){static{r(this,"CloneFailedError")}},bt=class extends ee.TaggedErrorClass()("RepositoryCacheFetchFailedError",{repository:ee.String,message:ee.String}){static{r(this,"FetchFailedError")}},Wn=class extends ee.TaggedErrorClass()("RepositoryCacheCheckoutFailedError",{repository:ee.String,branch:ee.String,message:ee.String}){static{r(this,"CheckoutFailedError")}},Jn=class extends ee.TaggedErrorClass()("RepositoryCacheResetFailedError",{repository:ee.String,message:ee.String}){static{r(this,"ResetFailedError")}},Yn=class extends ee.TaggedErrorClass()("RepositoryCacheLockFailedError",{localPath:ee.String,message:ee.String}){static{r(this,"LockFailedError")}},Zn=class extends ee.TaggedErrorClass()("RepositoryCacheOperationError",{operation:ee.String,path:ee.String,message:ee.String}){static{r(this,"CacheOperationError")}},en=class extends Rl.Service()("@opencode/RepositoryCache"){static{r(this,"Service")}};function ks(t){return t instanceof Bn||t instanceof Kn||t instanceof zn||t instanceof bt||t instanceof Wn||t instanceof Jn||t instanceof Yn||t instanceof Zn}r(ks,"isError");var Dl=xe.fn("RepositoryCache.parseRemote")(function*(t){return yield*xe.try({try:r(()=>ye.parseRemote(t),"try"),catch:r(e=>new Bn({repository:t,message:Do(e)}),"catch")})}),Ss=xe.fn("RepositoryCache.validateBranch")(function*(t){return yield*xe.try({try:r(()=>ye.validateBranch(t),"try"),catch:r(e=>new Kn({branch:t,message:Do(e)}),"catch")})}),Tl=Al.effect(en,xe.gen(function*(){let t=yield*G.Service,e=yield*Zo.Service,n=yield*Vt.Service,o=yield*H.Service;return en.of({ensure:xe.fn("RepositoryCache.ensure")(function*(i){i.branch&&(yield*Ss(i.branch));let s=i.reference.label,d=ye.cachePath(o.repos,i.reference,i.branch),c=ye.parse(i.reference.remote)??i.reference;return yield*n.withLock(xe.gen(function*(){yield*vs(t.ensureDir(Pl.dirname(d)),"ensure cache directory",d);let a=yield*e.repo.discover(ne.make(d)),l=a?yield*e.remote.get(a):void 0,f=l?ye.parse(l):void 0,p=a?yield*t.resolve(d):void 0,m=!!(a&&a.worktree===p&&f&&ye.same(f,c));!m&&(yield*t.existsSafe(d))&&(yield*vs(t.remove(d,{recursive:!0}),"remove stale cache",d));let y=m?i.refresh?"refreshed":"cached":"cloned";if(y==="cloned"&&(yield*e.repo.clone({remote:i.reference.remote,directory:ne.make(d),branch:i.branch}).pipe(xe.mapError(b=>new zn({repository:s,message:b.message})))),y==="refreshed"){if(!a)return yield*new bt({repository:s,message:"Repository is unavailable"});yield*e.sync.fetchRemotes(a).pipe(xe.mapError(C=>new bt({repository:s,message:C.message}))),i.branch&&(yield*e.sync.fetchBranch(a,{branch:i.branch}).pipe(xe.mapError(C=>new bt({repository:s,message:C.message}))));let b=i.branch??(yield*e.history.defaultRemoteBranch(a));b&&(yield*e.sync.checkoutRemoteBranch(a,{branch:b}).pipe(xe.mapError(C=>new Wn({repository:s,branch:b,message:C.message}))));let P=b??(yield*e.history.branch(a));yield*e.sync.resetHard(a,P?`origin/${P}`:"HEAD").pipe(xe.mapError(C=>new Jn({repository:s,message:C.message})))}let g=yield*e.repo.discover(ne.make(d));return{repository:s,host:i.reference.host,remote:i.reference.remote,localPath:d,status:y,head:g?yield*e.history.head(g):void 0,branch:g?yield*e.history.branch(g):void 0}}),`repository-cache:${d}`).pipe(xe.mapError(a=>ks(a)?a:new Yn({localPath:d,message:Do(a)})))})})})),Ol=ot({service:en,layer:Tl,deps:[Vt.node,G.node,Zo.node,H.node]});function Do(t){return t instanceof globalThis.Error?t.message:String(t)}r(Do,"errorMessage");function vs(t,e,n){return t.pipe(xe.mapError(o=>new Zn({operation:e,path:n,message:Do(o)})))}r(vs,"cacheOperation");var Ul=Qe.LocalSource,Vl=Qe.GitSource,Nl=Qe.Source,Es=Qe.Event,kr=Qe.Info,on=class extends _l.Service()("@opencode/v2/Reference"){static{r(this,"Service")}},bs=Ml.effect(on,nn.gen(function*(){let t=yield*H.Service,e=yield*se.Service,n=yield*tn.Service,o=yield*Ll.Scope,i=new Map,s=De.create({initial:r(()=>({sources:new Map}),"initial"),draft:r(d=>({add:r((c,a)=>d.sources.set(c,a),"add"),remove:r(c=>d.sources.delete(c),"remove"),list:r(()=>Array.from(d.sources.entries()),"list")}),"draft"),finalize:r(d=>nn.gen(function*(){i.clear();for(let[c,a]of d.list()){if(a.type==="local"){i.set(c,new kr({name:c,path:a.path,...a.description===void 0?{}:{description:a.description},...a.hidden===void 0?{}:{hidden:a.hidden},source:a}));continue}let l=ye.parse(a.repository);if(!(!l||!ye.isRemote(l))){if(a.branch)try{ye.validateBranch(a.branch)}catch{continue}i.set(c,new kr({name:c,path:ne.make(ye.cachePath(t.repos,l,a.branch)),...a.description===void 0?{}:{description:a.description},...a.hidden===void 0?{}:{hidden:a.hidden},source:a})),yield*n.ensure({reference:l,branch:a.branch,refresh:!0}).pipe(nn.catchCause(f=>nn.logWarning("failed to materialize reference",{name:c,repository:a.repository,cause:f})),nn.forkIn(o))}}yield*e.publish(Es.Updated,{})}),"finalize")});return on.of({transform:s.transform,reload:s.reload,list:nn.fn("Reference.list")(function*(){return Array.from(i.values())})})})),jl=bs,ql=Se({service:on,layer:bs,deps:[H.node,se.node,tn.node]});var $l={id:"core/config-reference",effect:xs.fn(function*(t){let e=yield*ie.Service,n=yield*pe.Service,o=yield*H.Service;yield*t.reference.transform(xs.fn(function*(i){let s=new Map;for(let d of(yield*e.entries()).filter(c=>c.type==="document")){let c=d.path?To.dirname(d.path):n.directory;for(let[a,l]of Object.entries(d.info.references??{})){if(!Fl(a))continue;let f=typeof l=="string"?void 0:l.description,p=typeof l=="string"?void 0:l.hidden;s.set(a,Hl(l)?ge.LocalSource.make({type:"local",path:ne.make(Gl(c,o.home,typeof l=="string"?l:l.path)),...f===void 0?{}:{description:f},...p===void 0?{}:{hidden:p}}):ge.GitSource.make({type:"git",repository:typeof l=="string"?l:l.repository,...l.branch===void 0?{}:{branch:l.branch},...f===void 0?{}:{description:f},...p===void 0?{}:{hidden:p}}))}}for(let[d,c]of s)i.add(d,c)}))})};function Fl(t){return t.length>0&&!/[\/\s`,]/.test(t)}r(Fl,"validAlias");function Hl(t){return typeof t=="string"?t.startsWith(".")||t.startsWith("/")||t.startsWith("~"):"path"in t}r(Hl,"local");function Gl(t,e,n){return n.startsWith("~/")?To.join(e,n.slice(2)):To.isAbsolute(n)?n:To.resolve(t,n)}r(Gl,"localPath");var eo={};T(eo,{ConfigSkillPlugin:()=>eo,Plugin:()=>pf});import Qn from"path";import{Effect as Ts}from"effect";var ae={};T(ae,{DirectorySource:()=>nf,EmbeddedSource:()=>rf,Info:()=>sf,Service:()=>an,SkillV2:()=>ae,Source:()=>Ir,UrlSource:()=>of,available:()=>af,node:()=>ff});import Ds from"path";import{Context as ef,Effect as ct,Layer as tf,Schema as dt}from"effect";var tt={};T(tt,{DirectorySource:()=>Is,EmbeddedSource:()=>Ps,Info:()=>Cs,Skill:()=>tt,Source:()=>Bl,UrlSource:()=>ws});import{Schema as he}from"effect";var Is=he.Struct({type:he.Literal("directory"),path:ne}).annotate({identifier:"SkillV2.DirectorySource"}),ws=he.Struct({type:he.Literal("url"),url:he.String}).annotate({identifier:"SkillV2.UrlSource"}),Cs=he.Struct({name:he.String,description:he.String.pipe(le),slash:he.Boolean.pipe(le),location:ne,content:he.String}).annotate({identifier:"SkillV2.Info"}),Ps=he.Struct({type:he.Literal("embedded"),skill:he.suspend(()=>Cs)}).annotate({identifier:"SkillV2.EmbeddedSource"}),Bl=Object.assign(he.Union([Is,ws,Ps]).pipe(he.toTaggedUnion("type"),he.annotate({identifier:"SkillV2.Source"})),{equals:r((t,e)=>t.type!==e.type?!1:t.type==="directory"&&e.type==="directory"?t.path===e.path:t.type==="url"&&e.type==="url"?t.url===e.url:t.type==="embedded"&&e.type==="embedded"?t.skill.name===e.skill.name:!1,"equals"),key:r(t=>t.type==="directory"?`directory:${t.path}`:t.type==="url"?`url:${t.url}`:`embedded:${t.skill.name}`,"key")});var sn={};T(sn,{Service:()=>rn,SkillDiscovery:()=>sn,node:()=>Ql});import Me from"path";import{Context as Kl,Effect as V,Layer as zl,Schedule as Rs,Schema as at}from"effect";import{HttpClient as Sr,HttpClientRequest as Er,HttpClientResponse as Wl}from"effect/unstable/http";var Jl=4,As=8;function Yl(t){return t.length>0&&t!=="."&&t!==".."&&!t.includes("/")&&!t.includes("\\")&&!t.includes("\0")}r(Yl,"isSafeSegment");function Zl(t){let e=t.split("/");return t.length>0&&!t.includes("\\")&&!t.includes("\0")&&!t.includes("?")&&!t.includes("#")&&!URL.canParse(t)&&!Me.posix.isAbsolute(t)&&!Me.win32.isAbsolute(t)&&e.every(n=>{try{let o=decodeURIComponent(n);return o.length>0&&o!=="."&&o!==".."&&!o.includes("/")&&!o.includes("\\")&&!o.includes("\0")}catch{return!1}})}r(Zl,"isSafeRelativePath");var br=class extends at.Class("SkillDiscovery.IndexSkill")({name:at.String,version:at.optional(at.String),files:at.Array(at.String)}){static{r(this,"IndexSkill")}},xr=class extends at.Class("SkillDiscovery.Index")({skills:at.Array(br)}){static{r(this,"Index")}},rn=class extends Kl.Service()("@opencode/v2/SkillDiscovery"){static{r(this,"Service")}},Xl=zl.effect(rn,V.gen(function*(){let t=yield*G.Service,e=yield*H.Service,n=(yield*Sr.HttpClient).pipe(Sr.retryTransient({retryOn:"errors-and-responses",times:2,schedule:Rs.exponential(200).pipe(Rs.jittered)}),Sr.filterStatusOk),o=V.fn("SkillDiscovery.download")(function*(i,s){return(yield*t.exists(s).pipe(V.orDie))?!0:yield*Er.get(i).pipe(n.execute,V.flatMap(d=>d.arrayBuffer),V.flatMap(d=>t.writeWithDirs(s,new Uint8Array(d))),V.as(!0),V.catch(d=>V.logError("failed to download skill file",{url:i,error:d}).pipe(V.as(!1))))});return rn.of({pull:V.fn("SkillDiscovery.pull")(function*(i){let s=i.endsWith("/")?i:`${i}/`,d=new URL(s),c=new URL("index.json",d).href,a=yield*Er.get(c).pipe(Er.acceptJson,n.execute,V.flatMap(Wl.schemaBodyJson(xr)),V.catch(f=>V.logError("failed to fetch skill index",{url:c,error:f}).pipe(V.as(void 0))));if(!a)return[];let l=Me.resolve(e.cache,"skills",Bun.hash(s).toString(16));return yield*V.forEach(a.skills.flatMap(f=>{if(!Yl(f.name))return[];if(!f.files.includes("SKILL.md")&&!f.files.includes(`${f.name}.md`))return[];let p=Me.resolve(l,f.name);if(!G.contains(l,p)||p===l)return[];let m=new URL(`${encodeURIComponent(f.name)}/`,d),y=Me.join(p,".opencode-version"),g=f.files.map(b=>{if(!Zl(b))return;let P;try{P=new URL(b,m)}catch{return}if(P.origin!==d.origin)return;let C=Me.resolve(p,b);if(!(!G.contains(p,C)||C===p))return{url:P.href,destination:C,file:b}});return g.some(b=>b===void 0)?[]:[{skill:f,root:p,versionFile:y,files:g}]}),({skill:f,root:p,versionFile:m,files:y})=>V.gen(function*(){let g=f.version,b=g===void 0?void 0:yield*t.readFileStringSafe(m).pipe(V.catch(()=>V.succeed(void 0)));if(g===void 0||b===g)yield*V.forEach(y,C=>o(C.url,C.destination),{concurrency:As,discard:!0});else{let C=crypto.randomUUID(),A=`${p}.tmp-${C}`,S=`${p}.old-${C}`;yield*V.gen(function*(){!(yield*V.forEach(y,B=>o(B.url,Me.resolve(A,B.file)),{concurrency:As})).every(Boolean)||!((yield*t.exists(Me.join(A,"SKILL.md")).pipe(V.orDie))||(yield*t.exists(Me.join(A,`${f.name}.md`)).pipe(V.orDie)))||(yield*t.writeFileString(Me.join(A,".opencode-version"),g),yield*V.uninterruptible(V.gen(function*(){let B=yield*t.exists(p).pipe(V.orDie);B&&(yield*t.rename(p,S)),yield*t.rename(A,p).pipe(V.catch(K=>V.gen(function*(){return B&&(yield*t.rename(S,p).pipe(V.ignore)),yield*V.fail(K)}))),B&&(yield*t.remove(S,{recursive:!0,force:!0}).pipe(V.ignore))})))}).pipe(V.catch(w=>V.logError("failed to refresh skill",{skill:f.name,error:w})),V.ensuring(t.remove(A,{recursive:!0,force:!0}).pipe(V.ignore)))}return(yield*t.exists(Me.join(p,"SKILL.md")).pipe(V.orDie))||(yield*t.exists(Me.join(p,`${f.name}.md`)).pipe(V.orDie))?[ne.make(p)]:[]}),{concurrency:Jl}).pipe(V.map(f=>f.flat()))})})})),Ql=ot({service:rn,layer:Xl,deps:[rt,G.node,H.node]});var nf=tt.DirectorySource,of=tt.UrlSource,rf=tt.EmbeddedSource,Ir=tt.Source,sf=tt.Info,af=r((t,e)=>t.filter(n=>Ce.evaluate("skill",n.name,e.permissions).effect!=="deny"),"available"),cf=dt.Struct({name:dt.String.pipe(dt.optional),description:dt.String.pipe(dt.optional),slash:dt.Boolean.pipe(dt.optional)}),df=dt.decodeUnknownOption(cf),an=class extends ef.Service()("@opencode/v2/Skill"){static{r(this,"Service")}},lf=tf.effect(an,ct.gen(function*(){let t=yield*sn.Service,e=yield*G.Service,n=De.create({initial:r(()=>({sources:[]}),"initial"),draft:r(d=>({source:r(c=>{d.sources.some(a=>Ir.equals(a,c))||d.sources.push(c)},"source"),list:r(()=>d.sources,"list")}),"draft")}),o=ct.fn("SkillV2.load")(function*(d){let c=[];if(d.type==="embedded")return[d.skill];let a=d.type==="directory"?[d.path]:yield*t.pull(d.url);for(let l of a){let f=yield*e.glob("{*.md,**/SKILL.md}",{cwd:l,absolute:!0,include:"file",symlink:!0,dot:!0}).pipe(ct.catch(()=>ct.succeed([])));for(let p of f.toSorted()){let m=yield*e.readFileStringSafe(p).pipe(ct.catch(()=>ct.succeed(void 0)));if(!m)continue;let y=Nt.parseOption(m);if(!y)continue;let g=df(y.data).valueOrUndefined;if(!g)continue;let b=g.name!==void 0?g.name:Ds.dirname(p)===l?Ds.basename(p,".md"):void 0;b&&c.push({name:b,description:g.description,slash:g.slash,location:ne.make(p),content:y.content})}}return c}),i=new Map,s=ct.fn("SkillV2.list")(function*(){let d=new Map;for(let c of n.get().sources){let a=Ir.key(c),l=i.get(a)??(yield*o(c));i.set(a,l);for(let f of l)d.set(f.name,f)}return Array.from(d.values())});return an.of({transform:n.transform,reload:n.reload,sources:ct.fn("SkillV2.sources")(function*(){return n.get().sources}),list:s})})),ff=Se({service:an,layer:lf,deps:[sn.node,G.node]});var pf={id:"config-skill",effect:Ts.fn(function*(t){let e=yield*ie.Service,n=yield*H.Service,o=yield*pe.Service;yield*t.skill.transform(Ts.fn(function*(i){let s=yield*e.entries(),d=s.flatMap(a=>a.type==="directory"?[a.path]:[]),c=s.flatMap(a=>a.type==="document"?a.info.skills??[]:[]);for(let a of d)i.source(ae.DirectorySource.make({type:"directory",path:ne.make(Qn.join(a,"skill"))})),i.source(ae.DirectorySource.make({type:"directory",path:ne.make(Qn.join(a,"skills"))}));for(let a of c){if(URL.canParse(a)&&/^(https?:)$/.test(new URL(a).protocol)){i.source(ae.UrlSource.make({type:"url",url:a}));continue}let l=a.startsWith("~/")?Qn.join(n.home,a.slice(2)):a;i.source(ae.DirectorySource.make({type:"directory",path:ne.make(Qn.isAbsolute(l)?l:Qn.join(o.directory,l))}))}}))})};var Be={};T(Be,{Event:()=>Ns,ID:()=>bf,PluginV2:()=>Be,Service:()=>fn,locationLayer:()=>xf,node:()=>If});import{Context as Ef,Deferred as Oo,Effect as Y,Exit as _o,Layer as It,Scope as xt}from"effect";var cn={};T(cn,{Event:()=>uf,ID:()=>Ms,Plugin:()=>cn});import{Schema as Os}from"effect";var Ms=Os.String.pipe(Os.brand("Plugin.ID")),_s=Lt({type:"plugin.added",schema:{id:Ms}}),uf={Added:_s,Definitions:Ut(_s)};var lt={};T(lt,{AISDK:()=>lt,InitError:()=>dn,Service:()=>ln,locationLayer:()=>Vs,node:()=>kf});import{Cause as mf,Context as gf,Effect as nt,Layer as hf,Schema as Ls,Scope as Us}from"effect";function yf(t,e,n){if(typeof e!="number"||e<=0||!t.body||!t.headers.get("content-type")?.includes("text/event-stream"))return t;let o=t.body.getReader(),i=new ReadableStream({async pull(s){let d=await new Promise((c,a)=>{let l=setTimeout(()=>{let f=new Error("SSE read timed out");n.abort(f),o.cancel(f).catch(()=>{}),a(f)},e);o.read().then(f=>{clearTimeout(l),c(f)},f=>{clearTimeout(l),a(f)})});if(d.done){s.close();return}s.enqueue(d.value)},async cancel(s){n.abort(s),await o.cancel(s)}});return new Response(i,{headers:new Headers(t.headers),status:t.status,statusText:t.statusText})}r(yf,"wrapSSE");function vf(t,e){let n={name:t.providerID,...t.api.type==="aisdk"?t.api.settings??{}:{},...t.request.body};t.api.type==="aisdk"&&t.api.url&&(n.baseURL=t.api.url);let o=n.fetch,i=n.chunkTimeout;return delete n.chunkTimeout,n.fetch=async(s,d)=>{let c={...d??{}},a=[c.signal,typeof i=="number"&&i>0?new AbortController:void 0,n.timeout!==void 0&&n.timeout!==null&&n.timeout!==!1?AbortSignal.timeout(n.timeout):void 0].filter(m=>!!m),l=a.find(m=>m instanceof AbortController),f=a.map(m=>m instanceof AbortController?m.signal:m);if(f.length===1&&(c.signal=f[0]),f.length>1&&(c.signal=AbortSignal.any(f)),(e==="@ai-sdk/openai"||e==="@ai-sdk/azure"||e==="@ai-sdk/amazon-bedrock/mantle")&&c.body&&c.method==="POST"){let m=JSON.parse(c.body);if(m.store!==!0&&Array.isArray(m.input)){for(let y of m.input)"id"in y&&delete y.id;c.body=JSON.stringify(m)}}let p=await(typeof o=="function"?o:fetch)(s,{...c,timeout:!1});return!l||typeof i!="number"?p:yf(p,i,l)},n}r(vf,"prepareOptions");var dn=class extends Ls.TaggedErrorClass()("AISDK.InitError",{providerID:_.ID,cause:Ls.Defect()}){static{r(this,"InitError")}};function wr(t){return nt.catchCause(e=>nt.fail(new dn({providerID:t,cause:mf.squash(e)})))}r(wr,"initError");var ln=class extends gf.Service()("@opencode/v2/AISDK"){static{r(this,"Service")}},Vs=hf.effect(ln,nt.gen(function*(){let t=[],e=[],n=new Map,o=new Map,i=r((c,a)=>nt.fn("AISDK.hook")(function*(l){let f=yield*Us.Scope,p=!0;a([...c(),l]);let m=nt.sync(()=>{p&&(p=!1,a(c().filter(y=>y!==l)))});return yield*Us.addFinalizer(f,m),{dispose:m}}),"register"),s=nt.fnUntraced(function*(c,a){for(let l of c){let f=l(a);nt.isEffect(f)&&(yield*f)}return a}),d=ln.of({hook:{sdk:i(()=>t,c=>t=c),language:i(()=>e,c=>e=c)},runSDK:r(c=>s(t,c),"runSDK"),runLanguage:r(c=>s(e,c),"runLanguage"),language:nt.fn("AISDK.language")(function*(c){let a=`${c.providerID}/${c.id}/${c.request.variant??"default"}`,l=n.get(a);if(l)return l;if(c.api.type!=="aisdk")return yield*new dn({providerID:c.providerID,cause:new Error(`Unsupported api ${c.api.type}`)});let f=vf(c,c.api.package),p=JSON.stringify({providerID:c.providerID,api:c.api,options:f}),m=o.get(p)??(yield*d.runSDK({model:c,package:c.api.package,options:f}).pipe(wr(c.providerID))).sdk;if(!m)return yield*new dn({providerID:c.providerID,cause:new Error("No AISDK provider plugin returned an SDK")});o.set(p,m);let y=yield*d.runLanguage({model:c,sdk:m,options:f}).pipe(wr(c.providerID)),g=yield*nt.sync(()=>y.language??m.languageModel(c.api.id)).pipe(wr(c.providerID));return n.set(a,g),g})});return d})),kf=Se({service:ln,layer:Vs,deps:[]});var to={};T(to,{PluginHost:()=>to,make:()=>Sf});import{Effect as ve,Schema as Cr}from"effect";var Ge=r(t=>t,"mutable"),Sf=ve.fn("PluginHost.make")(function*(t){let e=yield*W.Service,n=yield*lt.Service,o=yield*Je.Service,i=yield*Oe.Service,s=yield*N.Service,d=yield*ge.Service,c=yield*ae.Service;return{options:{},agent:{reload:e.reload,transform:r(a=>e.transform(l=>a({list:r(()=>Ge(l.list()),"list"),get:r(f=>Ge(l.get(W.ID.make(f))),"get"),default:r(f=>l.default(f===void 0?void 0:W.ID.make(f)),"default"),update:r((f,p)=>l.update(W.ID.make(f),p),"update"),remove:r(f=>l.remove(W.ID.make(f)),"remove")})),"transform")},aisdk:{sdk:r(a=>n.hook.sdk(l=>{let f={model:Ge(l.model),package:l.package,options:l.options,sdk:l.sdk},p=a(f);return ve.suspend(()=>ve.isEffect(p)?p:ve.void).pipe(ve.tap(()=>ve.sync(()=>l.sdk=f.sdk)))}),"sdk"),language:r(a=>n.hook.language(l=>{let f={model:Ge(l.model),sdk:l.sdk,options:l.options,language:l.language},p=a(f);return ve.suspend(()=>ve.isEffect(p)?p:ve.void).pipe(ve.tap(()=>ve.sync(()=>l.language=f.language)))}),"language")},catalog:{reload:o.reload,transform:r(a=>o.transform(l=>a({provider:{list:r(()=>Ge(l.provider.list()),"list"),get:r(f=>Ge(l.provider.get(_.ID.make(f))),"get"),update:r((f,p)=>l.provider.update(_.ID.make(f),p),"update"),remove:r(f=>l.provider.remove(_.ID.make(f)),"remove")},model:{get:r((f,p)=>Ge(l.model.get(_.ID.make(f),oe.ID.make(p))),"get"),update:r((f,p,m)=>l.model.update(_.ID.make(f),oe.ID.make(p),m),"update"),remove:r((f,p)=>l.model.remove(_.ID.make(f),oe.ID.make(p)),"remove"),default:{get:l.model.default.get,set:r((f,p)=>l.model.default.set(_.ID.make(f),oe.ID.make(p)),"set")}}})),"transform")},command:{reload:i.reload,transform:i.transform},integration:{reload:s.reload,connection:{active:r(a=>s.connection.active(N.ID.make(a)),"active"),resolve:r(a=>s.connection.resolve(a.type==="credential"?{...a,id:$e.ID.make(a.id)}:a),"resolve")},transform:r(a=>s.transform(l=>a({list:r(()=>Ge(l.list()),"list"),get:r(f=>Ge(l.get(N.ID.make(f))),"get"),update:r((f,p)=>l.update(N.ID.make(f),p),"update"),remove:r(f=>l.remove(N.ID.make(f)),"remove"),method:{list:r(f=>Ge(l.method.list(N.ID.make(f))),"list"),update:r(f=>{if("authorize"in f){let p=N.MethodID.make(f.method.id),m=f.refresh;l.method.update({integrationID:N.ID.make(f.integrationID),method:{...f.method,id:p},authorize:r(y=>f.authorize(y).pipe(ve.map(g=>g.mode==="auto"?{...g,callback:g.callback.pipe(ve.map(b=>$e.OAuth.make({...b,methodID:N.MethodID.make(b.methodID)})))}:{...g,callback:r(b=>g.callback(b).pipe(ve.map(P=>$e.OAuth.make({...P,methodID:N.MethodID.make(P.methodID)}))),"callback")})),"authorize"),...m?{refresh:r(y=>m(y).pipe(ve.map(g=>$e.OAuth.make({...g,methodID:N.MethodID.make(g.methodID)}))),"refresh")}:{},...f.label?{label:f.label}:{}});return}if(f.method.type==="env"){l.method.update({integrationID:N.ID.make(f.integrationID),method:{type:"env",names:f.method.names}});return}l.method.update({integrationID:N.ID.make(f.integrationID),method:{type:"key",label:f.method.label}})},"update"),remove:r((f,p)=>l.method.remove(N.ID.make(f),Cr.decodeUnknownSync(N.Method)(p)),"remove")}})),"transform")},plugin:{add:r(a=>t.add(Be.ID.make(a.id),a.effect),"add"),remove:r(a=>t.remove(Be.ID.make(a)),"remove")},reference:{reload:d.reload,transform:r(a=>d.transform(l=>a({add:r((f,p)=>l.add(f,Cr.decodeUnknownSync(ge.Source)(p)),"add"),remove:l.remove,list:l.list})),"transform")},skill:{reload:c.reload,transform:r(a=>c.transform(l=>a({source:r(f=>l.source(Cr.decodeUnknownSync(ae.Source)(f)),"source"),list:l.list})),"transform")}}});var bf=cn.ID,Ns=cn.Event,fn=class extends Ef.Service()("@opencode/v2/Plugin"){static{r(this,"Service")}},js=It.effect(fn,Y.gen(function*(){let t=yield*se.Service,e=Ai.makeUnsafe(),n=yield*xt.make(),o=new Map,i=new Set,s=new Map,d=new Map,c,a=Y.fn("Plugin.add")(function*(m,y){if(i.has(m))return yield*Y.die(`Plugin load cycle detected for ${m}`);yield*e.withLock(m)(Y.sync(()=>{i.add(m),d.delete(m)}).pipe(Y.andThen(De.batch(Y.gen(function*(){let g=o.get(m);o.delete(m),g&&(yield*xt.close(g,_o.void).pipe(Y.ignore));let b=yield*xt.fork(n);yield*y(c).pipe(xt.provide(b),Y.withSpan("Plugin.load",{attributes:{"plugin.id":m}}),Y.onExit(P=>_o.isFailure(P)?xt.close(b,P):Y.void)),yield*t.publish(Ns.Added,{id:m}),o.set(m,b),yield*Y.forEach(s.get(m)??[],P=>Oo.succeed(P,void 0),{discard:!0}),s.delete(m)}))),Y.onExit(g=>_o.isSuccess(g)?Y.void:(d.set(m,g),Y.forEach(s.get(m)??[],b=>Oo.done(b,g),{discard:!0}).pipe(Y.ensuring(Y.sync(()=>s.delete(m)))))),Y.ensuring(Y.sync(()=>i.delete(m)))))}),l=Y.fn("Plugin.remove")(function*(m){if(i.has(m))return yield*Y.die(`Cannot remove plugin ${m} while it is loading`);yield*e.withLock(m)(De.batch(Y.gen(function*(){let y=o.get(m);o.delete(m),d.delete(m),y&&(yield*xt.close(y,_o.void).pipe(Y.ignore))})))}),f=Y.fn("Plugin.wait")(function*(m){let y=yield*Oo.make(),g=yield*e.withLock(m)(Y.sync(()=>{if(o.has(m))return!1;let b=d.get(m);if(b)return b;let P=s.get(m)??new Set;return P.add(y),s.set(m,P),!0}));if(g){if(typeof g!="boolean")return yield*g;yield*Oo.await(y).pipe(Y.ensuring(e.withLock(m)(Y.sync(()=>{let b=s.get(m);b?.delete(y),b?.size===0&&s.delete(m)}))))}});yield*Y.addFinalizer(m=>Y.gen(function*(){o.clear(),yield*De.batch(xt.close(n,m))}));let p=fn.of({add:a,remove:l,wait:f});return c=yield*to.make(p),p})),xf=js.pipe(It.provideMerge(W.locationLayer),It.provideMerge(lt.locationLayer),It.provideMerge(Je.locationLayer),It.provideMerge(Oe.locationLayer),It.provideMerge(N.locationLayer),It.provideMerge(ge.locationLayer)),If=Se({service:fn,layer:js,deps:[se.node,W.node,lt.node,Je.node,Oe.node,N.node,ge.node,ae.node]});import{FetchHttpClient as Op,HttpClient as Ja}from"effect/unstable/http";var no={};T(no,{AgentPlugin:()=>no,Plugin:()=>Of});import pn from"path";import{Effect as wf}from"effect";var Cf=pn.join(H.Path.data,"tool-output","*"),Pf="You are an AI coding agent. Help the user accomplish software engineering tasks by inspecting the workspace, making targeted changes, and using tools according to the configured permissions.",Rf=`You are a file search specialist. You excel at thoroughly navigating and exploring codebases.
|
|
15
|
+
|
|
16
|
+
Your strengths:
|
|
17
|
+
- Rapidly finding files using glob patterns
|
|
18
|
+
- Searching code and text with powerful regex patterns
|
|
19
|
+
- Reading and analyzing file contents
|
|
20
|
+
|
|
21
|
+
Guidelines:
|
|
22
|
+
- Use Glob for broad file pattern matching
|
|
23
|
+
- Use Grep for searching file contents with regex
|
|
24
|
+
- Use Read when you know the specific file path you need to read
|
|
25
|
+
- Adapt your search approach based on the thoroughness level specified by the caller
|
|
26
|
+
- Return file paths as absolute paths in your final response
|
|
27
|
+
- For clear communication, avoid using emojis
|
|
28
|
+
- Do not create any files, or run bash commands that modify the user's system state in any way
|
|
29
|
+
|
|
30
|
+
Complete the user's search request efficiently and report your findings clearly.`,Af=`You are a context summarization agent. You are given a conversation between a user and an agent. Your goal is to produce a structured summary matching the format specified so another coding agent can continue the work.
|
|
31
|
+
|
|
32
|
+
Always follow the exact output structure requested by the user prompt. Keep every section, preserve exact file paths and identifiers when known, and prefer terse bullets over paragraphs.
|
|
33
|
+
|
|
34
|
+
Do not continue the conversation. Do not respond to any questions in the conversation. Only output the structured summary in the exact format requested by the user prompt. Respond in the same language as the conversation.`,Df=`You are a title generator. You output ONLY a thread title. Nothing else.
|
|
35
|
+
|
|
36
|
+
<task>
|
|
37
|
+
Generate a brief title that would help the user find this conversation later.
|
|
38
|
+
|
|
39
|
+
Follow all rules in <rules>
|
|
40
|
+
Use the <examples> so you know what a good title looks like.
|
|
41
|
+
Your output must be:
|
|
42
|
+
- A single line
|
|
43
|
+
- <=50 characters
|
|
44
|
+
- No explanations
|
|
45
|
+
</task>
|
|
46
|
+
|
|
47
|
+
<rules>
|
|
48
|
+
- you MUST use the same language as the user message you are summarizing
|
|
49
|
+
- Title must be grammatically correct and read naturally - no word salad
|
|
50
|
+
- Never include tool names in the title (e.g. "read tool", "bash tool", "edit tool")
|
|
51
|
+
- Focus on the main topic or question the user needs to retrieve
|
|
52
|
+
- Vary your phrasing - avoid repetitive patterns like always starting with "Analyzing"
|
|
53
|
+
- When a file is mentioned, focus on WHAT the user wants to do WITH the file, not just that they shared it
|
|
54
|
+
- Keep exact: technical terms, numbers, filenames, HTTP codes
|
|
55
|
+
- Remove: the, this, my, a, an
|
|
56
|
+
- Never assume tech stack
|
|
57
|
+
- Never use tools
|
|
58
|
+
- NEVER respond to questions, just generate a title for the conversation
|
|
59
|
+
- The title should NEVER include "summarizing" or "generating" when generating a title
|
|
60
|
+
- DO NOT SAY YOU CANNOT GENERATE A TITLE OR COMPLAIN ABOUT THE INPUT
|
|
61
|
+
- Always output something meaningful, even if the input is minimal.
|
|
62
|
+
- If the user message is short or conversational (e.g. "hello", "lol", "what's up", "hey"):
|
|
63
|
+
-> create a title that reflects the user's tone or intent (such as Greeting, Quick check-in, Light chat, Intro message, etc.)
|
|
64
|
+
</rules>
|
|
65
|
+
|
|
66
|
+
<examples>
|
|
67
|
+
"debug 500 errors in production" -> Debugging production 500 errors
|
|
68
|
+
"refactor user service" -> Refactoring user service
|
|
69
|
+
"why is app.js failing" -> app.js failure investigation
|
|
70
|
+
"implement rate limiting" -> Rate limiting implementation
|
|
71
|
+
"how do I connect postgres to my API" -> Postgres API connection
|
|
72
|
+
"best practices for React hooks" -> React hooks best practices
|
|
73
|
+
"@src/credential.ts can you add refresh token support" -> Credential refresh token support
|
|
74
|
+
"@utils/parser.ts this is broken" -> Parser bug fix
|
|
75
|
+
"look at @config.json" -> Config review
|
|
76
|
+
"@App.tsx add dark mode toggle" -> Dark mode toggle in App
|
|
77
|
+
</examples>`,Tf=`Summarize what was done in this conversation. Write like a pull request description.
|
|
78
|
+
|
|
79
|
+
Rules:
|
|
80
|
+
- 2-3 sentences max
|
|
81
|
+
- Describe the changes made, not the process
|
|
82
|
+
- Do not mention running tests, builds, or other validation steps
|
|
83
|
+
- Do not explain what the user asked for
|
|
84
|
+
- Write in first person (I added..., I fixed...)
|
|
85
|
+
- Never ask questions or add new questions
|
|
86
|
+
- If the conversation ends with an unanswered question to the user, preserve that exact question
|
|
87
|
+
- If the conversation ends with an imperative statement or request to the user (e.g. "Now please run the command and paste the console output"), always include that exact request in the summary`,Of={id:"agent",effect:wf.fn(function*(t){let n=(yield*pe.Service).directory,o=[Cf,pn.join(H.Path.tmp,"*")],i=[{action:"external_directory",resource:"*",effect:"ask"},...o.map(d=>({action:"external_directory",resource:d,effect:"allow"}))],s=[{action:"*",resource:"*",effect:"allow"},...i,{action:"question",resource:"*",effect:"deny"},{action:"plan_enter",resource:"*",effect:"deny"},{action:"plan_exit",resource:"*",effect:"deny"},{action:"read",resource:"*",effect:"allow"},{action:"read",resource:"*.env",effect:"ask"},{action:"read",resource:"*.env.*",effect:"ask"},{action:"read",resource:"*.env.example",effect:"allow"}];yield*t.agent.transform(d=>{d.update(W.defaultID,c=>{c.description="The default agent. Executes tools based on configured permissions.",c.system??=Pf,c.mode="primary",c.permissions.push(...Ce.merge(s,[{action:"question",resource:"*",effect:"allow"},{action:"plan_enter",resource:"*",effect:"allow"}]))}),d.update(W.ID.make("plan"),c=>{c.description="Plan mode. Disallows all edit tools.",c.mode="primary",c.permissions.push(...Ce.merge(s,[{action:"question",resource:"*",effect:"allow"},{action:"plan_exit",resource:"*",effect:"allow"},{action:"external_directory",resource:pn.join(H.Path.data,"plans","*"),effect:"allow"},{action:"edit",resource:"*",effect:"deny"},{action:"edit",resource:pn.join(".opencode","plans","*.md"),effect:"allow"},{action:"edit",resource:pn.relative(n,pn.join(H.Path.data,"plans","*.md")),effect:"allow"}]))}),d.update(W.ID.make("general"),c=>{c.description="General-purpose agent for researching complex questions and executing multi-step tasks. Use this agent to execute multiple units of work in parallel.",c.mode="subagent",c.permissions.push(...Ce.merge(s,[{action:"todowrite",resource:"*",effect:"deny"}]))}),d.update(W.ID.make("explore"),c=>{c.description='Fast agent specialized for exploring codebases. Use this when you need to quickly find files by patterns (eg. "src/components/**/*.tsx"), search code for keywords (eg. "API endpoints"), or answer questions about the codebase (eg. "how do API endpoints work?"). When calling this agent, specify the desired thoroughness level: "quick" for basic searches, "medium" for moderate exploration, or "very thorough" for comprehensive analysis across multiple locations and naming conventions.',c.system=Rf,c.mode="subagent",c.permissions.push(...Ce.merge(s,[{action:"*",resource:"*",effect:"deny"},{action:"grep",resource:"*",effect:"allow"},{action:"glob",resource:"*",effect:"allow"},{action:"webfetch",resource:"*",effect:"allow"},{action:"websearch",resource:"*",effect:"allow"},{action:"read",resource:"*",effect:"allow"}],i))}),d.update(W.ID.make("compaction"),c=>{c.mode="primary",c.hidden=!0,c.system=Af,c.permissions.push(...Ce.merge(s,[{action:"*",resource:"*",effect:"deny"}]))}),d.update(W.ID.make("title"),c=>{c.mode="primary",c.hidden=!0,c.system=Df,c.permissions.push(...Ce.merge(s,[{action:"*",resource:"*",effect:"deny"}]))}),d.update(W.ID.make("summary"),c=>{c.mode="primary",c.hidden=!0,c.system=Tf,c.permissions.push(...Ce.merge(s,[{action:"*",resource:"*",effect:"deny"}]))})})})};var oo={};T(oo,{CommandPlugin:()=>oo,Plugin:()=>Mf});import{Effect as _f}from"effect";var qs=`Create or update \`AGENTS.md\` for this repository.
|
|
88
|
+
|
|
89
|
+
The goal is a compact instruction file that helps future OpenCode sessions avoid mistakes and ramp up quickly. Every line should answer: "Would an agent likely miss this without help?" If not, leave it out.
|
|
90
|
+
|
|
91
|
+
User-provided focus or constraints (honor these):
|
|
92
|
+
$ARGUMENTS
|
|
93
|
+
|
|
94
|
+
## How to investigate
|
|
95
|
+
|
|
96
|
+
Read the highest-value sources first:
|
|
97
|
+
- \`README*\`, root manifests, workspace config, lockfiles
|
|
98
|
+
- build, test, lint, formatter, typecheck, and codegen config
|
|
99
|
+
- CI workflows and pre-commit / task runner config
|
|
100
|
+
- existing instruction files (\`AGENTS.md\`, \`CLAUDE.md\`, \`.cursor/rules/\`, \`.cursorrules\`, \`.github/copilot-instructions.md\`)
|
|
101
|
+
- repo-local OpenCode config such as \`opencode.json\`
|
|
102
|
+
|
|
103
|
+
If architecture is still unclear after reading config and docs, inspect a small number of representative code files to find the real entrypoints, package boundaries, and execution flow. Prefer reading the files that explain how the system is wired together over random leaf files.
|
|
104
|
+
|
|
105
|
+
Prefer executable sources of truth over prose. If docs conflict with config or scripts, trust the executable source and only keep what you can verify.
|
|
106
|
+
|
|
107
|
+
## What to extract
|
|
108
|
+
|
|
109
|
+
Look for the highest-signal facts for an agent working in this repo:
|
|
110
|
+
- exact developer commands, especially non-obvious ones
|
|
111
|
+
- how to run a single test, a single package, or a focused verification step
|
|
112
|
+
- required command order when it matters, such as \`lint -> typecheck -> test\`
|
|
113
|
+
- monorepo or multi-package boundaries, ownership of major directories, and the real app/library entrypoints
|
|
114
|
+
- framework or toolchain quirks: generated code, migrations, codegen, build artifacts, special env loading, dev servers, infra deploy flow
|
|
115
|
+
- testing quirks: fixtures, integration test prerequisites, snapshot workflows, required services, flaky or expensive suites
|
|
116
|
+
- important constraints from existing instruction files worth preserving
|
|
117
|
+
|
|
118
|
+
Good \`AGENTS.md\` content is usually hard-earned context that took reading multiple files to infer.
|
|
119
|
+
|
|
120
|
+
## Questions
|
|
121
|
+
|
|
122
|
+
Only ask the user questions if the repo cannot answer something important. Use the \`question\` tool for one short batch at most.
|
|
123
|
+
|
|
124
|
+
Good questions:
|
|
125
|
+
- undocumented team conventions
|
|
126
|
+
- branch / PR / release expectations
|
|
127
|
+
- missing setup or test prerequisites that are known but not written down
|
|
128
|
+
|
|
129
|
+
Do not ask about anything the repo already makes clear.
|
|
130
|
+
|
|
131
|
+
## Writing rules
|
|
132
|
+
|
|
133
|
+
Include only high-signal, repo-specific guidance such as:
|
|
134
|
+
- exact commands and shortcuts the agent would otherwise guess wrong
|
|
135
|
+
- architecture notes that are not obvious from filenames
|
|
136
|
+
- conventions that differ from language or framework defaults
|
|
137
|
+
- setup requirements, environment quirks, and operational gotchas
|
|
138
|
+
- references to existing instruction sources that matter
|
|
139
|
+
|
|
140
|
+
Exclude:
|
|
141
|
+
- generic software advice
|
|
142
|
+
- long tutorials or exhaustive file trees
|
|
143
|
+
- obvious language conventions
|
|
144
|
+
- speculative claims or anything you could not verify
|
|
145
|
+
- content better stored in another file referenced via \`opencode.json\` \`instructions\`
|
|
146
|
+
|
|
147
|
+
When in doubt, omit.
|
|
148
|
+
|
|
149
|
+
Prefer short sections and bullets. If the repo is simple, keep the file simple. If the repo is large, summarize the few structural facts that actually change how an agent should work.
|
|
150
|
+
|
|
151
|
+
If \`AGENTS.md\` already exists at \`\${path}\`, improve it in place rather than rewriting blindly. Preserve verified useful guidance, delete fluff or stale claims, and reconcile it with the current codebase.
|
|
152
|
+
`;var $s=`You are a code reviewer. Your job is to review code changes and provide actionable feedback.
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
Input: $ARGUMENTS
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Determining What to Review
|
|
161
|
+
|
|
162
|
+
Based on the input provided, determine which type of review to perform:
|
|
163
|
+
|
|
164
|
+
1. **No arguments (default)**: Review all uncommitted changes
|
|
165
|
+
- Run: \`git diff\` for unstaged changes
|
|
166
|
+
- Run: \`git diff --cached\` for staged changes
|
|
167
|
+
- Run: \`git status --short\` to identify untracked (net new) files
|
|
168
|
+
|
|
169
|
+
2. **Commit hash** (40-char SHA or short hash): Review that specific commit
|
|
170
|
+
- Run: \`git show $ARGUMENTS\`
|
|
171
|
+
|
|
172
|
+
3. **Branch name**: Compare current branch to the specified branch
|
|
173
|
+
- Run: \`git diff $ARGUMENTS...HEAD\`
|
|
174
|
+
|
|
175
|
+
4. **PR URL or number** (contains "github.com" or "pull" or looks like a PR number): Review the pull request
|
|
176
|
+
- Run: \`gh pr view $ARGUMENTS\` to get PR context
|
|
177
|
+
- Run: \`gh pr diff $ARGUMENTS\` to get the diff
|
|
178
|
+
|
|
179
|
+
Use best judgement when processing input.
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Gathering Context
|
|
184
|
+
|
|
185
|
+
**Diffs alone are not enough.** After getting the diff, read the entire file(s) being modified to understand the full context. Code that looks wrong in isolation may be correct given surrounding logic\u2014and vice versa.
|
|
186
|
+
|
|
187
|
+
- Use the diff to identify which files changed
|
|
188
|
+
- Use \`git status --short\` to identify untracked files, then read their full contents
|
|
189
|
+
- Read the full file to understand existing patterns, control flow, and error handling
|
|
190
|
+
- Check for existing style guide or conventions files (CONVENTIONS.md, AGENTS.md, .editorconfig, etc.)
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## What to Look For
|
|
195
|
+
|
|
196
|
+
**Bugs** - Your primary focus.
|
|
197
|
+
- Logic errors, off-by-one mistakes, incorrect conditionals
|
|
198
|
+
- If-else guards: missing guards, incorrect branching, unreachable code paths
|
|
199
|
+
- Edge cases: null/empty/undefined inputs, error conditions, race conditions
|
|
200
|
+
- Security issues: injection, auth bypass, data exposure
|
|
201
|
+
- Broken error handling that swallows failures, throws unexpectedly or returns error types that are not caught.
|
|
202
|
+
|
|
203
|
+
**Structure** - Does the code fit the codebase?
|
|
204
|
+
- Does it follow existing patterns and conventions?
|
|
205
|
+
- Are there established abstractions it should use but doesn't?
|
|
206
|
+
- Excessive nesting that could be flattened with early returns or extraction
|
|
207
|
+
|
|
208
|
+
**Performance** - Only flag if obviously problematic.
|
|
209
|
+
- O(n\xB2) on unbounded data, N+1 queries, blocking I/O on hot paths
|
|
210
|
+
|
|
211
|
+
**Behavior Changes** - If a behavioral change is introduced, raise it (especially if it's possibly unintentional).
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## Before You Flag Something
|
|
216
|
+
|
|
217
|
+
**Be certain.** If you're going to call something a bug, you need to be confident it actually is one.
|
|
218
|
+
|
|
219
|
+
- Only review the changes - do not review pre-existing code that wasn't modified
|
|
220
|
+
- Don't flag something as a bug if you're unsure - investigate first
|
|
221
|
+
- Don't invent hypothetical problems - if an edge case matters, explain the realistic scenario where it breaks
|
|
222
|
+
- If you need more context to be sure, use the tools below to get it
|
|
223
|
+
|
|
224
|
+
**Don't be a zealot about style.** When checking code against conventions:
|
|
225
|
+
|
|
226
|
+
- Verify the code is *actually* in violation. Don't complain about else statements if early returns are already being used correctly.
|
|
227
|
+
- Some "violations" are acceptable when they're the simplest option. A \`let\` statement is fine if the alternative is convoluted.
|
|
228
|
+
- Excessive nesting is a legitimate concern regardless of other style choices.
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## Tools
|
|
233
|
+
|
|
234
|
+
Use these to inform your review:
|
|
235
|
+
|
|
236
|
+
- **Explore agent** - Find how existing code handles similar problems. Check patterns, conventions, and prior art before claiming something doesn't fit.
|
|
237
|
+
- **Exa Code Context** - Verify correct usage of libraries/APIs before flagging something as wrong.
|
|
238
|
+
- **Web Search** - Research best practices if you're unsure about a pattern.
|
|
239
|
+
|
|
240
|
+
If you're uncertain about something and can't verify it with these tools, say "I'm not sure about X" rather than flagging it as a definite issue.
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## Output
|
|
245
|
+
|
|
246
|
+
1. If there is a bug, be direct and clear about why it is a bug.
|
|
247
|
+
2. Clearly communicate severity of issues. Do not overstate severity.
|
|
248
|
+
3. Critiques should clearly and explicitly communicate the scenarios, environments, or inputs that are necessary for the bug to arise. The comment should immediately indicate that the issue's severity depends on these factors.
|
|
249
|
+
4. Your tone should be matter-of-fact and not accusatory or overly positive. It should read as a helpful AI assistant suggestion without sounding too much like a human reviewer.
|
|
250
|
+
5. Write so the reader can quickly understand the issue without reading too closely.
|
|
251
|
+
6. AVOID flattery, do not give any comments that are not helpful to the reader.
|
|
252
|
+
`;var Mf={id:"command",effect:_f.fn(function*(t){let e=yield*pe.Service;yield*t.command.transform(n=>{n.update("init",o=>{o.template=qs.replace("${path}",e.project.directory),o.description="guided AGENTS.md setup"}),n.update("review",o=>{o.template=$s.replace("${path}",e.project.directory),o.description="review changes [commit|branch|pr], defaults to uncommitted",o.subtask=!0})})})};import{Effect as ro,Stream as Lf}from"effect";function Uf(t){let e=Date.parse(t);return Number.isFinite(e)?e:0}r(Uf,"released");function Pr(t){return[{input:t?.input??0,output:t?.output??0,cache:{read:t?.cache_read??0,write:t?.cache_write??0}},...t?.tiers?.map(n=>({tier:n.tier,input:n.input,output:n.output,cache:{read:n.cache_read??0,write:n.cache_write??0}}))??[],...t?.context_over_200k?[{tier:{type:"context",size:2e5},input:t.context_over_200k.input,output:t.context_over_200k.output,cache:{read:t.context_over_200k.cache_read??0,write:t.context_over_200k.cache_write??0}}]:[]]}r(Pr,"cost");function Vf(t,e){if(!e)return t;let n=Pr(e),[o,...i]=t,[s,...d]=n,c=r(f=>`${f.tier?.type??"base"}:${f.tier?.size??0}`,"tierKey"),a=r((f,p)=>({...f,...p,tier:p.tier??f.tier,cache:{...f.cache,...p.cache}}),"merge"),l=new Map(i.map(f=>[c(f),f]));for(let f of d){let p=l.get(c(f));l.set(c(f),p?a(p,f):f)}return[a(o??{input:0,output:0,cache:{read:0,write:0}},s),...l.values()]}r(Vf,"mergeCost");function Nf(t,e){return`${t.name} ${e.charAt(0).toUpperCase()}${e.slice(1)}`}r(Nf,"modeName");function Fs(t,e,n={}){t.name=n.name??e.name,t.family=e.family,t.api=e.provider?.npm?{id:e.id,type:"aisdk",package:e.provider.npm,url:e.provider.api}:{id:e.id,type:"native",url:e.provider?.api,settings:{}},t.capabilities={tools:e.tool_call,input:[...e.modalities?.input??[]],output:[...e.modalities?.output??[]]},t.variants=[],t.time.released=Uf(e.release_date),t.cost=n.cost??Pr(e.cost),t.status=e.status??"active",t.enabled=!0,t.limit={context:e.limit.context,input:e.limit.input,output:e.limit.output},Object.assign(t.request.headers,n.request?.headers??{}),Object.assign(t.request.body,n.request?.body??{})}r(Fs,"applyModel");var Hs={id:"models-dev",effect:ro.fn(function*(t){let e=yield*He.Service,n=yield*se.Service;yield*t.integration.transform(ro.fn(function*(o){let i=yield*e.get();for(let s of Object.values(i)){if(s.env.length===0)continue;let d=s.id;o.update(d,c=>c.name=s.name),o.method.update({integrationID:d,method:{type:"key"}}),o.method.update({integrationID:d,method:{type:"env",names:[...s.env]}})}})),yield*t.catalog.transform(ro.fn(function*(o){let i=yield*e.get();for(let s of Object.values(i)){let d=_.ID.make(s.id);o.provider.update(d,c=>{c.name=s.name,c.api=s.npm?{type:"aisdk",package:s.npm,url:s.api}:{type:"native",url:s.api,settings:{}}});for(let c of Object.values(s.models)){let a=Pr(c.cost);o.model.update(d,c.id,l=>Fs(l,c,{cost:a}));for(let[l,f]of Object.entries(c.experimental?.modes??{}))o.model.update(d,`${c.id}-${l}`,p=>Fs(p,c,{name:Nf(c,l),cost:Vf(a,f.cost),request:f.provider}))}}})),yield*n.subscribe(He.Event.Refreshed).pipe(Lf.runForEach(()=>t.integration.reload().pipe(ro.andThen(t.catalog.reload()))),ro.forkScoped({startImmediately:!0}))})};import{Effect as Rr}from"effect";var Gs={id:"alibaba",effect:Rr.fn(function*(t){yield*t.aisdk.sdk(Rr.fn(function*(e){if(e.package!=="@ai-sdk/alibaba")return;let n=yield*Rr.promise(()=>import("@ai-sdk/alibaba"));e.sdk=n.createAlibaba(e.options)}))})};import{Effect as wt}from"effect";function jf(t,e){if(t.startsWith("arn:")||["global.","us.","eu.","jp.","apac.","au."].some(c=>t.startsWith(c)))return t;let o=e??"us-east-1",i=o.split("-")[0];if(i==="us")return["nova-micro","nova-lite","nova-pro","nova-premier","nova-2","claude","deepseek.r1"].some(a=>t.includes(a))&&!o.startsWith("us-gov")?`${i}.${t}`:t;if(i==="eu"){let c=["eu-west-1","eu-west-2","eu-west-3","eu-north-1","eu-central-1","eu-south-1","eu-south-2"].some(l=>o.includes(l)),a=["claude","nova-lite","nova-micro","llama3","pixtral"].some(l=>t.includes(l));return c&&a?`${i}.${t}`:t}if(i!=="ap")return t;if(["ap-southeast-2","ap-southeast-4"].includes(o)&&["anthropic.claude-sonnet-4-5","anthropic.claude-haiku"].some(c=>t.includes(c)))return`au.${t}`;let d=o==="ap-northeast-1"?"jp":"apac";return["claude","nova-lite","nova-micro","nova-pro"].some(c=>t.includes(c))?`${d}.${t}`:t}r(jf,"resolveModelID");function qf(t,e){return e==="openai.gpt-oss-safeguard-20b"||e==="openai.gpt-oss-safeguard-120b"?t.chat(e):t.responses(e)}r(qf,"selectMantleModel");var Bs={id:"amazon-bedrock",effect:wt.fn(function*(t){yield*t.catalog.transform(wt.fn(function*(e){for(let n of e.provider.list())n.provider.api.type==="aisdk"&&n.provider.api.package==="@ai-sdk/amazon-bedrock"&&e.provider.update(n.provider.id,o=>{o.api.type==="aisdk"&&typeof o.request.body.endpoint=="string"&&(o.api.url=o.request.body.endpoint,delete o.request.body.endpoint)})})),yield*t.aisdk.sdk(wt.fn(function*(e){if(!["@ai-sdk/amazon-bedrock","@ai-sdk/amazon-bedrock/mantle"].includes(e.package))return;let n={...e.options},o=typeof n.profile=="string"?n.profile:process.env.AWS_PROFILE,i=typeof n.region=="string"?n.region:process.env.AWS_REGION??"us-east-1",s=process.env.AWS_BEARER_TOKEN_BEDROCK??(typeof n.bearerToken=="string"?n.bearerToken:void 0);s&&!process.env.AWS_BEARER_TOKEN_BEDROCK&&(process.env.AWS_BEARER_TOKEN_BEDROCK=s);let d=!!(process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI||process.env.AWS_CONTAINER_CREDENTIALS_FULL_URI);if(n.region=i,typeof n.endpoint=="string"&&(n.baseURL=n.endpoint),!s&&n.credentialProvider===void 0){let{fromNodeProviderChain:a}=yield*wt.promise(()=>import("@aws-sdk/credential-providers"));n.credentialProvider=a(o?{profile:o}:{})}if(e.package==="@ai-sdk/amazon-bedrock/mantle"){let a=yield*wt.promise(()=>import("@ai-sdk/amazon-bedrock/mantle"));e.sdk=a.createBedrockMantle(n);return}let c=yield*wt.promise(()=>import("@ai-sdk/amazon-bedrock"));e.sdk=c.createAmazonBedrock(n)})),yield*t.aisdk.language(wt.fn(function*(e){if(e.model.providerID!==_.ID.amazonBedrock)return;if(e.model.api.type==="aisdk"&&e.model.api.package==="@ai-sdk/amazon-bedrock/mantle"){e.language=qf(e.sdk,e.model.api.id);return}let n=typeof e.options.region=="string"?e.options.region:process.env.AWS_REGION;e.language=e.sdk.languageModel(jf(e.model.api.id,n))}))})};import{Effect as Mo}from"effect";var Ks={id:"anthropic",effect:Mo.fn(function*(t){yield*t.catalog.transform(Mo.fn(function*(e){for(let n of e.provider.list())n.provider.api.type==="aisdk"&&n.provider.api.package==="@ai-sdk/anthropic"&&e.provider.update(n.provider.id,o=>{o.request.headers["anthropic-beta"]="interleaved-thinking-2025-05-14,fine-grained-tool-streaming-2025-05-14"})})),yield*t.aisdk.sdk(Mo.fn(function*(e){if(e.package!=="@ai-sdk/anthropic")return;let n=yield*Mo.promise(()=>import("@ai-sdk/anthropic"));e.sdk=n.createAnthropic(e.options)}))})};import{Effect as ft}from"effect";function zs(t,e,n){return n&&t.chat?t.chat(e):t.responses?t.responses(e):t.messages?t.messages(e):t.chat?t.chat(e):t.languageModel(e)}r(zs,"selectLanguage");var Ws={id:"azure",effect:ft.fn(function*(t){yield*t.catalog.transform(ft.fn(function*(e){for(let n of e.provider.list()){if(n.provider.api.type!=="aisdk"||n.provider.api.package!=="@ai-sdk/azure")continue;let o=n.provider.request.body.resourceName,i=typeof o=="string"&&o.trim()!==""?o:process.env.AZURE_RESOURCE_NAME;i&&e.provider.update(n.provider.id,s=>{s.request.body.resourceName=i})}})),yield*t.aisdk.sdk(ft.fn(function*(e){if(e.package!=="@ai-sdk/azure")return;if(e.model.providerID===_.ID.azure&&!e.options.resourceName&&!e.options.baseURL&&(e.model.api.type!=="aisdk"||!e.model.api.url))throw new Error("AZURE_RESOURCE_NAME is missing, set it using env var or reconnecting the azure provider and setting it");let n=yield*ft.promise(()=>import("@ai-sdk/azure"));e.sdk=n.createAzure(e.options)})),yield*t.aisdk.language(ft.fn(function*(e){e.model.providerID===_.ID.azure&&(e.language=zs(e.sdk,e.model.api.id,!!e.options.useCompletionUrls))}))})},Js={id:"azure-cognitive-services",effect:ft.fn(function*(t){yield*t.catalog.transform(ft.fn(function*(e){let n=process.env.AZURE_COGNITIVE_SERVICES_RESOURCE_NAME;if(n)for(let o of e.provider.list())o.provider.api.type==="aisdk"&&o.provider.api.package==="@ai-sdk/openai-compatible"&&o.provider.id.includes("azure-cognitive-services")&&e.provider.update(o.provider.id,i=>{i.request.body.baseURL=`https://${n}.cognitiveservices.azure.com/openai`})})),yield*t.aisdk.language(ft.fn(function*(e){e.model.providerID===_.ID.make("azure-cognitive-services")&&(e.language=zs(e.sdk,e.model.api.id,!!e.options.useCompletionUrls))}))})};import{Effect as Lo}from"effect";var Ys={id:"cerebras",effect:Lo.fn(function*(t){yield*t.catalog.transform(Lo.fn(function*(e){for(let n of e.provider.list())n.provider.api.type==="aisdk"&&n.provider.api.package==="@ai-sdk/cerebras"&&e.provider.update(n.provider.id,o=>{o.request.headers["X-Cerebras-3rd-Party-Integration"]="opencode"})})),yield*t.aisdk.sdk(Lo.fn(function*(e){if(e.package!=="@ai-sdk/cerebras")return;let n=yield*Lo.promise(()=>import("@ai-sdk/cerebras"));e.sdk=n.createCerebras(e.options)}))})};import Ar from"os";import{Effect as un,Option as $f,Schema as Zs}from"effect";var Xs={id:"cloudflare-ai-gateway",effect:un.fn(function*(t){yield*t.aisdk.sdk(un.fn(function*(e){if(e.package!=="ai-gateway-provider"||e.options.baseURL)return;let n=Hf(e.options);if(!n)return;let o=Gf(e.options),{createAiGateway:i}=yield*un.promise(()=>import("ai-gateway-provider")).pipe(un.orDie),{createUnified:s}=yield*un.promise(()=>import("ai-gateway-provider/providers/unified")).pipe(un.orDie),d=i({accountId:n.accountId,gateway:n.gatewayId,apiKey:n.apiKey,options:Bf(e.options,o)});e.sdk={languageModel(c){let a=c.startsWith("workers-ai/")||c.startsWith("@cf/"),l=s(a?{apiKey:n.apiKey}:{});return d(l(c))}}}))})},Ff=Zs.decodeUnknownOption(Zs.UnknownFromJsonString);function Hf(t){let e=process.env.CLOUDFLARE_ACCOUNT_ID??Uo(t,"accountId"),n=process.env.CLOUDFLARE_GATEWAY_ID??Uo(t,"gatewayId")??Uo(t,"gateway"),o=process.env.CLOUDFLARE_API_TOKEN??process.env.CF_AIG_TOKEN??Uo(t,"apiKey");if(!(!e||!n||!o))return{accountId:e,gatewayId:n,apiKey:o}}r(Hf,"gatewayConfig");function Gf(t){if(t.metadata!==void 0)return t.metadata;let e=t.headers?.["cf-aig-metadata"];return e?$f.getOrUndefined(Ff(e)):void 0}r(Gf,"gatewayMetadata");function Bf(t,e){return{metadata:e,cacheTtl:t.cacheTtl,cacheKey:t.cacheKey,skipCache:t.skipCache,collectLog:t.collectLog,headers:{"User-Agent":`opencode/${Te} cloudflare-ai-gateway (${Ar.platform()} ${Ar.release()}; ${Ar.arch()})`}}}r(Bf,"gatewayOptions");function Uo(t,e){return typeof t[e]=="string"?t[e]:void 0}r(Uo,"stringOption");import Dr from"os";import{Effect as io}from"effect";var Vo=_.ID.make("cloudflare-workers-ai"),ta={id:"cloudflare-workers-ai",effect:io.fn(function*(t){yield*t.catalog.transform(io.fn(function*(e){let n=e.provider.get(Vo);n&&e.provider.update(n.provider.id,o=>{if(o.api.type!=="aisdk"||o.api.url)return;let i=Qs(o.request.body);i&&(o.api.url=ea(i))})})),yield*t.aisdk.sdk(io.fn(function*(e){if(e.model.providerID!==Vo||e.package!=="@ai-sdk/openai-compatible")return;let n=Qs(e.options);if(!Kf(e.model.api)&&!n)return;let o=yield*io.promise(()=>import("@ai-sdk/openai-compatible"));e.sdk=o.createOpenAICompatible(zf({...e.options,baseURL:e.options.baseURL??(n?ea(n):void 0)}))})),yield*t.aisdk.language(io.fn(function*(e){e.model.providerID===Vo&&(e.language=e.sdk.languageModel(e.model.api.id))}))})};function Qs(t){return process.env.CLOUDFLARE_ACCOUNT_ID??Jf(t,"accountId")}r(Qs,"resolveAccountId");function ea(t){return`https://api.cloudflare.com/client/v4/accounts/${t}/ai/v1`}r(ea,"workersEndpoint");function Kf(t){return t.type==="aisdk"&&!!t.url}r(Kf,"hasWorkersEndpoint");function zf(t){return{...t,baseURL:Wf(t.baseURL),apiKey:process.env.CLOUDFLARE_API_KEY??t.apiKey,headers:{"User-Agent":`opencode/${Te} cloudflare-workers-ai (${Dr.platform()} ${Dr.release()}; ${Dr.arch()})`,...t.headers},name:Vo}}r(zf,"sdkOptions");function Wf(t){return typeof t!="string"?t:t.replaceAll("${CLOUDFLARE_ACCOUNT_ID}",process.env.CLOUDFLARE_ACCOUNT_ID??"${CLOUDFLARE_ACCOUNT_ID}")}r(Wf,"expandAccountId");function Jf(t,e){return typeof t[e]=="string"?t[e]:void 0}r(Jf,"stringOption");import{Effect as Tr}from"effect";var na={id:"cohere",effect:Tr.fn(function*(t){yield*t.aisdk.sdk(Tr.fn(function*(e){if(e.package!=="@ai-sdk/cohere")return;let n=yield*Tr.promise(()=>import("@ai-sdk/cohere"));e.sdk=n.createCohere(e.options)}))})};import{Effect as Or}from"effect";var oa={id:"deepinfra",effect:Or.fn(function*(t){yield*t.aisdk.sdk(Or.fn(function*(e){if(e.package!=="@ai-sdk/deepinfra")return;let n=yield*Or.promise(()=>import("@ai-sdk/deepinfra"));e.sdk=n.createDeepInfra(e.options)}))})};import{Effect as so}from"effect";import{pathToFileURL as Yf}from"url";var ra={id:"dynamic-provider",effect:so.fn(function*(t){let e=yield*Fe.Service;yield*t.aisdk.sdk(so.fn(function*(n){if(n.sdk)return;let o=n.package.startsWith("file://")?n.package:(yield*e.add(n.package).pipe(so.orDie)).entrypoint;if(!o)throw new Error(`Package ${n.package} has no import entrypoint`);let i=yield*so.promise(async()=>await(o.startsWith("file://")?import(o):import(Yf(o).href))).pipe(so.orDie),s=Object.keys(i).find(d=>d.startsWith("create"));if(!s)throw new Error(`Package ${n.package} has no provider factory export`);n.sdk=i[s](n.options)}))})};import{Effect as _r}from"effect";var ia={id:"gateway",effect:_r.fn(function*(t){yield*t.aisdk.sdk(_r.fn(function*(e){if(e.package!=="@ai-sdk/gateway")return;let n=yield*_r.promise(()=>import("@ai-sdk/gateway"));e.sdk=n.createGateway(e.options)}))})};import{Effect as ao}from"effect";var sa={id:"github-copilot",effect:ao.fn(function*(t){yield*t.catalog.transform(ao.fn(function*(e){let n=e.provider.get(_.ID.githubCopilot);!n||!n.models.has(oe.ID.make("gpt-5-chat-latest"))||e.model.update(n.provider.id,oe.ID.make("gpt-5-chat-latest"),o=>{o.enabled=!1})})),yield*t.aisdk.sdk(ao.fn(function*(e){if(e.package!=="@ai-sdk/github-copilot")return;let n=yield*ao.promise(()=>import("./copilot-provider-TX4YFKJZ.js"));e.sdk=n.createOpenaiCompatible(e.options)})),yield*t.aisdk.language(ao.fn(function*(e){if(e.model.providerID!==_.ID.githubCopilot)return;if(e.sdk.responses===void 0&&e.sdk.chat===void 0){e.language=e.sdk.languageModel(e.model.api.id);return}if(e.options.endpoint==="responses"&&e.sdk.responses){e.language=e.sdk.responses(e.model.api.id);return}if(e.options.endpoint==="chat"&&e.sdk.chat){e.language=e.sdk.chat(e.model.api.id);return}let n=/^gpt-(\d+)/.exec(e.model.api.id);e.language=n&&Number(n[1])>=5&&!e.model.api.id.startsWith("gpt-5-mini")&&e.sdk.responses?e.sdk.responses(e.model.api.id):e.sdk.chat(e.model.api.id)}))})};import Mr from"os";import{Effect as mn}from"effect";var aa={id:"gitlab",effect:mn.fn(function*(t){yield*t.aisdk.sdk(mn.fn(function*(e){if(e.package!=="gitlab-ai-provider")return;let n=yield*mn.promise(()=>import("gitlab-ai-provider"));e.sdk=n.createGitLab({...e.options,instanceUrl:typeof e.options.instanceUrl=="string"?e.options.instanceUrl:process.env.GITLAB_INSTANCE_URL??"https://gitlab.com",apiKey:typeof e.options.apiKey=="string"?e.options.apiKey:process.env.GITLAB_TOKEN,aiGatewayHeaders:{"User-Agent":`opencode/${Te} gitlab-ai-provider/${n.VERSION} (${Mr.platform()} ${Mr.release()}; ${Mr.arch()})`,"anthropic-beta":"context-1m-2025-08-07",...e.options.aiGatewayHeaders},featureFlags:{duo_agent_platform_agentic_chat:!0,duo_agent_platform:!0,...e.options.featureFlags}})})),yield*t.aisdk.language(mn.fn(function*(e){if(e.model.providerID!==_.ID.gitlab)return;let n=typeof e.options.featureFlags=="object"&&e.options.featureFlags?e.options.featureFlags:{};if(e.model.api.id.startsWith("duo-workflow-")){let o=yield*mn.promise(()=>import("gitlab-ai-provider")).pipe(mn.orDie),i=typeof e.model.request.body.workflowRef=="string"?e.model.request.body.workflowRef:void 0,s=typeof e.model.request.body.workflowDefinition=="string"?e.model.request.body.workflowDefinition:void 0,d=e.sdk.workflowChat(o.isWorkflowModel(e.model.api.id)?e.model.api.id:"duo-workflow",{featureFlags:n,workflowDefinition:s});i&&(d.selectedModelRef=i),e.language=d;return}e.language=e.sdk.agenticChat(e.model.api.id,{aiGatewayHeaders:e.options.aiGatewayHeaders,featureFlags:n})}))})};import{Effect as Lr}from"effect";var ca={id:"google",effect:Lr.fn(function*(t){yield*t.aisdk.sdk(Lr.fn(function*(e){if(e.package!=="@ai-sdk/google")return;let n=yield*Lr.promise(()=>import("@ai-sdk/google"));e.sdk=n.createGoogleGenerativeAI(e.options)}))})};import{Effect as Ke}from"effect";function da(t){return t.project??process.env.GOOGLE_VERTEX_PROJECT??process.env.GOOGLE_CLOUD_PROJECT??process.env.GCP_PROJECT??process.env.GCLOUD_PROJECT}r(da,"resolveProject");function la(t){return t.location??process.env.GOOGLE_VERTEX_LOCATION??process.env.GOOGLE_CLOUD_LOCATION??process.env.VERTEX_LOCATION??"us-central1"}r(la,"resolveLocation");function Zf(t){return t==="global"?"aiplatform.googleapis.com":`${t}-aiplatform.googleapis.com`}r(Zf,"vertexEndpoint");function Xf(t,e,n){return t.replaceAll("${GOOGLE_VERTEX_PROJECT}",e??"${GOOGLE_VERTEX_PROJECT}").replaceAll("${GOOGLE_VERTEX_LOCATION}",n).replaceAll("${GOOGLE_VERTEX_ENDPOINT}",Zf(n))}r(Xf,"replaceVertexVars");function fa(t){return async(e,n)=>{let{GoogleAuth:o}=await import("google-auth-library"),d=await(await new o({scopes:["https://www.googleapis.com/auth/cloud-platform"]}).getClient()).getAccessToken(),c=new Headers(n?.headers);return c.set("Authorization",`Bearer ${d.token}`),typeof t=="function"?t(e,{...n,headers:c}):fetch(e,{...n,headers:c})}}r(fa,"authFetch");var pa={id:"google-vertex",effect:Ke.fn(function*(t){yield*t.catalog.transform(Ke.fn(function*(e){for(let n of e.provider.list()){if(n.provider.api.type!=="aisdk"||n.provider.api.package!=="@ai-sdk/google-vertex"&&!(n.provider.id===_.ID.googleVertex&&n.provider.api.package.includes("@ai-sdk/openai-compatible")))continue;let o=da(n.provider.request.body),i=String(la(n.provider.request.body));e.provider.update(n.provider.id,s=>{o&&(s.request.body.project=o),s.request.body.location=i,s.api.type==="aisdk"&&s.api.url&&(s.api.url=Xf(s.api.url,o,i)),s.api.type==="aisdk"&&s.api.package.includes("@ai-sdk/openai-compatible")&&(s.request.body.fetch=fa(s.request.body.fetch))})}})),yield*t.aisdk.sdk(Ke.fn(function*(e){if(e.model.providerID===_.ID.googleVertex&&e.package.includes("@ai-sdk/openai-compatible")){e.options.fetch=fa(e.options.fetch);return}if(e.package!=="@ai-sdk/google-vertex")return;let n=yield*Ke.promise(()=>import("@ai-sdk/google-vertex")),o=da(e.options),i=la(e.options),s={...e.options};delete s.fetch,e.sdk=n.createVertex({...s,project:o,location:i})})),yield*t.aisdk.language(Ke.fn(function*(e){e.model.providerID===_.ID.googleVertex&&(e.language=e.sdk.languageModel(String(e.model.api.id).trim()))}))})},ua={id:"google-vertex-anthropic",effect:Ke.fn(function*(t){yield*t.catalog.transform(Ke.fn(function*(e){for(let n of e.provider.list()){if(n.provider.api.type!=="aisdk"||n.provider.api.package!=="@ai-sdk/google-vertex/anthropic")continue;let o=n.provider.request.body.project??process.env.GOOGLE_CLOUD_PROJECT??process.env.GCP_PROJECT??process.env.GCLOUD_PROJECT,i=n.provider.request.body.location??process.env.GOOGLE_CLOUD_LOCATION??process.env.VERTEX_LOCATION??"global";e.provider.update(n.provider.id,s=>{o&&(s.request.body.project=o),s.request.body.location=i})}})),yield*t.aisdk.sdk(Ke.fn(function*(e){if(e.package!=="@ai-sdk/google-vertex/anthropic")return;let n=yield*Ke.promise(()=>import("@ai-sdk/google-vertex/anthropic")),o=typeof e.options.project=="string"?e.options.project:process.env.GOOGLE_CLOUD_PROJECT??process.env.GCP_PROJECT??process.env.GCLOUD_PROJECT,i=typeof e.options.location=="string"?e.options.location:process.env.GOOGLE_CLOUD_LOCATION??process.env.VERTEX_LOCATION??"global";e.sdk=n.createVertexAnthropic({...e.options,project:o,location:i,...(i==="eu"||i==="us")&&o&&!e.options.baseURL?{baseURL:`https://aiplatform.${i}.rep.googleapis.com/v1/projects/${o}/locations/${i}/publishers/anthropic/models`}:{}})})),yield*t.aisdk.language(Ke.fn(function*(e){e.model.providerID===_.ID.make("google-vertex-anthropic")&&(e.language=e.sdk.languageModel(String(e.model.api.id).trim()))}))})};import{Effect as Ur}from"effect";var ma={id:"groq",effect:Ur.fn(function*(t){yield*t.aisdk.sdk(Ur.fn(function*(e){if(e.package!=="@ai-sdk/groq")return;let n=yield*Ur.promise(()=>import("@ai-sdk/groq"));e.sdk=n.createGroq(e.options)}))})};import{Effect as ga}from"effect";var ha={id:"kilo",effect:ga.fn(function*(t){yield*t.catalog.transform(ga.fn(function*(e){for(let n of e.provider.list())n.provider.api.type==="aisdk"&&n.provider.api.package==="@ai-sdk/openai-compatible"&&n.provider.api.url==="https://api.kilo.ai/api/gateway"&&e.provider.update(n.provider.id,o=>{o.request.headers["HTTP-Referer"]="https://opencode.ai/",o.request.headers["X-Title"]="opencode"})}))})};import{Effect as ya}from"effect";var va={id:"llmgateway",effect:ya.fn(function*(t){let e=yield*N.Service;yield*t.catalog.transform(ya.fn(function*(n){for(let o of n.provider.list())o.provider.disabled||o.provider.api.type==="aisdk"&&o.provider.api.package==="@ai-sdk/openai-compatible"&&o.provider.api.url==="https://api.llmgateway.io/v1"&&(yield*e.get(N.ID.make(o.provider.id)))&&n.provider.update(o.provider.id,i=>{i.request.headers["HTTP-Referer"]="https://opencode.ai/",i.request.headers["X-Title"]="opencode",i.request.headers["X-Source"]="opencode"})}))})};import{Effect as Vr}from"effect";var ka={id:"mistral",effect:Vr.fn(function*(t){yield*t.aisdk.sdk(Vr.fn(function*(e){if(e.package!=="@ai-sdk/mistral")return;let n=yield*Vr.promise(()=>import("@ai-sdk/mistral"));e.sdk=n.createMistral(e.options)}))})};import{Effect as Sa}from"effect";var Ea={id:"nvidia",effect:Sa.fn(function*(t){yield*t.catalog.transform(Sa.fn(function*(e){for(let n of e.provider.list())n.provider.api.type==="aisdk"&&n.provider.api.package==="@ai-sdk/openai-compatible"&&n.provider.api.url==="https://integrate.api.nvidia.com/v1"&&e.provider.update(n.provider.id,o=>{o.request.headers["HTTP-Referer"]="https://opencode.ai/",o.request.headers["X-Title"]="opencode",o.request.headers["X-BILLING-INVOKE-ORIGIN"]??="OpenCode"})}))})};import{createServer as dp}from"node:http";import{Deferred as co,Effect as te}from"effect";var Pe={};T(Pe,{OauthCallbackPage:()=>Pe,bootstrap:()=>tp,error:()=>ep,success:()=>Qf});function Qf(t){let e=t?.provider;return jr({title:"Authorization successful",body:Nr({status:"success",headline:"Authorization successful",message:e?`OpenCode is now connected to ${Ct(e)}.`:"OpenCode is now authorized.",footnote:"You can close this window."}),script:t?.autoClose===!1?void 0:np})}r(Qf,"success");function ep(t,e){let n=e?.provider;return jr({title:"Authorization failed",body:Nr({status:"error",headline:"Authorization failed",message:n?`OpenCode couldn't finish connecting to ${Ct(n)}.`:"OpenCode couldn't complete authorization.",detail:t,footnote:"Close this window and try again from OpenCode."})})}r(ep,"error");function tp(t){return jr({title:"Finishing sign-in",body:Nr({status:"pending",headline:"Finishing sign-in",message:t.provider?`Completing your ${Ct(t.provider)} authorization.`:"Completing authorization.",footnote:"You can close this window once sign-in finishes."}),script:op(t)})}r(tp,"bootstrap");function Nr(t){let e=t.detail?.trim();return`<main class="card" id="oc-card" data-status="${t.status}" role="status" aria-live="polite">
|
|
253
|
+
<div class="brand">${ip}</div>
|
|
254
|
+
<div class="status" aria-hidden="true">
|
|
255
|
+
<span class="icon icon-pending">${cp}</span>
|
|
256
|
+
<span class="icon icon-success">${sp}</span>
|
|
257
|
+
<span class="icon icon-error">${ap}</span>
|
|
258
|
+
</div>
|
|
259
|
+
<h1 class="headline" id="oc-headline">${Ct(t.headline)}</h1>
|
|
260
|
+
<p class="message" id="oc-message">${t.message}</p>
|
|
261
|
+
<pre class="detail" id="oc-detail"${e?"":" hidden"}>${e?Ct(e):""}</pre>
|
|
262
|
+
<p class="footnote" id="oc-footnote">${Ct(t.footnote)}</p>
|
|
263
|
+
</main>`}r(Nr,"renderCard");function jr(t){return`<!doctype html>
|
|
264
|
+
<html lang="en">
|
|
265
|
+
<head>
|
|
266
|
+
<meta charset="utf-8" />
|
|
267
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
268
|
+
<meta name="robots" content="noindex" />
|
|
269
|
+
<title>${Ct(t.title)} \xB7 OpenCode</title>
|
|
270
|
+
<style>${rp}</style>
|
|
271
|
+
</head>
|
|
272
|
+
<body>
|
|
273
|
+
${t.body}${t.script?`
|
|
274
|
+
<script>${t.script}</script>`:""}
|
|
275
|
+
</body>
|
|
276
|
+
</html>`}r(jr,"renderDocument");var np="setTimeout(function(){try{window.close()}catch(e){}},2500)";function op(t){return`var PROVIDER=${ba(t.provider??"")};
|
|
277
|
+
var TOKEN_URL=new URL(${ba(t.tokenPath)},window.location.origin).href;
|
|
278
|
+
(function(){
|
|
279
|
+
var card=document.getElementById("oc-card"),headline=document.getElementById("oc-headline"),message=document.getElementById("oc-message"),detail=document.getElementById("oc-detail"),footnote=document.getElementById("oc-footnote");
|
|
280
|
+
function fail(text){card.dataset.status="error";headline.textContent="Authorization failed";message.textContent=PROVIDER?("OpenCode couldn't finish connecting to "+PROVIDER+"."):"OpenCode couldn't complete authorization.";if(text){detail.textContent=text;detail.hidden=false}footnote.textContent="Close this window and try again from OpenCode."}
|
|
281
|
+
function ok(){card.dataset.status="success";headline.textContent="Authorization successful";message.textContent=PROVIDER?("OpenCode is now connected to "+PROVIDER+"."):"OpenCode is now authorized.";detail.hidden=true;footnote.textContent="You can close this window.";setTimeout(function(){try{window.close()}catch(e){}},2500)}
|
|
282
|
+
try{
|
|
283
|
+
var hash=new URLSearchParams((window.location.hash||"").slice(1));
|
|
284
|
+
var search=new URLSearchParams(window.location.search||"");
|
|
285
|
+
var err=hash.get("error")||search.get("error");
|
|
286
|
+
var errDescription=hash.get("error_description")||search.get("error_description");
|
|
287
|
+
var body=err?{error:err,error_description:errDescription||""}:{access_token:hash.get("access_token")||"",expires_in:hash.get("expires_in")||"0",state:hash.get("state")||""};
|
|
288
|
+
fetch(TOKEN_URL,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(body)}).then(function(res){
|
|
289
|
+
if(!res.ok)return res.text().catch(function(){return""}).then(function(t){throw new Error(t||("callback failed ("+res.status+")"))});
|
|
290
|
+
if(err){fail(errDescription||err);return}
|
|
291
|
+
ok();
|
|
292
|
+
}).catch(function(e){fail(String(e&&e.message?e.message:e))});
|
|
293
|
+
}catch(e){fail(String(e&&e.message?e.message:e))}
|
|
294
|
+
})()`}r(op,"bootstrapScript");function ba(t){return JSON.stringify(t).replaceAll("<","\\u003c")}r(ba,"scriptString");function Ct(t){return t.replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'")}r(Ct,"escapeHtml");var xa=`
|
|
295
|
+
--oc-bg: #f8f8f8;
|
|
296
|
+
--oc-card: #fcfcfc;
|
|
297
|
+
--oc-text-strong: #171717;
|
|
298
|
+
--oc-text-base: #6f6f6f;
|
|
299
|
+
--oc-text-weak: #8f8f8f;
|
|
300
|
+
--oc-border-weak: #e5e5e5;
|
|
301
|
+
--oc-icon-strong: #171717;
|
|
302
|
+
--oc-icon-base: #8f8f8f;
|
|
303
|
+
--oc-icon-weak: #dbdbdb;
|
|
304
|
+
--oc-success: #2dba26;
|
|
305
|
+
--oc-error: #ed4831;
|
|
306
|
+
--oc-detail-bg: #fff8f6;
|
|
307
|
+
--oc-detail-border: #fdc3b7;
|
|
308
|
+
--oc-shadow: 0 16px 48px -6px rgba(0,0,0,.10), 0 6px 12px -2px rgba(0,0,0,.05), 0 1px 2px rgba(0,0,0,.06);`,Ia=`
|
|
309
|
+
--oc-bg: #101010;
|
|
310
|
+
--oc-card: #161616;
|
|
311
|
+
--oc-text-strong: rgba(255,255,255,.936);
|
|
312
|
+
--oc-text-base: rgba(255,255,255,.618);
|
|
313
|
+
--oc-text-weak: rgba(255,255,255,.422);
|
|
314
|
+
--oc-border-weak: #282828;
|
|
315
|
+
--oc-icon-strong: #ededed;
|
|
316
|
+
--oc-icon-base: #7e7e7e;
|
|
317
|
+
--oc-icon-weak: #343434;
|
|
318
|
+
--oc-success: #12c905;
|
|
319
|
+
--oc-error: #fc533a;
|
|
320
|
+
--oc-detail-bg: #28110c;
|
|
321
|
+
--oc-detail-border: #6a1206;
|
|
322
|
+
--oc-shadow: 0 16px 48px -6px rgba(0,0,0,.55), 0 6px 12px -2px rgba(0,0,0,.35), 0 1px 2px rgba(0,0,0,.4);`,rp=`
|
|
323
|
+
:root { color-scheme: light dark;${xa}
|
|
324
|
+
--oc-font-sans: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
325
|
+
--oc-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
|
326
|
+
}
|
|
327
|
+
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) {${Ia} } }
|
|
328
|
+
:root[data-theme="dark"] {${Ia} }
|
|
329
|
+
:root[data-theme="light"] {${xa} }
|
|
330
|
+
|
|
331
|
+
* { box-sizing: border-box; }
|
|
332
|
+
html, body { margin: 0; height: 100%; }
|
|
333
|
+
body {
|
|
334
|
+
min-height: 100vh;
|
|
335
|
+
display: grid;
|
|
336
|
+
place-items: center;
|
|
337
|
+
padding: 24px;
|
|
338
|
+
background: var(--oc-bg);
|
|
339
|
+
color: var(--oc-text-base);
|
|
340
|
+
font-family: var(--oc-font-sans);
|
|
341
|
+
line-height: 1.5;
|
|
342
|
+
-webkit-font-smoothing: antialiased;
|
|
343
|
+
text-rendering: optimizeLegibility;
|
|
344
|
+
}
|
|
345
|
+
.card {
|
|
346
|
+
width: min(100%, 28rem);
|
|
347
|
+
padding: 2.25rem 2rem 1.75rem;
|
|
348
|
+
background: var(--oc-card);
|
|
349
|
+
border: 1px solid var(--oc-border-weak);
|
|
350
|
+
border-radius: 14px;
|
|
351
|
+
box-shadow: var(--oc-shadow);
|
|
352
|
+
text-align: center;
|
|
353
|
+
}
|
|
354
|
+
.brand { display: flex; justify-content: center; margin-bottom: 1.75rem; }
|
|
355
|
+
.brand svg { height: 19px; width: auto; }
|
|
356
|
+
.status { display: flex; justify-content: center; margin-bottom: 1.125rem; }
|
|
357
|
+
.icon { display: none; line-height: 0; }
|
|
358
|
+
.icon svg { display: block; }
|
|
359
|
+
.card[data-status="pending"] .icon-pending,
|
|
360
|
+
.card[data-status="success"] .icon-success,
|
|
361
|
+
.card[data-status="error"] .icon-error { display: block; }
|
|
362
|
+
.icon-success { color: var(--oc-success); }
|
|
363
|
+
.icon-error { color: var(--oc-error); }
|
|
364
|
+
.icon-pending { color: var(--oc-text-weak); }
|
|
365
|
+
.headline { margin: 0; font-size: 1.1875rem; font-weight: 500; line-height: 1.3; letter-spacing: -0.012em; color: var(--oc-text-strong); }
|
|
366
|
+
.message { margin: 0.5rem 0 0; font-size: 0.9375rem; color: var(--oc-text-base); }
|
|
367
|
+
.detail {
|
|
368
|
+
margin: 1.25rem 0 0;
|
|
369
|
+
padding: 0.75rem 0.875rem;
|
|
370
|
+
text-align: left;
|
|
371
|
+
font-family: var(--oc-font-mono);
|
|
372
|
+
font-size: 0.8125rem;
|
|
373
|
+
line-height: 1.55;
|
|
374
|
+
color: var(--oc-text-strong);
|
|
375
|
+
background: var(--oc-detail-bg);
|
|
376
|
+
border: 1px solid var(--oc-detail-border);
|
|
377
|
+
border-radius: 8px;
|
|
378
|
+
white-space: pre-wrap;
|
|
379
|
+
word-break: break-word;
|
|
380
|
+
max-height: 9.5rem;
|
|
381
|
+
overflow: auto;
|
|
382
|
+
}
|
|
383
|
+
.detail[hidden] { display: none; }
|
|
384
|
+
.footnote { margin: 1.5rem 0 0; font-size: 0.8125rem; color: var(--oc-text-weak); }
|
|
385
|
+
.spinner { animation: oc-spin 0.8s linear infinite; transform-origin: center; }
|
|
386
|
+
@keyframes oc-spin { to { transform: rotate(360deg); } }
|
|
387
|
+
@media (prefers-reduced-motion: reduce) { .spinner { animation: none; } }
|
|
388
|
+
`,ip=`<svg class="wordmark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 234 42" fill="none" aria-label="OpenCode" role="img">
|
|
389
|
+
<path d="M18 30H6V18H18V30Z" fill="var(--oc-icon-weak)" />
|
|
390
|
+
<path d="M18 12H6V30H18V12ZM24 36H0V6H24V36Z" fill="var(--oc-icon-base)" />
|
|
391
|
+
<path d="M48 30H36V18H48V30Z" fill="var(--oc-icon-weak)" />
|
|
392
|
+
<path d="M36 30H48V12H36V30ZM54 36H36V42H30V6H54V36Z" fill="var(--oc-icon-base)" />
|
|
393
|
+
<path d="M84 24V30H66V24H84Z" fill="var(--oc-icon-weak)" />
|
|
394
|
+
<path d="M84 24H66V30H84V36H60V6H84V24ZM66 18H78V12H66V18Z" fill="var(--oc-icon-base)" />
|
|
395
|
+
<path d="M108 36H96V18H108V36Z" fill="var(--oc-icon-weak)" />
|
|
396
|
+
<path d="M108 12H96V36H90V6H108V12ZM114 36H108V12H114V36Z" fill="var(--oc-icon-base)" />
|
|
397
|
+
<path d="M144 30H126V18H144V30Z" fill="var(--oc-icon-weak)" />
|
|
398
|
+
<path d="M144 12H126V30H144V36H120V6H144V12Z" fill="var(--oc-icon-strong)" />
|
|
399
|
+
<path d="M168 30H156V18H168V30Z" fill="var(--oc-icon-weak)" />
|
|
400
|
+
<path d="M168 12H156V30H168V12ZM174 36H150V6H174V36Z" fill="var(--oc-icon-strong)" />
|
|
401
|
+
<path d="M198 30H186V18H198V30Z" fill="var(--oc-icon-weak)" />
|
|
402
|
+
<path d="M198 12H186V30H198V12ZM204 36H180V6H198V0H204V36Z" fill="var(--oc-icon-strong)" />
|
|
403
|
+
<path d="M234 24V30H216V24H234Z" fill="var(--oc-icon-weak)" />
|
|
404
|
+
<path d="M216 12V18H228V12H216ZM234 24H216V30H234V36H210V6H234V24Z" fill="var(--oc-icon-strong)" />
|
|
405
|
+
</svg>`,sp='<svg viewBox="0 0 24 24" width="30" height="30" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9" /><path d="m8.5 12.5 2.4 2.4 4.6-5.4" /></svg>',ap='<svg viewBox="0 0 24 24" width="30" height="30" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9" /><path d="m9 9 6 6m0-6-6 6" /></svg>',cp='<svg class="spinner" viewBox="0 0 24 24" width="30" height="30" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="12" cy="12" r="9" opacity="0.2" /><path d="M21 12a9 9 0 0 0-9-9" /></svg>';var jo="app_EMoamEEZ73f0CkXaXp7hrann",Pt="https://auth.openai.com",qr=1455,lp=3e3,$r=N.MethodID.make("chatgpt-browser"),Fr=N.MethodID.make("chatgpt-headless"),fp={integrationID:N.ID.make("openai"),method:{id:$r,type:"oauth",label:"ChatGPT Pro/Plus (browser)"},authorize:r(()=>te.gen(function*(){let t=yield*te.promise(up),e=Aa(crypto.getRandomValues(new Uint8Array(32)).buffer),n=yield*co.make(),o=`http://localhost:${qr}/auth/callback`,i=dp((s,d)=>{let c=new URL(s.url??"/",`http://localhost:${qr}`);if(c.pathname!=="/auth/callback"){d.writeHead(404).end("Not found");return}let a=c.searchParams.get("error_description")??c.searchParams.get("error"),l=c.searchParams.get("code");if(a){te.runFork(co.fail(n,new Error(a))),d.writeHead(400,{"Content-Type":"text/html"}).end(Pe.error(a,{provider:"ChatGPT"}));return}if(!l||c.searchParams.get("state")!==e){let f=l?"Invalid OAuth state":"Missing authorization code";te.runFork(co.fail(n,new Error(f))),d.writeHead(400,{"Content-Type":"text/html"}).end(Pe.error(f,{provider:"ChatGPT"}));return}te.runFork(co.succeed(n,l)),d.writeHead(200,{"Content-Type":"text/html"}).end(Pe.success({provider:"ChatGPT"}))});return yield*te.callback(s=>{i.once("error",d=>s(te.fail(d))),i.listen(qr,"localhost",()=>s(te.void))}),yield*te.addFinalizer(()=>te.sync(()=>i.close())),{mode:"auto",url:mp(o,t,e),instructions:"Complete authorization in your browser. This window will close automatically.",callback:co.await(n).pipe(te.flatMap(s=>Pa(s,o,t)),te.map(s=>Gr($r,s)))}}),"authorize"),refresh:r(t=>Ra($r,t),"refresh")},pp={integrationID:N.ID.make("openai"),method:{id:Fr,type:"oauth",label:"ChatGPT Pro/Plus (headless)"},authorize:r(()=>te.gen(function*(){let t=yield*Hr(`${Pt}/api/accounts/deviceauth/usercode`,{method:"POST",headers:No("application/json"),body:JSON.stringify({client_id:jo})}),e=Math.max(Number.parseInt(t.interval)||5,1)*1e3;return{mode:"auto",url:`${Pt}/codex/device`,instructions:`Enter code: ${t.user_code}`,callback:te.gen(function*(){for(;;){let n=yield*te.tryPromise({try:r(o=>fetch(`${Pt}/api/accounts/deviceauth/token`,{method:"POST",headers:No("application/json"),body:JSON.stringify({device_auth_id:t.device_auth_id,user_code:t.user_code}),signal:o}),"try"),catch:r(o=>o,"catch")});if(n.ok){let o=yield*te.promise(()=>n.json());return Gr(Fr,yield*Pa(o.authorization_code,`${Pt}/deviceauth/callback`,{verifier:o.code_verifier,challenge:""}))}if(n.status!==403&&n.status!==404)return yield*te.fail(new Error(`Device authorization failed: ${n.status}`));yield*te.sleep(e+lp)}})}}),"authorize"),refresh:r(t=>Ra(Fr,t),"refresh")},Ca={id:"openai",effect:te.fn(function*(t){yield*t.integration.transform(e=>{e.method.update(fp),e.method.update(pp)}),yield*t.catalog.transform(te.fn(function*(e){for(let n of e.provider.list())n.provider.api.type==="aisdk"&&n.provider.api.package==="@ai-sdk/openai"&&n.models.has(oe.ID.make("gpt-5-chat-latest"))&&e.model.update(n.provider.id,oe.ID.make("gpt-5-chat-latest"),o=>{o.enabled=!1})})),yield*t.aisdk.sdk(te.fn(function*(e){if(e.package!=="@ai-sdk/openai")return;let n=yield*te.promise(()=>import("@ai-sdk/openai"));e.sdk=n.createOpenAI(e.options)})),yield*t.aisdk.language(te.fn(function*(e){e.model.providerID===_.ID.openai&&(e.language=e.sdk.responses(e.model.api.id))}))})};function No(t){return{"Content-Type":t,"User-Agent":`opencode/${Te}`}}r(No,"headers");function Pa(t,e,n){return Hr(`${Pt}/oauth/token`,{method:"POST",headers:No("application/x-www-form-urlencoded"),body:new URLSearchParams({grant_type:"authorization_code",code:t,redirect_uri:e,client_id:jo,code_verifier:n.verifier}).toString()})}r(Pa,"exchange");function Ra(t,e){return Hr(`${Pt}/oauth/token`,{method:"POST",headers:No("application/x-www-form-urlencoded"),body:new URLSearchParams({grant_type:"refresh_token",refresh_token:e.refresh,client_id:jo}).toString()}).pipe(te.map(n=>{let o=Gr(t,n);return $e.OAuth.make({...o,metadata:o.metadata??e.metadata})}))}r(Ra,"refresh");function Hr(t,e){return te.tryPromise({try:r(async n=>{let o=await fetch(t,{...e,signal:n});if(!o.ok)throw new Error(`Request failed: ${o.status}`);return o.json()},"try"),catch:r(n=>n,"catch")})}r(Hr,"request");function Gr(t,e){let n=gp(e);return $e.OAuth.make({type:"oauth",methodID:t,refresh:e.refresh_token,access:e.access_token,expires:Date.now()+(e.expires_in??3600)*1e3,metadata:n?{accountID:n}:void 0})}r(Gr,"credential");async function up(){let t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~",e=Array.from(crypto.getRandomValues(new Uint8Array(43)),o=>t[o%t.length]).join(""),n=Aa(await crypto.subtle.digest("SHA-256",new TextEncoder().encode(e)));return{verifier:e,challenge:n}}r(up,"generatePKCE");function Aa(t){return Buffer.from(t).toString("base64url")}r(Aa,"base64UrlEncode");function mp(t,e,n){return`${Pt}/oauth/authorize?${new URLSearchParams({response_type:"code",client_id:jo,redirect_uri:t,scope:"openid profile email offline_access",code_challenge:e.challenge,code_challenge_method:"S256",id_token_add_organizations:"true",codex_cli_simplified_flow:"true",state:n,originator:"opencode"})}`}r(mp,"authorizeURL");function gp(t){return wa(t.id_token)??wa(t.access_token)}r(gp,"extractAccountID");function wa(t){let e=t.split(".")[1];if(e)try{let n=JSON.parse(Buffer.from(e,"base64url").toString());return n.chatgpt_account_id??n["https://api.openai.com/auth"]?.chatgpt_account_id??n.organizations?.[0]?.id}catch{return}}r(wa,"claim");import{Effect as Br}from"effect";function hp(t=fetch){return async(e,n)=>{if(n?.body&&typeof n.body=="string")try{let i=JSON.parse(n.body);"max_tokens"in i&&(i.max_completion_tokens=i.max_tokens,delete i.max_tokens,n={...n,body:JSON.stringify(i)})}catch{}let o=await t(e,n);if(!o.ok&&o.status===400)try{let i=await o.clone().json();if(String(i.message||i.error||"").toLowerCase().includes("conversation complete"))return new Response(JSON.stringify({choices:[{finish_reason:"stop",message:{content:"",role:"assistant"}}]}),{status:200,headers:new Headers({"content-type":"application/json"})})}catch{}if(o.body&&o.headers.get("content-type")?.includes("text/event-stream")){let i=o.body.getReader(),s=new TextEncoder,d=new TextDecoder,c=new ReadableStream({async pull(a){let{done:l,value:f}=await i.read();if(l){a.close();return}a.enqueue(s.encode(d.decode(f,{stream:!0}).replace(/"role"\s*:\s*""/g,'"role":"assistant"')))},cancel(){i.cancel()}});return new Response(c,{headers:o.headers,status:o.status})}return o}}r(hp,"cortexFetch");var Da={id:"snowflake-cortex",effect:Br.fn(function*(t){yield*t.aisdk.sdk(Br.fn(function*(e){if(e.model.providerID!==_.ID.make("snowflake-cortex"))return;let n=process.env.SNOWFLAKE_CORTEX_TOKEN??process.env.SNOWFLAKE_CORTEX_PAT??(typeof e.options.token=="string"?e.options.token:void 0)??(typeof e.options.apiKey=="string"?e.options.apiKey:void 0),o=typeof e.options.fetch=="function"?e.options.fetch:void 0;e.options.includeUsage!==!1&&(e.options.includeUsage=!0);let i=yield*Br.promise(()=>import("@ai-sdk/openai-compatible"));e.sdk=i.createOpenAICompatible({...e.options,...n?{apiKey:n}:{},fetch:hp(o)})}))})};import{Effect as Kr}from"effect";var Ta={id:"openai-compatible",effect:Kr.fn(function*(t){yield*t.aisdk.sdk(Kr.fn(function*(e){if(e.sdk||!e.package.includes("@ai-sdk/openai-compatible"))return;e.options.includeUsage!==!1&&(e.options.includeUsage=!0);let n=yield*Kr.promise(()=>import("@ai-sdk/openai-compatible"));e.sdk=n.createOpenAICompatible(e.options)}))})};import{Duration as Wr,Effect as Q,Schema as re,Semaphore as yp,Stream as Oa}from"effect";import{HttpClient as Ma,HttpClientRequest as ze,HttpClientResponse as fo}from"effect/unstable/http";var lo="https://opencode.ai/console",Jr="opencode-cli",La=N.MethodID.make("device"),vp=re.Struct({config:Li.Info}),kp=re.Struct({device_code:re.String,user_code:re.String,verification_uri_complete:re.String,expires_in:re.Number,interval:re.Number}),Ua=re.Struct({access_token:re.String,refresh_token:re.String,expires_in:re.Number}),Sp=re.Struct({error:re.String}),Ep=re.Union([Ua,Sp]),bp=re.Struct({id:re.String,email:re.String}),xp=re.Struct({id:re.String,name:re.String});function Ip(t){return{integrationID:N.ID.make("opencode"),method:{id:La,type:"oauth",label:"OpenCode Console account"},authorize:r(()=>Q.gen(function*(){let e=yield*Yr(t,`${lo}/auth/device/code`,{client_id:Jr},kp);return{mode:"auto",url:(yield*Q.try({try:r(()=>{let o=new URL(e.verification_uri_complete,`${lo}/`);if(o.protocol!=="http:"&&o.protocol!=="https:")throw new Error("expected HTTP(S)");return o},"try"),catch:r(o=>new Error(`Invalid device verification URL: ${o instanceof Error?o.message:String(o)}`),"catch")})).href,instructions:`Enter code: ${e.user_code}`,callback:Pp(t,lo,e.device_code,Wr.seconds(e.interval))}}),"authorize"),refresh:r(e=>Q.gen(function*(){let n=typeof e.metadata?.server=="string"?e.metadata.server:lo,o=yield*Yr(t,`${n}/auth/device/token`,{grant_type:"refresh_token",refresh_token:e.refresh,client_id:Jr},Ua);return{...e,access:o.access_token,refresh:o.refresh_token,expires:Date.now()+o.expires_in*1e3}}),"refresh"),label:r(e=>typeof e.metadata?.orgName=="string"?e.metadata.orgName:void 0,"label")}}r(Ip,"oauth");var Va={id:"opencode",effect:Q.fn(function*(t){let e=yield*se.Service,n=yield*Ma.HttpClient,o=yp.makeUnsafe(1),i=!1,s,d=Q.fn("OpencodePlugin.load")(function*(){let a=yield*t.integration.connection.active("opencode"),l=a?yield*t.integration.connection.resolve(a).pipe(Q.catch(()=>Q.succeed(void 0))):void 0;i=a!==void 0,s=l?yield*wp(n,l).pipe(Q.catch(f=>Q.logWarning("failed to load OpenCode provider config",{cause:f}).pipe(Q.as(void 0)))):void 0});yield*t.integration.transform(a=>{a.update("opencode",l=>{l.name="OpenCode"}),a.method.update(Ip(n)),a.method.update({integrationID:"opencode",method:{type:"key",label:"API key (service account)"}})}),i=(yield*t.integration.connection.active("opencode"))!==void 0,yield*t.catalog.transform(a=>{for(let[p,m]of Object.entries(s??{})){a.provider.update(p,y=>{y.integrationID=N.ID.make("opencode"),m.name!==void 0&&(y.name=m.name),y.api=m.npm?{type:"aisdk",package:m.npm,url:m.api}:{type:"native",url:m.api,settings:{}},Object.assign(y.request.headers,m.options?.headers),Object.assign(y.request.body,zr(m.options))});for(let[y,g]of Object.entries(m.models??{}))a.model.update(p,y,b=>{g.family!==void 0&&(b.family=g.family),g.name!==void 0&&(b.name=g.name),g.id!==void 0&&(b.api.id=g.id),g.provider!==void 0&&(b.api=g.provider.npm?{id:b.api.id,type:"aisdk",package:g.provider.npm,url:g.provider.api}:{id:b.api.id,type:"native",url:g.provider.api,settings:{}}),g.tool_call!==void 0&&(b.capabilities.tools=g.tool_call),g.modalities?.input!==void 0&&(b.capabilities.input=[...g.modalities.input]),g.modalities?.output!==void 0&&(b.capabilities.output=[...g.modalities.output]);let P=g.provider?.npm??m.npm,C=Ui.get(P);if(Object.assign(b.request.headers,g.headers),Object.assign(b.request.body,C.request(zr(g.options))),g.variants!==void 0&&(b.variants=Object.entries(g.variants).map(([A,S])=>({id:oe.VariantID.make(A),headers:{...S.headers??{}},body:C.request(zr(S))}))),g.release_date!==void 0){let A=Date.parse(g.release_date);b.time.released=Number.isFinite(A)?A:0}g.cost!==void 0&&(b.cost=Cp(g.cost)),b.status=g.status??"active",b.enabled=g.status!=="deprecated",g.limit!==void 0&&(b.limit={...g.limit})})}let l=a.provider.get(_.ID.opencode);if(!l)return;let f=!!(process.env.OPENCODE_API_KEY||i||l.provider.request.body.apiKey);if(a.provider.update(l.provider.id,p=>{f||(p.request.body.apiKey="public")}),!f)for(let p of l.models.values())p.cost.some(m=>m.input>0)&&a.model.update(l.provider.id,p.id,m=>{m.enabled=!1})});let c=r(()=>o.withPermit(d().pipe(Q.andThen(t.catalog.reload()))),"refresh");yield*e.subscribe(N.Event.ConnectionUpdated).pipe(Oa.filter(a=>a.data.integrationID===N.ID.make("opencode")),Oa.runForEach(c),Q.forkScoped({startImmediately:!0})),yield*c().pipe(Q.forkScoped)})};function wp(t,e){let n=e.metadata,o=typeof n?.server=="string"?n.server:lo,i=typeof n?.orgID=="string"?n.orgID:void 0,s=e.type==="oauth"?e.access:e.key;return t.execute(ze.get(`${o}/api/config`).pipe(ze.acceptJson,ze.bearerToken(s),ze.setHeaders(i?{"x-org-id":i}:{}))).pipe(Q.flatMap(d=>d.status===404?Q.succeed(void 0):fo.filterStatusOk(d).pipe(Q.flatMap(fo.schemaBodyJson(vp)),Q.map(c=>c.config.provider))))}r(wp,"fetchProviders");function zr(t){return Object.fromEntries(Object.entries(t??{}).filter(([e])=>e!=="apiKey"&&e!=="headers"))}r(zr,"withoutCredentials");function Cp(t){let e={input:t.input,output:t.output,cache:{read:t.cache_read??0,write:t.cache_write??0}};return t.context_over_200k?[e,{tier:{type:"context",size:2e5},input:t.context_over_200k.input,output:t.context_over_200k.output,cache:{read:t.context_over_200k.cache_read??0,write:t.context_over_200k.cache_write??0}}]:[e]}r(Cp,"remoteCost");function Pp(t,e,n,o){let i=r(s=>Q.gen(function*(){yield*Q.sleep(s);let d=yield*Yr(t,`${e}/auth/device/token`,{grant_type:"urn:ietf:params:oauth:grant-type:device_code",device_code:n,client_id:Jr},Ep,!1);return"access_token"in d?yield*Rp(t,e,d):d.error==="authorization_pending"?yield*i(s):d.error==="slow_down"?yield*i(Wr.sum(s,Wr.seconds(5))):yield*Q.fail(new Error(`Device authorization failed: ${d.error}`))}),"loop");return i(o)}r(Pp,"poll");function Rp(t,e,n){return Q.gen(function*(){let[o,i]=yield*Q.all([_a(t,`${e}/api/user`,n.access_token,bp),_a(t,`${e}/api/orgs`,n.access_token,re.Array(xp))],{concurrency:2}),s=i.toSorted((d,c)=>d.name.localeCompare(c.name)||d.id.localeCompare(c.id))[0];return $e.OAuth.make({type:"oauth",methodID:La,access:n.access_token,refresh:n.refresh_token,expires:Date.now()+n.expires_in*1e3,metadata:{server:e,accountID:o.id,email:o.email,orgID:s?.id,orgName:s?.name}})})}r(Rp,"credential");function _a(t,e,n,o){return Ma.filterStatusOk(t).execute(ze.get(e).pipe(ze.acceptJson,ze.bearerToken(n))).pipe(Q.flatMap(fo.schemaBodyJson(o)))}r(_a,"get");function Yr(t,e,n,o,i=!0){return ze.post(e).pipe(ze.acceptJson,ze.schemaBodyJson(re.Record(re.String,re.String))(n),Q.flatMap(s=>t.execute(s)),Q.flatMap(s=>i?fo.filterStatusOk(s):Q.succeed(s)),Q.flatMap(fo.schemaBodyJson(o)))}r(Yr,"post");import{Effect as qo}from"effect";var Na={id:"openrouter",effect:qo.fn(function*(t){yield*t.catalog.transform(qo.fn(function*(e){for(let n of e.provider.list())if(n.provider.api.type==="aisdk"&&n.provider.api.package==="@openrouter/ai-sdk-provider"){e.provider.update(n.provider.id,o=>{o.request.headers["HTTP-Referer"]="https://opencode.ai/",o.request.headers["X-Title"]="opencode"});for(let o of[oe.ID.make("gpt-5-chat-latest"),oe.ID.make("openai/gpt-5-chat")])n.models.has(o)&&e.model.update(n.provider.id,o,i=>{i.enabled=!1})}})),yield*t.aisdk.sdk(qo.fn(function*(e){if(e.package!=="@openrouter/ai-sdk-provider")return;let n=yield*qo.promise(()=>import("@openrouter/ai-sdk-provider"));e.sdk=n.createOpenRouter(e.options)}))})};import{Effect as Zr}from"effect";var ja={id:"perplexity",effect:Zr.fn(function*(t){yield*t.aisdk.sdk(Zr.fn(function*(e){if(e.package!=="@ai-sdk/perplexity")return;let n=yield*Zr.promise(()=>import("@ai-sdk/perplexity"));e.sdk=n.createPerplexity(e.options)}))})};import{Effect as gn}from"effect";import{pathToFileURL as Ap}from"url";var qa={id:"sap-ai-core",effect:gn.fn(function*(t){let e=yield*Fe.Service;yield*t.aisdk.sdk(gn.fn(function*(n){if(n.model.providerID!==_.ID.make("sap-ai-core"))return;let o=process.env.AICORE_SERVICE_KEY??(typeof n.options.serviceKey=="string"?n.options.serviceKey:void 0);o&&!process.env.AICORE_SERVICE_KEY&&(process.env.AICORE_SERVICE_KEY=o);let i=n.package.startsWith("file://")?n.package:(yield*e.add(n.package).pipe(gn.orDie)).entrypoint;if(!i)throw new Error(`Package ${n.package} has no import entrypoint`);let s=yield*gn.promise(async()=>await(i.startsWith("file://")?import(i):import(Ap(i).href))).pipe(gn.orDie),d=Object.keys(s).find(c=>c.startsWith("create"));if(!d)throw new Error(`Package ${n.package} has no provider factory export`);n.sdk=s[d](o?{deploymentId:process.env.AICORE_DEPLOYMENT_ID,resourceGroup:process.env.AICORE_RESOURCE_GROUP}:{})})),yield*t.aisdk.language(gn.fn(function*(n){n.model.providerID===_.ID.make("sap-ai-core")&&(n.language=n.sdk(n.model.api.id))}))})};import{Effect as Xr}from"effect";var $a={id:"togetherai",effect:Xr.fn(function*(t){yield*t.aisdk.sdk(Xr.fn(function*(e){if(e.package!=="@ai-sdk/togetherai")return;let n=yield*Xr.promise(()=>import("@ai-sdk/togetherai"));e.sdk=n.createTogetherAI(e.options)}))})};import{Effect as $o}from"effect";var Fa={id:"vercel",effect:$o.fn(function*(t){yield*t.catalog.transform($o.fn(function*(e){for(let n of e.provider.list())n.provider.api.type==="aisdk"&&n.provider.api.package==="@ai-sdk/vercel"&&e.provider.update(n.provider.id,o=>{o.request.headers["http-referer"]="https://opencode.ai/",o.request.headers["x-title"]="opencode"})})),yield*t.aisdk.sdk($o.fn(function*(e){if(e.package!=="@ai-sdk/vercel")return;let n=yield*$o.promise(()=>import("@ai-sdk/vercel"));e.sdk=n.createVercel(e.options)}))})};import{Effect as Qr}from"effect";var Ha={id:"venice",effect:Qr.fn(function*(t){yield*t.aisdk.sdk(Qr.fn(function*(e){if(e.package!=="venice-ai-sdk-provider")return;let n=yield*Qr.promise(()=>import("venice-ai-sdk-provider"));e.sdk=n.createVenice(e.options)}))})};import{Effect as Fo}from"effect";var Ga={id:"xai",effect:Fo.fn(function*(t){yield*t.aisdk.sdk(Fo.fn(function*(e){if(e.package!=="@ai-sdk/xai")return;let n=yield*Fo.promise(()=>import("@ai-sdk/xai"));e.sdk=n.createXai(e.options)})),yield*t.aisdk.language(Fo.fn(function*(e){e.model.providerID===_.ID.make("xai")&&(e.language=e.sdk.responses(e.model.api.id))}))})};import{Effect as Ba}from"effect";var Ka={id:"zenmux",effect:Ba.fn(function*(t){yield*t.catalog.transform(Ba.fn(function*(e){for(let n of e.provider.list())n.provider.api.type==="aisdk"&&n.provider.api.package==="@ai-sdk/openai-compatible"&&n.provider.api.url==="https://zenmux.ai/api/v1"&&e.provider.update(n.provider.id,o=>{o.request.headers["HTTP-Referer"]??="https://opencode.ai/",o.request.headers["X-Title"]??="opencode"})}))})};var za=[Gs,Bs,Ks,Js,Ws,Ys,Xs,ta,na,oa,ia,sa,aa,ca,ua,pa,ma,ha,va,ka,Ea,Va,Da,Ta,Ca,Na,ja,qa,$a,Fa,Ha,Ga,Ka,ra];var po={};T(po,{Plugin:()=>Tp,VariantPlugin:()=>po,generate:()=>Wa});import{Effect as Dp}from"effect";var Tp={id:"variant",effect:Dp.fn(function*(t){yield*t.catalog.transform(e=>{for(let n of e.provider.list())for(let o of n.models.values())e.model.update(o.providerID,o.id,i=>{let s=Wa(i);if(s.length===0)return;let d=new Map(i.variants.map(a=>[a.id,a])),c=new Set(s.map(a=>a.id));i.variants=[...s.map(a=>d.get(a.id)??a),...i.variants.filter(a=>!c.has(a.id))]})})})};function Wa(t){if(t.api.type!=="aisdk"||t.api.package!=="@ai-sdk/openai-compatible")return[];let e=`${t.id} ${t.api.id}`.toLowerCase();return["glm-5.2","glm-5-2","glm-5p2"].some(n=>e.includes(n))?["high","max"].map(n=>({id:n,headers:{},body:{reasoning_effort:n}})):[]}r(Wa,"generate");function M(t){return t}r(M,"define");var Ya=ei.effectDiscard(de.gen(function*(){let t=yield*Je.Service,e=yield*Oe.Service,n=yield*Be.Service,o=yield*N.Service,i=yield*W.Service,s=yield*ie.Service,d=yield*pe.Service,c=yield*He.Service,a=yield*Fe.Service,l=yield*se.Service,f=yield*G.Service,p=yield*So.Service,m=yield*H.Service,y=yield*Ja.HttpClient,g=yield*ae.Service,b=yield*ge.Service,P=r(C=>{let A={id:C.id,effect:r(S=>C.effect(S).pipe(de.provideService(Je.Service,t),de.provideService(Oe.Service,e),de.provideService(N.Service,o),de.provideService(W.Service,i),de.provideService(ie.Service,s),de.provideService(pe.Service,d),de.provideService(He.Service,c),de.provideService(Fe.Service,a),de.provideService(se.Service,l),de.provideService(G.Service,f),de.provideService(So.Service,p),de.provideService(H.Service,m),de.provideService(Ja.HttpClient,y),de.provideService(ae.Service,g),de.provideService(ge.Service,b)),"effect")};return n.add(Be.ID.make(A.id),A.effect)},"add");yield*De.batch(de.gen(function*(){yield*P(Xn.Plugin),yield*P(no.Plugin),yield*P(oo.Plugin),yield*P(Rt.Plugin),yield*P(Hs),yield*P(Un.Plugin),yield*P(Vn.Plugin),yield*P(eo.Plugin);for(let C of za)yield*P(C);yield*P(jn.Plugin),yield*P(qn.Plugin),yield*P(po.Plugin)})).pipe(de.withSpan("PluginInternal.boot"),de.forkScoped({startImmediately:!0}))})),_p=Ya.pipe(ei.provideMerge(ie.locationLayer),ei.provideMerge(Op.layer)),Mp=Se({name:"plugin-internal",layer:Ya,deps:[Je.node,Oe.node,Be.node,N.node,W.node,ie.node,pe.node,He.node,Fe.node,se.node,G.node,So.node,H.node,rt,ae.node,ge.node]});import{Effect as Lp}from"effect";var Za=`<!--
|
|
406
|
+
Built-in skill. Name and description are registered in code at
|
|
407
|
+
packages/core/src/plugin/skill.ts
|
|
408
|
+
and CUSTOMIZE_OPENCODE_SKILL_DESCRIPTION). The body below becomes the
|
|
409
|
+
skill's content.
|
|
410
|
+
-->
|
|
411
|
+
|
|
412
|
+
# Customizing opencode
|
|
413
|
+
|
|
414
|
+
opencode validates its own config strictly and refuses to start when a field
|
|
415
|
+
is wrong. The shapes below cover the common surface area, but they are a
|
|
416
|
+
**summary, not the source of truth**.
|
|
417
|
+
|
|
418
|
+
## Full schema reference
|
|
419
|
+
|
|
420
|
+
The authoritative list of every config option \u2014 with field types, enums,
|
|
421
|
+
defaults, and descriptions \u2014 lives in the published JSON Schema:
|
|
422
|
+
|
|
423
|
+
**<https://opencode.ai/config.json>**
|
|
424
|
+
|
|
425
|
+
If a field is not documented in this skill, or you need to confirm an exact
|
|
426
|
+
shape before writing config, **fetch that URL and read the schema directly**
|
|
427
|
+
rather than guessing. opencode hard-fails on invalid config, so the cost of a
|
|
428
|
+
wrong shape is a broken startup.
|
|
429
|
+
|
|
430
|
+
Independently, every \`opencode.json\` should declare
|
|
431
|
+
\`"$schema": "https://opencode.ai/config.json"\` so the user's editor catches
|
|
432
|
+
mistakes as they type.
|
|
433
|
+
|
|
434
|
+
## Applying changes
|
|
435
|
+
|
|
436
|
+
Config is loaded once when opencode starts and is not hot-reloaded. After
|
|
437
|
+
saving changes to \`opencode.json\`, an agent file, a skill, a plugin, or any
|
|
438
|
+
other config-time file, **tell the user to quit and restart opencode** for
|
|
439
|
+
the changes to take effect. The running session will keep using the
|
|
440
|
+
already-loaded config until then.
|
|
441
|
+
|
|
442
|
+
## Where files live
|
|
443
|
+
|
|
444
|
+
| Scope | Path |
|
|
445
|
+
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
|
|
446
|
+
| Project config | \`./opencode.json\`, \`./opencode.jsonc\`, or \`.opencode/opencode.json\` (opencode walks up from the cwd to the worktree root) |
|
|
447
|
+
| Global config | \`~/.config/opencode/opencode.json\` or \`~/.config/opencode/opencode.jsonc\` (NOT \`~/.opencode/\`) |
|
|
448
|
+
| Project agents | \`.opencode/agent/<name>.md\` or \`.opencode/agents/<name>.md\` |
|
|
449
|
+
| Global agents | \`~/.config/opencode/agent(s)/<name>.md\` |
|
|
450
|
+
| Project commands | \`.opencode/command/<name>.md\` or \`.opencode/commands/<name>.md\` |
|
|
451
|
+
| Global commands | \`~/.config/opencode/command(s)/<name>.md\` |
|
|
452
|
+
| Project skills | \`.opencode/skill(s)/<name>/SKILL.md\` |
|
|
453
|
+
| Global skills | \`~/.config/opencode/skill(s)/<name>/SKILL.md\` |
|
|
454
|
+
| External skills (auto-loaded) | \`~/.claude/skills/<name>/SKILL.md\`, \`~/.agents/skills/<name>/SKILL.md\` |
|
|
455
|
+
|
|
456
|
+
Configs from each scope are deep-merged. Project overrides global. Unknown
|
|
457
|
+
top-level keys in \`opencode.json\` are rejected with \`ConfigInvalidError\`.
|
|
458
|
+
|
|
459
|
+
## opencode.json
|
|
460
|
+
|
|
461
|
+
Every field is optional.
|
|
462
|
+
|
|
463
|
+
\`\`\`json
|
|
464
|
+
{
|
|
465
|
+
"$schema": "https://opencode.ai/config.json",
|
|
466
|
+
"username": "string",
|
|
467
|
+
"model": "provider/model-id",
|
|
468
|
+
"small_model": "provider/model-id",
|
|
469
|
+
"default_agent": "agent-name",
|
|
470
|
+
"shell": "/bin/zsh",
|
|
471
|
+
"logLevel": "DEBUG" | "INFO" | "WARN" | "ERROR",
|
|
472
|
+
"share": "manual" | "auto" | "disabled",
|
|
473
|
+
"autoupdate": true | false | "notify",
|
|
474
|
+
"snapshot": true,
|
|
475
|
+
"instructions": ["AGENTS.md", "docs/style.md"],
|
|
476
|
+
|
|
477
|
+
"skills": {
|
|
478
|
+
"paths": [".opencode/skills", "/abs/path/to/skills"],
|
|
479
|
+
"urls": ["https://example.com/.well-known/skills/"]
|
|
480
|
+
},
|
|
481
|
+
|
|
482
|
+
"references": {
|
|
483
|
+
"docs": {
|
|
484
|
+
"path": "../docs",
|
|
485
|
+
"description": "Use for product behavior and documentation conventions"
|
|
486
|
+
},
|
|
487
|
+
"sdk": {
|
|
488
|
+
"repository": "owner/sdk",
|
|
489
|
+
"branch": "main",
|
|
490
|
+
"description": "Use for SDK implementation details",
|
|
491
|
+
"hidden": true
|
|
492
|
+
}
|
|
493
|
+
},
|
|
494
|
+
|
|
495
|
+
"agent": {
|
|
496
|
+
"my-agent": {
|
|
497
|
+
"model": "anthropic/claude-sonnet-4-6",
|
|
498
|
+
"mode": "subagent",
|
|
499
|
+
"description": "...",
|
|
500
|
+
"permission": { "edit": "deny" }
|
|
501
|
+
}
|
|
502
|
+
},
|
|
503
|
+
|
|
504
|
+
"command": {
|
|
505
|
+
"deploy": { "description": "...", "template": "..." }
|
|
506
|
+
},
|
|
507
|
+
|
|
508
|
+
"provider": {
|
|
509
|
+
"anthropic": { "options": { "apiKey": "..." } }
|
|
510
|
+
},
|
|
511
|
+
"disabled_providers": ["openai"],
|
|
512
|
+
"enabled_providers": ["anthropic"],
|
|
513
|
+
|
|
514
|
+
"mcp": {
|
|
515
|
+
"playwright": {
|
|
516
|
+
"type": "local",
|
|
517
|
+
"command": ["npx", "-y", "@playwright/mcp"],
|
|
518
|
+
"enabled": true,
|
|
519
|
+
"environment": {}
|
|
520
|
+
},
|
|
521
|
+
"remote-thing": {
|
|
522
|
+
"type": "remote",
|
|
523
|
+
"url": "https://...",
|
|
524
|
+
"headers": { "Authorization": "Bearer ..." }
|
|
525
|
+
}
|
|
526
|
+
},
|
|
527
|
+
|
|
528
|
+
"plugin": [
|
|
529
|
+
"opencode-gemini-auth",
|
|
530
|
+
"opencode-foo@1.2.3",
|
|
531
|
+
"./local-plugin.ts",
|
|
532
|
+
["opencode-bar", { "option": "value" }]
|
|
533
|
+
],
|
|
534
|
+
|
|
535
|
+
"permission": {
|
|
536
|
+
"edit": "deny",
|
|
537
|
+
"bash": { "git *": "allow", "*": "ask" }
|
|
538
|
+
},
|
|
539
|
+
|
|
540
|
+
"formatter": false,
|
|
541
|
+
"lsp": false,
|
|
542
|
+
|
|
543
|
+
"experimental": {
|
|
544
|
+
"primary_tools": ["edit"],
|
|
545
|
+
"mcp_timeout": 30000
|
|
546
|
+
},
|
|
547
|
+
|
|
548
|
+
"tool_output": { "max_lines": 200, "max_bytes": 8192 },
|
|
549
|
+
|
|
550
|
+
"compaction": { "auto": true, "tail_turns": 15 }
|
|
551
|
+
}
|
|
552
|
+
\`\`\`
|
|
553
|
+
|
|
554
|
+
Shape notes worth being explicit about:
|
|
555
|
+
|
|
556
|
+
- \`model\` always carries a provider prefix: \`"anthropic/claude-sonnet-4-6"\`.
|
|
557
|
+
- \`skills\` is an object with \`paths\` and/or \`urls\`, not an array.
|
|
558
|
+
- \`references\` is an object keyed by alias. Each value is a local path, Git repository, or string shorthand.
|
|
559
|
+
- \`agent\` is an object keyed by agent name, not an array.
|
|
560
|
+
- \`command\` is an object keyed by command name, not an array.
|
|
561
|
+
- \`plugin\` is an array of strings or \`[name, options]\` tuples, not an object.
|
|
562
|
+
- \`mcp[name].command\` is an array of strings, never a single string. \`type\` is required.
|
|
563
|
+
- \`permission\` is either a string action or an object keyed by tool name.
|
|
564
|
+
|
|
565
|
+
## Skills
|
|
566
|
+
|
|
567
|
+
opencode's skill loader scans for \`**/SKILL.md\` inside skill directories. The
|
|
568
|
+
file is named \`SKILL.md\` exactly, and lives in its own folder named after the
|
|
569
|
+
skill:
|
|
570
|
+
|
|
571
|
+
\`\`\`
|
|
572
|
+
.opencode/skills/my-skill/SKILL.md
|
|
573
|
+
\`\`\`
|
|
574
|
+
|
|
575
|
+
Frontmatter:
|
|
576
|
+
|
|
577
|
+
\`\`\`markdown
|
|
578
|
+
---
|
|
579
|
+
name: my-skill
|
|
580
|
+
description: One sentence covering what this skill does AND when to trigger it. Front-load the literal keywords or filenames the user is likely to say.
|
|
581
|
+
---
|
|
582
|
+
|
|
583
|
+
# My Skill
|
|
584
|
+
|
|
585
|
+
(skill body in markdown: instructions, examples, references)
|
|
586
|
+
\`\`\`
|
|
587
|
+
|
|
588
|
+
- \`name\` is required, lowercase hyphen-separated, up to 64 chars, and matches the folder name.
|
|
589
|
+
- \`description\` is effectively required: skills without one are filtered out and never surfaced to the model. Cover both _what_ the skill does and _when_ to use it. Write in third person ("Use when...", not "I help with..."). Front-load concrete trigger keywords and filenames; gate with "Use ONLY when..." if the skill should stay quiet on adjacent topics.
|
|
590
|
+
- Optional: \`license\`, \`compatibility\`, \`metadata\` (string-string map).
|
|
591
|
+
|
|
592
|
+
Register skills from non-default locations via \`skills.paths\` (scanned
|
|
593
|
+
recursively for \`**/SKILL.md\`) and \`skills.urls\` (each URL serves a list of
|
|
594
|
+
skills).
|
|
595
|
+
|
|
596
|
+
## References
|
|
597
|
+
|
|
598
|
+
References make local directories and Git repositories outside the active
|
|
599
|
+
project available as supporting context. Configure them under \`references\`,
|
|
600
|
+
keyed by the alias used in \`@\` autocomplete:
|
|
601
|
+
|
|
602
|
+
\`\`\`json
|
|
603
|
+
{
|
|
604
|
+
"references": {
|
|
605
|
+
"docs": {
|
|
606
|
+
"path": "../product-docs",
|
|
607
|
+
"description": "Use for product behavior and terminology"
|
|
608
|
+
},
|
|
609
|
+
"effect": {
|
|
610
|
+
"repository": "Effect-TS/effect",
|
|
611
|
+
"branch": "main",
|
|
612
|
+
"description": "Use for Effect implementation details"
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
\`\`\`
|
|
617
|
+
|
|
618
|
+
Local \`path\` values may be relative to the declaring config, absolute, or use
|
|
619
|
+
\`~/\`. Git \`repository\` values accept Git URLs, host/path references, and GitHub
|
|
620
|
+
\`owner/repo\` shorthand; \`branch\` is optional. Both forms support optional
|
|
621
|
+
\`description\` and \`hidden\` fields.
|
|
622
|
+
|
|
623
|
+
- Only references with a \`description\` are advertised to agents in system context.
|
|
624
|
+
- \`hidden: true\` removes a reference from TUI \`@\` autocomplete only. It remains available to agents and by direct path.
|
|
625
|
+
- Reference directories are automatically allowed through the external-directory boundary; normal read/edit/tool permissions still apply.
|
|
626
|
+
- String shorthand is supported: use \`"docs": "../docs"\` for local paths or \`"effect": "Effect-TS/effect"\` for Git repositories.
|
|
627
|
+
|
|
628
|
+
## Agents
|
|
629
|
+
|
|
630
|
+
Two ways to define an agent. Use the file form for anything non-trivial.
|
|
631
|
+
|
|
632
|
+
### Inline (in \`opencode.json\`)
|
|
633
|
+
|
|
634
|
+
\`\`\`json
|
|
635
|
+
{
|
|
636
|
+
"agent": {
|
|
637
|
+
"my-reviewer": {
|
|
638
|
+
"description": "Reviews PRs for style violations.",
|
|
639
|
+
"mode": "subagent",
|
|
640
|
+
"model": "anthropic/claude-sonnet-4-6",
|
|
641
|
+
"permission": { "edit": "deny", "bash": "ask" },
|
|
642
|
+
"prompt": "You are a strict PR reviewer..."
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
\`\`\`
|
|
647
|
+
|
|
648
|
+
### File
|
|
649
|
+
|
|
650
|
+
\`\`\`
|
|
651
|
+
.opencode/agent/my-reviewer.md OR .opencode/agents/my-reviewer.md
|
|
652
|
+
\`\`\`
|
|
653
|
+
|
|
654
|
+
\`\`\`markdown
|
|
655
|
+
---
|
|
656
|
+
description: Reviews PRs for style violations.
|
|
657
|
+
mode: subagent
|
|
658
|
+
model: anthropic/claude-sonnet-4-6
|
|
659
|
+
permission:
|
|
660
|
+
edit: deny
|
|
661
|
+
bash: ask
|
|
662
|
+
---
|
|
663
|
+
|
|
664
|
+
You are a strict PR reviewer. Focus on...
|
|
665
|
+
\`\`\`
|
|
666
|
+
|
|
667
|
+
The file body becomes the agent's \`prompt\`. Do not also put \`prompt:\` in the
|
|
668
|
+
frontmatter.
|
|
669
|
+
|
|
670
|
+
\`mode\` is one of \`"primary"\`, \`"subagent"\`, \`"all"\`.
|
|
671
|
+
|
|
672
|
+
Allowed top-level frontmatter fields: \`name, model, variant, description, mode,
|
|
673
|
+
hidden, color, steps, options, permission, disable, temperature, top_p\`. Any
|
|
674
|
+
unknown field is silently routed into \`options\`.
|
|
675
|
+
|
|
676
|
+
To disable a built-in agent: \`agent: { build: { disable: true } }\`, or in a
|
|
677
|
+
file, \`disable: true\` in frontmatter.
|
|
678
|
+
|
|
679
|
+
\`default_agent\` must point to a non-hidden, primary-mode agent.
|
|
680
|
+
|
|
681
|
+
### Built-in agents
|
|
682
|
+
|
|
683
|
+
opencode ships with \`build\`, \`plan\`, \`general\`, \`explore\`. Hidden internal agents:
|
|
684
|
+
\`compaction\`, \`title\`, \`summary\`. To override a built-in's fields, define the
|
|
685
|
+
same key in \`agent: { <name>: { ... } }\`.
|
|
686
|
+
|
|
687
|
+
## Commands
|
|
688
|
+
|
|
689
|
+
opencode's command loader scans for \`**/*.md\` inside command directories. The
|
|
690
|
+
file is named after the command, and lives directly inside the \`command\` folder:
|
|
691
|
+
|
|
692
|
+
\`\`\`
|
|
693
|
+
.opencode/command/deploy.md
|
|
694
|
+
\`\`\`
|
|
695
|
+
|
|
696
|
+
Frontmatter:
|
|
697
|
+
|
|
698
|
+
\`\`\`markdown
|
|
699
|
+
---
|
|
700
|
+
description: One sentence describing what the command does.
|
|
701
|
+
agent: build
|
|
702
|
+
model: anthropic/claude-sonnet-4-6
|
|
703
|
+
---
|
|
704
|
+
|
|
705
|
+
(command body in markdown: the prompt opencode runs, with $ARGUMENTS for the user's input)
|
|
706
|
+
\`\`\`
|
|
707
|
+
|
|
708
|
+
- \`template\` is the command body \u2014 everything below the frontmatter \u2014 and is required: it is the prompt opencode runs when the command is invoked. Do not also put a \`template:\` key in the frontmatter.
|
|
709
|
+
- \`$ARGUMENTS\` is replaced with everything the user typed after the command; \`$1\`, \`$2\`, \u2026 pull individual positional arguments.
|
|
710
|
+
- Optional: \`description\`, \`agent\`, \`model\`, \`variant\`, \`subtask\`.
|
|
711
|
+
|
|
712
|
+
## Plugins
|
|
713
|
+
|
|
714
|
+
\`plugin:\` is an array. Each entry is one of:
|
|
715
|
+
|
|
716
|
+
\`\`\`json
|
|
717
|
+
"plugin": [
|
|
718
|
+
"opencode-gemini-auth", // npm spec, latest
|
|
719
|
+
"opencode-foo@1.2.3", // npm spec, pinned
|
|
720
|
+
"./local-plugin.ts", // file path, relative to the declaring config
|
|
721
|
+
"file:///abs/path/plugin.js", // file URL
|
|
722
|
+
["opencode-bar", { "key": "val" }] // tuple form with options
|
|
723
|
+
]
|
|
724
|
+
\`\`\`
|
|
725
|
+
|
|
726
|
+
Auto-discovered plugins (no config entry needed): any \`*.ts\` or \`*.js\` file in
|
|
727
|
+
\`.opencode/plugin/\` or \`.opencode/plugins/\`.
|
|
728
|
+
|
|
729
|
+
A plugin module exports \`default\` (or any named export) of type
|
|
730
|
+
\`Plugin = (input: PluginInput, options?) => Promise<Hooks>\`. The export is a
|
|
731
|
+
function, not a plain object literal, and the function returns an object
|
|
732
|
+
(return \`{}\` if there is nothing to register).
|
|
733
|
+
|
|
734
|
+
\`\`\`ts
|
|
735
|
+
import type { Plugin } from "@opencode-ai/plugin"
|
|
736
|
+
|
|
737
|
+
export default (async ({ client, project, directory, $ }) => {
|
|
738
|
+
return {
|
|
739
|
+
config: (cfg) => {
|
|
740
|
+
// cfg is the live merged config; mutate fields here.
|
|
741
|
+
},
|
|
742
|
+
"tool.execute.before": async (input, output) => {
|
|
743
|
+
// mutate output.args before the tool runs
|
|
744
|
+
},
|
|
745
|
+
}
|
|
746
|
+
}) satisfies Plugin
|
|
747
|
+
\`\`\`
|
|
748
|
+
|
|
749
|
+
Hook surface (mutate \`output\` in place; return \`void\`):
|
|
750
|
+
|
|
751
|
+
- \`event(input)\`: every bus event
|
|
752
|
+
- \`config(cfg)\`: once on init with the merged config
|
|
753
|
+
- \`chat.message\`, \`chat.params\`, \`chat.headers\`
|
|
754
|
+
- \`tool.execute.before\`, \`tool.execute.after\`
|
|
755
|
+
- \`tool.definition\`
|
|
756
|
+
- \`command.execute.before\`
|
|
757
|
+
- \`shell.env\`
|
|
758
|
+
- \`permission.ask\`
|
|
759
|
+
- \`experimental.chat.messages.transform\`, \`experimental.chat.system.transform\`,
|
|
760
|
+
\`experimental.session.compacting\`, \`experimental.compaction.autocontinue\`,
|
|
761
|
+
\`experimental.text.complete\`
|
|
762
|
+
|
|
763
|
+
Special object-shaped (not callbacks): \`tool: { my_tool: { ... } }\`,
|
|
764
|
+
\`auth: { ... }\`, \`provider: { ... }\`.
|
|
765
|
+
|
|
766
|
+
## MCP servers
|
|
767
|
+
|
|
768
|
+
\`mcp:\` is an object keyed by server name. Each server is discriminated by
|
|
769
|
+
\`type\`:
|
|
770
|
+
|
|
771
|
+
\`\`\`json
|
|
772
|
+
{
|
|
773
|
+
"mcp": {
|
|
774
|
+
"playwright": {
|
|
775
|
+
"type": "local",
|
|
776
|
+
"command": ["npx", "-y", "@playwright/mcp"],
|
|
777
|
+
"enabled": true,
|
|
778
|
+
"environment": { "BROWSER": "chromium" }
|
|
779
|
+
},
|
|
780
|
+
"github": {
|
|
781
|
+
"type": "remote",
|
|
782
|
+
"url": "https://...",
|
|
783
|
+
"enabled": true,
|
|
784
|
+
"headers": { "Authorization": "Bearer {env:GITHUB_TOKEN}" }
|
|
785
|
+
},
|
|
786
|
+
"old-server": { "enabled": false }
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
\`\`\`
|
|
790
|
+
|
|
791
|
+
\`command\` is an array of strings. \`environment\` sets environment variables for
|
|
792
|
+
a local MCP server. \`type\` is required. Use \`enabled: false\` to
|
|
793
|
+
disable a server inherited from a parent config. String values such as header
|
|
794
|
+
tokens support \`{env:VAR}\` interpolation (and \`{file:path}\`); the shell-style
|
|
795
|
+
\`\${VAR}\` is not substituted.
|
|
796
|
+
|
|
797
|
+
## Permissions
|
|
798
|
+
|
|
799
|
+
\`\`\`json
|
|
800
|
+
"permission": {
|
|
801
|
+
"edit": "deny",
|
|
802
|
+
"bash": { "git *": "allow", "rm *": "deny", "*": "ask" },
|
|
803
|
+
"external_directory": { "~/secrets/**": "deny", "*": "allow" }
|
|
804
|
+
}
|
|
805
|
+
\`\`\`
|
|
806
|
+
|
|
807
|
+
Actions: \`"allow"\`, \`"ask"\`, \`"deny"\`.
|
|
808
|
+
|
|
809
|
+
Per-tool value forms: \`"allow"\` shorthand (treated as \`{"*": "allow"}\`), or an
|
|
810
|
+
object \`{ pattern: action }\`. Within an object, **insertion order matters**.
|
|
811
|
+
opencode evaluates the LAST matching rule, so put broad rules first and narrow
|
|
812
|
+
rules last.
|
|
813
|
+
|
|
814
|
+
\`permission: "allow"\` (a string at the top level) is shorthand for "allow
|
|
815
|
+
everything" and is rarely what the user wants.
|
|
816
|
+
|
|
817
|
+
Known permission keys: \`read, edit, glob, grep, list, bash, task,
|
|
818
|
+
external_directory, todowrite, question, webfetch, websearch, lsp, doom_loop,
|
|
819
|
+
skill\`. Some of these (\`todowrite,
|
|
820
|
+
question, webfetch, websearch, doom_loop\`) only accept a flat
|
|
821
|
+
action, not a per-pattern object.
|
|
822
|
+
|
|
823
|
+
\`external_directory\` patterns are filesystem paths (use \`~/\`, absolute paths,
|
|
824
|
+
or globs like \`~/projects/**\`).
|
|
825
|
+
|
|
826
|
+
Per-agent \`permission:\` overrides top-level \`permission:\`. Plan Mode lives on
|
|
827
|
+
the \`plan\` agent's permission ruleset (\`edit: deny *\`).
|
|
828
|
+
|
|
829
|
+
## Escape hatches
|
|
830
|
+
|
|
831
|
+
When a user's config is broken and opencode won't start, these env vars help:
|
|
832
|
+
|
|
833
|
+
- \`OPENCODE_DISABLE_PROJECT_CONFIG=1\`: skip the project's local \`opencode.json\`
|
|
834
|
+
and start from globals only. Run from the project directory, opencode loads,
|
|
835
|
+
the user edits the broken file, then they restart without the flag.
|
|
836
|
+
- \`OPENCODE_CONFIG=/path/to/file.json\`: load an additional explicit config.
|
|
837
|
+
- \`OPENCODE_CONFIG_CONTENT='{"$schema":"https://opencode.ai/config.json"}'\`:
|
|
838
|
+
inject inline JSON as a final local-scope merge.
|
|
839
|
+
- \`OPENCODE_DISABLE_DEFAULT_PLUGINS=1\`: skip default plugins.
|
|
840
|
+
- \`OPENCODE_PURE=1\`: skip external plugins entirely.
|
|
841
|
+
- \`OPENCODE_DISABLE_EXTERNAL_SKILLS=1\`,
|
|
842
|
+
\`OPENCODE_DISABLE_CLAUDE_CODE_SKILLS=1\`: skip the external skill scans under
|
|
843
|
+
\`~/.claude/\` and \`~/.agents/\`.
|
|
844
|
+
|
|
845
|
+
## When proposing edits
|
|
846
|
+
|
|
847
|
+
- Validate against the schema before writing. If you are unsure of a field's
|
|
848
|
+
exact shape, or the field is not covered in this skill, fetch
|
|
849
|
+
\`https://opencode.ai/config.json\` and read the schema rather than guessing.
|
|
850
|
+
- Preserve \`$schema\` and any existing fields the user did not ask to change.
|
|
851
|
+
- For agent, command, skill, and plugin definitions, prefer creating new files
|
|
852
|
+
in the correct location over inlining everything in \`opencode.json\`.
|
|
853
|
+
- If the user's existing config is malformed, point them at the env-var escape
|
|
854
|
+
hatches above so they can edit from inside opencode without breaking their
|
|
855
|
+
session.
|
|
856
|
+
- After saving any config change, remind the user to quit and restart opencode
|
|
857
|
+
\u2014 running sessions keep using the already-loaded config.
|
|
858
|
+
`;var Xa=Za,Up={id:"skill",effect:Lp.fn(function*(t){yield*t.skill.transform(e=>{e.source(ae.EmbeddedSource.make({type:"embedded",skill:ae.Info.make({name:"customize-opencode",description:"Use ONLY when the user is editing or creating opencode's own configuration: opencode.json, opencode.jsonc, files under .opencode/, or files under ~/.config/opencode/. Also use when creating or fixing opencode agents, subagents, commands, skills, plugins, MCP servers, or permission rules. Do not use for the user's own application code, or for any project that is not configuring opencode itself.",location:ne.make("/builtin/customize-opencode.md"),content:Xa})}))})})};function Qa(t){return t.replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'")}r(Qa,"escapeHtml");var jp=".claude",qp=".agents",ec="skills/**/SKILL.md",$p="{skill,skills}/**/SKILL.md",tc="**/SKILL.md",nc="customize-opencode",Fp="Use ONLY when the user is editing or creating opencode's own configuration: opencode.json, opencode.jsonc, files under .opencode/, or files under ~/.config/opencode/. Also use when creating or fixing opencode agents, subagents, skills, plugins, MCP servers, or permission rules. Do not use for the user's own application code, or for any project that is not configuring opencode itself.",Hp=Rt.CustomizeOpencodeContent,Gp=X.Struct({name:X.String,description:X.optional(X.String),location:X.String,content:X.String}),Bp=X.StructWithRest(X.Struct({message:X.String,path:X.Array(X.String)}),[X.Record(X.String,X.Unknown)]);function Kp(t){return qi(t)&&typeof t.name=="string"&&(t.description===void 0||typeof t.description=="string")}r(Kp,"isSkillFrontmatter");var ni=class extends X.TaggedErrorClass()("SkillInvalidError",{path:X.String,message:X.optional(X.String),issues:X.optional(X.Array(Bp))}){static{r(this,"InvalidError")}},oi=class extends X.TaggedErrorClass()("SkillNameMismatchError",{path:X.String,expected:X.String,actual:X.String}){static{r(this,"NameMismatchError")}},Ho=class extends X.TaggedErrorClass()("Skill.NotFoundError",{name:X.String,available:X.Array(X.String)}){static{r(this,"NotFoundError")}get message(){return`Skill "${this.name}" not found. Available skills: ${this.available.join(", ")||"none"}`}},zp=Z.fnUntraced(function*(t,e,n){let o=yield*Z.tryPromise({try:r(()=>Fi.parse(e),"try"),catch:r(i=>i,"catch")}).pipe(Z.catch(Z.fnUntraced(function*(i){let s=$i.isInstance(i)?i.data.message:`Failed to parse skill ${e}`,{Session:d}=yield*Z.promise(()=>import("./session-6RNXZNG6.js"));yield*n.publish(d.Event.Error,{error:new Eo.Unknown({message:s}).toObject()}),yield*Z.logError("failed to load skill",{skill:e,error:i})})));o&&Kp(o.data)&&(t.skills[o.data.name]&&(yield*Z.logWarning("duplicate skill name",{name:o.data.name,existing:t.skills[o.data.name].location,duplicate:e})),t.dirs.add(hn.dirname(e)),t.skills[o.data.name]={name:o.data.name,description:o.data.description,location:e,content:o.content})}),uo=Z.fnUntraced(function*(t,e,n,o){let i=yield*Z.tryPromise({try:r(()=>Ci.scan(n,{cwd:e,absolute:!0,include:"file",symlink:!0,dot:o?.dot}),"try"),catch:r(s=>s,"catch")}).pipe(Z.catch(s=>o?.scope?Z.logError(`failed to scan ${o.scope} skills`,{dir:e,error:s}).pipe(Z.as([])):Z.die(s)));for(let s of i)t.matches.add(s),t.dirs.add(hn.dirname(s))}),Wp=Z.fnUntraced(function*(t,e,n,o,i,s,d,c){let a={matches:new Set,dirs:new Set},l=[];if(!i){s||l.push(jp),l.push(qp);for(let y of l){let g=hn.join(o.home,y);(yield*n.isDir(g))&&(yield*uo(a,g,ec,{dot:!0,scope:"global"}))}let m=yield*n.up({targets:l,start:d,stop:c}).pipe(Z.catch(()=>Z.succeed([])));for(let y of m)yield*uo(a,y,ec,{dot:!0,scope:"project"})}let f=yield*t.directories();for(let m of f)yield*uo(a,m,$p);let p=yield*t.get();for(let m of p.skills?.paths??[]){let y=m.startsWith("~/")?hn.join(o.home,m.slice(2)):m,g=hn.isAbsolute(y)?y:hn.join(d,y);if(!(yield*n.isDir(g))){yield*Z.logWarning("skill path not found",{path:g});continue}yield*uo(a,g,tc)}for(let m of p.skills?.urls??[]){let y=yield*e.pull(m);for(let g of y)yield*uo(a,g,tc)}return{matches:Array.from(a.matches),dirs:Array.from(a.dirs)}}),Jp=Z.fnUntraced(function*(t,e,n){yield*Z.forEach(e.matches,o=>zp(t,o,n),{concurrency:"unbounded",discard:!0}),yield*Z.logInfo("init",{count:Object.keys(t.skills).length})}),yn=class extends Np.Service()("@opencode/Skill"){static{r(this,"Service")}},Yp=Vp.effect(yn,Z.gen(function*(){let t=yield*Ht.Service,e=yield*jt.Service,n=yield*Ze.Service,o=yield*G.Service,i=yield*H.Service,s=yield*er.Service,d=yield*j.make(Z.fn("Skill.discovery")(function*(y){return yield*Wp(e,t,o,i,s.disableExternalSkills,s.disableClaudeCodeSkills,y.directory,y.worktree)})),c=yield*j.make(Z.fn("Skill.state")(function*(){let y={skills:{},dirs:new Set};return y.skills[nc]={name:nc,description:Fp,location:"<built-in>",content:Hp},yield*Jp(y,yield*j.get(d),n),y})),a=Z.fn("Skill.get")(function*(y){return(yield*j.get(c)).skills[y]}),l=Z.fn("Skill.require")(function*(y){let g=yield*j.get(c),b=g.skills[y];return b||(yield*new Ho({name:y,available:Object.keys(g.skills).toSorted()}))}),f=Z.fn("Skill.all")(function*(){let y=yield*j.get(c);return Object.values(y.skills)}),p=Z.fn("Skill.dirs")(function*(){return(yield*j.get(d)).dirs}),m=Z.fn("Skill.available")(function*(y){let g=yield*j.get(c),b=Object.values(g.skills).toSorted((P,C)=>P.name.localeCompare(C.name));return y?b.filter(P=>On.evaluate("skill",P.name,y.permission).action!=="deny"):b});return yn.of({get:a,require:l,all:f,dirs:p,available:m})}));function Zp(t,e){let n=t.filter(o=>o.description!==void 0);return n.length===0?"No skills are currently available.":e.verbose?["<available_skills>",...n.toSorted((o,i)=>o.name.localeCompare(i.name)).flatMap(o=>[" <skill>",` <name>${o.name}</name>`,` <description>${o.description}</description>`,` <location>${Qa(o.location)}</location>`," </skill>"]),"</available_skills>"].join(`
|
|
859
|
+
`):["## Available Skills",...n.toSorted((o,i)=>o.name.localeCompare(i.name)).map(o=>`- **${o.name}**: ${o.description}`)].join(`
|
|
860
|
+
`)}r(Zp,"fmt");var Xp=Ae.make({service:yn,layer:Yp,deps:[Ht.node,jt.node,Ze.node,G.node,H.node,er.node]});var vn={};T(vn,{ClientInfo:()=>ic,Entry:()=>sc,McpAuth:()=>vn,Service:()=>At,Tokens:()=>rc,node:()=>su,use:()=>ru});import Qp from"path";import{Effect as fe,Layer as eu,Context as tu,Option as nu,Schema as L}from"effect";var rc=L.Struct({accessToken:L.mutableKey(L.String),refreshToken:L.mutableKey(L.optional(L.String)),expiresAt:L.mutableKey(L.optional(L.Number)),scope:L.mutableKey(L.optional(L.String))}),ic=L.Struct({clientId:L.mutableKey(L.String),clientSecret:L.mutableKey(L.optional(L.String)),clientIdIssuedAt:L.mutableKey(L.optional(L.Number)),clientSecretExpiresAt:L.mutableKey(L.optional(L.Number))}),sc=L.Struct({tokens:L.mutableKey(L.optional(rc)),clientInfo:L.mutableKey(L.optional(ic)),codeVerifier:L.mutableKey(L.optional(L.String)),oauthState:L.mutableKey(L.optional(L.String)),serverUrl:L.mutableKey(L.optional(L.String))}),ou=L.decodeUnknownOption(L.Record(L.String,sc)),ii=Qp.join(H.Path.globalData,"mcp-auth.json"),oc=`mcp-auth:${ii}`,At=class extends tu.Service()("@opencode/McpAuth"){static{r(this,"Service")}},ru=ko(At),iu=eu.effect(At,fe.gen(function*(){let t=yield*G.Service,e=yield*Vt.Service,n=fe.fn("McpAuth.read")(function*(){return yield*t.readJson(ii).pipe(fe.map(A=>nu.getOrElse(ou(A),()=>({}))),fe.catch(()=>fe.succeed({})))}),o=fe.fn("McpAuth.all")(function*(){return yield*n().pipe(e.withLock(oc),fe.orDie)}),i=fe.fn("McpAuth.mutate")(function*(A){yield*fe.gen(function*(){let S=A(yield*n());S&&(yield*t.writeJson(ii,S,384).pipe(fe.orDie))}).pipe(e.withLock(oc),fe.orDie)}),s=fe.fn("McpAuth.get")(function*(A){return(yield*o())[A]}),d=fe.fn("McpAuth.getForUrl")(function*(A,S){let w=yield*s(A);if(w&&w.serverUrl&&w.serverUrl===S)return w}),c=fe.fn("McpAuth.set")(function*(A,S,w){yield*i(q=>({...q,[A]:w?{...S,serverUrl:w}:S}))}),a=fe.fn("McpAuth.remove")(function*(A){yield*i(S=>{let w={...S};return delete w[A],w})}),l=r((A,S)=>fe.fn(`McpAuth.${S}`)(function*(w,q,B){yield*i(K=>{let Ue=K[w]??{};return Ue[A]=q,B&&(Ue.serverUrl=B),{...K,[w]:Ue}})}),"updateField"),f=r((A,S)=>fe.fn(`McpAuth.${S}`)(function*(w){yield*i(q=>{let B=q[w];if(B)return delete B[A],{...q,[w]:B}})}),"clearField"),p=l("tokens","updateTokens"),m=l("clientInfo","updateClientInfo"),y=l("codeVerifier","updateCodeVerifier"),g=l("oauthState","updateOAuthState"),b=f("codeVerifier","clearCodeVerifier"),P=f("oauthState","clearOAuthState"),C=fe.fn("McpAuth.getOAuthState")(function*(A){return(yield*s(A))?.oauthState});return At.of({all:o,get:s,getForUrl:d,set:c,remove:a,updateTokens:p,updateClientInfo:m,updateCodeVerifier:y,clearCodeVerifier:b,updateOAuthState:g,getOAuthState:C,clearOAuthState:P})})),su=Ae.make({service:At,layer:iu,deps:[G.node,Vt.node]});var Re={};T(Re,{McpCatalog:()=>Re,callMeta:()=>dc,convertTool:()=>gu,defs:()=>mu,fetch:()=>hu,paginate:()=>go,prompts:()=>vu,resourceTemplates:()=>Su,resources:()=>ku,sanitize:()=>mo,toolName:()=>yu});import"@modelcontextprotocol/sdk/client/index.js";import{CallToolResultSchema as au,ListToolsResultSchema as cu,ToolSchema as du}from"@modelcontextprotocol/sdk/types.js";import{dynamicTool as lu,jsonSchema as fu}from"ai";import{Effect as pt}from"effect";var ac="alchemylab/fieldTags";function Xx(t,e,n,o){if(!n)return{description:t,schema:e};let i=new Set(o),s=structuredClone(e),d=s.properties?.operation?.enum,c=d?.filter(p=>i.has(p))??[],a=!!d&&c.length>0;a&&(s.properties.operation.enum=c);for(let[p,m]of Object.entries(n)){if(m.some(P=>i.has(P)))continue;let y=p.split("."),g=s;for(let P of y.slice(0,-1))g=g?.properties?.[P],g?.type==="array"&&(g=g.items);let b=y[y.length-1];!g?.properties||!(b in g.properties)||(delete g.properties[b],Array.isArray(g.required)&&(g.required=g.required.filter(P=>P!==b)))}let l=new Set(a?d.filter(p=>!i.has(p)):[]);return{description:t.split(`
|
|
861
|
+
`).filter(p=>{let m=/^\s*(?:•|•)\s+(.+?)\s+-\s/.exec(p);return m?!m[1].split("/").map(g=>g.trim()).every(g=>l.has(g)):!0}).join(`
|
|
862
|
+
`),schema:s}}r(Xx,"scopeTool");var pu=3e4,cc=1e3,uu=cu.extend({tools:du.omit({outputSchema:!0}).array()});async function go(t,e){let n=[],o=new Set,i;for(let s=0;s<cc;s++){let d=await t(i);if(n.push(...e(d)),d.nextCursor===void 0)return n;if(o.has(d.nextCursor))throw new Error(`MCP list returned duplicate cursor: ${d.nextCursor}`);o.add(d.nextCursor),i=d.nextCursor}throw new Error(`MCP list exceeded ${cc} pages`)}r(go,"paginate");function mu(t,e){return Eu(t,e??pu).pipe(pt.catch(()=>pt.void))}r(mu,"defs");function dc(t){let e=t?.callContext,n={};return e?.sessionId&&(n.sessionId=e.sessionId),e?.messageId&&(n.messageId=e.messageId),Object.keys(n).length>0?n:void 0}r(dc,"callMeta");function gu(t,e,n){let o={...t.inputSchema,type:"object",properties:t.inputSchema.properties??{},additionalProperties:!1},i=lu({description:t.description??"",inputSchema:fu(o),execute:r(async(d,c)=>{let a={};for(let[m,y]of Object.entries(d||{}))y!==null&&(a[m]=y);let l=await e.callTool({name:t.name,arguments:a,_meta:dc(c)},au,{resetTimeoutOnProgress:!0,signal:c.abortSignal,timeout:n,onprogress:r(()=>{},"onprogress")});if(l.isError)throw new Error(l.content.flatMap(m=>m.type==="text"?[m.text]:[]).filter(m=>m.trim()).join(`
|
|
863
|
+
|
|
864
|
+
`)||"MCP tool returned an error");let f=l._meta?.alchemy,p=l.content.length>0||l.structuredContent===void 0||l.structuredContent===null?l:{...l,content:[{type:"text",text:JSON.stringify(l.structuredContent)}]};return f?{...p,metadata:f}:p},"execute")}),s=t._meta?.[ac];return s&&typeof s=="object"&&Object.assign(i,{fieldTags:s,jsonInputSchema:o}),i}r(gu,"convertTool");function hu(t,e,n,o,i){return pt.tryPromise({try:r(()=>n(e),"try"),catch:r(s=>s,"catch")}).pipe(pt.tapError(s=>pt.logWarning(`failed to get ${o}`,{clientName:t,error:s instanceof Error?s.message:String(s)})),pt.map(s=>{let d=mo(t),c=t.replaceAll("%","%25").replaceAll(":","%3A");return Object.fromEntries(s.map(a=>[i?c+":"+i(a):d+":"+mo(a.name),{...a,client:t}]))}),pt.orElseSucceed(()=>{}))}r(hu,"fetch");var mo=r(t=>t.replace(/[^a-zA-Z0-9_-]/g,"_"),"sanitize"),yu=r((t,e)=>mo(t)+"_"+mo(e),"toolName");function vu(t,e){return t.getServerCapabilities()?.prompts?go(n=>t.listPrompts(n===void 0?void 0:{cursor:n},{timeout:e}),n=>n.prompts):Promise.resolve([])}r(vu,"prompts");function ku(t,e){return t.getServerCapabilities()?.resources?go(n=>t.listResources(n===void 0?void 0:{cursor:n},{timeout:e}),n=>n.resources):Promise.resolve([])}r(ku,"resources");function Su(t,e){return t.getServerCapabilities()?.resources?go(n=>t.listResourceTemplates(n===void 0?void 0:{cursor:n},{timeout:e}),n=>n.resourceTemplates):Promise.resolve([])}r(Su,"resourceTemplates");function Eu(t,e){return pt.tryPromise({try:r(()=>go(async n=>{let o=n===void 0?void 0:{cursor:n};try{return await t.listTools(o,{timeout:e})}catch(i){if(!(i instanceof Error)||!bu(i))throw i;return t.request({method:"tools/list",params:o},uu,{timeout:e})}},n=>n.tools),"try"),catch:r(n=>n instanceof Error?n:new Error(String(n)),"catch")})}r(Eu,"listTools");function bu(t){return/can't resolve reference|resolves to more than one schema|outputSchema|schema.*reference|reference.*schema/i.test(t.message)}r(bu,"isOutputSchemaValidationError");var li={};T(li,{BrowserOpenFailed:()=>_c,Failed:()=>am,MCP:()=>li,NotFoundError:()=>zo,Resource:()=>im,Service:()=>_t,Status:()=>um,ToolManifestEntry:()=>sm,ToolsChanged:()=>di,node:()=>hm,use:()=>mm});import Ku from"node:path";import{pathToFileURL as zu}from"node:url";import{Client as Wu}from"@modelcontextprotocol/sdk/client/index.js";import{StreamableHTTPClientTransport as Ic}from"@modelcontextprotocol/sdk/client/streamableHttp.js";import{SSEClientTransport as Ju}from"@modelcontextprotocol/sdk/client/sse.js";import{StdioClientTransport as wc}from"@modelcontextprotocol/sdk/client/stdio.js";import{UnauthorizedError as Cc}from"@modelcontextprotocol/sdk/client/auth.js";import{ListRootsRequestSchema as Yu,LoggingMessageNotificationSchema as Zu,ToolListChangedNotificationSchema as Xu}from"@modelcontextprotocol/sdk/types.js";function lc(t,e,n){let o;return Promise.race([t.finally(()=>{clearTimeout(o)}),new Promise((i,s)=>{o=setTimeout(()=>{s(new Error(n??`Operation timed out after ${e}ms`))},e)})])}r(lc,"withTimeout");import{Effect as Ie}from"effect";var kn=19876,ut="/mcp/oauth/callback",ho=class{constructor(e,n,o,i,s){this.mcpName=e;this.serverUrl=n;this.config=o;this.callbacks=i;this.auth=s}mcpName;serverUrl;config;callbacks;auth;static{r(this,"McpOAuthProvider")}get redirectUrl(){return this.config.redirectUri?this.config.redirectUri:`http://127.0.0.1:${this.config.callbackPort??kn}${ut}`}get clientMetadata(){return{redirect_uris:[this.redirectUrl],client_name:"OpenCode",client_uri:"https://opencode.ai",grant_types:["authorization_code","refresh_token"],response_types:["code"],token_endpoint_auth_method:this.config.clientSecret?"client_secret_post":"none",...this.config.scope?{scope:this.config.scope}:{}}}async clientInformation(){if(this.config.clientId)return{client_id:this.config.clientId,client_secret:this.config.clientSecret};let e=await Ie.runPromise(this.auth.getForUrl(this.mcpName,this.serverUrl));if(e?.clientInfo)return e.clientInfo.clientSecretExpiresAt&&e.clientInfo.clientSecretExpiresAt<Date.now()/1e3?void 0:{client_id:e.clientInfo.clientId,client_secret:e.clientInfo.clientSecret}}async saveClientInformation(e){await Ie.runPromise(this.auth.updateClientInfo(this.mcpName,{clientId:e.client_id,clientSecret:e.client_secret,clientIdIssuedAt:e.client_id_issued_at,clientSecretExpiresAt:e.client_secret_expires_at},this.serverUrl))}async tokens(){let e=await Ie.runPromise(this.auth.getForUrl(this.mcpName,this.serverUrl));if(e?.tokens)return{access_token:e.tokens.accessToken,token_type:"Bearer",refresh_token:e.tokens.refreshToken,expires_in:e.tokens.expiresAt?Math.max(0,Math.floor(e.tokens.expiresAt-Date.now()/1e3)):void 0,scope:e.tokens.scope}}async saveTokens(e){await Ie.runPromise(this.auth.updateTokens(this.mcpName,{accessToken:e.access_token,refreshToken:e.refresh_token,expiresAt:e.expires_in?Date.now()/1e3+e.expires_in:void 0,scope:e.scope},this.serverUrl))}async redirectToAuthorization(e){if(e.protocol!=="http:"&&e.protocol!=="https:")throw new Error(`MCP server "${this.serverUrl}" returned a ${e.protocol} authorization URL; only http and https are supported`);await this.callbacks.onRedirect(e)}async saveCodeVerifier(e){await Ie.runPromise(this.auth.updateCodeVerifier(this.mcpName,e))}async codeVerifier(){let e=await Ie.runPromise(this.auth.get(this.mcpName));if(!e?.codeVerifier)throw new Error(`No code verifier saved for MCP server: ${this.mcpName}`);return e.codeVerifier}async saveState(e){await Ie.runPromise(this.auth.updateOAuthState(this.mcpName,e))}async state(){let e=await Ie.runPromise(this.auth.get(this.mcpName));if(e?.oauthState)return e.oauthState;let n=Array.from(crypto.getRandomValues(new Uint8Array(32))).map(o=>o.toString(16).padStart(2,"0")).join("");return await Ie.runPromise(this.auth.updateOAuthState(this.mcpName,n)),n}async invalidateCredentials(e){let n=await Ie.runPromise(this.auth.get(this.mcpName));if(n)switch(e){case"all":await Ie.runPromise(this.auth.remove(this.mcpName));break;case"client":delete n.clientInfo,await Ie.runPromise(this.auth.set(this.mcpName,n));break;case"tokens":delete n.tokens,await Ie.runPromise(this.auth.set(this.mcpName,n));break}}},Go=class extends ho{static{r(this,"McpOAuthPendingProvider")}pendingClientInfo;pendingTokens;async clientInformation(){return this.config.clientId?{client_id:this.config.clientId,client_secret:this.config.clientSecret}:this.pendingClientInfo}async saveClientInformation(e){this.pendingClientInfo=e}async tokens(){return this.pendingTokens}async saveTokens(e){this.pendingTokens=e}async invalidateCredentials(e){(e==="all"||e==="client")&&(this.pendingClientInfo=void 0),(e==="all"||e==="tokens")&&(this.pendingTokens=void 0)}async commit(){this.pendingTokens&&await Ie.runPromise(this.auth.set(this.mcpName,{tokens:{accessToken:this.pendingTokens.access_token,refreshToken:this.pendingTokens.refresh_token,expiresAt:this.pendingTokens.expires_in?Date.now()/1e3+this.pendingTokens.expires_in:void 0,scope:this.pendingTokens.scope},clientInfo:this.pendingClientInfo&&!this.config.clientId?{clientId:this.pendingClientInfo.client_id,clientSecret:this.pendingClientInfo.client_secret,clientIdIssuedAt:this.pendingClientInfo.client_id_issued_at,clientSecretExpiresAt:this.pendingClientInfo.client_secret_expires_at}:void 0},this.serverUrl))}};function fc(t){if(!t)return{port:kn,path:ut};try{let e=new URL(t),n=e.port?parseInt(e.port,10):e.protocol==="https:"?443:80,o=e.pathname||ut;return{port:n,path:o}}catch{return{port:kn,path:ut}}}r(fc,"parseRedirectUri");var Tt={};T(Tt,{McpOAuthCallback:()=>Tt,cancelPending:()=>Du,ensureRunning:()=>Ru,isPortInUse:()=>uc,isRunning:()=>Tu,stop:()=>mc,waitForCallback:()=>Au});import{createConnection as xu}from"net";import{createServer as Iu}from"http";var wu="127.0.0.1",Bo=kn,si=ut,Le,we=new Map,Dt=new Map,Cu=300*1e3;function pc(t){for(let[e,n]of Dt)if(n===t){Dt.delete(e);break}}r(pc,"cleanupStateIndex");function Ko(){we.size>0||!Le||(Le.close(),Le=void 0)}r(Ko,"stopIfIdle");function Pu(t,e){let n=new URL(t.url||"/",`http://localhost:${Bo}`);if(n.pathname!==si){e.writeHead(404),e.end("Not found");return}let o=n.searchParams.get("code"),i=n.searchParams.get("state"),s=n.searchParams.get("error"),d=n.searchParams.get("error_description");if(!i){let a="Missing required state parameter - potential CSRF attack";e.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),e.end(Pe.error(a,{provider:"MCP"}));return}if(s){let a=d||s;if(we.has(i)){let l=we.get(i);clearTimeout(l.timeout),we.delete(i),pc(i),l.reject(new Error(a))}e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Pe.error(a,{provider:"MCP"})),Ko();return}if(!o){e.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),e.end(Pe.error("No authorization code provided",{provider:"MCP"}));return}if(!we.has(i)){let a="Invalid or expired state parameter - potential CSRF attack";e.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),e.end(Pe.error(a,{provider:"MCP"}));return}let c=we.get(i);clearTimeout(c.timeout),we.delete(i),pc(i),c.resolve(o),e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(Pe.success({provider:"MCP"})),Ko()}r(Pu,"handleRequest");async function Ru(t){let{port:e,path:n}=fc(t);Le&&(Bo!==e||si!==n)&&await mc(),!(Le||await uc(e))&&(Bo=e,si=n,Le=Iu(Pu),await new Promise((i,s)=>{Le.listen(Bo,wu,()=>{i()}),Le.on("error",s)}))}r(Ru,"ensureRunning");function Au(t,e){return e&&Dt.set(e,t),new Promise((n,o)=>{let i=setTimeout(()=>{we.has(t)&&(we.delete(t),e&&Dt.delete(e),o(new Error("OAuth callback timeout - authorization took too long")),Ko())},Cu);we.set(t,{resolve:n,reject:o,timeout:i})})}r(Au,"waitForCallback");function Du(t){let n=Dt.get(t)??t,o=we.get(n);o&&(clearTimeout(o.timeout),we.delete(n),Dt.delete(t),o.reject(new Error("Authorization cancelled")),Ko())}r(Du,"cancelPending");async function uc(t=kn){return new Promise(e=>{let n=xu(t,"127.0.0.1");n.on("connect",()=>{n.destroy(),e(!0)}),n.on("error",()=>{e(!1)})})}r(uc,"isPortInUse");async function mc(){Le&&(await new Promise(t=>Le.close(()=>t())),Le=void 0);for(let[t,e]of we)clearTimeout(e.timeout),e.reject(new Error("OAuth callback server stopped"));we.clear(),Dt.clear()}r(mc,"stop");function Tu(){return Le!==void 0}r(Tu,"isRunning");var Ot={};T(Ot,{CommandExecute:()=>hc,Definitions:()=>Mu,PromptAppend:()=>gc,SessionSelect:()=>vc,ToastShow:()=>yc,TuiEvent:()=>Ot});import{Effect as Ou,Schema as mt}from"effect";var _u=5e3,gc=qe.define({type:"tui.prompt.append",schema:{text:mt.String}}),hc=qe.define({type:"tui.command.execute",schema:{command:mt.Union([mt.Literals(["session.list","session.new","session.share","session.interrupt","session.compact","session.page.up","session.page.down","session.line.up","session.line.down","session.half.page.up","session.half.page.down","session.first","session.last","prompt.clear","prompt.submit","agent.cycle"]),mt.String])}}),yc=qe.define({type:"tui.toast.show",schema:{title:le(mt.String),message:mt.String,variant:mt.Literals(["info","success","warning","error"]),duration:gi.pipe(mt.withDecodingDefault(Ou.succeed(_u))).annotate({description:"Duration in milliseconds"})}}),vc=qe.define({type:"tui.session.select",schema:{sessionID:Si.annotate({description:"Session ID to navigate to"})}}),Mu=qe.inventory(gc,hc,yc,vc);import{Cause as Pc,Effect as v,Exit as Qu,Layer as em,Context as tm,Schema as z,Stream as Rc}from"effect";var En={};T(En,{EffectBridge:()=>En,bind:()=>Vu,fromPromise:()=>Nu,make:()=>ju});import{Context as kc,Effect as ke,Exit as Lu,Fiber as Uu}from"effect";function Sn(t,e){return t!==void 0?An.restore(t,e):e()}r(Sn,"restoreWorkspace");function Sc(){let t=Uu.getCurrent(),e=t?kc.getReferenceUnsafe(t.context,yt):void 0,n=(t?kc.getReferenceUnsafe(t.context,it):void 0)??An.workspaceID;return{instance:e,workspace:n}}r(Sc,"captureSync");var Vu=r(t=>{let e=Sc();return(...n)=>Sn(e.workspace,()=>ke.runSync(xo(ke.sync(()=>t(...n)),e)))},"bind"),Nu=r(t=>ke.gen(function*(){let e=yield*it;return yield*ke.promise(()=>Promise.resolve(Sn(e,()=>t())))}),"fromPromise");function ju(){return ke.gen(function*(){let t=yield*ke.context(),e=Sc(),n=(yield*yt)??e.instance,o=(yield*it)??e.workspace,i=r(s=>xo(s.pipe(ke.provide(t)),{instance:n,workspace:o}),"wrap");return{promise:r(s=>Sn(o,()=>ke.runPromise(i(s))),"promise"),fork:r(s=>Sn(o,()=>ke.runFork(i(s))),"fork"),run:r(s=>ke.callback(d=>{Sn(o,()=>ke.runPromiseExit(i(s)).then(c=>d(Lu.isSuccess(c)?ke.succeed(c.value):ke.failCause(c.cause))))}),"run"),bind:r(s=>(...d)=>Sn(o,()=>ke.runSync(i(ke.sync(()=>s(...d))))),"bind")}})}r(ju,"make");import{ChildProcess as nm,ChildProcessSpawner as om}from"effect/unstable/process";var bn={};T(bn,{BrowserOpenFailed:()=>bc,Definitions:()=>qu,McpEvent:()=>bn,ToolsChanged:()=>Ec});import{Schema as ai}from"effect";var Ec=qe.define({type:"mcp.tools.changed",schema:{server:ai.String}}),bc=qe.define({type:"mcp.browser.open.failed",schema:{mcpName:ai.String,url:ai.String}}),qu=qe.inventory(Ec,bc);var wn={};T(wn,{McpBrowser:()=>wn,Service:()=>In,node:()=>Bu});import $u from"open";function xc(t){let e=URL.canParse(t)?new URL(t):void 0;return!e||e.protocol!=="http:"&&e.protocol!=="https:"?Promise.reject(new Error(`Only http and https links can be opened in the browser: ${t}`)):$u(e.href)}r(xc,"openUrl");import{Context as Fu,Effect as xn,Layer as Hu}from"effect";var In=class extends Fu.Service()("@opencode/McpBrowser"){static{r(this,"Service")}},Gu=Hu.succeed(In,In.of({open:xn.fn("McpBrowser.open")(function*(t){let e=yield*xn.tryPromise({try:r(()=>xc(t),"try"),catch:r(n=>n instanceof Error?n:new Error(String(n)),"catch")});yield*xn.callback(n=>{let o=setTimeout(()=>n(xn.void),500);e.on("error",s=>{clearTimeout(o),n(xn.fail(s))});let i=r(s=>{s===null||s===0||(clearTimeout(o),n(xn.fail(new Error(`Browser open failed with exit code ${s}`))))},"onExit");e.on("exit",i),i(e.exitCode)})})})),Bu=Ae.make({service:In,layer:Gu,deps:[]});var Ac=3e4,rm={capabilities:{roots:{}}},im=z.Struct({name:z.String,uri:z.String,description:z.optional(z.String),mimeType:z.optional(z.String),client:z.String}).annotate({identifier:"McpResource"}),sm=z.Struct({name:z.String,description:z.optional(z.String),readOnly:z.optional(z.Boolean)}).annotate({identifier:"MCPToolManifestEntry"}),di=bn.ToolsChanged,_c=bn.BrowserOpenFailed,am=Eo.create("MCPFailed",{name:z.String}),zo=class extends z.TaggedErrorClass()("MCP.NotFoundError",{name:z.String}){static{r(this,"NotFoundError")}};function Dc(t){let e=new Wu({name:"opencode",version:Te},rm);return e.setRequestHandler(Yu,()=>Promise.resolve({roots:[{uri:zu(t).href}]})),e}r(Dc,"createClient");var cm=z.Struct({status:z.Literal("connected")}).annotate({identifier:"MCPStatusConnected"}),dm=z.Struct({status:z.Literal("disabled")}).annotate({identifier:"MCPStatusDisabled"}),lm=z.Struct({status:z.Literal("failed"),error:z.String}).annotate({identifier:"MCPStatusFailed"}),fm=z.Struct({status:z.Literal("needs_auth")}).annotate({identifier:"MCPStatusNeedsAuth"}),pm=z.Struct({status:z.Literal("needs_client_registration"),error:z.String}).annotate({identifier:"MCPStatusNeedsClientRegistration"}),um=z.Union([cm,dm,lm,fm,pm]).annotate({identifier:"MCPStatus",discriminator:"status"}),Cn=new Map;function yo(t){return typeof t=="object"&&t!==null&&"type"in t}r(yo,"isMcpConfigured");function Tc(t){if(URL.canParse(t))return new URL(t)}r(Tc,"remoteURL");var _t=class extends tm.Service()("@opencode/MCP"){static{r(this,"Service")}},Oc=new Map;function ci(t){let e=Oc.get(t);return e||(e=new Map,Oc.set(t,e)),e}r(ci,"runtimeFor");var mm=ko(_t),gm=em.effect(_t,v.gen(function*(){let t=yield*om.ChildProcessSpawner,e=yield*vn.Service,n=yield*Ze.Service,o=yield*wn.Service,i=v.fn("MCP.connectTransport")(function*(u,h){let E=yield*j.directory;return yield*v.acquireUseRelease(v.succeed(u),x=>v.tryPromise({try:r(()=>{let I=Dc(E);return lc(I.connect(x),h).then(()=>I)},"try"),catch:r(I=>I instanceof Error?I:new Error(String(I)),"catch")}),(x,I)=>Qu.isFailure(I)?v.tryPromise(()=>x.close()).pipe(v.ignore):v.void)}),s={status:{status:"disabled"}},d=v.fn("MCP.connectRemote")(function*(u,h){let E=h.oauth===!1,x=typeof h.oauth=="object"?h.oauth:void 0,I=Tc(h.url);if(!I)return{client:void 0,status:{status:"failed",error:`Invalid MCP URL for "${u}"`}};let R;E||(R=new ho(u,h.url,{clientId:x?.clientId,clientSecret:x?.clientSecret,scope:x?.scope,callbackPort:x?.callbackPort,redirectUri:x?.redirectUri},{onRedirect:r(async()=>{},"onRedirect")},e));let D=[{name:"StreamableHTTP",transport:new Ic(I,{authProvider:R,requestInit:h.headers?{headers:h.headers}:void 0})},{name:"SSE",transport:new Ju(I,{authProvider:R,requestInit:h.headers?{headers:h.headers}:void 0})}],$=h.timeout??Ac,O;for(let{name:Ve,transport:ce}of D){let mi=yield*i(ce,$).pipe(v.map(Mt=>({client:Mt,transportName:Ve})),v.catch(Mt=>{let vo=Mt instanceof Error?Mt:new Error(String(Mt));return Mt instanceof Cc||R&&vo.message.includes("OAuth")?vo.message.includes("registration")||vo.message.includes("client_id")?(O={status:"needs_client_registration",error:"Server does not support dynamic client registration. Please provide clientId in config."},n.publish(Ot.ToastShow,{title:"MCP Authentication Required",message:`Server "${u}" requires a pre-registered client ID. Add clientId to your config.`,variant:"warning",duration:8e3}).pipe(v.ignore,v.as(void 0))):(Cn.set(u,{transport:ce}),O={status:"needs_auth"},n.publish(Ot.ToastShow,{title:"MCP Authentication Required",message:`Server "${u}" requires authentication. Run: opencode mcp auth ${u}`,variant:"warning",duration:8e3}).pipe(v.ignore,v.as(void 0))):(O={status:"failed",error:vo.message},v.void)}));if(mi)return{client:mi.client,status:{status:"connected"}};if(O?.status==="needs_auth"||O?.status==="needs_client_registration")break}return{client:void 0,status:O??{status:"failed",error:"Unknown error"}}}),c=v.fn("MCP.connectLocal")(function*(u,h){let[E,...x]=h.command,I=yield*j.directory,R=h.cwd?Ku.resolve(I,h.cwd):I,D=new wc({stderr:"pipe",command:E,args:x,cwd:R,env:{...process.env,...E==="opencode"?{BUN_BE_BUN:"1"}:{},...h.environment}}),$=h.timeout??Ac;return yield*i(D,$).pipe(v.map(O=>({client:O,status:{status:"connected"}})),v.catch(O=>{let Ve=O instanceof Error?O.message:String(O);return v.succeed({client:void 0,status:{status:"failed",error:Ve}})}))}),a=v.fn("MCP.create")(function*(u,h){if(h.enabled===!1)return s;let{client:E,status:x}=h.type==="remote"?yield*d(u,h):yield*c(u,h);return E?yield*v.gen(function*(){let I=E.getServerCapabilities()?.tools?yield*Re.defs(E,h.timeout):[];return I?{mcpClient:E,status:x,defs:I,instructions:E.getInstructions()?.trim()}:yield*v.fail(new Error("Failed to get tools"))}).pipe(v.catchCause(I=>v.tryPromise(()=>E.close()).pipe(v.ignore,v.andThen(v.failCause(I))))):(x.status!=="connected"&&x.status!=="disabled"&&(yield*v.logWarning("server unavailable",{key:u,type:h.type,status:x.status})),{status:x})},v.map(u=>u),v.catchCause(u=>{if(Pc.hasInterruptsOnly(u))return v.interrupt;let h=Pc.squash(u);return v.succeed({status:{status:"failed",error:h instanceof Error?h.message:String(h)}})})),l=yield*jt.Service,f=v.fnUntraced(function*(u){if(process.platform==="win32")return[];let h=[],E=[u];for(let x=0;x<E.length;x++){let I=E[x],R=yield*t.spawn(nm.make("pgrep",["-P",String(I)],{stdin:"ignore"})),D=yield*Rc.mkString(Rc.decodeText(R.stdout));yield*R.exitCode;for(let $ of D.split(`
|
|
865
|
+
`)){let O=parseInt($,10);!isNaN(O)&&!h.includes(O)&&(h.push(O),E.push(O))}}return h},v.scoped,v.catch(()=>v.succeed([])));function p(u,h,E,x,I){E.onclose=()=>{u.clients[h]===E&&(delete u.clients[h],delete u.defs[h],delete u.instructions[h],u.status[h]={status:"failed",error:"Connection closed"},x.fork(v.logWarning("MCP connection closed",{server:h}).pipe(v.andThen(n.publish(di,{server:h})),v.ignore)))},E.setNotificationHandler(Zu,R=>x.promise(m(h,R.params))),E.getServerCapabilities()?.tools&&E.setNotificationHandler(Xu,async()=>{if(u.clients[h]!==E||u.status[h]?.status!=="connected")return;let R=await x.promise(Re.defs(E,I));R&&(u.clients[h]!==E||u.status[h]?.status!=="connected"||(u.defs[h]=R,await x.promise(n.publish(di,{server:h}).pipe(v.ignore))))})}r(p,"watch");function m(u,h){let E={server:u,logger:h.logger,level:h.level,data:h.data};switch(h.level){case"debug":return v.logDebug("MCP server log",E);case"info":case"notice":return v.logInfo("MCP server log",E);case"warning":return v.logWarning("MCP server log",E);case"error":case"critical":case"alert":case"emergency":return v.logError("MCP server log",E)}}r(m,"serverLog");let y=yield*j.make(v.fn("MCP.state")(function*(u){let h=yield*l.get(),E=yield*En.make(),x=Object.fromEntries([...ci(u.directory)].filter(([D])=>!(h.mcp??{})[D])),I={...x,...h.mcp??{}},R={config:{...x},status:{},clients:{},defs:{},instructions:{}};return yield*v.forEach(Object.entries(I),([D,$])=>v.gen(function*(){if(!yo($)){yield*v.logError("Ignoring MCP config entry without type",{key:D});return}if($.enabled===!1){R.status[D]={status:"disabled"};return}let O=yield*a(D,$);R.status[D]=O.status,O.mcpClient&&(R.clients[D]=O.mcpClient,R.defs[D]=O.defs,O.instructions&&(R.instructions[D]=O.instructions),p(R,D,O.mcpClient,E,$.timeout))}),{concurrency:"unbounded"}),yield*v.addFinalizer(()=>v.gen(function*(){let D=Object.values(R.clients);R.clients={},R.defs={},R.instructions={},yield*v.forEach(D,$=>v.gen(function*(){let O=$.transport instanceof wc?$.transport.pid:null;if(typeof O=="number"){let Ve=yield*f(O);for(let ce of Ve)try{process.kill(ce,"SIGTERM")}catch{}}yield*v.tryPromise(()=>$.close()).pipe(v.ignore)}),{concurrency:"unbounded"}),Cn.clear()})),R}));function g(u,h){let E=u.clients[h];return delete u.clients[h],delete u.defs[h],delete u.instructions[h],E?v.tryPromise(()=>E.close()).pipe(v.ignore):v.void}r(g,"closeClient");let b=v.fnUntraced(function*(u,h,E,x,I,R){let D=yield*En.make(),$=u.clients[h];return u.status[h]={status:"connected"},u.clients[h]=E,u.defs[h]=x,I?u.instructions[h]=I:delete u.instructions[h],p(u,h,E,D,R),$&&(yield*v.tryPromise(()=>$.close()).pipe(v.ignore)),u.status[h]}),P=v.fn("MCP.status")(function*(){let u=yield*j.get(y),E=(yield*l.get()).mcp??{},x={};for(let[I,R]of Object.entries(E))yo(R)&&(x[I]=u.status[I]??{status:"disabled"});for(let I of Object.keys(u.config))x[I]=u.status[I]??{status:"disabled"};return x}),C=v.fn("MCP.clients")(function*(){return(yield*j.get(y)).clients}),A=v.fn("MCP.instructions")(function*(){let u=yield*j.get(y);return Object.entries(u.instructions).filter(([h])=>u.status[h]?.status==="connected").sort(([h],[E])=>h.localeCompare(E)).map(([h,E])=>({name:h,instructions:E,tools:(u.defs[h]??[]).map(x=>Re.toolName(h,x.name))}))}),S=v.fn("MCP.createAndStore")(function*(u,h){let E=yield*j.get(y),x=yield*a(u,h);return E.status[u]=x.status,x.mcpClient?yield*b(E,u,x.mcpClient,x.defs,x.instructions,h.timeout):(yield*g(E,u),delete E.clients[u],x.status)}),w=v.fn("MCP.add")(function*(u,h){let E=yield*j.get(y);return E.config[u]=h,yield*S(u,h),ci(yield*j.directory).set(u,h),{status:E.status}}),q=v.fn("MCP.connect")(function*(u){let h=yield*gt(u);yield*S(u,{...h,enabled:!0})}),B=v.fn("MCP.disconnect")(function*(u){yield*gt(u);let h=yield*j.get(y);yield*g(h,u),delete h.clients[u],h.status[u]={status:"disabled"},ci(yield*j.directory).delete(u)});function K(u,h,E,x){let I=E&&yo(E)?E.timeout:void 0;return u.config[h]?.timeout??I??x}r(K,"requestTimeout");let Ue=v.fn("MCP.tools")(function*(){let u={},h=yield*j.get(y),E=yield*l.get(),x=E.mcp??{},I=E.experimental?.mcp_timeout;for(let[R,D]of Object.entries(h.clients)){if(h.status[R]?.status!=="connected")continue;let $=x[R],O=h.defs[R];if(!O){yield*v.logWarning("missing cached tools for connected server",{clientName:R});continue}let Ve=K(h,R,$,I);for(let ce of O)u[Re.toolName(R,ce.name)]={def:ce,client:D,timeout:Ve}}return u}),Pn=v.fn("MCP.toolManifest")(function*(){let u=yield*j.get(y),h={};for(let E of Object.keys(u.clients)){if(u.status[E]?.status!=="connected")continue;let x=u.defs[E];x&&(h[E]=x.map(I=>({name:I.name,...I.description?{description:I.description}:{},...typeof I.annotations?.readOnlyHint=="boolean"?{readOnly:I.annotations.readOnlyHint}:{}})))}return h});function Rn(u,h,E,x,I){return v.gen(function*(){let R=yield*l.get();return yield*v.forEach(Object.entries(u.clients).filter(([D])=>u.status[D]?.status==="connected"&&(!I||D===I)),([D,$])=>Re.fetch(D,$,O=>h(O,K(u,D,R.mcp?.[D],R.experimental?.mcp_timeout)),E,x).pipe(v.map(O=>Object.entries(O??{}))),{concurrency:"unbounded"}).pipe(v.map(D=>Object.fromEntries(D.flat())))})}r(Rn,"collectFromConnected");let Wo=v.fn("MCP.prompts")(function*(){return yield*Rn(yield*j.get(y),Re.prompts,"prompts")}),Mc=v.fn("MCP.resources")(function*(u){return yield*Rn(yield*j.get(y),Re.resources,"resources",h=>h.uri,u)}),Lc=v.fn("MCP.resourceTemplates")(function*(u){return yield*Rn(yield*j.get(y),Re.resourceTemplates,"resource templates",h=>h.uriTemplate,u)}),fi=v.fnUntraced(function*(u,h,E,x){let I=yield*j.get(y),R=I.clients[u];if(!R){yield*v.logWarning(`client not found for ${E}`,{clientName:u});return}let D=yield*l.get();return yield*v.tryPromise({try:r(()=>h(R,K(I,u,D.mcp?.[u],D.experimental?.mcp_timeout)),"try"),catch:r($=>$,"catch")}).pipe(v.tapError($=>v.logError(`failed to ${E}`,{clientName:u,...x,error:$ instanceof Error?$.message:String($)})),v.orElseSucceed(()=>{}))}),Uc=v.fn("MCP.getPrompt")(function*(u,h,E){return yield*fi(u,(x,I)=>x.getPrompt({name:h,arguments:E},{timeout:I}),"getPrompt",{promptName:h})}),Vc=v.fn("MCP.readResource")(function*(u,h){return yield*fi(u,(E,x)=>E.readResource({uri:h},{timeout:x}),"readResource",{resourceUri:h})}),Nc=v.fnUntraced(function*(u){let h=yield*j.get(y);if(h.config[u])return h.config[u];let x=(yield*l.get()).mcp?.[u];if(!(!x||!yo(x)))return x}),gt=v.fnUntraced(function*(u){let h=yield*Nc(u);return h||(yield*new zo({name:u}))}),pi=v.fn("MCP.startAuth")(function*(u){let h=yield*gt(u);if(h.type!=="remote")throw new Error(`MCP server ${u} is not a remote server`);if(h.oauth===!1)throw new Error(`MCP server ${u} has OAuth explicitly disabled`);let E=Tc(h.url);if(!E)throw new Error(`Invalid MCP URL for "${u}"`);let x=typeof h.oauth=="object"?h.oauth:void 0,I=x?.redirectUri??(x?.callbackPort?`http://127.0.0.1:${x.callbackPort}${ut}`:void 0);yield*v.promise(()=>Tt.ensureRunning(I));let R=Array.from(crypto.getRandomValues(new Uint8Array(32))).map(ce=>ce.toString(16).padStart(2,"0")).join("");yield*e.updateOAuthState(u,R);let D,$=new Go(u,h.url,{clientId:x?.clientId,clientSecret:x?.clientSecret,scope:x?.scope,redirectUri:I},{onRedirect:r(async ce=>{D=ce},"onRedirect")},e),O=new Ic(E,{authProvider:$,requestInit:h.headers?{headers:h.headers}:void 0}),Ve=yield*j.directory;return yield*v.tryPromise({try:r(()=>{let ce=Dc(Ve);return ce.connect(O).then(async()=>(await $.commit(),{authorizationUrl:"",oauthState:R,client:ce}))},"try"),catch:r(ce=>ce,"catch")}).pipe(v.catch(ce=>ce instanceof Cc&&D?(Cn.set(u,{transport:O,provider:$}),v.succeed({authorizationUrl:D.toString(),oauthState:R})):v.die(ce)))}),jc=v.fn("MCP.authenticate")(function*(u,h){let E=yield*pi(u);if(!E.authorizationUrl){let D="client"in E?E.client:void 0,$=yield*gt(u).pipe(v.tapError(()=>v.tryPromise(()=>D?.close()??Promise.resolve()).pipe(v.ignore))),O=D?D.getServerCapabilities()?.tools?yield*Re.defs(D,$.timeout):[]:void 0;if(!D||!O)return yield*v.tryPromise(()=>D?.close()??Promise.resolve()).pipe(v.ignore),{status:"failed",error:"Failed to get tools"};let Ve=yield*j.get(y);return yield*e.clearOAuthState(u),yield*b(Ve,u,D,O,D.getInstructions()?.trim(),$.timeout)}let x=Tt.waitForCallback(E.oauthState,u);h?.(E.authorizationUrl),yield*o.open(E.authorizationUrl).pipe(v.catch(()=>n.publish(_c,{mcpName:u,url:E.authorizationUrl}).pipe(v.ignore)));let I=yield*v.promise(()=>x);if((yield*e.getOAuthState(u))!==E.oauthState)throw yield*e.clearOAuthState(u),new Error("OAuth state mismatch - potential CSRF attack");return yield*e.clearOAuthState(u),yield*ui(u,I)}),ui=v.fn("MCP.finishAuth")(function*(u,h){yield*gt(u);let E=Cn.get(u);if(!E)throw new Error(`No pending OAuth flow for MCP server: ${u}`);let x=yield*v.tryPromise({try:r(()=>E.transport.finishAuth(h),"try"),catch:r(R=>R,"catch")}).pipe(v.match({onFailure:r(R=>R instanceof Error?R.message:String(R),"onFailure"),onSuccess:r(()=>{},"onSuccess")}));if(x)return{status:"failed",error:`OAuth completion failed: ${x}`};yield*v.promise(()=>E.provider?.commit()??Promise.resolve()),yield*e.clearCodeVerifier(u),Cn.delete(u);let I=yield*gt(u);return yield*S(u,{...I,enabled:!0})}),qc=v.fn("MCP.removeAuth")(function*(u){yield*e.remove(u),Tt.cancelPending(u),Cn.delete(u)}),$c=v.fn("MCP.supportsOAuth")(function*(u){let h=yield*gt(u);return h.type==="remote"&&h.oauth!==!1}),Fc=v.fn("MCP.hasStoredTokens")(function*(u){return!!(yield*e.get(u))?.tokens}),Hc=v.fn("MCP.getAuthStatus")(function*(u){let E=((yield*j.has(y))?(yield*j.get(y)).config[u]:void 0)??(yield*l.get()).mcp?.[u];if(!E||!yo(E)||E.type!=="remote")return"not_authenticated";let x=yield*e.getForUrl(u,E.url);return x?.tokens?x.tokens.expiresAt&&x.tokens.expiresAt<Date.now()/1e3?"expired":"authenticated":"not_authenticated"});return _t.of({status:P,clients:C,instructions:A,tools:Ue,defs:Pn,prompts:Wo,resources:Mc,resourceTemplates:Lc,add:w,connect:q,disconnect:B,getPrompt:Uc,readResource:Vc,startAuth:pi,authenticate:jc,finishAuth:ui,removeAuth:qc,supportsOAuth:$c,hasStoredTokens:Fc,getAuthStatus:Hc})})),hm=Ae.make({service:_t,layer:gm,deps:[Ri.node,vn.node,Ze.node,jt.node,wn.node]});export{lt as a,_n as b,Oe as c,zt as d,Yt as e,Ce as f,cn as g,Qe as h,ge as i,tt as j,ae as k,Be as l,Dn as m,He as n,Pe as o,ti as p,xc as q,Hm as r,En as s,ir as t,On as u,Ht as v,ri as w,lc as x,vn as y,Ot as z,Xx as A,Re as B,bn as C,li as D};
|