@vibecontrols/agent 2026.531.13 → 2026.531.15
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.
Potentially problematic release.
This version of @vibecontrols/agent might be problematic. Click here for more details.
- package/dist/app-nepbpk4d.js +2 -0
- package/dist/cli.js +1 -1
- package/dist/{index-fwd90spw.js → index-0n663tk5.js} +2 -2
- package/dist/{index-pd9haevn.js → index-4s5hv6a7.js} +2 -2
- package/dist/index-7qkzdq23.js +3 -0
- package/dist/{index-1x89a7r1.js → index-cyhcvfxs.js} +2 -2
- package/dist/{index-q96eskyn.js → index-mq3amjcf.js} +1 -1
- package/dist/{index-h2n00ae3.js → index-s3vbcsga.js} +2 -2
- package/dist/{index-ttafzcs7.js → index-wk359257.js} +1 -1
- package/dist/{index-vfwervz9.js → index-wmeb40wr.js} +1 -1
- package/dist/{index-rv8as74y.js → index-yhwmtghn.js} +2 -2
- package/dist/index.js +1 -1
- package/dist/{plugin-system-3z2smf2a.js → plugin-system-w3vnn5vh.js} +1 -1
- package/dist/{secondary-profile-attach-9c1rp4y7.js → secondary-profile-attach-mgt3bv4j.js} +1 -1
- package/package.json +1 -1
- package/dist/app-w2196qbz.js +0 -2
- package/dist/index-49a60qjr.js +0 -3
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import{getDaemonProfile,profileRegistry,registerAllowedTunnelSuffix}from"./index-7pdmqbj8.js";import{getPluginRegistry,getVibecontrolsDir}from"./index-bysm7taq.js";import{__require}from"./index-e9rt4m94.js";import{existsSync as existsSync2,mkdirSync,readFileSync as readFileSync2,renameSync,realpathSync,rmSync,statSync,writeFileSync}from"fs";import{homedir as osHomedir}from"os";import{dirname as dirname2,isAbsolute,join as join2,relative}from"path";import{fileURLToPath as fileURLToPath3}from"url";var PROVIDER_TYPES=["tunnel","session","ai","plan"];class ServiceRegistry{providers=new Map;providerOrder=new Map;defaults=new Map;services=new Map;db;constructor(db){this.db=db}getDb(){return this.db}setProviderDefault(type,pluginName){this.defaults.set(type,pluginName)}clearProviderDefault(type,pluginName){if(!pluginName||this.defaults.get(type)===pluginName)this.defaults.delete(type)}async hydrateDefaultsFromDb(){if(!this.db)return;for(let type of PROVIDER_TYPES)try{let name=await this.db.getConfig(`provider:default:${type}`);if(name)this.defaults.set(type,name)}catch{}}registerProvider(type,provider,pluginName){if(!this.providers.has(type))this.providers.set(type,new Map),this.providerOrder.set(type,[]);let typeMap=this.providers.get(type),order=this.providerOrder.get(type);if(typeMap.has(pluginName))getDaemonProfile().logger.info("service-registry",`Updating ${type} provider from plugin '${pluginName}'`);else getDaemonProfile().logger.info("service-registry",`Registered ${type} provider from plugin '${pluginName}'`);if(typeMap.set(pluginName,{provider,pluginName,registeredAt:new Date}),!order.includes(pluginName))order.push(pluginName)}getProvider(type){let typeMap=this.providers.get(type);if(!typeMap||typeMap.size===0)return;let defaultName=this.defaults.get(type);if(defaultName&&typeMap.has(defaultName))return typeMap.get(defaultName).provider;let order=this.providerOrder.get(type);if(order&&order.length>0){let firstPluginName=order[0];return typeMap.get(firstPluginName)?.provider}return}getProviderByName(type,pluginName){let typeMap=this.providers.get(type);if(!typeMap)return;return typeMap.get(pluginName)?.provider}hasProvider(type){let typeMap=this.providers.get(type);return!!typeMap&&typeMap.size>0}unregisterProvider(type,pluginName){let typeMap=this.providers.get(type);if(!typeMap)return!1;let removed=typeMap.delete(pluginName);if(removed){let order=this.providerOrder.get(type);if(order){let idx=order.indexOf(pluginName);if(idx!==-1)order.splice(idx,1)}this.clearProviderDefault(type,pluginName),getDaemonProfile().logger.info("service-registry",`Unregistered ${type} provider from plugin '${pluginName}'`)}return removed}unregisterPlugin(pluginName){for(let type of PROVIDER_TYPES)this.unregisterProvider(type,pluginName);this.unregisterServices(pluginName)}listProvidersForType(type){let typeMap=this.providers.get(type);if(!typeMap)return[];let defaultName=this.defaults.get(type);if(!defaultName||!typeMap.has(defaultName)){let order=this.providerOrder.get(type);defaultName=order&&order.length>0?order[0]:void 0}return Array.from(typeMap.keys()).map((name)=>({pluginName:name,isDefault:name===defaultName}))}registerService(pluginName,serviceName,service){let key=`${pluginName}:${serviceName}`;this.services.set(key,{service,pluginName}),getDaemonProfile().logger.debug("service-registry",`Registered service '${key}'`)}getService(pluginName,serviceName){let key=`${pluginName}:${serviceName}`;return this.services.get(key)?.service}unregisterServices(pluginName){let keysToDelete=[];for(let[key,entry]of this.services)if(entry.pluginName===pluginName)keysToDelete.push(key);for(let key of keysToDelete)this.services.delete(key);if(keysToDelete.length>0)getDaemonProfile().logger.info("service-registry",`Unregistered ${keysToDelete.length} services from ${pluginName}`)}listProviders(){let result=[];for(let[type,typeMap]of this.providers)for(let[pluginName,entry]of typeMap)result.push({type,name:pluginName,pluginName:entry.pluginName});return result}listServices(){return Array.from(this.services.entries()).map(([key,entry])=>({pluginName:entry.pluginName,serviceName:key.split(":").slice(1).join(":")}))}clear(){this.providers.clear(),this.providerOrder.clear(),this.defaults.clear(),this.services.clear()}}import{existsSync,readFileSync}from"fs";import{dirname,join}from"path";import{fileURLToPath}from"url";var AGENT_PACKAGE_NAME="@vibecontrols/agent",cached;function getAgentVersion(){if(cached)return cached;try{let dir=dirname(fileURLToPath(import.meta.url));for(let i=0;i<10&&dir&&dir!==dirname(dir);i++){let pkgPath=join(dir,"package.json");if(existsSync(pkgPath))try{let pkg=JSON.parse(readFileSync(pkgPath,"utf8"));if(pkg.name===AGENT_PACKAGE_NAME&&typeof pkg.version==="string")return cached=pkg.version,cached}catch{}dir=dirname(dir)}}catch{}return cached??"0.0.0"}function pluginContractV2EnforceMode(){let v=process.env.VIBECONTROLS_PLUGIN_CONTRACT_V2_ENFORCE;return v==="1"||v==="true"||v==="on"}var FULL_TRUST_CAPS={storage:"rw",secrets:"rw",gateway:!0,broadcast:!0,subprocess:!0,audit:!0,telemetry:!0,singletonOnly:!1,requiresIsolation:!1},EMPTY_CAPS={storage:"none",secrets:"none",gateway:!1,broadcast:!1,subprocess:!1,audit:!1,telemetry:!1,singletonOnly:!1,requiresIsolation:!1};function strictCapsMode(){let v=process.env.VIBECONTROLS_STRICT_PLUGIN_CAPS;return v==="1"||v==="true"||v==="on"}function buildCapabilityProxy(hostServices,pluginName,caps,audit){return new Proxy(hostServices,{get(target,prop,receiver){if(prop==="storage")return guardedStorage(target.storage,caps.storage??"none",pluginName,audit);if(prop==="broadcast"&&!caps.broadcast)return refusalFn(pluginName,"broadcast",audit);if(prop==="workspaceQuery"&&!caps.gateway)return refusalFn(pluginName,"workspaceQuery",audit);if(prop==="getAgentRecordId"&&!caps.gateway)return refusalFn(pluginName,"getAgentRecordId",audit);if(prop==="getWorkspaceId"&&!caps.gateway)return refusalFn(pluginName,"getWorkspaceId",audit);if(prop==="telemetry"){if(!caps.telemetry)return;return Reflect.get(target,prop,receiver)}return Reflect.get(target,prop,receiver)}})}function guardedStorage(storage,mode,pluginName,audit){if(mode==="rw")return storage;return new Proxy(storage,{get(target,op,receiver){let opName=String(op),isWriter=opName==="set"||opName==="delete"||opName==="deleteAll";if(mode==="none"||mode==="read"&&isWriter)return(..._args)=>{throw audit("plugin.capability.denied",{pluginName,surface:"storage",op:opName,mode}),Error(`plugin '${pluginName}' lacks storage:${isWriter?"rw":"read"} capability (op=${opName})`)};return Reflect.get(target,op,receiver)}})}function refusalFn(pluginName,what,audit){return(..._args)=>{throw audit("plugin.capability.denied",{pluginName,op:what}),Error(`plugin '${pluginName}' lacks capability for ${what}`)}}import{Worker}from"worker_threads";import{fileURLToPath as fileURLToPath2}from"url";import{randomUUID}from"crypto";function resolveRuntimeEntry(){let here=fileURLToPath2(import.meta.url),sep=here.lastIndexOf("/"),dir=sep>=0?here.slice(0,sep):here,tsPath=`${dir}/plugin-worker-runtime.ts`,jsPath=`${dir}/plugin-worker-runtime.js`;if(here.endsWith(".ts"))return tsPath;return jsPath}class PluginWorkerHost{worker;pending=new Map;spec;initPromise;terminated=!1;constructor(spec){this.spec=spec}async start(){if(this.initPromise)return this.initPromise;return this.initPromise=this.spawn(),this.initPromise}async spawn(){let entry=this.spec.runtimeEntry??resolveRuntimeEntry(),worker=new Worker(entry,{env:process.env});this.worker=worker,worker.on("message",(msg)=>this.onMessage(msg)),worker.on("error",(err)=>this.onWorkerError(err instanceof Error?err:Error(String(err)))),worker.on("exit",(code)=>this.onWorkerExit(code)),await this.call("init",{modulePath:this.spec.modulePath,ctxStub:{name:this.spec.ctx.name,dataDir:this.spec.ctx.dataDir}})}async dispatch(method,params=[]){if(this.terminated)throw Error("PluginWorkerHost terminated");if(!this.worker)await this.start();return this.call("dispatch",{method,params})}call(op,args){if(!this.worker)return Promise.reject(Error("worker not spawned"));let id=randomUUID();return new Promise((resolve,reject)=>{this.pending.set(id,{resolve,reject});try{this.worker?.postMessage({id,op,args})}catch(err){this.pending.delete(id),reject(err instanceof Error?err:Error(String(err)))}})}onMessage(msg){let pending=this.pending.get(msg.id);if(!pending)return;if(this.pending.delete(msg.id),msg.ok)pending.resolve(msg.result);else{let err=Error(msg.error?.message??"worker error");if(msg.error?.stack)err.stack=msg.error.stack;pending.reject(err)}}onWorkerError(err){for(let[,p]of this.pending)p.reject(err);this.pending.clear()}onWorkerExit(code){if(this.pending.size>0){let err=Error(`worker exited (code=${code}) with pending calls`);for(let[,p]of this.pending)p.reject(err);this.pending.clear()}this.terminated=!0}async terminate(){if(this.terminated=!0,!this.worker)return;try{await this.worker.terminate()}catch{}this.worker=void 0}}var CORE_PLUGINS=[{packageName:"@vibecontrols/vibe-plugin-storage",pluginName:"storage",label:"Storage facade",description:"Storage provider registry \u2014 owns AgentDatabase contract. Bundled with the agent; the storage meta lazy-loads the configured provider by name.",category:"storage",trusted:!0,isCore:!0,isDefault:!0,isCritical:!0,removable:!1},...["agent","task","config","git","plugin-mgr","log"].map((name)=>({packageName:`@vibecontrols/vibe-plugin-${name}`,pluginName:name,label:`${name} (built-in)`,description:`Built-in ${name} plugin bundled with the agent.`,category:"core",trusted:!0,isCore:!0,removable:!1}))],META_PLUGINS=[{packageName:"@vibecontrols/vibe-plugin-tunnel",pluginName:"tunnel",label:"Tunnel manager",description:"Owns TunnelProvider interface. Routes to a registered tunnel provider.",category:"tunnel",trusted:!0,isDefault:!0,isCritical:!0,cliCommand:"tunnel",apiPrefix:"/api/tunnel"},{packageName:"@vibecontrols/vibe-plugin-session-manager",pluginName:"session-manager",label:"Session manager",description:"Owns SessionProvider interface. Routes to a registered session backend.",category:"session",trusted:!0,isCore:!0,isDefault:!0,isCritical:!0,cliCommand:"session",apiPrefix:"/api/sessions"},{packageName:"@vibecontrols/vibe-plugin-ai",pluginName:"ai",label:"AI orchestration",description:"Owns AIAgentProvider interface. Prompts, contexts, sessions, dispatch, logs.",category:"ai",trusted:!0,isDefault:!0,isCritical:!0,cliCommand:"ai",apiPrefix:"/api/ai"},{packageName:"@vibecontrols/vibe-plugin-plan",pluginName:"plan",label:"Plan orchestration",description:"Owns PlanProvider interface. Routes plan sessions to a registered provider.",category:"plan",trusted:!0,isDefault:!0,cliCommand:"plan",apiPrefix:"/api/plan"},{packageName:"@vibecontrols/vibe-plugin-gitops",pluginName:"gitops",label:"GitOps orchestrator",description:"Owns GitOpsProvider interface. Routes repo / PR / CI / security queries to a registered provider.",category:"gitops",trusted:!0,isDefault:!0,cliCommand:"gitops",apiPrefix:"/api/gitops"},{packageName:"@vibecontrols/vibe-plugin-security",pluginName:"security",label:"Security lifecycle",description:"Security lifecycle orchestrator \u2014 owns /api/security and dispatches to per-stage providers.",category:"security",trusted:!0,isDefault:!0,cliCommand:"security",apiPrefix:"/api/security"}],AGENT_PLUGINS=[{packageName:"@vibecontrols/vibe-plugin-agent-backup",pluginName:"agent-backup",label:"Agent backup",description:"Backup and restore agent state.",category:"agent",trusted:!0,isDefault:!0}],PLUGIN_CATALOG=[...CORE_PLUGINS,...META_PLUGINS,...AGENT_PLUGINS],ABILITIES=[{key:"storage",label:"Storage",description:"Encrypted local state for the agent.",categories:["storage"],mandatory:!0,defaultSelected:!0},{key:"tunnel",label:"Tunnels",description:"Expose the agent for remote access + share links.",categories:["tunnel"],mandatory:!0,defaultSelected:!0},{key:"backup",label:"Backup",description:"Backup + restore agent state.",categories:["agent"],mandatory:!0,defaultSelected:!0},{key:"session",label:"Terminal sessions",description:"Long-lived terminal / AI agent sessions.",categories:["session"],mandatory:!1,defaultSelected:!0},{key:"ai",label:"AI orchestration",description:"AI agent harnesses, prompts + dispatch.",categories:["ai"],mandatory:!1,defaultSelected:!0},{key:"plan",label:"Plan review",description:"Review / approve AI-proposed plans.",categories:["plan"],mandatory:!1,defaultSelected:!0},{key:"gitops",label:"GitOps",description:"Repo / PR / CI / security integration.",categories:["gitops"],mandatory:!1,defaultSelected:!0},{key:"security",label:"Security",description:"Security scanning lifecycle.",categories:["security"],mandatory:!1,defaultSelected:!0}],CORE_PLUGIN_NAMES=PLUGIN_CATALOG.filter((p)=>p.isCore&&p.category==="core").map((p)=>p.pluginName),DEFAULT_PLUGINS=PLUGIN_CATALOG.filter((p)=>p.isDefault===!0);function getDefaultPluginsForPlatform(_platform){return DEFAULT_PLUGINS}function getDefaultPluginsForAbilities(platform,selectedAbilityKeys){let selected=selectedAbilityKeys instanceof Set?selectedAbilityKeys:new Set(selectedAbilityKeys),activeCategories=new Set;for(let ability of ABILITIES)if(ability.mandatory||selected.has(ability.key))for(let c of ability.categories)activeCategories.add(c);return getDefaultPluginsForPlatform(platform).filter((p)=>activeCategories.has(p.category))}var TRUSTED_PACKAGES=new Set(PLUGIN_CATALOG.filter((p)=>p.trusted).map((p)=>p.packageName));function getCriticalPluginNames(){let fromCatalog=PLUGIN_CATALOG.filter((p)=>p.isCritical).flatMap((p)=>[p.packageName,p.pluginName]),override=process.env.VIBECONTROLS_CRITICAL_PLUGINS;if(override){let parts=override.split(",").map((s)=>s.trim()).filter(Boolean);return new Set([...fromCatalog,...parts])}return new Set(fromCatalog)}function isCriticalPlugin(packageOrName){return getCriticalPluginNames().has(packageOrName)}var AVAILABLE_PLUGINS=PLUGIN_CATALOG.filter((p)=>!p.isCore||p.category!=="core");function getCatalogEntry(packageName){return PLUGIN_CATALOG.find((p)=>p.packageName===packageName)}function collectPluginBinaries(_pluginIdentifiers){return new Set}function isTrustedPackage(packageName){return packageName.startsWith("@vibecontrols/vibe-plugin-")||TRUSTED_PACKAGES.has(packageName)}function resolvePluginByShortName(input){let raw=input.trim();if(!raw)return;if(raw.startsWith("@vibecontrols/"))return PLUGIN_CATALOG.find((p)=>p.packageName===raw);if(raw.startsWith("vibe-plugin-"))return PLUGIN_CATALOG.find((p)=>p.packageName===`@vibecontrols/${raw}`);let byPluginName=PLUGIN_CATALOG.find((p)=>p.pluginName===raw);if(byPluginName)return byPluginName;return PLUGIN_CATALOG.find((p)=>p.packageName===`@vibecontrols/vibe-plugin-${raw}`)}function getCatalogEntry2(pluginName){return PLUGIN_CATALOG.find((entry)=>entry.pluginName===pluginName)}var REGISTRY_FILE_NAME="plugins.json",PLUGIN_PACKAGE_RE=/^@vibecontrols\/vibe-plugin-[a-z0-9][a-z0-9-]{0,80}$/,PLUGIN_NAME_RE=/^[a-z0-9][a-z0-9-]{0,63}$/,PLUGIN_API_PREFIX_RE=/^\/api\/[A-Za-z0-9][A-Za-z0-9/_-]{0,127}$/,PLUGIN_PUBLIC_PATH_RE=/^\/[A-Za-z0-9][A-Za-z0-9/_-]{0,159}$/,PLUGIN_PACKAGE_ROOT=Symbol.for("vibecontrols.pluginPackageRoot");function getPluginPackageRoot(plugin){return plugin[PLUGIN_PACKAGE_ROOT]}function validatePluginPackageName(packageName){let normalized=packageName.trim();if(!PLUGIN_PACKAGE_RE.test(normalized))throw Error("Plugin package must be a @vibecontrols/vibe-plugin-* package name.");if(!isTrustedPackage(normalized)&&process.env.VIBECONTROLS_ALLOW_UNTRUSTED_PLUGINS!=="1")throw Error("Plugin package is not in the trusted VibeControls catalog.");return normalized}function isPathInside(parent,child){let rel=relative(parent,child);return rel===""||!!rel&&!rel.startsWith("..")&&!isAbsolute(rel)}function getInstallMode(){let v=(process.env.VIBECONTROLS_PLUGIN_INSTALL_MODE||"").toLowerCase();if(v==="local")return"local";if(v==="global")return"global";return process.platform==="win32"?"local":"global"}var PROVIDER_DEFAULT_PREFIX="provider:default:";function isPluginEntry(value){if(!value||typeof value!=="object")return!1;let entry=value;return typeof entry.packageName==="string"&&typeof entry.version==="string"&&typeof entry.pluginName==="string"&&typeof entry.installedAt==="string"}var DEFAULT_PLUGINS2=DEFAULT_PLUGINS;class PluginManager{registry=[];loaded=new Map;corePlugins=new Map;db;forcedIsolation=new Set;workerHosts=new Map;constructor(db){this.db=db,this.ensureDir(),this.loadRegistry();let isolateEnv=process.env.VIBE_ISOLATE_PLUGINS;if(typeof isolateEnv==="string"&&isolateEnv.length>0)this.setForcedIsolation(isolateEnv.split(",").map((n)=>n.trim()).filter((n)=>n.length>0))}setForcedIsolation(names){this.forcedIsolation=new Set(names.filter((n)=>n.length>0))}shouldIsolate(plugin){if(this.forcedIsolation.has(plugin.name))return!0;return plugin.capabilities?.requiresIsolation===!0}getWorkerHost(pluginName){return this.workerHosts.get(pluginName)}registerWorkerHost(pluginName,host){this.workerHosts.set(pluginName,host)}auditSink=(event,payload)=>{getDaemonProfile().logger.warn("plugin-capability",event,payload)};static resolveEffectiveCapabilities(plugin,isCore){if(plugin.capabilities)return plugin.capabilities;return isCore?FULL_TRUST_CAPS:EMPTY_CAPS}wrapHostServices(plugin,hostServices){let caps=PluginManager.resolveEffectiveCapabilities(plugin,this.corePlugins.has(plugin.name));return buildCapabilityProxy(hostServices,plugin.name,caps,this.auditSink)}acceptCapabilities(plugin,source){if(plugin.capabilities?.singletonOnly===!0&&profileRegistry.size()>1)return getDaemonProfile().logger.error("plugin-manager",`[plugin] '${plugin.name}' refused to load: singletonOnly capability incompatible with multi-profile daemon (profiles=${profileRegistry.size()}, source=${source})`),!1;if(plugin.capabilities)return!0;if(strictCapsMode())return getDaemonProfile().logger.error("plugin-manager",`[plugin] '${plugin.name}' refused to load: missing required capabilities declaration (source=${source})`),!1;if(source.startsWith("core:"))getDaemonProfile().logger.warn("plugin-manager",`[plugin] '${plugin.name}' loaded without a capabilities declaration \u2014 granting full trust (core plugin). Declare capabilities explicitly. (source=${source})`);else getDaemonProfile().logger.warn("plugin-manager",`[plugin] '${plugin.name}' loaded without a capabilities declaration \u2014 defaulting to EMPTY capability set (deny by default). External plugins MUST declare capabilities explicitly to access host services. (source=${source})`);return!0}ensureDir(){let dir=getVibecontrolsDir();if(!existsSync2(dir))mkdirSync(dir,{recursive:!0})}loadRegistry(){let registryFile=join2(getVibecontrolsDir(),REGISTRY_FILE_NAME);try{if(existsSync2(registryFile)){let raw=readFileSync2(registryFile,"utf-8"),parsed=JSON.parse(raw);if(Array.isArray(parsed)&&parsed.every(isPluginEntry))this.registry=parsed.filter((entry)=>{try{return validatePluginPackageName(entry.packageName),!0}catch(err){return getDaemonProfile().logger.warn("plugin-manager","Ignoring invalid plugin entry",{packageName:entry.packageName,error:String(err)}),!1}});else throw Error("plugins.json has an invalid schema")}}catch(err){getDaemonProfile().logger.warn("plugin-manager","Failed to load plugin registry",{path:registryFile,error:String(err)}),this.registry=[]}}saveRegistry(){this.ensureDir();let registryFile=join2(getVibecontrolsDir(),REGISTRY_FILE_NAME),tmpFile=`${registryFile}.${process.pid}.tmp`;writeFileSync(tmpFile,`${JSON.stringify(this.registry,null,2)}
|
|
3
|
-
`,{encoding:"utf-8",mode:384}),renameSync(tmpFile,registryFile)}async loadCorePlugins(){let coreModules=await Promise.allSettled([import("./index-
|
|
4
|
-
`);if(refreshLatest&&concreteLatest){let installedVer=this.readInstalledVersion(join2(localDir,"node_modules"),packageName);if(installedVer&&installedVer!==concreteLatest){getDaemonProfile().logger.info("plugin-manager",`Pre-clean ${packageName}: on-disk v${installedVer} != target v${concreteLatest} \u2014 removing stale copy + lockfile to force fresh resolve`);try{rmSync(join2(localDir,"node_modules",packageName),{recursive:!0,force:!0})}catch{}try{rmSync(join2(localDir,"bun.lock"),{force:!0}),rmSync(join2(localDir,"bun.lockb"),{force:!0})}catch{}}try{rmSync(join2(localDir,"bun.lock"),{force:!0}),rmSync(join2(localDir,"bun.lockb"),{force:!0})}catch{}}if(Bun.spawnSync(["bun","add",installSpec,"--registry",registry],{cwd:localDir,timeout:120000,stdout:"pipe",stderr:"pipe"}).exitCode!==0){let npmResult=Bun.spawnSync(["npm","install",installSpec,"--registry",registry],{cwd:localDir,timeout:120000,stdout:"pipe",stderr:"pipe"});if(npmResult.exitCode!==0)throw Error(npmResult.stderr.toString().trim())}if(refreshLatest&&concreteLatest){let installedVer=this.readInstalledVersion(join2(localDir,"node_modules"),packageName);if(installedVer!==concreteLatest){getDaemonProfile().logger.warn("plugin-manager",`bun kept ${packageName}@${installedVer??"missing"} after requesting ${concreteLatest}; retrying with npm after removing stale local copy`);try{rmSync(join2(localDir,"node_modules",packageName),{recursive:!0,force:!0}),rmSync(join2(localDir,"bun.lock"),{force:!0}),rmSync(join2(localDir,"bun.lockb"),{force:!0}),rmSync(join2(localDir,"package-lock.json"),{force:!0})}catch{}let npmResult=Bun.spawnSync(["npm","install",installSpec,"--registry",registry,"--save-exact"],{cwd:localDir,timeout:120000,stdout:"pipe",stderr:"pipe"});if(npmResult.exitCode!==0)throw Error(npmResult.stderr.toString().trim())}}}else if(Bun.spawnSync(["bun","install","-g",installSpec,"--registry",registry],{timeout:120000,stdout:"pipe",stderr:"pipe"}).exitCode!==0){let npmResult=Bun.spawnSync(["npm","install","-g",installSpec,"--registry",registry],{timeout:120000,stdout:"pipe",stderr:"pipe"});if(npmResult.exitCode!==0)throw Error(npmResult.stderr.toString().trim())}this.pluginRoots=void 0}catch(err){let message=err instanceof Error?err.message:String(err);if(refreshLatest)try{await import(packageName),getDaemonProfile().logger.warn("plugin-manager",`Could not refresh ${packageName} to @latest (${message}); using the already-installed copy`),this.pluginRoots=void 0;let plugin2=await this.importPlugin(packageName),entry2={packageName,version:plugin2.version,pluginName:plugin2.name,installedAt:new Date().toISOString()};return this.registry=this.registry.filter((e)=>e.packageName!==packageName),this.registry.push(entry2),this.saveRegistry(),entry2}catch{}throw Error(`Failed to install ${packageName}: ${message}`,{cause:err})}let plugin=await this.importPlugin(packageName);if(refreshLatest&&concreteLatest&&plugin.version!==concreteLatest)getDaemonProfile().logger.warn("plugin-manager",`${packageName} refreshed to ${plugin.version} but registry latest is ${concreteLatest} \u2014 a stale resolver/cache may still be in play`);if(this.corePlugins.has(plugin.name))getDaemonProfile().logger.info("plugin-manager",`External plugin '${packageName}' overrides core plugin '${plugin.name}'`);let entry={packageName,version:plugin.version,pluginName:plugin.name,installedAt:new Date().toISOString()};return this.registry=this.registry.filter((e)=>e.packageName!==packageName),this.registry.push(entry),this.saveRegistry(),getDaemonProfile().logger.info("plugin-manager",`Installed ${packageName}@${plugin.version} (${plugin.name})`),entry}async ensureDefaultPlugins(onStatus,skipPlugins=[],selectedAbilities){let installed=[],skipSet=new Set(skipPlugins),entries=selectedAbilities?getDefaultPluginsForAbilities(process.platform,selectedAbilities):getDefaultPluginsForPlatform(process.platform);for(let entry of entries){if(skipSet.has(entry.packageName)||skipSet.has(entry.pluginName)){getDaemonProfile().logger.info("plugin-manager",`${entry.packageName} skipped by --skip-plugin`);continue}if(entry.isCore){getDaemonProfile().logger.info("plugin-manager",`${entry.packageName} is bundled with the agent \u2014 skipping auto-install`);continue}if(this.registry.some((r)=>r.packageName===entry.packageName)){getDaemonProfile().logger.info("plugin-manager",`${entry.packageName} already installed, skipping auto-install`);continue}onStatus?.(`Installing ${entry.label} (${entry.packageName})...`);try{await this.install(entry.packageName),installed.push(entry),onStatus?.(`Installed ${entry.label} (${entry.packageName})`)}catch(err){let message=err instanceof Error?err.message:String(err);getDaemonProfile().logger.error("plugin-manager",`Failed to auto-install ${entry.packageName}: ${message}`),onStatus?.(`Failed to install ${entry.label}: ${message}`)}}if(installed.length>0)this.loadRegistry();return installed}async installAndLoad(packageName,app,hostServices){let entry=await this.install(packageName),plugin=this.loaded.get(entry.packageName);if(plugin){this.registerPluginProviders(plugin,hostServices);let wrapped=this.wrapHostServices(plugin,hostServices);if(plugin.onServerStart)await plugin.onServerStart(app,wrapped);if(plugin.onServerReady)await plugin.onServerReady(app,wrapped)}return entry}async update(packageName){packageName=validatePluginPackageName(packageName),getDaemonProfile().logger.info("plugin-manager",`Updating ${packageName}...`);let existing=this.registry.find((e)=>e.packageName===packageName);if(!existing)throw Error(`Plugin ${packageName} is not installed. Use 'install' first.`);let registry=getPluginRegistry();try{if(Bun.spawnSync(["bun","install","-g",`${packageName}@latest`,"--registry",registry],{timeout:120000,stdout:"pipe",stderr:"pipe"}).exitCode!==0){let npmResult=Bun.spawnSync(["npm","install","-g",`${packageName}@latest`,"--registry",registry],{timeout:120000,stdout:"pipe",stderr:"pipe"});if(npmResult.exitCode!==0)throw Error(npmResult.stderr.toString().trim())}}catch(err){let message=err instanceof Error?err.message:String(err);throw Error(`Failed to update ${packageName}: ${message}`,{cause:err})}this.loaded.delete(packageName);let plugin=await this.importPlugin(packageName),entry={packageName,version:plugin.version,pluginName:plugin.name,installedAt:existing.installedAt};return this.registry=this.registry.filter((e)=>e.packageName!==packageName),this.registry.push(entry),this.saveRegistry(),getDaemonProfile().logger.info("plugin-manager",`Updated ${packageName} to v${plugin.version}`),entry}async updateAll(){let results=[];for(let entry of[...this.registry])try{let updated=await this.update(entry.packageName);results.push({packageName:entry.packageName,success:!0,version:updated.version})}catch(err){results.push({packageName:entry.packageName,success:!1,error:err instanceof Error?err.message:String(err)})}return results}async removeAll(hostServices){let results=[],toRemove=[...this.registry];for(let entry of toRemove)try{await this.remove(entry.packageName,hostServices),results.push({packageName:entry.packageName,success:!0})}catch(err){results.push({packageName:entry.packageName,success:!1,error:err instanceof Error?err.message:String(err)})}return results}async remove(packageName,hostServices){packageName=validatePluginPackageName(packageName),getDaemonProfile().logger.info("plugin-manager",`Removing ${packageName}...`);let plugin=this.loaded.get(packageName);if(plugin?.onServerStop)try{await plugin.onServerStop()}catch(err){getDaemonProfile().logger.warn("plugin-manager",`Error stopping ${packageName}: ${err}`)}if(plugin)hostServices?.serviceRegistry.unregisterPlugin(plugin.name),this.loaded.delete(packageName);let registryEntry=this.registry.find((e)=>e.packageName===packageName);if(!plugin&®istryEntry)hostServices?.serviceRegistry.unregisterPlugin(registryEntry.pluginName);let localDir=join2(getVibecontrolsDir(),"agent-plugins");try{if(existsSync2(join2(localDir,"package.json")))Bun.spawnSync(["bun","remove",packageName],{cwd:localDir,timeout:60000,stdout:"pipe",stderr:"pipe"})}catch{}try{Bun.spawnSync(["bun","remove","-g",packageName],{timeout:60000,stdout:"pipe",stderr:"pipe"})}catch{try{Bun.spawnSync(["npm","uninstall","-g",packageName],{timeout:60000,stdout:"pipe",stderr:"pipe"})}catch{}}this.pluginRoots=void 0,this.registry=this.registry.filter((e)=>e.packageName!==packageName),this.saveRegistry(),getDaemonProfile().logger.info("plugin-manager",`Removed ${packageName}`)}async loadAll(){this.loaded.clear();let stale=[];for(let entry of this.registry)try{validatePluginPackageName(entry.packageName),await this.importPlugin(entry.packageName),getDaemonProfile().logger.info("plugin-manager",`Loaded ${entry.packageName} (${entry.pluginName})`)}catch(err){let code=err.code;if(code==="ENOENT_PLUGIN")getDaemonProfile().logger.info("plugin-manager",`${entry.packageName} not present on disk \u2014 dropping from registry`),stale.push(entry.packageName);else if(code==="EPLUGIN_LEGACY_SINGLETON")getDaemonProfile().logger.warn("plugin-manager",`Skipping ${entry.packageName}: ${err instanceof Error?err.message:String(err)}`);else getDaemonProfile().logger.warn("plugin-manager",`Failed to load ${entry.packageName} \u2014 dropping from registry: ${err}`),stale.push(entry.packageName)}if(stale.length>0){this.registry=this.registry.filter((e)=>!stale.includes(e.packageName));try{this.saveRegistry()}catch(err){getDaemonProfile().logger.warn("plugin-manager",`Failed to persist pruned registry: ${err}`)}}}async importPlugin(packageName){packageName=validatePluginPackageName(packageName);let mod={},packageRoot;{let roots=this.getGlobalRoots(),loaded=!1,attempts=[],allMissing=!0;for(let root of roots){let absolutePath=join2(root,packageName);if(!existsSync2(absolutePath)){attempts.push({path:absolutePath,error:"directory missing"});continue}allMissing=!1;try{packageRoot=absolutePath,mod=await import(absolutePath),loaded=!0;break}catch(err){attempts.push({path:absolutePath,error:err instanceof Error?err.message:String(err)})}try{let pkgJsonPath=join2(absolutePath,"package.json");if(!existsSync2(pkgJsonPath)){attempts.push({path:pkgJsonPath,error:"package.json missing"});continue}let pkgJson=JSON.parse(readFileSync2(pkgJsonPath,"utf8")),entry=pkgJson.module??pkgJson.main??"./index.js",filePath=join2(absolutePath,entry);packageRoot=absolutePath,mod=await import(filePath),loaded=!0;break}catch(err){attempts.push({path:absolutePath,error:err instanceof Error?err.message:String(err)})}}if(!loaded)try{packageRoot=this.resolvePackageRoot(packageName)??packageRoot,mod=await import(packageName),loaded=!0}catch(err){attempts.push({path:`bare:${packageName}`,error:err instanceof Error?err.message:String(err)})}if(!loaded){let detail=attempts.map((a)=>`${a.path} (${a.error})`).join("; "),err=Error(`Cannot find module '${packageName}': explicit root attempts and bare import failed: ${detail||"(no roots probed)"}`);if(allMissing&&roots.length>0)err.code="ENOENT_PLUGIN";throw err}}let plugin=this.extractPlugin(mod,`external:${packageName}`,getDaemonProfile());if(!plugin){if(this.hasLegacySingleton(mod)){let err=Error(`${packageName} uses removed singleton contract; upgrade to createPlugin(ctx) factory (set VIBECONTROLS_PLUGIN_CONTRACT_V2_ENFORCE=1 to refuse strictly)`);throw err.code="EPLUGIN_LEGACY_SINGLETON",err}throw Error(`${packageName} does not export a valid createPlugin(ctx) factory`)}if(this.validatePluginExport(plugin,packageName,packageRoot),!this.acceptCapabilities(plugin,`external:${packageName}`))throw Error(`${packageName} refused to load: missing required capabilities declaration`);if(packageRoot)Object.defineProperty(plugin,PLUGIN_PACKAGE_ROOT,{value:packageRoot,enumerable:!1,configurable:!1});if(this.logResolvedPlugin(packageName,plugin.version,packageRoot),this.loaded.set(packageName,plugin),this.shouldIsolate(plugin))try{let ctx=getDaemonProfile(),host=new PluginWorkerHost({modulePath:packageName,pluginName:plugin.name,ctx:{name:ctx.name,dataDir:ctx.dataDir}});await host.start(),this.workerHosts.set(plugin.name,host),ctx.logger.info("plugin-manager",`Isolated plugin '${plugin.name}' running in worker_threads`)}catch(err){getDaemonProfile().logger.warn("plugin-manager",`Failed to isolate plugin '${plugin.name}'; falling back to in-host: ${err instanceof Error?err.message:String(err)}`)}return plugin}resolvePackageRoot(packageName){let meta=import.meta;if(typeof meta.resolve!=="function")return;try{let resolved=meta.resolve(packageName);if(!resolved.startsWith("file:"))return;let current=dirname2(fileURLToPath3(resolved));while(current&¤t!==dirname2(current)){if(existsSync2(join2(current,"package.json")))return current;current=dirname2(current)}}catch{return}return}validatePluginExport(plugin,packageName,packageRoot){if(!PLUGIN_NAME_RE.test(plugin.name))throw Error(`${packageName} exports an invalid plugin name`);if(!plugin.version||plugin.version.length>64)throw Error(`${packageName} exports an invalid plugin version`);if(plugin.description&&plugin.description.length>500)throw Error(`${packageName} description is too long`);if(plugin.cliCommand&&!PLUGIN_NAME_RE.test(plugin.cliCommand))throw Error(`${packageName} exports an invalid CLI command`);if(plugin.apiPrefix){if(!PLUGIN_API_PREFIX_RE.test(plugin.apiPrefix)||plugin.apiPrefix.includes("..")||plugin.apiPrefix.includes("//"))throw Error(`${packageName} exports an invalid API prefix`)}if(plugin.publicPaths){if(plugin.publicPaths.length>20)throw Error(`${packageName} exports too many public paths`);for(let publicPath of plugin.publicPaths)if(!PLUGIN_PUBLIC_PATH_RE.test(publicPath)||publicPath.includes("..")||publicPath.includes("//"))throw Error(`${packageName} exports an invalid public path`)}if(plugin.dependencies&&plugin.dependencies.length>20)throw Error(`${packageName} exports too many dependencies`);if(plugin.tags){let allowedTags=new Set(["backend","frontend","cli","provider","adapter","integration"]);if(plugin.tags.length>allowedTags.size)throw Error(`${packageName} exports too many tags`);for(let tag of plugin.tags)if(!allowedTags.has(tag))throw Error(`${packageName} exports an invalid tag`)}if(plugin.ui){if(plugin.ui.title&&plugin.ui.title.length>120)throw Error(`${packageName} UI title is too long`);if(plugin.ui.staticDir){if(!packageRoot)throw Error(`${packageName} UI staticDir requires a package root`);let rootReal=realpathSync(packageRoot),staticReal=realpathSync(plugin.ui.staticDir);if(!statSync(staticReal).isDirectory()||!isPathInside(rootReal,staticReal))throw Error(`${packageName} UI staticDir must be inside the plugin package`)}}}pluginRoots;getPluginRoots(){if(this.pluginRoots!==void 0)return this.pluginRoots;let roots=[],seen=new Set,push=(p)=>{if(!p)return;if(seen.has(p))return;if(!existsSync2(p))return;seen.add(p),roots.push(p)};try{let localDir=join2(getVibecontrolsDir(),"agent-plugins","node_modules");push(localDir)}catch{}let extra=process.env.VIBECONTROLS_PLUGIN_ROOTS;if(extra){let rootsDelimiter=process.platform==="win32"?";":":";for(let p of extra.split(rootsDelimiter).map((s)=>s.trim()).filter(Boolean))push(p)}try{let dir=process.cwd(),root=dirname2(dir)===dir?dir:"/";while(dir&&dir!==root&&dir!==dirname2(dir))push(join2(dir,"node_modules")),dir=dirname2(dir)}catch{}try{let dir=dirname2(fileURLToPath3(import.meta.url)),stop=dirname2(dir)===dir?dir:"/";while(dir&&dir!==stop&&dir!==dirname2(dir)){if(existsSync2(join2(dir,"package.json"))){push(join2(dir,"node_modules"));break}dir=dirname2(dir)}}catch{}try{push(join2(osHomedir(),".bun","install","global","node_modules"))}catch{}try{let result=Bun.spawnSync(["npm","root","-g"],{stdout:"pipe",stderr:"pipe",timeout:1e4});if(result.exitCode===0)push(result.stdout.toString().trim())}catch{}return this.pluginRoots=roots,roots}getGlobalRoots(){return this.getPluginRoots()}readInstalledVersion(root,packageName){try{let pkgJsonPath=join2(root,packageName,"package.json");if(!existsSync2(pkgJsonPath))return;let pkg=JSON.parse(readFileSync2(pkgJsonPath,"utf8"));return typeof pkg.version==="string"?pkg.version:void 0}catch{return}}logResolvedPlugin(packageName,loadedVersion,loadedDir){let logger=getDaemonProfile().logger;logger.debug("plugin-manager",`Resolved ${packageName}@${loadedVersion}`,{from:loadedDir??"(bare import)"});try{let shadows=[];for(let root of this.getPluginRoots()){let dir=join2(root,packageName);if(loadedDir&&dir===loadedDir)continue;let ver=this.readInstalledVersion(root,packageName);if(ver&&ver!==loadedVersion)shadows.push(`${dir} (v${ver})`)}if(shadows.length>0)logger.warn("plugin-manager",`${packageName}: loaded v${loadedVersion} but stale duplicate copy(ies) exist at a different version \u2014 these shadow the active copy across reinstalls. Run \`vibe nuke --all\` to purge them.`,{loadedVersion,loadedFrom:loadedDir??"(bare import)",shadows})}catch{}}getNpmGlobalRoot(){let roots=this.getPluginRoots();return roots.length>0?roots[0]:null}extractPlugin(mod,label,ctx){let factory=this.findFactory(mod);if(factory){let plugin=factory(ctx);if(!this.isVibePlugin(plugin))throw Error(`plugin '${label}' createPlugin(ctx) factory returned an invalid VibePlugin`);return plugin}if(this.hasLegacySingleton(mod)){let message=`plugin '${label}' uses removed singleton contract; upgrade to createPlugin(ctx) factory`;if(pluginContractV2EnforceMode())throw Error(message);getDaemonProfile().logger.warn("plugin-manager",message);return}return}findFactory(mod){if(typeof mod.createPlugin==="function")return mod.createPlugin;let defaultExport=mod.default;if(defaultExport&&typeof defaultExport.createPlugin==="function")return defaultExport.createPlugin;return}hasLegacySingleton(mod){if(this.isVibePlugin(mod.vibePlugin))return!0;let defaultExport=mod.default;if(defaultExport&&this.isVibePlugin(defaultExport.vibePlugin))return!0;if(this.isVibePlugin(defaultExport))return!0;return!1}isVibePlugin(value){if(!value||typeof value!=="object")return!1;let candidate=value;return typeof candidate.name==="string"&&typeof candidate.version==="string"}registerProviders(plugin,hostServices){this.registerPluginProviders(plugin,hostServices)}registerPluginProviders(plugin,hostServices){let isDefault=getCatalogEntry2(plugin.name)?.isDefault===!0,pinDefault=(type)=>{if(!isDefault)return;hostServices.serviceRegistry.setProviderDefault(type,plugin.name)};if(plugin.providers?.tunnel){if(hostServices.serviceRegistry.registerProvider("tunnel",plugin.providers.tunnel,plugin.name),pinDefault("tunnel"),plugin.tunnelDomainSuffixes)for(let suffix of plugin.tunnelDomainSuffixes)registerAllowedTunnelSuffix(suffix)}if(plugin.providers?.session)hostServices.serviceRegistry.registerProvider("session",plugin.providers.session,plugin.name),pinDefault("session");if(plugin.providers?.ai)hostServices.serviceRegistry.registerProvider("ai",plugin.providers.ai,plugin.name),pinDefault("ai")}async dispatchCliSetup(program,hostServices){for(let plugin of this.getAllPlugins())if(plugin.onCliSetup)try{await plugin.onCliSetup(program,this.wrapHostServices(plugin,hostServices))}catch(err){getDaemonProfile().logger.warn("plugin-manager",`onCliSetup failed for ${plugin.name}: ${err}`)}}async dispatchServerStart(app,hostServices){let sorted=this.sortAllByDependencies(),failures=[];for(let plugin of sorted){if(this.registerPluginProviders(plugin,hostServices),plugin.onServerStart){let startedAt=Date.now();try{await plugin.onServerStart(app,this.wrapHostServices(plugin,hostServices)),(async()=>{try{let{telemetryService}=await import("./telemetry-rew0mtj2.js");telemetryService.emit("plugin.activated",{plugin_name:plugin.name,version:plugin.version,duration_ms:Date.now()-startedAt})}catch{}})()}catch(err){let message=err instanceof Error?err.message:String(err);getDaemonProfile().logger.error("plugin-manager",`onServerStart failed for ${plugin.name}: ${message}`),(async()=>{try{let{telemetryService}=await import("./telemetry-rew0mtj2.js");telemetryService.emit("plugin.failed",{plugin_name:plugin.name,error_class:err instanceof Error?err.constructor.name:"Error"})}catch{}})();let entry=this.registry.find((e)=>e.pluginName===plugin.name);failures.push({plugin:plugin.name,packageName:entry?.packageName,error:message})}}this.registerPluginProviders(plugin,hostServices)}return{failures}}async dispatchServerReady(app,hostServices){for(let plugin of this.getAllPlugins())if(plugin.onServerReady)try{await plugin.onServerReady(app,this.wrapHostServices(plugin,hostServices))}catch(err){getDaemonProfile().logger.warn("plugin-manager",`onServerReady failed for ${plugin.name}: ${err}`)}}async provisionDefaultPrereqs(app,hostServices){let{runPluginPrereqs}=await import("./prereqs-runner-k85knvak.js"),skipInstall=process.env.VIBE_SKIP_PREREQ_INSTALL==="1",platform=process.platform;getDaemonProfile().logger.info("plugin-manager",`Provisioning default providers \u2014 agent build v${getAgentVersion()}, platform=${platform}, pluginInstallMode=${getInstallMode()}, skipInstall=${skipInstall}`);let newlyInstalled=[],metaPkgs=getDefaultPluginsForPlatform(process.platform).map((p)=>p.packageName);if(!skipInstall)for(let pkg of metaPkgs){if(this.loaded.has(pkg))continue;try{getDaemonProfile().logger.info("plugin-manager",`Installing default meta ${pkg}`),await this.install(pkg,{refreshLatest:!0}),newlyInstalled.push(pkg)}catch(err){getDaemonProfile().logger.warn("plugin-manager",`Failed to install default meta ${pkg}: ${err}`)}}let providerPkgs=new Set;for(let[metaPkg,metaPlugin]of this.getAllLoaded()){let mps=metaPlugin.metaProviders??[];if(mps.length>0)getDaemonProfile().logger.info("plugin-manager",`Meta ${metaPkg} declares ${mps.length} provider(s) (platform=${platform})`);for(let prov of mps)if(prov.defaultOn?.includes(platform))providerPkgs.add(prov.packageName)}if(getDaemonProfile().logger.info("plugin-manager",`Default providers for ${platform}: ${[...providerPkgs].join(", ")||"(none)"}`),!skipInstall)for(let pkg of providerPkgs){if(this.loaded.has(pkg))continue;try{getDaemonProfile().logger.info("plugin-manager",`Installing default provider ${pkg} (declared by a meta plugin)`),await this.install(pkg,{refreshLatest:!0}),newlyInstalled.push(pkg)}catch(err){getDaemonProfile().logger.warn("plugin-manager",`Failed to install default provider ${pkg}: ${err}`)}}let defaults=new Set([...metaPkgs,...providerPkgs]);for(let[packageName,plugin]of this.getAllLoaded()){if(!defaults.has(packageName))continue;try{let r=await runPluginPrereqs(plugin,packageName,app,this.db??null,{skipInstall});if(!r.noProtocol&&!r.satisfied){let pending=r.pendingSudo.map((p)=>p.name).join(", ")||"none";getDaemonProfile().logger.warn("plugin-manager",`${packageName}: prerequisites still unsatisfied after install (pendingSudo: ${pending})`)}}catch(err){getDaemonProfile().logger.warn("plugin-manager",`${packageName}: prereq provisioning failed: ${err}`)}}for(let pkg of newlyInstalled){let plugin=this.loaded.get(pkg);if(!plugin)continue;try{this.registerPluginProviders(plugin,hostServices);let wrapped=this.wrapHostServices(plugin,hostServices);if(plugin.onServerStart)await plugin.onServerStart(app,wrapped);if(plugin.onServerReady)await plugin.onServerReady(app,wrapped)}catch(err){getDaemonProfile().logger.warn("plugin-manager",`${pkg}: provider start failed: ${err}`)}}await this.electPlatformDefaultProviders(hostServices,platform)}inferProviderTypeForPlugin(hostServices,pluginName){for(let type of PROVIDER_TYPES)if(hostServices.serviceRegistry.listProvidersForType(type).some((e)=>e.pluginName===pluginName))return type;return}async electPlatformDefaultProviders(hostServices,platform){for(let[,metaPlugin]of this.getAllLoaded())for(let prov of metaPlugin.metaProviders??[]){if(!prov.pluginName)continue;if(!prov.defaultOn?.includes(platform))continue;let type=prov.providerType??this.inferProviderTypeForPlugin(hostServices,prov.pluginName);if(!type)continue;if(!hostServices.serviceRegistry.listProvidersForType(type).some((e)=>e.pluginName===prov.pluginName))continue;try{let existing=await this.getDefaultProvider(type);if(existing&&existing!==prov.pluginName)continue;if(hostServices.serviceRegistry.setProviderDefault(type,prov.pluginName),!existing)await this.setDefaultProvider(type,prov.pluginName).catch(()=>{});getDaemonProfile().logger.info("plugin-manager",`Elected platform-default '${type}' provider '${prov.pluginName}' for ${platform}`)}catch(err){getDaemonProfile().logger.warn("plugin-manager",`Failed to elect default '${type}' provider '${prov.pluginName}': ${err}`)}}}async dispatchServerStop(context){for(let plugin of this.getAllPlugins())if(plugin.onServerStop)try{await plugin.onServerStop(context)}catch(err){getDaemonProfile().logger.warn("plugin-manager",`onServerStop failed for ${plugin.name}: ${err}`)}}async runPluginNuke(packageName,hostServices,ctx){let targets=packageName?this.loaded.has(packageName)?[[packageName,this.loaded.get(packageName)]]:[]:Array.from(this.loaded.entries()),results=[];for(let[pkg,plugin]of targets){if(!plugin.onNuke)continue;try{let wrapped=this.wrapHostServices(plugin,hostServices),out=await plugin.onNuke(wrapped,ctx);results.push({plugin:pkg,ok:!0,reaped:out?.reaped??[],notes:out?.notes??[]}),getDaemonProfile().logger.info("plugin-manager",`onNuke ${ctx.dryRun?"(dry-run) ":""}completed for ${pkg}`,{reaped:out?.reaped??[]})}catch(err){let msg=err instanceof Error?err.message:String(err);results.push({plugin:pkg,ok:!1,reaped:[],notes:[],error:msg}),getDaemonProfile().logger.warn("plugin-manager",`onNuke failed for ${pkg}: ${msg}`)}}return{results}}async reloadAll(app,hostServices){await this.dispatchServerStop({reason:"reload"});for(let plugin of this.loaded.values())hostServices.serviceRegistry.unregisterPlugin(plugin.name);this.loaded.clear(),this.corePlugins.clear(),this.loadRegistry(),await this.loadCorePlugins(),await this.loadAll(),await this.dispatchServerStart(app,hostServices),await this.dispatchServerReady(app,hostServices)}sortAllByDependencies(){let allPlugins=this.getAllPlugins(),pluginMap=new Map;for(let plugin of allPlugins)pluginMap.set(plugin.name,plugin);let visited=new Set,visiting=new Set,sorted=[],visit=(name)=>{if(visited.has(name))return;if(visiting.has(name))throw Error(`Plugin dependency cycle detected at '${name}'`);let plugin=pluginMap.get(name);if(!plugin)return;if(visiting.add(name),plugin.dependencies)for(let dep of plugin.dependencies){if(!pluginMap.has(dep)){getDaemonProfile().logger.warn("plugin-manager",`Plugin '${plugin.name}' depends on missing plugin '${dep}'`);continue}visit(dep)}visiting.delete(name),visited.add(name),sorted.push(plugin)};for(let plugin of allPlugins)visit(plugin.name);return sorted}sortByDependencies(){let entries=Array.from(this.loaded.entries()),nameToPackage=new Map;for(let[pkg,plugin]of entries)nameToPackage.set(plugin.name,pkg);let visited=new Set,sorted=[],visit=(pkg)=>{if(visited.has(pkg))return;visited.add(pkg);let plugin=this.loaded.get(pkg);if(plugin?.dependencies)for(let dep of plugin.dependencies){let depPkg=nameToPackage.get(dep);if(depPkg&&this.loaded.has(depPkg))visit(depPkg)}let loadedPlugin=this.loaded.get(pkg);if(loadedPlugin)sorted.push([pkg,loadedPlugin])};for(let[pkg]of entries)visit(pkg);return sorted}getPluginByKey(key){for(let[,plugin]of this.loaded)if(plugin.name===key)return plugin;return this.corePlugins.get(key)}getAllPlugins(){let merged=new Map;for(let[key,plugin]of this.corePlugins)merged.set(key,plugin);for(let[,plugin]of this.loaded)merged.set(plugin.name,plugin);return Array.from(merged.values())}getAllPluginsByTag(tag){return this.getAllPlugins().filter((plugin)=>plugin.tags?.includes(tag)??!1)}resolvePluginChain(tokens){let allKeys=new Set;for(let p of this.getAllPlugins())allKeys.add(p.name);let chain=[],commandIdx=-1;for(let i=0;i<tokens.length;i++){if(tokens[i].startsWith("-")){commandIdx=i;break}if(allKeys.has(tokens[i]))chain.push(tokens[i]);else{commandIdx=i;break}}if(commandIdx===-1)return{chain,command:"",args:[]};return{chain,command:tokens[commandIdx],args:tokens.slice(commandIdx+1)}}async getDefaultProvider(type){if(!this.db)return null;return await this.db.getConfig(`${PROVIDER_DEFAULT_PREFIX}${type}`)??null}async setDefaultProvider(type,pluginName){if(!this.db)throw Error("Cannot set default provider: PluginManager was constructed without a database reference");if(!this.getPluginByKey(pluginName))throw Error(`Plugin '${pluginName}' not found`);await this.db.setConfig(`${PROVIDER_DEFAULT_PREFIX}${type}`,pluginName),getDaemonProfile().logger.info("plugin-manager",`Set default '${type}' provider to '${pluginName}'`)}getPluginDetails(){let coreInfos=this.getCorePluginDetails(),externalInfos=this.getExternalPluginDetails(),merged=new Map;for(let info of coreInfos)merged.set(info.pluginName,info);for(let info of externalInfos)merged.set(info.pluginName,info);return Array.from(merged.values())}getCorePluginDetails(){let infos=[];for(let[name,plugin]of this.corePlugins)infos.push({packageName:`@vibecontrols/plugin-${name}`,pluginName:name,version:plugin.version,description:plugin.description,tags:plugin.tags,cliCommand:plugin.cliCommand,apiPrefix:plugin.apiPrefix,dependencies:plugin.dependencies,installedAt:"",loaded:!0,isCore:!0,hasUI:!!plugin.ui,uiUrl:plugin.ui?`/ui/${name}`:void 0,hasCliSetup:!!plugin.onCliSetup,hasServerStart:!!plugin.onServerStart,hasServerStop:!!plugin.onServerStop,hasServerReady:!!plugin.onServerReady,hasProviders:!!(plugin.providers?.tunnel||plugin.providers?.session||plugin.providers?.ai)});return infos}getExternalPluginDetails(){return this.registry.map((entry)=>{let plugin=this.loaded.get(entry.packageName),catalogEntry=getCatalogEntry2(entry.pluginName);return{packageName:entry.packageName,pluginName:entry.pluginName,version:plugin?.version??entry.version,description:plugin?.description,tags:plugin?.tags,cliCommand:plugin?.cliCommand,apiPrefix:plugin?.apiPrefix,dependencies:plugin?.dependencies,installedAt:entry.installedAt,loaded:!!plugin,isCore:catalogEntry?.isCore===!0,hasUI:!!plugin?.ui,uiUrl:plugin?.ui?`/ui/${entry.pluginName}`:void 0,hasCliSetup:!!plugin?.onCliSetup,hasServerStart:!!plugin?.onServerStart,hasServerStop:!!plugin?.onServerStop,hasServerReady:!!plugin?.onServerReady,hasProviders:!!(plugin?.providers?.tunnel||plugin?.providers?.session||plugin?.providers?.ai)}})}getRegistry(){return[...this.registry]}getLoaded(packageName){return this.loaded.get(packageName)}getAllLoaded(){return new Map(this.loaded)}isInstalled(packageName){return this.registry.some((e)=>e.packageName===packageName)}isLoaded(packageName){return this.loaded.has(packageName)}}
|
|
3
|
+
`,{encoding:"utf-8",mode:384}),renameSync(tmpFile,registryFile)}async loadCorePlugins(){let coreModules=await Promise.allSettled([import("./index-4s5hv6a7.js"),import("./index-0n663tk5.js"),import("./index-m483e746.js"),import("./index-e875a6zy.js"),import("./index-yhwmtghn.js"),import("./index-4ymjceh1.js")]),ctx=getDaemonProfile();for(let i=0;i<coreModules.length;i++){let result=coreModules[i],expectedName=CORE_PLUGIN_NAMES[i];if(result.status==="fulfilled"){let mod=result.value,plugin;try{plugin=this.extractPlugin(mod,`core:${expectedName}`,ctx)}catch(err){getDaemonProfile().logger.error("plugin-manager",`Core plugin '${expectedName}' refused to load: ${err instanceof Error?err.message:String(err)}`);continue}if(plugin?.name){if(!this.acceptCapabilities(plugin,`core:${expectedName}`))continue;this.corePlugins.set(plugin.name,plugin),getDaemonProfile().logger.info("plugin-manager",`Core plugin loaded: ${plugin.name} v${plugin.version}`)}else getDaemonProfile().logger.warn("plugin-manager",`Core plugin '${expectedName}' did not export a valid createPlugin(ctx) factory`)}else getDaemonProfile().logger.warn("plugin-manager",`Failed to load core plugin '${expectedName}': ${result.reason}`)}getDaemonProfile().logger.info("plugin-manager",`Core plugins loaded: ${this.corePlugins.size}/${CORE_PLUGIN_NAMES.length}`)}async resolveConcreteLatest(packageName,registry){try{let url=`${registry.replace(/\/+$/,"")}/${packageName.replace("/","%2F")}`,res=await fetch(url,{headers:{accept:"application/json"},signal:AbortSignal.timeout(20000)});if(!res.ok)return;let latest=(await res.json())["dist-tags"]?.latest;if(typeof latest==="string"&&/^\d+\.\d+\.\d+/.test(latest))return latest}catch{}return}async install(packageName,opts={}){packageName=validatePluginPackageName(packageName);let refreshLatest=opts.refreshLatest===!0;if(getDaemonProfile().logger.info("plugin-manager",`Installing ${packageName}${refreshLatest?"@latest (refresh)":""}...`),!refreshLatest)try{await import(packageName),getDaemonProfile().logger.info("plugin-manager",`${packageName} already resolvable \u2014 skipping global install`);let plugin2=await this.importPlugin(packageName),entry2={packageName,version:plugin2.version,pluginName:plugin2.name,installedAt:new Date().toISOString()};return this.registry=this.registry.filter((e)=>e.packageName!==packageName),this.registry.push(entry2),this.saveRegistry(),entry2}catch{}let registry=getPluginRegistry(),installMode=getInstallMode(),concreteLatest=refreshLatest?await this.resolveConcreteLatest(packageName,registry):void 0,installSpec=refreshLatest?`${packageName}@${concreteLatest??"latest"}`:packageName;try{if(installMode==="local"){let localDir=join2(getVibecontrolsDir(),"agent-plugins");if(!existsSync2(localDir))mkdirSync(localDir,{recursive:!0});let pkgJsonPath=join2(localDir,"package.json");if(!existsSync2(pkgJsonPath))writeFileSync(pkgJsonPath,JSON.stringify({name:"vibecontrols-agent-plugins",private:!0,version:"0.0.0",dependencies:{}},null,2)+`
|
|
4
|
+
`);if(refreshLatest&&concreteLatest){let installedVer=this.readInstalledVersion(join2(localDir,"node_modules"),packageName);if(installedVer&&installedVer!==concreteLatest){getDaemonProfile().logger.info("plugin-manager",`Pre-clean ${packageName}: on-disk v${installedVer} != target v${concreteLatest} \u2014 removing stale copy + lockfile to force fresh resolve`);try{rmSync(join2(localDir,"node_modules",packageName),{recursive:!0,force:!0})}catch{}try{rmSync(join2(localDir,"bun.lock"),{force:!0}),rmSync(join2(localDir,"bun.lockb"),{force:!0})}catch{}}try{rmSync(join2(localDir,"bun.lock"),{force:!0}),rmSync(join2(localDir,"bun.lockb"),{force:!0})}catch{}}if(Bun.spawnSync(["bun","add",installSpec,"--registry",registry],{cwd:localDir,timeout:120000,stdout:"pipe",stderr:"pipe"}).exitCode!==0){let npmResult=Bun.spawnSync(["npm","install",installSpec,"--registry",registry],{cwd:localDir,timeout:120000,stdout:"pipe",stderr:"pipe"});if(npmResult.exitCode!==0)throw Error(npmResult.stderr.toString().trim())}if(refreshLatest&&concreteLatest){let installedVer=this.readInstalledVersion(join2(localDir,"node_modules"),packageName);if(installedVer!==concreteLatest){getDaemonProfile().logger.warn("plugin-manager",`bun kept ${packageName}@${installedVer??"missing"} after requesting ${concreteLatest}; retrying with npm after removing stale local copy`);try{rmSync(join2(localDir,"node_modules",packageName),{recursive:!0,force:!0}),rmSync(join2(localDir,"bun.lock"),{force:!0}),rmSync(join2(localDir,"bun.lockb"),{force:!0}),rmSync(join2(localDir,"package-lock.json"),{force:!0})}catch{}let npmResult=Bun.spawnSync(["npm","install",installSpec,"--registry",registry,"--save-exact"],{cwd:localDir,timeout:120000,stdout:"pipe",stderr:"pipe"});if(npmResult.exitCode!==0)throw Error(npmResult.stderr.toString().trim())}}}else if(Bun.spawnSync(["bun","install","-g",installSpec,"--registry",registry],{timeout:120000,stdout:"pipe",stderr:"pipe"}).exitCode!==0){let npmResult=Bun.spawnSync(["npm","install","-g",installSpec,"--registry",registry],{timeout:120000,stdout:"pipe",stderr:"pipe"});if(npmResult.exitCode!==0)throw Error(npmResult.stderr.toString().trim())}this.pluginRoots=void 0}catch(err){let message=err instanceof Error?err.message:String(err);if(refreshLatest)try{await import(packageName),getDaemonProfile().logger.warn("plugin-manager",`Could not refresh ${packageName} to @latest (${message}); using the already-installed copy`),this.pluginRoots=void 0;let plugin2=await this.importPlugin(packageName),entry2={packageName,version:plugin2.version,pluginName:plugin2.name,installedAt:new Date().toISOString()};return this.registry=this.registry.filter((e)=>e.packageName!==packageName),this.registry.push(entry2),this.saveRegistry(),entry2}catch{}throw Error(`Failed to install ${packageName}: ${message}`,{cause:err})}let plugin=await this.importPlugin(packageName);if(refreshLatest&&concreteLatest&&plugin.version!==concreteLatest)getDaemonProfile().logger.warn("plugin-manager",`${packageName} refreshed to ${plugin.version} but registry latest is ${concreteLatest} \u2014 a stale resolver/cache may still be in play`);if(this.corePlugins.has(plugin.name))getDaemonProfile().logger.info("plugin-manager",`External plugin '${packageName}' overrides core plugin '${plugin.name}'`);let entry={packageName,version:plugin.version,pluginName:plugin.name,installedAt:new Date().toISOString()};return this.registry=this.registry.filter((e)=>e.packageName!==packageName),this.registry.push(entry),this.saveRegistry(),getDaemonProfile().logger.info("plugin-manager",`Installed ${packageName}@${plugin.version} (${plugin.name})`),entry}async ensureDefaultPlugins(onStatus,skipPlugins=[],selectedAbilities){let installed=[],skipSet=new Set(skipPlugins),entries=selectedAbilities?getDefaultPluginsForAbilities(process.platform,selectedAbilities):getDefaultPluginsForPlatform(process.platform);for(let entry of entries){if(skipSet.has(entry.packageName)||skipSet.has(entry.pluginName)){getDaemonProfile().logger.info("plugin-manager",`${entry.packageName} skipped by --skip-plugin`);continue}if(entry.isCore&&entry.category==="core"){getDaemonProfile().logger.info("plugin-manager",`${entry.packageName} is bundled with the agent \u2014 skipping auto-install`);continue}if(this.registry.some((r)=>r.packageName===entry.packageName)){getDaemonProfile().logger.info("plugin-manager",`${entry.packageName} already installed, skipping auto-install`);continue}onStatus?.(`Installing ${entry.label} (${entry.packageName})...`);try{await this.install(entry.packageName,{refreshLatest:!0}),installed.push(entry),onStatus?.(`Installed ${entry.label} (${entry.packageName})`)}catch(err){let message=err instanceof Error?err.message:String(err);getDaemonProfile().logger.error("plugin-manager",`Failed to auto-install ${entry.packageName}: ${message}`),onStatus?.(`Failed to install ${entry.label}: ${message}`)}}if(installed.length>0)this.loadRegistry();return installed}async installAndLoad(packageName,app,hostServices){let entry=await this.install(packageName),plugin=this.loaded.get(entry.packageName);if(plugin){this.registerPluginProviders(plugin,hostServices);let wrapped=this.wrapHostServices(plugin,hostServices);if(plugin.onServerStart)await plugin.onServerStart(app,wrapped);if(plugin.onServerReady)await plugin.onServerReady(app,wrapped)}return entry}async update(packageName){packageName=validatePluginPackageName(packageName),getDaemonProfile().logger.info("plugin-manager",`Updating ${packageName}...`);let existing=this.registry.find((e)=>e.packageName===packageName);if(!existing)throw Error(`Plugin ${packageName} is not installed. Use 'install' first.`);let registry=getPluginRegistry();try{if(Bun.spawnSync(["bun","install","-g",`${packageName}@latest`,"--registry",registry],{timeout:120000,stdout:"pipe",stderr:"pipe"}).exitCode!==0){let npmResult=Bun.spawnSync(["npm","install","-g",`${packageName}@latest`,"--registry",registry],{timeout:120000,stdout:"pipe",stderr:"pipe"});if(npmResult.exitCode!==0)throw Error(npmResult.stderr.toString().trim())}}catch(err){let message=err instanceof Error?err.message:String(err);throw Error(`Failed to update ${packageName}: ${message}`,{cause:err})}this.loaded.delete(packageName);let plugin=await this.importPlugin(packageName),entry={packageName,version:plugin.version,pluginName:plugin.name,installedAt:existing.installedAt};return this.registry=this.registry.filter((e)=>e.packageName!==packageName),this.registry.push(entry),this.saveRegistry(),getDaemonProfile().logger.info("plugin-manager",`Updated ${packageName} to v${plugin.version}`),entry}async updateAll(){let results=[];for(let entry of[...this.registry])try{let updated=await this.update(entry.packageName);results.push({packageName:entry.packageName,success:!0,version:updated.version})}catch(err){results.push({packageName:entry.packageName,success:!1,error:err instanceof Error?err.message:String(err)})}return results}async removeAll(hostServices){let results=[],toRemove=[...this.registry];for(let entry of toRemove)try{await this.remove(entry.packageName,hostServices),results.push({packageName:entry.packageName,success:!0})}catch(err){results.push({packageName:entry.packageName,success:!1,error:err instanceof Error?err.message:String(err)})}return results}async remove(packageName,hostServices){packageName=validatePluginPackageName(packageName),getDaemonProfile().logger.info("plugin-manager",`Removing ${packageName}...`);let plugin=this.loaded.get(packageName);if(plugin?.onServerStop)try{await plugin.onServerStop()}catch(err){getDaemonProfile().logger.warn("plugin-manager",`Error stopping ${packageName}: ${err}`)}if(plugin)hostServices?.serviceRegistry.unregisterPlugin(plugin.name),this.loaded.delete(packageName);let registryEntry=this.registry.find((e)=>e.packageName===packageName);if(!plugin&®istryEntry)hostServices?.serviceRegistry.unregisterPlugin(registryEntry.pluginName);let localDir=join2(getVibecontrolsDir(),"agent-plugins");try{if(existsSync2(join2(localDir,"package.json")))Bun.spawnSync(["bun","remove",packageName],{cwd:localDir,timeout:60000,stdout:"pipe",stderr:"pipe"})}catch{}try{Bun.spawnSync(["bun","remove","-g",packageName],{timeout:60000,stdout:"pipe",stderr:"pipe"})}catch{try{Bun.spawnSync(["npm","uninstall","-g",packageName],{timeout:60000,stdout:"pipe",stderr:"pipe"})}catch{}}this.pluginRoots=void 0,this.registry=this.registry.filter((e)=>e.packageName!==packageName),this.saveRegistry(),getDaemonProfile().logger.info("plugin-manager",`Removed ${packageName}`)}async loadAll(){this.loaded.clear();let stale=[];for(let entry of this.registry)try{validatePluginPackageName(entry.packageName),await this.importPlugin(entry.packageName),getDaemonProfile().logger.info("plugin-manager",`Loaded ${entry.packageName} (${entry.pluginName})`)}catch(err){let code=err.code;if(code==="ENOENT_PLUGIN")getDaemonProfile().logger.info("plugin-manager",`${entry.packageName} not present on disk \u2014 dropping from registry`),stale.push(entry.packageName);else if(code==="EPLUGIN_LEGACY_SINGLETON")getDaemonProfile().logger.warn("plugin-manager",`Skipping ${entry.packageName}: ${err instanceof Error?err.message:String(err)}`);else getDaemonProfile().logger.warn("plugin-manager",`Failed to load ${entry.packageName} \u2014 dropping from registry: ${err}`),stale.push(entry.packageName)}if(stale.length>0){this.registry=this.registry.filter((e)=>!stale.includes(e.packageName));try{this.saveRegistry()}catch(err){getDaemonProfile().logger.warn("plugin-manager",`Failed to persist pruned registry: ${err}`)}}}async importPlugin(packageName){packageName=validatePluginPackageName(packageName);let mod={},packageRoot;{let roots=this.getGlobalRoots(),loaded=!1,attempts=[],allMissing=!0;for(let root of roots){let absolutePath=join2(root,packageName);if(!existsSync2(absolutePath)){attempts.push({path:absolutePath,error:"directory missing"});continue}allMissing=!1;try{packageRoot=absolutePath,mod=await import(absolutePath),loaded=!0;break}catch(err){attempts.push({path:absolutePath,error:err instanceof Error?err.message:String(err)})}try{let pkgJsonPath=join2(absolutePath,"package.json");if(!existsSync2(pkgJsonPath)){attempts.push({path:pkgJsonPath,error:"package.json missing"});continue}let pkgJson=JSON.parse(readFileSync2(pkgJsonPath,"utf8")),entry=pkgJson.module??pkgJson.main??"./index.js",filePath=join2(absolutePath,entry);packageRoot=absolutePath,mod=await import(filePath),loaded=!0;break}catch(err){attempts.push({path:absolutePath,error:err instanceof Error?err.message:String(err)})}}if(!loaded)try{packageRoot=this.resolvePackageRoot(packageName)??packageRoot,mod=await import(packageName),loaded=!0}catch(err){attempts.push({path:`bare:${packageName}`,error:err instanceof Error?err.message:String(err)})}if(!loaded){let detail=attempts.map((a)=>`${a.path} (${a.error})`).join("; "),err=Error(`Cannot find module '${packageName}': explicit root attempts and bare import failed: ${detail||"(no roots probed)"}`);if(allMissing&&roots.length>0)err.code="ENOENT_PLUGIN";throw err}}let plugin=this.extractPlugin(mod,`external:${packageName}`,getDaemonProfile());if(!plugin){if(this.hasLegacySingleton(mod)){let err=Error(`${packageName} uses removed singleton contract; upgrade to createPlugin(ctx) factory (set VIBECONTROLS_PLUGIN_CONTRACT_V2_ENFORCE=1 to refuse strictly)`);throw err.code="EPLUGIN_LEGACY_SINGLETON",err}throw Error(`${packageName} does not export a valid createPlugin(ctx) factory`)}if(this.validatePluginExport(plugin,packageName,packageRoot),!this.acceptCapabilities(plugin,`external:${packageName}`))throw Error(`${packageName} refused to load: missing required capabilities declaration`);if(packageRoot)Object.defineProperty(plugin,PLUGIN_PACKAGE_ROOT,{value:packageRoot,enumerable:!1,configurable:!1});if(this.logResolvedPlugin(packageName,plugin.version,packageRoot),this.loaded.set(packageName,plugin),this.shouldIsolate(plugin))try{let ctx=getDaemonProfile(),host=new PluginWorkerHost({modulePath:packageName,pluginName:plugin.name,ctx:{name:ctx.name,dataDir:ctx.dataDir}});await host.start(),this.workerHosts.set(plugin.name,host),ctx.logger.info("plugin-manager",`Isolated plugin '${plugin.name}' running in worker_threads`)}catch(err){getDaemonProfile().logger.warn("plugin-manager",`Failed to isolate plugin '${plugin.name}'; falling back to in-host: ${err instanceof Error?err.message:String(err)}`)}return plugin}resolvePackageRoot(packageName){let meta=import.meta;if(typeof meta.resolve!=="function")return;try{let resolved=meta.resolve(packageName);if(!resolved.startsWith("file:"))return;let current=dirname2(fileURLToPath3(resolved));while(current&¤t!==dirname2(current)){if(existsSync2(join2(current,"package.json")))return current;current=dirname2(current)}}catch{return}return}validatePluginExport(plugin,packageName,packageRoot){if(!PLUGIN_NAME_RE.test(plugin.name))throw Error(`${packageName} exports an invalid plugin name`);if(!plugin.version||plugin.version.length>64)throw Error(`${packageName} exports an invalid plugin version`);if(plugin.description&&plugin.description.length>500)throw Error(`${packageName} description is too long`);if(plugin.cliCommand&&!PLUGIN_NAME_RE.test(plugin.cliCommand))throw Error(`${packageName} exports an invalid CLI command`);if(plugin.apiPrefix){if(!PLUGIN_API_PREFIX_RE.test(plugin.apiPrefix)||plugin.apiPrefix.includes("..")||plugin.apiPrefix.includes("//"))throw Error(`${packageName} exports an invalid API prefix`)}if(plugin.publicPaths){if(plugin.publicPaths.length>20)throw Error(`${packageName} exports too many public paths`);for(let publicPath of plugin.publicPaths)if(!PLUGIN_PUBLIC_PATH_RE.test(publicPath)||publicPath.includes("..")||publicPath.includes("//"))throw Error(`${packageName} exports an invalid public path`)}if(plugin.dependencies&&plugin.dependencies.length>20)throw Error(`${packageName} exports too many dependencies`);if(plugin.tags){let allowedTags=new Set(["backend","frontend","cli","provider","adapter","integration"]);if(plugin.tags.length>allowedTags.size)throw Error(`${packageName} exports too many tags`);for(let tag of plugin.tags)if(!allowedTags.has(tag))throw Error(`${packageName} exports an invalid tag`)}if(plugin.ui){if(plugin.ui.title&&plugin.ui.title.length>120)throw Error(`${packageName} UI title is too long`);if(plugin.ui.staticDir){if(!packageRoot)throw Error(`${packageName} UI staticDir requires a package root`);let rootReal=realpathSync(packageRoot),staticReal=realpathSync(plugin.ui.staticDir);if(!statSync(staticReal).isDirectory()||!isPathInside(rootReal,staticReal))throw Error(`${packageName} UI staticDir must be inside the plugin package`)}}}pluginRoots;getPluginRoots(){if(this.pluginRoots!==void 0)return this.pluginRoots;let roots=[],seen=new Set,push=(p)=>{if(!p)return;if(seen.has(p))return;if(!existsSync2(p))return;seen.add(p),roots.push(p)};try{let localDir=join2(getVibecontrolsDir(),"agent-plugins","node_modules");push(localDir)}catch{}let extra=process.env.VIBECONTROLS_PLUGIN_ROOTS;if(extra){let rootsDelimiter=process.platform==="win32"?";":":";for(let p of extra.split(rootsDelimiter).map((s)=>s.trim()).filter(Boolean))push(p)}try{let dir=process.cwd(),root=dirname2(dir)===dir?dir:"/";while(dir&&dir!==root&&dir!==dirname2(dir))push(join2(dir,"node_modules")),dir=dirname2(dir)}catch{}try{let dir=dirname2(fileURLToPath3(import.meta.url)),stop=dirname2(dir)===dir?dir:"/";while(dir&&dir!==stop&&dir!==dirname2(dir)){if(existsSync2(join2(dir,"package.json"))){push(join2(dir,"node_modules"));break}dir=dirname2(dir)}}catch{}try{push(join2(osHomedir(),".bun","install","global","node_modules"))}catch{}try{let result=Bun.spawnSync(["npm","root","-g"],{stdout:"pipe",stderr:"pipe",timeout:1e4});if(result.exitCode===0)push(result.stdout.toString().trim())}catch{}return this.pluginRoots=roots,roots}getGlobalRoots(){return this.getPluginRoots()}readInstalledVersion(root,packageName){try{let pkgJsonPath=join2(root,packageName,"package.json");if(!existsSync2(pkgJsonPath))return;let pkg=JSON.parse(readFileSync2(pkgJsonPath,"utf8"));return typeof pkg.version==="string"?pkg.version:void 0}catch{return}}logResolvedPlugin(packageName,loadedVersion,loadedDir){let logger=getDaemonProfile().logger;logger.debug("plugin-manager",`Resolved ${packageName}@${loadedVersion}`,{from:loadedDir??"(bare import)"});try{let shadows=[];for(let root of this.getPluginRoots()){let dir=join2(root,packageName);if(loadedDir&&dir===loadedDir)continue;let ver=this.readInstalledVersion(root,packageName);if(ver&&ver!==loadedVersion)shadows.push(`${dir} (v${ver})`)}if(shadows.length>0)logger.warn("plugin-manager",`${packageName}: loaded v${loadedVersion} but stale duplicate copy(ies) exist at a different version \u2014 these shadow the active copy across reinstalls. Run \`vibe nuke --all\` to purge them.`,{loadedVersion,loadedFrom:loadedDir??"(bare import)",shadows})}catch{}}getNpmGlobalRoot(){let roots=this.getPluginRoots();return roots.length>0?roots[0]:null}extractPlugin(mod,label,ctx){let factory=this.findFactory(mod);if(factory){let plugin=factory(ctx);if(!this.isVibePlugin(plugin))throw Error(`plugin '${label}' createPlugin(ctx) factory returned an invalid VibePlugin`);return plugin}if(this.hasLegacySingleton(mod)){let message=`plugin '${label}' uses removed singleton contract; upgrade to createPlugin(ctx) factory`;if(pluginContractV2EnforceMode())throw Error(message);getDaemonProfile().logger.warn("plugin-manager",message);return}return}findFactory(mod){if(typeof mod.createPlugin==="function")return mod.createPlugin;let defaultExport=mod.default;if(defaultExport&&typeof defaultExport.createPlugin==="function")return defaultExport.createPlugin;return}hasLegacySingleton(mod){if(this.isVibePlugin(mod.vibePlugin))return!0;let defaultExport=mod.default;if(defaultExport&&this.isVibePlugin(defaultExport.vibePlugin))return!0;if(this.isVibePlugin(defaultExport))return!0;return!1}isVibePlugin(value){if(!value||typeof value!=="object")return!1;let candidate=value;return typeof candidate.name==="string"&&typeof candidate.version==="string"}registerProviders(plugin,hostServices){this.registerPluginProviders(plugin,hostServices)}registerPluginProviders(plugin,hostServices){let isDefault=getCatalogEntry2(plugin.name)?.isDefault===!0,pinDefault=(type)=>{if(!isDefault)return;hostServices.serviceRegistry.setProviderDefault(type,plugin.name)};if(plugin.providers?.tunnel){if(hostServices.serviceRegistry.registerProvider("tunnel",plugin.providers.tunnel,plugin.name),pinDefault("tunnel"),plugin.tunnelDomainSuffixes)for(let suffix of plugin.tunnelDomainSuffixes)registerAllowedTunnelSuffix(suffix)}if(plugin.providers?.session)hostServices.serviceRegistry.registerProvider("session",plugin.providers.session,plugin.name),pinDefault("session");if(plugin.providers?.ai)hostServices.serviceRegistry.registerProvider("ai",plugin.providers.ai,plugin.name),pinDefault("ai")}async dispatchCliSetup(program,hostServices){for(let plugin of this.getAllPlugins())if(plugin.onCliSetup)try{await plugin.onCliSetup(program,this.wrapHostServices(plugin,hostServices))}catch(err){getDaemonProfile().logger.warn("plugin-manager",`onCliSetup failed for ${plugin.name}: ${err}`)}}async dispatchServerStart(app,hostServices){let sorted=this.sortAllByDependencies(),failures=[];for(let plugin of sorted){if(this.registerPluginProviders(plugin,hostServices),plugin.onServerStart){let startedAt=Date.now();try{await plugin.onServerStart(app,this.wrapHostServices(plugin,hostServices)),(async()=>{try{let{telemetryService}=await import("./telemetry-rew0mtj2.js");telemetryService.emit("plugin.activated",{plugin_name:plugin.name,version:plugin.version,duration_ms:Date.now()-startedAt})}catch{}})()}catch(err){let message=err instanceof Error?err.message:String(err);getDaemonProfile().logger.error("plugin-manager",`onServerStart failed for ${plugin.name}: ${message}`),(async()=>{try{let{telemetryService}=await import("./telemetry-rew0mtj2.js");telemetryService.emit("plugin.failed",{plugin_name:plugin.name,error_class:err instanceof Error?err.constructor.name:"Error"})}catch{}})();let entry=this.registry.find((e)=>e.pluginName===plugin.name);failures.push({plugin:plugin.name,packageName:entry?.packageName,error:message})}}this.registerPluginProviders(plugin,hostServices)}return{failures}}async dispatchServerReady(app,hostServices){for(let plugin of this.getAllPlugins())if(plugin.onServerReady)try{await plugin.onServerReady(app,this.wrapHostServices(plugin,hostServices))}catch(err){getDaemonProfile().logger.warn("plugin-manager",`onServerReady failed for ${plugin.name}: ${err}`)}}async provisionDefaultPrereqs(app,hostServices,mountPlugin){let{runPluginPrereqs}=await import("./prereqs-runner-k85knvak.js"),skipInstall=process.env.VIBE_SKIP_PREREQ_INSTALL==="1",platform=process.platform;getDaemonProfile().logger.info("plugin-manager",`Provisioning default providers \u2014 agent build v${getAgentVersion()}, platform=${platform}, pluginInstallMode=${getInstallMode()}, skipInstall=${skipInstall}`);let newlyInstalled=[],metaPkgs=getDefaultPluginsForPlatform(process.platform).map((p)=>p.packageName);if(!skipInstall)for(let pkg of metaPkgs){if(this.loaded.has(pkg))continue;try{getDaemonProfile().logger.info("plugin-manager",`Installing default meta ${pkg}`),await this.install(pkg,{refreshLatest:!0}),newlyInstalled.push(pkg)}catch(err){getDaemonProfile().logger.warn("plugin-manager",`Failed to install default meta ${pkg}: ${err}`)}}let providerPkgs=new Set;for(let[metaPkg,metaPlugin]of this.getAllLoaded()){let mps=metaPlugin.metaProviders??[];if(mps.length>0)getDaemonProfile().logger.info("plugin-manager",`Meta ${metaPkg} declares ${mps.length} provider(s) (platform=${platform})`);for(let prov of mps)if(prov.defaultOn?.includes(platform))providerPkgs.add(prov.packageName)}if(getDaemonProfile().logger.info("plugin-manager",`Default providers for ${platform}: ${[...providerPkgs].join(", ")||"(none)"}`),!skipInstall)for(let pkg of providerPkgs){if(this.loaded.has(pkg))continue;try{getDaemonProfile().logger.info("plugin-manager",`Installing default provider ${pkg} (declared by a meta plugin)`),await this.install(pkg,{refreshLatest:!0}),newlyInstalled.push(pkg)}catch(err){getDaemonProfile().logger.warn("plugin-manager",`Failed to install default provider ${pkg}: ${err}`)}}let defaults=new Set([...metaPkgs,...providerPkgs]);for(let[packageName,plugin]of this.getAllLoaded()){if(!defaults.has(packageName))continue;try{let r=await runPluginPrereqs(plugin,packageName,app,this.db??null,{skipInstall});if(!r.noProtocol&&!r.satisfied){let pending=r.pendingSudo.map((p)=>p.name).join(", ")||"none";getDaemonProfile().logger.warn("plugin-manager",`${packageName}: prerequisites still unsatisfied after install (pendingSudo: ${pending})`)}}catch(err){getDaemonProfile().logger.warn("plugin-manager",`${packageName}: prereq provisioning failed: ${err}`)}}for(let pkg of newlyInstalled){let plugin=this.loaded.get(pkg);if(!plugin)continue;try{if(plugin.createRoutes&&mountPlugin?.(plugin))getDaemonProfile().logger.info("plugin-manager",`${pkg}: mounted routes after default provisioning`);this.registerPluginProviders(plugin,hostServices);let wrapped=this.wrapHostServices(plugin,hostServices);if(plugin.onServerStart)await plugin.onServerStart(app,wrapped);if(plugin.onServerReady)await plugin.onServerReady(app,wrapped)}catch(err){getDaemonProfile().logger.warn("plugin-manager",`${pkg}: provider start failed: ${err}`)}}await this.electPlatformDefaultProviders(hostServices,platform)}inferProviderTypeForPlugin(hostServices,pluginName){for(let type of PROVIDER_TYPES)if(hostServices.serviceRegistry.listProvidersForType(type).some((e)=>e.pluginName===pluginName))return type;return}async electPlatformDefaultProviders(hostServices,platform){for(let[,metaPlugin]of this.getAllLoaded())for(let prov of metaPlugin.metaProviders??[]){if(!prov.pluginName)continue;if(!prov.defaultOn?.includes(platform))continue;let type=prov.providerType??this.inferProviderTypeForPlugin(hostServices,prov.pluginName);if(!type)continue;if(!hostServices.serviceRegistry.listProvidersForType(type).some((e)=>e.pluginName===prov.pluginName))continue;try{let existing=await this.getDefaultProvider(type);if(existing&&existing!==prov.pluginName)continue;if(hostServices.serviceRegistry.setProviderDefault(type,prov.pluginName),!existing)await this.setDefaultProvider(type,prov.pluginName).catch(()=>{});getDaemonProfile().logger.info("plugin-manager",`Elected platform-default '${type}' provider '${prov.pluginName}' for ${platform}`)}catch(err){getDaemonProfile().logger.warn("plugin-manager",`Failed to elect default '${type}' provider '${prov.pluginName}': ${err}`)}}}async dispatchServerStop(context){for(let plugin of this.getAllPlugins())if(plugin.onServerStop)try{await plugin.onServerStop(context)}catch(err){getDaemonProfile().logger.warn("plugin-manager",`onServerStop failed for ${plugin.name}: ${err}`)}}async runPluginNuke(packageName,hostServices,ctx){let targets=packageName?this.loaded.has(packageName)?[[packageName,this.loaded.get(packageName)]]:[]:Array.from(this.loaded.entries()),results=[];for(let[pkg,plugin]of targets){if(!plugin.onNuke)continue;try{let wrapped=this.wrapHostServices(plugin,hostServices),out=await plugin.onNuke(wrapped,ctx);results.push({plugin:pkg,ok:!0,reaped:out?.reaped??[],notes:out?.notes??[]}),getDaemonProfile().logger.info("plugin-manager",`onNuke ${ctx.dryRun?"(dry-run) ":""}completed for ${pkg}`,{reaped:out?.reaped??[]})}catch(err){let msg=err instanceof Error?err.message:String(err);results.push({plugin:pkg,ok:!1,reaped:[],notes:[],error:msg}),getDaemonProfile().logger.warn("plugin-manager",`onNuke failed for ${pkg}: ${msg}`)}}return{results}}async reloadAll(app,hostServices){await this.dispatchServerStop({reason:"reload"});for(let plugin of this.loaded.values())hostServices.serviceRegistry.unregisterPlugin(plugin.name);this.loaded.clear(),this.corePlugins.clear(),this.loadRegistry(),await this.loadCorePlugins(),await this.loadAll(),await this.dispatchServerStart(app,hostServices),await this.dispatchServerReady(app,hostServices)}sortAllByDependencies(){let allPlugins=this.getAllPlugins(),pluginMap=new Map;for(let plugin of allPlugins)pluginMap.set(plugin.name,plugin);let visited=new Set,visiting=new Set,sorted=[],visit=(name)=>{if(visited.has(name))return;if(visiting.has(name))throw Error(`Plugin dependency cycle detected at '${name}'`);let plugin=pluginMap.get(name);if(!plugin)return;if(visiting.add(name),plugin.dependencies)for(let dep of plugin.dependencies){if(!pluginMap.has(dep)){getDaemonProfile().logger.warn("plugin-manager",`Plugin '${plugin.name}' depends on missing plugin '${dep}'`);continue}visit(dep)}visiting.delete(name),visited.add(name),sorted.push(plugin)};for(let plugin of allPlugins)visit(plugin.name);return sorted}sortByDependencies(){let entries=Array.from(this.loaded.entries()),nameToPackage=new Map;for(let[pkg,plugin]of entries)nameToPackage.set(plugin.name,pkg);let visited=new Set,sorted=[],visit=(pkg)=>{if(visited.has(pkg))return;visited.add(pkg);let plugin=this.loaded.get(pkg);if(plugin?.dependencies)for(let dep of plugin.dependencies){let depPkg=nameToPackage.get(dep);if(depPkg&&this.loaded.has(depPkg))visit(depPkg)}let loadedPlugin=this.loaded.get(pkg);if(loadedPlugin)sorted.push([pkg,loadedPlugin])};for(let[pkg]of entries)visit(pkg);return sorted}getPluginByKey(key){for(let[,plugin]of this.loaded)if(plugin.name===key)return plugin;return this.corePlugins.get(key)}getAllPlugins(){let merged=new Map;for(let[key,plugin]of this.corePlugins)merged.set(key,plugin);for(let[,plugin]of this.loaded)merged.set(plugin.name,plugin);return Array.from(merged.values())}getAllPluginsByTag(tag){return this.getAllPlugins().filter((plugin)=>plugin.tags?.includes(tag)??!1)}resolvePluginChain(tokens){let allKeys=new Set;for(let p of this.getAllPlugins())allKeys.add(p.name);let chain=[],commandIdx=-1;for(let i=0;i<tokens.length;i++){if(tokens[i].startsWith("-")){commandIdx=i;break}if(allKeys.has(tokens[i]))chain.push(tokens[i]);else{commandIdx=i;break}}if(commandIdx===-1)return{chain,command:"",args:[]};return{chain,command:tokens[commandIdx],args:tokens.slice(commandIdx+1)}}async getDefaultProvider(type){if(!this.db)return null;return await this.db.getConfig(`${PROVIDER_DEFAULT_PREFIX}${type}`)??null}async setDefaultProvider(type,pluginName){if(!this.db)throw Error("Cannot set default provider: PluginManager was constructed without a database reference");if(!this.getPluginByKey(pluginName))throw Error(`Plugin '${pluginName}' not found`);await this.db.setConfig(`${PROVIDER_DEFAULT_PREFIX}${type}`,pluginName),getDaemonProfile().logger.info("plugin-manager",`Set default '${type}' provider to '${pluginName}'`)}getPluginDetails(){let coreInfos=this.getCorePluginDetails(),externalInfos=this.getExternalPluginDetails(),merged=new Map;for(let info of coreInfos)merged.set(info.pluginName,info);for(let info of externalInfos)merged.set(info.pluginName,info);return Array.from(merged.values())}getCorePluginDetails(){let infos=[];for(let[name,plugin]of this.corePlugins)infos.push({packageName:`@vibecontrols/plugin-${name}`,pluginName:name,version:plugin.version,description:plugin.description,tags:plugin.tags,cliCommand:plugin.cliCommand,apiPrefix:plugin.apiPrefix,dependencies:plugin.dependencies,installedAt:"",loaded:!0,isCore:!0,hasUI:!!plugin.ui,uiUrl:plugin.ui?`/ui/${name}`:void 0,hasCliSetup:!!plugin.onCliSetup,hasServerStart:!!plugin.onServerStart,hasServerStop:!!plugin.onServerStop,hasServerReady:!!plugin.onServerReady,hasProviders:!!(plugin.providers?.tunnel||plugin.providers?.session||plugin.providers?.ai)});return infos}getExternalPluginDetails(){return this.registry.map((entry)=>{let plugin=this.loaded.get(entry.packageName),catalogEntry=getCatalogEntry2(entry.pluginName);return{packageName:entry.packageName,pluginName:entry.pluginName,version:plugin?.version??entry.version,description:plugin?.description,tags:plugin?.tags,cliCommand:plugin?.cliCommand,apiPrefix:plugin?.apiPrefix,dependencies:plugin?.dependencies,installedAt:entry.installedAt,loaded:!!plugin,isCore:catalogEntry?.isCore===!0,hasUI:!!plugin?.ui,uiUrl:plugin?.ui?`/ui/${entry.pluginName}`:void 0,hasCliSetup:!!plugin?.onCliSetup,hasServerStart:!!plugin?.onServerStart,hasServerStop:!!plugin?.onServerStop,hasServerReady:!!plugin?.onServerReady,hasProviders:!!(plugin?.providers?.tunnel||plugin?.providers?.session||plugin?.providers?.ai)}})}getRegistry(){return[...this.registry]}getLoaded(packageName){return this.loaded.get(packageName)}getAllLoaded(){return new Map(this.loaded)}isInstalled(packageName){return this.registry.some((e)=>e.packageName===packageName)}isLoaded(packageName){return this.loaded.has(packageName)}}
|
|
5
5
|
export{ServiceRegistry,getAgentVersion,PLUGIN_CATALOG,ABILITIES,CORE_PLUGIN_NAMES,getDefaultPluginsForAbilities,TRUSTED_PACKAGES,isCriticalPlugin,AVAILABLE_PLUGINS,getCatalogEntry,collectPluginBinaries,isTrustedPackage,resolvePluginByShortName,getPluginPackageRoot,validatePluginPackageName,DEFAULT_PLUGINS2 as DEFAULT_PLUGINS,PluginManager};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{CliContributorRegistry,createIframeBridge}from"./index-
|
|
2
|
+
import{CliContributorRegistry,createIframeBridge}from"./index-wk359257.js";import{PluginManager,ServiceRegistry,getAgentVersion}from"./index-cyhcvfxs.js";import{getOsAdapter}from"./index-srbb2214.js";import{mountProfileRoutes}from"./index-brtw3j8x.js";import{getAgentApiKey}from"./index-b4wy3jrt.js";import{readAgentConfigWithSecrets,writeAgentConfig}from"./index-2pqv0bya.js";import{assertAllowedGatewayUrl,gatewayClient,getDaemonProfile,getOrCreateProfile,profileRegistry,sanitizeOperatorTunnelUrl,sanitizeTunnelUrl}from"./index-7pdmqbj8.js";import{getVibecontrolsProductDir,validateAgentName}from"./index-bysm7taq.js";import{__require}from"./index-e9rt4m94.js";var RETRY_BACKOFFS_MS=[0,5000,15000,30000,60000],RATE_LIMIT_BUFFER_MS=2000,RATE_LIMIT_MIN_WAIT_MS=5000,RATE_LIMIT_MAX_WAIT_MS=120000,RATE_LIMIT_MAX_RETRIES=10,MAX_GATEWAY_RESPONSE_BYTES=1048576;class RateLimitError extends Error{resetAt;resource;constructor(message,resource,resetAt){super(message);this.name="RateLimitError",this.resource=resource,this.resetAt=resetAt}}function detectRateLimit(errors,resource){if(!errors?.length)return null;let hit=errors.find((e)=>e.extensions?.code==="RATE_LIMITED");if(!hit)return null;let resetRaw=hit.extensions?.resetAt,resetAt=null;if(resetRaw){let parsed=new Date(resetRaw);if(!Number.isNaN(parsed.getTime()))resetAt=parsed}return new RateLimitError(`${resource} rate limited${resetAt?` until ${resetAt.toISOString()}`:""}`,resource,resetAt)}function computeRateLimitDelay(err){if(!err.resetAt)return 60000;let waitMs=err.resetAt.getTime()-Date.now()+RATE_LIMIT_BUFFER_MS;return Math.min(Math.max(waitMs,RATE_LIMIT_MIN_WAIT_MS),RATE_LIMIT_MAX_WAIT_MS)}async function readResponseTextCapped(response,maxBytes){let contentLength=response.headers.get("content-length");if(contentLength){let parsed=Number.parseInt(contentLength,10);if(Number.isInteger(parsed)&&parsed>maxBytes)throw Error(`Gateway response is too large (${parsed} bytes)`)}if(!response.body)return"";let reader=response.body.getReader(),chunks=[],total=0;try{while(!0){let{done,value}=await reader.read();if(done)break;if(!value)continue;if(total+=value.byteLength,total>maxBytes)throw await reader.cancel().catch(()=>{return}),Error(`Gateway response exceeds ${maxBytes} bytes`);chunks.push(value)}}finally{reader.releaseLock()}let merged=new Uint8Array(total),offset=0;for(let chunk of chunks)merged.set(chunk,offset),offset+=chunk.byteLength;return new TextDecoder().decode(merged)}async function readGraphqlJson(response,resource){let raw=await readResponseTextCapped(response,MAX_GATEWAY_RESPONSE_BYTES),data;try{data=raw?JSON.parse(raw):{}}catch(err){let preview=raw.slice(0,240).replace(/\s+/g," ");throw Error(`${resource} returned non-JSON response (${response.status} ${response.statusText})${preview?`: ${preview}`:""}`,{cause:err})}if(!response.ok){let preview=raw.slice(0,240).replace(/\s+/g," ");throw Error(`${resource} failed (${response.status} ${response.statusText})${preview?`: ${preview}`:""}`)}return data}function ensureGraphqlSuffix(url){return url.endsWith("/graphql")?url:`${url}/graphql`}function isLocalDevGatewayHost(url){let host;try{host=new URL(url).hostname.toLowerCase().replace(/^\[|\]$/g,"")}catch{return!1}if(host==="localhost"||host==="127.0.0.1"||host==="::1"||host==="0.0.0.0"||host==="host.docker.internal")return!0;return host.endsWith(".localhost")||host.endsWith(".local")||host.endsWith(".local.burdenoff.com")}function devTlsFetchInit(url){if(!(process.env.VIBE_DEV_INSECURE_TLS==="1"||process.env.NODE_TLS_REJECT_UNAUTHORIZED==="0")&&!isLocalDevGatewayHost(url))return{};return{tls:{rejectUnauthorized:!1}}}async function authenticateApp(globalGatewayUrl,clientId,clientSecret){let res=await fetch(ensureGraphqlSuffix(globalGatewayUrl),{method:"POST",...devTlsFetchInit(globalGatewayUrl),headers:{"Content-Type":"application/json"},body:JSON.stringify({query:`mutation AuthenticateApp($input: AuthenticateAppInput!) {
|
|
3
3
|
authenticateApp(input: $input) { accessToken expiresIn }
|
|
4
4
|
}`,variables:{input:{clientId,clientSecret,scopes:[]}}}),signal:AbortSignal.timeout(15000)}),data=await readGraphqlJson(res,"authenticateApp"),rl=detectRateLimit(data.errors,"authenticateApp");if(rl)throw rl;if(data.errors?.length){let codes=data.errors.map((e)=>e.extensions?.code??"UNKNOWN").join(",");throw Error(`authenticateApp errors [${codes}]: ${data.errors.map((e)=>e.message).join("; ")}`)}let token=data.data?.authenticateApp?.accessToken;if(!token)throw Error("authenticateApp returned no token");return token}async function issueWorkspaceToken(workspaceGatewayUrl,appToken,workspaceId,organizationId){let res=await fetch(ensureGraphqlSuffix(workspaceGatewayUrl),{method:"POST",...devTlsFetchInit(workspaceGatewayUrl),headers:{"Content-Type":"application/json",Authorization:`Bearer ${appToken}`},body:JSON.stringify({query:`mutation IssueAgentWorkspaceToken($input: IssueWorkspaceTokenInput!) {
|
|
5
5
|
issueWorkspaceToken(input: $input) {
|