@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.

@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import{listTrackedByOwner,spawnTracked}from"./index-926vt87h.js";import{LifecycleManager,createAgentDatabase,fetchEncryptionKey}from"./index-q96eskyn.js";import{resolveSafePath}from"./index-skmkfyzb.js";import{readTunnelState,startBootstrapTunnel,stopBootstrapTunnel}from"./index-95nmejfd.js";import{ServiceManager}from"./index-vfwervz9.js";import{redactUnknownSecrets}from"./index-y5q0m3cx.js";import{CliContributorRegistry,createIframeBridge,createUIServer,renderUiBootstrapHtml}from"./index-ttafzcs7.js";import{PluginManager,ServiceRegistry,isCriticalPlugin}from"./index-1x89a7r1.js";import{getOsAdapter}from"./index-srbb2214.js";import{broadcast,createEventsWs,createLogWs,createPluginRouter,createTerminalProxy,dispatchProfileRequest,mountProfileRoutes,rateLimitPlugin}from"./index-brtw3j8x.js";import{createAuthPlugin,getAgentApiKey,getApiKeyFromHeaders,getUiCookieFromRequest,isValidAgentApiKey,isValidUiPluginName,issueIframeToken,issueScopedIframeToken,issueTerminalCookieToken,issueUiCookieToken,markPluginPublicPathsDirty,verifyIframeToken,verifyIframeTokenWithReason,verifyUiCookieToken}from"./index-b4wy3jrt.js";import{Elysia,t}from"./index-rnk0kny8.js";import{getAgentConfigSeed,readAgentConfig,writeAgentConfig,writeAgentConfigAwaitSecrets}from"./index-2pqv0bya.js";import{assertAllowedGatewayUrl,currentProfileOrNull,enterProfileContext,enterRequestContext,extractRequestId,gatewayClient,generateRequestId,getDaemonProfile,getOrCreateProfile,getRequestId,profileRegistry}from"./index-7pdmqbj8.js";import{getDefaultProfile,getInstances,getPluginRegistry,getProfileDataDir,getVibecontrolsDir,getVibecontrolsProductDir,getVibecontrolsProfile,setDefaultProfile,validateAgentName}from"./index-bysm7taq.js";import{__require,__toESM}from"./index-e9rt4m94.js";var isBun=typeof new Headers()?.toJSON==="function",processHeaders=(headers)=>{if(isBun)return Object.keys(headers.toJSON()).join(", ");let keys="",i=0;return headers.forEach((_,key)=>{if(i)keys=keys+", "+key;else keys=key;i++}),keys},cors=(config)=>{let{aot=!0,origin=!0,methods=!0,allowedHeaders=!0,exposeHeaders=!0,credentials=!0,maxAge=5,preflight=!0}=config??{};if(Array.isArray(allowedHeaders))allowedHeaders=allowedHeaders.join(", ");if(Array.isArray(exposeHeaders))exposeHeaders=exposeHeaders.join(", ");let origins=typeof origin==="boolean"?void 0:Array.isArray(origin)?origin:[origin],app=new Elysia({name:"@elysiajs/cors",seed:config,aot}),anyOrigin=origins?.some((o)=>o==="*"),originMap={};if(origins){for(let origin2 of origins)if(typeof origin2==="string")originMap[origin2]=!0}let processOrigin=(origin2,request,from)=>{if(Array.isArray(origin2))return origin2.some((o)=>processOrigin(o,request,from));switch(typeof origin2){case"string":if(from in originMap)return!0;let fromProtocol=from.indexOf("://");if(fromProtocol!==-1)from=from.slice(fromProtocol+3);return origin2===from;case"function":return origin2(request)===!0;case"object":if(origin2 instanceof RegExp)return origin2.test(from)}return!1},handleOrigin=(set,request)=>{if(origin===!0){set.headers.vary="*",set.headers["access-control-allow-origin"]=request.headers.get("Origin")||"*";return}if(anyOrigin){set.headers.vary="*",set.headers["access-control-allow-origin"]="*";return}if(!origins?.length)return;if(origins.length){let from=request.headers.get("Origin")??"";for(let i=0;i<origins.length;i++)if(processOrigin(origins[i],request,from)===!0){set.headers.vary=origin?"Origin":"*",set.headers["access-control-allow-origin"]=from||"*";return}}set.headers.vary="Origin"},handleMethod=(set,method)=>{if(!method)return;if(methods===!0)return set.headers["access-control-allow-methods"]=method??"*";if(methods===!1||!methods?.length)return;if(methods==="*")return set.headers["access-control-allow-methods"]="*";if(!Array.isArray(methods))return set.headers["access-control-allow-methods"]=methods;set.headers["access-control-allow-methods"]=methods.join(", ")},defaultHeaders={};if(typeof exposeHeaders==="string")defaultHeaders["access-control-expose-headers"]=exposeHeaders;if(typeof allowedHeaders==="string")defaultHeaders["access-control-allow-headers"]=allowedHeaders;if(credentials===!0)defaultHeaders["access-control-allow-credentials"]="true";app.headers(defaultHeaders);function handleOption({set,request,headers}){if(handleOrigin(set,request),handleMethod(set,request.headers.get("access-control-request-method")),allowedHeaders===!0||exposeHeaders===!0){if(allowedHeaders===!0)set.headers["access-control-allow-headers"]=headers["access-control-request-headers"];if(exposeHeaders===!0)set.headers["access-control-expose-headers"]=Object.keys(headers).join(",")}if(maxAge)set.headers["access-control-max-age"]=maxAge.toString();return new Response(null,{status:204})}if(preflight)app.options("/",handleOption).options("/*",handleOption);return app.onRequest(function({set,request}){if(handleOrigin(set,request),preflight&&request.method==="OPTIONS")return handleOption({set,request,headers:isBun?request.headers.toJSON():Object.fromEntries(request.headers.entries())});if(handleMethod(set,request.method),allowedHeaders===!0||exposeHeaders===!0){let headers=processHeaders(request.headers);if(allowedHeaders===!0)set.headers["access-control-allow-headers"]=headers;if(exposeHeaders===!0)set.headers["access-control-expose-headers"]=headers}})};import{createHash}from"crypto";var NS="idempotency",TTL_MS=300000,MAX_ENTRIES=1e4;function cacheKey(method,path,rawKey,bodyHash){return createHash("sha256").update(`${method}|${path}|${rawKey}|${bodyHash}`).digest("hex")}async function readCached(db,key){let raw=await db.getPluginState(NS,key);if(!raw)return null;try{let entry=JSON.parse(raw);if(entry.expiresAt<Date.now())return await db.deletePluginState(NS,key),null;return entry}catch{return null}}async function writeCached(db,key,entry){await db.setPluginState(NS,key,JSON.stringify(entry))}async function sweepIdempotency(db){let all=await db.getAllPluginState(NS),now=Date.now(),removed=0,live=[];for(let e of all)try{if(JSON.parse(e.value).expiresAt<now)await db.deletePluginState(NS,e.key),removed+=1;else live.push({key:e.key,updatedAt:e.updatedAt})}catch{await db.deletePluginState(NS,e.key),removed+=1}if(live.length>MAX_ENTRIES){live.sort((a,b)=>(a.updatedAt??"").localeCompare(b.updatedAt??""));let overage=live.slice(0,live.length-MAX_ENTRIES);for(let entry of overage)await db.deletePluginState(NS,entry.key),removed+=1}if(removed>0)getDaemonProfile().logger.info("idempotency",`Swept ${removed} expired/over-cap entries`)}var sweepTimer=null,SWEEP_INTERVAL_MS=600000;function startSweepIfNeeded(deps){if(sweepTimer)return;sweepTimer=setInterval(()=>{let db=deps.getDb();if(!db)return;sweepIdempotency(db).catch((err)=>{getDaemonProfile().logger.warn("idempotency","Sweep failed",{error:String(err)})})},SWEEP_INTERVAL_MS),sweepTimer.unref?.()}function idempotencyPlugin(deps){return startSweepIfNeeded(deps),new Elysia({name:"plugin/idempotency"}).onBeforeHandle(async({request,path,set,store})=>{if(request.method!=="POST"&&request.method!=="PUT")return;let rawKey=request.headers.get("x-idempotency-key")??request.headers.get("X-Idempotency-Key");if(!rawKey)return;if(rawKey.length<8||rawKey.length>200)return set.status=400,{error:"X-Idempotency-Key must be 8\u2013200 chars",code:"BAD_REQUEST"};let db=deps.getDb();if(!db)return;let bodyHash="no-body";try{let text=await request.clone().text();bodyHash=createHash("sha256").update(text).digest("hex")}catch{}let key=cacheKey(request.method,path,rawKey,bodyHash),cached=await readCached(db,key);if(cached){set.status=cached.status;let headers=set.headers??={};headers["Content-Type"]=cached.contentType,headers["X-Idempotency-Replay"]="true",store.__idemReplay=cached.body;try{return JSON.parse(cached.body)}catch{return cached.body}}store.__idemKey=key}).onAfterHandle(async({response,set,store})=>{let key=store.__idemKey;if(!key)return;let db=deps.getDb();if(!db)return;let status=set.status??200;if(status<200||status>=300)return;let body=typeof response==="string"?response:JSON.stringify(response),contentType=set.headers?.["Content-Type"]??"application/json";try{await writeCached(db,key,{status,body,contentType,expiresAt:Date.now()+TTL_MS})}catch(err){getDaemonProfile().logger.warn("idempotency","Failed to persist response",{error:String(err)})}}).as("global")}import os from"os";import{readFileSync as readFileSync2}from"fs";import{join as join2}from"path";var DISABLED_REGISTRY={enabled:!1,async scrape(){return`# vibecontrols agent metrics disabled (OTel SDK not initialised)
2
+ import{listTrackedByOwner,spawnTracked}from"./index-926vt87h.js";import{LifecycleManager,createAgentDatabase,fetchEncryptionKey}from"./index-mq3amjcf.js";import{resolveSafePath}from"./index-skmkfyzb.js";import{readTunnelState,startBootstrapTunnel,stopBootstrapTunnel}from"./index-95nmejfd.js";import{ServiceManager}from"./index-wmeb40wr.js";import{redactUnknownSecrets}from"./index-y5q0m3cx.js";import{CliContributorRegistry,createIframeBridge,createUIServer,renderUiBootstrapHtml}from"./index-wk359257.js";import{PluginManager,ServiceRegistry,isCriticalPlugin}from"./index-cyhcvfxs.js";import{getOsAdapter}from"./index-srbb2214.js";import{broadcast,createEventsWs,createLogWs,createPluginRouter,createTerminalProxy,dispatchProfileRequest,mountProfileRoutes,rateLimitPlugin}from"./index-brtw3j8x.js";import{createAuthPlugin,getAgentApiKey,getApiKeyFromHeaders,getUiCookieFromRequest,isValidAgentApiKey,isValidUiPluginName,issueIframeToken,issueScopedIframeToken,issueTerminalCookieToken,issueUiCookieToken,markPluginPublicPathsDirty,verifyIframeToken,verifyIframeTokenWithReason,verifyUiCookieToken}from"./index-b4wy3jrt.js";import{Elysia,t}from"./index-rnk0kny8.js";import{getAgentConfigSeed,readAgentConfig,writeAgentConfig,writeAgentConfigAwaitSecrets}from"./index-2pqv0bya.js";import{assertAllowedGatewayUrl,currentProfileOrNull,enterProfileContext,enterRequestContext,extractRequestId,gatewayClient,generateRequestId,getDaemonProfile,getOrCreateProfile,getRequestId,profileRegistry}from"./index-7pdmqbj8.js";import{getDefaultProfile,getInstances,getPluginRegistry,getProfileDataDir,getVibecontrolsDir,getVibecontrolsProductDir,getVibecontrolsProfile,setDefaultProfile,validateAgentName}from"./index-bysm7taq.js";import{__require,__toESM}from"./index-e9rt4m94.js";var isBun=typeof new Headers()?.toJSON==="function",processHeaders=(headers)=>{if(isBun)return Object.keys(headers.toJSON()).join(", ");let keys="",i=0;return headers.forEach((_,key)=>{if(i)keys=keys+", "+key;else keys=key;i++}),keys},cors=(config)=>{let{aot=!0,origin=!0,methods=!0,allowedHeaders=!0,exposeHeaders=!0,credentials=!0,maxAge=5,preflight=!0}=config??{};if(Array.isArray(allowedHeaders))allowedHeaders=allowedHeaders.join(", ");if(Array.isArray(exposeHeaders))exposeHeaders=exposeHeaders.join(", ");let origins=typeof origin==="boolean"?void 0:Array.isArray(origin)?origin:[origin],app=new Elysia({name:"@elysiajs/cors",seed:config,aot}),anyOrigin=origins?.some((o)=>o==="*"),originMap={};if(origins){for(let origin2 of origins)if(typeof origin2==="string")originMap[origin2]=!0}let processOrigin=(origin2,request,from)=>{if(Array.isArray(origin2))return origin2.some((o)=>processOrigin(o,request,from));switch(typeof origin2){case"string":if(from in originMap)return!0;let fromProtocol=from.indexOf("://");if(fromProtocol!==-1)from=from.slice(fromProtocol+3);return origin2===from;case"function":return origin2(request)===!0;case"object":if(origin2 instanceof RegExp)return origin2.test(from)}return!1},handleOrigin=(set,request)=>{if(origin===!0){set.headers.vary="*",set.headers["access-control-allow-origin"]=request.headers.get("Origin")||"*";return}if(anyOrigin){set.headers.vary="*",set.headers["access-control-allow-origin"]="*";return}if(!origins?.length)return;if(origins.length){let from=request.headers.get("Origin")??"";for(let i=0;i<origins.length;i++)if(processOrigin(origins[i],request,from)===!0){set.headers.vary=origin?"Origin":"*",set.headers["access-control-allow-origin"]=from||"*";return}}set.headers.vary="Origin"},handleMethod=(set,method)=>{if(!method)return;if(methods===!0)return set.headers["access-control-allow-methods"]=method??"*";if(methods===!1||!methods?.length)return;if(methods==="*")return set.headers["access-control-allow-methods"]="*";if(!Array.isArray(methods))return set.headers["access-control-allow-methods"]=methods;set.headers["access-control-allow-methods"]=methods.join(", ")},defaultHeaders={};if(typeof exposeHeaders==="string")defaultHeaders["access-control-expose-headers"]=exposeHeaders;if(typeof allowedHeaders==="string")defaultHeaders["access-control-allow-headers"]=allowedHeaders;if(credentials===!0)defaultHeaders["access-control-allow-credentials"]="true";app.headers(defaultHeaders);function handleOption({set,request,headers}){if(handleOrigin(set,request),handleMethod(set,request.headers.get("access-control-request-method")),allowedHeaders===!0||exposeHeaders===!0){if(allowedHeaders===!0)set.headers["access-control-allow-headers"]=headers["access-control-request-headers"];if(exposeHeaders===!0)set.headers["access-control-expose-headers"]=Object.keys(headers).join(",")}if(maxAge)set.headers["access-control-max-age"]=maxAge.toString();return new Response(null,{status:204})}if(preflight)app.options("/",handleOption).options("/*",handleOption);return app.onRequest(function({set,request}){if(handleOrigin(set,request),preflight&&request.method==="OPTIONS")return handleOption({set,request,headers:isBun?request.headers.toJSON():Object.fromEntries(request.headers.entries())});if(handleMethod(set,request.method),allowedHeaders===!0||exposeHeaders===!0){let headers=processHeaders(request.headers);if(allowedHeaders===!0)set.headers["access-control-allow-headers"]=headers;if(exposeHeaders===!0)set.headers["access-control-expose-headers"]=headers}})};import{createHash}from"crypto";var NS="idempotency",TTL_MS=300000,MAX_ENTRIES=1e4;function cacheKey(method,path,rawKey,bodyHash){return createHash("sha256").update(`${method}|${path}|${rawKey}|${bodyHash}`).digest("hex")}async function readCached(db,key){let raw=await db.getPluginState(NS,key);if(!raw)return null;try{let entry=JSON.parse(raw);if(entry.expiresAt<Date.now())return await db.deletePluginState(NS,key),null;return entry}catch{return null}}async function writeCached(db,key,entry){await db.setPluginState(NS,key,JSON.stringify(entry))}async function sweepIdempotency(db){let all=await db.getAllPluginState(NS),now=Date.now(),removed=0,live=[];for(let e of all)try{if(JSON.parse(e.value).expiresAt<now)await db.deletePluginState(NS,e.key),removed+=1;else live.push({key:e.key,updatedAt:e.updatedAt})}catch{await db.deletePluginState(NS,e.key),removed+=1}if(live.length>MAX_ENTRIES){live.sort((a,b)=>(a.updatedAt??"").localeCompare(b.updatedAt??""));let overage=live.slice(0,live.length-MAX_ENTRIES);for(let entry of overage)await db.deletePluginState(NS,entry.key),removed+=1}if(removed>0)getDaemonProfile().logger.info("idempotency",`Swept ${removed} expired/over-cap entries`)}var sweepTimer=null,SWEEP_INTERVAL_MS=600000;function startSweepIfNeeded(deps){if(sweepTimer)return;sweepTimer=setInterval(()=>{let db=deps.getDb();if(!db)return;sweepIdempotency(db).catch((err)=>{getDaemonProfile().logger.warn("idempotency","Sweep failed",{error:String(err)})})},SWEEP_INTERVAL_MS),sweepTimer.unref?.()}function idempotencyPlugin(deps){return startSweepIfNeeded(deps),new Elysia({name:"plugin/idempotency"}).onBeforeHandle(async({request,path,set,store})=>{if(request.method!=="POST"&&request.method!=="PUT")return;let rawKey=request.headers.get("x-idempotency-key")??request.headers.get("X-Idempotency-Key");if(!rawKey)return;if(rawKey.length<8||rawKey.length>200)return set.status=400,{error:"X-Idempotency-Key must be 8\u2013200 chars",code:"BAD_REQUEST"};let db=deps.getDb();if(!db)return;let bodyHash="no-body";try{let text=await request.clone().text();bodyHash=createHash("sha256").update(text).digest("hex")}catch{}let key=cacheKey(request.method,path,rawKey,bodyHash),cached=await readCached(db,key);if(cached){set.status=cached.status;let headers=set.headers??={};headers["Content-Type"]=cached.contentType,headers["X-Idempotency-Replay"]="true",store.__idemReplay=cached.body;try{return JSON.parse(cached.body)}catch{return cached.body}}store.__idemKey=key}).onAfterHandle(async({response,set,store})=>{let key=store.__idemKey;if(!key)return;let db=deps.getDb();if(!db)return;let status=set.status??200;if(status<200||status>=300)return;let body=typeof response==="string"?response:JSON.stringify(response),contentType=set.headers?.["Content-Type"]??"application/json";try{await writeCached(db,key,{status,body,contentType,expiresAt:Date.now()+TTL_MS})}catch(err){getDaemonProfile().logger.warn("idempotency","Failed to persist response",{error:String(err)})}}).as("global")}import os from"os";import{readFileSync as readFileSync2}from"fs";import{join as join2}from"path";var DISABLED_REGISTRY={enabled:!1,async scrape(){return`# vibecontrols agent metrics disabled (OTel SDK not initialised)
3
3
  `},recordHttpRequest(){},setPluginsLoaded(){}},cached=null,initPromise=null;async function getMetricsRegistry(opts){if(cached)return cached;if(initPromise)return initPromise;return initPromise=(async()=>{try{let{MeterProvider}=await import("./index-7t06bbkg.js").then((m)=>__toESM(m.default,1)),{PrometheusExporter,PrometheusSerializer}=await import("./index-q7zah1sn.js").then((m)=>__toESM(m.default,1)),reader=new PrometheusExporter({preventServerStart:!0}),serializer=new PrometheusSerializer,meter=new MeterProvider({readers:[reader]}).getMeter("vibecontrols-agent"),infoGauge=meter.createGauge("vibecontrols_agent_info",{description:"Static info about the agent process; value is always 1."});meter.createObservableGauge("vibecontrols_agent_uptime_seconds",{description:"Process uptime in seconds."}).addCallback((res)=>{res.observe(process.uptime())});let httpCounter=meter.createCounter("vibecontrols_http_requests_total",{description:"Total HTTP requests handled by the agent, labelled by method, route, status."}),pluginsLoadedSnapshot={};meter.createObservableGauge("vibecontrols_plugins_loaded",{description:"Plugins loaded by the agent, broken down by status (loaded, failed, etc.)."}).addCallback((res)=>{for(let[status,count]of Object.entries(pluginsLoadedSnapshot))res.observe(count,{status})}),infoGauge.record(1,{version:opts?.version??"unknown",profile:opts?.profile??"default"});let handle={enabled:!0,async scrape(){let collected=await reader.collect();if(!collected.resourceMetrics)return"";return serializer.serialize(collected.resourceMetrics)},recordHttpRequest(method,route,status){httpCounter.add(1,{method,route,status:String(status)})},setPluginsLoaded(byStatus){pluginsLoadedSnapshot={...byStatus}}};return cached=handle,getDaemonProfile().logger.info("metrics","OTel Prometheus registry initialised"),handle}catch(err){return getDaemonProfile().logger.warn("metrics","Failed to initialise OTel metrics; /metrics will return a stub body",{error:err instanceof Error?err.message:String(err)}),cached=DISABLED_REGISTRY,DISABLED_REGISTRY}})(),initPromise}function recordHttpRequest(method,route,status){if(!cached)return;cached.recordHttpRequest(method,route,status)}function setPluginsLoaded(byStatus){if(!cached)return;cached.setPluginsLoaded(byStatus)}var LOOPBACK_ADDRS=new Set(["127.0.0.1","::1"]),warnedAnonEnv=!1;function maybeWarnAnonEnv(){if(warnedAnonEnv)return;if(process.env.METRICS_ANONYMOUS_LOCALHOST==="true")warnedAnonEnv=!0,getDaemonProfile().logger.warn("metrics","METRICS_ANONYMOUS_LOCALHOST=true \u2014 /metrics is open to TCP loopback peers without an API key. Prefer issuing a scoped API key for your scraper.")}function normalizeAddr(addr){let cleaned=addr.replace(/^\[|\]$/g,"");if(cleaned.startsWith("::ffff:"))return cleaned.slice(7);return cleaned}function isLoopbackPeer(request,server){let peer=server?.requestIP(request)?.address;if(!peer)return!1;return LOOPBACK_ADDRS.has(normalizeAddr(peer))}function createMetricsRoutes(){return maybeWarnAnonEnv(),new Elysia({name:"routes/metrics"}).get("/metrics",async({request,server,set})=>{if(!(process.env.METRICS_ANONYMOUS_LOCALHOST==="true"&&isLoopbackPeer(request,server))){let provided=getApiKeyFromHeaders(Object.fromEntries(request.headers.entries()));if(!isValidAgentApiKey(provided))return set.status=401,set.headers["content-type"]="application/json",JSON.stringify({error:"Unauthorized",message:"Invalid or missing API key"})}let body=await(await getMetricsRegistry()).scrape();return set.headers["content-type"]="text/plain; version=0.0.4; charset=utf-8",body})}import{randomBytes,timingSafeEqual}from"crypto";import{chmodSync,existsSync,mkdirSync,readFileSync,unlinkSync,writeFileSync}from"fs";import{dirname,join}from"path";var inMemoryToken=null;function pairingTokenPath(){return join(getVibecontrolsDir(),"pairing-token")}function generateToken(){return randomBytes(32).toString("base64url")}function constantTimeMatch(a,b){let aBuf=Buffer.from(a),bBuf=Buffer.from(b);if(aBuf.length!==bBuf.length)return!1;try{return timingSafeEqual(aBuf,bBuf)}catch{return!1}}function mintPairingToken(){if(inMemoryToken)return inMemoryToken;let path=pairingTokenPath();try{if(existsSync(path)){let existing=readFileSync(path,"utf8").trim();if(existing.length>=32)return inMemoryToken=existing,existing}}catch{}let token=generateToken();try{mkdirSync(dirname(path),{recursive:!0}),writeFileSync(path,token,{encoding:"utf8"});try{chmodSync(path,384)}catch{}}catch(err){}return inMemoryToken=token,token}function isValidPairingToken(candidate){if(!candidate)return!1;if(!inMemoryToken)return!1;return constantTimeMatch(candidate,inMemoryToken)}function invalidatePairingToken(){inMemoryToken=null;try{let path=pairingTokenPath();if(existsSync(path))unlinkSync(path)}catch{}}function getPairingTokenFromHeaders(headers){return headers["x-pairing-token"]??headers["X-Pairing-Token"]??null}function getMachineId(){let hostname=os.hostname(),platform=os.platform(),arch=os.arch(),hasher=new Bun.CryptoHasher("sha256");return hasher.update(`${hostname}-${platform}-${arch}`),hasher.digest("hex").substring(0,16)}function getAgentVersion(){for(let depth of["..","../.."])try{let pkgPath=join2(import.meta.dir,depth,"package.json"),v=JSON.parse(readFileSync2(pkgPath,"utf8")).version;if(v)return v}catch{}return"0.0.0"}async function getActiveTunnelUrl(serviceRegistry){let providers=[],defaultProvider=serviceRegistry.getProvider("tunnel");if(defaultProvider)providers.push(defaultProvider);for(let entry of serviceRegistry.listProvidersForType("tunnel")){let provider=serviceRegistry.getProviderByName("tunnel",entry.pluginName);if(provider&&!providers.includes(provider))providers.push(provider)}for(let provider of providers){if(!provider.getActiveTunnelUrl)continue;let url=await provider.getActiveTunnelUrl();if(url)return url}return null}function createPreConfigRoutes({serviceRegistry,runFinalize,getDb}){let version=getAgentVersion(),machineId=getMachineId();return new Elysia({prefix:"/api/agent"}).get("/identity",()=>({machineId,hostname:os.hostname(),platform:os.platform(),arch:os.arch(),version,uptime:process.uptime()})).get("/version",()=>({version,runtime:"bun",runtimeVersion:typeof Bun<"u"?Bun.version:"unknown"})).get("/api-key",({request,server,set})=>{if(!isLoopbackPeer(request,server)){let provided=getApiKeyFromHeaders(Object.fromEntries(request.headers.entries()));if(!isValidAgentApiKey(provided))return set.status=401,{error:"Unauthorized",message:"Invalid or missing API key"}}return{apiKey:getAgentApiKey()}}).post("/iframe-token",({body,request,set})=>{let provided=getApiKeyFromHeaders(Object.fromEntries(request.headers.entries()));if(!isValidAgentApiKey(provided))return set.status=401,{error:"Unauthorized",message:"Invalid or missing API key"};try{if(Array.isArray(body.pathPrefixes)&&body.pathPrefixes.length>0)return issueScopedIframeToken({pathPrefixes:body.pathPrefixes},body.ttlSeconds??void 0);if(!body.pathPrefix)return set.status=400,{error:"BadRequest",message:"Provide either pathPrefix (string) or pathPrefixes (string[])"};return issueIframeToken(body.pathPrefix,body.ttlSeconds??void 0)}catch(err){return set.status=400,{error:"BadRequest",message:err instanceof Error?err.message:String(err)}}},{body:t.Object({pathPrefix:t.Optional(t.String({minLength:1})),pathPrefixes:t.Optional(t.Array(t.String({minLength:1}),{minItems:1,maxItems:16})),ttlSeconds:t.Optional(t.Number())})}).post("/terminal-exchange",({body,set})=>{let{sid,token}=body;if(!sid||!token)return set.status=400,{error:"BadRequest",message:"sid and token required"};if(sid.includes("/")||sid.includes("\x00")||sid.includes(`
4
- `)||sid.includes("|"))return set.status=400,{error:"BadRequest",message:"invalid sid"};let expectedPath=`/terminal/${sid}`,verifyResult=verifyIframeTokenWithReason(token,expectedPath);if(!verifyResult.ok)return getDaemonProfile().logger.warn("terminal-exchange","iframe token rejected",{sid,reason:verifyResult.reason}),set.status=401,{error:"Unauthorized",message:"invalid iframe token",code:verifyResult.reason==="expired"?"expired":verifyResult.reason==="replayed"?"replayed":"invalid"};let cookie=issueTerminalCookieToken(sid,600),cookieName=`vt_term_${sid}`;return set.headers["set-cookie"]=`${cookieName}=${cookie.token}; HttpOnly; Secure; SameSite=None; Path=/terminal/${sid}; Max-Age=600`,set.status=204,null},{body:t.Object({sid:t.String({minLength:1}),token:t.String({minLength:1})})}).post("/ui-exchange",({body,set})=>{let{plugin,token}=body;if(!plugin||!token)return set.status=400,{error:"BadRequest",message:"plugin and token required"};if(!isValidUiPluginName(plugin))return set.status=400,{error:"BadRequest",message:"invalid plugin name"};let expectedPath=`/ui/${plugin}`;if(!verifyIframeToken(token,expectedPath))return set.status=401,{error:"Unauthorized",message:"invalid iframe token"};let cookie=issueUiCookieToken(plugin,600),cookieName=`vt_ui_${plugin}`;return set.headers["set-cookie"]=`${cookieName}=${cookie.token}; HttpOnly; Secure; SameSite=None; Path=/ui/${plugin}/; Max-Age=600`,set.status=204,null},{body:t.Object({plugin:t.String({minLength:1}),token:t.String({minLength:1})})}).post("/ui-exchange-plugin",({body,set})=>{let{plugin,token}=body;if(!plugin||!token)return set.status=400,{error:"BadRequest",message:"plugin and token required"};if(!isValidUiPluginName(plugin))return set.status=400,{error:"BadRequest",message:"invalid plugin name"};if(![`/api/plugins/${plugin}/ui`,`/${plugin}`].find((p)=>verifyIframeToken(token,p)))return set.status=401,{error:"Unauthorized",message:"invalid iframe token"};let cookie=issueUiCookieToken(plugin,600),cookieName=`vt_ui_${plugin}`;return set.headers["set-cookie"]=`${cookieName}=${cookie.token}; HttpOnly; Secure; SameSite=None; Path=/api/plugins/${plugin}/ui/; Max-Age=600`,set.status=204,null},{body:t.Object({plugin:t.String({minLength:1}),token:t.String({minLength:1})})}).get("/system",()=>({hostname:os.hostname(),platform:os.platform(),arch:os.arch(),release:os.release(),cpus:os.cpus().length,totalMemory:os.totalmem(),freeMemory:os.freemem(),uptime:os.uptime(),bunVersion:typeof Bun<"u"?Bun.version:void 0,agentVersion:version,homeDir:os.homedir(),cwd:process.cwd(),environment:"production"})).get("/tunnel",async()=>{let url=await getActiveTunnelUrl(serviceRegistry);if(!url)return{tunnelUrl:null,message:"No tunnel provider registered"};return{tunnelUrl:url}}).get("/status",()=>{let providers=["tunnel","session","ai"].filter((type)=>serviceRegistry.hasProvider(type));return{state:getDaemonProfile().getBootState(),status:getDaemonProfile().getBootState(),version,providers,timestamp:new Date().toISOString()}}).get("/gateway-auth",()=>({configured:gatewayClient.isConfigured(),config:redactUnknownSecrets(gatewayClient.getConfig()),state:getDaemonProfile().getBootState()})).post("/retry-config",async({set})=>{let{getFinalizeRetryHandle}=await import("./finalize-retry-handle-registry-vbq5qhj1.js"),handle=getFinalizeRetryHandle();if(!handle)return set.status=409,{ok:!1,error:"No finalize retry worker is active. The agent either never had cached credentials to retry with, or it already reached the ready state."};let result=await handle.forceRetryNow();if(!result.ok)set.status=503;return{ok:result.ok,error:result.ok?void 0:result.error,state:getDaemonProfile().getBootState(),worker:handle.getState()}}).post("/gateway-auth",async({body,request,set})=>{let stateForAuth=getDaemonProfile().getBootState(),headerMap=Object.fromEntries(request.headers.entries());if(stateForAuth==="ready"){let provided=getApiKeyFromHeaders(headerMap);if(!isValidAgentApiKey(provided))return set.status=401,{success:!1,state:stateForAuth,error:"Unauthorized: API key required to reconfigure"}}else{let apiKey=getApiKeyFromHeaders(headerMap),pairing=getPairingTokenFromHeaders(headerMap),apiKeyOk=isValidAgentApiKey(apiKey),pairingOk=isValidPairingToken(pairing);if(!apiKeyOk&&!pairingOk)return set.status=401,{success:!1,state:stateForAuth,error:"Unauthorized: provide x-agent-api-key OR x-pairing-token for bootstrap"}}let{clientId,clientSecret,workspaceId,globalGatewayUrl,workspaceGatewayUrl}=body;if(!clientId||!clientSecret||!workspaceId||!globalGatewayUrl||!workspaceGatewayUrl)return set.status=400,{success:!1,state:getDaemonProfile().getBootState(),error:"clientId, clientSecret, workspaceId, globalGatewayUrl, and workspaceGatewayUrl are required"};let safeGlobalGatewayUrl,safeWorkspaceGatewayUrl;try{safeGlobalGatewayUrl=assertAllowedGatewayUrl(globalGatewayUrl,"globalGatewayUrl"),safeWorkspaceGatewayUrl=assertAllowedGatewayUrl(workspaceGatewayUrl,"workspaceGatewayUrl")}catch(err){return set.status=400,{success:!1,state:getDaemonProfile().getBootState(),error:err instanceof Error?err.message:String(err)}}{let ctx=currentProfileOrNull()??getDaemonProfile();try{await writeAgentConfigAwaitSecrets({clientId,clientSecret,workspaceId,organizationId:body.organizationId,globalGatewayUrl:safeGlobalGatewayUrl,workspaceGatewayUrl:safeWorkspaceGatewayUrl,agentRecordId:body.agentRecordId,scopes:body.scopes},{dir:ctx.dataDir,scope:ctx.name})}catch(err){return set.status=500,{success:!1,state:getDaemonProfile().getBootState(),error:`Failed to persist gateway credentials to secrets backend: ${err instanceof Error?err.message:String(err)}`}}}let state=getDaemonProfile().getBootState();if(state==="ready"){let db=getDb();if(db){if(await db.setConfig("gateway-auth:clientId",clientId),await db.setConfig("gateway-auth:clientSecret",clientSecret),await db.setConfig("gateway-auth:workspaceId",workspaceId),body.organizationId)await db.setConfig("gateway-auth:organizationId",body.organizationId);if(await db.setConfig("gateway-auth:globalGatewayUrl",safeGlobalGatewayUrl),await db.setConfig("gateway-auth:workspaceGatewayUrl",safeWorkspaceGatewayUrl),body.agentRecordId)await db.setConfig("gateway-auth:agentRecordId",body.agentRecordId)}return gatewayClient.configure({globalGatewayUrl:safeGlobalGatewayUrl,workspaceGatewayUrl:safeWorkspaceGatewayUrl,clientId,clientSecret,workspaceId,organizationId:body.organizationId}),getDaemonProfile().logger.info("preconfig","Gateway credentials re-configured (agent was already ready)"),{success:!0,state,message:"Gateway auth re-configured"}}return getDaemonProfile().logger.info("preconfig","Gateway credentials received \u2014 beginning finalize (background)"),invalidatePairingToken(),runFinalize({clientId,clientSecret,workspaceId,organizationId:body.organizationId,globalGatewayUrl:safeGlobalGatewayUrl,workspaceGatewayUrl:safeWorkspaceGatewayUrl},{agentRecordId:body.agentRecordId,scopes:body.scopes}).catch((err)=>{getDaemonProfile().logger.error("preconfig","Background finalize threw",{error:err instanceof Error?err.message:String(err)})}),set.status=202,{success:!0,state:getDaemonProfile().getBootState(),agentRecordId:body.agentRecordId,message:"Gateway credentials accepted; finalize is running in the background. Poll /health/ready for completion."}},{body:t.Object({clientId:t.Optional(t.String()),clientSecret:t.Optional(t.String()),workspaceId:t.Optional(t.String()),organizationId:t.Optional(t.String()),globalGatewayUrl:t.Optional(t.String()),workspaceGatewayUrl:t.Optional(t.String()),scopes:t.Optional(t.Array(t.String())),agentRecordId:t.Optional(t.String())})})}import{existsSync as existsSync2,mkdirSync as mkdirSync2,rmSync,readdirSync}from"fs";import{join as join3}from"path";function profileDir(name){return join3(getVibecontrolsProductDir(),"agents",validateAgentName(name))}function listProfileNames(){let dir=join3(getVibecontrolsProductDir(),"agents");if(!existsSync2(dir))return[];return readdirSync(dir,{withFileTypes:!0}).filter((entry)=>entry.isDirectory()).map((entry)=>entry.name).filter((name)=>/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(name))}function profileDataDir(name){return join3(getVibecontrolsProductDir(),"agents",validateAgentName(name))}function readConfigForProfile(name){return readAgentConfig({dir:profileDataDir(name)})}function writeConfigForProfile(name,cfg){return writeAgentConfig(cfg,{dir:profileDataDir(name),scope:validateAgentName(name)})}function summarize(name){let defaultName=getDefaultProfile(),instance=getInstances().find((p)=>p.name===name),ctx=profileRegistry.get(name),summary={name,isDefault:name===defaultName,isRunning:instance?.status==="running",attached:ctx!==void 0,bootState:ctx?ctx.getBootState():null,dataDir:ctx?ctx.dataDir:null};if(instance)summary.port=instance.port,summary.pid=instance.pid,summary.startTime=instance.startTime;if(existsSync2(profileDir(name)))summary.config=redactUnknownSecrets(readConfigForProfile(name));return summary}function createProfileManagementRoutes(deps={}){let sm=deps.serviceManagerFactory?deps.serviceManagerFactory():new ServiceManager;return new Elysia({prefix:"/api/profiles"}).get("/",()=>{let onDisk=listProfileNames(),defaultName=getDefaultProfile(),names=new Set(onDisk);return names.add(defaultName),[...names].sort().map((n)=>summarize(n))}).post("/",async({body,set})=>{try{let name=validateAgentName(body.name),dir=profileDir(name);if(existsSync2(dir))return set.status=409,{error:"exists",message:`Profile '${name}' already exists.`};let seed;if(body.copyFrom){let src=validateAgentName(body.copyFrom);if(!existsSync2(profileDir(src)))return set.status=400,{error:"copy-source-missing",message:`Profile '${src}' does not exist.`};seed=readConfigForProfile(src),delete seed["static-api-key"],delete seed.agentRecordId,delete seed.apiKeys}else seed=getAgentConfigSeed();if(body.gatewayUrl)seed.globalGatewayUrl=body.gatewayUrl;if(body.workspaceGatewayUrl)seed.workspaceGatewayUrl=body.workspaceGatewayUrl;if(body.clientId)seed.clientId=body.clientId;if(body.clientSecret)seed.clientSecret=body.clientSecret;if(body.workspaceId)seed.workspaceId=body.workspaceId;if(body.organizationId)seed.organizationId=body.organizationId;mkdirSync2(dir,{recursive:!0}),writeConfigForProfile(name,seed);try{getOrCreateProfile(name)}catch(err){getDaemonProfile().logger.warn("profile-mgmt",`In-process attach failed for '${name}'`,{error:String(err)})}if(getDaemonProfile().logger.info("profile-mgmt",`Created profile '${name}' at ${dir}`),body.start){let startCfg={name,port:body.port??0,daemon:!0,dbPath:getProfileDataDir(),profile:name};await sm.startDaemon(startCfg)}return set.status=201,summarize(name)}catch(err){return set.status=400,{error:"create-failed",message:err instanceof Error?err.message:String(err)}}},{body:t.Object({name:t.String(),gatewayUrl:t.Optional(t.String()),workspaceGatewayUrl:t.Optional(t.String()),clientId:t.Optional(t.String()),clientSecret:t.Optional(t.String()),workspaceId:t.Optional(t.String()),organizationId:t.Optional(t.String()),copyFrom:t.Optional(t.String()),start:t.Optional(t.Boolean()),port:t.Optional(t.Number())})}).get("/:name",({params,set})=>{try{let name=validateAgentName(params.name);if(!existsSync2(profileDir(name)))return set.status=404,{error:"not-found",message:`No profile '${name}'.`};return summarize(name)}catch(err){return set.status=400,{error:"bad-request",message:err instanceof Error?err.message:String(err)}}},{params:t.Object({name:t.String()})}).put("/:name",({params,body,set})=>{try{let name=validateAgentName(params.name);if(!existsSync2(profileDir(name)))return set.status=404,{error:"not-found",message:`No profile '${name}'.`};let forbidden=["static-api-key","apiKeys","agentRecordId"];for(let key of forbidden)if(key in body)return set.status=400,{error:"forbidden-field",message:`Field '${key}' is managed via dedicated commands (vibe key rotate / vibe profile create). It cannot be patched here.`};let next={...readConfigForProfile(name),...body};return writeConfigForProfile(name,next),summarize(name)}catch(err){return set.status=400,{error:"update-failed",message:err instanceof Error?err.message:String(err)}}},{params:t.Object({name:t.String()}),body:t.Record(t.String(),t.Any())}).delete("/:name",async({params,body,query,set})=>{try{let name=validateAgentName(params.name);if(name===getDefaultProfile())return set.status=409,{error:"is-default",message:`Cannot delete active default profile '${name}'. Switch to another profile first.`};let purge=query?.purge==="true"||query?.purge==="1",hasDir=existsSync2(profileDir(name)),inRegistry=profileRegistry.has(name);if(!hasDir&&!inRegistry)return set.status=404,{error:"not-found",message:`No profile '${name}'.`};if(hasDir&&!purge&&!body?.confirm)return set.status=400,{error:"confirm-required",message:"Pass { confirm: true } in the body or `?purge=true` in the query to delete the on-disk dataDir (destructive)."};try{await sm.stop(name)}catch{}try{await profileRegistry.destroy(name)}catch(err){getDaemonProfile().logger.warn("profile-mgmt",`In-process detach failed for '${name}'`,{error:String(err)})}if(hasDir)if(body?.keepConfig)for(let entry of readdirSync(profileDir(name))){if(entry==="config.json")continue;rmSync(join3(profileDir(name),entry),{recursive:!0,force:!0})}else rmSync(profileDir(name),{recursive:!0,force:!0});return getDaemonProfile().logger.info("profile-mgmt",`Deleted profile '${name}'`),{ok:!0,deleted:name,keptConfig:!!body?.keepConfig,detached:inRegistry,purged:hasDir}}catch(err){return set.status=400,{error:"delete-failed",message:err instanceof Error?err.message:String(err)}}},{params:t.Object({name:t.String()}),query:t.Optional(t.Object({purge:t.Optional(t.String())})),body:t.Optional(t.Object({confirm:t.Optional(t.Boolean()),keepConfig:t.Optional(t.Boolean())}))}).post("/:name/switch",({params,set})=>{try{let name=validateAgentName(params.name);if(!existsSync2(profileDir(name)))return set.status=404,{error:"not-found",message:`No profile '${name}'.`};return setDefaultProfile(name),getDaemonProfile().logger.info("profile-mgmt",`Default profile switched to '${name}'`),{ok:!0,defaultProfile:name}}catch(err){return set.status=400,{error:"switch-failed",message:err instanceof Error?err.message:String(err)}}},{params:t.Object({name:t.String()})}).post("/:name/start",async({params,body,set})=>{try{let name=validateAgentName(params.name);if(!existsSync2(profileDir(name)))return set.status=404,{error:"not-found",message:`No profile '${name}'.`};try{getOrCreateProfile(name)}catch(err){getDaemonProfile().logger.warn("profile-mgmt",`In-process attach failed for '${name}'`,{error:String(err)})}if(!getInstances().some((p)=>p.name===name&&p.status==="running")){let startCfg={name,port:body?.port??0,daemon:!0,dbPath:getProfileDataDir(),profile:name};await sm.startDaemon(startCfg)}return summarize(name)}catch(err){return set.status=500,{error:"start-failed",message:err instanceof Error?err.message:String(err)}}},{params:t.Object({name:t.String()}),body:t.Optional(t.Object({port:t.Optional(t.Number())}))}).post("/:name/stop",async({params,set})=>{try{let name=validateAgentName(params.name);try{await sm.stop(name)}catch{}try{await profileRegistry.destroy(name)}catch(err){getDaemonProfile().logger.warn("profile-mgmt",`In-process detach failed for '${name}'`,{error:String(err)})}return summarize(name)}catch(err){return set.status=500,{error:"stop-failed",message:err instanceof Error?err.message:String(err)}}},{params:t.Object({name:t.String()})})}function buildProfileStats(){let rss=process.memoryUsage(),ru=process.resourceUsage(),totalCpuUserMs=ru.userCPUTime/1000,totalCpuSystemMs=ru.systemCPUTime/1000,totalCpuMs=totalCpuUserMs+totalCpuSystemMs,profiles=profileRegistry.list().map((ctx)=>{let childPidCount;try{childPidCount=listTrackedByOwner(ctx.spawnOwnerKey).length}catch{childPidCount=0}return{name:ctx.name,status:ctx.getBootState(),childPidCount,cpuMs:totalCpuMs,heapBytes:rss.heapUsed,dataDir:ctx.dataDir}});return{process:{pid:process.pid,uptimeSeconds:process.uptime(),cpuUserMs:totalCpuUserMs,cpuSystemMs:totalCpuSystemMs,heapUsedBytes:rss.heapUsed,heapTotalBytes:rss.heapTotal,rssBytes:rss.rss},profiles,notes:{perProfileCpu:"deferred",perProfileHeap:"deferred"}}}function createProfileStatsRoutes(){return new Elysia({prefix:"/api/profile-stats"}).get("/",()=>buildProfileStats())}function withTimeout(p,ms){return Promise.race([p,new Promise((_,reject)=>setTimeout(()=>reject(Error(`timeout after ${ms}ms`)),ms))])}function isEnoent(err){let msg=err instanceof Error?err.message:String(err);return/ENOENT/.test(msg)||/no such file or directory/i.test(msg)}async function runDbProbe(db){let probeKey=`__health__:probe:${typeof crypto<"u"&&typeof crypto.randomUUID==="function"?crypto.randomUUID():`${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`}`,value=String(Date.now());if(await withTimeout(db.setConfig(probeKey,value),2000),await withTimeout(db.getConfig(probeKey),2000)!==value)throw Error("round-trip mismatch");try{await withTimeout(db.deleteConfig(probeKey),500)}catch{}}async function checkDb(db,dbPath){if(!db)return{ok:!1,message:"database not opened"};let start=performance.now();try{return await runDbProbe(db),{ok:!0,durationMs:performance.now()-start}}catch(err){if(dbPath&&isEnoent(err))try{return(await import("fs")).mkdirSync(dbPath,{recursive:!0}),await runDbProbe(db),{ok:!0,message:`recovered: dbPath ${dbPath} was missing \u2014 recreated`,durationMs:performance.now()-start}}catch(retryErr){return{ok:!1,message:`ENOENT on dbPath ${dbPath}: ${retryErr instanceof Error?retryErr.message:String(retryErr)}`,durationMs:performance.now()-start}}return{ok:!1,message:err instanceof Error?err.message:String(err),durationMs:performance.now()-start}}}function checkProvider(registry,type){if(!registry)return{ok:!1,message:"no service registry"};let awaiting=getDaemonProfile().getBootState()==="awaiting-config";if(type==="tunnel"){let p=registry.getProvider("tunnel");if(!p&&process.env.AGENT_TUNNEL==="false")return{ok:!0,message:"tunnel disabled via AGENT_TUNNEL=false"};if(p)return{ok:!0,message:`provider: ${p.name}`};return{ok:!1,message:awaiting?"agent is awaiting-config \u2014 POST OAuth credentials to /api/agent/gateway-auth to register tunnel provider":"no tunnel provider registered"}}if(type==="session"){let p=registry.getProvider("session");if(p)return{ok:!0,message:`provider: ${p.name}`};return{ok:!1,message:awaiting?"agent is awaiting-config \u2014 POST OAuth credentials to /api/agent/gateway-auth to register session provider":"no session provider registered"}}return{ok:!0}}async function checkPluginHealth(pm){if(!pm)return{};let results={};for(let plugin of pm.getAllPlugins()){let fn=plugin.getHealth;if(typeof fn!=="function")continue;let start=performance.now();try{let out=await withTimeout(Promise.resolve(fn.call(plugin)),2000);results[plugin.name]={ok:out?.ok!==!1,message:out?.message,durationMs:performance.now()-start}}catch(err){results[plugin.name]={ok:!1,message:err instanceof Error?err.message:String(err),durationMs:performance.now()-start}}}return results}function createHealthRoutes(depsOrRegistry){let deps=depsOrRegistry&&"serviceRegistry"in depsOrRegistry?depsOrRegistry:{serviceRegistry:depsOrRegistry};return new Elysia({prefix:"/health"}).get("/",()=>{return{status:"ok",lifecycleState:deps.serviceRegistry?.getService("agent","lifecycle")?.getState()??"running",bootState:getDaemonProfile().getBootState(),timestamp:new Date().toISOString(),uptime:process.uptime()}}).get("/live",()=>({status:"ok"})).get("/ready",async({set})=>{let lifecycleState=deps.serviceRegistry?.getService("agent","lifecycle")?.getState()??"running",bootState=getDaemonProfile().getBootState(),components={};components.boot={ok:bootState==="ready",message:bootState==="ready"?void 0:`boot state ${bootState}`},components.lifecycle={ok:lifecycleState==="running",message:lifecycleState==="running"?void 0:`lifecycle ${lifecycleState}`},components.db=await checkDb(deps.getDb?.()??null,deps.getDbPath?.()??null),components.tunnel=checkProvider(deps.serviceRegistry,"tunnel"),components.session=checkProvider(deps.serviceRegistry,"session");let plugins=await checkPluginHealth(deps.getPluginManager?.()??null),allOk=Object.values(components).every((r)=>r.ok)&&Object.values(plugins).every((r)=>r.ok);if(!allOk)set.status=503;let reasons=bootState==="degraded"?getDaemonProfile().getDegradedReasons():[],daemonName=getDaemonProfile().name,profilesMap={};for(let ctx of profileRegistry.list())profilesMap[ctx.name]={bootState:ctx.getBootState(),ok:ctx.getBootState()==="ready",degradedReasons:ctx.getDegradedReasons()};let lastFinalizeError=getDaemonProfile().getLastFinalizeError(),body={status:allOk?"ok":"degraded",lifecycleState,bootState,daemon:{profile:daemonName,bootState,ok:bootState==="ready"},profiles:profilesMap,components,plugins,degradedReasons:reasons,lastFinalizeError,timestamp:new Date().toISOString()};if(!allOk)getDaemonProfile().logger.warn("health","Readiness probe failed",{components,plugins,bootState});return body})}var inflight=0,totalServed=0;function createInflightTracker(){return new Elysia({name:"inflight-tracker"}).onRequest(()=>{inflight+=1}).onAfterResponse(()=>{inflight=Math.max(0,inflight-1),totalServed+=1})}function createStatsRoutes(){return new Elysia({prefix:"/api/stats"}).get("/inflight",()=>({inflight:Math.max(0,inflight-1),totalServed}))}var ALLOWED_COMMANDS=Object.freeze(["code","code-insiders","codium","cursor","idea","pycharm","webstorm","goland","phpstorm","rubymine","clion","rider","zed","subl","vim","nvim","emacs","neovide","fleet","helix"]),ALLOWED_SET=new Set(ALLOWED_COMMANDS),ALLOWED_ARG_FLAGS=new Set(["--new-window","-n","--reuse-window","-r","--wait","-w","--add","--goto"]);function which(cmd){try{return Bun.which(cmd)??null}catch{return null}}function createEditorRoutes(){return new Elysia({prefix:"/api/editor"}).get("/allowlist",()=>({commands:[...ALLOWED_COMMANDS]})).get("/detect",async()=>{let results=ALLOWED_COMMANDS.map((cmd)=>[cmd,which(cmd)]),available=[],paths={};for(let[cmd,p]of results)if(p)available.push(cmd),paths[cmd]=p;return{available,paths}}).post("/open",async({body,set})=>{let{command,path:rawPath,args=[]}=body;if(!ALLOWED_SET.has(command))return set.status=400,{ok:!1,error:`Command '${command}' is not in the IDE allowlist`};for(let a of args)if(typeof a!=="string"||!ALLOWED_ARG_FLAGS.has(a))return set.status=400,{ok:!1,error:`Argument '${a}' is not in the flag allowlist`};let resolvedPath;try{resolvedPath=(await resolveSafePath(rawPath,{mustExist:!0})).realPath}catch(err){return set.status=400,{ok:!1,error:`Invalid path: ${err instanceof Error?err.message:String(err)}`}}let resolvedCmd=which(command);if(!resolvedCmd)return set.status=404,{ok:!1,error:`'${command}' is not installed or not on PATH on this agent`};try{let child=spawnTracked({owner:`editor:${command}`,cmd:[resolvedCmd,...args,resolvedPath],env:process.env,stdout:"ignore",stderr:"ignore",stdin:"ignore",meta:{command,path:resolvedPath}});return getDaemonProfile().logger.info("editor",`Launched ${command} on ${resolvedPath}`,{pid:child.pid}),getDaemonProfile().audit.emit("agent","editor.open",{command,path:resolvedPath,pid:child.pid}),{ok:!0,command,resolvedPath,pid:child.pid}}catch(err){return set.status=500,{ok:!1,error:`Failed to spawn editor: ${err instanceof Error?err.message:String(err)}`}}},{body:t.Object({command:t.String({minLength:1,maxLength:40}),path:t.String({minLength:1,maxLength:4096}),args:t.Optional(t.Array(t.String({maxLength:32})))})})}var REGISTRY_KEY=Symbol.for("@vibecontrols/plugin-sdk:contextProviders@1");function getRegistry(){let slots=globalThis,existing=slots[REGISTRY_KEY];if(existing)return existing;let created=new Map;return slots[REGISTRY_KEY]=created,created}function listContextProviders(){return Array.from(getRegistry().values())}function safeHost(maybeUrl){if(!maybeUrl)return null;try{return new URL(maybeUrl).host}catch{return null}}async function buildAgentSelfContext(deps,args){let pm=deps.getPluginManager(),loadedPlugins=pm?pm.getPluginDetails().map((p)=>({pluginName:p.pluginName,packageName:p.packageName,version:p.version,tags:p.tags??[]})):[],mem=process.memoryUsage(),tunnelHost=safeHost(deps.getTunnelHost?.()??null);return{pluginName:"agent",description:"vibecontrols-agent runtime self-report",generatedAt:new Date().toISOString(),data:{profile:args.profile,vibeId:args.vibeId??null,runtime:{bunVersion:typeof Bun<"u"?Bun.version:null,nodeVersion:process.versions.node??null,platform:process.platform,arch:process.arch,pid:process.pid,uptimeSeconds:Math.round(process.uptime()),memory:{rssMB:Math.round(mem.rss/1048576),heapUsedMB:Math.round(mem.heapUsed/1048576)}},agent:{version:deps.getAgentVersion?.()??null,profileRegistered:getVibecontrolsProfile(),tunnelHost},plugins:{count:loadedPlugins.length,items:loadedPlugins}}}}var DEFAULT_PROVIDER_TIMEOUT_MS=2000,SINGLE_FLIGHT_TTL_MS=1000;async function withTimeout2(promise,timeoutMs){let timer,timeout=new Promise((_,reject)=>{timer=setTimeout(()=>reject(Error(`timeout after ${timeoutMs}ms`)),timeoutMs)});try{return await Promise.race([promise,timeout])}finally{if(timer)clearTimeout(timer)}}async function runOne(provider,args){let start=performance.now(),timeoutMs=provider.timeoutMs??DEFAULT_PROVIDER_TIMEOUT_MS;try{let data=await withTimeout2(provider.getContext(args),timeoutMs);if(!data.generatedAt)data.generatedAt=new Date().toISOString();return{ok:!0,data,durationMs:Math.round(performance.now()-start)}}catch(err){return{ok:!1,error:err.message??String(err),durationMs:Math.round(performance.now()-start)}}}class ContextAggregator{deps;inflight=new Map;constructor(deps){this.deps=deps}async aggregate(args){let key=`${args.profile}::${args.vibeId??""}`,existing=this.inflight.get(key);if(existing&&Date.now()-existing.ts<SINGLE_FLIGHT_TTL_MS)return existing.promise;let promise=this.doAggregate(args).finally(()=>{setTimeout(()=>{let entry=this.inflight.get(key);if(entry&&entry.promise===promise)this.inflight.delete(key)},SINGLE_FLIGHT_TTL_MS).unref?.()});return this.inflight.set(key,{ts:Date.now(),promise}),promise}async selfContext(args){return buildAgentSelfContext(this.deps,args)}async pluginContext(name,args){let provider=listContextProviders().find((p)=>p.name===name);if(!provider)return null;return runOne(provider,args)}async pluginsContext(args){let providers=listContextProviders(),settled=await Promise.allSettled(providers.map((p)=>runOne(p,args))),out={};return providers.forEach((p,i)=>{let r=settled[i];if(r&&r.status==="fulfilled")out[p.name]=r.value;else if(r&&r.status==="rejected")out[p.name]={ok:!1,error:r.reason instanceof Error?r.reason.message:String(r.reason),durationMs:0}}),out}async doAggregate(args){let[agent,plugins]=await Promise.all([this.selfContext(args),this.pluginsContext(args)]);return{agent,plugins}}}function parseVibeId(query){let raw=query.vibeId;if(typeof raw!=="string")return;let v=raw.trim();return v.length>0&&v.length<=128?v:void 0}function createContextRoutes(deps){let aggregator=new ContextAggregator(deps);return new Elysia({prefix:"/api/agent/context"}).get("/",async({params,query})=>{let profile=params?.profile??"default",vibeId=parseVibeId(query);return aggregator.aggregate({profile,vibeId})},{query:t.Object({vibeId:t.Optional(t.String())})}).get("/agent",async({params,query})=>{let profile=params?.profile??"default",vibeId=parseVibeId(query);return aggregator.selfContext({profile,vibeId})},{query:t.Object({vibeId:t.Optional(t.String())})}).get("/plugins",async({params,query})=>{let profile=params?.profile??"default",vibeId=parseVibeId(query);return aggregator.pluginsContext({profile,vibeId})},{query:t.Object({vibeId:t.Optional(t.String())})}).get("/plugins/:name",async({params,query,set})=>{let profile=params?.profile??"default",name=params?.name;if(!name)return set.status=400,{error:"missing plugin name"};let vibeId=parseVibeId(query),entry=await aggregator.pluginContext(name,{profile,vibeId});if(!entry)return set.status=404,{error:`no context provider registered under name "${name}"`};return entry},{params:t.Object({name:t.String()}),query:t.Object({vibeId:t.Optional(t.String())})})}var FINALIZE_EXEMPT_PREFIXES=["/health","/api/agent/status","/api/agent/version","/api/agent/identity","/api/agent/api-key","/api/agent/tunnel","/api/agent/system","/api/agent/gateway-auth","/api/stats","/metrics","/api/profiles","/api/profile-stats"];function isFinalizeExempt(path){return FINALIZE_EXEMPT_PREFIXES.some((p)=>path.startsWith(p))}var UUID_RE=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function normalizeRouteLabel(path){return path.split("/").map((seg)=>{if(!seg)return seg;if(/^\d+$/.test(seg))return":id";if(UUID_RE.test(seg))return":id";if(seg.length>=24&&/^[A-Za-z0-9_-]+$/.test(seg))return":id";return seg}).join("/")}async function createApp(options){let{port,host,dbPath,logLevel,corsOrigin}=options,effectiveDbPath=dbPath??getProfileDataDir();try{(await import("fs")).mkdirSync(effectiveDbPath,{recursive:!0})}catch(err){throw getDaemonProfile().logger.error("app","Failed to create dbPath dir at boot",{dbPath:effectiveDbPath,error:String(err)}),Error(`Cannot create dbPath ${effectiveDbPath}: ${err instanceof Error?err.message:String(err)}`,{cause:err})}if(logLevel)getDaemonProfile().logger.setLevel(logLevel);(async()=>{let{logShipper}=await import("./log-shipper-9rtt4y1s.js");logShipper.init()})(),(async()=>{let version=await getPackageVersion();await getMetricsRegistry({version,profile:getVibecontrolsProfile()})})();try{let{checkDependencies}=await import("./bootstrap.service-fknk5beq.js"),deps=checkDependencies(),missingRequired=deps.filter((d)=>d.required&&!d.installed),missingOptional=deps.filter((d)=>!d.required&&!d.installed);if(missingRequired.length>0)getDaemonProfile().logger.error("app",`Missing required system deps: ${missingRequired.map((d)=>d.name).join(", ")}. Run \`vibe setup\` to install.`);if(missingOptional.length>0)getDaemonProfile().logger.warn("app",`Missing optional system deps: ${missingOptional.map((d)=>d.name).join(", ")}. Some plugins may fail their prereqs check.`)}catch(err){getDaemonProfile().logger.warn("app","Boot-time dependency check failed",{error:String(err)})}try{getDaemonProfile().audit.runRetention()}catch(err){getDaemonProfile().logger.warn("app","Audit-log retention sweep failed",{error:String(err)})}let serviceRegistry=new ServiceRegistry;startBootstrapTunnel(serviceRegistry,{port});let CORS_METHODS="GET, POST, PUT, PATCH, DELETE, OPTIONS",CORS_HEADERS="Content-Type, x-agent-api-key, Authorization, x-requested-with",configuredCorsOrigins=Array.isArray(corsOrigin)?corsOrigin:(corsOrigin??"").split(",").map((origin)=>origin.trim()).filter(Boolean),trustedProductionOrigins=new Set(["https://vibecontrols.com","https://app.vibecontrols.com","https://alphaapp.vibecontrols.com","https://burdenoff.com","https://app.burdenoff.com","https://alphaapp.burdenoff.com"]),isAllowedOrigin=(origin)=>{try{let url=new URL(origin);if(configuredCorsOrigins.includes(origin))return!0;if(configuredCorsOrigins.includes("*"))return!1;return url.hostname==="localhost"||url.hostname==="127.0.0.1"||url.hostname==="0.0.0.0"||url.hostname.endsWith(".local.burdenoff.com")||trustedProductionOrigins.has(url.origin)}catch{return!1}},db=null,pluginManager=null,hostServices=null,lifecycle=null,pluginPublicPaths=()=>[],pluginRoutesApp=null,uiServerApp=null,finalizeInFlight=null,SHUTDOWN_PHASE_MS=5000,runPhase=async(name,fn)=>{let started=Date.now();try{await Promise.race([Promise.resolve(fn()),new Promise((_,reject)=>setTimeout(()=>reject(Error(`shutdown phase ${name} exceeded ${SHUTDOWN_PHASE_MS}ms`)),SHUTDOWN_PHASE_MS))]),getDaemonProfile().logger.info("app",`shutdown.phase ${name} complete`,{ms:Date.now()-started})}catch(err){getDaemonProfile().logger.warn("app",`shutdown.phase ${name} failed`,{error:String(err),ms:Date.now()-started})}},stopFn=async(context)=>{if(getDaemonProfile().logger.info("app","Agent shutdown starting",{reason:context?.reason??"shutdown"}),await runPhase("plugins",async()=>{if(pluginManager)await pluginManager.dispatchServerStop(context)}),await runPhase("bootstrap-tunnel",()=>stopBootstrapTunnel()),await runPhase("tracked-subprocesses",async()=>{let{killAllTracked}=await import("./subprocess-vks78xmn.js");await killAllTracked()}),context?.reason!=="reload")await runPhase("db-close",async()=>{if(db)await db.close()});getDaemonProfile().logger.close(),getDaemonProfile().logger.info("app","Agent server stopped")},finalize=async(creds,opts)=>{if(getDaemonProfile().getBootState()==="ready")return{ok:!0};if(finalizeInFlight)return finalizeInFlight;return finalizeInFlight=(async()=>{getDaemonProfile().setBootState("initializing");try{let safeCreds={...creds,globalGatewayUrl:assertAllowedGatewayUrl(creds.globalGatewayUrl,"globalGatewayUrl"),workspaceGatewayUrl:assertAllowedGatewayUrl(creds.workspaceGatewayUrl,"workspaceGatewayUrl")},encryptionKey=await fetchEncryptionKey(safeCreds),resolvedDbPath=effectiveDbPath,cfgForStorage=readAgentConfig({dir:getDaemonProfile().dataDir}),storageAdapterName=cfgForStorage.storageAdapter??process.env.VIBE_STORAGE_ADAPTER??void 0,storageAdapterOptions=cfgForStorage.storageOptions;try{db=await createAgentDatabase({dbPath:resolvedDbPath,encryptionKey,adapterName:storageAdapterName,adapterOptions:storageAdapterOptions})}catch(openErr){let message=openErr instanceof Error?openErr.message:String(openErr);getDaemonProfile().logger.error("app","Storage open failed; quarantining and retrying once",{error:message,path:resolvedDbPath});try{let fs=await import("fs");if(fs.existsSync(resolvedDbPath)){let ts=new Date().toISOString().replace(/[:.]/g,"-"),broken=`${resolvedDbPath}.broken-${ts}`;fs.renameSync(resolvedDbPath,broken),getDaemonProfile().logger.warn("app",`Quarantined storage to ${broken} \u2014 fresh DB will be created`)}db=await createAgentDatabase({dbPath:resolvedDbPath,encryptionKey,adapterName:storageAdapterName,adapterOptions:storageAdapterOptions})}catch(retryErr){let retryMsg=retryErr instanceof Error?retryErr.message:String(retryErr);throw getDaemonProfile().recordDegradedReason("storage",retryMsg),Error(`Storage open failed twice; agent is degraded: ${retryMsg}`,{cause:retryErr})}}if(await writeAgentConfigAwaitSecrets({clientId:safeCreds.clientId,clientSecret:safeCreds.clientSecret,workspaceId:safeCreds.workspaceId,organizationId:safeCreds.organizationId,globalGatewayUrl:safeCreds.globalGatewayUrl,workspaceGatewayUrl:safeCreds.workspaceGatewayUrl,agentRecordId:opts?.agentRecordId,scopes:opts?.scopes},{dir:getDaemonProfile().dataDir,scope:getDaemonProfile().name}),await db.setConfig("gateway-auth:clientId",safeCreds.clientId),await db.setConfig("gateway-auth:clientSecret",safeCreds.clientSecret),await db.setConfig("gateway-auth:globalGatewayUrl",safeCreds.globalGatewayUrl),await db.setConfig("gateway-auth:workspaceGatewayUrl",safeCreds.workspaceGatewayUrl),await db.setConfig("gateway-auth:workspaceId",safeCreds.workspaceId),safeCreds.organizationId)await db.setConfig("gateway-auth:organizationId",safeCreds.organizationId);if(opts?.agentRecordId)await db.setConfig("gateway-auth:agentRecordId",opts.agentRecordId);serviceRegistry.db=db,await serviceRegistry.hydrateDefaultsFromDb(),pluginManager=new PluginManager(db),await pluginManager.loadCorePlugins();try{await pluginManager.loadAll()}catch(err){getDaemonProfile().logger.warn("app","Failed to load some external plugins",{error:String(err)})}let autoInstallDisabled=process.env.VIBE_SKIP_AUTO_INSTALL==="1"||await db.getConfig("plugins:auto-install-disabled");if(autoInstallDisabled!=="true"&&autoInstallDisabled!==!0)try{let installed=await pluginManager.ensureDefaultPlugins((message)=>getDaemonProfile().logger.info("app",`[auto-install] ${message}`));if(installed.length>0)getDaemonProfile().logger.info("app",`Auto-installed ${installed.length} default plugin(s): ${installed.map((p)=>p.packageName).join(", ")}`)}catch(err){getDaemonProfile().logger.warn("app","Failed to auto-install default plugins",{error:String(err)})}getDaemonProfile().logger.info("app",`Plugins loaded: ${pluginManager.getPluginDetails().length} total (${pluginManager.getPluginDetails().filter((p)=>p.isCore).length} core)`);try{let details=pluginManager.getPluginDetails(),byStatus={loaded:details.filter((p)=>p.loaded).length,failed:details.filter((p)=>!p.loaded).length};setPluginsLoaded(byStatus)}catch{}let storageProvider={async get(namespace,key){return await db.getPluginState(namespace,key)??null},async set(namespace,key,value){await db.setPluginState(namespace,key,value)},async delete(namespace,key){return db.deletePluginState(namespace,key)},async list(namespace){return await db.getAllPluginState(namespace)},async deleteAll(namespace){return db.deleteAllPluginState(namespace)}},packageVersion=await getPackageVersion();hostServices={storage:storageProvider,logger:getDaemonProfile().logger,serviceRegistry,getProvider:(type)=>serviceRegistry.getProvider(type),getAgentBaseUrl:()=>process.env.AGENT_URL||`http://localhost:${port}`,getAgentVersion:()=>packageVersion,validateApiKey:(key)=>isValidAgentApiKey(key),setCodeServerSessionValidator:(fn)=>{codeServerSessionValidator=fn},broadcast,workspaceQuery:async(query,variables)=>gatewayClient.workspaceQuery(query,variables),isGatewayConfigured:()=>gatewayClient.isConfigured(),getAgentRecordId:async()=>await db.getConfig("gateway-auth:agentRecordId")??null,getWorkspaceId:async()=>await db.getConfig("gateway-auth:workspaceId")??null,getConfig:async(key)=>await db.getConfig(key)??void 0,getPluginRegistry:()=>getPluginRegistry(),getDataDir:()=>getVibecontrolsDir(),cliContributors:new CliContributorRegistry,audit:{emit:(event,payload)=>getDaemonProfile().audit.emit("agent",event,payload??{})},telemetry:{emit:(event,payload)=>{import("./telemetry-rew0mtj2.js").then(({telemetryService})=>telemetryService.emit(event,payload??{})).catch(()=>{})}},os:getOsAdapter(),iframeBridge:createIframeBridge()},gatewayClient.configure({globalGatewayUrl:safeCreds.globalGatewayUrl,workspaceGatewayUrl:safeCreds.workspaceGatewayUrl,clientId:safeCreds.clientId,clientSecret:safeCreds.clientSecret,workspaceId:safeCreds.workspaceId,organizationId:safeCreds.organizationId});let routeDeps={db,serviceRegistry,pluginManager,broadcast,hostServices};routeDeps.app=app;let pluginRoutesAppInitialized=!1,rebuildPluginSurfaces=()=>{let{routes:pluginRoutes,getPublicPaths,mountPlugin}=createPluginRouter(pluginManager,routeDeps);if(routeDeps.mountPlugin=mountPlugin,pluginPublicPaths=getPublicPaths,markPluginPublicPathsDirty(),pluginRoutesApp=pluginRoutes,uiServerApp=createUIServer(pluginManager),pluginManager&&pluginRoutesAppInitialized&&hostServices)pluginManager.dispatchServerStart(pluginRoutesApp,hostServices).catch((err)=>getDaemonProfile().logger.warn("app","Re-dispatch of onServerStart after plugin reload failed",{error:String(err)}));pluginRoutesAppInitialized=!0};routeDeps.rebuildPluginSurfaces=rebuildPluginSurfaces,rebuildPluginSurfaces(),lifecycle=new LifecycleManager(serviceRegistry,pluginManager,db,app,hostServices,stopFn),serviceRegistry.registerService("agent","lifecycle",lifecycle),getDaemonProfile().attachServices({db,serviceRegistry,pluginManager,lifecycle,hostServices}),mountProfileRoutes(getDaemonProfile(),{rebuildPluginSurfaces,mountPlugin:routeDeps.mountPlugin});try{await getDaemonProfile().keyVault.bindApiKey(getAgentApiKey())}catch(err){getDaemonProfile().logger.warn("app","Failed to bind api key into daemon keyVault",{error:String(err)})}let criticalFailures=[];try{let{failures}=await pluginManager.dispatchServerStart(pluginRoutesApp,hostServices);for(let f of failures)if(isCriticalPlugin(f.plugin)||(f.packageName?isCriticalPlugin(f.packageName):!1))criticalFailures.push(f),getDaemonProfile().recordDegradedReason(f.plugin,f.error);else getDaemonProfile().logger.warn("app",`Non-critical plugin ${f.plugin} failed onServerStart; continuing`,{error:f.error})}catch(err){getDaemonProfile().logger.warn("app","Error during plugin onServerStart dispatch",{error:String(err)})}try{await pluginManager.dispatchServerReady(app,hostServices)}catch(err){getDaemonProfile().logger.warn("app","Error during plugin onServerReady dispatch",{error:String(err)})}if(getDaemonProfile().clearFinalizeError(),criticalFailures.length>0)getDaemonProfile().setBootState("degraded"),getDaemonProfile().logger.error("app","Agent finalized but degraded \u2014 critical plugins failed",{failures:criticalFailures.map((f)=>`${f.plugin}: ${f.error}`)});else getDaemonProfile().setBootState("ready"),getDaemonProfile().logger.info("app","Agent finalized \u2014 state=ready"),getDaemonProfile().audit.emit("agent","gateway-auth.configured",{workspaceId:safeCreds.workspaceId,organizationId:safeCreds.organizationId,agentRecordId:opts?.agentRecordId});return(async()=>{try{if(await pluginManager.provisionDefaultPrereqs(app,hostServices),getDaemonProfile().logger.info("app","Default provider prerequisites provisioned"),(serviceRegistry.listProvidersForType("tunnel")??[]).some((p)=>p.pluginName!=="bootstrap")){let{tryHandoverBootstrapTunnel}=await import("./tunnel-bootstrap-x82wcnt8.js");if(!tryHandoverBootstrapTunnel())stopBootstrapTunnel();serviceRegistry.unregisterProvider("tunnel","bootstrap"),getDaemonProfile().logger.info("app","Bootstrap tunnel handed over to the real tunnel provider")}}catch(err){getDaemonProfile().logger.warn("app","Plugin prerequisite provisioning failed",{error:String(err)})}})(),{ok:!0}}catch(err){getDaemonProfile().setBootState("awaiting-config");let msg=err instanceof Error?err.message:String(err);if(getDaemonProfile().recordFinalizeError(msg),getDaemonProfile().logger.error("app","Finalize failed",{error:msg}),process.env.VIBE_STRICT_KEY_FETCH==="1")getDaemonProfile().logger.error("app","VIBE_STRICT_KEY_FETCH=1 \u2192 aborting daemon (strict mode)",{error:msg}),setTimeout(()=>process.exit(1),50);return{ok:!1,error:msg}}finally{finalizeInFlight=null}})(),finalizeInFlight},corsPlugin=cors({origin:(request)=>{let origin=request.headers.get("origin");return!!origin&&isAllowedOrigin(origin)},credentials:!0,allowedHeaders:CORS_HEADERS.split(",").map((s)=>s.trim()),methods:CORS_METHODS.split(",").map((s)=>s.trim()),exposeHeaders:["content-type","content-length"],maxAge:86400,preflight:!0}),DEFAULT_MAX_BODY_BYTES=10485760,maxBodyEnv=process.env.VIBECONTROLS_MAX_BODY_BYTES,parsedMaxBody=maxBodyEnv?Number.parseInt(maxBodyEnv,10):NaN,maxBodySize=Number.isFinite(parsedMaxBody)&&parsedMaxBody>0?parsedMaxBody:DEFAULT_MAX_BODY_BYTES,appRef={current:null},app=new Elysia({serve:{maxRequestBodySize:maxBodySize}}).onRequest(({request,set})=>{let requestId=extractRequestId(request.headers)??generateRequestId();enterRequestContext({requestId,startedAt:new Date().toISOString()});let headers=set.headers??={};headers["X-Request-Id"]=requestId}).onRequest(({request})=>{try{let url=new URL(request.url).pathname,name=/^\/api\/profiles\/([^/]+)(?:\/|$)/.exec(url)?.[1],ctx=name?profileRegistry.get(name):null;enterProfileContext(ctx??getDaemonProfile())}catch{enterProfileContext(getDaemonProfile())}}).onRequest(({request,set})=>{let url=new URL(request.url).pathname;if(!url.startsWith("/api/"))return;if(url==="/api/profiles"||url.startsWith("/api/profiles/"))return;if(url==="/api/profile-stats"||url.startsWith("/api/profile-stats/"))return;let defaultProfileUrl=new URL(request.url);defaultProfileUrl.pathname=`/api/profiles/default${url.slice(4)}`;try{request.headers.set("x-vc-profile-rewrite","1"),request.headers.set("x-vc-profile-rewrite-target",defaultProfileUrl.pathname)}catch{}return}).derive(()=>({requestId:getRequestId()??generateRequestId()})).use(corsPlugin).use(rateLimitPlugin()).use(createAuthPlugin(()=>pluginPublicPaths())).use(idempotencyPlugin({getDb:()=>currentProfileOrNull()?.db??db})).onBeforeHandle(({request,set})=>{let state=getDaemonProfile().getBootState();if(state==="ready")return;let url=new URL(request.url).pathname;if(isFinalizeExempt(url))return;return set.status=503,{error:"Agent not yet configured",message:"Agent is in '"+state+"' state. POST credentials to /api/agent/gateway-auth to finalize.",state}}).onAfterHandle(({request,set})=>{let url=new URL(request.url).pathname,isNoisy=url==="/health"||url.startsWith("/api/logs/stream")||url.startsWith("/ui/")||url==="/ws/events"||url==="/api/sessions/health-check"||url.startsWith("/terminal/"),status=typeof set.status==="number"?set.status:200,level=isNoisy?"debug":status>=400?"warn":"info";getDaemonProfile().logger[level]("http",`${request.method} ${url} \u2192 ${status}`,{method:request.method,path:url,statusCode:status});try{recordHttpRequest(request.method,normalizeRouteLabel(url),status)}catch{}}).use(createHealthRoutes({serviceRegistry,getDb:()=>currentProfileOrNull()?.db??db,getDbPath:()=>effectiveDbPath,getPluginManager:()=>currentProfileOrNull()?.pluginManager??pluginManager})).use(createMetricsRoutes()).use(createPreConfigRoutes({serviceRegistry,runFinalize:(creds,opts)=>finalize(creds,opts),getDb:()=>currentProfileOrNull()?.db??db})).use(createInflightTracker()).use(createStatsRoutes()).use(createEditorRoutes()).use(createContextRoutes({getPluginManager:()=>currentProfileOrNull()?.pluginManager??pluginManager,getTunnelHost:()=>readTunnelState()?.url??null})).use(createProfileManagementRoutes()).use(createProfileStatsRoutes()).use(createEventsWs()).use(createLogWs()).use(createTerminalProxy(serviceRegistry)).ws("/code-server/*",buildCodeServerBridge(port)).all("/api/profiles/:name/*",async({params,request,set})=>{let hasReqBody=request.method!=="GET"&&request.method!=="HEAD",bodyBytes=hasReqBody?await request.arrayBuffer():void 0,dispatched=await dispatchProfileRequest(params.name,request,bodyBytes);if(dispatched&&dispatched.status!==404)return dispatched;let running=getVibecontrolsProfile(),requested=params.name;if(requested!==running)return set.status=404,{error:"profile-mismatch",running,requested,hint:"This daemon serves a different profile. Call GET /api/profiles to discover the right tunnel."};let u=new URL(request.url),stripped=u.pathname.replace(/^\/api\/profiles\/[^/]+/,"/api"),headers=new Headers(request.headers);headers.set("x-vc-profile-rewrite","1");let init={method:request.method,headers};if(hasReqBody&&bodyBytes!==void 0)init.body=bodyBytes;let rewritten=new Request(`${u.origin}${stripped}${u.search}`,init),target=appRef.current;if(!target)return new Response(JSON.stringify({error:"agent-not-ready"}),{status:503,headers:{"content-type":"application/json"}});return target.handle(rewritten)}).all("/api/*",async({request})=>{if(getDaemonProfile().getBootState()!=="ready"||!pluginRoutesApp)return new Response(JSON.stringify({error:"Agent not yet configured",state:getDaemonProfile().getBootState(),message:"Plugin routes are unavailable until the agent reaches state=ready. POST credentials to /api/agent/gateway-auth to finalize."}),{status:503,headers:{"content-type":"application/json"}});try{let apiUiUrl=new URL(request.url),apiUiMatch=/^\/api\/plugins\/([a-z0-9-]{1,64})\/ui(?:\/.*)?$/.exec(apiUiUrl.pathname);if(apiUiMatch&&request.method==="GET"){let plugin=apiUiMatch[1];if(isValidUiPluginName(plugin)){let restAfterUi=apiUiUrl.pathname.slice(`/api/plugins/${plugin}/ui`.length),isBareDoc=restAfterUi===""||restAfterUi==="/",looksLikeNavigation=request.headers.get("sec-fetch-mode")==="navigate";if(isBareDoc||looksLikeNavigation){let cookie=getUiCookieFromRequest(request,plugin);if(!cookie||!verifyUiCookieToken(cookie,plugin))return new Response(renderUiBootstrapHtml(plugin,"/api/profiles/default/agent/ui-exchange-plugin"),{status:200,headers:{"content-type":"text/html; charset=utf-8","Content-Security-Policy":"frame-ancestors 'self' http://localhost:* http://127.0.0.1:* https://localhost:* https://127.0.0.1:* https://*.local.burdenoff.com https://vibecontrols.com https://*.vibecontrols.com https://burdenoff.com https://app.burdenoff.com https://alphaapp.burdenoff.com"}})}}}}catch{}return pluginRoutesApp.handle(request)}).all("/ui/*",async({request})=>{if(getDaemonProfile().getBootState()!=="ready"||!uiServerApp)return new Response("Plugin UI not yet available",{status:503});return uiServerApp.handle(request)}).all("/code-server/*",async({request})=>{if(getDaemonProfile().getBootState()!=="ready"||!pluginRoutesApp)return new Response("code-server not yet available",{status:503});return pluginRoutesApp.handle(request)}).all("/plan/*",async({request})=>{if(getDaemonProfile().getBootState()!=="ready"||!pluginRoutesApp)return new Response("plan provider not yet available",{status:503});return pluginRoutesApp.handle(request)});return appRef.current=app,{app,async start(){app.listen({port,hostname:host}),getDaemonProfile().logger.info("app",`Agent server listening on ${host}:${port}`);try{let list=(process.env.VIBECONTROLS_PROFILES??"").split(",").map((s)=>s.trim()).filter(Boolean),bootName=getDaemonProfile().name,{getOrCreateProfile:getOrCreateProfile2}=await import("./daemon-profile-c7zt62gk.js"),{attachSecondaryProfile}=await import("./secondary-profile-attach-9c1rp4y7.js"),strict=process.env.VIBE_STRICT_KEY_FETCH==="1";for(let name of list){if(name===bootName)continue;try{let ctx=getOrCreateProfile2(name),result=await attachSecondaryProfile(ctx);if(result.ok)getDaemonProfile().logger.info("app",`Secondary profile '${name}' attached (db+services online)`);else if(strict)throw Error(`attachServices for secondary profile '${name}' failed: ${result.error}`);else ctx.recordDegradedReason("attach",result.error??"unknown"),getDaemonProfile().logger.warn("app",`Secondary profile '${name}' is degraded (no creds / attach failed)`,{error:result.error})}catch(err){if(strict)throw getDaemonProfile().logger.error("app",`--strict-key-fetch: secondary profile '${name}' attach failed; aborting`,{error:String(err)}),setTimeout(()=>process.exit(1),50),err;getDaemonProfile().logger.warn("app",`Failed to attach secondary profile '${name}'`,{error:String(err)})}}}catch{}return app},stop:stopFn,finalize,getState:()=>getDaemonProfile().getBootState(),getLifecycle:()=>currentProfileOrNull()?.lifecycle??lifecycle,getDb:()=>currentProfileOrNull()?.db??db,getServiceRegistry:()=>currentProfileOrNull()?.serviceRegistry??serviceRegistry,getPluginManager:()=>currentProfileOrNull()?.pluginManager??pluginManager,getHostServices:()=>currentProfileOrNull()?.hostServices??hostServices}}var codeServerSessionValidator=null;function getCookieValue(cookieHeader,name){if(!cookieHeader)return null;let m=cookieHeader.match(new RegExp(`(?:^|;\\s*)${name}=([^;]*)`));return m?m[1]:null}function buildCodeServerBridge(port){let payloadBytes=(payload)=>typeof payload==="string"?Buffer.byteLength(payload):payload.byteLength;return{open(ws){let wsData=ws.data,apiKey=wsData.query?.apiKey??getApiKeyFromHeaders(wsData.headers??{})??getApiKeyFromHeaders(wsData.request?Object.fromEntries(wsData.request.headers.entries()):{});if(!isValidAgentApiKey(apiKey)){let cookieHeader=wsData.headers?.cookie??wsData.request?.headers.get("cookie")??null,sessionToken=getCookieValue(cookieHeader,"__vibe_cs_session");if(!sessionToken||!codeServerSessionValidator?.(sessionToken)){ws.close(1008,"Unauthorized");return}}let bridgeProfile=getDaemonProfile().name;fetch(`http://127.0.0.1:${port}/api/profiles/${encodeURIComponent(bridgeProfile)}/code-server/status`,{headers:{"x-agent-api-key":getAgentApiKey()}}).then((r)=>r.json()).then((raw)=>{if(wsData._csClosed)return;let status=raw;if(!status.running||!status.port){ws.close(1011,"code-server not running");return}let requestUrl=wsData.request?.url??"/code-server/",upstreamPath;try{let url=new URL(requestUrl,`http://127.0.0.1:${status.port}`);upstreamPath=(url.pathname.replace(/^\/code-server\/?/,"/")||"/")+url.search}catch{upstreamPath="/"}let upstreamWs=new WebSocket(`ws://127.0.0.1:${status.port}${upstreamPath}`),state={upstream:upstreamWs,ready:!1,buffer:[],bufferBytes:0,openTimer:setTimeout(()=>{try{upstreamWs.close(1011,"upstream open timeout")}catch{}try{ws.close(1011,"upstream open timeout")}catch{}},1e4)};wsData._csBridge=state,upstreamWs.addEventListener("open",()=>{clearTimeout(state.openTimer),state.ready=!0;for(let msg of state.buffer)upstreamWs.send(msg);state.buffer.length=0,state.bufferBytes=0}),upstreamWs.addEventListener("message",(event)=>{try{let d=event.data;if(d instanceof ArrayBuffer)ws.send(new Uint8Array(d));else if(d instanceof Blob)d.arrayBuffer().then((ab)=>{try{ws.send(new Uint8Array(ab))}catch{}});else ws.send(d)}catch{}}),upstreamWs.addEventListener("close",(event)=>{clearTimeout(state.openTimer);try{ws.close(event.code||1000,event.reason||"upstream closed")}catch{}}),upstreamWs.addEventListener("error",()=>{clearTimeout(state.openTimer);try{ws.close(1011,"upstream error")}catch{}})}).catch(()=>{ws.close(1011,"Failed to query code-server status")})},message(ws,message){let state=ws.data?._csBridge;if(!state)return;let payload;if(typeof message==="string")payload=message;else if(message instanceof ArrayBuffer)payload=message;else if(message instanceof Uint8Array||Buffer.isBuffer(message)){let copy=new ArrayBuffer(message.byteLength);new Uint8Array(copy).set(new Uint8Array(message.buffer,message.byteOffset,message.byteLength)),payload=copy}else if(typeof message==="object"&&message!==null)payload=JSON.stringify(message);else payload=String(message);if(state.upstream&&state.ready&&state.upstream.readyState===WebSocket.OPEN)try{state.upstream.send(payload)}catch{}else{let nextBytes=payloadBytes(payload);if(state.buffer.length>=256||state.bufferBytes+nextBytes>1048576){try{state.upstream.close(1013,"buffer limit exceeded")}catch{}try{ws.close(1013,"buffer limit exceeded")}catch{}return}state.buffer.push(payload),state.bufferBytes+=nextBytes}},close(ws){ws.data._csClosed=!0;let state=ws.data?._csBridge;if(state?.openTimer)clearTimeout(state.openTimer);if(state?.upstream&&state.upstream.readyState===WebSocket.OPEN)state.upstream.close(1000,"client disconnected")}}}async function getPackageVersion(){try{let{readFileSync:readFileSync3}=await import("fs"),{join:join4,dirname:dirname2}=await import("path"),{fileURLToPath}=await import("url"),__dirname2=dirname2(fileURLToPath(import.meta.url));return JSON.parse(readFileSync3(join4(__dirname2,"..","package.json"),"utf8")).version||"1.0.0"}catch{return"1.0.0"}}
4
+ `)||sid.includes("|"))return set.status=400,{error:"BadRequest",message:"invalid sid"};let expectedPath=`/terminal/${sid}`,verifyResult=verifyIframeTokenWithReason(token,expectedPath);if(!verifyResult.ok)return getDaemonProfile().logger.warn("terminal-exchange","iframe token rejected",{sid,reason:verifyResult.reason}),set.status=401,{error:"Unauthorized",message:"invalid iframe token",code:verifyResult.reason==="expired"?"expired":verifyResult.reason==="replayed"?"replayed":"invalid"};let cookie=issueTerminalCookieToken(sid,600),cookieName=`vt_term_${sid}`;return set.headers["set-cookie"]=`${cookieName}=${cookie.token}; HttpOnly; Secure; SameSite=None; Path=/terminal/${sid}; Max-Age=600`,set.status=204,null},{body:t.Object({sid:t.String({minLength:1}),token:t.String({minLength:1})})}).post("/ui-exchange",({body,set})=>{let{plugin,token}=body;if(!plugin||!token)return set.status=400,{error:"BadRequest",message:"plugin and token required"};if(!isValidUiPluginName(plugin))return set.status=400,{error:"BadRequest",message:"invalid plugin name"};let expectedPath=`/ui/${plugin}`;if(!verifyIframeToken(token,expectedPath))return set.status=401,{error:"Unauthorized",message:"invalid iframe token"};let cookie=issueUiCookieToken(plugin,600),cookieName=`vt_ui_${plugin}`;return set.headers["set-cookie"]=`${cookieName}=${cookie.token}; HttpOnly; Secure; SameSite=None; Path=/ui/${plugin}/; Max-Age=600`,set.status=204,null},{body:t.Object({plugin:t.String({minLength:1}),token:t.String({minLength:1})})}).post("/ui-exchange-plugin",({body,set})=>{let{plugin,token}=body;if(!plugin||!token)return set.status=400,{error:"BadRequest",message:"plugin and token required"};if(!isValidUiPluginName(plugin))return set.status=400,{error:"BadRequest",message:"invalid plugin name"};if(![`/api/plugins/${plugin}/ui`,`/${plugin}`].find((p)=>verifyIframeToken(token,p)))return set.status=401,{error:"Unauthorized",message:"invalid iframe token"};let cookie=issueUiCookieToken(plugin,600),cookieName=`vt_ui_${plugin}`;return set.headers["set-cookie"]=`${cookieName}=${cookie.token}; HttpOnly; Secure; SameSite=None; Path=/api/plugins/${plugin}/ui/; Max-Age=600`,set.status=204,null},{body:t.Object({plugin:t.String({minLength:1}),token:t.String({minLength:1})})}).get("/system",()=>({hostname:os.hostname(),platform:os.platform(),arch:os.arch(),release:os.release(),cpus:os.cpus().length,totalMemory:os.totalmem(),freeMemory:os.freemem(),uptime:os.uptime(),bunVersion:typeof Bun<"u"?Bun.version:void 0,agentVersion:version,homeDir:os.homedir(),cwd:process.cwd(),environment:"production"})).get("/tunnel",async()=>{let url=await getActiveTunnelUrl(serviceRegistry);if(!url)return{tunnelUrl:null,message:"No tunnel provider registered"};return{tunnelUrl:url}}).get("/status",()=>{let providers=["tunnel","session","ai"].filter((type)=>serviceRegistry.hasProvider(type));return{state:getDaemonProfile().getBootState(),status:getDaemonProfile().getBootState(),version,providers,timestamp:new Date().toISOString()}}).get("/gateway-auth",()=>({configured:gatewayClient.isConfigured(),config:redactUnknownSecrets(gatewayClient.getConfig()),state:getDaemonProfile().getBootState()})).post("/retry-config",async({set})=>{let{getFinalizeRetryHandle}=await import("./finalize-retry-handle-registry-vbq5qhj1.js"),handle=getFinalizeRetryHandle();if(!handle)return set.status=409,{ok:!1,error:"No finalize retry worker is active. The agent either never had cached credentials to retry with, or it already reached the ready state."};let result=await handle.forceRetryNow();if(!result.ok)set.status=503;return{ok:result.ok,error:result.ok?void 0:result.error,state:getDaemonProfile().getBootState(),worker:handle.getState()}}).post("/gateway-auth",async({body,request,set})=>{let stateForAuth=getDaemonProfile().getBootState(),headerMap=Object.fromEntries(request.headers.entries());if(stateForAuth==="ready"){let provided=getApiKeyFromHeaders(headerMap);if(!isValidAgentApiKey(provided))return set.status=401,{success:!1,state:stateForAuth,error:"Unauthorized: API key required to reconfigure"}}else{let apiKey=getApiKeyFromHeaders(headerMap),pairing=getPairingTokenFromHeaders(headerMap),apiKeyOk=isValidAgentApiKey(apiKey),pairingOk=isValidPairingToken(pairing);if(!apiKeyOk&&!pairingOk)return set.status=401,{success:!1,state:stateForAuth,error:"Unauthorized: provide x-agent-api-key OR x-pairing-token for bootstrap"}}let{clientId,clientSecret,workspaceId,globalGatewayUrl,workspaceGatewayUrl}=body;if(!clientId||!clientSecret||!workspaceId||!globalGatewayUrl||!workspaceGatewayUrl)return set.status=400,{success:!1,state:getDaemonProfile().getBootState(),error:"clientId, clientSecret, workspaceId, globalGatewayUrl, and workspaceGatewayUrl are required"};let safeGlobalGatewayUrl,safeWorkspaceGatewayUrl;try{safeGlobalGatewayUrl=assertAllowedGatewayUrl(globalGatewayUrl,"globalGatewayUrl"),safeWorkspaceGatewayUrl=assertAllowedGatewayUrl(workspaceGatewayUrl,"workspaceGatewayUrl")}catch(err){return set.status=400,{success:!1,state:getDaemonProfile().getBootState(),error:err instanceof Error?err.message:String(err)}}{let ctx=currentProfileOrNull()??getDaemonProfile();try{await writeAgentConfigAwaitSecrets({clientId,clientSecret,workspaceId,organizationId:body.organizationId,globalGatewayUrl:safeGlobalGatewayUrl,workspaceGatewayUrl:safeWorkspaceGatewayUrl,agentRecordId:body.agentRecordId,scopes:body.scopes},{dir:ctx.dataDir,scope:ctx.name})}catch(err){return set.status=500,{success:!1,state:getDaemonProfile().getBootState(),error:`Failed to persist gateway credentials to secrets backend: ${err instanceof Error?err.message:String(err)}`}}}let state=getDaemonProfile().getBootState();if(state==="ready"){let db=getDb();if(db){if(await db.setConfig("gateway-auth:clientId",clientId),await db.setConfig("gateway-auth:clientSecret",clientSecret),await db.setConfig("gateway-auth:workspaceId",workspaceId),body.organizationId)await db.setConfig("gateway-auth:organizationId",body.organizationId);if(await db.setConfig("gateway-auth:globalGatewayUrl",safeGlobalGatewayUrl),await db.setConfig("gateway-auth:workspaceGatewayUrl",safeWorkspaceGatewayUrl),body.agentRecordId)await db.setConfig("gateway-auth:agentRecordId",body.agentRecordId)}return gatewayClient.configure({globalGatewayUrl:safeGlobalGatewayUrl,workspaceGatewayUrl:safeWorkspaceGatewayUrl,clientId,clientSecret,workspaceId,organizationId:body.organizationId}),getDaemonProfile().logger.info("preconfig","Gateway credentials re-configured (agent was already ready)"),{success:!0,state,message:"Gateway auth re-configured"}}return getDaemonProfile().logger.info("preconfig","Gateway credentials received \u2014 beginning finalize (background)"),invalidatePairingToken(),runFinalize({clientId,clientSecret,workspaceId,organizationId:body.organizationId,globalGatewayUrl:safeGlobalGatewayUrl,workspaceGatewayUrl:safeWorkspaceGatewayUrl},{agentRecordId:body.agentRecordId,scopes:body.scopes}).catch((err)=>{getDaemonProfile().logger.error("preconfig","Background finalize threw",{error:err instanceof Error?err.message:String(err)})}),set.status=202,{success:!0,state:getDaemonProfile().getBootState(),agentRecordId:body.agentRecordId,message:"Gateway credentials accepted; finalize is running in the background. Poll /health/ready for completion."}},{body:t.Object({clientId:t.Optional(t.String()),clientSecret:t.Optional(t.String()),workspaceId:t.Optional(t.String()),organizationId:t.Optional(t.String()),globalGatewayUrl:t.Optional(t.String()),workspaceGatewayUrl:t.Optional(t.String()),scopes:t.Optional(t.Array(t.String())),agentRecordId:t.Optional(t.String())})})}import{existsSync as existsSync2,mkdirSync as mkdirSync2,rmSync,readdirSync}from"fs";import{join as join3}from"path";function profileDir(name){return join3(getVibecontrolsProductDir(),"agents",validateAgentName(name))}function listProfileNames(){let dir=join3(getVibecontrolsProductDir(),"agents");if(!existsSync2(dir))return[];return readdirSync(dir,{withFileTypes:!0}).filter((entry)=>entry.isDirectory()).map((entry)=>entry.name).filter((name)=>/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(name))}function profileDataDir(name){return join3(getVibecontrolsProductDir(),"agents",validateAgentName(name))}function readConfigForProfile(name){return readAgentConfig({dir:profileDataDir(name)})}function writeConfigForProfile(name,cfg){return writeAgentConfig(cfg,{dir:profileDataDir(name),scope:validateAgentName(name)})}function summarize(name){let defaultName=getDefaultProfile(),instance=getInstances().find((p)=>p.name===name),ctx=profileRegistry.get(name),summary={name,isDefault:name===defaultName,isRunning:instance?.status==="running",attached:ctx!==void 0,bootState:ctx?ctx.getBootState():null,dataDir:ctx?ctx.dataDir:null};if(instance)summary.port=instance.port,summary.pid=instance.pid,summary.startTime=instance.startTime;if(existsSync2(profileDir(name)))summary.config=redactUnknownSecrets(readConfigForProfile(name));return summary}function createProfileManagementRoutes(deps={}){let sm=deps.serviceManagerFactory?deps.serviceManagerFactory():new ServiceManager;return new Elysia({prefix:"/api/profiles"}).get("/",()=>{let onDisk=listProfileNames(),defaultName=getDefaultProfile(),names=new Set(onDisk);return names.add(defaultName),[...names].sort().map((n)=>summarize(n))}).post("/",async({body,set})=>{try{let name=validateAgentName(body.name),dir=profileDir(name);if(existsSync2(dir))return set.status=409,{error:"exists",message:`Profile '${name}' already exists.`};let seed;if(body.copyFrom){let src=validateAgentName(body.copyFrom);if(!existsSync2(profileDir(src)))return set.status=400,{error:"copy-source-missing",message:`Profile '${src}' does not exist.`};seed=readConfigForProfile(src),delete seed["static-api-key"],delete seed.agentRecordId,delete seed.apiKeys}else seed=getAgentConfigSeed();if(body.gatewayUrl)seed.globalGatewayUrl=body.gatewayUrl;if(body.workspaceGatewayUrl)seed.workspaceGatewayUrl=body.workspaceGatewayUrl;if(body.clientId)seed.clientId=body.clientId;if(body.clientSecret)seed.clientSecret=body.clientSecret;if(body.workspaceId)seed.workspaceId=body.workspaceId;if(body.organizationId)seed.organizationId=body.organizationId;mkdirSync2(dir,{recursive:!0}),writeConfigForProfile(name,seed);try{getOrCreateProfile(name)}catch(err){getDaemonProfile().logger.warn("profile-mgmt",`In-process attach failed for '${name}'`,{error:String(err)})}if(getDaemonProfile().logger.info("profile-mgmt",`Created profile '${name}' at ${dir}`),body.start){let startCfg={name,port:body.port??0,daemon:!0,dbPath:getProfileDataDir(),profile:name};await sm.startDaemon(startCfg)}return set.status=201,summarize(name)}catch(err){return set.status=400,{error:"create-failed",message:err instanceof Error?err.message:String(err)}}},{body:t.Object({name:t.String(),gatewayUrl:t.Optional(t.String()),workspaceGatewayUrl:t.Optional(t.String()),clientId:t.Optional(t.String()),clientSecret:t.Optional(t.String()),workspaceId:t.Optional(t.String()),organizationId:t.Optional(t.String()),copyFrom:t.Optional(t.String()),start:t.Optional(t.Boolean()),port:t.Optional(t.Number())})}).get("/:name",({params,set})=>{try{let name=validateAgentName(params.name);if(!existsSync2(profileDir(name)))return set.status=404,{error:"not-found",message:`No profile '${name}'.`};return summarize(name)}catch(err){return set.status=400,{error:"bad-request",message:err instanceof Error?err.message:String(err)}}},{params:t.Object({name:t.String()})}).put("/:name",({params,body,set})=>{try{let name=validateAgentName(params.name);if(!existsSync2(profileDir(name)))return set.status=404,{error:"not-found",message:`No profile '${name}'.`};let forbidden=["static-api-key","apiKeys","agentRecordId"];for(let key of forbidden)if(key in body)return set.status=400,{error:"forbidden-field",message:`Field '${key}' is managed via dedicated commands (vibe key rotate / vibe profile create). It cannot be patched here.`};let next={...readConfigForProfile(name),...body};return writeConfigForProfile(name,next),summarize(name)}catch(err){return set.status=400,{error:"update-failed",message:err instanceof Error?err.message:String(err)}}},{params:t.Object({name:t.String()}),body:t.Record(t.String(),t.Any())}).delete("/:name",async({params,body,query,set})=>{try{let name=validateAgentName(params.name);if(name===getDefaultProfile())return set.status=409,{error:"is-default",message:`Cannot delete active default profile '${name}'. Switch to another profile first.`};let purge=query?.purge==="true"||query?.purge==="1",hasDir=existsSync2(profileDir(name)),inRegistry=profileRegistry.has(name);if(!hasDir&&!inRegistry)return set.status=404,{error:"not-found",message:`No profile '${name}'.`};if(hasDir&&!purge&&!body?.confirm)return set.status=400,{error:"confirm-required",message:"Pass { confirm: true } in the body or `?purge=true` in the query to delete the on-disk dataDir (destructive)."};try{await sm.stop(name)}catch{}try{await profileRegistry.destroy(name)}catch(err){getDaemonProfile().logger.warn("profile-mgmt",`In-process detach failed for '${name}'`,{error:String(err)})}if(hasDir)if(body?.keepConfig)for(let entry of readdirSync(profileDir(name))){if(entry==="config.json")continue;rmSync(join3(profileDir(name),entry),{recursive:!0,force:!0})}else rmSync(profileDir(name),{recursive:!0,force:!0});return getDaemonProfile().logger.info("profile-mgmt",`Deleted profile '${name}'`),{ok:!0,deleted:name,keptConfig:!!body?.keepConfig,detached:inRegistry,purged:hasDir}}catch(err){return set.status=400,{error:"delete-failed",message:err instanceof Error?err.message:String(err)}}},{params:t.Object({name:t.String()}),query:t.Optional(t.Object({purge:t.Optional(t.String())})),body:t.Optional(t.Object({confirm:t.Optional(t.Boolean()),keepConfig:t.Optional(t.Boolean())}))}).post("/:name/switch",({params,set})=>{try{let name=validateAgentName(params.name);if(!existsSync2(profileDir(name)))return set.status=404,{error:"not-found",message:`No profile '${name}'.`};return setDefaultProfile(name),getDaemonProfile().logger.info("profile-mgmt",`Default profile switched to '${name}'`),{ok:!0,defaultProfile:name}}catch(err){return set.status=400,{error:"switch-failed",message:err instanceof Error?err.message:String(err)}}},{params:t.Object({name:t.String()})}).post("/:name/start",async({params,body,set})=>{try{let name=validateAgentName(params.name);if(!existsSync2(profileDir(name)))return set.status=404,{error:"not-found",message:`No profile '${name}'.`};try{getOrCreateProfile(name)}catch(err){getDaemonProfile().logger.warn("profile-mgmt",`In-process attach failed for '${name}'`,{error:String(err)})}if(!getInstances().some((p)=>p.name===name&&p.status==="running")){let startCfg={name,port:body?.port??0,daemon:!0,dbPath:getProfileDataDir(),profile:name};await sm.startDaemon(startCfg)}return summarize(name)}catch(err){return set.status=500,{error:"start-failed",message:err instanceof Error?err.message:String(err)}}},{params:t.Object({name:t.String()}),body:t.Optional(t.Object({port:t.Optional(t.Number())}))}).post("/:name/stop",async({params,set})=>{try{let name=validateAgentName(params.name);try{await sm.stop(name)}catch{}try{await profileRegistry.destroy(name)}catch(err){getDaemonProfile().logger.warn("profile-mgmt",`In-process detach failed for '${name}'`,{error:String(err)})}return summarize(name)}catch(err){return set.status=500,{error:"stop-failed",message:err instanceof Error?err.message:String(err)}}},{params:t.Object({name:t.String()})})}function buildProfileStats(){let rss=process.memoryUsage(),ru=process.resourceUsage(),totalCpuUserMs=ru.userCPUTime/1000,totalCpuSystemMs=ru.systemCPUTime/1000,totalCpuMs=totalCpuUserMs+totalCpuSystemMs,profiles=profileRegistry.list().map((ctx)=>{let childPidCount;try{childPidCount=listTrackedByOwner(ctx.spawnOwnerKey).length}catch{childPidCount=0}return{name:ctx.name,status:ctx.getBootState(),childPidCount,cpuMs:totalCpuMs,heapBytes:rss.heapUsed,dataDir:ctx.dataDir}});return{process:{pid:process.pid,uptimeSeconds:process.uptime(),cpuUserMs:totalCpuUserMs,cpuSystemMs:totalCpuSystemMs,heapUsedBytes:rss.heapUsed,heapTotalBytes:rss.heapTotal,rssBytes:rss.rss},profiles,notes:{perProfileCpu:"deferred",perProfileHeap:"deferred"}}}function createProfileStatsRoutes(){return new Elysia({prefix:"/api/profile-stats"}).get("/",()=>buildProfileStats())}function withTimeout(p,ms){return Promise.race([p,new Promise((_,reject)=>setTimeout(()=>reject(Error(`timeout after ${ms}ms`)),ms))])}function isEnoent(err){let msg=err instanceof Error?err.message:String(err);return/ENOENT/.test(msg)||/no such file or directory/i.test(msg)}async function runDbProbe(db){let probeKey=`__health__:probe:${typeof crypto<"u"&&typeof crypto.randomUUID==="function"?crypto.randomUUID():`${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`}`,value=String(Date.now());if(await withTimeout(db.setConfig(probeKey,value),2000),await withTimeout(db.getConfig(probeKey),2000)!==value)throw Error("round-trip mismatch");try{await withTimeout(db.deleteConfig(probeKey),500)}catch{}}async function checkDb(db,dbPath){if(!db)return{ok:!1,message:"database not opened"};let start=performance.now();try{return await runDbProbe(db),{ok:!0,durationMs:performance.now()-start}}catch(err){if(dbPath&&isEnoent(err))try{return(await import("fs")).mkdirSync(dbPath,{recursive:!0}),await runDbProbe(db),{ok:!0,message:`recovered: dbPath ${dbPath} was missing \u2014 recreated`,durationMs:performance.now()-start}}catch(retryErr){return{ok:!1,message:`ENOENT on dbPath ${dbPath}: ${retryErr instanceof Error?retryErr.message:String(retryErr)}`,durationMs:performance.now()-start}}return{ok:!1,message:err instanceof Error?err.message:String(err),durationMs:performance.now()-start}}}function checkProvider(registry,type){if(!registry)return{ok:!1,message:"no service registry"};let awaiting=getDaemonProfile().getBootState()==="awaiting-config";if(type==="tunnel"){let p=registry.getProvider("tunnel");if(!p&&process.env.AGENT_TUNNEL==="false")return{ok:!0,message:"tunnel disabled via AGENT_TUNNEL=false"};if(p)return{ok:!0,message:`provider: ${p.name}`};return{ok:!1,message:awaiting?"agent is awaiting-config \u2014 POST OAuth credentials to /api/agent/gateway-auth to register tunnel provider":"no tunnel provider registered"}}if(type==="session"){let p=registry.getProvider("session");if(p)return{ok:!0,message:`provider: ${p.name}`};return{ok:!1,message:awaiting?"agent is awaiting-config \u2014 POST OAuth credentials to /api/agent/gateway-auth to register session provider":"no session provider registered"}}return{ok:!0}}async function checkPluginHealth(pm){if(!pm)return{};let results={};for(let plugin of pm.getAllPlugins()){let fn=plugin.getHealth;if(typeof fn!=="function")continue;let start=performance.now();try{let out=await withTimeout(Promise.resolve(fn.call(plugin)),2000);results[plugin.name]={ok:out?.ok!==!1,message:out?.message,durationMs:performance.now()-start}}catch(err){results[plugin.name]={ok:!1,message:err instanceof Error?err.message:String(err),durationMs:performance.now()-start}}}return results}function createHealthRoutes(depsOrRegistry){let deps=depsOrRegistry&&"serviceRegistry"in depsOrRegistry?depsOrRegistry:{serviceRegistry:depsOrRegistry};return new Elysia({prefix:"/health"}).get("/",()=>{return{status:"ok",lifecycleState:deps.serviceRegistry?.getService("agent","lifecycle")?.getState()??"running",bootState:getDaemonProfile().getBootState(),timestamp:new Date().toISOString(),uptime:process.uptime()}}).get("/live",()=>({status:"ok"})).get("/ready",async({set})=>{let lifecycleState=deps.serviceRegistry?.getService("agent","lifecycle")?.getState()??"running",bootState=getDaemonProfile().getBootState(),components={};components.boot={ok:bootState==="ready",message:bootState==="ready"?void 0:`boot state ${bootState}`},components.lifecycle={ok:lifecycleState==="running",message:lifecycleState==="running"?void 0:`lifecycle ${lifecycleState}`},components.db=await checkDb(deps.getDb?.()??null,deps.getDbPath?.()??null),components.tunnel=checkProvider(deps.serviceRegistry,"tunnel"),components.session=checkProvider(deps.serviceRegistry,"session");let plugins=await checkPluginHealth(deps.getPluginManager?.()??null),allOk=Object.values(components).every((r)=>r.ok)&&Object.values(plugins).every((r)=>r.ok);if(!allOk)set.status=503;let reasons=bootState==="degraded"?getDaemonProfile().getDegradedReasons():[],daemonName=getDaemonProfile().name,profilesMap={};for(let ctx of profileRegistry.list())profilesMap[ctx.name]={bootState:ctx.getBootState(),ok:ctx.getBootState()==="ready",degradedReasons:ctx.getDegradedReasons()};let lastFinalizeError=getDaemonProfile().getLastFinalizeError(),body={status:allOk?"ok":"degraded",lifecycleState,bootState,daemon:{profile:daemonName,bootState,ok:bootState==="ready"},profiles:profilesMap,components,plugins,degradedReasons:reasons,lastFinalizeError,timestamp:new Date().toISOString()};if(!allOk)getDaemonProfile().logger.warn("health","Readiness probe failed",{components,plugins,bootState});return body})}var inflight=0,totalServed=0;function createInflightTracker(){return new Elysia({name:"inflight-tracker"}).onRequest(()=>{inflight+=1}).onAfterResponse(()=>{inflight=Math.max(0,inflight-1),totalServed+=1})}function createStatsRoutes(){return new Elysia({prefix:"/api/stats"}).get("/inflight",()=>({inflight:Math.max(0,inflight-1),totalServed}))}var ALLOWED_COMMANDS=Object.freeze(["code","code-insiders","codium","cursor","idea","pycharm","webstorm","goland","phpstorm","rubymine","clion","rider","zed","subl","vim","nvim","emacs","neovide","fleet","helix"]),ALLOWED_SET=new Set(ALLOWED_COMMANDS),ALLOWED_ARG_FLAGS=new Set(["--new-window","-n","--reuse-window","-r","--wait","-w","--add","--goto"]);function which(cmd){try{return Bun.which(cmd)??null}catch{return null}}function createEditorRoutes(){return new Elysia({prefix:"/api/editor"}).get("/allowlist",()=>({commands:[...ALLOWED_COMMANDS]})).get("/detect",async()=>{let results=ALLOWED_COMMANDS.map((cmd)=>[cmd,which(cmd)]),available=[],paths={};for(let[cmd,p]of results)if(p)available.push(cmd),paths[cmd]=p;return{available,paths}}).post("/open",async({body,set})=>{let{command,path:rawPath,args=[]}=body;if(!ALLOWED_SET.has(command))return set.status=400,{ok:!1,error:`Command '${command}' is not in the IDE allowlist`};for(let a of args)if(typeof a!=="string"||!ALLOWED_ARG_FLAGS.has(a))return set.status=400,{ok:!1,error:`Argument '${a}' is not in the flag allowlist`};let resolvedPath;try{resolvedPath=(await resolveSafePath(rawPath,{mustExist:!0})).realPath}catch(err){return set.status=400,{ok:!1,error:`Invalid path: ${err instanceof Error?err.message:String(err)}`}}let resolvedCmd=which(command);if(!resolvedCmd)return set.status=404,{ok:!1,error:`'${command}' is not installed or not on PATH on this agent`};try{let child=spawnTracked({owner:`editor:${command}`,cmd:[resolvedCmd,...args,resolvedPath],env:process.env,stdout:"ignore",stderr:"ignore",stdin:"ignore",meta:{command,path:resolvedPath}});return getDaemonProfile().logger.info("editor",`Launched ${command} on ${resolvedPath}`,{pid:child.pid}),getDaemonProfile().audit.emit("agent","editor.open",{command,path:resolvedPath,pid:child.pid}),{ok:!0,command,resolvedPath,pid:child.pid}}catch(err){return set.status=500,{ok:!1,error:`Failed to spawn editor: ${err instanceof Error?err.message:String(err)}`}}},{body:t.Object({command:t.String({minLength:1,maxLength:40}),path:t.String({minLength:1,maxLength:4096}),args:t.Optional(t.Array(t.String({maxLength:32})))})})}var REGISTRY_KEY=Symbol.for("@vibecontrols/plugin-sdk:contextProviders@1");function getRegistry(){let slots=globalThis,existing=slots[REGISTRY_KEY];if(existing)return existing;let created=new Map;return slots[REGISTRY_KEY]=created,created}function listContextProviders(){return Array.from(getRegistry().values())}function safeHost(maybeUrl){if(!maybeUrl)return null;try{return new URL(maybeUrl).host}catch{return null}}async function buildAgentSelfContext(deps,args){let pm=deps.getPluginManager(),loadedPlugins=pm?pm.getPluginDetails().map((p)=>({pluginName:p.pluginName,packageName:p.packageName,version:p.version,tags:p.tags??[]})):[],mem=process.memoryUsage(),tunnelHost=safeHost(deps.getTunnelHost?.()??null);return{pluginName:"agent",description:"vibecontrols-agent runtime self-report",generatedAt:new Date().toISOString(),data:{profile:args.profile,vibeId:args.vibeId??null,runtime:{bunVersion:typeof Bun<"u"?Bun.version:null,nodeVersion:process.versions.node??null,platform:process.platform,arch:process.arch,pid:process.pid,uptimeSeconds:Math.round(process.uptime()),memory:{rssMB:Math.round(mem.rss/1048576),heapUsedMB:Math.round(mem.heapUsed/1048576)}},agent:{version:deps.getAgentVersion?.()??null,profileRegistered:getVibecontrolsProfile(),tunnelHost},plugins:{count:loadedPlugins.length,items:loadedPlugins}}}}var DEFAULT_PROVIDER_TIMEOUT_MS=2000,SINGLE_FLIGHT_TTL_MS=1000;async function withTimeout2(promise,timeoutMs){let timer,timeout=new Promise((_,reject)=>{timer=setTimeout(()=>reject(Error(`timeout after ${timeoutMs}ms`)),timeoutMs)});try{return await Promise.race([promise,timeout])}finally{if(timer)clearTimeout(timer)}}async function runOne(provider,args){let start=performance.now(),timeoutMs=provider.timeoutMs??DEFAULT_PROVIDER_TIMEOUT_MS;try{let data=await withTimeout2(provider.getContext(args),timeoutMs);if(!data.generatedAt)data.generatedAt=new Date().toISOString();return{ok:!0,data,durationMs:Math.round(performance.now()-start)}}catch(err){return{ok:!1,error:err.message??String(err),durationMs:Math.round(performance.now()-start)}}}class ContextAggregator{deps;inflight=new Map;constructor(deps){this.deps=deps}async aggregate(args){let key=`${args.profile}::${args.vibeId??""}`,existing=this.inflight.get(key);if(existing&&Date.now()-existing.ts<SINGLE_FLIGHT_TTL_MS)return existing.promise;let promise=this.doAggregate(args).finally(()=>{setTimeout(()=>{let entry=this.inflight.get(key);if(entry&&entry.promise===promise)this.inflight.delete(key)},SINGLE_FLIGHT_TTL_MS).unref?.()});return this.inflight.set(key,{ts:Date.now(),promise}),promise}async selfContext(args){return buildAgentSelfContext(this.deps,args)}async pluginContext(name,args){let provider=listContextProviders().find((p)=>p.name===name);if(!provider)return null;return runOne(provider,args)}async pluginsContext(args){let providers=listContextProviders(),settled=await Promise.allSettled(providers.map((p)=>runOne(p,args))),out={};return providers.forEach((p,i)=>{let r=settled[i];if(r&&r.status==="fulfilled")out[p.name]=r.value;else if(r&&r.status==="rejected")out[p.name]={ok:!1,error:r.reason instanceof Error?r.reason.message:String(r.reason),durationMs:0}}),out}async doAggregate(args){let[agent,plugins]=await Promise.all([this.selfContext(args),this.pluginsContext(args)]);return{agent,plugins}}}function parseVibeId(query){let raw=query.vibeId;if(typeof raw!=="string")return;let v=raw.trim();return v.length>0&&v.length<=128?v:void 0}function createContextRoutes(deps){let aggregator=new ContextAggregator(deps);return new Elysia({prefix:"/api/agent/context"}).get("/",async({params,query})=>{let profile=params?.profile??"default",vibeId=parseVibeId(query);return aggregator.aggregate({profile,vibeId})},{query:t.Object({vibeId:t.Optional(t.String())})}).get("/agent",async({params,query})=>{let profile=params?.profile??"default",vibeId=parseVibeId(query);return aggregator.selfContext({profile,vibeId})},{query:t.Object({vibeId:t.Optional(t.String())})}).get("/plugins",async({params,query})=>{let profile=params?.profile??"default",vibeId=parseVibeId(query);return aggregator.pluginsContext({profile,vibeId})},{query:t.Object({vibeId:t.Optional(t.String())})}).get("/plugins/:name",async({params,query,set})=>{let profile=params?.profile??"default",name=params?.name;if(!name)return set.status=400,{error:"missing plugin name"};let vibeId=parseVibeId(query),entry=await aggregator.pluginContext(name,{profile,vibeId});if(!entry)return set.status=404,{error:`no context provider registered under name "${name}"`};return entry},{params:t.Object({name:t.String()}),query:t.Object({vibeId:t.Optional(t.String())})})}var FINALIZE_EXEMPT_PREFIXES=["/health","/api/agent/status","/api/agent/version","/api/agent/identity","/api/agent/api-key","/api/agent/tunnel","/api/agent/system","/api/agent/gateway-auth","/api/stats","/metrics","/api/profiles","/api/profile-stats"];function isFinalizeExempt(path){return FINALIZE_EXEMPT_PREFIXES.some((p)=>path.startsWith(p))}var UUID_RE=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function normalizeRouteLabel(path){return path.split("/").map((seg)=>{if(!seg)return seg;if(/^\d+$/.test(seg))return":id";if(UUID_RE.test(seg))return":id";if(seg.length>=24&&/^[A-Za-z0-9_-]+$/.test(seg))return":id";return seg}).join("/")}async function createApp(options){let{port,host,dbPath,logLevel,corsOrigin}=options,effectiveDbPath=dbPath??getProfileDataDir();try{(await import("fs")).mkdirSync(effectiveDbPath,{recursive:!0})}catch(err){throw getDaemonProfile().logger.error("app","Failed to create dbPath dir at boot",{dbPath:effectiveDbPath,error:String(err)}),Error(`Cannot create dbPath ${effectiveDbPath}: ${err instanceof Error?err.message:String(err)}`,{cause:err})}if(logLevel)getDaemonProfile().logger.setLevel(logLevel);(async()=>{let{logShipper}=await import("./log-shipper-9rtt4y1s.js");logShipper.init()})(),(async()=>{let version=await getPackageVersion();await getMetricsRegistry({version,profile:getVibecontrolsProfile()})})();try{let{checkDependencies}=await import("./bootstrap.service-fknk5beq.js"),deps=checkDependencies(),missingRequired=deps.filter((d)=>d.required&&!d.installed),missingOptional=deps.filter((d)=>!d.required&&!d.installed);if(missingRequired.length>0)getDaemonProfile().logger.error("app",`Missing required system deps: ${missingRequired.map((d)=>d.name).join(", ")}. Run \`vibe setup\` to install.`);if(missingOptional.length>0)getDaemonProfile().logger.warn("app",`Missing optional system deps: ${missingOptional.map((d)=>d.name).join(", ")}. Some plugins may fail their prereqs check.`)}catch(err){getDaemonProfile().logger.warn("app","Boot-time dependency check failed",{error:String(err)})}try{getDaemonProfile().audit.runRetention()}catch(err){getDaemonProfile().logger.warn("app","Audit-log retention sweep failed",{error:String(err)})}let serviceRegistry=new ServiceRegistry;startBootstrapTunnel(serviceRegistry,{port});let CORS_METHODS="GET, POST, PUT, PATCH, DELETE, OPTIONS",CORS_HEADERS="Content-Type, x-agent-api-key, Authorization, x-requested-with",configuredCorsOrigins=Array.isArray(corsOrigin)?corsOrigin:(corsOrigin??"").split(",").map((origin)=>origin.trim()).filter(Boolean),trustedProductionOrigins=new Set(["https://vibecontrols.com","https://app.vibecontrols.com","https://alphaapp.vibecontrols.com","https://burdenoff.com","https://app.burdenoff.com","https://alphaapp.burdenoff.com"]),isAllowedOrigin=(origin)=>{try{let url=new URL(origin);if(configuredCorsOrigins.includes(origin))return!0;if(configuredCorsOrigins.includes("*"))return!1;return url.hostname==="localhost"||url.hostname==="127.0.0.1"||url.hostname==="0.0.0.0"||url.hostname.endsWith(".local.burdenoff.com")||trustedProductionOrigins.has(url.origin)}catch{return!1}},db=null,pluginManager=null,hostServices=null,lifecycle=null,pluginPublicPaths=()=>[],pluginRoutesApp=null,uiServerApp=null,finalizeInFlight=null,SHUTDOWN_PHASE_MS=5000,runPhase=async(name,fn)=>{let started=Date.now();try{await Promise.race([Promise.resolve(fn()),new Promise((_,reject)=>setTimeout(()=>reject(Error(`shutdown phase ${name} exceeded ${SHUTDOWN_PHASE_MS}ms`)),SHUTDOWN_PHASE_MS))]),getDaemonProfile().logger.info("app",`shutdown.phase ${name} complete`,{ms:Date.now()-started})}catch(err){getDaemonProfile().logger.warn("app",`shutdown.phase ${name} failed`,{error:String(err),ms:Date.now()-started})}},stopFn=async(context)=>{if(getDaemonProfile().logger.info("app","Agent shutdown starting",{reason:context?.reason??"shutdown"}),await runPhase("plugins",async()=>{if(pluginManager)await pluginManager.dispatchServerStop(context)}),await runPhase("bootstrap-tunnel",()=>stopBootstrapTunnel()),await runPhase("tracked-subprocesses",async()=>{let{killAllTracked}=await import("./subprocess-vks78xmn.js");await killAllTracked()}),context?.reason!=="reload")await runPhase("db-close",async()=>{if(db)await db.close()});getDaemonProfile().logger.close(),getDaemonProfile().logger.info("app","Agent server stopped")},finalize=async(creds,opts)=>{if(getDaemonProfile().getBootState()==="ready")return{ok:!0};if(finalizeInFlight)return finalizeInFlight;return finalizeInFlight=(async()=>{getDaemonProfile().setBootState("initializing");try{let safeCreds={...creds,globalGatewayUrl:assertAllowedGatewayUrl(creds.globalGatewayUrl,"globalGatewayUrl"),workspaceGatewayUrl:assertAllowedGatewayUrl(creds.workspaceGatewayUrl,"workspaceGatewayUrl")},encryptionKey=await fetchEncryptionKey(safeCreds),resolvedDbPath=effectiveDbPath,cfgForStorage=readAgentConfig({dir:getDaemonProfile().dataDir}),storageAdapterName=cfgForStorage.storageAdapter??process.env.VIBE_STORAGE_ADAPTER??void 0,storageAdapterOptions=cfgForStorage.storageOptions;try{db=await createAgentDatabase({dbPath:resolvedDbPath,encryptionKey,adapterName:storageAdapterName,adapterOptions:storageAdapterOptions})}catch(openErr){let message=openErr instanceof Error?openErr.message:String(openErr);getDaemonProfile().logger.error("app","Storage open failed; quarantining and retrying once",{error:message,path:resolvedDbPath});try{let fs=await import("fs");if(fs.existsSync(resolvedDbPath)){let ts=new Date().toISOString().replace(/[:.]/g,"-"),broken=`${resolvedDbPath}.broken-${ts}`;fs.renameSync(resolvedDbPath,broken),getDaemonProfile().logger.warn("app",`Quarantined storage to ${broken} \u2014 fresh DB will be created`)}db=await createAgentDatabase({dbPath:resolvedDbPath,encryptionKey,adapterName:storageAdapterName,adapterOptions:storageAdapterOptions})}catch(retryErr){let retryMsg=retryErr instanceof Error?retryErr.message:String(retryErr);throw getDaemonProfile().recordDegradedReason("storage",retryMsg),Error(`Storage open failed twice; agent is degraded: ${retryMsg}`,{cause:retryErr})}}if(await writeAgentConfigAwaitSecrets({clientId:safeCreds.clientId,clientSecret:safeCreds.clientSecret,workspaceId:safeCreds.workspaceId,organizationId:safeCreds.organizationId,globalGatewayUrl:safeCreds.globalGatewayUrl,workspaceGatewayUrl:safeCreds.workspaceGatewayUrl,agentRecordId:opts?.agentRecordId,scopes:opts?.scopes},{dir:getDaemonProfile().dataDir,scope:getDaemonProfile().name}),await db.setConfig("gateway-auth:clientId",safeCreds.clientId),await db.setConfig("gateway-auth:clientSecret",safeCreds.clientSecret),await db.setConfig("gateway-auth:globalGatewayUrl",safeCreds.globalGatewayUrl),await db.setConfig("gateway-auth:workspaceGatewayUrl",safeCreds.workspaceGatewayUrl),await db.setConfig("gateway-auth:workspaceId",safeCreds.workspaceId),safeCreds.organizationId)await db.setConfig("gateway-auth:organizationId",safeCreds.organizationId);if(opts?.agentRecordId)await db.setConfig("gateway-auth:agentRecordId",opts.agentRecordId);serviceRegistry.db=db,await serviceRegistry.hydrateDefaultsFromDb(),pluginManager=new PluginManager(db),await pluginManager.loadCorePlugins();try{await pluginManager.loadAll()}catch(err){getDaemonProfile().logger.warn("app","Failed to load some external plugins",{error:String(err)})}let autoInstallDisabled=process.env.VIBE_SKIP_AUTO_INSTALL==="1"||await db.getConfig("plugins:auto-install-disabled");if(autoInstallDisabled!=="true"&&autoInstallDisabled!==!0)try{let installed=await pluginManager.ensureDefaultPlugins((message)=>getDaemonProfile().logger.info("app",`[auto-install] ${message}`));if(installed.length>0)getDaemonProfile().logger.info("app",`Auto-installed ${installed.length} default plugin(s): ${installed.map((p)=>p.packageName).join(", ")}`)}catch(err){getDaemonProfile().logger.warn("app","Failed to auto-install default plugins",{error:String(err)})}getDaemonProfile().logger.info("app",`Plugins loaded: ${pluginManager.getPluginDetails().length} total (${pluginManager.getPluginDetails().filter((p)=>p.isCore).length} core)`);try{let details=pluginManager.getPluginDetails(),byStatus={loaded:details.filter((p)=>p.loaded).length,failed:details.filter((p)=>!p.loaded).length};setPluginsLoaded(byStatus)}catch{}let storageProvider={async get(namespace,key){return await db.getPluginState(namespace,key)??null},async set(namespace,key,value){await db.setPluginState(namespace,key,value)},async delete(namespace,key){return db.deletePluginState(namespace,key)},async list(namespace){return await db.getAllPluginState(namespace)},async deleteAll(namespace){return db.deleteAllPluginState(namespace)}},packageVersion=await getPackageVersion();hostServices={storage:storageProvider,logger:getDaemonProfile().logger,serviceRegistry,getProvider:(type)=>serviceRegistry.getProvider(type),getAgentBaseUrl:()=>process.env.AGENT_URL||`http://localhost:${port}`,getAgentVersion:()=>packageVersion,validateApiKey:(key)=>isValidAgentApiKey(key),setCodeServerSessionValidator:(fn)=>{codeServerSessionValidator=fn},broadcast,workspaceQuery:async(query,variables)=>gatewayClient.workspaceQuery(query,variables),isGatewayConfigured:()=>gatewayClient.isConfigured(),getAgentRecordId:async()=>await db.getConfig("gateway-auth:agentRecordId")??null,getWorkspaceId:async()=>await db.getConfig("gateway-auth:workspaceId")??null,getConfig:async(key)=>await db.getConfig(key)??void 0,getPluginRegistry:()=>getPluginRegistry(),getDataDir:()=>getVibecontrolsDir(),cliContributors:new CliContributorRegistry,audit:{emit:(event,payload)=>getDaemonProfile().audit.emit("agent",event,payload??{})},telemetry:{emit:(event,payload)=>{import("./telemetry-rew0mtj2.js").then(({telemetryService})=>telemetryService.emit(event,payload??{})).catch(()=>{})}},os:getOsAdapter(),iframeBridge:createIframeBridge()},gatewayClient.configure({globalGatewayUrl:safeCreds.globalGatewayUrl,workspaceGatewayUrl:safeCreds.workspaceGatewayUrl,clientId:safeCreds.clientId,clientSecret:safeCreds.clientSecret,workspaceId:safeCreds.workspaceId,organizationId:safeCreds.organizationId});let routeDeps={db,serviceRegistry,pluginManager,broadcast,hostServices};routeDeps.app=app;let pluginRoutesAppInitialized=!1,rebuildPluginSurfaces=()=>{let{routes:pluginRoutes,getPublicPaths,mountPlugin}=createPluginRouter(pluginManager,routeDeps);if(routeDeps.mountPlugin=mountPlugin,pluginPublicPaths=getPublicPaths,markPluginPublicPathsDirty(),pluginRoutesApp=pluginRoutes,uiServerApp=createUIServer(pluginManager),pluginManager&&pluginRoutesAppInitialized&&hostServices)pluginManager.dispatchServerStart(pluginRoutesApp,hostServices).catch((err)=>getDaemonProfile().logger.warn("app","Re-dispatch of onServerStart after plugin reload failed",{error:String(err)}));pluginRoutesAppInitialized=!0};routeDeps.rebuildPluginSurfaces=rebuildPluginSurfaces,rebuildPluginSurfaces(),lifecycle=new LifecycleManager(serviceRegistry,pluginManager,db,app,hostServices,stopFn),serviceRegistry.registerService("agent","lifecycle",lifecycle),getDaemonProfile().attachServices({db,serviceRegistry,pluginManager,lifecycle,hostServices}),mountProfileRoutes(getDaemonProfile(),{rebuildPluginSurfaces,mountPlugin:routeDeps.mountPlugin});try{await getDaemonProfile().keyVault.bindApiKey(getAgentApiKey())}catch(err){getDaemonProfile().logger.warn("app","Failed to bind api key into daemon keyVault",{error:String(err)})}let criticalFailures=[];try{let{failures}=await pluginManager.dispatchServerStart(pluginRoutesApp,hostServices);for(let f of failures)if(isCriticalPlugin(f.plugin)||(f.packageName?isCriticalPlugin(f.packageName):!1))criticalFailures.push(f),getDaemonProfile().recordDegradedReason(f.plugin,f.error);else getDaemonProfile().logger.warn("app",`Non-critical plugin ${f.plugin} failed onServerStart; continuing`,{error:f.error})}catch(err){getDaemonProfile().logger.warn("app","Error during plugin onServerStart dispatch",{error:String(err)})}try{await pluginManager.dispatchServerReady(app,hostServices)}catch(err){getDaemonProfile().logger.warn("app","Error during plugin onServerReady dispatch",{error:String(err)})}if(getDaemonProfile().clearFinalizeError(),criticalFailures.length>0)getDaemonProfile().setBootState("degraded"),getDaemonProfile().logger.error("app","Agent finalized but degraded \u2014 critical plugins failed",{failures:criticalFailures.map((f)=>`${f.plugin}: ${f.error}`)});else getDaemonProfile().setBootState("ready"),getDaemonProfile().logger.info("app","Agent finalized \u2014 state=ready"),getDaemonProfile().audit.emit("agent","gateway-auth.configured",{workspaceId:safeCreds.workspaceId,organizationId:safeCreds.organizationId,agentRecordId:opts?.agentRecordId});return(async()=>{try{if(await pluginManager.provisionDefaultPrereqs(app,hostServices,routeDeps.mountPlugin),getDaemonProfile().logger.info("app","Default provider prerequisites provisioned"),(serviceRegistry.listProvidersForType("tunnel")??[]).some((p)=>p.pluginName!=="bootstrap")){let{tryHandoverBootstrapTunnel}=await import("./tunnel-bootstrap-x82wcnt8.js");if(!tryHandoverBootstrapTunnel())stopBootstrapTunnel();serviceRegistry.unregisterProvider("tunnel","bootstrap"),getDaemonProfile().logger.info("app","Bootstrap tunnel handed over to the real tunnel provider")}}catch(err){getDaemonProfile().logger.warn("app","Plugin prerequisite provisioning failed",{error:String(err)})}})(),{ok:!0}}catch(err){getDaemonProfile().setBootState("awaiting-config");let msg=err instanceof Error?err.message:String(err);if(getDaemonProfile().recordFinalizeError(msg),getDaemonProfile().logger.error("app","Finalize failed",{error:msg}),process.env.VIBE_STRICT_KEY_FETCH==="1")getDaemonProfile().logger.error("app","VIBE_STRICT_KEY_FETCH=1 \u2192 aborting daemon (strict mode)",{error:msg}),setTimeout(()=>process.exit(1),50);return{ok:!1,error:msg}}finally{finalizeInFlight=null}})(),finalizeInFlight},corsPlugin=cors({origin:(request)=>{let origin=request.headers.get("origin");return!!origin&&isAllowedOrigin(origin)},credentials:!0,allowedHeaders:CORS_HEADERS.split(",").map((s)=>s.trim()),methods:CORS_METHODS.split(",").map((s)=>s.trim()),exposeHeaders:["content-type","content-length"],maxAge:86400,preflight:!0}),DEFAULT_MAX_BODY_BYTES=10485760,maxBodyEnv=process.env.VIBECONTROLS_MAX_BODY_BYTES,parsedMaxBody=maxBodyEnv?Number.parseInt(maxBodyEnv,10):NaN,maxBodySize=Number.isFinite(parsedMaxBody)&&parsedMaxBody>0?parsedMaxBody:DEFAULT_MAX_BODY_BYTES,appRef={current:null},app=new Elysia({serve:{maxRequestBodySize:maxBodySize}}).onRequest(({request,set})=>{let requestId=extractRequestId(request.headers)??generateRequestId();enterRequestContext({requestId,startedAt:new Date().toISOString()});let headers=set.headers??={};headers["X-Request-Id"]=requestId}).onRequest(({request})=>{try{let url=new URL(request.url).pathname,name=/^\/api\/profiles\/([^/]+)(?:\/|$)/.exec(url)?.[1],ctx=name?profileRegistry.get(name):null;enterProfileContext(ctx??getDaemonProfile())}catch{enterProfileContext(getDaemonProfile())}}).onRequest(({request,set})=>{let url=new URL(request.url).pathname;if(!url.startsWith("/api/"))return;if(url==="/api/profiles"||url.startsWith("/api/profiles/"))return;if(url==="/api/profile-stats"||url.startsWith("/api/profile-stats/"))return;let defaultProfileUrl=new URL(request.url);defaultProfileUrl.pathname=`/api/profiles/default${url.slice(4)}`;try{request.headers.set("x-vc-profile-rewrite","1"),request.headers.set("x-vc-profile-rewrite-target",defaultProfileUrl.pathname)}catch{}return}).derive(()=>({requestId:getRequestId()??generateRequestId()})).use(corsPlugin).use(rateLimitPlugin()).use(createAuthPlugin(()=>pluginPublicPaths())).use(idempotencyPlugin({getDb:()=>currentProfileOrNull()?.db??db})).onBeforeHandle(({request,set})=>{let state=getDaemonProfile().getBootState();if(state==="ready")return;let url=new URL(request.url).pathname;if(isFinalizeExempt(url))return;return set.status=503,{error:"Agent not yet configured",message:"Agent is in '"+state+"' state. POST credentials to /api/agent/gateway-auth to finalize.",state}}).onAfterHandle(({request,set})=>{let url=new URL(request.url).pathname,isNoisy=url==="/health"||url.startsWith("/api/logs/stream")||url.startsWith("/ui/")||url==="/ws/events"||url==="/api/sessions/health-check"||url.startsWith("/terminal/"),status=typeof set.status==="number"?set.status:200,level=isNoisy?"debug":status>=400?"warn":"info";getDaemonProfile().logger[level]("http",`${request.method} ${url} \u2192 ${status}`,{method:request.method,path:url,statusCode:status});try{recordHttpRequest(request.method,normalizeRouteLabel(url),status)}catch{}}).use(createHealthRoutes({serviceRegistry,getDb:()=>currentProfileOrNull()?.db??db,getDbPath:()=>effectiveDbPath,getPluginManager:()=>currentProfileOrNull()?.pluginManager??pluginManager})).use(createMetricsRoutes()).use(createPreConfigRoutes({serviceRegistry,runFinalize:(creds,opts)=>finalize(creds,opts),getDb:()=>currentProfileOrNull()?.db??db})).use(createInflightTracker()).use(createStatsRoutes()).use(createEditorRoutes()).use(createContextRoutes({getPluginManager:()=>currentProfileOrNull()?.pluginManager??pluginManager,getTunnelHost:()=>readTunnelState()?.url??null})).use(createProfileManagementRoutes()).use(createProfileStatsRoutes()).use(createEventsWs()).use(createLogWs()).use(createTerminalProxy(serviceRegistry)).ws("/code-server/*",buildCodeServerBridge(port)).all("/api/profiles/:name/*",async({params,request,set})=>{let hasReqBody=request.method!=="GET"&&request.method!=="HEAD",bodyBytes=hasReqBody?await request.arrayBuffer():void 0,dispatched=await dispatchProfileRequest(params.name,request,bodyBytes);if(dispatched&&dispatched.status!==404)return dispatched;let running=getVibecontrolsProfile(),requested=params.name;if(requested!==running)return set.status=404,{error:"profile-mismatch",running,requested,hint:"This daemon serves a different profile. Call GET /api/profiles to discover the right tunnel."};let u=new URL(request.url),stripped=u.pathname.replace(/^\/api\/profiles\/[^/]+/,"/api"),headers=new Headers(request.headers);headers.set("x-vc-profile-rewrite","1");let init={method:request.method,headers};if(hasReqBody&&bodyBytes!==void 0)init.body=bodyBytes;let rewritten=new Request(`${u.origin}${stripped}${u.search}`,init),target=appRef.current;if(!target)return new Response(JSON.stringify({error:"agent-not-ready"}),{status:503,headers:{"content-type":"application/json"}});return target.handle(rewritten)}).all("/api/*",async({request})=>{if(getDaemonProfile().getBootState()!=="ready"||!pluginRoutesApp)return new Response(JSON.stringify({error:"Agent not yet configured",state:getDaemonProfile().getBootState(),message:"Plugin routes are unavailable until the agent reaches state=ready. POST credentials to /api/agent/gateway-auth to finalize."}),{status:503,headers:{"content-type":"application/json"}});try{let apiUiUrl=new URL(request.url),apiUiMatch=/^\/api\/plugins\/([a-z0-9-]{1,64})\/ui(?:\/.*)?$/.exec(apiUiUrl.pathname);if(apiUiMatch&&request.method==="GET"){let plugin=apiUiMatch[1];if(isValidUiPluginName(plugin)){let restAfterUi=apiUiUrl.pathname.slice(`/api/plugins/${plugin}/ui`.length),isBareDoc=restAfterUi===""||restAfterUi==="/",looksLikeNavigation=request.headers.get("sec-fetch-mode")==="navigate";if(isBareDoc||looksLikeNavigation){let cookie=getUiCookieFromRequest(request,plugin);if(!cookie||!verifyUiCookieToken(cookie,plugin))return new Response(renderUiBootstrapHtml(plugin,"/api/profiles/default/agent/ui-exchange-plugin"),{status:200,headers:{"content-type":"text/html; charset=utf-8","Content-Security-Policy":"frame-ancestors 'self' http://localhost:* http://127.0.0.1:* https://localhost:* https://127.0.0.1:* https://*.local.burdenoff.com https://vibecontrols.com https://*.vibecontrols.com https://burdenoff.com https://app.burdenoff.com https://alphaapp.burdenoff.com"}})}}}}catch{}return pluginRoutesApp.handle(request)}).all("/ui/*",async({request})=>{if(getDaemonProfile().getBootState()!=="ready"||!uiServerApp)return new Response("Plugin UI not yet available",{status:503});return uiServerApp.handle(request)}).all("/code-server/*",async({request})=>{if(getDaemonProfile().getBootState()!=="ready"||!pluginRoutesApp)return new Response("code-server not yet available",{status:503});return pluginRoutesApp.handle(request)}).all("/plan/*",async({request})=>{if(getDaemonProfile().getBootState()!=="ready"||!pluginRoutesApp)return new Response("plan provider not yet available",{status:503});return pluginRoutesApp.handle(request)});return appRef.current=app,{app,async start(){app.listen({port,hostname:host}),getDaemonProfile().logger.info("app",`Agent server listening on ${host}:${port}`);try{let list=(process.env.VIBECONTROLS_PROFILES??"").split(",").map((s)=>s.trim()).filter(Boolean),bootName=getDaemonProfile().name,{getOrCreateProfile:getOrCreateProfile2}=await import("./daemon-profile-c7zt62gk.js"),{attachSecondaryProfile}=await import("./secondary-profile-attach-mgt3bv4j.js"),strict=process.env.VIBE_STRICT_KEY_FETCH==="1";for(let name of list){if(name===bootName)continue;try{let ctx=getOrCreateProfile2(name),result=await attachSecondaryProfile(ctx);if(result.ok)getDaemonProfile().logger.info("app",`Secondary profile '${name}' attached (db+services online)`);else if(strict)throw Error(`attachServices for secondary profile '${name}' failed: ${result.error}`);else ctx.recordDegradedReason("attach",result.error??"unknown"),getDaemonProfile().logger.warn("app",`Secondary profile '${name}' is degraded (no creds / attach failed)`,{error:result.error})}catch(err){if(strict)throw getDaemonProfile().logger.error("app",`--strict-key-fetch: secondary profile '${name}' attach failed; aborting`,{error:String(err)}),setTimeout(()=>process.exit(1),50),err;getDaemonProfile().logger.warn("app",`Failed to attach secondary profile '${name}'`,{error:String(err)})}}}catch{}return app},stop:stopFn,finalize,getState:()=>getDaemonProfile().getBootState(),getLifecycle:()=>currentProfileOrNull()?.lifecycle??lifecycle,getDb:()=>currentProfileOrNull()?.db??db,getServiceRegistry:()=>currentProfileOrNull()?.serviceRegistry??serviceRegistry,getPluginManager:()=>currentProfileOrNull()?.pluginManager??pluginManager,getHostServices:()=>currentProfileOrNull()?.hostServices??hostServices}}var codeServerSessionValidator=null;function getCookieValue(cookieHeader,name){if(!cookieHeader)return null;let m=cookieHeader.match(new RegExp(`(?:^|;\\s*)${name}=([^;]*)`));return m?m[1]:null}function buildCodeServerBridge(port){let payloadBytes=(payload)=>typeof payload==="string"?Buffer.byteLength(payload):payload.byteLength;return{open(ws){let wsData=ws.data,apiKey=wsData.query?.apiKey??getApiKeyFromHeaders(wsData.headers??{})??getApiKeyFromHeaders(wsData.request?Object.fromEntries(wsData.request.headers.entries()):{});if(!isValidAgentApiKey(apiKey)){let cookieHeader=wsData.headers?.cookie??wsData.request?.headers.get("cookie")??null,sessionToken=getCookieValue(cookieHeader,"__vibe_cs_session");if(!sessionToken||!codeServerSessionValidator?.(sessionToken)){ws.close(1008,"Unauthorized");return}}let bridgeProfile=getDaemonProfile().name;fetch(`http://127.0.0.1:${port}/api/profiles/${encodeURIComponent(bridgeProfile)}/code-server/status`,{headers:{"x-agent-api-key":getAgentApiKey()}}).then((r)=>r.json()).then((raw)=>{if(wsData._csClosed)return;let status=raw;if(!status.running||!status.port){ws.close(1011,"code-server not running");return}let requestUrl=wsData.request?.url??"/code-server/",upstreamPath;try{let url=new URL(requestUrl,`http://127.0.0.1:${status.port}`);upstreamPath=(url.pathname.replace(/^\/code-server\/?/,"/")||"/")+url.search}catch{upstreamPath="/"}let upstreamWs=new WebSocket(`ws://127.0.0.1:${status.port}${upstreamPath}`),state={upstream:upstreamWs,ready:!1,buffer:[],bufferBytes:0,openTimer:setTimeout(()=>{try{upstreamWs.close(1011,"upstream open timeout")}catch{}try{ws.close(1011,"upstream open timeout")}catch{}},1e4)};wsData._csBridge=state,upstreamWs.addEventListener("open",()=>{clearTimeout(state.openTimer),state.ready=!0;for(let msg of state.buffer)upstreamWs.send(msg);state.buffer.length=0,state.bufferBytes=0}),upstreamWs.addEventListener("message",(event)=>{try{let d=event.data;if(d instanceof ArrayBuffer)ws.send(new Uint8Array(d));else if(d instanceof Blob)d.arrayBuffer().then((ab)=>{try{ws.send(new Uint8Array(ab))}catch{}});else ws.send(d)}catch{}}),upstreamWs.addEventListener("close",(event)=>{clearTimeout(state.openTimer);try{ws.close(event.code||1000,event.reason||"upstream closed")}catch{}}),upstreamWs.addEventListener("error",()=>{clearTimeout(state.openTimer);try{ws.close(1011,"upstream error")}catch{}})}).catch(()=>{ws.close(1011,"Failed to query code-server status")})},message(ws,message){let state=ws.data?._csBridge;if(!state)return;let payload;if(typeof message==="string")payload=message;else if(message instanceof ArrayBuffer)payload=message;else if(message instanceof Uint8Array||Buffer.isBuffer(message)){let copy=new ArrayBuffer(message.byteLength);new Uint8Array(copy).set(new Uint8Array(message.buffer,message.byteOffset,message.byteLength)),payload=copy}else if(typeof message==="object"&&message!==null)payload=JSON.stringify(message);else payload=String(message);if(state.upstream&&state.ready&&state.upstream.readyState===WebSocket.OPEN)try{state.upstream.send(payload)}catch{}else{let nextBytes=payloadBytes(payload);if(state.buffer.length>=256||state.bufferBytes+nextBytes>1048576){try{state.upstream.close(1013,"buffer limit exceeded")}catch{}try{ws.close(1013,"buffer limit exceeded")}catch{}return}state.buffer.push(payload),state.bufferBytes+=nextBytes}},close(ws){ws.data._csClosed=!0;let state=ws.data?._csBridge;if(state?.openTimer)clearTimeout(state.openTimer);if(state?.upstream&&state.upstream.readyState===WebSocket.OPEN)state.upstream.close(1000,"client disconnected")}}}async function getPackageVersion(){try{let{readFileSync:readFileSync3}=await import("fs"),{join:join4,dirname:dirname2}=await import("path"),{fileURLToPath}=await import("url"),__dirname2=dirname2(fileURLToPath(import.meta.url));return JSON.parse(readFileSync3(join4(__dirname2,"..","package.json"),"utf8")).version||"1.0.0"}catch{return"1.0.0"}}
5
5
  export{mintPairingToken,invalidatePairingToken,createApp};
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import{getPluginPackageRoot}from"./index-1x89a7r1.js";import{getAgentApiKey,getIframeTokenFromRequest,getUiCookieFromRequest,isValidUiPluginName,issueUiCookieToken,verifyIframeToken,verifyUiCookieToken}from"./index-b4wy3jrt.js";import{Elysia}from"./index-rnk0kny8.js";class CliContributorRegistry{statusSections=[];doctorChecks=[];addStatusSection(section){this.statusSections.push(section)}addDoctorCheck(check){this.doctorChecks.push(check)}getStatusSections(){return this.statusSections}getDoctorChecks(){return this.doctorChecks}}var activeRegistry=null;function setActiveContributorRegistry(registry){activeRegistry=registry}function getActiveContributorRegistry(){if(!activeRegistry)activeRegistry=new CliContributorRegistry;return activeRegistry}import{extname,relative,resolve}from"path";import{realpath}from"fs/promises";var DEFAULT_FRAME_ANCESTORS=["'self'","http://localhost:*","http://127.0.0.1:*","https://localhost:*","https://127.0.0.1:*","https://*.local.burdenoff.com","https://vibecontrols.com","https://*.vibecontrols.com","https://burdenoff.com","https://app.burdenoff.com","https://alphaapp.burdenoff.com"],warnedAboutUnsafeOverride=!1;function frameAncestorsCsp(){let override=process.env.VIBE_UI_FRAME_ANCESTORS?.trim(),sources=override?override.split(/[\s,]+/).filter(Boolean):DEFAULT_FRAME_ANCESTORS;if(override&&!warnedAboutUnsafeOverride&&(sources.includes("*")||!sources.includes("'self'")))warnedAboutUnsafeOverride=!0,console.warn(`[ui-server] VIBE_UI_FRAME_ANCESTORS override does not include "'self'" or contains "*". This significantly weakens CSP frame-ancestors and is almost never intended. Override: ${override}`);return`frame-ancestors ${sources.join(" ")}`}var MIME_TYPES={".html":"text/html",".js":"application/javascript",".mjs":"application/javascript",".css":"text/css",".json":"application/json",".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".svg":"image/svg+xml",".ico":"image/x-icon",".woff":"font/woff",".woff2":"font/woff2",".ttf":"font/ttf",".map":"application/json",".wasm":"application/wasm"};function getMimeType(filePath){return MIME_TYPES[extname(filePath).toLowerCase()]||"application/octet-stream"}var AUTH_BRIDGE_SCRIPT=`<script>
2
+ import{getPluginPackageRoot}from"./index-cyhcvfxs.js";import{getAgentApiKey,getIframeTokenFromRequest,getUiCookieFromRequest,isValidUiPluginName,issueUiCookieToken,verifyIframeToken,verifyUiCookieToken}from"./index-b4wy3jrt.js";import{Elysia}from"./index-rnk0kny8.js";class CliContributorRegistry{statusSections=[];doctorChecks=[];addStatusSection(section){this.statusSections.push(section)}addDoctorCheck(check){this.doctorChecks.push(check)}getStatusSections(){return this.statusSections}getDoctorChecks(){return this.doctorChecks}}var activeRegistry=null;function setActiveContributorRegistry(registry){activeRegistry=registry}function getActiveContributorRegistry(){if(!activeRegistry)activeRegistry=new CliContributorRegistry;return activeRegistry}import{extname,relative,resolve}from"path";import{realpath}from"fs/promises";var DEFAULT_FRAME_ANCESTORS=["'self'","http://localhost:*","http://127.0.0.1:*","https://localhost:*","https://127.0.0.1:*","https://*.local.burdenoff.com","https://vibecontrols.com","https://*.vibecontrols.com","https://burdenoff.com","https://app.burdenoff.com","https://alphaapp.burdenoff.com"],warnedAboutUnsafeOverride=!1;function frameAncestorsCsp(){let override=process.env.VIBE_UI_FRAME_ANCESTORS?.trim(),sources=override?override.split(/[\s,]+/).filter(Boolean):DEFAULT_FRAME_ANCESTORS;if(override&&!warnedAboutUnsafeOverride&&(sources.includes("*")||!sources.includes("'self'")))warnedAboutUnsafeOverride=!0,console.warn(`[ui-server] VIBE_UI_FRAME_ANCESTORS override does not include "'self'" or contains "*". This significantly weakens CSP frame-ancestors and is almost never intended. Override: ${override}`);return`frame-ancestors ${sources.join(" ")}`}var MIME_TYPES={".html":"text/html",".js":"application/javascript",".mjs":"application/javascript",".css":"text/css",".json":"application/json",".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".svg":"image/svg+xml",".ico":"image/x-icon",".woff":"font/woff",".woff2":"font/woff2",".ttf":"font/ttf",".map":"application/json",".wasm":"application/wasm"};function getMimeType(filePath){return MIME_TYPES[extname(filePath).toLowerCase()]||"application/octet-stream"}var AUTH_BRIDGE_SCRIPT=`<script>
3
3
  window.__VIBE_AUTH__={apiKey:null};
4
4
  (function(){
5
5
  var p=new URLSearchParams(window.location.search);
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import{getAgentVersion}from"./index-1x89a7r1.js";import{getOsAdapter}from"./index-srbb2214.js";import{getDefaultProfile,getInstances,getVibecontrolsDir,getVibecontrolsProductDir,setDefaultProfile,setInstances,validateAgentName}from"./index-bysm7taq.js";import{__require}from"./index-e9rt4m94.js";import{existsSync,readdirSync,readFileSync,writeFileSync,mkdirSync,openSync,closeSync,unlinkSync}from"fs";import{join}from"path";import{tmpdir}from"os";import{spawn as spawnDaemon}from"child_process";class ServiceManager{registryPath;logsDir;productDir;constructor(){let productDir=getVibecontrolsProductDir();this.productDir=productDir,this.registryPath=join(productDir,"agents.json");let agentDir=getVibecontrolsDir();this.logsDir=join(agentDir,"logs"),mkdirSync(productDir,{recursive:!0}),mkdirSync(agentDir,{recursive:!0}),mkdirSync(this.logsDir,{recursive:!0})}async startDaemon(config){return validateAgentName(config.name),this.withInstanceLock(config.name,async()=>{let existing=await this.findProcessByName(config.name);if(existing&&existing.status==="running"){let runningVersion=existing.version,installedVersion=getAgentVersion();if(runningVersion===installedVersion){console.log(`\u26A0\uFE0F Agent '${config.name}' is already running on port ${existing.port}`);return}console.log(`\uD83D\uDD04 Agent '${config.name}' is running an older build (${runningVersion??"unknown"} \u2192 ${installedVersion}) \u2014 restarting to apply the update`);try{await this.stopInternal(config.name)}catch(err){console.log(`\u26A0\uFE0F Could not cleanly stop the stale daemon (${err instanceof Error?err.message:String(err)}); proceeding to start the new build`)}}let logFile=join(this.logsDir,`${config.name}.log`),logFd=openSync(logFile,"a"),distEntry=join(import.meta.dir,"index.js"),devEntry=join(import.meta.dir,"..","index.ts"),indexPath=existsSync(distEntry)?distEntry:devEntry,child=spawnDaemon(process.execPath,["run",indexPath],{detached:!0,windowsHide:!0,stdio:["ignore",logFd,logFd],env:{...process.env,VIBECONTROLS_PROFILE:config.profile||"default",PORT:config.port.toString(),DB_PATH:config.dbPath,NODE_ENV:"production",AGENT_LOG_FILE:logFile}});child.on("error",()=>{}),closeSync(logFd),await new Promise((resolve)=>setTimeout(resolve,2000));let pid=child.pid;if(!(pid!==void 0&&await this.isProcessRunning(pid))){let tail="";try{tail=readFileSync(logFile,"utf8").split(/\r?\n/).filter((l)=>l.trim()).slice(-25).join(`
2
+ import{getAgentVersion}from"./index-cyhcvfxs.js";import{getOsAdapter}from"./index-srbb2214.js";import{getDefaultProfile,getInstances,getVibecontrolsDir,getVibecontrolsProductDir,setDefaultProfile,setInstances,validateAgentName}from"./index-bysm7taq.js";import{__require}from"./index-e9rt4m94.js";import{existsSync,readdirSync,readFileSync,writeFileSync,mkdirSync,openSync,closeSync,unlinkSync}from"fs";import{join}from"path";import{tmpdir}from"os";import{spawn as spawnDaemon}from"child_process";class ServiceManager{registryPath;logsDir;productDir;constructor(){let productDir=getVibecontrolsProductDir();this.productDir=productDir,this.registryPath=join(productDir,"agents.json");let agentDir=getVibecontrolsDir();this.logsDir=join(agentDir,"logs"),mkdirSync(productDir,{recursive:!0}),mkdirSync(agentDir,{recursive:!0}),mkdirSync(this.logsDir,{recursive:!0})}async startDaemon(config){return validateAgentName(config.name),this.withInstanceLock(config.name,async()=>{let existing=await this.findProcessByName(config.name);if(existing&&existing.status==="running"){let runningVersion=existing.version,installedVersion=getAgentVersion();if(runningVersion===installedVersion){console.log(`\u26A0\uFE0F Agent '${config.name}' is already running on port ${existing.port}`);return}console.log(`\uD83D\uDD04 Agent '${config.name}' is running an older build (${runningVersion??"unknown"} \u2192 ${installedVersion}) \u2014 restarting to apply the update`);try{await this.stopInternal(config.name)}catch(err){console.log(`\u26A0\uFE0F Could not cleanly stop the stale daemon (${err instanceof Error?err.message:String(err)}); proceeding to start the new build`)}}let logFile=join(this.logsDir,`${config.name}.log`),logFd=openSync(logFile,"a"),distEntry=join(import.meta.dir,"index.js"),devEntry=join(import.meta.dir,"..","index.ts"),indexPath=existsSync(distEntry)?distEntry:devEntry,child=spawnDaemon(process.execPath,["run",indexPath],{detached:!0,windowsHide:!0,stdio:["ignore",logFd,logFd],env:{...process.env,VIBECONTROLS_PROFILE:config.profile||"default",PORT:config.port.toString(),DB_PATH:config.dbPath,NODE_ENV:"production",AGENT_LOG_FILE:logFile}});child.on("error",()=>{}),closeSync(logFd),await new Promise((resolve)=>setTimeout(resolve,2000));let pid=child.pid;if(!(pid!==void 0&&await this.isProcessRunning(pid))){let tail="";try{tail=readFileSync(logFile,"utf8").split(/\r?\n/).filter((l)=>l.trim()).slice(-25).join(`
3
3
  `)}catch{}let where=`See ${logFile}`;throw Error(tail?`Failed to start agent '${config.name}'. ${where}
4
4
  --- last log lines ---
5
5
  ${tail}`:`Failed to start agent '${config.name}'. ${where}`)}child.unref(),await this.saveProcessInfo(config.name,pid,config),console.log(`\uD83D\uDE80 Agent '${config.name}' started (PID: ${pid}, Port: ${config.port})`)})}async stop(name){return validateAgentName(name),this.withInstanceLock(name,()=>this.stopInternal(name))}async stopInternal(name){let agentProcess=await this.findProcessByName(name);if(!agentProcess||agentProcess.status!=="running"){console.log(`\u26A0\uFE0F Agent '${name}' is not running`);return}try{if(process.kill(agentProcess.pid,"SIGTERM"),await new Promise((resolve)=>setTimeout(resolve,3000)),await this.isProcessRunning(agentProcess.pid))process.kill(agentProcess.pid,"SIGKILL");await this.updateProcessStatus(name,"stopped"),console.log(`\u2705 Agent '${name}' stopped (tunnel + API key preserved)`)}catch(err){throw Error(`Failed to stop agent '${name}': ${err}`,{cause:err})}}async restart(name,config){validateAgentName(name),validateAgentName(config.name);let existing=await this.findProcessByName(name);if(existing&&existing.status==="running")await this.stop(name);await this.startDaemon(config),console.log(`\uD83D\uDD04 Agent '${name}' restarted (tunnel + API key preserved)`)}async kill(name){return validateAgentName(name),this.withInstanceLock(name,async()=>{let agentProcess=await this.findProcessByName(name);if(!agentProcess||agentProcess.status!=="running"){console.log(`\u26A0\uFE0F Agent '${name}' is not running`);return}let flagPath=join(tmpdir(),`.boff-vibecontrols-kill-${agentProcess.pid}`);try{await Bun.write(flagPath,"kill")}catch{}try{process.kill(agentProcess.pid,"SIGTERM"),await new Promise((resolve)=>setTimeout(resolve,5000))}catch{}if(await this.isProcessRunning(agentProcess.pid))await this.killProcessTree(agentProcess.pid);await this.updateProcessStatus(name,"stopped"),console.log(`\uD83D\uDC80 Agent '${name}' killed (tunnel + state torn down)`)})}async getStatus(name){return validateAgentName(name),this.findProcessByName(name)}discoverRuntimeInstances(){let agentsDir=join(this.productDir,"agents");if(!existsSync(agentsDir))return[];let profileDirs;try{profileDirs=readdirSync(agentsDir,{withFileTypes:!0}).filter((entry)=>entry.isDirectory()).map((entry)=>entry.name)}catch{return[]}let discovered=[];for(let profile of profileDirs){let runtimePath=join(agentsDir,profile,"runtime.json");if(!existsSync(runtimePath))continue;try{let rt=JSON.parse(readFileSync(runtimePath,"utf8"));if(typeof rt.pid!=="number"||typeof rt.port!=="number")continue;let name=rt.profile||profile;try{validateAgentName(name)}catch{continue}discovered.push({name,pid:rt.pid,port:rt.port,config:{name,port:rt.port,daemon:!0,dbPath:join(agentsDir,profile,"agent-db"),host:rt.host,profile:name},startTime:rt.startedAt??new Date(0).toISOString(),status:"unknown",version:rt.version})}catch{}}return discovered}async getStatusAll(){let registry=this.loadRegistry(),registryNames=new Set(registry.map((p)=>p.name)),candidates=[...registry];for(let disc of this.discoverRuntimeInstances())if(!registryNames.has(disc.name))candidates.push(disc);let processes=[];for(let candidate of candidates){let isRunning=await this.isManagedProcessRunning(candidate);if(!registryNames.has(candidate.name)&&!isRunning)continue;processes.push({...candidate,status:isRunning?"running":"stopped"})}let adopt=processes.filter((p)=>p.status==="running"&&!registryNames.has(p.name));if(adopt.length>0)try{let fresh=this.loadRegistry(),freshNames=new Set(fresh.map((p)=>p.name)),toAdd=adopt.filter((p)=>!freshNames.has(p.name));if(toAdd.length>0)this.saveRegistry([...fresh,...toAdd.map((p)=>({...p,status:"running"}))])}catch{}return processes}async listInstances(){return this.getStatusAll()}getDefaultProfile(){return getDefaultProfile()}setDefaultProfile(name){setDefaultProfile(validateAgentName(name))}async showLogs(name,options){validateAgentName(name);let logFile=join(this.logsDir,`${name}.log`);if(!existsSync(logFile)){console.log(`No logs found for agent '${name}'`);return}if(options.follow)try{let printTail=async(initial)=>{let contents=await Bun.file(logFile).text(),trail=contents.split(`
@@ -1,6 +1,6 @@
1
1
  // @bun
2
- import{readPrereqState,runPluginPrereqs}from"./index-9nn2kpyg.js";import{notifyBackendPluginChange}from"./index-q96eskyn.js";import"./index-23rdsqea.js";import"./index-ttafzcs7.js";import{AVAILABLE_PLUGINS,getCatalogEntry,isCriticalPlugin,isTrustedPackage,validatePluginPackageName}from"./index-1x89a7r1.js";import"./index-srbb2214.js";import"./index-brtw3j8x.js";import"./index-b4wy3jrt.js";import{INTERNAL_DISPATCH_HEADER,getInternalDispatchToken}from"./index-d3mz9vws.js";import{Elysia,t}from"./index-rnk0kny8.js";import{apiGet,apiPost,getAgentUrl,maybePrintJson,pickOutputMode,resolveProfileName,runMultimode}from"./index-wvabz3xh.js";import{colors,errMsg,fail,formatTable,header,info,kv,success,warn}from"./index-r0qezdp7.js";import{interactiveDetail,interactiveTable}from"./index-campp0wv.js";import"./index-2pqv0bya.js";import{getDaemonProfile}from"./index-7pdmqbj8.js";import"./index-bysm7taq.js";import"./index-zs58d1hc.js";import{__require}from"./index-e9rt4m94.js";import{timingSafeEqual}from"crypto";async function getRegistryIntegrity(pkg,version){try{let proc=Bun.spawn({cmd:["npm","view",`${pkg}@${version}`,"dist.integrity","--json"],stdout:"pipe",stderr:"pipe"});if(await proc.exited!==0)return null;let trimmed=(await new Response(proc.stdout).text()).trim();if(!trimmed)return null;if(trimmed.startsWith('"'))try{let parsed=JSON.parse(trimmed);return typeof parsed==="string"?parsed:null}catch{return null}return trimmed}catch{return null}}function compareIntegrity(expected,actual){let a=Buffer.from(expected),b=Buffer.from(actual);if(a.length!==b.length)return!1;try{return timingSafeEqual(a,b)}catch{return!1}}var AVAILABLE_PLUGINS2=AVAILABLE_PLUGINS.map((p)=>({packageName:p.packageName,name:p.pluginName,description:p.description,cliCommand:p.cliCommand,apiPrefix:p.apiPrefix,installed:!1,category:p.category})),lifecycleLocks=new Map;function withPluginLifecycleLock(packageName,fn){let run=(lifecycleLocks.get(packageName)??Promise.resolve()).then(fn,fn),stored=run.then(()=>{return},()=>{return});return lifecycleLocks.set(packageName,stored),stored.finally(()=>{if(lifecycleLocks.get(packageName)===stored)lifecycleLocks.delete(packageName)}),run}function isPackageInstallInFlight(packageName){return lifecycleLocks.has(packageName)}function availablePluginsPayload(pluginManager){let installed=pluginManager.getPluginDetails(),installedNames=new Set(installed.map((p)=>p.packageName));return{plugins:AVAILABLE_PLUGINS2.map((p)=>({...p,installed:installedNames.has(p.packageName)}))}}function createRoutes(deps){let{pluginManager}=deps;return new Elysia().get("/",()=>{let plugins=pluginManager.getPluginDetails();return{plugins,count:plugins.length}}).get("/available",()=>availablePluginsPayload(pluginManager)).get("/catalog",()=>availablePluginsPayload(pluginManager)).get("/contributions",({query})=>{let wantedMount=typeof query?.mountPoint==="string"&&query.mountPoint?query.mountPoint:null,items=[],packageNameByPluginName=new Map;for(let detail of pluginManager.getPluginDetails())packageNameByPluginName.set(detail.pluginName,detail.packageName);for(let plugin of pluginManager.getAllPlugins()){let ui=plugin.ui;if(!ui||!ui.contributions||ui.contributions.length===0)continue;let fallbackCaps=ui.capabilities??{restPaths:[],wsTopics:[],rpcMethods:[]};for(let contribution of ui.contributions){if(wantedMount&&contribution.mountPoint!==wantedMount)continue;let meta=contribution.meta,rawOverride=meta&&typeof meta.url==="string"?meta.url:null,overrideUrl=rawOverride&&rawOverride.startsWith("/")&&!rawOverride.startsWith("//")&&!rawOverride.includes("\x00")&&!rawOverride.includes("..")?rawOverride:null;items.push({pluginKey:plugin.name,pluginPackageName:packageNameByPluginName.get(plugin.name),contribution,capabilities:contribution.capabilities??fallbackCaps,url:overrideUrl??`/ui/${encodeURIComponent(plugin.name)}`})}}return{contributions:items,count:items.length}}).post("/install",async({body,set})=>{if(!body.packageName||typeof body.packageName!=="string")return set.status=400,{error:"Missing required field: packageName"};if(body.packageName.startsWith("@burdenoff/"))body.packageName=body.packageName.replace(/^@burdenoff\//,"@vibecontrols/");if(!isTrustedPackage(body.packageName))return set.status=403,{error:"Plugin package is not in the trusted VibeControls catalog"};try{let packageName=validatePluginPackageName(body.packageName);if(isPackageInstallInFlight(packageName)){let slug=packageName.split("/").pop()?.replace("vibe-plugin-","");if(pluginManager.getAllPlugins().some((p)=>p.name===slug))return{success:!0,message:`Plugin ${packageName} is already installed`,packageName,alreadyInstalled:!0};return set.status=409,{error:"Install for this package is already in progress. Wait for it to finish.",packageName}}return await withPluginLifecycleLock(packageName,async()=>{let pluginName=packageName.split("/").pop()?.replace("vibe-plugin-",""),legacyAiProviderName=pluginName?.startsWith("ai-")?pluginName.slice(3):void 0,existingPlugin=pluginManager.getAllPlugins().find((p)=>p.name===pluginName||p.name===legacyAiProviderName),alreadyRunning=!!existingPlugin,installedEntry=await pluginManager.install(packageName),catalogEntry=getCatalogEntry(packageName);if(catalogEntry?.integrity){let actualIntegrity=await getRegistryIntegrity(packageName,installedEntry.version);if(!actualIntegrity||!compareIntegrity(catalogEntry.integrity,actualIntegrity)){try{await pluginManager.remove(packageName,deps.hostServices)}catch(rollbackErr){console.warn(`[plugin-mgr] integrity rollback uninstall failed for ${packageName}:`,rollbackErr)}return getDaemonProfile().audit.emit("agent","plugin.install.rejected",{packageName,version:installedEntry.version,reason:"integrity_mismatch",expected:catalogEntry.integrity,actual:actualIntegrity}),set.status=400,{error:"integrity mismatch",expected:catalogEntry.integrity,actual:actualIntegrity}}}else console.warn(`[plugin-mgr] plugin ${packageName} has no pinned integrity \u2014 accepting npm registry's hash`);let newPlugin=pluginManager.getAllPlugins().find((p)=>p.name===installedEntry.pluginName);if(newPlugin){let lifecycleErrors=[];if(deps.mountPlugin)deps.mountPlugin(newPlugin);if(deps.hostServices){if(alreadyRunning&&existingPlugin?.onServerStop)try{await existingPlugin.onServerStop()}catch(err){lifecycleErrors.push(`onServerStop failed: ${err instanceof Error?err.message:String(err)}`)}if(pluginManager.registerProviders(newPlugin,deps.hostServices),newPlugin.onServerStart&&deps.app)try{await newPlugin.onServerStart(deps.app,deps.hostServices),pluginManager.registerProviders(newPlugin,deps.hostServices)}catch(err){lifecycleErrors.push(`onServerStart failed: ${err instanceof Error?err.message:String(err)}`)}if(newPlugin.onServerReady&&deps.app)try{await newPlugin.onServerReady(deps.app,deps.hostServices)}catch(err){lifecycleErrors.push(`onServerReady failed: ${err instanceof Error?err.message:String(err)}`)}}if(deps.rebuildPluginSurfaces?.(),lifecycleErrors.length>0)return set.status=500,{success:!1,message:`Plugin ${packageName} installed but failed to start`,lifecycleErrors,restartRequired:!0}}let prereqs;if(newPlugin&&deps.app)try{prereqs=await runPluginPrereqs(newPlugin,packageName,deps.app,deps.db,{skipInstall:!!body.skipPrereqs})}catch(err){prereqs=void 0,console.warn(`[plugin-mgr] prereq run failed for ${packageName}:`,err)}return notifyBackendPluginChange(deps.db),getDaemonProfile().audit.emit("agent","plugin.installed",{packageName,version:installedEntry.version,pluginName:installedEntry.pluginName,wasRunning:alreadyRunning}),{success:!0,message:`Plugin ${packageName} installed and loaded successfully`,prereqs:prereqs?{satisfied:prereqs.satisfied,missing:prereqs.status?.missing??[],pendingSudo:prereqs.pendingSudo,skipped:!!body.skipPrereqs}:void 0}})}catch(err){return set.status=500,{error:"Failed to install plugin",details:String(err)}}},{body:t.Object({packageName:t.String(),skipPrereqs:t.Optional(t.Boolean())})}).post("/prereqs/status",async({body,set})=>{if(!body.packageName)return set.status=400,{error:"Missing packageName"};let pkg=body.packageName,plugin=pluginManager.getAllPlugins().find((p)=>p.name===pkg||pluginManager.getLoaded(pkg)?.name===p.name);if(!plugin||!deps.app)return await readPrereqState(deps.db,pkg)??{satisfied:!0,missing:[]};try{let r=await runPluginPrereqs(plugin,pkg,deps.app,deps.db,{skipInstall:!0});return{satisfied:r.satisfied,missing:r.status?.missing??[],noProtocol:r.noProtocol}}catch(err){return set.status=500,{error:String(err)}}},{body:t.Object({packageName:t.String()})}).post("/prereqs/install",async({body,set})=>{if(!body.packageName)return set.status=400,{error:"Missing packageName"};let pkg=body.packageName,plugin=pluginManager.getAllPlugins().find((p)=>p.name===pkg||pluginManager.getLoaded(pkg)?.name===p.name);if(!plugin||!deps.app)return set.status=404,{error:"Plugin not loaded"};try{let r=await runPluginPrereqs(plugin,pkg,deps.app,deps.db,{skipInstall:!1});return{satisfied:r.satisfied,installed:r.install?.installed??[],pendingSudo:r.pendingSudo,errors:r.install?.errors??[],noProtocol:r.noProtocol}}catch(err){return set.status=500,{error:String(err)}}},{body:t.Object({packageName:t.String(),approveSudo:t.Optional(t.Boolean())})}).post("/prereqs/uninstall",async({body,set})=>{if(!body.packageName)return set.status=400,{error:"Missing packageName"};let pkg=body.packageName,plugin=pluginManager.getAllPlugins().find((p)=>p.name===pkg);if(!plugin||!plugin.apiPrefix||!deps.app)return set.status=404,{error:"Plugin not loaded"};let handle=deps.app.handle;if(typeof handle!=="function")return set.status=500,{error:"App handle unavailable"};let path=`${plugin.apiPrefix.replace(/\/+$/,"")}/prereqs/uninstall`,res=await handle.call(deps.app,new Request(`http://agent.local${path}`,{method:"POST",headers:{"x-vc-profile-rewrite":"1",[INTERNAL_DISPATCH_HEADER]:getInternalDispatchToken()}}));if(res.status===404)return set.status=404,{error:"Plugin has no prereqs/uninstall endpoint"};return res.json()},{body:t.Object({packageName:t.String()})}).post("/nuke",async({body,set})=>{if(!deps.hostServices)return set.status=503,{error:"hostServices unavailable"};let agentDir=deps.hostServices.getDataDir?.();return{ok:!0,...await pluginManager.runPluginNuke(body.packageName,deps.hostServices,{agentDir,dryRun:!!body.dryRun})}},{body:t.Object({packageName:t.Optional(t.String()),dryRun:t.Optional(t.Boolean())})}).post("/remove",async({body,set})=>{if(!body.packageName||typeof body.packageName!=="string")return set.status=400,{error:"Missing required field: packageName"};if(body.packageName.startsWith("@burdenoff/"))body.packageName=body.packageName.replace(/^@burdenoff\//,"@vibecontrols/");if(isCriticalPlugin(body.packageName))return{success:!0,message:`Plugin ${body.packageName} is critical and cannot be removed; treating remove as a no-op.`,skipped:!0};try{let packageName=validatePluginPackageName(body.packageName);return await withPluginLifecycleLock(packageName,async()=>{return await pluginManager.remove(packageName,deps.hostServices),deps.rebuildPluginSurfaces?.(),notifyBackendPluginChange(deps.db),getDaemonProfile().audit.emit("agent","plugin.removed",{packageName}),{success:!0,message:`Plugin ${packageName} removed successfully`}})}catch(err){return set.status=500,{error:"Failed to remove plugin",details:String(err)}}},{body:t.Object({packageName:t.String()})}).post("/update",async({body,set})=>{if(!body.packageName||typeof body.packageName!=="string")return set.status=400,{error:"Missing required field: packageName"};try{let packageName=validatePluginPackageName(body.packageName);return await withPluginLifecycleLock(packageName,async()=>{let existingPlugin=pluginManager.getLoaded(packageName);if(existingPlugin?.onServerStop)await existingPlugin.onServerStop({reason:"reload"});if(existingPlugin&&deps.hostServices)deps.hostServices.serviceRegistry.unregisterPlugin(existingPlugin.name);let entry=await pluginManager.update(packageName),updatedPlugin=pluginManager.getLoaded(packageName);if(updatedPlugin&&deps.hostServices){if(pluginManager.registerProviders(updatedPlugin,deps.hostServices),updatedPlugin.onServerStart&&deps.app)await updatedPlugin.onServerStart(deps.app,deps.hostServices),pluginManager.registerProviders(updatedPlugin,deps.hostServices);if(updatedPlugin.onServerReady&&deps.app)await updatedPlugin.onServerReady(deps.app,deps.hostServices)}return deps.rebuildPluginSurfaces?.(),notifyBackendPluginChange(deps.db),{success:!0,message:`Plugin ${packageName} updated to v${entry.version}`,version:entry.version}})}catch(err){return set.status=500,{error:"Failed to update plugin",details:String(err)}}},{body:t.Object({packageName:t.String()})}).post("/update-all",async({set})=>{try{let results=await withPluginLifecycleLock("*",()=>pluginManager.updateAll());return{success:!0,results,message:`Updated ${results.filter((r)=>r.success).length}/${results.length} plugin(s)`}}catch(err){return set.status=500,{error:"Failed to update all plugins",details:String(err)}}}).post("/remove-all",async({set})=>{try{let results=await withPluginLifecycleLock("*",async()=>{let removed=await pluginManager.removeAll(deps.hostServices);return deps.rebuildPluginSurfaces?.(),removed});return{success:!0,results,message:`Removed ${results.filter((r)=>r.success).length}/${results.length} plugin(s)`}}catch(err){return set.status=500,{error:"Failed to remove all plugins",details:String(err)}}}).post("/reload",async({set})=>{try{if(!deps.app||!deps.hostServices)return set.status=503,{error:"Plugin lifecycle services are not ready"};let plugins=await withPluginLifecycleLock("*",async()=>{return await pluginManager.reloadAll(deps.app,deps.hostServices),deps.rebuildPluginSurfaces?.(),pluginManager.getPluginDetails()});return{success:!0,plugins,message:`Reloaded ${plugins.length} plugin(s)`}}catch(err){return set.status=500,{error:"Failed to reload plugins",details:String(err)}}}).post("/:name/reload",async({params,set})=>{if(!deps.app||!deps.hostServices)return set.status=503,{error:"Plugin lifecycle services are not ready"};let target=params.name,plugin=pluginManager.getAllPlugins().find((p)=>p.name===target);if(!plugin)return set.status=404,{error:`Plugin "${target}" not found`};let packageName=pluginManager.getPluginDetails().find((d)=>d.pluginName===target)?.packageName??`core:${target}`;if(isPackageInstallInFlight(packageName))return set.status=409,{error:"Plugin lifecycle in progress; try again shortly",packageName};try{return await withPluginLifecycleLock(packageName,async()=>{if(plugin.onServerStop)try{await plugin.onServerStop({reason:"reload"})}catch(err){console.warn(`[plugin-mgr] onServerStop during reload of ${target}:`,err)}if(deps.hostServices)deps.hostServices.serviceRegistry.unregisterPlugin(plugin.name);if(pluginManager.registerProviders(plugin,deps.hostServices),plugin.onServerStart)await plugin.onServerStart(deps.app,deps.hostServices),pluginManager.registerProviders(plugin,deps.hostServices);if(plugin.onServerReady)await plugin.onServerReady(deps.app,deps.hostServices);return deps.rebuildPluginSurfaces?.(),{success:!0,message:`Plugin ${target} reloaded`,version:plugin.version}})}catch(err){return set.status=500,{error:"Failed to reload plugin",details:String(err)}}},{params:t.Object({name:t.String()})})}import{mkdirSync,writeFileSync,existsSync}from"fs";import{isAbsolute,join,relative,resolve}from"path";var DEFAULT_AGENT_URL="http://localhost:3005",PLUGIN_BASENAME_RE=/^[a-z0-9][a-z0-9-]{0,63}$/,ALLOWED_TAGS=new Set(["backend","frontend","cli","provider","adapter","integration"]);function assertInside(parent,child){let rel=relative(parent,child);if(rel.startsWith("..")||isAbsolute(rel))throw Error("Plugin scaffold path escapes the selected directory.")}function toLiteral(value){return JSON.stringify(value)}function register(program){let cmd=program.command("plugin").description("Manage plugins");cmd.command("list").description("List installed plugins").option("--agent-url <url>","Agent URL",DEFAULT_AGENT_URL).option("--profile <name>","Target a specific profile by name").option("--json","Emit JSON").option("--plain","Force plain text output").action(async(options)=>{try{let merged={...program.opts(),...options},url=getAgentUrl(options),profile=encodeURIComponent(resolveProfileName(merged)),fetchData=async()=>{try{return(await apiGet(url,`/api/profiles/${profile}/plugins`)).plugins||[]}catch{warn("Agent not reachable. Attempting local plugin registry...");let{PluginManager}=await import("./plugin-system-3z2smf2a.js");return new PluginManager().getPluginDetails()||[]}},statusOf=(p)=>p.status??(p.loaded===!0||p.enabled===!0?"enabled":"disabled"),nameOf=(p)=>p.pluginName||p.name||p.packageName||p.package||"-";await runMultimode({mode:pickOutputMode(merged),fetchData,plain:(list)=>{if(!list.length){info("No plugins installed.");return}header("Installed Plugins"),formatTable(list.map((p)=>({Name:nameOf(p),Version:p.version||"-",Status:statusOf(p),Description:p.description||"-"})))},interactive:async(list)=>{if(!list.length){header("Installed Plugins"),info("No plugins installed.");return}let rows=list.map((p)=>{let name=nameOf(p),status=statusOf(p),detailLines=[`${colors.bold(name)} ${status==="enabled"?colors.green(status):colors.dim(status)}`,"",` Version: ${p.version||"-"}`,` Description: ${p.description||"-"}`];if(p.tags&&Array.isArray(p.tags))detailLines.push(` Tags: ${p.tags.join(", ")}`);if(p.cliCommand)detailLines.push(` CLI command: vibe ${p.cliCommand}`);return{id:name,label:name,hint:status,detail:detailLines.join(`
3
- `)}});await interactiveTable({title:`vibe plugin \u2014 ${list.length} installed`,rows,footer:"\u2191/\u2193 navigate \xB7 q to quit"})},json:(list)=>list.map((p)=>({name:nameOf(p),version:p.version??null,status:statusOf(p),description:p.description??null,tags:p.tags??null,cliCommand:p.cliCommand??null}))})}catch(err){fail(errMsg(err))}}),cmd.command("install").description("Install a plugin").argument("<package>","NPM package name to install").option("--agent-url <url>","Agent URL",DEFAULT_AGENT_URL).option("--profile <name>","Target a specific profile by name").option("--skip-prereqs","Skip running the plugin's prereqs/install",!1).option("--json","Emit JSON result").action(async(packageName,options)=>{try{let merged={...program.opts(),...options},url=getAgentUrl(options),profile=encodeURIComponent(resolveProfileName(merged));try{let result=await apiPost(url,`/api/profiles/${profile}/plugins/install`,{packageName,skipPrereqs:!!options.skipPrereqs});if(maybePrintJson(merged,{ok:!0,action:"install",package:packageName,version:result?.version??null,prereqs:result?.prereqs??null}))return;if(success(`Plugin "${packageName}" installed.`),result?.version)kv("Version",result.version);if(result?.prereqs){let p=result.prereqs;if(p.skipped)warn(`Prerequisite install skipped. Run \`vibe plugin prereqs ${packageName} install\` later.`);else if(!p.satisfied)warn(`Prerequisites not yet satisfied: ${(p.missing||[]).map((m)=>m.name).join(", ")||"(unknown)"}`);if((p.pendingSudo||[]).length>0){warn(`${p.pendingSudo.length} command(s) need sudo. Run them and re-check with \`vibe plugin prereqs ${packageName} status\`:`);for(let ps of p.pendingSudo)kv(` ${ps.name}`,ps.command)}}}catch{warn("Agent not reachable. Attempting local install...");try{let{PluginManager}=await import("./plugin-system-3z2smf2a.js");if(await new PluginManager().install(packageName),maybePrintJson(merged,{ok:!0,action:"install",package:packageName,local:!0}))return;success(`Plugin "${packageName}" installed locally.`)}catch(localErr){fail(`Could not install plugin via agent or locally: ${errMsg(localErr)}`)}}}catch(err){fail(errMsg(err))}}),cmd.command("remove").description("Remove a plugin").argument("<package>","NPM package name to remove").option("--agent-url <url>","Agent URL",DEFAULT_AGENT_URL).option("--profile <name>","Target a specific profile by name").option("--json","Emit JSON result").action(async(packageName,options)=>{try{let merged={...program.opts(),...options},url=getAgentUrl(options),profile=encodeURIComponent(resolveProfileName(merged));try{if(await apiPost(url,`/api/profiles/${profile}/plugins/remove`,{packageName}),maybePrintJson(merged,{ok:!0,action:"remove",package:packageName}))return;success(`Plugin "${packageName}" removed.`)}catch{warn("Agent not reachable. Attempting local removal...");try{let{PluginManager}=await import("./plugin-system-3z2smf2a.js");if(await new PluginManager().remove(packageName),maybePrintJson(merged,{ok:!0,action:"remove",package:packageName,local:!0}))return;success(`Plugin "${packageName}" removed locally.`)}catch(localErr){fail(`Could not remove plugin via agent or locally: ${errMsg(localErr)}`)}}}catch(err){fail(errMsg(err))}}),cmd.command("update").description("Update a plugin (or all plugins with --all)").argument("[package]","NPM package name to update").option("--all","Update all installed plugins",!1).option("--agent-url <url>","Agent URL",DEFAULT_AGENT_URL).option("--profile <name>","Target a specific profile by name").option("--json","Emit JSON result").action(async(packageName,options)=>{try{let merged={...program.opts(),...options},url=getAgentUrl(options),profile=encodeURIComponent(resolveProfileName(merged));if(options.all){info("Updating all plugins...");try{let result=await apiPost(url,`/api/profiles/${profile}/plugins/update-all`,{}),results=result?.results||[];if(maybePrintJson(merged,{ok:!0,action:"update-all",results}))return;for(let r of results)if(r.success)success(`Updated ${r.packageName}${r.version?` to v${r.version}`:""}`);else warn(`Failed to update ${r.packageName}: ${r.error}`);success(result?.message||"Done.")}catch{warn("Agent not reachable. Attempting local update...");try{let{PluginManager}=await import("./plugin-system-3z2smf2a.js"),results=await new PluginManager().updateAll();if(maybePrintJson(merged,{ok:!0,action:"update-all",results,local:!0}))return;for(let r of results)if(r.success)success(`Updated ${r.packageName}${r.version?` to v${r.version}`:""}`);else warn(`Failed to update ${r.packageName}: ${r.error}`)}catch(localErr){fail(`Could not update plugins: ${errMsg(localErr)}`)}}}else if(packageName){info(`Updating ${packageName}...`);try{let result=await apiPost(url,`/api/profiles/${profile}/plugins/update`,{packageName});if(maybePrintJson(merged,{ok:!0,action:"update",package:packageName,version:result?.version??null,message:result?.message??null}))return;success(result?.message||`Plugin "${packageName}" updated.`)}catch{warn("Agent not reachable. Attempting local update...");try{let{PluginManager}=await import("./plugin-system-3z2smf2a.js"),entry=await new PluginManager().update(packageName);if(maybePrintJson(merged,{ok:!0,action:"update",package:packageName,version:entry.version,local:!0}))return;success(`Plugin "${packageName}" updated to v${entry.version}.`)}catch(localErr){fail(`Could not update plugin: ${errMsg(localErr)}`)}}}else fail("Provide a package name to update, or use --all to update all plugins.")}catch(err){fail(errMsg(err))}}),cmd.command("uninstall").description("Uninstall a plugin (or all plugins with --all)").argument("[package]","NPM package name to uninstall").option("--all","Uninstall all external plugins",!1).option("--agent-url <url>","Agent URL",DEFAULT_AGENT_URL).option("--profile <name>","Target a specific profile by name").option("--json","Emit JSON result").action(async(packageName,options)=>{try{let merged={...program.opts(),...options},url=getAgentUrl(options),profile=encodeURIComponent(resolveProfileName(merged));if(options.all){info("Uninstalling all plugins...");try{let result=await apiPost(url,`/api/profiles/${profile}/plugins/remove-all`,{}),results=result?.results||[];if(maybePrintJson(merged,{ok:!0,action:"uninstall-all",results}))return;for(let r of results)if(r.success)success(`Removed ${r.packageName}`);else warn(`Failed to remove ${r.packageName}: ${r.error}`);success(result?.message||"Done.")}catch{warn("Agent not reachable. Attempting local removal...");try{let{PluginManager}=await import("./plugin-system-3z2smf2a.js"),results=await new PluginManager().removeAll();if(maybePrintJson(merged,{ok:!0,action:"uninstall-all",results,local:!0}))return;for(let r of results)if(r.success)success(`Removed ${r.packageName}`);else warn(`Failed to remove ${r.packageName}: ${r.error}`)}catch(localErr){fail(`Could not uninstall plugins: ${errMsg(localErr)}`)}}}else if(packageName)try{if(await apiPost(url,`/api/profiles/${profile}/plugins/remove`,{packageName}),maybePrintJson(merged,{ok:!0,action:"uninstall",package:packageName}))return;success(`Plugin "${packageName}" uninstalled.`)}catch{warn("Agent not reachable. Attempting local removal...");try{let{PluginManager}=await import("./plugin-system-3z2smf2a.js");if(await new PluginManager().remove(packageName),maybePrintJson(merged,{ok:!0,action:"uninstall",package:packageName,local:!0}))return;success(`Plugin "${packageName}" uninstalled locally.`)}catch(localErr){fail(`Could not uninstall plugin: ${errMsg(localErr)}`)}}else fail("Provide a package name to uninstall, or use --all to uninstall all plugins.")}catch(err){fail(errMsg(err))}}),cmd.command("reload").description("Reload all plugins").option("--agent-url <url>","Agent URL",DEFAULT_AGENT_URL).option("--profile <name>","Target a specific profile by name").option("--json","Emit JSON result").action(async(options)=>{try{let merged={...program.opts(),...options},url=getAgentUrl(options),profile=encodeURIComponent(resolveProfileName(merged));if(await apiPost(url,`/api/profiles/${profile}/plugins/reload`,{}),maybePrintJson(merged,{ok:!0,action:"reload"}))return;success("Plugins reloaded.")}catch(err){fail(errMsg(err))}}),cmd.command("available").description("Show available plugins").option("--agent-url <url>","Agent URL",DEFAULT_AGENT_URL).option("--profile <name>","Target a specific profile by name").option("--json","Emit JSON").option("--plain","Force plain text output").action(async(options)=>{try{let merged={...program.opts(),...options},url=getAgentUrl(options),profile=encodeURIComponent(resolveProfileName(merged)),fetchData=async()=>{return(await apiGet(url,`/api/profiles/${profile}/plugins/available`)).plugins||[]},nameOf=(p)=>p.name||p.package||"-",versionOf=(p)=>p.version||p.latestVersion||"-";await runMultimode({mode:pickOutputMode(merged),fetchData,plain:(plugins)=>{if(!plugins||plugins.length===0){info("No available plugins found.");return}header("Available Plugins"),formatTable(plugins.map((p)=>({Name:nameOf(p),Version:versionOf(p),Description:p.description||"-"})))},interactive:async(plugins)=>{if(!plugins||plugins.length===0){header("Available Plugins"),info("No available plugins found.");return}let rows=plugins.map((p)=>{let name=nameOf(p),lines=[colors.bold(name),"",` Version: ${versionOf(p)}`,` Description: ${p.description||"-"}`];return{id:name,label:name,hint:versionOf(p),detail:lines.join(`
2
+ import{readPrereqState,runPluginPrereqs}from"./index-9nn2kpyg.js";import{notifyBackendPluginChange}from"./index-mq3amjcf.js";import"./index-23rdsqea.js";import"./index-wk359257.js";import{AVAILABLE_PLUGINS,getCatalogEntry,isCriticalPlugin,isTrustedPackage,validatePluginPackageName}from"./index-cyhcvfxs.js";import"./index-srbb2214.js";import"./index-brtw3j8x.js";import"./index-b4wy3jrt.js";import{INTERNAL_DISPATCH_HEADER,getInternalDispatchToken}from"./index-d3mz9vws.js";import{Elysia,t}from"./index-rnk0kny8.js";import{apiGet,apiPost,getAgentUrl,maybePrintJson,pickOutputMode,resolveProfileName,runMultimode}from"./index-wvabz3xh.js";import{colors,errMsg,fail,formatTable,header,info,kv,success,warn}from"./index-r0qezdp7.js";import{interactiveDetail,interactiveTable}from"./index-campp0wv.js";import"./index-2pqv0bya.js";import{getDaemonProfile}from"./index-7pdmqbj8.js";import"./index-bysm7taq.js";import"./index-zs58d1hc.js";import{__require}from"./index-e9rt4m94.js";import{timingSafeEqual}from"crypto";async function getRegistryIntegrity(pkg,version){try{let proc=Bun.spawn({cmd:["npm","view",`${pkg}@${version}`,"dist.integrity","--json"],stdout:"pipe",stderr:"pipe"});if(await proc.exited!==0)return null;let trimmed=(await new Response(proc.stdout).text()).trim();if(!trimmed)return null;if(trimmed.startsWith('"'))try{let parsed=JSON.parse(trimmed);return typeof parsed==="string"?parsed:null}catch{return null}return trimmed}catch{return null}}function compareIntegrity(expected,actual){let a=Buffer.from(expected),b=Buffer.from(actual);if(a.length!==b.length)return!1;try{return timingSafeEqual(a,b)}catch{return!1}}var AVAILABLE_PLUGINS2=AVAILABLE_PLUGINS.map((p)=>({packageName:p.packageName,name:p.pluginName,description:p.description,cliCommand:p.cliCommand,apiPrefix:p.apiPrefix,installed:!1,category:p.category})),lifecycleLocks=new Map;function withPluginLifecycleLock(packageName,fn){let run=(lifecycleLocks.get(packageName)??Promise.resolve()).then(fn,fn),stored=run.then(()=>{return},()=>{return});return lifecycleLocks.set(packageName,stored),stored.finally(()=>{if(lifecycleLocks.get(packageName)===stored)lifecycleLocks.delete(packageName)}),run}function isPackageInstallInFlight(packageName){return lifecycleLocks.has(packageName)}function availablePluginsPayload(pluginManager){let installed=pluginManager.getPluginDetails(),installedNames=new Set(installed.map((p)=>p.packageName));return{plugins:AVAILABLE_PLUGINS2.map((p)=>({...p,installed:installedNames.has(p.packageName)}))}}function createRoutes(deps){let{pluginManager}=deps;return new Elysia().get("/",()=>{let plugins=pluginManager.getPluginDetails();return{plugins,count:plugins.length}}).get("/available",()=>availablePluginsPayload(pluginManager)).get("/catalog",()=>availablePluginsPayload(pluginManager)).get("/contributions",({query})=>{let wantedMount=typeof query?.mountPoint==="string"&&query.mountPoint?query.mountPoint:null,items=[],packageNameByPluginName=new Map;for(let detail of pluginManager.getPluginDetails())packageNameByPluginName.set(detail.pluginName,detail.packageName);for(let plugin of pluginManager.getAllPlugins()){let ui=plugin.ui;if(!ui||!ui.contributions||ui.contributions.length===0)continue;let fallbackCaps=ui.capabilities??{restPaths:[],wsTopics:[],rpcMethods:[]};for(let contribution of ui.contributions){if(wantedMount&&contribution.mountPoint!==wantedMount)continue;let meta=contribution.meta,rawOverride=meta&&typeof meta.url==="string"?meta.url:null,overrideUrl=rawOverride&&rawOverride.startsWith("/")&&!rawOverride.startsWith("//")&&!rawOverride.includes("\x00")&&!rawOverride.includes("..")?rawOverride:null;items.push({pluginKey:plugin.name,pluginPackageName:packageNameByPluginName.get(plugin.name),contribution,capabilities:contribution.capabilities??fallbackCaps,url:overrideUrl??`/ui/${encodeURIComponent(plugin.name)}`})}}return{contributions:items,count:items.length}}).post("/install",async({body,set})=>{if(!body.packageName||typeof body.packageName!=="string")return set.status=400,{error:"Missing required field: packageName"};if(body.packageName.startsWith("@burdenoff/"))body.packageName=body.packageName.replace(/^@burdenoff\//,"@vibecontrols/");if(!isTrustedPackage(body.packageName))return set.status=403,{error:"Plugin package is not in the trusted VibeControls catalog"};try{let packageName=validatePluginPackageName(body.packageName);if(isPackageInstallInFlight(packageName)){let slug=packageName.split("/").pop()?.replace("vibe-plugin-","");if(pluginManager.getAllPlugins().some((p)=>p.name===slug))return{success:!0,message:`Plugin ${packageName} is already installed`,packageName,alreadyInstalled:!0};return set.status=409,{error:"Install for this package is already in progress. Wait for it to finish.",packageName}}return await withPluginLifecycleLock(packageName,async()=>{let pluginName=packageName.split("/").pop()?.replace("vibe-plugin-",""),legacyAiProviderName=pluginName?.startsWith("ai-")?pluginName.slice(3):void 0,existingPlugin=pluginManager.getAllPlugins().find((p)=>p.name===pluginName||p.name===legacyAiProviderName),alreadyRunning=!!existingPlugin,installedEntry=await pluginManager.install(packageName),catalogEntry=getCatalogEntry(packageName);if(catalogEntry?.integrity){let actualIntegrity=await getRegistryIntegrity(packageName,installedEntry.version);if(!actualIntegrity||!compareIntegrity(catalogEntry.integrity,actualIntegrity)){try{await pluginManager.remove(packageName,deps.hostServices)}catch(rollbackErr){console.warn(`[plugin-mgr] integrity rollback uninstall failed for ${packageName}:`,rollbackErr)}return getDaemonProfile().audit.emit("agent","plugin.install.rejected",{packageName,version:installedEntry.version,reason:"integrity_mismatch",expected:catalogEntry.integrity,actual:actualIntegrity}),set.status=400,{error:"integrity mismatch",expected:catalogEntry.integrity,actual:actualIntegrity}}}else console.warn(`[plugin-mgr] plugin ${packageName} has no pinned integrity \u2014 accepting npm registry's hash`);let newPlugin=pluginManager.getAllPlugins().find((p)=>p.name===installedEntry.pluginName);if(newPlugin){let lifecycleErrors=[];if(deps.mountPlugin)deps.mountPlugin(newPlugin);if(deps.hostServices){if(alreadyRunning&&existingPlugin?.onServerStop)try{await existingPlugin.onServerStop()}catch(err){lifecycleErrors.push(`onServerStop failed: ${err instanceof Error?err.message:String(err)}`)}if(pluginManager.registerProviders(newPlugin,deps.hostServices),newPlugin.onServerStart&&deps.app)try{await newPlugin.onServerStart(deps.app,deps.hostServices),pluginManager.registerProviders(newPlugin,deps.hostServices)}catch(err){lifecycleErrors.push(`onServerStart failed: ${err instanceof Error?err.message:String(err)}`)}if(newPlugin.onServerReady&&deps.app)try{await newPlugin.onServerReady(deps.app,deps.hostServices)}catch(err){lifecycleErrors.push(`onServerReady failed: ${err instanceof Error?err.message:String(err)}`)}}if(deps.rebuildPluginSurfaces?.(),lifecycleErrors.length>0)return set.status=500,{success:!1,message:`Plugin ${packageName} installed but failed to start`,lifecycleErrors,restartRequired:!0}}let prereqs;if(newPlugin&&deps.app)try{prereqs=await runPluginPrereqs(newPlugin,packageName,deps.app,deps.db,{skipInstall:!!body.skipPrereqs})}catch(err){prereqs=void 0,console.warn(`[plugin-mgr] prereq run failed for ${packageName}:`,err)}return notifyBackendPluginChange(deps.db),getDaemonProfile().audit.emit("agent","plugin.installed",{packageName,version:installedEntry.version,pluginName:installedEntry.pluginName,wasRunning:alreadyRunning}),{success:!0,message:`Plugin ${packageName} installed and loaded successfully`,prereqs:prereqs?{satisfied:prereqs.satisfied,missing:prereqs.status?.missing??[],pendingSudo:prereqs.pendingSudo,skipped:!!body.skipPrereqs}:void 0}})}catch(err){return set.status=500,{error:"Failed to install plugin",details:String(err)}}},{body:t.Object({packageName:t.String(),skipPrereqs:t.Optional(t.Boolean())})}).post("/prereqs/status",async({body,set})=>{if(!body.packageName)return set.status=400,{error:"Missing packageName"};let pkg=body.packageName,plugin=pluginManager.getAllPlugins().find((p)=>p.name===pkg||pluginManager.getLoaded(pkg)?.name===p.name);if(!plugin||!deps.app)return await readPrereqState(deps.db,pkg)??{satisfied:!0,missing:[]};try{let r=await runPluginPrereqs(plugin,pkg,deps.app,deps.db,{skipInstall:!0});return{satisfied:r.satisfied,missing:r.status?.missing??[],noProtocol:r.noProtocol}}catch(err){return set.status=500,{error:String(err)}}},{body:t.Object({packageName:t.String()})}).post("/prereqs/install",async({body,set})=>{if(!body.packageName)return set.status=400,{error:"Missing packageName"};let pkg=body.packageName,plugin=pluginManager.getAllPlugins().find((p)=>p.name===pkg||pluginManager.getLoaded(pkg)?.name===p.name);if(!plugin||!deps.app)return set.status=404,{error:"Plugin not loaded"};try{let r=await runPluginPrereqs(plugin,pkg,deps.app,deps.db,{skipInstall:!1});return{satisfied:r.satisfied,installed:r.install?.installed??[],pendingSudo:r.pendingSudo,errors:r.install?.errors??[],noProtocol:r.noProtocol}}catch(err){return set.status=500,{error:String(err)}}},{body:t.Object({packageName:t.String(),approveSudo:t.Optional(t.Boolean())})}).post("/prereqs/uninstall",async({body,set})=>{if(!body.packageName)return set.status=400,{error:"Missing packageName"};let pkg=body.packageName,plugin=pluginManager.getAllPlugins().find((p)=>p.name===pkg);if(!plugin||!plugin.apiPrefix||!deps.app)return set.status=404,{error:"Plugin not loaded"};let handle=deps.app.handle;if(typeof handle!=="function")return set.status=500,{error:"App handle unavailable"};let path=`${plugin.apiPrefix.replace(/\/+$/,"")}/prereqs/uninstall`,res=await handle.call(deps.app,new Request(`http://agent.local${path}`,{method:"POST",headers:{"x-vc-profile-rewrite":"1",[INTERNAL_DISPATCH_HEADER]:getInternalDispatchToken()}}));if(res.status===404)return set.status=404,{error:"Plugin has no prereqs/uninstall endpoint"};return res.json()},{body:t.Object({packageName:t.String()})}).post("/nuke",async({body,set})=>{if(!deps.hostServices)return set.status=503,{error:"hostServices unavailable"};let agentDir=deps.hostServices.getDataDir?.();return{ok:!0,...await pluginManager.runPluginNuke(body.packageName,deps.hostServices,{agentDir,dryRun:!!body.dryRun})}},{body:t.Object({packageName:t.Optional(t.String()),dryRun:t.Optional(t.Boolean())})}).post("/remove",async({body,set})=>{if(!body.packageName||typeof body.packageName!=="string")return set.status=400,{error:"Missing required field: packageName"};if(body.packageName.startsWith("@burdenoff/"))body.packageName=body.packageName.replace(/^@burdenoff\//,"@vibecontrols/");if(isCriticalPlugin(body.packageName))return{success:!0,message:`Plugin ${body.packageName} is critical and cannot be removed; treating remove as a no-op.`,skipped:!0};try{let packageName=validatePluginPackageName(body.packageName);return await withPluginLifecycleLock(packageName,async()=>{return await pluginManager.remove(packageName,deps.hostServices),deps.rebuildPluginSurfaces?.(),notifyBackendPluginChange(deps.db),getDaemonProfile().audit.emit("agent","plugin.removed",{packageName}),{success:!0,message:`Plugin ${packageName} removed successfully`}})}catch(err){return set.status=500,{error:"Failed to remove plugin",details:String(err)}}},{body:t.Object({packageName:t.String()})}).post("/update",async({body,set})=>{if(!body.packageName||typeof body.packageName!=="string")return set.status=400,{error:"Missing required field: packageName"};try{let packageName=validatePluginPackageName(body.packageName);return await withPluginLifecycleLock(packageName,async()=>{let existingPlugin=pluginManager.getLoaded(packageName);if(existingPlugin?.onServerStop)await existingPlugin.onServerStop({reason:"reload"});if(existingPlugin&&deps.hostServices)deps.hostServices.serviceRegistry.unregisterPlugin(existingPlugin.name);let entry=await pluginManager.update(packageName),updatedPlugin=pluginManager.getLoaded(packageName);if(updatedPlugin&&deps.hostServices){if(pluginManager.registerProviders(updatedPlugin,deps.hostServices),updatedPlugin.onServerStart&&deps.app)await updatedPlugin.onServerStart(deps.app,deps.hostServices),pluginManager.registerProviders(updatedPlugin,deps.hostServices);if(updatedPlugin.onServerReady&&deps.app)await updatedPlugin.onServerReady(deps.app,deps.hostServices)}return deps.rebuildPluginSurfaces?.(),notifyBackendPluginChange(deps.db),{success:!0,message:`Plugin ${packageName} updated to v${entry.version}`,version:entry.version}})}catch(err){return set.status=500,{error:"Failed to update plugin",details:String(err)}}},{body:t.Object({packageName:t.String()})}).post("/update-all",async({set})=>{try{let results=await withPluginLifecycleLock("*",()=>pluginManager.updateAll());return{success:!0,results,message:`Updated ${results.filter((r)=>r.success).length}/${results.length} plugin(s)`}}catch(err){return set.status=500,{error:"Failed to update all plugins",details:String(err)}}}).post("/remove-all",async({set})=>{try{let results=await withPluginLifecycleLock("*",async()=>{let removed=await pluginManager.removeAll(deps.hostServices);return deps.rebuildPluginSurfaces?.(),removed});return{success:!0,results,message:`Removed ${results.filter((r)=>r.success).length}/${results.length} plugin(s)`}}catch(err){return set.status=500,{error:"Failed to remove all plugins",details:String(err)}}}).post("/reload",async({set})=>{try{if(!deps.app||!deps.hostServices)return set.status=503,{error:"Plugin lifecycle services are not ready"};let plugins=await withPluginLifecycleLock("*",async()=>{return await pluginManager.reloadAll(deps.app,deps.hostServices),deps.rebuildPluginSurfaces?.(),pluginManager.getPluginDetails()});return{success:!0,plugins,message:`Reloaded ${plugins.length} plugin(s)`}}catch(err){return set.status=500,{error:"Failed to reload plugins",details:String(err)}}}).post("/:name/reload",async({params,set})=>{if(!deps.app||!deps.hostServices)return set.status=503,{error:"Plugin lifecycle services are not ready"};let target=params.name,plugin=pluginManager.getAllPlugins().find((p)=>p.name===target);if(!plugin)return set.status=404,{error:`Plugin "${target}" not found`};let packageName=pluginManager.getPluginDetails().find((d)=>d.pluginName===target)?.packageName??`core:${target}`;if(isPackageInstallInFlight(packageName))return set.status=409,{error:"Plugin lifecycle in progress; try again shortly",packageName};try{return await withPluginLifecycleLock(packageName,async()=>{if(plugin.onServerStop)try{await plugin.onServerStop({reason:"reload"})}catch(err){console.warn(`[plugin-mgr] onServerStop during reload of ${target}:`,err)}if(deps.hostServices)deps.hostServices.serviceRegistry.unregisterPlugin(plugin.name);if(pluginManager.registerProviders(plugin,deps.hostServices),plugin.onServerStart)await plugin.onServerStart(deps.app,deps.hostServices),pluginManager.registerProviders(plugin,deps.hostServices);if(plugin.onServerReady)await plugin.onServerReady(deps.app,deps.hostServices);return deps.rebuildPluginSurfaces?.(),{success:!0,message:`Plugin ${target} reloaded`,version:plugin.version}})}catch(err){return set.status=500,{error:"Failed to reload plugin",details:String(err)}}},{params:t.Object({name:t.String()})})}import{mkdirSync,writeFileSync,existsSync}from"fs";import{isAbsolute,join,relative,resolve}from"path";var DEFAULT_AGENT_URL="http://localhost:3005",PLUGIN_BASENAME_RE=/^[a-z0-9][a-z0-9-]{0,63}$/,ALLOWED_TAGS=new Set(["backend","frontend","cli","provider","adapter","integration"]);function assertInside(parent,child){let rel=relative(parent,child);if(rel.startsWith("..")||isAbsolute(rel))throw Error("Plugin scaffold path escapes the selected directory.")}function toLiteral(value){return JSON.stringify(value)}function register(program){let cmd=program.command("plugin").description("Manage plugins");cmd.command("list").description("List installed plugins").option("--agent-url <url>","Agent URL",DEFAULT_AGENT_URL).option("--profile <name>","Target a specific profile by name").option("--json","Emit JSON").option("--plain","Force plain text output").action(async(options)=>{try{let merged={...program.opts(),...options},url=getAgentUrl(options),profile=encodeURIComponent(resolveProfileName(merged)),fetchData=async()=>{try{return(await apiGet(url,`/api/profiles/${profile}/plugins`)).plugins||[]}catch{warn("Agent not reachable. Attempting local plugin registry...");let{PluginManager}=await import("./plugin-system-w3vnn5vh.js");return new PluginManager().getPluginDetails()||[]}},statusOf=(p)=>p.status??(p.loaded===!0||p.enabled===!0?"enabled":"disabled"),nameOf=(p)=>p.pluginName||p.name||p.packageName||p.package||"-";await runMultimode({mode:pickOutputMode(merged),fetchData,plain:(list)=>{if(!list.length){info("No plugins installed.");return}header("Installed Plugins"),formatTable(list.map((p)=>({Name:nameOf(p),Version:p.version||"-",Status:statusOf(p),Description:p.description||"-"})))},interactive:async(list)=>{if(!list.length){header("Installed Plugins"),info("No plugins installed.");return}let rows=list.map((p)=>{let name=nameOf(p),status=statusOf(p),detailLines=[`${colors.bold(name)} ${status==="enabled"?colors.green(status):colors.dim(status)}`,"",` Version: ${p.version||"-"}`,` Description: ${p.description||"-"}`];if(p.tags&&Array.isArray(p.tags))detailLines.push(` Tags: ${p.tags.join(", ")}`);if(p.cliCommand)detailLines.push(` CLI command: vibe ${p.cliCommand}`);return{id:name,label:name,hint:status,detail:detailLines.join(`
3
+ `)}});await interactiveTable({title:`vibe plugin \u2014 ${list.length} installed`,rows,footer:"\u2191/\u2193 navigate \xB7 q to quit"})},json:(list)=>list.map((p)=>({name:nameOf(p),version:p.version??null,status:statusOf(p),description:p.description??null,tags:p.tags??null,cliCommand:p.cliCommand??null}))})}catch(err){fail(errMsg(err))}}),cmd.command("install").description("Install a plugin").argument("<package>","NPM package name to install").option("--agent-url <url>","Agent URL",DEFAULT_AGENT_URL).option("--profile <name>","Target a specific profile by name").option("--skip-prereqs","Skip running the plugin's prereqs/install",!1).option("--json","Emit JSON result").action(async(packageName,options)=>{try{let merged={...program.opts(),...options},url=getAgentUrl(options),profile=encodeURIComponent(resolveProfileName(merged));try{let result=await apiPost(url,`/api/profiles/${profile}/plugins/install`,{packageName,skipPrereqs:!!options.skipPrereqs});if(maybePrintJson(merged,{ok:!0,action:"install",package:packageName,version:result?.version??null,prereqs:result?.prereqs??null}))return;if(success(`Plugin "${packageName}" installed.`),result?.version)kv("Version",result.version);if(result?.prereqs){let p=result.prereqs;if(p.skipped)warn(`Prerequisite install skipped. Run \`vibe plugin prereqs ${packageName} install\` later.`);else if(!p.satisfied)warn(`Prerequisites not yet satisfied: ${(p.missing||[]).map((m)=>m.name).join(", ")||"(unknown)"}`);if((p.pendingSudo||[]).length>0){warn(`${p.pendingSudo.length} command(s) need sudo. Run them and re-check with \`vibe plugin prereqs ${packageName} status\`:`);for(let ps of p.pendingSudo)kv(` ${ps.name}`,ps.command)}}}catch{warn("Agent not reachable. Attempting local install...");try{let{PluginManager}=await import("./plugin-system-w3vnn5vh.js");if(await new PluginManager().install(packageName),maybePrintJson(merged,{ok:!0,action:"install",package:packageName,local:!0}))return;success(`Plugin "${packageName}" installed locally.`)}catch(localErr){fail(`Could not install plugin via agent or locally: ${errMsg(localErr)}`)}}}catch(err){fail(errMsg(err))}}),cmd.command("remove").description("Remove a plugin").argument("<package>","NPM package name to remove").option("--agent-url <url>","Agent URL",DEFAULT_AGENT_URL).option("--profile <name>","Target a specific profile by name").option("--json","Emit JSON result").action(async(packageName,options)=>{try{let merged={...program.opts(),...options},url=getAgentUrl(options),profile=encodeURIComponent(resolveProfileName(merged));try{if(await apiPost(url,`/api/profiles/${profile}/plugins/remove`,{packageName}),maybePrintJson(merged,{ok:!0,action:"remove",package:packageName}))return;success(`Plugin "${packageName}" removed.`)}catch{warn("Agent not reachable. Attempting local removal...");try{let{PluginManager}=await import("./plugin-system-w3vnn5vh.js");if(await new PluginManager().remove(packageName),maybePrintJson(merged,{ok:!0,action:"remove",package:packageName,local:!0}))return;success(`Plugin "${packageName}" removed locally.`)}catch(localErr){fail(`Could not remove plugin via agent or locally: ${errMsg(localErr)}`)}}}catch(err){fail(errMsg(err))}}),cmd.command("update").description("Update a plugin (or all plugins with --all)").argument("[package]","NPM package name to update").option("--all","Update all installed plugins",!1).option("--agent-url <url>","Agent URL",DEFAULT_AGENT_URL).option("--profile <name>","Target a specific profile by name").option("--json","Emit JSON result").action(async(packageName,options)=>{try{let merged={...program.opts(),...options},url=getAgentUrl(options),profile=encodeURIComponent(resolveProfileName(merged));if(options.all){info("Updating all plugins...");try{let result=await apiPost(url,`/api/profiles/${profile}/plugins/update-all`,{}),results=result?.results||[];if(maybePrintJson(merged,{ok:!0,action:"update-all",results}))return;for(let r of results)if(r.success)success(`Updated ${r.packageName}${r.version?` to v${r.version}`:""}`);else warn(`Failed to update ${r.packageName}: ${r.error}`);success(result?.message||"Done.")}catch{warn("Agent not reachable. Attempting local update...");try{let{PluginManager}=await import("./plugin-system-w3vnn5vh.js"),results=await new PluginManager().updateAll();if(maybePrintJson(merged,{ok:!0,action:"update-all",results,local:!0}))return;for(let r of results)if(r.success)success(`Updated ${r.packageName}${r.version?` to v${r.version}`:""}`);else warn(`Failed to update ${r.packageName}: ${r.error}`)}catch(localErr){fail(`Could not update plugins: ${errMsg(localErr)}`)}}}else if(packageName){info(`Updating ${packageName}...`);try{let result=await apiPost(url,`/api/profiles/${profile}/plugins/update`,{packageName});if(maybePrintJson(merged,{ok:!0,action:"update",package:packageName,version:result?.version??null,message:result?.message??null}))return;success(result?.message||`Plugin "${packageName}" updated.`)}catch{warn("Agent not reachable. Attempting local update...");try{let{PluginManager}=await import("./plugin-system-w3vnn5vh.js"),entry=await new PluginManager().update(packageName);if(maybePrintJson(merged,{ok:!0,action:"update",package:packageName,version:entry.version,local:!0}))return;success(`Plugin "${packageName}" updated to v${entry.version}.`)}catch(localErr){fail(`Could not update plugin: ${errMsg(localErr)}`)}}}else fail("Provide a package name to update, or use --all to update all plugins.")}catch(err){fail(errMsg(err))}}),cmd.command("uninstall").description("Uninstall a plugin (or all plugins with --all)").argument("[package]","NPM package name to uninstall").option("--all","Uninstall all external plugins",!1).option("--agent-url <url>","Agent URL",DEFAULT_AGENT_URL).option("--profile <name>","Target a specific profile by name").option("--json","Emit JSON result").action(async(packageName,options)=>{try{let merged={...program.opts(),...options},url=getAgentUrl(options),profile=encodeURIComponent(resolveProfileName(merged));if(options.all){info("Uninstalling all plugins...");try{let result=await apiPost(url,`/api/profiles/${profile}/plugins/remove-all`,{}),results=result?.results||[];if(maybePrintJson(merged,{ok:!0,action:"uninstall-all",results}))return;for(let r of results)if(r.success)success(`Removed ${r.packageName}`);else warn(`Failed to remove ${r.packageName}: ${r.error}`);success(result?.message||"Done.")}catch{warn("Agent not reachable. Attempting local removal...");try{let{PluginManager}=await import("./plugin-system-w3vnn5vh.js"),results=await new PluginManager().removeAll();if(maybePrintJson(merged,{ok:!0,action:"uninstall-all",results,local:!0}))return;for(let r of results)if(r.success)success(`Removed ${r.packageName}`);else warn(`Failed to remove ${r.packageName}: ${r.error}`)}catch(localErr){fail(`Could not uninstall plugins: ${errMsg(localErr)}`)}}}else if(packageName)try{if(await apiPost(url,`/api/profiles/${profile}/plugins/remove`,{packageName}),maybePrintJson(merged,{ok:!0,action:"uninstall",package:packageName}))return;success(`Plugin "${packageName}" uninstalled.`)}catch{warn("Agent not reachable. Attempting local removal...");try{let{PluginManager}=await import("./plugin-system-w3vnn5vh.js");if(await new PluginManager().remove(packageName),maybePrintJson(merged,{ok:!0,action:"uninstall",package:packageName,local:!0}))return;success(`Plugin "${packageName}" uninstalled locally.`)}catch(localErr){fail(`Could not uninstall plugin: ${errMsg(localErr)}`)}}else fail("Provide a package name to uninstall, or use --all to uninstall all plugins.")}catch(err){fail(errMsg(err))}}),cmd.command("reload").description("Reload all plugins").option("--agent-url <url>","Agent URL",DEFAULT_AGENT_URL).option("--profile <name>","Target a specific profile by name").option("--json","Emit JSON result").action(async(options)=>{try{let merged={...program.opts(),...options},url=getAgentUrl(options),profile=encodeURIComponent(resolveProfileName(merged));if(await apiPost(url,`/api/profiles/${profile}/plugins/reload`,{}),maybePrintJson(merged,{ok:!0,action:"reload"}))return;success("Plugins reloaded.")}catch(err){fail(errMsg(err))}}),cmd.command("available").description("Show available plugins").option("--agent-url <url>","Agent URL",DEFAULT_AGENT_URL).option("--profile <name>","Target a specific profile by name").option("--json","Emit JSON").option("--plain","Force plain text output").action(async(options)=>{try{let merged={...program.opts(),...options},url=getAgentUrl(options),profile=encodeURIComponent(resolveProfileName(merged)),fetchData=async()=>{return(await apiGet(url,`/api/profiles/${profile}/plugins/available`)).plugins||[]},nameOf=(p)=>p.name||p.package||"-",versionOf=(p)=>p.version||p.latestVersion||"-";await runMultimode({mode:pickOutputMode(merged),fetchData,plain:(plugins)=>{if(!plugins||plugins.length===0){info("No available plugins found.");return}header("Available Plugins"),formatTable(plugins.map((p)=>({Name:nameOf(p),Version:versionOf(p),Description:p.description||"-"})))},interactive:async(plugins)=>{if(!plugins||plugins.length===0){header("Available Plugins"),info("No available plugins found.");return}let rows=plugins.map((p)=>{let name=nameOf(p),lines=[colors.bold(name),"",` Version: ${versionOf(p)}`,` Description: ${p.description||"-"}`];return{id:name,label:name,hint:versionOf(p),detail:lines.join(`
4
4
  `)}});await interactiveTable({title:`vibe plugin available \u2014 ${plugins.length} plugin(s)`,rows,footer:"\u2191/\u2193 navigate \xB7 q to quit"})},json:(plugins)=>plugins.map((p)=>({name:nameOf(p),version:versionOf(p),description:p.description??null}))})}catch(err){fail(errMsg(err))}});let prereqsCmd=cmd.command("prereqs").description("Inspect or run a plugin's prerequisite-install protocol").argument("<package>","NPM package name (or short plugin name)");prereqsCmd.command("status",{isDefault:!0}).description("Show the plugin's prereq status").option("--agent-url <url>","Agent URL",DEFAULT_AGENT_URL).option("--profile <name>","Target a specific profile by name").option("--json","Emit JSON").option("--plain","Force plain text output").action(async(options,cmdRef)=>{let pkg=cmdRef.parent?.args?.[0];if(!pkg){fail("Missing plugin package argument.");return}try{let merged={...program.opts(),...options},url=getAgentUrl(options),fetchData=async()=>apiPost(url,"/api/plugins/prereqs/status",{packageName:pkg});await runMultimode({mode:pickOutputMode(merged),fetchData,plain:(r)=>{if(kv("Plugin",pkg),kv("Satisfied",r?.satisfied?"yes":"no"),Array.isArray(r?.missing)&&r.missing.length>0)kv("Missing",r.missing.map((m)=>m.name).join(", "))},interactive:async(r)=>{let lines=[`Plugin: ${pkg}`,`Satisfied: ${r?.satisfied?"yes":"no"}`];if(Array.isArray(r?.missing)&&r.missing.length>0)lines.push(`Missing: ${r.missing.map((m)=>m.name).join(", ")}`);await interactiveDetail({title:`Prereqs: ${pkg}`,body:lines.join(`
5
5
  `),footer:"q / Esc to quit"})},json:(r)=>({plugin:pkg,satisfied:!!r?.satisfied,missing:Array.isArray(r?.missing)?r.missing:[],pendingSudo:Array.isArray(r?.pendingSudo)?r.pendingSudo:[]})})}catch(err){fail(`Could not read prereq status: ${errMsg(err)}`)}}),prereqsCmd.command("install").description("Run the plugin's prerequisite install endpoint").option("--agent-url <url>","Agent URL",DEFAULT_AGENT_URL).option("--profile <name>","Target a specific profile by name").option("--approve-sudo","Auto-approve sudo commands the plugin returns",!1).option("--json","Emit JSON result").action(async(options,cmdRef)=>{let pkg=cmdRef.parent?.args?.[0];if(!pkg){fail("Missing plugin package argument.");return}try{let merged={...program.opts(),...options},url=getAgentUrl(options),r=await apiPost(url,"/api/plugins/prereqs/install",{packageName:pkg,approveSudo:!!options.approveSudo});if(maybePrintJson(merged,{ok:!0,action:"prereqs-install",plugin:pkg,satisfied:!!r?.satisfied,pendingSudo:r?.pendingSudo??[]}))return;if(r?.satisfied)success(`Prerequisites satisfied for ${pkg}.`);else warn(`Prerequisites still missing for ${pkg}.`);if(Array.isArray(r?.pendingSudo)&&r.pendingSudo.length>0){warn(`${r.pendingSudo.length} command(s) require sudo:`);for(let ps of r.pendingSudo)kv(` ${ps.name}`,ps.command)}}catch(err){fail(`Prereq install failed: ${errMsg(err)}`)}}),prereqsCmd.command("uninstall").description("Run the plugin's prerequisite uninstall endpoint (if supported)").option("--agent-url <url>","Agent URL",DEFAULT_AGENT_URL).option("--profile <name>","Target a specific profile by name").option("--json","Emit JSON result").action(async(options,cmdRef)=>{let pkg=cmdRef.parent?.args?.[0];if(!pkg){fail("Missing plugin package argument.");return}try{let merged={...program.opts(),...options},url=getAgentUrl(options);if(await apiPost(url,"/api/plugins/prereqs/uninstall",{packageName:pkg}),maybePrintJson(merged,{ok:!0,action:"prereqs-uninstall",plugin:pkg}))return;success(`Prereq uninstall completed for ${pkg}.`)}catch(err){warn(`Prereq uninstall not supported or failed: ${errMsg(err)}`)}}),cmd.command("create").description("Scaffold a new plugin project").argument("<name>",'Plugin name (e.g. "docker" \u2192 vibe-plugin-docker)').option("-d, --dir <directory>","Parent directory",".").option("--tag <tag>","Plugin tag (backend, frontend, cli, provider, adapter, integration)","backend").option("--with-ui","Include a companion UI plugin scaffold",!1).option("--json","Emit JSON result").action(async(name,options)=>{try{let merged={...program.opts(),...options},baseName=name.startsWith("vibe-plugin-")?name.slice(12):name;if(!PLUGIN_BASENAME_RE.test(baseName)){fail("Plugin name must use lowercase letters, numbers, and dashes only.");return}let tag=options.tag;if(!ALLOWED_TAGS.has(tag)){fail("Invalid plugin tag.");return}let pluginName=`vibe-plugin-${baseName}`,parentDir=resolve(options.dir),dir=resolve(parentDir,pluginName);if(assertInside(parentDir,dir),existsSync(dir)){fail(`Directory "${dir}" already exists.`);return}info(`Scaffolding ${pluginName}...`),mkdirSync(join(dir,"src"),{recursive:!0}),mkdirSync(join(dir,"dist"),{recursive:!0});let description=`VibeControls plugin: ${baseName}`,packageJson={name:`@vibecontrols/${pluginName}`,version:"0.1.0",main:"./dist/index.js",type:"module",engines:{bun:">=1.3.0"},scripts:{build:"bun build ./src/index.ts --outdir ./dist --target bun",lint:"eslint ./src",format:"bunx prettier . --write","format:check":"bunx prettier . --check","type:check":"tsc --noEmit",clean:"rimraf dist",prebuild:"bun run clean",prepublishOnly:"bun run build",sanity:"bun run format:check && bun run lint && bun run type:check && bun run build"},keywords:["vibecontrols","vibe","vibe-plugin",baseName,"bun"],author:{name:"Your Name",email:"you@example.com"},license:"SEE LICENSE IN LICENSE",description,devDependencies:{"@types/bun":"^1.2.16","bun-types":"^1.3.9",commander:"^14.0.3",eslint:"^9.30.1",prettier:"^3.6.2",rimraf:"^6.0.1",typescript:"^5.8.3","typescript-eslint":"^8.56.0"},peerDependencies:{"@vibecontrols/agent":">=2.0.0"},peerDependenciesMeta:{"@vibecontrols/agent":{optional:!0}},publishConfig:{access:"public",registry:"https://registry.npmjs.org/"},files:["dist/**/*","README.md","LICENSE"]};writeFileSync(join(dir,"package.json"),JSON.stringify(packageJson,null,2)+`
6
6
  `);let tsconfig={compilerOptions:{target:"ES2022",module:"ES2022",moduleResolution:"bundler",types:["bun-types"],strict:!0,esModuleInterop:!0,skipLibCheck:!0,outDir:"./dist",rootDir:"./src",declaration:!0,sourceMap:!0},include:["src/**/*.ts"],exclude:["node_modules","dist"]};writeFileSync(join(dir,"tsconfig.json"),JSON.stringify(tsconfig,null,2)+`