@seanhogg/builderforce-agents 2026.10.3 → 2026.10.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{agent-CxhUn-aN.js → agent-Cu57zjv6.js} +1 -1
- package/dist/{agent-CiEaiH-p.js → agent-LoZ_09Jv.js} +1 -1
- package/dist/{agents-DkKFDcYq.js → agents-Dgrr6E7S.js} +1 -1
- package/dist/{agents-IZrPoZIi.js → agents-DiRof4zA.js} +1 -1
- package/dist/{audio-preflight-COZAlqnx.js → audio-preflight-Cg4vjX8I.js} +1 -1
- package/dist/{auth-choice-CrYQF7zX.js → auth-choice-BJmosINc.js} +1 -1
- package/dist/{auth-choice-DhUBmu6y.js → auth-choice-CDoW8QDy.js} +1 -1
- package/dist/{auth-choice.apply-Botyf6Sg.js → auth-choice.apply-25j_lhua.js} +1 -1
- package/dist/{auth-choice.apply-k9tk1hGj.js → auth-choice.apply-CE1TC_Ts.js} +1 -1
- package/dist/{auth-choice.apply-Cch5UXis.js → auth-choice.apply-DSHzvYNu.js} +1 -1
- package/dist/{auth-choice.apply-CXRcLO-h.js → auth-choice.apply-ND2C2oSe.js} +1 -1
- package/dist/{auth-choice.apply.transformers-BkN8HlZJ.js → auth-choice.apply.transformers-BF-qyu2L.js} +1 -1
- package/dist/{auth-choice.apply.transformers-B9SieNNk.js → auth-choice.apply.transformers-CBQbUAwr.js} +1 -1
- package/dist/{auth-choice.apply.transformers-D02W3zy7.js → auth-choice.apply.transformers-DE9QrzbX.js} +1 -1
- package/dist/{auth-choice.apply.transformers-Dnr7Izx1.js → auth-choice.apply.transformers-vr05ATPq.js} +1 -1
- package/dist/{banner-Bd45EXyp.js → banner-Bx4c92N8.js} +1 -1
- package/dist/build-info.json +3 -3
- package/dist/{builderforce-BxVfTQsc.js → builderforce-DHU87PJG.js} +1 -1
- package/dist/{builderforce-C86noipf.js → builderforce-DgYCZ3Up.js} +1 -1
- package/dist/bundled/boot-md/handler.js +1 -1
- package/dist/bundled/session-memory/handler.js +1 -1
- package/dist/{channel-options-BHetVK54.js → channel-options-BZoCW2EZ.js} +1 -1
- package/dist/{channel-options-D5PmuxT-.js → channel-options-DAkHvC-x.js} +1 -1
- package/dist/{channel-web-B5QgCj6B.js → channel-web-BWEX1FnI.js} +1 -1
- package/dist/{channels-cli-sHtDH37K.js → channels-cli-DHFIXbTT.js} +1 -1
- package/dist/{channels-cli-CgZqXqUm.js → channels-cli-DvkQEBwz.js} +1 -1
- package/dist/chrome-CbBg1ngA.js +4 -0
- package/dist/{cli-DKoe6Ywl.js → cli-C9bsC2UP.js} +1 -1
- package/dist/{cli-DlaHihmr.js → cli-DnMFuBeA.js} +1 -1
- package/dist/{command-registry-FQIQbQAx.js → command-registry-DUOpdtcT.js} +1 -1
- package/dist/{command-registry-BhyY4aXy.js → command-registry-DrRz6Wgg.js} +1 -1
- package/dist/{completion-cli-D86ydD3X.js → completion-cli-BtLeKqh_.js} +1 -1
- package/dist/{completion-cli-H4iKy2_f.js → completion-cli-Cq33pQdJ.js} +1 -1
- package/dist/{completion-cli-CoFRiwNp.js → completion-cli-EbyCUnCP.js} +1 -1
- package/dist/{completion-cli-DF6vmGRs.js → completion-cli-mzQa8oTd.js} +1 -1
- package/dist/{config-cli-D6KAk3vw.js → config-cli-BIQl_nrn.js} +1 -1
- package/dist/{config-cli-9HoPtGDR.js → config-cli-Dw1pr9MW.js} +1 -1
- package/dist/{configure-B_FvthXy.js → configure-B1HJIRSM.js} +1 -1
- package/dist/{configure-CYwCU0Hw.js → configure-BPX5i4at.js} +1 -1
- package/dist/{configure-BgZGeNXf.js → configure-CKm9_xkS.js} +1 -1
- package/dist/{configure-6QCgecON.js → configure-CQPFd8N9.js} +1 -1
- package/dist/{deps-jUQM2eq1.js → deps-DN7fhGiB.js} +1 -1
- package/dist/{doctor-completion-CZrfkBfj.js → doctor-completion-B7JXY8EJ.js} +1 -1
- package/dist/{doctor-completion-BSbAN5p1.js → doctor-completion-BEVC1EV7.js} +1 -1
- package/dist/{embedded-CA0n2tyG.js → embedded-BBM-usEa.js} +7 -7
- package/dist/{embedded-SSuKQ6Yc.js → embedded-CIuP-6Ex.js} +2 -2
- package/dist/entry.js +1 -1
- package/dist/extensionAPI.js +1 -1
- package/dist/{gateway-cli-8SuDvuCq.js → gateway-cli-CvdguqNO.js} +2 -2
- package/dist/{gateway-cli-D5pW1jLs.js → gateway-cli-DvMzpFIF.js} +2 -2
- package/dist/{health-BLW40WUJ.js → health-Bd0YvHPq.js} +1 -1
- package/dist/{health-DqZB_jd8.js → health-CcUquV5P.js} +1 -1
- package/dist/{health-Cggr6c-2.js → health-CoTbsx1p.js} +1 -1
- package/dist/{hooks-cli-BQZjt-Fk.js → hooks-cli-D1mx0_F_.js} +1 -1
- package/dist/{hooks-cli-D5Zt0sN4.js → hooks-cli-Dr0hMOiz.js} +1 -1
- package/dist/index.js +2 -2
- package/dist/llm-slug-generator.js +1 -1
- package/dist/{models-DH9Vrv7O.js → models-D3MukbTO.js} +1 -1
- package/dist/{models-cli-DLZZwy_m.js → models-cli-CBUEjJ_T.js} +1 -1
- package/dist/{models-cli-CAaWi4TX.js → models-cli-nD2MyRO3.js} +1 -1
- package/dist/{models-bp562zNz.js → models-px2EtCBB.js} +1 -1
- package/dist/{onboard-pzmSj6MG.js → onboard-CelRLEbD.js} +1 -1
- package/dist/{onboard-CpFQ-bpz.js → onboard-D_Ja6cJL.js} +1 -1
- package/dist/{onboard-channels-BsMS0Ehd.js → onboard-channels-C5v3gxTE.js} +1 -1
- package/dist/{onboard-channels-D1FMu5M8.js → onboard-channels-CEMtoVzX.js} +1 -1
- package/dist/{onboard-channels-CKWKLbTn.js → onboard-channels-DIvxrZLb.js} +1 -1
- package/dist/{onboard-channels-CqXCWPaQ.js → onboard-channels-pPjt4AF5.js} +1 -1
- package/dist/{onboard-interactive-BAcb1Yd8.js → onboard-interactive-BIVMtUaZ.js} +1 -1
- package/dist/{onboard-interactive-COTt-hGf.js → onboard-interactive-CeQp6fAt.js} +1 -1
- package/dist/{onboard-interactive-B_YG0JwA.js → onboard-interactive-D3YgFz9n.js} +1 -1
- package/dist/{onboard-interactive-BdwTeKJ2.js → onboard-interactive-tVpsWM3V.js} +1 -1
- package/dist/{onboarding-C8IDtM8O.js → onboarding-B9P9Rocf.js} +2 -2
- package/dist/{onboarding-BhMZqtBx.js → onboarding-DXxufSuN.js} +2 -2
- package/dist/{onboarding.finalize-DpyMh92r.js → onboarding.finalize-BJbv33Sa.js} +1 -1
- package/dist/{onboarding.finalize-DEhEHZPV.js → onboarding.finalize-CiIdxWgH.js} +1 -1
- package/dist/{outbound-send-deps-CKOfRpqk.js → outbound-send-deps-DL5n0r7v.js} +1 -1
- package/dist/{plugin-registry-Bi-9AQMd.js → plugin-registry-B5gTbK3m.js} +1 -1
- package/dist/{plugin-registry-nxUQWv6l.js → plugin-registry-CBXZbshG.js} +1 -1
- package/dist/{plugin-registry-BlKyKAq2.js → plugin-registry-DEWbh_9i.js} +1 -1
- package/dist/{plugin-registry-CqGq9jzk.js → plugin-registry-Glc-xriO.js} +1 -1
- package/dist/plugin-sdk/{channel-web-C3UtHX6b.js → channel-web-CW5s6vEZ.js} +1 -1
- package/dist/plugin-sdk/index.js +1 -1
- package/dist/plugin-sdk/{reply-BTKDKB2t.js → reply-pngAtrhW.js} +2 -2
- package/dist/plugin-sdk/{web-CsPSK9U2.js → web-DfrDkFj_.js} +1 -1
- package/dist/{plugins-CUhWH9-E.js → plugins-BJNBD6Si.js} +1 -1
- package/dist/{plugins-B8Lge-oB.js → plugins-BZnMash4.js} +1 -1
- package/dist/{plugins-cli-c36MSKiX.js → plugins-cli-Cv_bwpr4.js} +1 -1
- package/dist/{plugins-cli-CgjC_YvF.js → plugins-cli-DkFN_JgK.js} +1 -1
- package/dist/{program-QMtnfrM_.js → program-DYU1raxm.js} +2 -2
- package/dist/{program-context-BgCNjcCh.js → program-context-D4S-3zNt.js} +1 -1
- package/dist/{prompt-select-styled-CWG9o2CX.js → prompt-select-styled-BhKY5Oj4.js} +1 -1
- package/dist/{prompt-select-styled-m1_NXutn.js → prompt-select-styled-D1StbM6j.js} +1 -1
- package/dist/{provider-auth-helpers-BFCTgzr_.js → provider-auth-helpers-5ZQb3SEz.js} +1 -1
- package/dist/{provider-auth-helpers-D0eiRpeb.js → provider-auth-helpers-Cibq8oDi.js} +1 -1
- package/dist/{provider-dispatcher-Djomkp5i.js → provider-dispatcher-Bwaplzm8.js} +1 -1
- package/dist/{provider-dispatcher-B6kumPDM.js → provider-dispatcher-kL8Yl9XU.js} +1 -1
- package/dist/{push-apns-DalSFp-6.js → push-apns-BXmSvfvx.js} +1 -1
- package/dist/{push-apns-DwSjHMuA.js → push-apns-C9hsLIBU.js} +1 -1
- package/dist/{pw-ai-1DyAPekE.js → pw-ai-BLyUwyRC.js} +1 -1
- package/dist/{register.agent-BZn434eF.js → register.agent-C4x77WJe.js} +1 -1
- package/dist/{register.agent-DNaHcARI.js → register.agent-CbP_v3k5.js} +1 -1
- package/dist/{register.configure-GTH7BPIx.js → register.configure-B-j2lVkz.js} +1 -1
- package/dist/{register.configure-Bflad790.js → register.configure-BsBerk8U.js} +1 -1
- package/dist/{register.maintenance-Dl7P66Jm.js → register.maintenance-B83yzc-P.js} +1 -1
- package/dist/{register.maintenance-B1XK1zeY.js → register.maintenance-WLPWJ7vr.js} +1 -1
- package/dist/{register.message-CJS3PPCy.js → register.message-BVo8xLbS.js} +1 -1
- package/dist/{register.message-CA5LiG16.js → register.message-DZ9zcORn.js} +1 -1
- package/dist/{register.onboard-Bj6wFSzC.js → register.onboard-CWCqKyU7.js} +1 -1
- package/dist/{register.onboard-4y1mzgCn.js → register.onboard-D9mB9MLj.js} +1 -1
- package/dist/{register.setup-Cvk8SB1q.js → register.setup-BMFb9IC4.js} +1 -1
- package/dist/{register.setup-zLIWO_nF.js → register.setup-C22fWTFR.js} +1 -1
- package/dist/{register.status-health-sessions-CjxA4ATI.js → register.status-health-sessions-BqMqFeMA.js} +1 -1
- package/dist/{register.status-health-sessions-CIYKmgKO.js → register.status-health-sessions-C-jqKRZ5.js} +1 -1
- package/dist/{register.subclis-Ua7PkPpv.js → register.subclis-Ceyv8kgc.js} +1 -1
- package/dist/{register.subclis-Ct4QBaKi.js → register.subclis-DxcQwaQg.js} +1 -1
- package/dist/{reply-gZ_yr2mJ.js → reply-BeKidf2F.js} +4 -4
- package/dist/{run-main-Cyc_C0B-.js → run-main-EhlBxGJB.js} +1 -1
- package/dist/{runner-C1sy_uJN.js → runner-P3IfAnSL.js} +3 -3
- package/dist/{server-node-events-CSsH-eIF.js → server-node-events-BZuSkcbo.js} +1 -1
- package/dist/{server-node-events-Bz_Qo5BV.js → server-node-events-CIsEZSfR.js} +1 -1
- package/dist/{session-dirs-fh5kvbyH.js → session-dirs-DH7k5ehu.js} +1 -1
- package/dist/{session-dirs-DVL9vHmq.js → session-dirs-DgwMogyJ.js} +1 -1
- package/dist/{status-sAc6yoa3.js → status-BY0kS_wo.js} +1 -1
- package/dist/{status-SPonEO1J.js → status-B_SXw9W4.js} +1 -1
- package/dist/{status-DZYF4S6_.js → status-BqEzSHhZ.js} +1 -1
- package/dist/{status-ChEjU5un.js → status-Ca-hgLW_.js} +1 -1
- package/dist/{status-CpxCM8BO.js → status-_KIJcQH-.js} +1 -1
- package/dist/{subagent-registry-BHP3_ka8.js → subagent-registry-98yia-RN.js} +4 -4
- package/dist/{subagent-registry-BYK0Wq_w.js → subagent-registry-Ch9dN-TR.js} +1 -1
- package/dist/{subagent-registry-DR5M5QUP.js → subagent-registry-CiYeuaym.js} +1 -1
- package/dist/{tui-Ujq2bTco.js → tui-BIpdEy5i.js} +2 -2
- package/dist/{tui-BsMw6I4Y.js → tui-DeG1am8h.js} +2 -2
- package/dist/{tui-cli-CLYxMYyC.js → tui-cli-3mxSu-O0.js} +1 -1
- package/dist/{tui-cli-BBKMdwDt.js → tui-cli-CXRFHYWv.js} +1 -1
- package/dist/{update-cli-uQLI7RCN.js → update-cli-BYhJHTZ0.js} +1 -1
- package/dist/{update-cli-BKcCNOzz.js → update-cli-DkgHl95y.js} +1 -1
- package/dist/{web-Bkk568P6.js → web--D7qJmx6.js} +1 -1
- package/dist/{web-wR7gzEVJ.js → web-CgypI7gs.js} +1 -1
- package/dist/{web-CGo9DnE4.js → web-DKmwaw7q.js} +1 -1
- package/dist/{web-DktK5vCb.js → web-Dvcfg5Kd.js} +1 -1
- package/extensions/memory-lancedb/package.json +2 -2
- package/package.json +1 -1
- package/dist/chrome-CAuboFG7.js +0 -4
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{_ as expandHomePrefix,g as resolveStateDir,i as isNixMode,l as resolveGatewayLockDir,o as resolveConfigPath,r as STATE_DIR,t as CONFIG_PATH,u as resolveGatewayPort,y as resolveRequiredHomeDir}from"./paths-5FcIFMsj.js";import{B as theme,C as shortenHomePath,D as truncateUtf16Safe,G as getResolvedLoggerSettings,P as setVerbose,R as colorize,U as getChildLogger,W as getLogger,b as resolveUserPath,c as ensureDir,d as isPlainObject,r as clamp,t as CONFIG_DIR,z as isRich}from"./utils-DbaBVFaK.js";import{B as formatXHighModelHint,G as normalizeThinkLevel,K as normalizeUsageDisplay,U as normalizeElevatedLevel,W as normalizeReasoningLevel,Y as supportsXHighThinking,q as normalizeVerboseLevel,z as formatThinkingLevels}from"./embedded-helpers-DHfhLu2W.js";import{$ as normalizeOptionalSessionKey,$n as markGatewaySigusr1RestartHandled,$t as requestNodePairing,Ar as resolveTtsProviderOrder,At as getPluginToolMeta,B as resolveOutboundSessionRoute,Bt as computeBackoff,C as spawnSubagentDirect,Cn as getTotalPendingReplies,Cr as getTtsProvider,Ct as findAgentRole,Dr as resolveTtsAutoMode,Dt as codebaseSearchTool,E as resolveAnnounceTargetFromKey,Er as resolveTtsApiKey,Et as projectKnowledgeTool,F as pruneLegacyStoreKeys,Fr as OPENAI_TTS_VOICES,Gr as setCommandLaneConcurrency,Gt as refreshRemoteBinsForConnectedNodes,Ht as getRemoteSkillEligibility,I as resolveGatewaySessionStoreTarget,J as normalizeHttpWebhookUrl,Jn as runSubagentAnnounceFlow,Jr as startDiagnosticHeartbeat,Jt as setSkillsRemoteRegistry,K as resetDirectoryCache,Kr as waitForActiveTasks,Kt as refreshRemoteNodeBins,L as resolveSessionModelRef,Ln as countActiveDescendantRuns,Lt as handleSlackHttpRequest,M as listSessionsFromStore,Mn as isAbortTrigger,Mr as setTtsProvider,Mt as loadBuilderForceAgentsPlugins,N as loadCombinedSessionStoreForGateway,Nn as stopSubagentsForRequester,Nr as textToSpeech,Or as resolveTtsConfig,Ot as requestHeartbeatNow,P as loadSessionEntry,Pr as OPENAI_TTS_MODELS,Pt as normalizeGroupActivation,Q as normalizeOptionalAgentId,Qn as isGatewaySigusr1RestartExternallyAllowed,Qt as renamePairedNode,Rt as readJsonBodyWithLimit,S as createBuilderForceAgentsTools,Si as resolveInputFileLimits,Sn as createReplyDispatcher,Sr as registerAgentRunContext,St as loadHiredAgentsCached,T as readLatestAssistantReply,Ti as resolveAgentTimeoutMs,Tr as isTtsProviderConfigured,Tt as registerPlatformPersonasAsRoles,U as resolveOutboundTarget,Ur as getTotalQueueSize,Ut as primeRemoteSkillsCache,Vn as listDescendantRunsForRequester,Vr as getActiveTaskCount,Vt as sleepWithAbort,W as resolveSessionDeliveryTarget,Wr as resetAllLanes,Wt as recordRemoteNodeInfo,X as normalizeCronJobPatch,Xn as deferGatewayRestartUntilIdle,Xr as isDiagnosticsEnabled,Xt as listNodePairing,Y as normalizeCronJobCreate,Yn as consumeGatewaySigusr1RestartAuthorization,Yr as stopDiagnosticHeartbeat,Yt as approveNodePairing,Z as inferLegacyName,Zn as emitGatewayRestart,Zr as DEFAULT_HEARTBEAT_ACK_MAX_CHARS,Zt as rejectNodePairing,_ as waitForEmbeddedRunEnd,_i as DEFAULT_INPUT_MAX_REDIRECTS,_r as registerTeamMemoryContextBuilder,_t as globalOrchestrator,a as getCliSessionId,an as resolvePairingPaths,ar as formatRestartSentinelMessage,at as hasLegacyDeliveryHints,b as buildDefaultToolPolicyPipelineSteps,bi as extractImageContentFromSource,br as getAgentRunContext,bt as dispatchToRemoteAgentNode,ci as applyModelOverrideToSessionEntry,cn as writeJsonAtomic,d as normalizeSendPolicy,di as enqueueSystemEvent,dn as getHookType,dr as buildAssignedCapabilityAppend,dt as initApprovalGate,en as updatePairedNodeMetadata,er as scheduleGatewaySigusr1Restart,et as normalizeOptionalText,f as resolveSendPolicy,fi as isSystemEventContextChanged,fn as isExternalHookSession,fr as getLimbicSystemService,ft as resolveApproval,g as getActiveEmbeddedRunCount,gi as DEFAULT_INPUT_IMAGE_MIMES,gn as buildHistoryContextFromEntries,gr as registerKnowledgeLoop,gt as workflowStatusTool,h as abortEmbeddedRun,hi as DEFAULT_INPUT_IMAGE_MAX_BYTES,hr as initSsmMemoryService,ht as gitHistoryTool,i as resolveCronStyleNow,in as pruneExpiredPending,ir as formatDoctorNonInteractiveHint,it as buildDeliveryFromLegacyPayload,j as listAgentsForGateway,jr as setTtsEnabled,k as canonicalizeSpawnedByForAgent,kn as formatZonedTimestamp,kr as resolveTtsPrefsPath,li as applyVerboseOverride,ln as buildSafeExternalPrompt,lr as writeRestartSentinel,lt as applyBrowserProxyPaths,m as runEmbeddedAgent,mr as getSsmMemoryService,mt as agentFleetTool,n as BARE_SESSION_RESET_PROMPT,ni as lookupContextTokens,nn as generatePairingToken,nr as setPreRestartDeferralCheck,nt as normalizeRequiredName,o as setCliSessionId,on as createAsyncLock,ot as stripLegacyDeliveryFields,p as clearSessionQueues,pr as initLimbicSystemService,pt as semanticSearchTool,qr as CommandLane,qt as removeRemoteNodeInfo,rn as verifyPairingToken,rr as consumeRestartSentinel,rt as migrateLegacyCronPayload,s as runCliAgent,sn as readJsonFile,sr as summarizeRestartSentinel,ti as stripHeartbeatToken,tn as verifyNodeToken,tr as setGatewaySigusr1RestartPolicy,tt as normalizePayloadToSystemText,ui as parseVerboseOverride,un as detectSuspiciousPatterns,ur as resolveUserTimezone,ut as persistBrowserProxyFiles,vi as DEFAULT_INPUT_TIMEOUT_MS,vr as clearAgentRunContext,vt as dispatchChunkToRemoteAgentNode,w as resolveRelayTaskModel,wr as isTtsEnabled,wt as getBuiltInAgentRoles,xi as normalizeMimeList,xn as dispatchInboundMessage,xr as onAgentEvent,xt as fetchFleetEntries,y as applyToolPolicyPipeline,yi as extractFileContentFromSource,yr as emitAgentEvent,yt as dispatchResultToRemoteAgentNode,z as ensureOutboundSessionEntry,zn as initSubagentRegistry,zr as runWithModelFallback,zt as requestBodyErrorToText}from"./reply-gZ_yr2mJ.js";import{C as parseAgentSessionKey,S as isSubagentSessionKey,_ as toAgentStoreSessionKey,a as buildAgentMainSessionKey,b as isCronRunSessionKey,c as classifySessionKeyShape,d as normalizeAgentId,f as normalizeMainKey,g as toAgentRequestSessionKey,l as isValidAgentId,n as DEFAULT_ACCOUNT_ID,p as resolveAgentIdFromSessionKey,r as DEFAULT_AGENT_ID,t as AGENT_ID_PATTERN}from"./session-key-EoB0qaG9.js";import{s as matchesSkillFilter,t as resolveBuilderForceAgentsPackageRoot}from"./builderforce-root-D64_sXEi.js";import{c as setConsoleTimestampPrefix,i as defaultRuntime,n as runtimeForLogger,s as setConsoleSubsystemFilter,t as createSubsystemLogger}from"./subsystem-B3TqcCrZ.js";import{C as createInternalHookEvent,S as clearInternalHooks,T as triggerInternalHook,d as getActivePluginRegistry,m as createEmptyPluginRegistry,r as DEFAULT_CHAT_CHANNEL,t as CHANNEL_IDS,w as registerInternalHook}from"./registry-TdK-aV05.js";import{i as logWarn,t as logDebug}from"./logger-Bch0bx9c.js";import{n as runExec,t as runCommandWithTimeout}from"./exec-DdcIjeyn.js";import{A as resolveWorkspaceFilePath,E as isWorkspaceOnboardingCompleted,O as resolveAgentRuntimeDir,S as DEFAULT_USER_FILENAME,_ as DEFAULT_IDENTITY_FILENAME,a as resolveAgentModelFallbacksOverride,b as DEFAULT_SOUL_FILENAME,c as resolveAgentWorkspaceDir,d as resolveSessionAgentId,g as DEFAULT_HEARTBEAT_FILENAME,h as DEFAULT_BOOTSTRAP_FILENAME,i as resolveAgentDir,j as resolveWorkspaceTemplateDir,k as resolveDefaultAgentWorkspaceDir,l as resolveDefaultAgentId,n as listAgentIds,p as DEFAULT_AGENTS_FILENAME,r as resolveAgentConfig,s as resolveAgentSkillsFilter,t as listAgentEntries,v as DEFAULT_MEMORY_ALT_FILENAME,w as ensureAgentWorkspace,x as DEFAULT_TOOLS_FILENAME,y as DEFAULT_MEMORY_FILENAME}from"./agent-scope-DPtjOxzp.js";import{N as resolveOllamaApiBase,Z as canUseToolDecision,a as getModelRefStatus,b as resolveThinkingDefault,cn as DEFAULT_MODEL,et as nativeComplete,f as resolveAllowedModelRef,g as resolveHooksGmailModel,h as resolveDefaultModelForAgent,it as SessionManager,k as resolveFreetokenApiBase,ln as DEFAULT_PROVIDER,m as resolveConfiguredModelRef,o as isCliProvider,rn as normalizeSecretInput,rt as CURRENT_SESSION_VERSION,sn as DEFAULT_CONTEXT_TOKENS,t as buildAllowedModelSet,tn as isPidAlive,v as resolveSubagentConfiguredModelSelection}from"./model-selection-DlYajIzF.js";import{t as normalizeBaseUrl}from"./normalize-base-url-Dz6Za7Ks.js";import{t as formatCliCommand}from"./command-format-Dd7BgZsg.js";import{i as readSharedEnvVar,t as isOfflineMode}from"./env-file-BI2jpOmF.js";import"./boolean-Cn4K2fc9.js";import{n as logAcceptedEnvOption,t as isTruthyEnvValue}from"./env-BHP32i7Q.js";import{C as renderPolicyDirectives,E as resolveEngineById,T as CURRENT_ENGINE_ID,b as coercePolicyGates,i as deriveActivitySummary,n as KNOWLEDGE_DIRS,r as buildKnowledgeMemoryEntry$1}from"./src-CQLQD-1r.js";import{A as applyMergePatch,H as resolveSubagentMaxConcurrent,U as VERSION,V as resolveAgentMaxConcurrent,W as resolveRuntimeServiceVersion,a as readConfigFileSnapshot,c as writeConfigFile,f as validateConfigObjectWithPlugins,i as parseConfigJson5,j as applyLegacyMigrations,n as createConfigIO,o as readConfigFileSnapshotForWrite,p as BuilderForceAgentsSchema,r as loadConfig,s as resolveConfigSnapshotHash,v as sensitive,y as parseDurationMs}from"./io-DhUMGsxN.js";import{s as isTestDefaultMemorySlotDisabled}from"./manifest-registry-CBVaj2md.js";import{t as migrateLegacyConfig}from"./config-lGOyM6Kq.js";import{l as registerUnhandledRejectionHandler}from"./runner-CDpBWK3-.js";import{r as loadModelCatalog}from"./model-catalog-BQUEoIev.js";import{g as collectExplicitAllowlist,x as resolveToolProfilePolicy,y as mergeAlsoAllowPolicy}from"./sandbox-Cq6rH4hg.js";import"./chrome-BW8dGyxs.js";import{i as enableTailscaleServe,n as disableTailscaleServe,o as getTailnetHostname,r as enableTailscaleFunnel,t as disableTailscaleFunnel}from"./tailscale-0ey4P_at.js";import{a as AUTH_RATE_LIMIT_SCOPE_DEVICE_TOKEN,c as safeEqualSecret,i as resolveGatewayAuth,n as authorizeGatewayConnect,o as AUTH_RATE_LIMIT_SCOPE_SHARED_SECRET,r as isLocalDirectRequest,s as createAuthRateLimiter,t as assertGatewayAuthConfigured}from"./auth-C4PxZEj8.js";import{n as pickPrimaryTailnetIPv4,r as pickPrimaryTailnetIPv6}from"./tailnet-B5_J9bgV.js";import{a as isTrustedProxyAddress,d as resolveGatewayClientIp,f as resolveGatewayListenHosts,i as isPrivateOrLoopbackAddress,l as pickPrimaryLanIPv4,n as isLoopbackAddress,p as resolveHostName,r as isLoopbackHost,s as normalizeHostHeader,t as rawDataToString,u as resolveGatewayBindHost}from"./ws-s_ZQMnLb.js";import"./server-context-1YSNvKDs.js";import{d as hasBinary}from"./frontmatter-DpzOtLJz.js";import{i as loadWorkspaceSkillEntries,r as buildWorkspaceSkillSnapshot}from"./skills-vjE49XV9.js";import"./plugin-skills-RFjYtysK.js";import"./routes-DsdK6VOy.js";import"./redact-BT5hARuQ.js";import{a as isErrno,n as formatErrorMessage}from"./errors-BK3rMW8O.js";import"./paths-CejDLFxE.js";import{t as SsrFBlockedError}from"./ssrf-DHJTyOuH.js";import{c as detectMime}from"./image-ops-D7Ex-H05.js";import"./store-Nf9BxXC7.js";import{a as inspectPortUsage,c as formatPortDiagnostics,r as ensurePortAvailable}from"./ports-B-SXoPqJ.js";import{t as movePathToTrash}from"./trash-DlNzpifq.js";import{A as evaluateSessionFreshness,B as resolveMainSessionKey,C as readSessionMessages,D as stripEnvelopeFromMessages,E as resolveSessionTranscriptCandidates,L as canonicalizeMainSessionAlias,M as resolveSessionResetPolicy,R as resolveAgentMainSessionKey,S as capArrayByJsonBytes,U as snapshotSessionOrigin,V as resolveMainSessionKeyFromConfig,a as loadSessionStore,b as archiveFileOnDisk,g as mergeDeliveryContext,m as deliveryContextFromSession,n as parseSessionThreadInfo,rt as cleanStaleLockFiles,t as extractDeliveryInfo,u as updateSessionStore,v as normalizeSessionDeliveryFields,w as readSessionPreviewItemsFromTranscript,x as archiveSessionTranscripts,z as resolveExplicitAgentSessionKey}from"./sessions-Dv212g1O.js";import{f as GATEWAY_CLIENT_CAPS,g as hasGatewayClientCap,h as GATEWAY_CLIENT_NAMES,i as isGatewayMessageChannel,l as normalizeMessageChannel,m as GATEWAY_CLIENT_MODES,n as isDeliverableMessageChannel,p as GATEWAY_CLIENT_IDS,r as isGatewayCliClient,s as isWebchatClient,t as INTERNAL_MESSAGE_CHANNEL}from"./message-channel-BW_q2nVi.js";import{n as listChannelPlugins,r as normalizeChannelId,t as getChannelPlugin}from"./plugins-C0lu7LGS.js";import"./accounts-2InvZDx2.js";import"./accounts-CrKsbGuP.js";import"./accounts-BnsrG5TA.js";import{t as buildChannelAccountBindings}from"./bindings-qYFdqpJ3.js";import"./send-DSwQqUiD.js";import"./send-BGZYkspG.js";import{c as resolveStorePath,i as resolveSessionTranscriptPath,n as resolveSessionFilePath,r as resolveSessionFilePathOptions,s as resolveSessionTranscriptsDirForAgent}from"./paths-DCzWXtSj.js";import{i as normalizeInputProvenance}from"./input-provenance-BlnIdpqS.js";import"./tool-images-CR9Y0R5I.js";import"./tool-display-Dx-rz3CF.js";import{t as fetchWithSsrFGuard}from"./fetch-guard-DxN_CtRp.js";import"./api-key-rotation-BbNoamfM.js";import"./fetch-CMEvVIy8.js";import"./sqlite-BxinAVYp.js";import{n as SILENT_REPLY_TOKEN,r as isSilentReplyText}from"./tokens-Ct4DyfhX.js";import{S as globalPersonaRegistry,_ as isBuilderForceAgentsProject,b as USER_PERSONAS_DIR,n as loadProjectContext,o as updateProjectContextFields,v as resolveBuilderForceAgentsDir}from"./project-context-store-BPhHGfFl.js";import{n as createBrowserRouteDispatcher,r as getMachineDisplayName}from"./with-timeout-DTcvZn3s.js";import{C as getGlobalHookRunner,T as runGlobalGatewayStopSafely,a as normalizeReplyPayloadsForDelivery,t as deliverOutboundPayloads}from"./deliver-CrB451sO.js";import"./send-ZCmcplsV.js";import{a as shouldIncludeHook,i as resolveHookConfig,n as loadWorkspaceHookEntries}from"./workspace-eFrsAV2Q.js";import{a as resolveAgentIdentity,n as createReplyPrefixOptions}from"./reply-prefix-BwtP84WV.js";import{i as resolveMemoryBackendConfig,r as getMemorySearchManager}from"./memory-cli-Dgqoendm.js";import"./manager-pjodgk3H.js";import"./retry-Jis-ZZfm.js";import{$ as validateNodePairRejectParams,A as validateCronStatusParams,At as validateWizardStatusParams,B as validateExecApprovalsGetParams,C as validateConfigSetParams,Ct as validateUpdateRunParams,D as validateCronRemoveParams,Dt as validateWizardCancelParams,E as validateCronListParams,Et as validateWebLoginWaitParams,F as validateDevicePairRemoveParams,Ft as parseSessionLabel,G as validateModelsListParams,H as validateExecApprovalsNodeSetParams,Ht as verifyDeviceSignature,I as validateDeviceTokenRevokeParams,It as buildDeviceAuthPayload,J as validateNodeInvokeParams,K as validateNodeDescribeParams,L as validateDeviceTokenRotateParams,Lt as normalizeDeviceAuthScopes,M as validateDevicePairApproveParams,Mt as ErrorCodes,N as validateDevicePairListParams,Nt as errorShape,O as validateCronRunParams,Ot as validateWizardNextParams,P as validateDevicePairRejectParams,Q as validateNodePairListParams,R as validateExecApprovalRequestParams,S as validateConfigSchemaParams,St as validateTalkModeParams,T as validateCronAddParams,Tt as validateWebLoginStartParams,U as validateExecApprovalsSetParams,V as validateExecApprovalsNodeGetParams,Vt as normalizeDevicePublicKeyBase64Url,W as validateLogsTailParams,X as validateNodeListParams,Y as validateNodeInvokeResultParams,Z as validateNodePairApproveParams,_ as validateChatInjectParams,_t as validateSkillsBinsParams,a as validateAgentWaitParams,at as validateRequestFrame,b as validateConfigGetParams,bt as validateSkillsUpdateParams,c as validateAgentsFilesGetParams,ct as validateSessionsDeleteParams,d as validateAgentsListParams,dt as validateSessionsPatchParams,et as validateNodePairRequestParams,f as validateAgentsUpdateParams,ft as validateSessionsPreviewParams,g as validateChatHistoryParams,gt as validateSessionsUsageParams,h as validateChatAbortParams,ht as validateSessionsUndoParams,i as validateAgentParams,it as validatePushTestParams,j as validateCronUpdateParams,jt as PROTOCOL_VERSION,k as validateCronRunsParams,kt as validateWizardStartParams,l as validateAgentsFilesListParams,lt as validateSessionsForkParams,m as validateChannelsStatusParams,mt as validateSessionsResolveParams,n as formatValidationErrors,nt as validateNodeRenameParams,o as validateAgentsCreateParams,ot as validateSendParams,p as validateChannelsLogoutParams,pt as validateSessionsResetParams,q as validateNodeEventParams,r as validateAgentIdentityParams,rt as validatePollParams,s as validateAgentsDeleteParams,st as validateSessionsCompactParams,t as GatewayClient,tt as validateNodePairVerifyParams,u as validateAgentsFilesSetParams,ut as validateSessionsListParams,v as validateChatSendParams,vt as validateSkillsInstallParams,w as validateConnectParams,wt as validateWakeParams,x as validateConfigPatchParams,xt as validateTalkConfigParams,y as validateConfigApplyParams,yt as validateSkillsStatusParams,z as validateExecApprovalResolveParams,zt as deriveDeviceIdFromPublicKey}from"./client-BxPDO8Ed.js";import{n as callGateway,o as loadGatewayTlsRuntime$1}from"./call-DLeUWFtQ.js";import{a as jsonResult,t as ToolInputError}from"./common-W8GhA4hE.js";import"./chunk-B9aj7NGY.js";import"./markdown-tables-iDNbGky8.js";import"./ir-EgWVNCXR.js";import"./render-CSLaFZoy.js";import"./builderforcellm-syscheck-BpNlQ4Rx.js";import"./send-iQicMwPr.js";import"./outbound-attachment-BR2FQu7J.js";import"./fetch-B6_hd7w9.js";import"./delivery-queue-BZWZDdpJ.js";import{n as normalizePollInput}from"./polls-DbHrteSV.js";import{t as getChannelActivity}from"./channel-activity-GeHNfvd4.js";import"./tables-D5WcKZWq.js";import"./pairing-store-PKyjZas4.js";import{t as formatDocsLink}from"./links-CYRGsVCu.js";import{n as runCommandWithRuntime}from"./cli-utils-BLNnV_WG.js";import{t as formatHelpExamples}from"./help-format-NhTn4dWd.js";import{n as withProgress}from"./progress-OKwbfa23.js";import"./resolve-route-EE2-ObOq.js";import"./replies-BhjI7rPj.js";import{a as registerSkillsChangeListener,i as getSkillsSnapshotVersion,n as bumpSkillsSnapshotVersion}from"./refresh-Cyy0oi_E.js";import{a as resolveSubagentToolPolicy,i as resolveGroupToolPolicy,r as resolveEffectiveToolPolicy,u as listAgentWorkspaceDirs}from"./coding-tools.policy-DQxeoYmD.js";import"./send-C9xXqEqr.js";import{C as normalizeControlUiBasePath,S as buildControlUiAvatarUrl,c as handleReset,w as resolveAssistantAvatarUrl,x as CONTROL_UI_AVATAR_PREFIX}from"./onboard-helpers-DHGeaHZA.js";import"./prompt-style-BwwmGo3-.js";import"./pairing-labels-BpeDWVFP.js";import{a as loadSessionUsageTimeSeries,c as hasNonzeroUsage,n as loadCostUsageSummary,r as loadSessionCostSummary,s as deriveSessionTotalTokens,t as discoverAllSessions}from"./session-cost-usage-BDkGtjt9.js";import{n as formatTokenCount,r as formatUsd}from"./usage-format-BzezFt2J.js";import{t as loadProviderUsageSummary}from"./provider-usage-BqXFLAwn.js";import"./active-listener-DBdxNyOd.js";import{a as mergeExecApprovalsSocketDefaults,c as readExecApprovalsSnapshot,p as saveExecApprovals,r as ensureExecApprovals,s as normalizeExecApprovals,t as DEFAULT_EXEC_APPROVAL_TIMEOUT_MS}from"./exec-approvals-kmxxyvIe.js";import"./nodes-screen-BWDONgPE.js";import{d as savePersonaAssignment,f as initializeBuilderForceAgentsProject,t as appendKnowledgeMemory,u as loadPersonaAssignments}from"./project-context-Dp8w9r_P.js";import{r as startBrowserControlServiceFromConfig,t as createBrowserControlContext}from"./control-service-Bkbx5ybP.js";import{i as parseAbsoluteTimeMs,n as resolveCronStaggerMs,r as resolveDefaultCronStaggerMs,t as normalizeCronStaggerMs}from"./stagger-NaB6u1z1.js";import{n as resolveMessageChannelSelection}from"./channel-selection-BjcuqdFb.js";import"./mamba-state-engine-DPAATSLG.js";import"./transformers-stream-QS2dnQob.js";import{i as onHeartbeatEvent,r as getLastHeartbeatEvent,t as resolveHeartbeatVisibility}from"./heartbeat-visibility-Bd7nwrAb.js";import{n as createOutboundSendDeps,t as createDefaultDeps}from"./deps-jUQM2eq1.js";import{t as ensureBuilderForceAgentsCliOnPath}from"./path-env-CbxzWzgp.js";import"./runtime-guard-BiPTd1ED.js";import{t as forceFreePortAndWait}from"./ports-DHj46r2E.js";import{t as buildChannelUiCatalog}from"./catalog-BIdILD-k.js";import{t as buildWorkspaceSkillStatus}from"./skills-status-U_k3Ca5B.js";import{n as DEFAULT_GATEWAY_HTTP_TOOL_DENY}from"./dangerous-tools-D_AaRzHd.js";import{n as inheritOptionFromParent}from"./command-options-BrcCiCUA.js";import{t as WizardCancelledError}from"./prompts-Yv4eTTSo.js";import{t as resolveChannelDefaultAccountId}from"./helpers-_XD3UAOf.js";import{t as applyPluginAutoEnable}from"./plugin-auto-enable-CWK7KiRF.js";import"./install-safe-path-BUT0oL1h.js";import"./skill-scanner-CN9z0hSY.js";import{t as buildChannelAccountSnapshot}from"./status-B7Z3cqiO.js";import"./channels-status-issues-B-9_0W90.js";import"./daemon-runtime-CWFj-hSG.js";import"./systemd-CTHIdkg9.js";import"./service-BXrSjb3e.js";import"./lifecycle-core-BUp08YyP.js";import"./diagnostics-Bsqm-Flj.js";import{t as parsePort$1}from"./parse-port-BFNa0WrG.js";import{n as addGatewayServiceCommands}from"./daemon-cli-CjCweBX-.js";import"./table-BKeTpiIp.js";import{n as resolveWideAreaDiscoveryDomain,r as writeWideAreaGatewayZone}from"./widearea-dns-Dc2di-mD.js";import{i as toOptionString,n as extractGatewayMiskeys,r as maybeExplainGatewayServiceStop,t as describeUnknownError}from"./shared-DHkdoNQu.js";import{c as probeGateway,o as isNodeCommandAllowed,s as resolveNodeCommandAllowlist}from"./audit-72BjkOp9.js";import{t as discoverGatewayBeacons}from"./bonjour-discovery-BpFETe_g.js";import{n as getStatusSummary,r as pickGatewaySelfPresence}from"./status-DZYF4S6_.js";import{c as startHeartbeatRunner,i as styleHealthChannelLine,n as getHealthSnapshot,o as runHeartbeatOnce,s as setHeartbeatsEnabled,t as formatHealthChannelLines}from"./health-Cggr6c-2.js";import{a as resolveControlUiRootSync,i as resolveControlUiRootOverrideSync,t as ensureControlUiAssetsBuilt}from"./control-ui-assets-CAmSpVpE.js";import{h as normalizeUpdateChannel,l as DEFAULT_PACKAGE_CHANNEL,n as compareSemverStrings,o as resolveNpmChannelTag,t as checkUpdateStatus}from"./update-check-CwmSkavG.js";import{t as runOnboardingWizard}from"./onboarding-BhMZqtBx.js";import{a as sendApnsAlert,c as parseMessageWithAttachments,d as shouldLogWs,f as summarizeAgentEventForWsLog,i as resolveApnsAuthConfigFromEnv,l as formatForLog,n as normalizeApnsEnvironment,o as sendApnsBackgroundWake,p as setGatewayWsLogStyle,s as normalizeRpcAttachmentsToChatAttachments,t as loadApnsRegistration,u as logWs}from"./push-apns-DalSFp-6.js";import{T as resolveGmailHookRuntimeConfig,_ as buildGogWatchServeArgs,i as ensureTailscaleEndpoint,v as buildGogWatchStartArgs}from"./gmail-setup-utils-C2pbrI7I.js";import{t as createOutboundSendDeps$1}from"./outbound-send-deps-DS_1j6Dm.js";import{a as pruneAgentConfig,i as loadAgentIdentity,r as findAgentEntryIndex,s as loadAgentIdentityFromWorkspace,t as applyAgentConfig}from"./agents.config-D4ThL3Cg.js";import{i as resolveAgentOutboundTarget,r as resolveAgentDeliveryPlan,t as agentCommand}from"./agent-CxhUn-aN.js";import"./dm-policy-shared-B5SWfgvG.js";import"./node-service-C41a54YN.js";import"./status.update-BvLaYyY5.js";import{n as validateSystemRunCommandConsistency,t as formatExecCommand}from"./system-run-command-IGKiGgdN.js";import{t as installSkill}from"./skills-install-DXm4y2QA.js";import{n as runGatewayUpdate,t as resolveAgentSessionDirs}from"./session-dirs-DVL9vHmq.js";import{n as syncBuilderForceAgentsDirectoryOnStartup,t as syncBuilderForceAgentsDirectory}from"./builderforce-directory-sync-DJdx8s3l.js";import{n as mergeBuilderforceContext,t as buildLocalMachineProfile}from"./builderforce-context-xdRubwNz.js";import{a as emitWorkflowEnd,c as initTelemetry,i as emitTaskStart,l as setRelayHook,o as emitWorkflowStart,r as emitTaskEnd}from"./workflow-telemetry-CcOSOvct.js";import{fileURLToPath,pathToFileURL}from"node:url";import*as fsSync from"node:fs";import fs,{constants}from"node:fs";import os from"node:os";import path,{dirname,join,relative,sep}from"node:path";import crypto,{createHash,randomUUID}from"node:crypto";import JSON5 from"json5";import chalk from"chalk";import fs$1,{mkdir,readFile,readdir,writeFile}from"node:fs/promises";import{execFile,spawn,spawnSync}from"node:child_process";import{promisify}from"node:util";import{z}from"zod";import net from"node:net";import{createServer}from"node:http";import{createServer as createServer$1}from"node:https";import{WebSocket as WebSocket$1,WebSocketServer}from"ws";import{Buffer as Buffer$1}from"node:buffer";import{neutralLimbicState}from"@seanhogg/builderforce-memory-engine/limbic";import{Type}from"@sinclair/typebox";import chokidar from"chokidar";import{EventEmitter}from"node:events";import{Cron}from"croner";import{query}from"@anthropic-ai/claude-agent-sdk";function parsePort(value){if(!value)return;let parsed=Number.parseInt(value,10);if(!(!Number.isFinite(parsed)||parsed<=0))return parsed}function parseSshConfigOutput(output){let result={identityFiles:[]},lines=output.split(`
|
|
1
|
+
import{_ as expandHomePrefix,g as resolveStateDir,i as isNixMode,l as resolveGatewayLockDir,o as resolveConfigPath,r as STATE_DIR,t as CONFIG_PATH,u as resolveGatewayPort,y as resolveRequiredHomeDir}from"./paths-5FcIFMsj.js";import{B as theme,C as shortenHomePath,D as truncateUtf16Safe,G as getResolvedLoggerSettings,P as setVerbose,R as colorize,U as getChildLogger,W as getLogger,b as resolveUserPath,c as ensureDir,d as isPlainObject,r as clamp,t as CONFIG_DIR,z as isRich}from"./utils-DbaBVFaK.js";import{B as formatXHighModelHint,G as normalizeThinkLevel,K as normalizeUsageDisplay,U as normalizeElevatedLevel,W as normalizeReasoningLevel,Y as supportsXHighThinking,q as normalizeVerboseLevel,z as formatThinkingLevels}from"./embedded-helpers-DHfhLu2W.js";import{$ as normalizeOptionalSessionKey,$n as markGatewaySigusr1RestartHandled,$t as requestNodePairing,Ar as resolveTtsProviderOrder,At as getPluginToolMeta,B as resolveOutboundSessionRoute,Bt as computeBackoff,C as spawnSubagentDirect,Cn as getTotalPendingReplies,Cr as getTtsProvider,Ct as findAgentRole,Dr as resolveTtsAutoMode,Dt as codebaseSearchTool,E as resolveAnnounceTargetFromKey,Er as resolveTtsApiKey,Et as projectKnowledgeTool,F as pruneLegacyStoreKeys,Fr as OPENAI_TTS_VOICES,Gr as setCommandLaneConcurrency,Gt as refreshRemoteBinsForConnectedNodes,Ht as getRemoteSkillEligibility,I as resolveGatewaySessionStoreTarget,J as normalizeHttpWebhookUrl,Jn as runSubagentAnnounceFlow,Jr as startDiagnosticHeartbeat,Jt as setSkillsRemoteRegistry,K as resetDirectoryCache,Kr as waitForActiveTasks,Kt as refreshRemoteNodeBins,L as resolveSessionModelRef,Ln as countActiveDescendantRuns,Lt as handleSlackHttpRequest,M as listSessionsFromStore,Mn as isAbortTrigger,Mr as setTtsProvider,Mt as loadBuilderForceAgentsPlugins,N as loadCombinedSessionStoreForGateway,Nn as stopSubagentsForRequester,Nr as textToSpeech,Or as resolveTtsConfig,Ot as requestHeartbeatNow,P as loadSessionEntry,Pr as OPENAI_TTS_MODELS,Pt as normalizeGroupActivation,Q as normalizeOptionalAgentId,Qn as isGatewaySigusr1RestartExternallyAllowed,Qt as renamePairedNode,Rt as readJsonBodyWithLimit,S as createBuilderForceAgentsTools,Si as resolveInputFileLimits,Sn as createReplyDispatcher,Sr as registerAgentRunContext,St as loadHiredAgentsCached,T as readLatestAssistantReply,Ti as resolveAgentTimeoutMs,Tr as isTtsProviderConfigured,Tt as registerPlatformPersonasAsRoles,U as resolveOutboundTarget,Ur as getTotalQueueSize,Ut as primeRemoteSkillsCache,Vn as listDescendantRunsForRequester,Vr as getActiveTaskCount,Vt as sleepWithAbort,W as resolveSessionDeliveryTarget,Wr as resetAllLanes,Wt as recordRemoteNodeInfo,X as normalizeCronJobPatch,Xn as deferGatewayRestartUntilIdle,Xr as isDiagnosticsEnabled,Xt as listNodePairing,Y as normalizeCronJobCreate,Yn as consumeGatewaySigusr1RestartAuthorization,Yr as stopDiagnosticHeartbeat,Yt as approveNodePairing,Z as inferLegacyName,Zn as emitGatewayRestart,Zr as DEFAULT_HEARTBEAT_ACK_MAX_CHARS,Zt as rejectNodePairing,_ as waitForEmbeddedRunEnd,_i as DEFAULT_INPUT_MAX_REDIRECTS,_r as registerTeamMemoryContextBuilder,_t as globalOrchestrator,a as getCliSessionId,an as resolvePairingPaths,ar as formatRestartSentinelMessage,at as hasLegacyDeliveryHints,b as buildDefaultToolPolicyPipelineSteps,bi as extractImageContentFromSource,br as getAgentRunContext,bt as dispatchToRemoteAgentNode,ci as applyModelOverrideToSessionEntry,cn as writeJsonAtomic,d as normalizeSendPolicy,di as enqueueSystemEvent,dn as getHookType,dr as buildAssignedCapabilityAppend,dt as initApprovalGate,en as updatePairedNodeMetadata,er as scheduleGatewaySigusr1Restart,et as normalizeOptionalText,f as resolveSendPolicy,fi as isSystemEventContextChanged,fn as isExternalHookSession,fr as getLimbicSystemService,ft as resolveApproval,g as getActiveEmbeddedRunCount,gi as DEFAULT_INPUT_IMAGE_MIMES,gn as buildHistoryContextFromEntries,gr as registerKnowledgeLoop,gt as workflowStatusTool,h as abortEmbeddedRun,hi as DEFAULT_INPUT_IMAGE_MAX_BYTES,hr as initSsmMemoryService,ht as gitHistoryTool,i as resolveCronStyleNow,in as pruneExpiredPending,ir as formatDoctorNonInteractiveHint,it as buildDeliveryFromLegacyPayload,j as listAgentsForGateway,jr as setTtsEnabled,k as canonicalizeSpawnedByForAgent,kn as formatZonedTimestamp,kr as resolveTtsPrefsPath,li as applyVerboseOverride,ln as buildSafeExternalPrompt,lr as writeRestartSentinel,lt as applyBrowserProxyPaths,m as runEmbeddedAgent,mr as getSsmMemoryService,mt as agentFleetTool,n as BARE_SESSION_RESET_PROMPT,ni as lookupContextTokens,nn as generatePairingToken,nr as setPreRestartDeferralCheck,nt as normalizeRequiredName,o as setCliSessionId,on as createAsyncLock,ot as stripLegacyDeliveryFields,p as clearSessionQueues,pr as initLimbicSystemService,pt as semanticSearchTool,qr as CommandLane,qt as removeRemoteNodeInfo,rn as verifyPairingToken,rr as consumeRestartSentinel,rt as migrateLegacyCronPayload,s as runCliAgent,sn as readJsonFile,sr as summarizeRestartSentinel,ti as stripHeartbeatToken,tn as verifyNodeToken,tr as setGatewaySigusr1RestartPolicy,tt as normalizePayloadToSystemText,ui as parseVerboseOverride,un as detectSuspiciousPatterns,ur as resolveUserTimezone,ut as persistBrowserProxyFiles,vi as DEFAULT_INPUT_TIMEOUT_MS,vr as clearAgentRunContext,vt as dispatchChunkToRemoteAgentNode,w as resolveRelayTaskModel,wr as isTtsEnabled,wt as getBuiltInAgentRoles,xi as normalizeMimeList,xn as dispatchInboundMessage,xr as onAgentEvent,xt as fetchFleetEntries,y as applyToolPolicyPipeline,yi as extractFileContentFromSource,yr as emitAgentEvent,yt as dispatchResultToRemoteAgentNode,z as ensureOutboundSessionEntry,zn as initSubagentRegistry,zr as runWithModelFallback,zt as requestBodyErrorToText}from"./reply-BeKidf2F.js";import{C as parseAgentSessionKey,S as isSubagentSessionKey,_ as toAgentStoreSessionKey,a as buildAgentMainSessionKey,b as isCronRunSessionKey,c as classifySessionKeyShape,d as normalizeAgentId,f as normalizeMainKey,g as toAgentRequestSessionKey,l as isValidAgentId,n as DEFAULT_ACCOUNT_ID,p as resolveAgentIdFromSessionKey,r as DEFAULT_AGENT_ID,t as AGENT_ID_PATTERN}from"./session-key-EoB0qaG9.js";import{s as matchesSkillFilter,t as resolveBuilderForceAgentsPackageRoot}from"./builderforce-root-D64_sXEi.js";import{c as setConsoleTimestampPrefix,i as defaultRuntime,n as runtimeForLogger,s as setConsoleSubsystemFilter,t as createSubsystemLogger}from"./subsystem-B3TqcCrZ.js";import{C as createInternalHookEvent,S as clearInternalHooks,T as triggerInternalHook,d as getActivePluginRegistry,m as createEmptyPluginRegistry,r as DEFAULT_CHAT_CHANNEL,t as CHANNEL_IDS,w as registerInternalHook}from"./registry-TdK-aV05.js";import{i as logWarn,t as logDebug}from"./logger-Bch0bx9c.js";import{n as runExec,t as runCommandWithTimeout}from"./exec-DdcIjeyn.js";import{A as resolveWorkspaceFilePath,E as isWorkspaceOnboardingCompleted,O as resolveAgentRuntimeDir,S as DEFAULT_USER_FILENAME,_ as DEFAULT_IDENTITY_FILENAME,a as resolveAgentModelFallbacksOverride,b as DEFAULT_SOUL_FILENAME,c as resolveAgentWorkspaceDir,d as resolveSessionAgentId,g as DEFAULT_HEARTBEAT_FILENAME,h as DEFAULT_BOOTSTRAP_FILENAME,i as resolveAgentDir,j as resolveWorkspaceTemplateDir,k as resolveDefaultAgentWorkspaceDir,l as resolveDefaultAgentId,n as listAgentIds,p as DEFAULT_AGENTS_FILENAME,r as resolveAgentConfig,s as resolveAgentSkillsFilter,t as listAgentEntries,v as DEFAULT_MEMORY_ALT_FILENAME,w as ensureAgentWorkspace,x as DEFAULT_TOOLS_FILENAME,y as DEFAULT_MEMORY_FILENAME}from"./agent-scope-DPtjOxzp.js";import{N as resolveOllamaApiBase,Z as canUseToolDecision,a as getModelRefStatus,b as resolveThinkingDefault,cn as DEFAULT_MODEL,et as nativeComplete,f as resolveAllowedModelRef,g as resolveHooksGmailModel,h as resolveDefaultModelForAgent,it as SessionManager,k as resolveFreetokenApiBase,ln as DEFAULT_PROVIDER,m as resolveConfiguredModelRef,o as isCliProvider,rn as normalizeSecretInput,rt as CURRENT_SESSION_VERSION,sn as DEFAULT_CONTEXT_TOKENS,t as buildAllowedModelSet,tn as isPidAlive,v as resolveSubagentConfiguredModelSelection}from"./model-selection-DlYajIzF.js";import{t as normalizeBaseUrl}from"./normalize-base-url-Dz6Za7Ks.js";import{t as formatCliCommand}from"./command-format-Dd7BgZsg.js";import{i as readSharedEnvVar,t as isOfflineMode}from"./env-file-BI2jpOmF.js";import"./boolean-Cn4K2fc9.js";import{n as logAcceptedEnvOption,t as isTruthyEnvValue}from"./env-BHP32i7Q.js";import{C as renderPolicyDirectives,E as resolveEngineById,T as CURRENT_ENGINE_ID,b as coercePolicyGates,i as deriveActivitySummary,n as KNOWLEDGE_DIRS,r as buildKnowledgeMemoryEntry$1}from"./src-CQLQD-1r.js";import{A as applyMergePatch,H as resolveSubagentMaxConcurrent,U as VERSION,V as resolveAgentMaxConcurrent,W as resolveRuntimeServiceVersion,a as readConfigFileSnapshot,c as writeConfigFile,f as validateConfigObjectWithPlugins,i as parseConfigJson5,j as applyLegacyMigrations,n as createConfigIO,o as readConfigFileSnapshotForWrite,p as BuilderForceAgentsSchema,r as loadConfig,s as resolveConfigSnapshotHash,v as sensitive,y as parseDurationMs}from"./io-DhUMGsxN.js";import{s as isTestDefaultMemorySlotDisabled}from"./manifest-registry-CBVaj2md.js";import{t as migrateLegacyConfig}from"./config-lGOyM6Kq.js";import{l as registerUnhandledRejectionHandler}from"./runner-CDpBWK3-.js";import{r as loadModelCatalog}from"./model-catalog-BQUEoIev.js";import{g as collectExplicitAllowlist,x as resolveToolProfilePolicy,y as mergeAlsoAllowPolicy}from"./sandbox-Cq6rH4hg.js";import"./chrome-BW8dGyxs.js";import{i as enableTailscaleServe,n as disableTailscaleServe,o as getTailnetHostname,r as enableTailscaleFunnel,t as disableTailscaleFunnel}from"./tailscale-0ey4P_at.js";import{a as AUTH_RATE_LIMIT_SCOPE_DEVICE_TOKEN,c as safeEqualSecret,i as resolveGatewayAuth,n as authorizeGatewayConnect,o as AUTH_RATE_LIMIT_SCOPE_SHARED_SECRET,r as isLocalDirectRequest,s as createAuthRateLimiter,t as assertGatewayAuthConfigured}from"./auth-C4PxZEj8.js";import{n as pickPrimaryTailnetIPv4,r as pickPrimaryTailnetIPv6}from"./tailnet-B5_J9bgV.js";import{a as isTrustedProxyAddress,d as resolveGatewayClientIp,f as resolveGatewayListenHosts,i as isPrivateOrLoopbackAddress,l as pickPrimaryLanIPv4,n as isLoopbackAddress,p as resolveHostName,r as isLoopbackHost,s as normalizeHostHeader,t as rawDataToString,u as resolveGatewayBindHost}from"./ws-s_ZQMnLb.js";import"./server-context-1YSNvKDs.js";import{d as hasBinary}from"./frontmatter-DpzOtLJz.js";import{i as loadWorkspaceSkillEntries,r as buildWorkspaceSkillSnapshot}from"./skills-vjE49XV9.js";import"./plugin-skills-RFjYtysK.js";import"./routes-DsdK6VOy.js";import"./redact-BT5hARuQ.js";import{a as isErrno,n as formatErrorMessage}from"./errors-BK3rMW8O.js";import"./paths-CejDLFxE.js";import{t as SsrFBlockedError}from"./ssrf-DHJTyOuH.js";import{c as detectMime}from"./image-ops-D7Ex-H05.js";import"./store-Nf9BxXC7.js";import{a as inspectPortUsage,c as formatPortDiagnostics,r as ensurePortAvailable}from"./ports-B-SXoPqJ.js";import{t as movePathToTrash}from"./trash-DlNzpifq.js";import{A as evaluateSessionFreshness,B as resolveMainSessionKey,C as readSessionMessages,D as stripEnvelopeFromMessages,E as resolveSessionTranscriptCandidates,L as canonicalizeMainSessionAlias,M as resolveSessionResetPolicy,R as resolveAgentMainSessionKey,S as capArrayByJsonBytes,U as snapshotSessionOrigin,V as resolveMainSessionKeyFromConfig,a as loadSessionStore,b as archiveFileOnDisk,g as mergeDeliveryContext,m as deliveryContextFromSession,n as parseSessionThreadInfo,rt as cleanStaleLockFiles,t as extractDeliveryInfo,u as updateSessionStore,v as normalizeSessionDeliveryFields,w as readSessionPreviewItemsFromTranscript,x as archiveSessionTranscripts,z as resolveExplicitAgentSessionKey}from"./sessions-Dv212g1O.js";import{f as GATEWAY_CLIENT_CAPS,g as hasGatewayClientCap,h as GATEWAY_CLIENT_NAMES,i as isGatewayMessageChannel,l as normalizeMessageChannel,m as GATEWAY_CLIENT_MODES,n as isDeliverableMessageChannel,p as GATEWAY_CLIENT_IDS,r as isGatewayCliClient,s as isWebchatClient,t as INTERNAL_MESSAGE_CHANNEL}from"./message-channel-BW_q2nVi.js";import{n as listChannelPlugins,r as normalizeChannelId,t as getChannelPlugin}from"./plugins-C0lu7LGS.js";import"./accounts-2InvZDx2.js";import"./accounts-CrKsbGuP.js";import"./accounts-BnsrG5TA.js";import{t as buildChannelAccountBindings}from"./bindings-qYFdqpJ3.js";import"./send-DSwQqUiD.js";import"./send-BGZYkspG.js";import{c as resolveStorePath,i as resolveSessionTranscriptPath,n as resolveSessionFilePath,r as resolveSessionFilePathOptions,s as resolveSessionTranscriptsDirForAgent}from"./paths-DCzWXtSj.js";import{i as normalizeInputProvenance}from"./input-provenance-BlnIdpqS.js";import"./tool-images-CR9Y0R5I.js";import"./tool-display-Dx-rz3CF.js";import{t as fetchWithSsrFGuard}from"./fetch-guard-DxN_CtRp.js";import"./api-key-rotation-BbNoamfM.js";import"./fetch-CMEvVIy8.js";import"./sqlite-BxinAVYp.js";import{n as SILENT_REPLY_TOKEN,r as isSilentReplyText}from"./tokens-Ct4DyfhX.js";import{S as globalPersonaRegistry,_ as isBuilderForceAgentsProject,b as USER_PERSONAS_DIR,n as loadProjectContext,o as updateProjectContextFields,v as resolveBuilderForceAgentsDir}from"./project-context-store-BPhHGfFl.js";import{n as createBrowserRouteDispatcher,r as getMachineDisplayName}from"./with-timeout-DTcvZn3s.js";import{C as getGlobalHookRunner,T as runGlobalGatewayStopSafely,a as normalizeReplyPayloadsForDelivery,t as deliverOutboundPayloads}from"./deliver-CrB451sO.js";import"./send-ZCmcplsV.js";import{a as shouldIncludeHook,i as resolveHookConfig,n as loadWorkspaceHookEntries}from"./workspace-eFrsAV2Q.js";import{a as resolveAgentIdentity,n as createReplyPrefixOptions}from"./reply-prefix-BwtP84WV.js";import{i as resolveMemoryBackendConfig,r as getMemorySearchManager}from"./memory-cli-Dgqoendm.js";import"./manager-pjodgk3H.js";import"./retry-Jis-ZZfm.js";import{$ as validateNodePairRejectParams,A as validateCronStatusParams,At as validateWizardStatusParams,B as validateExecApprovalsGetParams,C as validateConfigSetParams,Ct as validateUpdateRunParams,D as validateCronRemoveParams,Dt as validateWizardCancelParams,E as validateCronListParams,Et as validateWebLoginWaitParams,F as validateDevicePairRemoveParams,Ft as parseSessionLabel,G as validateModelsListParams,H as validateExecApprovalsNodeSetParams,Ht as verifyDeviceSignature,I as validateDeviceTokenRevokeParams,It as buildDeviceAuthPayload,J as validateNodeInvokeParams,K as validateNodeDescribeParams,L as validateDeviceTokenRotateParams,Lt as normalizeDeviceAuthScopes,M as validateDevicePairApproveParams,Mt as ErrorCodes,N as validateDevicePairListParams,Nt as errorShape,O as validateCronRunParams,Ot as validateWizardNextParams,P as validateDevicePairRejectParams,Q as validateNodePairListParams,R as validateExecApprovalRequestParams,S as validateConfigSchemaParams,St as validateTalkModeParams,T as validateCronAddParams,Tt as validateWebLoginStartParams,U as validateExecApprovalsSetParams,V as validateExecApprovalsNodeGetParams,Vt as normalizeDevicePublicKeyBase64Url,W as validateLogsTailParams,X as validateNodeListParams,Y as validateNodeInvokeResultParams,Z as validateNodePairApproveParams,_ as validateChatInjectParams,_t as validateSkillsBinsParams,a as validateAgentWaitParams,at as validateRequestFrame,b as validateConfigGetParams,bt as validateSkillsUpdateParams,c as validateAgentsFilesGetParams,ct as validateSessionsDeleteParams,d as validateAgentsListParams,dt as validateSessionsPatchParams,et as validateNodePairRequestParams,f as validateAgentsUpdateParams,ft as validateSessionsPreviewParams,g as validateChatHistoryParams,gt as validateSessionsUsageParams,h as validateChatAbortParams,ht as validateSessionsUndoParams,i as validateAgentParams,it as validatePushTestParams,j as validateCronUpdateParams,jt as PROTOCOL_VERSION,k as validateCronRunsParams,kt as validateWizardStartParams,l as validateAgentsFilesListParams,lt as validateSessionsForkParams,m as validateChannelsStatusParams,mt as validateSessionsResolveParams,n as formatValidationErrors,nt as validateNodeRenameParams,o as validateAgentsCreateParams,ot as validateSendParams,p as validateChannelsLogoutParams,pt as validateSessionsResetParams,q as validateNodeEventParams,r as validateAgentIdentityParams,rt as validatePollParams,s as validateAgentsDeleteParams,st as validateSessionsCompactParams,t as GatewayClient,tt as validateNodePairVerifyParams,u as validateAgentsFilesSetParams,ut as validateSessionsListParams,v as validateChatSendParams,vt as validateSkillsInstallParams,w as validateConnectParams,wt as validateWakeParams,x as validateConfigPatchParams,xt as validateTalkConfigParams,y as validateConfigApplyParams,yt as validateSkillsStatusParams,z as validateExecApprovalResolveParams,zt as deriveDeviceIdFromPublicKey}from"./client-BxPDO8Ed.js";import{n as callGateway,o as loadGatewayTlsRuntime$1}from"./call-DLeUWFtQ.js";import{a as jsonResult,t as ToolInputError}from"./common-W8GhA4hE.js";import"./chunk-B9aj7NGY.js";import"./markdown-tables-iDNbGky8.js";import"./ir-EgWVNCXR.js";import"./render-CSLaFZoy.js";import"./builderforcellm-syscheck-BpNlQ4Rx.js";import"./send-iQicMwPr.js";import"./outbound-attachment-BR2FQu7J.js";import"./fetch-B6_hd7w9.js";import"./delivery-queue-BZWZDdpJ.js";import{n as normalizePollInput}from"./polls-DbHrteSV.js";import{t as getChannelActivity}from"./channel-activity-GeHNfvd4.js";import"./tables-D5WcKZWq.js";import"./pairing-store-PKyjZas4.js";import{t as formatDocsLink}from"./links-CYRGsVCu.js";import{n as runCommandWithRuntime}from"./cli-utils-BLNnV_WG.js";import{t as formatHelpExamples}from"./help-format-NhTn4dWd.js";import{n as withProgress}from"./progress-OKwbfa23.js";import"./resolve-route-EE2-ObOq.js";import"./replies-BhjI7rPj.js";import{a as registerSkillsChangeListener,i as getSkillsSnapshotVersion,n as bumpSkillsSnapshotVersion}from"./refresh-Cyy0oi_E.js";import{a as resolveSubagentToolPolicy,i as resolveGroupToolPolicy,r as resolveEffectiveToolPolicy,u as listAgentWorkspaceDirs}from"./coding-tools.policy-DQxeoYmD.js";import"./send-C9xXqEqr.js";import{C as normalizeControlUiBasePath,S as buildControlUiAvatarUrl,c as handleReset,w as resolveAssistantAvatarUrl,x as CONTROL_UI_AVATAR_PREFIX}from"./onboard-helpers-DHGeaHZA.js";import"./prompt-style-BwwmGo3-.js";import"./pairing-labels-BpeDWVFP.js";import{a as loadSessionUsageTimeSeries,c as hasNonzeroUsage,n as loadCostUsageSummary,r as loadSessionCostSummary,s as deriveSessionTotalTokens,t as discoverAllSessions}from"./session-cost-usage-BDkGtjt9.js";import{n as formatTokenCount,r as formatUsd}from"./usage-format-BzezFt2J.js";import{t as loadProviderUsageSummary}from"./provider-usage-BqXFLAwn.js";import"./active-listener-DBdxNyOd.js";import{a as mergeExecApprovalsSocketDefaults,c as readExecApprovalsSnapshot,p as saveExecApprovals,r as ensureExecApprovals,s as normalizeExecApprovals,t as DEFAULT_EXEC_APPROVAL_TIMEOUT_MS}from"./exec-approvals-kmxxyvIe.js";import"./nodes-screen-BWDONgPE.js";import{d as savePersonaAssignment,f as initializeBuilderForceAgentsProject,t as appendKnowledgeMemory,u as loadPersonaAssignments}from"./project-context-Dp8w9r_P.js";import{r as startBrowserControlServiceFromConfig,t as createBrowserControlContext}from"./control-service-Bkbx5ybP.js";import{i as parseAbsoluteTimeMs,n as resolveCronStaggerMs,r as resolveDefaultCronStaggerMs,t as normalizeCronStaggerMs}from"./stagger-NaB6u1z1.js";import{n as resolveMessageChannelSelection}from"./channel-selection-BjcuqdFb.js";import"./mamba-state-engine-DPAATSLG.js";import"./transformers-stream-QS2dnQob.js";import{i as onHeartbeatEvent,r as getLastHeartbeatEvent,t as resolveHeartbeatVisibility}from"./heartbeat-visibility-Bd7nwrAb.js";import{n as createOutboundSendDeps,t as createDefaultDeps}from"./deps-DN7fhGiB.js";import{t as ensureBuilderForceAgentsCliOnPath}from"./path-env-CbxzWzgp.js";import"./runtime-guard-BiPTd1ED.js";import{t as forceFreePortAndWait}from"./ports-DHj46r2E.js";import{t as buildChannelUiCatalog}from"./catalog-BIdILD-k.js";import{t as buildWorkspaceSkillStatus}from"./skills-status-U_k3Ca5B.js";import{n as DEFAULT_GATEWAY_HTTP_TOOL_DENY}from"./dangerous-tools-D_AaRzHd.js";import{n as inheritOptionFromParent}from"./command-options-BrcCiCUA.js";import{t as WizardCancelledError}from"./prompts-Yv4eTTSo.js";import{t as resolveChannelDefaultAccountId}from"./helpers-_XD3UAOf.js";import{t as applyPluginAutoEnable}from"./plugin-auto-enable-CWK7KiRF.js";import"./install-safe-path-BUT0oL1h.js";import"./skill-scanner-CN9z0hSY.js";import{t as buildChannelAccountSnapshot}from"./status-B7Z3cqiO.js";import"./channels-status-issues-B-9_0W90.js";import"./daemon-runtime-CWFj-hSG.js";import"./systemd-CTHIdkg9.js";import"./service-BXrSjb3e.js";import"./lifecycle-core-BUp08YyP.js";import"./diagnostics-Bsqm-Flj.js";import{t as parsePort$1}from"./parse-port-BFNa0WrG.js";import{n as addGatewayServiceCommands}from"./daemon-cli-CjCweBX-.js";import"./table-BKeTpiIp.js";import{n as resolveWideAreaDiscoveryDomain,r as writeWideAreaGatewayZone}from"./widearea-dns-Dc2di-mD.js";import{i as toOptionString,n as extractGatewayMiskeys,r as maybeExplainGatewayServiceStop,t as describeUnknownError}from"./shared-DHkdoNQu.js";import{c as probeGateway,o as isNodeCommandAllowed,s as resolveNodeCommandAllowlist}from"./audit-72BjkOp9.js";import{t as discoverGatewayBeacons}from"./bonjour-discovery-BpFETe_g.js";import{n as getStatusSummary,r as pickGatewaySelfPresence}from"./status-BqEzSHhZ.js";import{c as startHeartbeatRunner,i as styleHealthChannelLine,n as getHealthSnapshot,o as runHeartbeatOnce,s as setHeartbeatsEnabled,t as formatHealthChannelLines}from"./health-CoTbsx1p.js";import{a as resolveControlUiRootSync,i as resolveControlUiRootOverrideSync,t as ensureControlUiAssetsBuilt}from"./control-ui-assets-CAmSpVpE.js";import{h as normalizeUpdateChannel,l as DEFAULT_PACKAGE_CHANNEL,n as compareSemverStrings,o as resolveNpmChannelTag,t as checkUpdateStatus}from"./update-check-CwmSkavG.js";import{t as runOnboardingWizard}from"./onboarding-DXxufSuN.js";import{a as sendApnsAlert,c as parseMessageWithAttachments,d as shouldLogWs,f as summarizeAgentEventForWsLog,i as resolveApnsAuthConfigFromEnv,l as formatForLog,n as normalizeApnsEnvironment,o as sendApnsBackgroundWake,p as setGatewayWsLogStyle,s as normalizeRpcAttachmentsToChatAttachments,t as loadApnsRegistration,u as logWs}from"./push-apns-BXmSvfvx.js";import{T as resolveGmailHookRuntimeConfig,_ as buildGogWatchServeArgs,i as ensureTailscaleEndpoint,v as buildGogWatchStartArgs}from"./gmail-setup-utils-C2pbrI7I.js";import{t as createOutboundSendDeps$1}from"./outbound-send-deps-DS_1j6Dm.js";import{a as pruneAgentConfig,i as loadAgentIdentity,r as findAgentEntryIndex,s as loadAgentIdentityFromWorkspace,t as applyAgentConfig}from"./agents.config-D4ThL3Cg.js";import{i as resolveAgentOutboundTarget,r as resolveAgentDeliveryPlan,t as agentCommand}from"./agent-Cu57zjv6.js";import"./dm-policy-shared-B5SWfgvG.js";import"./node-service-C41a54YN.js";import"./status.update-BvLaYyY5.js";import{n as validateSystemRunCommandConsistency,t as formatExecCommand}from"./system-run-command-IGKiGgdN.js";import{t as installSkill}from"./skills-install-DXm4y2QA.js";import{n as runGatewayUpdate,t as resolveAgentSessionDirs}from"./session-dirs-DgwMogyJ.js";import{n as syncBuilderForceAgentsDirectoryOnStartup,t as syncBuilderForceAgentsDirectory}from"./builderforce-directory-sync-DJdx8s3l.js";import{n as mergeBuilderforceContext,t as buildLocalMachineProfile}from"./builderforce-context-xdRubwNz.js";import{a as emitWorkflowEnd,c as initTelemetry,i as emitTaskStart,l as setRelayHook,o as emitWorkflowStart,r as emitTaskEnd}from"./workflow-telemetry-CcOSOvct.js";import{fileURLToPath,pathToFileURL}from"node:url";import*as fsSync from"node:fs";import fs,{constants}from"node:fs";import os from"node:os";import path,{dirname,join,relative,sep}from"node:path";import crypto,{createHash,randomUUID}from"node:crypto";import JSON5 from"json5";import chalk from"chalk";import fs$1,{mkdir,readFile,readdir,writeFile}from"node:fs/promises";import{execFile,spawn,spawnSync}from"node:child_process";import{promisify}from"node:util";import{z}from"zod";import net from"node:net";import{createServer}from"node:http";import{createServer as createServer$1}from"node:https";import{WebSocket as WebSocket$1,WebSocketServer}from"ws";import{Buffer as Buffer$1}from"node:buffer";import{neutralLimbicState}from"@seanhogg/builderforce-memory-engine/limbic";import{Type}from"@sinclair/typebox";import chokidar from"chokidar";import{EventEmitter}from"node:events";import{Cron}from"croner";import{query}from"@anthropic-ai/claude-agent-sdk";function parsePort(value){if(!value)return;let parsed=Number.parseInt(value,10);if(!(!Number.isFinite(parsed)||parsed<=0))return parsed}function parseSshConfigOutput(output){let result={identityFiles:[]},lines=output.split(`
|
|
2
2
|
`);for(let raw of lines){let line=raw.trim();if(!line)continue;let[key,...rest]=line.split(/\s+/),value=rest.join(` `).trim();if(!(!key||!value))switch(key){case`user`:result.user=value;break;case`hostname`:result.host=value;break;case`port`:result.port=parsePort(value);break;case`identityfile`:value!==`none`&&result.identityFiles.push(value);break;default:break}}return result}async function resolveSshConfig(target,opts={}){let args=[`-G`];target.port>0&&target.port!==22&&args.push(`-p`,String(target.port)),opts.identity?.trim()&&args.push(`-i`,opts.identity.trim());let userHost=target.user?`${target.user}@${target.host}`:target.host;return args.push(`--`,userHost),await new Promise(resolve=>{let child=spawn(`/usr/bin/ssh`,args,{stdio:[`ignore`,`pipe`,`ignore`]}),stdout=``;child.stdout?.setEncoding(`utf8`),child.stdout?.on(`data`,chunk=>{stdout+=String(chunk)});let timeoutMs=Math.max(200,opts.timeoutMs??800),timer=setTimeout(()=>{try{child.kill(`SIGKILL`)}finally{resolve(null)}},timeoutMs);child.once(`error`,()=>{clearTimeout(timer),resolve(null)}),child.once(`exit`,code=>{if(clearTimeout(timer),code!==0||!stdout.trim()){resolve(null);return}resolve(parseSshConfigOutput(stdout))})})}function parseSshTarget(raw){let trimmed=raw.trim().replace(/^ssh\s+/,``);if(!trimmed)return null;let[userPart,hostPart]=trimmed.includes(`@`)?(()=>{let idx=trimmed.indexOf(`@`),user=trimmed.slice(0,idx).trim(),host=trimmed.slice(idx+1).trim();return[user||void 0,host]})():[void 0,trimmed],colonIdx=hostPart.lastIndexOf(`:`);if(colonIdx>0&&colonIdx<hostPart.length-1){let host=hostPart.slice(0,colonIdx).trim(),portRaw=hostPart.slice(colonIdx+1).trim(),port=Number.parseInt(portRaw,10);return!host||!Number.isFinite(port)||port<=0||host.startsWith(`-`)?null:{user:userPart,host,port}}return!hostPart||hostPart.startsWith(`-`)?null:{user:userPart,host:hostPart,port:22}}async function pickEphemeralPort(){return await new Promise((resolve,reject)=>{let server=net.createServer();server.once(`error`,reject),server.listen(0,`127.0.0.1`,()=>{let addr=server.address();server.close(()=>{if(!addr||typeof addr==`string`){reject(Error(`failed to allocate a local port`));return}resolve(addr.port)})})})}async function canConnectLocal(port){return await new Promise(resolve=>{let socket=net.connect({host:`127.0.0.1`,port}),done=ok=>{socket.removeAllListeners(),socket.destroy(),resolve(ok)};socket.once(`connect`,()=>done(!0)),socket.once(`error`,()=>done(!1)),socket.setTimeout(250,()=>done(!1))})}async function waitForLocalListener(port,timeoutMs){let startedAt=Date.now();for(;Date.now()-startedAt<timeoutMs;){if(await canConnectLocal(port))return;await new Promise(r=>setTimeout(r,50))}throw Error(`ssh tunnel did not start listening on localhost:${port}`)}async function startSshPortForward(opts){let parsed=parseSshTarget(opts.target);if(!parsed)throw Error(`invalid SSH target: ${opts.target}`);let localPort=opts.localPortPreferred;try{await ensurePortAvailable(localPort)}catch(err){if(isErrno(err)&&err.code===`EADDRINUSE`)localPort=await pickEphemeralPort();else throw err}let userHost=parsed.user?`${parsed.user}@${parsed.host}`:parsed.host,args=[`-N`,`-L`,`${localPort}:127.0.0.1:${opts.remotePort}`,`-p`,String(parsed.port),`-o`,`ExitOnForwardFailure=yes`,`-o`,`BatchMode=yes`,`-o`,`StrictHostKeyChecking=accept-new`,`-o`,`UpdateHostKeys=yes`,`-o`,`ConnectTimeout=5`,`-o`,`ServerAliveInterval=15`,`-o`,`ServerAliveCountMax=3`];opts.identity?.trim()&&args.push(`-i`,opts.identity.trim()),args.push(`--`,userHost);let stderr=[],child=spawn(`/usr/bin/ssh`,args,{stdio:[`ignore`,`ignore`,`pipe`]});child.stderr?.setEncoding(`utf8`),child.stderr?.on(`data`,chunk=>{let lines=String(chunk).split(`
|
|
3
3
|
`).map(l=>l.trim()).filter(Boolean);stderr.push(...lines)});let stop=async()=>{child.killed||(child.kill(`SIGTERM`),await new Promise(resolve=>{let t=setTimeout(()=>{try{child.kill(`SIGKILL`)}finally{resolve()}},1500);child.once(`exit`,()=>{clearTimeout(t),resolve()})}))};try{await Promise.race([waitForLocalListener(localPort,Math.max(250,opts.timeoutMs)),new Promise((_,reject)=>{child.once(`exit`,(code,signal)=>{reject(Error(`ssh exited (${code??`null`}${signal?`/${signal}`:``})`))})})])}catch(err){await stop();let suffix=stderr.length>0?`\n${stderr.join(`
|
|
4
4
|
`)}`:``;throw Error(`${err instanceof Error?err.message:String(err)}${suffix}`,{cause:err})}return{parsedTarget:parsed,localPort,remotePort:opts.remotePort,pid:typeof child.pid==`number`?child.pid:null,stderr,stop}}function parseIntOrNull(value){let s=typeof value==`string`?value.trim():typeof value==`number`||typeof value==`bigint`?String(value):``;if(!s)return null;let n=Number.parseInt(s,10);return Number.isFinite(n)?n:null}function parseTimeoutMs(raw,fallbackMs){let value=typeof raw==`string`?raw.trim():typeof raw==`number`||typeof raw==`bigint`?String(raw):``;if(!value)return fallbackMs;let parsed=Number.parseInt(value,10);if(!Number.isFinite(parsed)||parsed<=0)throw Error(`invalid --timeout: ${value}`);return parsed}function normalizeWsUrl(value){let trimmed=value.trim();return!trimmed||!trimmed.startsWith(`ws://`)&&!trimmed.startsWith(`wss://`)?null:trimmed}function resolveTargets(cfg,explicitUrl){let targets=[],add=t=>{targets.some(x=>x.url===t.url)||targets.push(t)},explicit=typeof explicitUrl==`string`?normalizeWsUrl(explicitUrl):null;explicit&&add({id:`explicit`,kind:`explicit`,url:explicit,active:!0});let remoteUrl=typeof cfg.gateway?.remote?.url==`string`?normalizeWsUrl(cfg.gateway.remote.url):null;return remoteUrl&&add({id:`configRemote`,kind:`configRemote`,url:remoteUrl,active:cfg.gateway?.mode===`remote`}),add({id:`localLoopback`,kind:`localLoopback`,url:`ws://127.0.0.1:${resolveGatewayPort(cfg)}`,active:cfg.gateway?.mode!==`remote`}),targets}function resolveProbeBudgetMs(overallMs,kind){return kind===`localLoopback`?Math.min(800,overallMs):kind===`sshTunnel`?Math.min(2e3,overallMs):Math.min(1500,overallMs)}function sanitizeSshTarget(value){if(typeof value!=`string`)return null;let trimmed=value.trim();return trimmed?trimmed.replace(/^ssh\\s+/,``):null}function resolveAuthForTarget(cfg,target,overrides){let tokenOverride=overrides.token?.trim()?overrides.token.trim():void 0,passwordOverride=overrides.password?.trim()?overrides.password.trim():void 0;if(tokenOverride||passwordOverride)return{token:tokenOverride,password:passwordOverride};if(target.kind===`configRemote`||target.kind===`sshTunnel`){let token=typeof cfg.gateway?.remote?.token==`string`?cfg.gateway.remote.token.trim():``,remotePassword=cfg.gateway?.remote?.password,password=typeof remotePassword==`string`?remotePassword.trim():``;return{token:token.length>0?token:void 0,password:password.length>0?password:void 0}}let envToken=process.env.BUILDERFORCE_AGENTS_GATEWAY_TOKEN?.trim()||``,envPassword=process.env.BUILDERFORCE_AGENTS_GATEWAY_PASSWORD?.trim()||``,cfgToken=typeof cfg.gateway?.auth?.token==`string`?cfg.gateway.auth.token.trim():``,cfgPassword=typeof cfg.gateway?.auth?.password==`string`?cfg.gateway.auth.password.trim():``;return{token:envToken||cfgToken||void 0,password:envPassword||cfgPassword||void 0}}function extractConfigSummary(snapshotUnknown){let snap=snapshotUnknown,path=typeof snap?.path==`string`?snap.path:null,exists=!!snap?.exists,valid=!!snap?.valid,issuesRaw=Array.isArray(snap?.issues)?snap.issues:[],legacyRaw=Array.isArray(snap?.legacyIssues)?snap.legacyIssues:[],cfg=snap?.config??{},gateway=cfg.gateway??{},wideArea=(cfg.discovery??{}).wideArea??{},remote=gateway.remote??{},auth=gateway.auth??{},controlUi=gateway.controlUi??{},tailscale=gateway.tailscale??{},authMode=typeof auth.mode==`string`?auth.mode:null,authTokenConfigured=typeof auth.token==`string`?auth.token.trim().length>0:!1,authPasswordConfigured=typeof auth.password==`string`?auth.password.trim().length>0:!1,remoteUrl=typeof remote.url==`string`?normalizeWsUrl(remote.url):null,remoteTokenConfigured=typeof remote.token==`string`?remote.token.trim().length>0:!1,remotePasswordConfigured=typeof remote.password==`string`?String(remote.password).trim().length>0:!1,wideAreaEnabled=typeof wideArea.enabled==`boolean`?wideArea.enabled:null;return{path,exists,valid,issues:issuesRaw.filter(i=>!!(i&&typeof i.path==`string`&&typeof i.message==`string`)).map(i=>({path:i.path,message:i.message})),legacyIssues:legacyRaw.filter(i=>!!(i&&typeof i.path==`string`&&typeof i.message==`string`)).map(i=>({path:i.path,message:i.message})),gateway:{mode:typeof gateway.mode==`string`?gateway.mode:null,bind:typeof gateway.bind==`string`?gateway.bind:null,port:parseIntOrNull(gateway.port),controlUiEnabled:typeof controlUi.enabled==`boolean`?controlUi.enabled:null,controlUiBasePath:typeof controlUi.basePath==`string`?controlUi.basePath:null,authMode,authTokenConfigured,authPasswordConfigured,remoteUrl,remoteTokenConfigured,remotePasswordConfigured,tailscaleMode:typeof tailscale.mode==`string`?tailscale.mode:null},discovery:{wideAreaEnabled}}}function buildNetworkHints(cfg){let tailnetIPv4=pickPrimaryTailnetIPv4(),port=resolveGatewayPort(cfg);return{localLoopbackUrl:`ws://127.0.0.1:${port}`,localTailnetUrl:tailnetIPv4?`ws://${tailnetIPv4}:${port}`:null,tailnetIPv4:tailnetIPv4??null}}function renderTargetHeader(target,rich){let kindLabel=target.kind===`localLoopback`?`Local loopback`:target.kind===`sshTunnel`?`Remote over SSH`:target.kind===`configRemote`?target.active?`Remote (configured)`:`Remote (configured, inactive)`:`URL (explicit)`;return`${colorize(rich,theme.heading,kindLabel)} ${colorize(rich,theme.muted,target.url)}`}function renderProbeSummaryLine(probe,rich){if(probe.ok){let latency=typeof probe.connectLatencyMs==`number`?`${probe.connectLatencyMs}ms`:`unknown`;return`${colorize(rich,theme.success,`Connect: ok`)} (${latency}) · ${colorize(rich,theme.success,`RPC: ok`)}`}let detail=probe.error?` - ${probe.error}`:``;if(probe.connectLatencyMs!=null){let latency=typeof probe.connectLatencyMs==`number`?`${probe.connectLatencyMs}ms`:`unknown`;return`${colorize(rich,theme.success,`Connect: ok`)} (${latency}) · ${colorize(rich,theme.error,`RPC: failed`)}${detail}`}return`${colorize(rich,theme.error,`Connect: failed`)}${detail}`}async function gatewayStatusCommand(opts,runtime){let startedAt=Date.now(),cfg=loadConfig(),rich=isRich()&&opts.json!==!0,overallTimeoutMs=parseTimeoutMs(opts.timeout,3e3),wideAreaDomain=resolveWideAreaDiscoveryDomain({configDomain:cfg.discovery?.wideArea?.domain}),baseTargets=resolveTargets(cfg,opts.url),network=buildNetworkHints(cfg),discoveryTimeoutMs=Math.min(1200,overallTimeoutMs),discoveryPromise=discoverGatewayBeacons({timeoutMs:discoveryTimeoutMs,wideAreaDomain}),sshTarget=sanitizeSshTarget(opts.ssh)??sanitizeSshTarget(cfg.gateway?.remote?.sshTarget),sshIdentity=sanitizeSshTarget(opts.sshIdentity)??sanitizeSshTarget(cfg.gateway?.remote?.sshIdentity),remotePort=resolveGatewayPort(cfg),sshTunnelError=null,sshTunnelStarted=!1;if(sshTarget||=inferSshTargetFromRemoteUrl(cfg.gateway?.remote?.url),sshTarget){let resolved=await resolveSshTarget(sshTarget,sshIdentity,overallTimeoutMs);resolved&&(sshTarget=resolved.target,!sshIdentity&&resolved.identity&&(sshIdentity=resolved.identity))}let{discovery,probed}=await withProgress({label:`Inspecting gateways…`,indeterminate:!0,enabled:opts.json!==!0},async()=>{let tryStartTunnel=async()=>{if(!sshTarget)return null;try{let tunnel=await startSshPortForward({target:sshTarget,identity:sshIdentity??void 0,localPortPreferred:remotePort,remotePort,timeoutMs:Math.min(1500,overallTimeoutMs)});return sshTunnelStarted=!0,tunnel}catch(err){return sshTunnelError=err instanceof Error?err.message:String(err),null}},discoveryTask=discoveryPromise.catch(()=>[]),tunnelTask=sshTarget?tryStartTunnel():Promise.resolve(null),[discovery,tunnelFirst]=await Promise.all([discoveryTask,tunnelTask]);if(!sshTarget&&opts.sshAuto){let user=process.env.USER?.trim()||``,candidates=discovery.map(b=>{let host=b.tailnetDns||b.lanHost||b.host;if(!host?.trim())return null;let sshPort=typeof b.sshPort==`number`&&b.sshPort>0?b.sshPort:22,base=user?`${user}@${host.trim()}`:host.trim();return sshPort===22?base:`${base}:${sshPort}`}).filter(candidate=>!!(candidate&&parseSshTarget(candidate)));candidates.length>0&&(sshTarget=candidates[0]??null)}let tunnel=tunnelFirst||(sshTarget&&!sshTunnelStarted&&!sshTunnelError?await tryStartTunnel():null),tunnelTarget=tunnel?{id:`sshTunnel`,kind:`sshTunnel`,url:`ws://127.0.0.1:${tunnel.localPort}`,active:!0,tunnel:{kind:`ssh`,target:sshTarget??``,localPort:tunnel.localPort,remotePort,pid:tunnel.pid}}:null,targets=tunnelTarget?[tunnelTarget,...baseTargets.filter(t=>t.url!==tunnelTarget.url)]:baseTargets;try{return{discovery,probed:await Promise.all(targets.map(async target=>{let auth=resolveAuthForTarget(cfg,target,{token:typeof opts.token==`string`?opts.token:void 0,password:typeof opts.password==`string`?opts.password:void 0}),timeoutMs=resolveProbeBudgetMs(overallTimeoutMs,target.kind),probe=await probeGateway({url:target.url,auth,timeoutMs});return{target,probe,configSummary:probe.configSnapshot?extractConfigSummary(probe.configSnapshot):null,self:pickGatewaySelfPresence(probe.presence)}}))}}finally{if(tunnel)try{await tunnel.stop()}catch{}}}),reachable=probed.filter(p=>p.probe.ok),ok=reachable.length>0,multipleGateways=reachable.length>1,primary=reachable.find(p=>p.target.kind===`explicit`)??reachable.find(p=>p.target.kind===`sshTunnel`)??reachable.find(p=>p.target.kind===`configRemote`)??reachable.find(p=>p.target.kind===`localLoopback`)??null,warnings=[];if(sshTarget&&!sshTunnelStarted&&warnings.push({code:`ssh_tunnel_failed`,message:sshTunnelError?`SSH tunnel failed: ${String(sshTunnelError)}`:`SSH tunnel failed to start; falling back to direct probes.`}),multipleGateways&&warnings.push({code:`multiple_gateways`,message:`Unconventional setup: multiple reachable gateways detected. Usually one gateway per network is recommended unless you intentionally run isolated profiles, like a rescue bot (see docs: /gateway#multiple-gateways-same-host).`,targetIds:reachable.map(p=>p.target.id)}),opts.json){runtime.log(JSON.stringify({ok,ts:Date.now(),durationMs:Date.now()-startedAt,timeoutMs:overallTimeoutMs,primaryTargetId:primary?.target.id??null,warnings,network,discovery:{timeoutMs:discoveryTimeoutMs,count:discovery.length,beacons:discovery.map(b=>({instanceName:b.instanceName,displayName:b.displayName??null,domain:b.domain??null,host:b.host??null,lanHost:b.lanHost??null,tailnetDns:b.tailnetDns??null,gatewayPort:b.gatewayPort??null,sshPort:b.sshPort??null,wsUrl:(()=>{let host=b.tailnetDns||b.lanHost||b.host,port=b.gatewayPort??18789;return host?`ws://${host}:${port}`:null})()}))},targets:probed.map(p=>({id:p.target.id,kind:p.target.kind,url:p.target.url,active:p.target.active,tunnel:p.target.tunnel??null,connect:{ok:p.probe.ok,latencyMs:p.probe.connectLatencyMs,error:p.probe.error,close:p.probe.close},self:p.self,config:p.configSummary,health:p.probe.health,summary:p.probe.status,presence:p.probe.presence}))},null,2)),ok||runtime.exit(1);return}if(runtime.log(colorize(rich,theme.heading,`Gateway Status`)),runtime.log(ok?`${colorize(rich,theme.success,`Reachable`)}: yes`:`${colorize(rich,theme.error,`Reachable`)}: no`),runtime.log(colorize(rich,theme.muted,`Probe budget: ${overallTimeoutMs}ms`)),warnings.length>0){runtime.log(``),runtime.log(colorize(rich,theme.warn,`Warning:`));for(let w of warnings)runtime.log(`- ${w.message}`)}runtime.log(``),runtime.log(colorize(rich,theme.heading,`Discovery (this machine)`));let discoveryDomains=wideAreaDomain?`local. + ${wideAreaDomain}`:`local.`;runtime.log(discovery.length>0?`Found ${discovery.length} gateway(s) via Bonjour (${discoveryDomains})`:`Found 0 gateways via Bonjour (${discoveryDomains})`),discovery.length===0&&runtime.log(colorize(rich,theme.muted,`Tip: if the gateway is remote, mDNS won’t cross networks; use Wide-Area Bonjour (split DNS) or SSH tunnels.`)),runtime.log(``),runtime.log(colorize(rich,theme.heading,`Targets`));for(let p of probed){if(runtime.log(renderTargetHeader(p.target,rich)),runtime.log(` ${renderProbeSummaryLine(p.probe,rich)}`),p.target.tunnel?.kind===`ssh`&&runtime.log(` ${colorize(rich,theme.muted,`ssh`)}: ${colorize(rich,theme.command,p.target.tunnel.target)}`),p.probe.ok&&p.self){let host=p.self.host??`unknown`,ip=p.self.ip?` (${p.self.ip})`:``,platform=p.self.platform?` · ${p.self.platform}`:``,version=p.self.version?` · app ${p.self.version}`:``;runtime.log(` ${colorize(rich,theme.info,`Gateway`)}: ${host}${ip}${platform}${version}`)}if(p.configSummary){let c=p.configSummary,wideArea=c.discovery.wideAreaEnabled===!0?`enabled`:c.discovery.wideAreaEnabled===!1?`disabled`:`unknown`;runtime.log(` ${colorize(rich,theme.info,`Wide-area discovery`)}: ${wideArea}`)}runtime.log(``)}ok||runtime.exit(1)}function inferSshTargetFromRemoteUrl(rawUrl){if(typeof rawUrl!=`string`)return null;let trimmed=rawUrl.trim();if(!trimmed)return null;let host=null;try{host=new URL(trimmed).hostname||null}catch{return null}if(!host)return null;let user=process.env.USER?.trim()||``;return user?`${user}@${host}`:host}function buildSshTarget(input){let host=input.host?.trim()??``;if(!host)return null;let user=input.user?.trim()??``,base=user?`${user}@${host}`:host,port=input.port??22;return port&&port!==22?`${base}:${port}`:base}async function resolveSshTarget(rawTarget,identity,overallTimeoutMs){let parsed=parseSshTarget(rawTarget);if(!parsed)return null;let config=await resolveSshConfig(parsed,{identity:identity??void 0,timeoutMs:Math.min(800,overallTimeoutMs)});if(!config)return{target:rawTarget,identity:identity??void 0};let target=buildSshTarget({user:config.user??parsed.user,host:config.host??parsed.host,port:config.port??parsed.port});return target?{target,identity:identity??config.identityFiles.find(entry=>entry.trim().length>0)?.trim()??void 0}:{target:rawTarget,identity:identity??void 0}}const gatewayCallOpts=cmd=>cmd.option(`--url <url>`,`Gateway WebSocket URL (defaults to gateway.remote.url when configured)`).option(`--token <token>`,`Gateway token (if required)`).option(`--password <password>`,`Gateway password (password auth)`).option(`--timeout <ms>`,`Timeout in ms`,`10000`).option(`--expect-final`,`Wait for final response (agent)`,!1).option(`--json`,`Output JSON`,!1),callGatewayCli=async(method,opts,params)=>withProgress({label:`Gateway ${method}`,indeterminate:!0,enabled:opts.json!==!0},async()=>await callGateway({url:opts.url,token:opts.token,password:opts.password,method,params,expectFinal:!!opts.expectFinal,timeoutMs:Number(opts.timeout??1e4),clientName:GATEWAY_CLIENT_NAMES.CLI,mode:GATEWAY_CLIENT_MODES.CLI}));function parseDiscoverTimeoutMs(raw,fallbackMs){if(raw==null)return fallbackMs;let value=typeof raw==`string`?raw.trim():typeof raw==`number`||typeof raw==`bigint`?String(raw):null;if(value===null)throw Error(`invalid --timeout`);if(!value)return fallbackMs;let parsed=Number.parseInt(value,10);if(!Number.isFinite(parsed)||parsed<=0)throw Error(`invalid --timeout: ${value}`);return parsed}function pickBeaconHost(beacon){let host=beacon.host||beacon.tailnetDns||beacon.lanHost;return host?.trim()?host.trim():null}function pickGatewayPort(beacon){let port=beacon.port??beacon.gatewayPort??18789;return port>0?port:18789}function dedupeBeacons(beacons){let out=[],seen=new Set;for(let b of beacons){let host=pickBeaconHost(b)??``,key=[b.domain??``,b.instanceName??``,b.displayName??``,host,String(b.port??``),String(b.gatewayPort??``)].join(`|`);seen.has(key)||(seen.add(key),out.push(b))}return out}function renderBeaconLines(beacon,rich){let nameRaw=(beacon.displayName||beacon.instanceName||`Gateway`).trim(),domainRaw=(beacon.domain||`local.`).trim(),title=colorize(rich,theme.accentBright,nameRaw),domain=colorize(rich,theme.muted,domainRaw),host=pickBeaconHost(beacon),gatewayPort=pickGatewayPort(beacon),scheme=beacon.gatewayTls?`wss`:`ws`,wsUrl=host?`${scheme}://${host}:${gatewayPort}`:null,lines=[`- ${title} ${domain}`];if(beacon.tailnetDns&&lines.push(` ${colorize(rich,theme.info,`tailnet`)}: ${beacon.tailnetDns}`),beacon.lanHost&&lines.push(` ${colorize(rich,theme.info,`lan`)}: ${beacon.lanHost}`),beacon.host&&lines.push(` ${colorize(rich,theme.info,`host`)}: ${beacon.host}`),wsUrl&&lines.push(` ${colorize(rich,theme.muted,`ws`)}: ${colorize(rich,theme.command,wsUrl)}`),beacon.role&&lines.push(` ${colorize(rich,theme.muted,`role`)}: ${beacon.role}`),beacon.transport&&lines.push(` ${colorize(rich,theme.muted,`transport`)}: ${beacon.transport}`),beacon.gatewayTls){let fingerprint=beacon.gatewayTlsFingerprintSha256?`sha256 ${beacon.gatewayTlsFingerprintSha256}`:`enabled`;lines.push(` ${colorize(rich,theme.muted,`tls`)}: ${fingerprint}`)}if(typeof beacon.sshPort==`number`&&beacon.sshPort>0&&host){let ssh=`ssh -N -L 18789:127.0.0.1:18789 <user>@${host} -p ${beacon.sshPort}`;lines.push(` ${colorize(rich,theme.muted,`ssh`)}: ${colorize(rich,theme.command,ssh)}`)}return lines}function truncateCloseReason(reason,maxBytes=120){if(!reason)return`invalid handshake`;let buf=Buffer$1.from(reason);return buf.length<=maxBytes?reason:buf.subarray(0,maxBytes).toString()}const log$7=createSubsystemLogger(`gateway/exec-approvals`);function normalizeMode(mode){return mode??`session`}function matchSessionFilter(sessionKey,patterns){return patterns.some(pattern=>{try{return sessionKey.includes(pattern)||new RegExp(pattern).test(sessionKey)}catch{return sessionKey.includes(pattern)}})}function shouldForward(params){let config=params.config;if(!config?.enabled)return!1;if(config.agentFilter?.length){let agentId=params.request.request.agentId??parseAgentSessionKey(params.request.request.sessionKey)?.agentId;if(!agentId||!config.agentFilter.includes(agentId))return!1}if(config.sessionFilter?.length){let sessionKey=params.request.request.sessionKey;if(!sessionKey||!matchSessionFilter(sessionKey,config.sessionFilter))return!1}return!0}function buildTargetKey(target){let channel=normalizeMessageChannel(target.channel)??target.channel,accountId=target.accountId??``,threadId=target.threadId??``;return[channel,target.to,accountId,threadId].join(`:`)}function shouldSkipDiscordForwarding(target){return(normalizeMessageChannel(target.channel)??target.channel)===`discord`}function formatApprovalCommand(command){if(!command.includes(`
|
|
@@ -14,7 +14,7 @@ import{_ as expandHomePrefix,g as resolveStateDir,i as isNixMode,l as resolveGat
|
|
|
14
14
|
|
|
15
15
|
`).trim(),fallbackFinalMessage;if(combinedReply){let{storePath:latestStorePath,entry:latestEntry}=loadSessionEntry(sessionKey),appended=appendAssistantTranscriptMessage({message:combinedReply,sessionId:latestEntry?.sessionId??entry?.sessionId??clientRunId,storePath:latestStorePath,sessionFile:latestEntry?.sessionFile,agentId,createIfMissing:!0});appended.ok?fallbackFinalMessage=appended.message:(context.logGateway.warn(`webchat transcript append failed: ${appended.error??`unknown error`}`),fallbackFinalMessage={role:`assistant`,content:[{type:`text`,text:combinedReply}],timestamp:Date.now(),stopReason:`stop`,usage:{input:0,output:0,totalTokens:0}})}agentRunStarted?fallbackFinalMessage&&startedGatewayRunId&&context.removeChatRun(startedGatewayRunId,clientRunId,rawSessionKey)&&broadcastChatFinal({context,runId:clientRunId,sessionKey:rawSessionKey,message:fallbackFinalMessage}):broadcastChatFinal({context,runId:clientRunId,sessionKey:rawSessionKey,message:fallbackFinalMessage}),context.dedupe.set(`chat:${clientRunId}`,{ts:Date.now(),ok:!0,payload:{runId:clientRunId,status:`ok`}})}).catch(err=>{let error=errorShape(ErrorCodes.UNAVAILABLE,String(err));context.dedupe.set(`chat:${clientRunId}`,{ts:Date.now(),ok:!1,payload:{runId:clientRunId,status:`error`,summary:String(err)},error}),broadcastChatError({context,runId:clientRunId,sessionKey:rawSessionKey,errorMessage:String(err)})}).finally(()=>{context.chatAbortControllers.delete(clientRunId)})}catch(err){let error=errorShape(ErrorCodes.UNAVAILABLE,String(err)),payload={runId:clientRunId,status:`error`,summary:String(err)};context.dedupe.set(`chat:${clientRunId}`,{ts:Date.now(),ok:!1,payload,error}),respond(!1,payload,error,{runId:clientRunId,error:formatForLog(err)})}},"chat.inject":async({params,respond,context})=>{if(!validateChatInjectParams(params)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid chat.inject params: ${formatValidationErrors(validateChatInjectParams.errors)}`));return}let p=params,rawSessionKey=p.sessionKey,{cfg,storePath,entry}=loadSessionEntry(rawSessionKey),sessionId=entry?.sessionId;if(!sessionId||!storePath){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`session not found`));return}let appended=appendAssistantTranscriptMessage({message:p.message,label:p.label,sessionId,storePath,sessionFile:entry?.sessionFile,agentId:resolveSessionAgentId({sessionKey:rawSessionKey,config:cfg}),createIfMissing:!1});if(!appended.ok||!appended.messageId||!appended.message){respond(!1,void 0,errorShape(ErrorCodes.UNAVAILABLE,`failed to write transcript: ${appended.error??`unknown error`}`));return}let chatPayload={runId:`inject-${appended.messageId}`,sessionKey:rawSessionKey,seq:0,state:`final`,message:appended.message};context.broadcast(`chat`,chatPayload),context.nodeSendToSession(rawSessionKey,`chat`,chatPayload),respond(!0,{ok:!0,messageId:appended.messageId})}},IRC_FIELD_LABELS={"channels.irc":`IRC`,"channels.irc.dmPolicy":`IRC DM Policy`,"channels.irc.nickserv.enabled":`IRC NickServ Enabled`,"channels.irc.nickserv.service":`IRC NickServ Service`,"channels.irc.nickserv.password":`IRC NickServ Password`,"channels.irc.nickserv.passwordFile":`IRC NickServ Password File`,"channels.irc.nickserv.register":`IRC NickServ Register`,"channels.irc.nickserv.registerEmail":`IRC NickServ Register Email`},IRC_FIELD_HELP={"channels.irc.configWrites":`Allow IRC to write config in response to channel events/commands (default: true).`,"channels.irc.dmPolicy":`Direct message access control ("pairing" recommended). "open" requires channels.irc.allowFrom=["*"].`,"channels.irc.nickserv.enabled":`Enable NickServ identify/register after connect (defaults to enabled when password is configured).`,"channels.irc.nickserv.service":`NickServ service nick (default: NickServ).`,"channels.irc.nickserv.password":`NickServ password used for IDENTIFY/REGISTER (sensitive).`,"channels.irc.nickserv.passwordFile":`Optional file path containing NickServ password.`,"channels.irc.nickserv.register":`If true, send NickServ REGISTER on every connect. Use once for initial registration, then disable.`,"channels.irc.nickserv.registerEmail":`Email used with NickServ REGISTER (required when register=true).`},FIELD_HELP={"meta.lastTouchedVersion":`Auto-set when BuilderForceAgents writes the config.`,"meta.lastTouchedAt":`ISO timestamp of the last config write (auto-set).`,"update.channel":`Update channel for git + npm installs ("stable", "beta", or "dev").`,"update.checkOnStart":`Check for npm updates when the gateway starts (default: true).`,"gateway.remote.url":`Remote Gateway WebSocket URL (ws:// or wss://).`,"gateway.remote.tlsFingerprint":`Expected sha256 TLS fingerprint for the remote gateway (pin to avoid MITM).`,"gateway.remote.sshTarget":`Remote gateway over SSH (tunnels the gateway port to localhost). Format: user@host or user@host:port.`,"gateway.remote.sshIdentity":`Optional SSH identity file path (passed to ssh -i).`,"agents.list.*.skills":`Optional allowlist of skills for this agent (omit = all skills; empty = no skills).`,"agents.list[].skills":`Optional allowlist of skills for this agent (omit = all skills; empty = no skills).`,"agents.list[].identity.avatar":`Avatar image path (relative to the agent workspace only) or a remote URL/data URL.`,"agents.defaults.heartbeat.suppressToolErrorWarnings":`Suppress tool error warning payloads during heartbeat runs.`,"agents.list[].heartbeat.suppressToolErrorWarnings":`Suppress tool error warning payloads during heartbeat runs.`,"discovery.mdns.mode":`mDNS broadcast mode ("minimal" default, "full" includes cliPath/sshPort, "off" disables mDNS).`,"gateway.auth.token":`Required by default for gateway access (unless using Tailscale Serve identity); required for non-loopback binds.`,"gateway.auth.password":`Required for Tailscale funnel.`,"gateway.controlUi.basePath":`Optional URL prefix where the Control UI is served (e.g. /builderforce).`,"gateway.controlUi.root":`Optional filesystem root for Control UI assets (defaults to dist/control-ui).`,"gateway.controlUi.allowedOrigins":`Allowed browser origins for Control UI/WebChat websocket connections (full origins only, e.g. https://control.example.com).`,"gateway.controlUi.allowInsecureAuth":`Allow Control UI auth over insecure HTTP (token-only; not recommended).`,"gateway.controlUi.dangerouslyDisableDeviceAuth":`DANGEROUS. Disable Control UI device identity checks (token/password only).`,"gateway.http.endpoints.chatCompletions.enabled":"Enable the OpenAI-compatible `POST /v1/chat/completions` endpoint (default: false).","gateway.reload.mode":`Hot reload strategy for config changes ("hybrid" recommended).`,"gateway.reload.debounceMs":`Debounce window (ms) before applying config changes.`,"gateway.nodes.browser.mode":`Node browser routing ("auto" = pick single connected browser node, "manual" = require node param, "off" = disable).`,"gateway.nodes.browser.node":`Pin browser routing to a specific node id or name (optional).`,"gateway.nodes.allowCommands":`Extra node.invoke commands to allow beyond the gateway defaults (array of command strings).`,"gateway.nodes.denyCommands":`Commands to block even if present in node claims or default allowlist.`,"nodeHost.browserProxy.enabled":`Expose the local browser control server via node proxy.`,"nodeHost.browserProxy.allowProfiles":`Optional allowlist of browser profile names exposed via the node proxy.`,"diagnostics.flags":`Enable targeted diagnostics logs by flag (e.g. ["telegram.http"]). Supports wildcards like "telegram.*" or "*".`,"diagnostics.cacheTrace.enabled":`Log cache trace snapshots for embedded agent runs (default: false).`,"diagnostics.cacheTrace.filePath":`JSONL output path for cache trace logs (default: $BUILDERFORCE_AGENTS_STATE_DIR/logs/cache-trace.jsonl).`,"diagnostics.cacheTrace.includeMessages":`Include full message payloads in trace output (default: true).`,"diagnostics.cacheTrace.includePrompt":`Include prompt text in trace output (default: true).`,"diagnostics.cacheTrace.includeSystem":`Include system prompt in trace output (default: true).`,"tools.exec.applyPatch.enabled":`Experimental. Enables apply_patch for OpenAI models when allowed by tool policy.`,"tools.exec.applyPatch.workspaceOnly":`Restrict apply_patch paths to the workspace directory (default: true). Set false to allow writing outside the workspace (dangerous).`,"tools.exec.applyPatch.allowModels":`Optional allowlist of model ids (e.g. "gpt-5.2" or "openai/gpt-5.2").`,"tools.loopDetection.enabled":`Enable repetitive tool-call loop detection and backoff safety checks (default: false).`,"tools.loopDetection.historySize":`Tool history window size for loop detection (default: 30).`,"tools.loopDetection.warningThreshold":`Warning threshold for repetitive patterns when detector is enabled (default: 10).`,"tools.loopDetection.criticalThreshold":`Critical threshold for repetitive patterns when detector is enabled (default: 20).`,"tools.loopDetection.globalCircuitBreakerThreshold":`Global no-progress breaker threshold (default: 30).`,"tools.loopDetection.detectors.genericRepeat":`Enable generic repeated same-tool/same-params loop detection (default: true).`,"tools.loopDetection.detectors.knownPollNoProgress":`Enable known poll tool no-progress loop detection (default: true).`,"tools.loopDetection.detectors.pingPong":`Enable ping-pong loop detection (default: true).`,"tools.exec.notifyOnExit":`When true (default), backgrounded exec sessions enqueue a system event and request a heartbeat on exit.`,"tools.exec.notifyOnExitEmptySuccess":`When true, successful backgrounded exec exits with empty output still enqueue a completion system event (default: false).`,"tools.exec.pathPrepend":`Directories to prepend to PATH for exec runs (gateway/sandbox).`,"tools.exec.safeBins":`Allow stdin-only safe binaries to run without explicit allowlist entries.`,"tools.fs.workspaceOnly":`Restrict filesystem tools (read/write/edit/apply_patch) to the workspace directory (default: false).`,"tools.fs.convergedFileTools":`Back write/edit with the SHARED cross-surface tool definitions (and add delete_file/list_files) instead of the native on-prem copies. Same model-facing names, same workspace confinement as tools.fs.workspaceOnly; non-sandboxed sessions only (default: true).`,"tools.sessions.visibility":`Controls which sessions can be targeted by sessions_list/sessions_history/sessions_send. ("tree" default = current session + spawned subagent sessions; "self" = only current; "agent" = any session in the current agent id; "all" = any session; cross-agent still requires tools.agentToAgent).`,"tools.message.allowCrossContextSend":`Legacy override: allow cross-context sends across all providers.`,"tools.message.crossContext.allowWithinProvider":`Allow sends to other channels within the same provider (default: true).`,"tools.message.crossContext.allowAcrossProviders":`Allow sends across different providers (default: false).`,"tools.message.crossContext.marker.enabled":`Add a visible origin marker when sending cross-context (default: true).`,"tools.message.crossContext.marker.prefix":`Text prefix for cross-context markers (supports "{channel}").`,"tools.message.crossContext.marker.suffix":`Text suffix for cross-context markers (supports "{channel}").`,"tools.message.broadcast.enabled":`Enable broadcast action (default: true).`,"tools.web.search.enabled":`Enable the web_search tool (requires a provider API key).`,"tools.web.search.provider":`Search provider ("brave" or "perplexity").`,"tools.web.search.apiKey":`Brave Search API key (fallback: BRAVE_API_KEY env var).`,"tools.web.search.maxResults":`Default number of results to return (1-10).`,"tools.web.search.timeoutSeconds":`Timeout in seconds for web_search requests.`,"tools.web.search.cacheTtlMinutes":`Cache TTL in minutes for web_search results.`,"tools.web.search.keylessFallback":`Let web_search fall back to a keyless index when the selected provider has no API key (default: off). Opt-in because it adds outbound requests the operator did not configure.`,"tools.web.search.keyless.searxngUrl":`Base URL of a SearXNG instance you run. Used by the keyless adapter in preference to Wikipedia; the instance needs formats: [json] enabled.`,"tools.web.search.perplexity.apiKey":`Perplexity or OpenRouter API key (fallback: PERPLEXITY_API_KEY or OPENROUTER_API_KEY env var).`,"tools.web.search.perplexity.baseUrl":`Perplexity base URL override (default: https://openrouter.ai/api/v1 or https://api.perplexity.ai).`,"tools.web.search.perplexity.model":`Perplexity model override (default: "perplexity/sonar-pro").`,"tools.web.fetch.enabled":`Enable the web_fetch tool (lightweight HTTP fetch).`,"tools.web.fetch.maxChars":`Max characters returned by web_fetch (truncated).`,"tools.web.fetch.maxCharsCap":`Hard cap for web_fetch maxChars (applies to config and tool calls).`,"tools.web.fetch.timeoutSeconds":`Timeout in seconds for web_fetch requests.`,"tools.web.fetch.cacheTtlMinutes":`Cache TTL in minutes for web_fetch results.`,"tools.web.fetch.maxRedirects":`Maximum redirects allowed for web_fetch (default: 3).`,"tools.web.fetch.userAgent":`Override User-Agent header for web_fetch requests.`,"tools.web.fetch.readability":`Use Readability to extract main content from HTML (fallbacks to basic HTML cleanup).`,"tools.web.fetch.firecrawl.enabled":`Enable Firecrawl fallback for web_fetch (if configured).`,"tools.web.fetch.firecrawl.apiKey":`Firecrawl API key (fallback: FIRECRAWL_API_KEY env var).`,"tools.web.fetch.firecrawl.baseUrl":`Firecrawl base URL (e.g. https://api.firecrawl.dev or custom endpoint).`,"tools.web.fetch.firecrawl.onlyMainContent":`When true, Firecrawl returns only the main content (default: true).`,"tools.web.fetch.firecrawl.maxAgeMs":`Firecrawl maxAge (ms) for cached results when supported by the API.`,"tools.web.fetch.firecrawl.timeoutSeconds":`Timeout in seconds for Firecrawl requests.`,"channels.slack.allowBots":`Allow bot-authored messages to trigger Slack replies (default: false).`,"channels.slack.thread.historyScope":`Scope for Slack thread history context ("thread" isolates per thread; "channel" reuses channel history).`,"channels.slack.thread.inheritParent":`If true, Slack thread sessions inherit the parent channel transcript (default: false).`,"channels.slack.thread.initialHistoryLimit":`Maximum number of existing Slack thread messages to fetch when starting a new thread session (default: 20, set to 0 to disable).`,"channels.mattermost.botToken":`Bot token from Mattermost System Console -> Integrations -> Bot Accounts.`,"channels.mattermost.baseUrl":`Base URL for your Mattermost server (e.g., https://chat.example.com).`,"channels.mattermost.chatmode":`Reply to channel messages on mention ("oncall"), on trigger chars (">" or "!") ("onchar"), or on every message ("onmessage").`,"channels.mattermost.oncharPrefixes":`Trigger prefixes for onchar mode (default: [">", "!"]).`,"channels.mattermost.requireMention":`Require @mention in channels before responding (default: true).`,"auth.profiles":`Named auth profiles (provider + mode + optional email).`,"auth.order":`Ordered auth profile IDs per provider (used for automatic failover).`,"auth.cooldowns.billingBackoffHours":`Base backoff (hours) when a profile fails due to billing/insufficient credits (default: 5).`,"auth.cooldowns.billingBackoffHoursByProvider":`Optional per-provider overrides for billing backoff (hours).`,"auth.cooldowns.billingMaxHours":`Cap (hours) for billing backoff (default: 24).`,"auth.cooldowns.failureWindowHours":`Failure window (hours) for backoff counters (default: 24).`,"agents.defaults.bootstrapMaxChars":`Max characters of each workspace bootstrap file injected into the system prompt before truncation (default: 20000).`,"agents.defaults.bootstrapTotalMaxChars":`Max total characters across all injected workspace bootstrap files (default: 150000).`,"agents.defaults.repoRoot":`Optional repository root shown in the system prompt runtime line (overrides auto-detect).`,"agents.defaults.envelopeTimezone":`Timezone for message envelopes ("utc", "local", "user", or an IANA timezone string).`,"agents.defaults.envelopeTimestamp":`Include absolute timestamps in message envelopes ("on" or "off").`,"agents.defaults.envelopeElapsed":`Include elapsed time in message envelopes ("on" or "off").`,"agents.defaults.models":`Configured model catalog (keys are full provider/model IDs).`,"agents.defaults.memorySearch":`Vector search over .builderforce/MEMORY.md and .builderforce/memory/*.md (per-agent overrides supported).`,"agents.defaults.memorySearch.sources":`Sources to index for memory search (default: ["memory"]; add "sessions" to include session transcripts).`,"agents.defaults.memorySearch.extraPaths":`Extra paths to include in memory search (directories or .md files; relative paths resolved from workspace).`,"agents.defaults.memorySearch.experimental.sessionMemory":`Enable experimental session transcript indexing for memory search (default: false).`,"agents.defaults.memorySearch.provider":`Embedding provider ("openai", "gemini", "voyage", or "local").`,"agents.defaults.memorySearch.remote.baseUrl":`Custom base URL for remote embeddings (OpenAI-compatible proxies or Gemini overrides).`,"agents.defaults.memorySearch.remote.apiKey":`Custom API key for the remote embedding provider.`,"agents.defaults.memorySearch.remote.headers":`Extra headers for remote embeddings (merged; remote overrides OpenAI headers).`,"agents.defaults.memorySearch.remote.batch.enabled":`Enable batch API for memory embeddings (OpenAI/Gemini; default: true).`,"agents.defaults.memorySearch.remote.batch.wait":`Wait for batch completion when indexing (default: true).`,"agents.defaults.memorySearch.remote.batch.concurrency":`Max concurrent embedding batch jobs for memory indexing (default: 2).`,"agents.defaults.memorySearch.remote.batch.pollIntervalMs":`Polling interval in ms for batch status (default: 2000).`,"agents.defaults.memorySearch.remote.batch.timeoutMinutes":`Timeout in minutes for batch indexing (default: 60).`,"agents.defaults.memorySearch.local.modelPath":`Local GGUF model path or hf: URI (node-llama-cpp).`,"agents.defaults.memorySearch.fallback":`Fallback provider when embeddings fail ("openai", "gemini", "local", or "none").`,"agents.defaults.memorySearch.store.path":`SQLite index path (default: ~/.builderforce/memory/{agentId}.sqlite).`,"agents.defaults.memorySearch.store.vector.enabled":`Enable sqlite-vec extension for vector search (default: true).`,"agents.defaults.memorySearch.store.vector.extensionPath":`Optional override path to sqlite-vec extension library (.dylib/.so/.dll).`,"agents.defaults.memorySearch.query.hybrid.enabled":`Enable hybrid BM25 + vector search for memory (default: true).`,"agents.defaults.memorySearch.query.hybrid.vectorWeight":`Weight for vector similarity when merging results (0-1).`,"agents.defaults.memorySearch.query.hybrid.textWeight":`Weight for BM25 text relevance when merging results (0-1).`,"agents.defaults.memorySearch.query.hybrid.candidateMultiplier":`Multiplier for candidate pool size (default: 4).`,"agents.defaults.memorySearch.cache.enabled":`Cache chunk embeddings in SQLite to speed up reindexing and frequent updates (default: true).`,memory:`Memory backend configuration (global).`,"memory.backend":`Memory backend ("builtin" for BuilderForceAgents embeddings, "qmd" for QMD sidecar).`,"memory.citations":`Default citation behavior ("auto", "on", or "off").`,"memory.qmd.command":`Path to the qmd binary (default: resolves from PATH).`,"memory.qmd.includeDefaultMemory":`Whether to automatically index .builderforce/MEMORY.md + .builderforce/memory/**/*.md (default: true).`,"memory.qmd.paths":`Additional directories/files to index with QMD (path + optional glob pattern).`,"memory.qmd.paths.path":`Absolute or ~-relative path to index via QMD.`,"memory.qmd.paths.pattern":`Glob pattern relative to the path root (default: **/*.md).`,"memory.qmd.paths.name":`Optional stable name for the QMD collection (default derived from path).`,"memory.qmd.sessions.enabled":`Enable QMD session transcript indexing (experimental, default: false).`,"memory.qmd.sessions.exportDir":`Override directory for sanitized session exports before indexing.`,"memory.qmd.sessions.retentionDays":`Retention window for exported sessions before pruning (default: unlimited).`,"memory.qmd.update.interval":`How often the QMD sidecar refreshes indexes (duration string, default: 5m).`,"memory.qmd.update.debounceMs":`Minimum delay between successive QMD refresh runs (default: 15000).`,"memory.qmd.update.onBoot":`Run QMD update once on gateway startup (default: true).`,"memory.qmd.update.waitForBootSync":`Block startup until the boot QMD refresh finishes (default: false).`,"memory.qmd.update.embedInterval":`How often QMD embeddings are refreshed (duration string, default: 60m). Set to 0 to disable periodic embed.`,"memory.qmd.update.commandTimeoutMs":`Timeout for QMD maintenance commands like collection list/add (default: 30000).`,"memory.qmd.update.updateTimeoutMs":"Timeout for `qmd update` runs (default: 120000).","memory.qmd.update.embedTimeoutMs":"Timeout for `qmd embed` runs (default: 120000).","memory.qmd.limits.maxResults":`Max QMD results returned to the agent loop (default: 6).`,"memory.qmd.limits.maxSnippetChars":`Max characters per snippet pulled from QMD (default: 700).`,"memory.qmd.limits.maxInjectedChars":`Max total characters injected from QMD hits per turn.`,"memory.qmd.limits.timeoutMs":`Per-query timeout for QMD searches (default: 4000).`,"memory.qmd.scope":`Session/channel scope for QMD recall (same syntax as session.sendPolicy; default: direct-only). Use match.rawKeyPrefix to match full agent-prefixed session keys.`,"agents.defaults.memorySearch.cache.maxEntries":`Optional cap on cached embeddings (best-effort).`,"agents.defaults.memorySearch.sync.onSearch":`Lazy sync: schedule a reindex on search after changes.`,"agents.defaults.memorySearch.sync.watch":`Watch memory files for changes (chokidar).`,"agents.defaults.memorySearch.sync.sessions.deltaBytes":`Minimum appended bytes before session transcripts trigger reindex (default: 100000).`,"agents.defaults.memorySearch.sync.sessions.deltaMessages":`Minimum appended JSONL lines before session transcripts trigger reindex (default: 50).`,"plugins.enabled":`Enable plugin/extension loading (default: true).`,"plugins.allow":`Optional allowlist of plugin ids; when set, only listed plugins load.`,"plugins.deny":`Optional denylist of plugin ids; deny wins over allowlist.`,"plugins.load.paths":`Additional plugin files or directories to load.`,"plugins.slots":`Select which plugins own exclusive slots (memory, etc.).`,"plugins.slots.memory":`Select the active memory plugin by id, or "none" to disable memory plugins.`,"plugins.entries":`Per-plugin settings keyed by plugin id (enable/disable + config payloads).`,"plugins.entries.*.enabled":`Overrides plugin enable/disable for this entry (restart required).`,"plugins.entries.*.config":`Plugin-defined config payload (schema is provided by the plugin).`,"plugins.installs":"CLI-managed install metadata (used by `builderforce plugins update` to locate install sources).","plugins.installs.*.source":`Install source ("npm", "archive", or "path").`,"plugins.installs.*.spec":`Original npm spec used for install (if source is npm).`,"plugins.installs.*.sourcePath":`Original archive/path used for install (if any).`,"plugins.installs.*.installPath":`Resolved install directory (usually ~/.builderforce/extensions/<id>).`,"plugins.installs.*.version":`Version recorded at install time (if available).`,"plugins.installs.*.installedAt":`ISO timestamp of last install/update.`,"agents.list.*.identity.avatar":`Agent avatar (workspace-relative path, http(s) URL, or data URI).`,"agents.defaults.model.primary":`Primary model (provider/model).`,"agents.defaults.model.fallbacks":`Ordered fallback models (provider/model). Used when the primary model fails.`,"agents.defaults.imageModel.primary":`Optional image model (provider/model) used when the primary model lacks image input.`,"agents.defaults.imageModel.fallbacks":`Ordered fallback image models (provider/model).`,"agents.defaults.imageMaxDimensionPx":`Max image side length in pixels when sanitizing transcript/tool-result image payloads (default: 1200).`,"agents.defaults.cliBackends":`Optional CLI backends for text-only fallback (claude-cli, etc.).`,"agents.defaults.humanDelay.mode":`Delay style for block replies ("off", "natural", "custom").`,"agents.defaults.humanDelay.minMs":`Minimum delay in ms for custom humanDelay (default: 800).`,"agents.defaults.humanDelay.maxMs":`Maximum delay in ms for custom humanDelay (default: 2500).`,"commands.native":`Register native commands with channels that support it (Discord/Slack/Telegram).`,"commands.nativeSkills":`Register native skill commands (user-invocable skills) with channels that support it.`,"commands.text":`Allow text command parsing (slash commands only).`,"commands.bash":"Allow bash chat command (`!`; `/bash` alias) to run host shell commands (default: false; requires tools.elevated).","commands.bashForegroundMs":`How long bash waits before backgrounding (default: 2000; 0 backgrounds immediately).`,"commands.config":`Allow /config chat command to read/write config on disk (default: false).`,"commands.debug":`Allow /debug chat command for runtime-only overrides (default: false).`,"commands.restart":`Allow /restart and gateway restart tool actions (default: false).`,"commands.useAccessGroups":`Enforce access-group allowlists/policies for commands.`,"commands.ownerAllowFrom":`Explicit owner allowlist for owner-only tools/commands. Use channel-native IDs (optionally prefixed like "whatsapp:+15551234567"). '*' is ignored.`,"cron.enabled":`Enable the cron scheduler in the gateway (default: true). Set to false to stop scheduled jobs from running; useful when the gateway is unstable or you want to reduce activity.`,"session.dmScope":`DM session scoping: "main" keeps continuity; "per-peer", "per-channel-peer", or "per-account-channel-peer" isolates DM history (recommended for shared inboxes/multi-account).`,"session.identityLinks":`Map canonical identities to provider-prefixed peer IDs for DM session linking (example: telegram:123456).`,"channels.telegram.configWrites":`Allow Telegram to write config in response to channel events/commands (default: true).`,"channels.slack.configWrites":`Allow Slack to write config in response to channel events/commands (default: true).`,"channels.mattermost.configWrites":`Allow Mattermost to write config in response to channel events/commands (default: true).`,"channels.discord.configWrites":`Allow Discord to write config in response to channel events/commands (default: true).`,"channels.discord.proxy":`Proxy URL for Discord gateway + API requests (app-id lookup and allowlist resolution). Set per account via channels.discord.accounts.<id>.proxy.`,"channels.whatsapp.configWrites":`Allow WhatsApp to write config in response to channel events/commands (default: true).`,"channels.signal.configWrites":`Allow Signal to write config in response to channel events/commands (default: true).`,"channels.imessage.configWrites":`Allow iMessage to write config in response to channel events/commands (default: true).`,"channels.msteams.configWrites":`Allow Microsoft Teams to write config in response to channel events/commands (default: true).`,...IRC_FIELD_HELP,"channels.discord.commands.native":`Override native commands for Discord (bool or "auto").`,"channels.discord.commands.nativeSkills":`Override native skill commands for Discord (bool or "auto").`,"channels.telegram.commands.native":`Override native commands for Telegram (bool or "auto").`,"channels.telegram.commands.nativeSkills":`Override native skill commands for Telegram (bool or "auto").`,"channels.slack.commands.native":`Override native commands for Slack (bool or "auto").`,"channels.slack.commands.nativeSkills":`Override native skill commands for Slack (bool or "auto").`,"channels.slack.streamMode":`Live stream preview mode for Slack replies (replace | status_final | append).`,"session.agentToAgent.maxPingPongTurns":`Max reply-back turns between requester and target (0–5).`,"channels.telegram.customCommands":`Additional Telegram bot menu commands (merged with native; conflicts ignored).`,"messages.suppressToolErrors":`When true, suppress ⚠️ tool-error warnings from being shown to the user. The agent already sees errors in context and can retry. Default: false.`,"messages.ackReaction":`Emoji reaction used to acknowledge inbound messages (empty disables).`,"messages.ackReactionScope":`When to send ack reactions ("group-mentions", "group-all", "direct", "all").`,"messages.inbound.debounceMs":`Debounce window (ms) for batching rapid inbound messages from the same sender (0 to disable).`,"channels.telegram.dmPolicy":`Direct message access control ("pairing" recommended). "open" requires channels.telegram.allowFrom=["*"].`,"channels.telegram.streamMode":`Live stream preview mode for Telegram replies (off | partial | block). Separate from block streaming; uses sendMessage + editMessageText.`,"channels.telegram.draftChunk.minChars":`Minimum chars before emitting a Telegram stream preview update when channels.telegram.streamMode="block" (default: 200).`,"channels.telegram.draftChunk.maxChars":`Target max size for a Telegram stream preview chunk when channels.telegram.streamMode="block" (default: 800; clamped to channels.telegram.textChunkLimit).`,"channels.telegram.draftChunk.breakPreference":`Preferred breakpoints for Telegram draft chunks (paragraph | newline | sentence). Default: paragraph.`,"channels.telegram.retry.attempts":`Max retry attempts for outbound Telegram API calls (default: 3).`,"channels.telegram.retry.minDelayMs":`Minimum retry delay in ms for Telegram outbound calls.`,"channels.telegram.retry.maxDelayMs":`Maximum retry delay cap in ms for Telegram outbound calls.`,"channels.telegram.retry.jitter":`Jitter factor (0-1) applied to Telegram retry delays.`,"channels.telegram.network.autoSelectFamily":`Override Node autoSelectFamily for Telegram (true=enable, false=disable).`,"channels.telegram.timeoutSeconds":`Max seconds before Telegram API requests are aborted (default: 500 per grammY).`,"channels.whatsapp.dmPolicy":`Direct message access control ("pairing" recommended). "open" requires channels.whatsapp.allowFrom=["*"].`,"channels.whatsapp.selfChatMode":`Same-phone setup (bot uses your personal WhatsApp number).`,"channels.whatsapp.debounceMs":`Debounce window (ms) for batching rapid consecutive messages from the same sender (0 to disable).`,"channels.signal.dmPolicy":`Direct message access control ("pairing" recommended). "open" requires channels.signal.allowFrom=["*"].`,"channels.imessage.dmPolicy":`Direct message access control ("pairing" recommended). "open" requires channels.imessage.allowFrom=["*"].`,"channels.bluebubbles.dmPolicy":`Direct message access control ("pairing" recommended). "open" requires channels.bluebubbles.allowFrom=["*"].`,"channels.discord.dmPolicy":`Direct message access control ("pairing" recommended). "open" requires channels.discord.allowFrom=["*"].`,"channels.discord.dm.policy":`Direct message access control ("pairing" recommended). "open" requires channels.discord.allowFrom=["*"] (legacy: channels.discord.dm.allowFrom).`,"channels.discord.retry.attempts":`Max retry attempts for outbound Discord API calls (default: 3).`,"channels.discord.retry.minDelayMs":`Minimum retry delay in ms for Discord outbound calls.`,"channels.discord.retry.maxDelayMs":`Maximum retry delay cap in ms for Discord outbound calls.`,"channels.discord.retry.jitter":`Jitter factor (0-1) applied to Discord retry delays.`,"channels.discord.maxLinesPerMessage":`Soft max line count per Discord message (default: 17).`,"channels.discord.ui.components.accentColor":`Accent color for Discord component containers (hex). Set per account via channels.discord.accounts.<id>.ui.components.accentColor.`,"channels.discord.intents.presence":`Enable the Guild Presences privileged intent. Must also be enabled in the Discord Developer Portal. Allows tracking user activities (e.g. Spotify). Default: false.`,"channels.discord.intents.guildMembers":`Enable the Guild Members privileged intent. Must also be enabled in the Discord Developer Portal. Default: false.`,"channels.discord.pluralkit.enabled":`Resolve PluralKit proxied messages and treat system members as distinct senders.`,"channels.discord.pluralkit.token":`Optional PluralKit token for resolving private systems or members.`,"channels.discord.activity":`Discord presence activity text (defaults to custom status).`,"channels.discord.status":`Discord presence status (online, dnd, idle, invisible).`,"channels.discord.activityType":`Discord presence activity type (0=Playing,1=Streaming,2=Listening,3=Watching,4=Custom,5=Competing).`,"channels.discord.activityUrl":`Discord presence streaming URL (required for activityType=1).`,"channels.slack.dm.policy":`Direct message access control ("pairing" recommended). "open" requires channels.slack.allowFrom=["*"] (legacy: channels.slack.dm.allowFrom).`,"channels.slack.dmPolicy":`Direct message access control ("pairing" recommended). "open" requires channels.slack.allowFrom=["*"].`},FIELD_LABELS={"meta.lastTouchedVersion":`Config Last Touched Version`,"meta.lastTouchedAt":`Config Last Touched At`,"update.channel":`Update Channel`,"update.checkOnStart":`Update Check on Start`,"diagnostics.enabled":`Diagnostics Enabled`,"diagnostics.flags":`Diagnostics Flags`,"diagnostics.otel.enabled":`OpenTelemetry Enabled`,"diagnostics.otel.endpoint":`OpenTelemetry Endpoint`,"diagnostics.otel.protocol":`OpenTelemetry Protocol`,"diagnostics.otel.headers":`OpenTelemetry Headers`,"diagnostics.otel.serviceName":`OpenTelemetry Service Name`,"diagnostics.otel.traces":`OpenTelemetry Traces Enabled`,"diagnostics.otel.metrics":`OpenTelemetry Metrics Enabled`,"diagnostics.otel.logs":`OpenTelemetry Logs Enabled`,"diagnostics.otel.sampleRate":`OpenTelemetry Trace Sample Rate`,"diagnostics.otel.flushIntervalMs":`OpenTelemetry Flush Interval (ms)`,"diagnostics.cacheTrace.enabled":`Cache Trace Enabled`,"diagnostics.cacheTrace.filePath":`Cache Trace File Path`,"diagnostics.cacheTrace.includeMessages":`Cache Trace Include Messages`,"diagnostics.cacheTrace.includePrompt":`Cache Trace Include Prompt`,"diagnostics.cacheTrace.includeSystem":`Cache Trace Include System`,"agents.list.*.identity.avatar":`Identity Avatar`,"agents.list.*.skills":`Agent Skill Filter`,"gateway.remote.url":`Remote Gateway URL`,"gateway.remote.sshTarget":`Remote Gateway SSH Target`,"gateway.remote.sshIdentity":`Remote Gateway SSH Identity`,"gateway.remote.token":`Remote Gateway Token`,"gateway.remote.password":`Remote Gateway Password`,"gateway.remote.tlsFingerprint":`Remote Gateway TLS Fingerprint`,"gateway.auth.token":`Gateway Token`,"gateway.auth.password":`Gateway Password`,"tools.media.image.enabled":`Enable Image Understanding`,"tools.media.image.maxBytes":`Image Understanding Max Bytes`,"tools.media.image.maxChars":`Image Understanding Max Chars`,"tools.media.image.prompt":`Image Understanding Prompt`,"tools.media.image.timeoutSeconds":`Image Understanding Timeout (sec)`,"tools.media.image.attachments":`Image Understanding Attachment Policy`,"tools.media.image.models":`Image Understanding Models`,"tools.media.image.scope":`Image Understanding Scope`,"tools.media.models":`Media Understanding Shared Models`,"tools.media.concurrency":`Media Understanding Concurrency`,"tools.media.audio.enabled":`Enable Audio Understanding`,"tools.media.audio.maxBytes":`Audio Understanding Max Bytes`,"tools.media.audio.maxChars":`Audio Understanding Max Chars`,"tools.media.audio.prompt":`Audio Understanding Prompt`,"tools.media.audio.timeoutSeconds":`Audio Understanding Timeout (sec)`,"tools.media.audio.language":`Audio Understanding Language`,"tools.media.audio.attachments":`Audio Understanding Attachment Policy`,"tools.media.audio.models":`Audio Understanding Models`,"tools.media.audio.scope":`Audio Understanding Scope`,"tools.media.video.enabled":`Enable Video Understanding`,"tools.media.video.maxBytes":`Video Understanding Max Bytes`,"tools.media.video.maxChars":`Video Understanding Max Chars`,"tools.media.video.prompt":`Video Understanding Prompt`,"tools.media.video.timeoutSeconds":`Video Understanding Timeout (sec)`,"tools.media.video.attachments":`Video Understanding Attachment Policy`,"tools.media.video.models":`Video Understanding Models`,"tools.media.video.scope":`Video Understanding Scope`,"tools.links.enabled":`Enable Link Understanding`,"tools.links.maxLinks":`Link Understanding Max Links`,"tools.links.timeoutSeconds":`Link Understanding Timeout (sec)`,"tools.links.models":`Link Understanding Models`,"tools.links.scope":`Link Understanding Scope`,"tools.profile":`Tool Profile`,"tools.alsoAllow":`Tool Allowlist Additions`,"agents.list[].tools.profile":`Agent Tool Profile`,"agents.list[].tools.alsoAllow":`Agent Tool Allowlist Additions`,"tools.byProvider":`Tool Policy by Provider`,"agents.list[].tools.byProvider":`Agent Tool Policy by Provider`,"tools.exec.applyPatch.enabled":`Enable apply_patch`,"tools.exec.applyPatch.workspaceOnly":`apply_patch Workspace-Only`,"tools.exec.applyPatch.allowModels":`apply_patch Model Allowlist`,"tools.loopDetection.enabled":`Tool-loop Detection`,"tools.loopDetection.historySize":`Tool-loop History Size`,"tools.loopDetection.warningThreshold":`Tool-loop Warning Threshold`,"tools.loopDetection.criticalThreshold":`Tool-loop Critical Threshold`,"tools.loopDetection.globalCircuitBreakerThreshold":`Tool-loop Global Circuit Breaker Threshold`,"tools.loopDetection.detectors.genericRepeat":`Tool-loop Generic Repeat Detection`,"tools.loopDetection.detectors.knownPollNoProgress":`Tool-loop Poll No-Progress Detection`,"tools.loopDetection.detectors.pingPong":`Tool-loop Ping-Pong Detection`,"tools.fs.workspaceOnly":`Workspace-only FS tools`,"tools.fs.convergedFileTools":`Converged (shared) file tools`,"tools.sessions.visibility":`Session Tools Visibility`,"tools.exec.notifyOnExit":`Exec Notify On Exit`,"tools.exec.notifyOnExitEmptySuccess":`Exec Notify On Empty Success`,"tools.exec.approvalRunningNoticeMs":`Exec Approval Running Notice (ms)`,"tools.exec.host":`Exec Host`,"tools.exec.security":`Exec Security`,"tools.exec.ask":`Exec Ask`,"tools.exec.node":`Exec Node Binding`,"tools.exec.pathPrepend":`Exec PATH Prepend`,"tools.exec.safeBins":`Exec Safe Bins`,"tools.message.allowCrossContextSend":`Allow Cross-Context Messaging`,"tools.message.crossContext.allowWithinProvider":`Allow Cross-Context (Same Provider)`,"tools.message.crossContext.allowAcrossProviders":`Allow Cross-Context (Across Providers)`,"tools.message.crossContext.marker.enabled":`Cross-Context Marker`,"tools.message.crossContext.marker.prefix":`Cross-Context Marker Prefix`,"tools.message.crossContext.marker.suffix":`Cross-Context Marker Suffix`,"tools.message.broadcast.enabled":`Enable Message Broadcast`,"tools.web.search.enabled":`Enable Web Search Tool`,"tools.web.search.provider":`Web Search Provider`,"tools.web.search.apiKey":`Brave Search API Key`,"tools.web.search.maxResults":`Web Search Max Results`,"tools.web.search.timeoutSeconds":`Web Search Timeout (sec)`,"tools.web.search.cacheTtlMinutes":`Web Search Cache TTL (min)`,"tools.web.search.keylessFallback":`Web Search Keyless Fallback`,"tools.web.search.keyless.searxngUrl":`Web Search SearXNG URL`,"tools.web.fetch.enabled":`Enable Web Fetch Tool`,"tools.web.fetch.maxChars":`Web Fetch Max Chars`,"tools.web.fetch.timeoutSeconds":`Web Fetch Timeout (sec)`,"tools.web.fetch.cacheTtlMinutes":`Web Fetch Cache TTL (min)`,"tools.web.fetch.maxRedirects":`Web Fetch Max Redirects`,"tools.web.fetch.userAgent":`Web Fetch User-Agent`,"gateway.controlUi.basePath":`Control UI Base Path`,"gateway.controlUi.root":`Control UI Assets Root`,"gateway.controlUi.allowedOrigins":`Control UI Allowed Origins`,"gateway.controlUi.allowInsecureAuth":`Allow Insecure Control UI Auth`,"gateway.controlUi.dangerouslyDisableDeviceAuth":`Dangerously Disable Control UI Device Auth`,"gateway.http.endpoints.chatCompletions.enabled":`OpenAI Chat Completions Endpoint`,"gateway.reload.mode":`Config Reload Mode`,"gateway.reload.debounceMs":`Config Reload Debounce (ms)`,"gateway.nodes.browser.mode":`Gateway Node Browser Mode`,"gateway.nodes.browser.node":`Gateway Node Browser Pin`,"gateway.nodes.allowCommands":`Gateway Node Allowlist (Extra Commands)`,"gateway.nodes.denyCommands":`Gateway Node Denylist`,"nodeHost.browserProxy.enabled":`Node Browser Proxy Enabled`,"nodeHost.browserProxy.allowProfiles":`Node Browser Proxy Allowed Profiles`,"skills.load.watch":`Watch Skills`,"skills.load.watchDebounceMs":`Skills Watch Debounce (ms)`,"agents.defaults.workspace":`Workspace`,"agents.defaults.repoRoot":`Repo Root`,"agents.defaults.bootstrapMaxChars":`Bootstrap Max Chars`,"agents.defaults.bootstrapTotalMaxChars":`Bootstrap Total Max Chars`,"agents.defaults.envelopeTimezone":`Envelope Timezone`,"agents.defaults.envelopeTimestamp":`Envelope Timestamp`,"agents.defaults.envelopeElapsed":`Envelope Elapsed`,"agents.defaults.memorySearch":`Memory Search`,"agents.defaults.memorySearch.enabled":`Enable Memory Search`,"agents.defaults.memorySearch.sources":`Memory Search Sources`,"agents.defaults.memorySearch.extraPaths":`Extra Memory Paths`,"agents.defaults.memorySearch.experimental.sessionMemory":`Memory Search Session Index (Experimental)`,"agents.defaults.memorySearch.provider":`Memory Search Provider`,"agents.defaults.memorySearch.remote.baseUrl":`Remote Embedding Base URL`,"agents.defaults.memorySearch.remote.apiKey":`Remote Embedding API Key`,"agents.defaults.memorySearch.remote.headers":`Remote Embedding Headers`,"agents.defaults.memorySearch.remote.batch.concurrency":`Remote Batch Concurrency`,"agents.defaults.memorySearch.model":`Memory Search Model`,"agents.defaults.memorySearch.fallback":`Memory Search Fallback`,"agents.defaults.memorySearch.local.modelPath":`Local Embedding Model Path`,"agents.defaults.memorySearch.store.path":`Memory Search Index Path`,"agents.defaults.memorySearch.store.vector.enabled":`Memory Search Vector Index`,"agents.defaults.memorySearch.store.vector.extensionPath":`Memory Search Vector Extension Path`,"agents.defaults.memorySearch.chunking.tokens":`Memory Chunk Tokens`,"agents.defaults.memorySearch.chunking.overlap":`Memory Chunk Overlap Tokens`,"agents.defaults.memorySearch.sync.onSessionStart":`Index on Session Start`,"agents.defaults.memorySearch.sync.onSearch":`Index on Search (Lazy)`,"agents.defaults.memorySearch.sync.watch":`Watch Memory Files`,"agents.defaults.memorySearch.sync.watchDebounceMs":`Memory Watch Debounce (ms)`,"agents.defaults.memorySearch.sync.sessions.deltaBytes":`Session Delta Bytes`,"agents.defaults.memorySearch.sync.sessions.deltaMessages":`Session Delta Messages`,"agents.defaults.memorySearch.query.maxResults":`Memory Search Max Results`,"agents.defaults.memorySearch.query.minScore":`Memory Search Min Score`,"agents.defaults.memorySearch.query.hybrid.enabled":`Memory Search Hybrid`,"agents.defaults.memorySearch.query.hybrid.vectorWeight":`Memory Search Vector Weight`,"agents.defaults.memorySearch.query.hybrid.textWeight":`Memory Search Text Weight`,"agents.defaults.memorySearch.query.hybrid.candidateMultiplier":`Memory Search Hybrid Candidate Multiplier`,"agents.defaults.memorySearch.cache.enabled":`Memory Search Embedding Cache`,"agents.defaults.memorySearch.cache.maxEntries":`Memory Search Embedding Cache Max Entries`,memory:`Memory`,"memory.backend":`Memory Backend`,"memory.citations":`Memory Citations Mode`,"memory.qmd.command":`QMD Binary`,"memory.qmd.includeDefaultMemory":`QMD Include Default Memory`,"memory.qmd.paths":`QMD Extra Paths`,"memory.qmd.paths.path":`QMD Path`,"memory.qmd.paths.pattern":`QMD Path Pattern`,"memory.qmd.paths.name":`QMD Path Name`,"memory.qmd.sessions.enabled":`QMD Session Indexing`,"memory.qmd.sessions.exportDir":`QMD Session Export Directory`,"memory.qmd.sessions.retentionDays":`QMD Session Retention (days)`,"memory.qmd.update.interval":`QMD Update Interval`,"memory.qmd.update.debounceMs":`QMD Update Debounce (ms)`,"memory.qmd.update.onBoot":`QMD Update on Startup`,"memory.qmd.update.waitForBootSync":`QMD Wait for Boot Sync`,"memory.qmd.update.embedInterval":`QMD Embed Interval`,"memory.qmd.update.commandTimeoutMs":`QMD Command Timeout (ms)`,"memory.qmd.update.updateTimeoutMs":`QMD Update Timeout (ms)`,"memory.qmd.update.embedTimeoutMs":`QMD Embed Timeout (ms)`,"memory.qmd.limits.maxResults":`QMD Max Results`,"memory.qmd.limits.maxSnippetChars":`QMD Max Snippet Chars`,"memory.qmd.limits.maxInjectedChars":`QMD Max Injected Chars`,"memory.qmd.limits.timeoutMs":`QMD Search Timeout (ms)`,"memory.qmd.scope":`QMD Surface Scope`,"auth.profiles":`Auth Profiles`,"auth.order":`Auth Profile Order`,"auth.cooldowns.billingBackoffHours":`Billing Backoff (hours)`,"auth.cooldowns.billingBackoffHoursByProvider":`Billing Backoff Overrides`,"auth.cooldowns.billingMaxHours":`Billing Backoff Cap (hours)`,"auth.cooldowns.failureWindowHours":`Failover Window (hours)`,"agents.defaults.models":`Models`,"agents.defaults.model.primary":`Primary Model`,"agents.defaults.model.fallbacks":`Model Fallbacks`,"agents.defaults.imageModel.primary":`Image Model`,"agents.defaults.imageModel.fallbacks":`Image Model Fallbacks`,"agents.defaults.imageMaxDimensionPx":`Image Max Dimension (px)`,"agents.defaults.humanDelay.mode":`Human Delay Mode`,"agents.defaults.humanDelay.minMs":`Human Delay Min (ms)`,"agents.defaults.humanDelay.maxMs":`Human Delay Max (ms)`,"agents.defaults.cliBackends":`CLI Backends`,"commands.native":`Native Commands`,"commands.nativeSkills":`Native Skill Commands`,"commands.text":`Text Commands`,"commands.bash":`Allow Bash Chat Command`,"commands.bashForegroundMs":`Bash Foreground Window (ms)`,"commands.config":`Allow /config`,"commands.debug":`Allow /debug`,"commands.restart":`Allow Restart`,"commands.useAccessGroups":`Use Access Groups`,"commands.ownerAllowFrom":`Command Owners`,"ui.seamColor":`Accent Color`,"ui.assistant.name":`Assistant Name`,"ui.assistant.avatar":`Assistant Avatar`,"browser.evaluateEnabled":`Browser Evaluate Enabled`,"browser.snapshotDefaults":`Browser Snapshot Defaults`,"browser.snapshotDefaults.mode":`Browser Snapshot Mode`,"browser.remoteCdpTimeoutMs":`Remote CDP Timeout (ms)`,"browser.remoteCdpHandshakeTimeoutMs":`Remote CDP Handshake Timeout (ms)`,"session.dmScope":`DM Session Scope`,"session.agentToAgent.maxPingPongTurns":`Agent-to-Agent Ping-Pong Turns`,"messages.suppressToolErrors":`Suppress Tool Error Warnings`,"messages.ackReaction":`Ack Reaction Emoji`,"messages.ackReactionScope":`Ack Reaction Scope`,"messages.inbound.debounceMs":`Inbound Message Debounce (ms)`,"talk.apiKey":`Talk API Key`,"channels.whatsapp":`WhatsApp`,"channels.telegram":`Telegram`,"channels.telegram.customCommands":`Telegram Custom Commands`,"channels.discord":`Discord`,"channels.slack":`Slack`,"channels.mattermost":`Mattermost`,"channels.signal":`Signal`,"channels.imessage":`iMessage`,"channels.bluebubbles":`BlueBubbles`,"channels.msteams":`MS Teams`,...IRC_FIELD_LABELS,"channels.telegram.botToken":`Telegram Bot Token`,"channels.telegram.dmPolicy":`Telegram DM Policy`,"channels.telegram.streamMode":`Telegram Stream Mode`,"channels.telegram.draftChunk.minChars":`Telegram Draft Chunk Min Chars`,"channels.telegram.draftChunk.maxChars":`Telegram Draft Chunk Max Chars`,"channels.telegram.draftChunk.breakPreference":`Telegram Draft Chunk Break Preference`,"channels.telegram.retry.attempts":`Telegram Retry Attempts`,"channels.telegram.retry.minDelayMs":`Telegram Retry Min Delay (ms)`,"channels.telegram.retry.maxDelayMs":`Telegram Retry Max Delay (ms)`,"channels.telegram.retry.jitter":`Telegram Retry Jitter`,"channels.telegram.network.autoSelectFamily":`Telegram autoSelectFamily`,"channels.telegram.timeoutSeconds":`Telegram API Timeout (seconds)`,"channels.telegram.capabilities.inlineButtons":`Telegram Inline Buttons`,"channels.whatsapp.dmPolicy":`WhatsApp DM Policy`,"channels.whatsapp.selfChatMode":`WhatsApp Self-Phone Mode`,"channels.whatsapp.debounceMs":`WhatsApp Message Debounce (ms)`,"channels.signal.dmPolicy":`Signal DM Policy`,"channels.imessage.dmPolicy":`iMessage DM Policy`,"channels.bluebubbles.dmPolicy":`BlueBubbles DM Policy`,"channels.discord.dmPolicy":`Discord DM Policy`,"channels.discord.dm.policy":`Discord DM Policy`,"channels.discord.retry.attempts":`Discord Retry Attempts`,"channels.discord.retry.minDelayMs":`Discord Retry Min Delay (ms)`,"channels.discord.retry.maxDelayMs":`Discord Retry Max Delay (ms)`,"channels.discord.retry.jitter":`Discord Retry Jitter`,"channels.discord.maxLinesPerMessage":`Discord Max Lines Per Message`,"channels.discord.ui.components.accentColor":`Discord Component Accent Color`,"channels.discord.intents.presence":`Discord Presence Intent`,"channels.discord.intents.guildMembers":`Discord Guild Members Intent`,"channels.discord.pluralkit.enabled":`Discord PluralKit Enabled`,"channels.discord.pluralkit.token":`Discord PluralKit Token`,"channels.discord.activity":`Discord Presence Activity`,"channels.discord.status":`Discord Presence Status`,"channels.discord.activityType":`Discord Presence Activity Type`,"channels.discord.activityUrl":`Discord Presence Activity URL`,"channels.slack.dm.policy":`Slack DM Policy`,"channels.slack.dmPolicy":`Slack DM Policy`,"channels.slack.allowBots":`Slack Allow Bot Messages`,"channels.discord.token":`Discord Bot Token`,"channels.slack.botToken":`Slack Bot Token`,"channels.slack.appToken":`Slack App Token`,"channels.slack.userToken":`Slack User Token`,"channels.slack.userTokenReadOnly":`Slack User Token Read Only`,"channels.slack.streamMode":`Slack Stream Mode`,"channels.slack.thread.historyScope":`Slack Thread History Scope`,"channels.slack.thread.inheritParent":`Slack Thread Parent Inheritance`,"channels.slack.thread.initialHistoryLimit":`Slack Thread Initial History Limit`,"channels.mattermost.botToken":`Mattermost Bot Token`,"channels.mattermost.baseUrl":`Mattermost Base URL`,"channels.mattermost.chatmode":`Mattermost Chat Mode`,"channels.mattermost.oncharPrefixes":`Mattermost Onchar Prefixes`,"channels.mattermost.requireMention":`Mattermost Require Mention`,"channels.signal.account":`Signal Account`,"channels.imessage.cliPath":`iMessage CLI Path`,"agents.list[].skills":`Agent Skill Filter`,"agents.list[].identity.avatar":`Agent Avatar`,"discovery.mdns.mode":`mDNS Discovery Mode`,"plugins.enabled":`Enable Plugins`,"plugins.allow":`Plugin Allowlist`,"plugins.deny":`Plugin Denylist`,"plugins.load.paths":`Plugin Load Paths`,"plugins.slots":`Plugin Slots`,"plugins.slots.memory":`Memory Plugin`,"plugins.entries":`Plugin Entries`,"plugins.entries.*.enabled":`Plugin Enabled`,"plugins.entries.*.config":`Plugin Config`,"plugins.installs":`Plugin Install Records`,"plugins.installs.*.source":`Plugin Install Source`,"plugins.installs.*.spec":`Plugin Install Spec`,"plugins.installs.*.sourcePath":`Plugin Install Source Path`,"plugins.installs.*.installPath":`Plugin Install Path`,"plugins.installs.*.version":`Plugin Install Version`,"plugins.installs.*.installedAt":`Plugin Install Time`},log$4=createSubsystemLogger(`config/schema`),GROUP_LABELS={wizard:`Wizard`,update:`Update`,diagnostics:`Diagnostics`,logging:`Logging`,gateway:`Gateway`,nodeHost:`Node Host`,agents:`Agents`,tools:`Tools`,bindings:`Bindings`,audio:`Audio`,models:`Models`,messages:`Messages`,commands:`Commands`,session:`Session`,cron:`Cron`,hooks:`Hooks`,ui:`UI`,browser:`Browser`,talk:`Talk`,channels:`Messaging Channels`,skills:`Skills`,plugins:`Plugins`,discovery:`Discovery`,presence:`Presence`,voicewake:`Voice Wake`},GROUP_ORDER={wizard:20,update:25,diagnostics:27,gateway:30,nodeHost:35,agents:40,tools:50,bindings:55,audio:60,models:70,messages:80,commands:85,session:90,cron:100,hooks:110,ui:120,browser:130,talk:140,channels:150,skills:200,plugins:205,discovery:210,presence:220,voicewake:230,logging:900},FIELD_PLACEHOLDERS={"gateway.remote.url":`ws://host:18789`,"gateway.remote.tlsFingerprint":`sha256:ab12cd34…`,"gateway.remote.sshTarget":`user@host`,"gateway.controlUi.basePath":`/builderforce`,"gateway.controlUi.root":`dist/control-ui`,"gateway.controlUi.allowedOrigins":`https://control.example.com`,"channels.mattermost.baseUrl":`https://chat.example.com`,"agents.list[].identity.avatar":`avatars/builderforce.png`},NORMALIZED_SENSITIVE_KEY_WHITELIST_SUFFIXES=[`maxtokens`,`maxoutputtokens`,`maxinputtokens`,`maxcompletiontokens`,`contexttokens`,`totaltokens`,`tokencount`,`tokenlimit`,`tokenbudget`,`passwordFile`].map(suffix=>suffix.toLowerCase()),SENSITIVE_PATTERNS=[/token$/i,/password/i,/secret/i,/api.?key/i];function isWhitelistedSensitivePath(path){let lowerPath=path.toLowerCase();return NORMALIZED_SENSITIVE_KEY_WHITELIST_SUFFIXES.some(suffix=>lowerPath.endsWith(suffix))}function matchesSensitivePattern(path){return SENSITIVE_PATTERNS.some(pattern=>pattern.test(path))}function isSensitiveConfigPath(path){return!isWhitelistedSensitivePath(path)&&matchesSensitivePattern(path)}function buildBaseHints(){let hints={};for(let[group,label]of Object.entries(GROUP_LABELS))hints[group]={label,group:label,order:GROUP_ORDER[group]};for(let[path,label]of Object.entries(FIELD_LABELS)){let current=hints[path];hints[path]=current?{...current,label}:{label}}for(let[path,help]of Object.entries(FIELD_HELP)){let current=hints[path];hints[path]=current?{...current,help}:{help}}for(let[path,placeholder]of Object.entries(FIELD_PLACEHOLDERS)){let current=hints[path];hints[path]=current?{...current,placeholder}:{placeholder}}return hints}function applySensitiveHints(hints,allowedKeys){let next={...hints};for(let key of Object.keys(next))allowedKeys&&!allowedKeys.has(key)||next[key]?.sensitive===void 0&&isSensitiveConfigPath(key)&&(next[key]={...next[key],sensitive:!0});return next}function isUnwrappable(object){return!!object&&typeof object==`object`&&`unwrap`in object&&typeof object.unwrap==`function`&&!(object instanceof z.ZodArray)}function mapSensitivePaths(schema,path,hints){let next={...hints},currentSchema=schema,isSensitive=sensitive.has(currentSchema);for(;isUnwrappable(currentSchema);)currentSchema=currentSchema.unwrap(),isSensitive||=sensitive.has(currentSchema);if(isSensitive?next[path]={...next[path],sensitive:!0}:isSensitiveConfigPath(path)&&!next[path]?.sensitive&&log$4.warn(`possibly sensitive key found: (${path})`),currentSchema instanceof z.ZodObject){let shape=currentSchema.shape;for(let key in shape){let nextPath=path?`${path}.${key}`:key;next=mapSensitivePaths(shape[key],nextPath,next)}}else if(currentSchema instanceof z.ZodArray){let nextPath=path?`${path}[]`:`[]`;next=mapSensitivePaths(currentSchema.element,nextPath,next)}else if(currentSchema instanceof z.ZodRecord){let nextPath=path?`${path}.*`:`*`;next=mapSensitivePaths(currentSchema._def.valueType,nextPath,next)}else if(currentSchema instanceof z.ZodUnion||currentSchema instanceof z.ZodDiscriminatedUnion)for(let option of currentSchema.options)next=mapSensitivePaths(option,path,next);else currentSchema instanceof z.ZodIntersection&&(next=mapSensitivePaths(currentSchema._def.left,path,next),next=mapSensitivePaths(currentSchema._def.right,path,next));return next}const log$3=createSubsystemLogger(`config/redaction`),ENV_VAR_PLACEHOLDER_PATTERN=/^\$\{[^}]*\}$/;function isSensitivePath(path){return path.endsWith(`[]`)?isSensitiveConfigPath(path.slice(0,-2)):isSensitiveConfigPath(path)}function isEnvVarPlaceholder(value){return ENV_VAR_PLACEHOLDER_PATTERN.test(value.trim())}function isExtensionPath(path){return path===`plugins`||path.startsWith(`plugins.`)||path===`channels`||path.startsWith(`channels.`)}function isExplicitlyNonSensitivePath(hints,paths){return hints?paths.some(path=>hints[path]?.sensitive===!1):!1}const REDACTED_SENTINEL=`__BUILDERFORCE_AGENTS_REDACTED__`;function buildRedactionLookup(hints){let result=new Set;for(let[path,hint]of Object.entries(hints)){if(!hint.sensitive)continue;let parts=path.split(`.`),joinedPath=parts.shift()??``;result.add(joinedPath),joinedPath.endsWith(`[]`)&&result.add(joinedPath.slice(0,-2));for(let part of parts)part.endsWith(`[]`)&&result.add(`${joinedPath}.${part.slice(0,-2)}`),joinedPath=`${joinedPath}.${part}`,result.add(joinedPath)}return result.size!==0&&result.add(``),result}function redactObject(obj,hints){if(hints){let lookup=buildRedactionLookup(hints);return lookup.has(``)?redactObjectWithLookup(obj,lookup,``,[],hints):redactObjectGuessing(obj,``,[],hints)}else return redactObjectGuessing(obj,``,[])}function collectSensitiveValues(obj,hints){let result=[];if(hints){let lookup=buildRedactionLookup(hints);lookup.has(``)?redactObjectWithLookup(obj,lookup,``,result,hints):redactObjectGuessing(obj,``,result,hints)}else redactObjectGuessing(obj,``,result);return result}function redactObjectWithLookup(obj,lookup,prefix,values,hints){if(obj==null)return obj;if(Array.isArray(obj)){let path=`${prefix}[]`;return lookup.has(path)?obj.map(item=>typeof item==`string`&&!isEnvVarPlaceholder(item)?(values.push(item),REDACTED_SENTINEL):redactObjectWithLookup(item,lookup,path,values,hints)):isExtensionPath(prefix)?redactObjectGuessing(obj,prefix,values,hints):obj}if(typeof obj==`object`){let result={};for(let[key,value]of Object.entries(obj)){let path=prefix?`${prefix}.${key}`:key,wildcardPath=prefix?`${prefix}.*`:`*`,matched=!1;for(let candidate of[path,wildcardPath])if(result[key]=value,lookup.has(candidate)){matched=!0,typeof value==`string`&&!isEnvVarPlaceholder(value)?(result[key]=REDACTED_SENTINEL,values.push(value)):typeof value==`object`&&value&&(result[key]=redactObjectWithLookup(value,lookup,candidate,values,hints));break}if(!matched&&isExtensionPath(path)){let markedNonSensitive=isExplicitlyNonSensitivePath(hints,[path,wildcardPath]);typeof value==`string`&&!markedNonSensitive&&isSensitivePath(path)&&!isEnvVarPlaceholder(value)?(result[key]=REDACTED_SENTINEL,values.push(value)):typeof value==`object`&&value&&(result[key]=redactObjectGuessing(value,path,values,hints))}}return result}return obj}function redactObjectGuessing(obj,prefix,values,hints){if(obj==null)return obj;if(Array.isArray(obj))return obj.map(item=>{let path=`${prefix}[]`;return!isExplicitlyNonSensitivePath(hints,[path])&&isSensitivePath(path)&&typeof item==`string`&&!isEnvVarPlaceholder(item)?(values.push(item),REDACTED_SENTINEL):redactObjectGuessing(item,path,values,hints)});if(typeof obj==`object`){let result={};for(let[key,value]of Object.entries(obj)){let dotPath=prefix?`${prefix}.${key}`:key;!isExplicitlyNonSensitivePath(hints,[dotPath,prefix?`${prefix}.*`:`*`])&&isSensitivePath(dotPath)&&typeof value==`string`&&!isEnvVarPlaceholder(value)?(result[key]=REDACTED_SENTINEL,values.push(value)):typeof value==`object`&&value?result[key]=redactObjectGuessing(value,dotPath,values,hints):result[key]=value}return result}return obj}function redactRawText(raw,config,hints){let sensitiveValues=collectSensitiveValues(config,hints);sensitiveValues.sort((a,b)=>b.length-a.length);let result=raw;for(let value of sensitiveValues)result=result.replaceAll(value,REDACTED_SENTINEL);return result}function redactConfigObject(value,uiHints){return redactObject(value,uiHints)}function redactConfigSnapshot(snapshot,uiHints){if(!snapshot.valid)return{...snapshot,config:{},raw:null,parsed:null,resolved:{}};let redactedConfig=redactObject(snapshot.config,uiHints),redactedRaw=snapshot.raw?redactRawText(snapshot.raw,snapshot.config,uiHints):null,redactedParsed=snapshot.parsed?redactObject(snapshot.parsed,uiHints):snapshot.parsed,redactedResolved=redactConfigObject(snapshot.resolved,uiHints);return{...snapshot,config:redactedConfig,raw:redactedRaw,parsed:redactedParsed,resolved:redactedResolved}}function restoreRedactedValues(incoming,original,hints){if(incoming==null)return{ok:!1,error:`no input`};if(typeof incoming!=`object`)return{ok:!1,error:`input not an object`};try{if(hints){let lookup=buildRedactionLookup(hints);return lookup.has(``)?{ok:!0,result:restoreRedactedValuesWithLookup(incoming,original,lookup,``,hints)}:{ok:!0,result:restoreRedactedValuesGuessing(incoming,original,``,hints)}}else return{ok:!0,result:restoreRedactedValuesGuessing(incoming,original,``)}}catch(err){if(err instanceof RedactionError)return{ok:!1,humanReadableMessage:`Sentinel value "${REDACTED_SENTINEL}" in key ${err.key} is not valid as real data`};throw err}}var RedactionError=class extends Error{constructor(key){super(`internal error class---should never escape`),this.key=key,this.name=`RedactionError`}};function restoreOriginalValueOrThrow(params){if(params.key in params.original)return params.original[params.key];throw log$3.warn(`Cannot un-redact config key ${params.path} as it doesn't have any value`),new RedactionError(params.path)}function restoreRedactedValuesWithLookup(incoming,original,lookup,prefix,hints){if(typeof incoming!=`object`||!incoming)return incoming;if(Array.isArray(incoming)){let path=`${prefix}[]`;if(!lookup.has(path))return isExtensionPath(prefix)?restoreRedactedValuesGuessing(incoming,original,prefix,hints):incoming;let origArr=Array.isArray(original)?original:[];return incoming.length<origArr.length&&log$3.warn(`Redacted config array key ${path} has been truncated`),incoming.map((item,i)=>item===REDACTED_SENTINEL?origArr[i]:restoreRedactedValuesWithLookup(item,origArr[i],lookup,path,hints))}let orig=original&&typeof original==`object`&&!Array.isArray(original)?original:{},result={};for(let[key,value]of Object.entries(incoming)){result[key]=value;let path=prefix?`${prefix}.${key}`:key,wildcardPath=prefix?`${prefix}.*`:`*`,matched=!1;for(let candidate of[path,wildcardPath])if(lookup.has(candidate)){matched=!0,value===REDACTED_SENTINEL?result[key]=restoreOriginalValueOrThrow({key,path:candidate,original:orig}):typeof value==`object`&&value&&(result[key]=restoreRedactedValuesWithLookup(value,orig[key],lookup,candidate,hints));break}!matched&&isExtensionPath(path)&&(!isExplicitlyNonSensitivePath(hints,[path,wildcardPath])&&isSensitivePath(path)&&value===REDACTED_SENTINEL?result[key]=restoreOriginalValueOrThrow({key,path,original:orig}):typeof value==`object`&&value&&(result[key]=restoreRedactedValuesGuessing(value,orig[key],path,hints)))}return result}function restoreRedactedValuesGuessing(incoming,original,prefix,hints){if(typeof incoming!=`object`||!incoming)return incoming;if(Array.isArray(incoming)){let origArr=Array.isArray(original)?original:[];return incoming.map((item,i)=>{let path=`${prefix}[]`;return incoming.length<origArr.length&&log$3.warn(`Redacted config array key ${path} has been truncated`),!isExplicitlyNonSensitivePath(hints,[path])&&isSensitivePath(path)&&item===REDACTED_SENTINEL?origArr[i]:restoreRedactedValuesGuessing(item,origArr[i],path,hints)})}let orig=original&&typeof original==`object`&&!Array.isArray(original)?original:{},result={};for(let[key,value]of Object.entries(incoming)){let path=prefix?`${prefix}.${key}`:key;!isExplicitlyNonSensitivePath(hints,[path,prefix?`${prefix}.*`:`*`])&&isSensitivePath(path)&&value===REDACTED_SENTINEL?result[key]=restoreOriginalValueOrThrow({key,path,original:orig}):typeof value==`object`&&value?result[key]=restoreRedactedValuesGuessing(value,orig[key],path,hints):result[key]=value}return result}function cloneSchema(value){return typeof structuredClone==`function`?structuredClone(value):JSON.parse(JSON.stringify(value))}function asSchemaObject(value){return!value||typeof value!=`object`||Array.isArray(value)?null:value}function isObjectSchema(schema){let type=schema.type;return type===`object`||Array.isArray(type)&&type.includes(`object`)?!0:!!(schema.properties||schema.additionalProperties)}function mergeObjectSchema(base,extension){let mergedRequired=new Set([...base.required??[],...extension.required??[]]),merged={...base,...extension,properties:{...base.properties,...extension.properties}};mergedRequired.size>0&&(merged.required=Array.from(mergedRequired));let additional=extension.additionalProperties??base.additionalProperties;return additional!==void 0&&(merged.additionalProperties=additional),merged}function collectExtensionHintKeys(hints,plugins,channels){let pluginPrefixes=plugins.map(plugin=>plugin.id.trim()).filter(Boolean).map(id=>`plugins.entries.${id}`),channelPrefixes=channels.map(channel=>channel.id.trim()).filter(Boolean).map(id=>`channels.${id}`),prefixes=[...pluginPrefixes,...channelPrefixes];return new Set(Object.keys(hints).filter(key=>prefixes.some(prefix=>key===prefix||key.startsWith(`${prefix}.`))))}function applyPluginHints(hints,plugins){let next={...hints};for(let plugin of plugins){let id=plugin.id.trim();if(!id)continue;let name=(plugin.name??id).trim()||id,basePath=`plugins.entries.${id}`;next[basePath]={...next[basePath],label:name,help:plugin.description?`${plugin.description} (plugin: ${id})`:`Plugin entry for ${id}.`},next[`${basePath}.enabled`]={...next[`${basePath}.enabled`],label:`Enable ${name}`},next[`${basePath}.config`]={...next[`${basePath}.config`],label:`${name} Config`,help:`Plugin-defined config payload for ${id}.`};let uiHints=plugin.configUiHints??{};for(let[relPathRaw,hint]of Object.entries(uiHints)){let relPath=relPathRaw.trim().replace(/^\./,``);if(!relPath)continue;let key=`${basePath}.config.${relPath}`;next[key]={...next[key],...hint}}}return next}function applyChannelHints(hints,channels){let next={...hints};for(let channel of channels){let id=channel.id.trim();if(!id)continue;let basePath=`channels.${id}`,current=next[basePath]??{},label=channel.label?.trim(),help=channel.description?.trim();next[basePath]={...current,...label?{label}:{},...help?{help}:{}};let uiHints=channel.configUiHints??{};for(let[relPathRaw,hint]of Object.entries(uiHints)){let relPath=relPathRaw.trim().replace(/^\./,``);if(!relPath)continue;let key=`${basePath}.${relPath}`;next[key]={...next[key],...hint}}}return next}function listHeartbeatTargetChannels(channels){let seen=new Set,ordered=[];for(let id of CHANNEL_IDS){let normalized=id.trim().toLowerCase();!normalized||seen.has(normalized)||(seen.add(normalized),ordered.push(normalized))}for(let channel of channels){let normalized=channel.id.trim().toLowerCase();!normalized||seen.has(normalized)||(seen.add(normalized),ordered.push(normalized))}return ordered}function applyHeartbeatTargetHints(hints,channels){let next={...hints},channelList=listHeartbeatTargetChannels(channels),help=`Delivery target ("last", "none", or a channel id).${channelList.length?` Known channels: ${channelList.join(`, `)}.`:``}`;for(let path of[`agents.defaults.heartbeat.target`,`agents.list.*.heartbeat.target`]){let current=next[path]??{};next[path]={...current,help:current.help??help,placeholder:current.placeholder??`last`}}return next}function applyPluginSchemas(schema,plugins){let next=cloneSchema(schema),entriesNode=asSchemaObject(asSchemaObject(asSchemaObject(next)?.properties?.plugins)?.properties?.entries);if(!entriesNode)return next;let entryBase=asSchemaObject(entriesNode.additionalProperties),entryProperties=entriesNode.properties??{};entriesNode.properties=entryProperties;for(let plugin of plugins){if(!plugin.configSchema)continue;let entryObject=asSchemaObject(entryBase?cloneSchema(entryBase):{type:`object`})??{type:`object`},baseConfigSchema=asSchemaObject(entryObject.properties?.config),pluginSchema=asSchemaObject(plugin.configSchema),nextConfigSchema=baseConfigSchema&&pluginSchema&&isObjectSchema(baseConfigSchema)&&isObjectSchema(pluginSchema)?mergeObjectSchema(baseConfigSchema,pluginSchema):cloneSchema(plugin.configSchema);entryObject.properties={...entryObject.properties,config:nextConfigSchema},entryProperties[plugin.id]=entryObject}return next}function applyChannelSchemas(schema,channels){let next=cloneSchema(schema),channelsNode=asSchemaObject(asSchemaObject(next)?.properties?.channels);if(!channelsNode)return next;let channelProps=channelsNode.properties??{};channelsNode.properties=channelProps;for(let channel of channels){if(!channel.configSchema)continue;let existing=asSchemaObject(channelProps[channel.id]),incoming=asSchemaObject(channel.configSchema);existing&&incoming&&isObjectSchema(existing)&&isObjectSchema(incoming)?channelProps[channel.id]=mergeObjectSchema(existing,incoming):channelProps[channel.id]=cloneSchema(channel.configSchema)}return next}let cachedBase=null;function stripChannelSchema(schema){let next=cloneSchema(schema),root=asSchemaObject(next);if(!root||!root.properties)return next;delete root.properties.$schema,Array.isArray(root.required)&&(root.required=root.required.filter(key=>key!==`$schema`));let channelsNode=asSchemaObject(root.properties.channels);return channelsNode&&(channelsNode.properties={},channelsNode.required=[],channelsNode.additionalProperties=!0),next}function buildBaseConfigSchema(){if(cachedBase)return cachedBase;let schema=BuilderForceAgentsSchema.toJSONSchema({target:`draft-07`,unrepresentable:`any`});schema.title=`BuilderForceAgentsConfig`;let hints=mapSensitivePaths(BuilderForceAgentsSchema,``,buildBaseHints()),next={schema:stripChannelSchema(schema),uiHints:hints,version:VERSION,generatedAt:new Date().toISOString()};return cachedBase=next,next}function buildConfigSchema(params){let base=buildBaseConfigSchema(),plugins=params?.plugins??[],channels=params?.channels??[];if(plugins.length===0&&channels.length===0)return base;let mergedWithoutSensitiveHints=applyHeartbeatTargetHints(applyChannelHints(applyPluginHints(base.uiHints,plugins),channels),channels),mergedHints=applySensitiveHints(mergedWithoutSensitiveHints,collectExtensionHintKeys(mergedWithoutSensitiveHints,plugins,channels)),mergedSchema=applyChannelSchemas(applyPluginSchemas(base.schema,plugins),channels);return{...base,schema:mergedSchema,uiHints:mergedHints}}function resolveBaseHashParam(params){let raw=params?.baseHash;return typeof raw==`string`&&raw.trim()||null}function parseRestartRequestParams(params){let sessionKey=typeof params.sessionKey==`string`&¶ms.sessionKey?.trim()||void 0,note=typeof params.note==`string`&¶ms.note?.trim()||void 0,restartDelayMsRaw=params.restartDelayMs;return{sessionKey,note,restartDelayMs:typeof restartDelayMsRaw==`number`&&Number.isFinite(restartDelayMsRaw)?Math.max(0,Math.floor(restartDelayMsRaw)):void 0}}function requireConfigBaseHash(params,snapshot,respond){if(!snapshot.exists)return!0;let snapshotHash=resolveConfigSnapshotHash(snapshot);if(!snapshotHash)return respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`config base hash unavailable; re-run config.get and retry`)),!1;let baseHash=resolveBaseHashParam(params);return baseHash?baseHash===snapshotHash?!0:(respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`config changed since last load; re-run config.get and retry`)),!1):(respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`config base hash required; re-run config.get and retry`)),!1)}function parseRawConfigOrRespond(params,requestName,respond){let rawValue=params.raw;return typeof rawValue==`string`?rawValue:(respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid ${requestName} params: raw (string) required`)),null)}function parseValidateConfigFromRawOrRespond(params,requestName,snapshot,respond){let rawValue=parseRawConfigOrRespond(params,requestName,respond);if(!rawValue)return null;let parsedRes=parseConfigJson5(rawValue);if(!parsedRes.ok)return respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,parsedRes.error)),null;let schema=loadSchemaWithPlugins(),restored=restoreRedactedValues(parsedRes.parsed,snapshot.config,schema.uiHints);if(!restored.ok)return respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,restored.humanReadableMessage??`invalid config`)),null;let validated=validateConfigObjectWithPlugins(restored.result);return validated.ok?{config:validated.config,schema}:(respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid config`,{details:{issues:validated.issues}})),null)}function resolveConfigRestartRequest(params){let{sessionKey,note,restartDelayMs}=parseRestartRequestParams(params),{deliveryContext,threadId}=extractDeliveryInfo(sessionKey);return{sessionKey,note,restartDelayMs,deliveryContext,threadId}}function buildConfigRestartSentinelPayload(params){return{kind:params.kind,status:`ok`,ts:Date.now(),sessionKey:params.sessionKey,deliveryContext:params.deliveryContext,threadId:params.threadId,message:params.note??null,doctorHint:formatDoctorNonInteractiveHint(),stats:{mode:params.mode,root:CONFIG_PATH}}}async function tryWriteRestartSentinelPayload(payload){try{return await writeRestartSentinel(payload)}catch{return null}}function loadSchemaWithPlugins(){let cfg=loadConfig();return buildConfigSchema({plugins:loadBuilderForceAgentsPlugins({config:cfg,cache:!0,workspaceDir:resolveAgentWorkspaceDir(cfg,resolveDefaultAgentId(cfg)),logger:{info:()=>{},warn:()=>{},error:()=>{},debug:()=>{}}}).plugins.map(plugin=>({id:plugin.id,name:plugin.name,description:plugin.description,configUiHints:plugin.configUiHints,configSchema:plugin.configJsonSchema})),channels:listChannelPlugins().map(entry=>({id:entry.id,label:entry.meta.label,description:entry.meta.blurb,configSchema:entry.configSchema?.schema,configUiHints:entry.configSchema?.uiHints}))})}const configHandlers={"config.get":async({params,respond})=>{assertValidParams(params,validateConfigGetParams,`config.get`,respond)&&respond(!0,redactConfigSnapshot(await readConfigFileSnapshot(),loadSchemaWithPlugins().uiHints),void 0)},"config.schema":({params,respond})=>{assertValidParams(params,validateConfigSchemaParams,`config.schema`,respond)&&respond(!0,loadSchemaWithPlugins(),void 0)},"config.set":async({params,respond})=>{if(!assertValidParams(params,validateConfigSetParams,`config.set`,respond))return;let{snapshot,writeOptions}=await readConfigFileSnapshotForWrite();if(!requireConfigBaseHash(params,snapshot,respond))return;let parsed=parseValidateConfigFromRawOrRespond(params,`config.set`,snapshot,respond);parsed&&(await writeConfigFile(parsed.config,writeOptions),respond(!0,{ok:!0,path:CONFIG_PATH,config:redactConfigObject(parsed.config,parsed.schema.uiHints)},void 0))},"config.patch":async({params,respond})=>{if(!assertValidParams(params,validateConfigPatchParams,`config.patch`,respond))return;let{snapshot,writeOptions}=await readConfigFileSnapshotForWrite();if(!requireConfigBaseHash(params,snapshot,respond))return;if(!snapshot.valid){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid config; fix before patching`));return}let rawValue=params.raw;if(typeof rawValue!=`string`){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid config.patch params: raw (string) required`));return}let parsedRes=parseConfigJson5(rawValue);if(!parsedRes.ok){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,parsedRes.error));return}if(!parsedRes.parsed||typeof parsedRes.parsed!=`object`||Array.isArray(parsedRes.parsed)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`config.patch raw must be an object`));return}let merged=applyMergePatch(snapshot.config,parsedRes.parsed,{mergeObjectArraysById:!0}),schemaPatch=loadSchemaWithPlugins(),restoredMerge=restoreRedactedValues(merged,snapshot.config,schemaPatch.uiHints);if(!restoredMerge.ok){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,restoredMerge.humanReadableMessage??`invalid config`));return}let validated=validateConfigObjectWithPlugins(applyLegacyMigrations(restoredMerge.result).next??restoredMerge.result);if(!validated.ok){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid config`,{details:{issues:validated.issues}}));return}await writeConfigFile(validated.config,writeOptions);let{sessionKey,note,restartDelayMs,deliveryContext,threadId}=resolveConfigRestartRequest(params),payload=buildConfigRestartSentinelPayload({kind:`config-patch`,mode:`config.patch`,sessionKey,deliveryContext,threadId,note}),sentinelPath=await tryWriteRestartSentinelPayload(payload),restart=scheduleGatewaySigusr1Restart({delayMs:restartDelayMs,reason:`config.patch`});respond(!0,{ok:!0,path:CONFIG_PATH,config:redactConfigObject(validated.config,schemaPatch.uiHints),restart,sentinel:{path:sentinelPath,payload}},void 0)},"config.apply":async({params,respond})=>{if(!assertValidParams(params,validateConfigApplyParams,`config.apply`,respond))return;let{snapshot,writeOptions}=await readConfigFileSnapshotForWrite();if(!requireConfigBaseHash(params,snapshot,respond))return;let parsed=parseValidateConfigFromRawOrRespond(params,`config.apply`,snapshot,respond);if(!parsed)return;await writeConfigFile(parsed.config,writeOptions);let{sessionKey,note,restartDelayMs,deliveryContext,threadId}=resolveConfigRestartRequest(params),payload=buildConfigRestartSentinelPayload({kind:`config-apply`,mode:`config.apply`,sessionKey,deliveryContext,threadId,note}),sentinelPath=await tryWriteRestartSentinelPayload(payload),restart=scheduleGatewaySigusr1Restart({delayMs:restartDelayMs,reason:`config.apply`});respond(!0,{ok:!0,path:CONFIG_PATH,config:redactConfigObject(parsed.config,parsed.schema.uiHints),restart,sentinel:{path:sentinelPath,payload}},void 0)}},connectHandlers={connect:({respond})=>{respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`connect is only valid as the first request`))}},ONE_MINUTE_MS=60*1e3;function validateScheduleTimestamp(schedule,nowMs=Date.now()){if(schedule.kind!==`at`)return{ok:!0};let atRaw=typeof schedule.at==`string`?schedule.at.trim():``,atMs=atRaw?parseAbsoluteTimeMs(atRaw):null;if(atMs===null||!Number.isFinite(atMs))return{ok:!1,message:`Invalid schedule.at: expected ISO-8601 timestamp (got ${String(schedule.at)})`};let diffMs=atMs-nowMs;if(diffMs<-ONE_MINUTE_MS){let nowDate=new Date(nowMs).toISOString();return{ok:!1,message:`schedule.at is in the past: ${new Date(atMs).toISOString()} (${Math.floor(-diffMs/ONE_MINUTE_MS)} minutes ago). Current time: ${nowDate}`}}return diffMs>315576e6?{ok:!1,message:`schedule.at is too far in the future: ${new Date(atMs).toISOString()} (${Math.floor(diffMs/(365.25*24*60*60*1e3))} years ahead). Maximum allowed: 10 years`}:{ok:!0}}const cronHandlers={wake:({params,respond,context})=>{if(!validateWakeParams(params)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid wake params: ${formatValidationErrors(validateWakeParams.errors)}`));return}let p=params;respond(!0,context.cron.wake({mode:p.mode,text:p.text}),void 0)},"cron.list":async({params,respond,context})=>{if(!validateCronListParams(params)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid cron.list params: ${formatValidationErrors(validateCronListParams.errors)}`));return}let p=params;respond(!0,{jobs:await context.cron.list({includeDisabled:p.includeDisabled})},void 0)},"cron.status":async({params,respond,context})=>{if(!validateCronStatusParams(params)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid cron.status params: ${formatValidationErrors(validateCronStatusParams.errors)}`));return}respond(!0,await context.cron.status(),void 0)},"cron.add":async({params,respond,context})=>{let normalized=normalizeCronJobCreate(params)??params;if(!validateCronAddParams(normalized)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid cron.add params: ${formatValidationErrors(validateCronAddParams.errors)}`));return}let jobCreate=normalized,timestampValidation=validateScheduleTimestamp(jobCreate.schedule);if(!timestampValidation.ok){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,timestampValidation.message));return}respond(!0,await context.cron.add(jobCreate),void 0)},"cron.update":async({params,respond,context})=>{let normalizedPatch=normalizeCronJobPatch(params?.patch),candidate=normalizedPatch&&typeof params==`object`&¶ms?{...params,patch:normalizedPatch}:params;if(!validateCronUpdateParams(candidate)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid cron.update params: ${formatValidationErrors(validateCronUpdateParams.errors)}`));return}let p=candidate,jobId=p.id??p.jobId;if(!jobId){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid cron.update params: missing id`));return}let patch=p.patch;if(patch.schedule){let timestampValidation=validateScheduleTimestamp(patch.schedule);if(!timestampValidation.ok){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,timestampValidation.message));return}}respond(!0,await context.cron.update(jobId,patch),void 0)},"cron.remove":async({params,respond,context})=>{if(!validateCronRemoveParams(params)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid cron.remove params: ${formatValidationErrors(validateCronRemoveParams.errors)}`));return}let p=params,jobId=p.id??p.jobId;if(!jobId){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid cron.remove params: missing id`));return}respond(!0,await context.cron.remove(jobId),void 0)},"cron.run":async({params,respond,context})=>{if(!validateCronRunParams(params)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid cron.run params: ${formatValidationErrors(validateCronRunParams.errors)}`));return}let p=params,jobId=p.id??p.jobId;if(!jobId){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid cron.run params: missing id`));return}respond(!0,await context.cron.run(jobId,p.mode??`force`),void 0)},"cron.runs":async({params,respond,context})=>{if(!validateCronRunsParams(params)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid cron.runs params: ${formatValidationErrors(validateCronRunsParams.errors)}`));return}let p=params,jobId=p.id??p.jobId;if(!jobId){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid cron.runs params: missing id`));return}respond(!0,{entries:await readCronRunLogEntries(resolveCronRunLogPath({storePath:context.cronStorePath,jobId}),{limit:p.limit,jobId})},void 0)}},withLock=createAsyncLock();async function loadState(baseDir){let{pendingPath,pairedPath}=resolvePairingPaths(baseDir,`devices`),[pending,paired]=await Promise.all([readJsonFile(pendingPath),readJsonFile(pairedPath)]),state={pendingById:pending??{},pairedByDeviceId:paired??{}};return pruneExpiredPending(state.pendingById,Date.now(),3e5),state}async function persistState(state,baseDir){let{pendingPath,pairedPath}=resolvePairingPaths(baseDir,`devices`);await Promise.all([writeJsonAtomic(pendingPath,state.pendingById),writeJsonAtomic(pairedPath,state.pairedByDeviceId)])}function normalizeDeviceId(deviceId){return deviceId.trim()}function normalizeRole(role){return role?.trim()||null}function mergeRoles(...items){let roles=new Set;for(let item of items)if(item)if(Array.isArray(item))for(let role of item){let trimmed=role.trim();trimmed&&roles.add(trimmed)}else{let trimmed=item.trim();trimmed&&roles.add(trimmed)}if(roles.size!==0)return[...roles]}function mergeScopes(...items){let scopes=new Set;for(let item of items)if(item)for(let scope of item){let trimmed=scope.trim();trimmed&&scopes.add(trimmed)}if(scopes.size!==0)return[...scopes]}function scopesAllow(requested,allowed){if(requested.length===0)return!0;if(allowed.length===0)return!1;let allowedSet=new Set(allowed);return requested.every(scope=>allowedSet.has(scope))}function newToken(){return generatePairingToken()}function getPairedDeviceFromState(state,deviceId){return state.pairedByDeviceId[normalizeDeviceId(deviceId)]??null}function cloneDeviceTokens(device){return device.tokens?{...device.tokens}:{}}function buildDeviceAuthToken(params){return{token:newToken(),role:params.role,scopes:params.scopes,createdAtMs:params.existing?.createdAtMs??params.now,rotatedAtMs:params.rotatedAtMs,revokedAtMs:void 0,lastUsedAtMs:params.existing?.lastUsedAtMs}}async function listDevicePairing(baseDir){let state=await loadState(baseDir);return{pending:Object.values(state.pendingById).toSorted((a,b)=>b.ts-a.ts),paired:Object.values(state.pairedByDeviceId).toSorted((a,b)=>b.approvedAtMs-a.approvedAtMs)}}async function getPairedDevice(deviceId,baseDir){return(await loadState(baseDir)).pairedByDeviceId[normalizeDeviceId(deviceId)]??null}async function requestDevicePairing(req,baseDir){return await withLock(async()=>{let state=await loadState(baseDir),deviceId=normalizeDeviceId(req.deviceId);if(!deviceId)throw Error(`deviceId required`);let existing=Object.values(state.pendingById).find(p=>p.deviceId===deviceId);if(existing)return{status:`pending`,request:existing,created:!1};let isRepair=!!state.pairedByDeviceId[deviceId],request={requestId:randomUUID(),deviceId,publicKey:req.publicKey,displayName:req.displayName,platform:req.platform,clientId:req.clientId,clientMode:req.clientMode,role:req.role,roles:req.role?[req.role]:void 0,scopes:req.scopes,remoteIp:req.remoteIp,silent:req.silent,isRepair,ts:Date.now()};return state.pendingById[request.requestId]=request,await persistState(state,baseDir),{status:`pending`,request,created:!0}})}async function approveDevicePairing(requestId,baseDir){return await withLock(async()=>{let state=await loadState(baseDir),pending=state.pendingById[requestId];if(!pending)return null;let now=Date.now(),existing=state.pairedByDeviceId[pending.deviceId],roles=mergeRoles(existing?.roles,existing?.role,pending.roles,pending.role),scopes=mergeScopes(existing?.scopes,pending.scopes),tokens=existing?.tokens?{...existing.tokens}:{},roleForToken=normalizeRole(pending.role);if(roleForToken){let nextScopes=normalizeDeviceAuthScopes(pending.scopes),existingToken=tokens[roleForToken],now=Date.now();tokens[roleForToken]={token:newToken(),role:roleForToken,scopes:nextScopes,createdAtMs:existingToken?.createdAtMs??now,rotatedAtMs:existingToken?now:void 0,revokedAtMs:void 0,lastUsedAtMs:existingToken?.lastUsedAtMs}}let device={deviceId:pending.deviceId,publicKey:pending.publicKey,displayName:pending.displayName,platform:pending.platform,clientId:pending.clientId,clientMode:pending.clientMode,role:pending.role,roles,scopes,remoteIp:pending.remoteIp,tokens,createdAtMs:existing?.createdAtMs??now,approvedAtMs:now};return delete state.pendingById[requestId],state.pairedByDeviceId[device.deviceId]=device,await persistState(state,baseDir),{requestId,device}})}async function rejectDevicePairing(requestId,baseDir){return await withLock(async()=>{let state=await loadState(baseDir),pending=state.pendingById[requestId];return pending?(delete state.pendingById[requestId],await persistState(state,baseDir),{requestId,deviceId:pending.deviceId}):null})}async function removePairedDevice(deviceId,baseDir){return await withLock(async()=>{let state=await loadState(baseDir),normalized=normalizeDeviceId(deviceId);return!normalized||!state.pairedByDeviceId[normalized]?null:(delete state.pairedByDeviceId[normalized],await persistState(state,baseDir),{deviceId:normalized})})}async function updatePairedDeviceMetadata(deviceId,patch,baseDir){return await withLock(async()=>{let state=await loadState(baseDir),existing=state.pairedByDeviceId[normalizeDeviceId(deviceId)];if(!existing)return;let roles=mergeRoles(existing.roles,existing.role,patch.role),scopes=mergeScopes(existing.scopes,patch.scopes);state.pairedByDeviceId[deviceId]={...existing,...patch,deviceId:existing.deviceId,createdAtMs:existing.createdAtMs,approvedAtMs:existing.approvedAtMs,role:patch.role??existing.role,roles,scopes},await persistState(state,baseDir)})}function summarizeDeviceTokens(tokens){if(!tokens)return;let summaries=Object.values(tokens).map(token=>({role:token.role,scopes:token.scopes,createdAtMs:token.createdAtMs,rotatedAtMs:token.rotatedAtMs,revokedAtMs:token.revokedAtMs,lastUsedAtMs:token.lastUsedAtMs})).toSorted((a,b)=>a.role.localeCompare(b.role));return summaries.length>0?summaries:void 0}async function verifyDeviceToken(params){return await withLock(async()=>{let state=await loadState(params.baseDir),device=getPairedDeviceFromState(state,params.deviceId);if(!device)return{ok:!1,reason:`device-not-paired`};let role=normalizeRole(params.role);if(!role)return{ok:!1,reason:`role-missing`};let entry=device.tokens?.[role];return entry?entry.revokedAtMs?{ok:!1,reason:`token-revoked`}:verifyPairingToken(params.token,entry.token)?scopesAllow(normalizeDeviceAuthScopes(params.scopes),entry.scopes)?(entry.lastUsedAtMs=Date.now(),device.tokens??={},device.tokens[role]=entry,state.pairedByDeviceId[device.deviceId]=device,await persistState(state,params.baseDir),{ok:!0}):{ok:!1,reason:`scope-mismatch`}:{ok:!1,reason:`token-mismatch`}:{ok:!1,reason:`token-missing`}})}async function ensureDeviceToken(params){return await withLock(async()=>{let state=await loadState(params.baseDir),requestedScopes=normalizeDeviceAuthScopes(params.scopes),context=resolveDeviceTokenUpdateContext({state,deviceId:params.deviceId,role:params.role});if(!context)return null;let{device,role,tokens,existing}=context;if(existing&&!existing.revokedAtMs&&scopesAllow(requestedScopes,existing.scopes))return existing;let now=Date.now(),next=buildDeviceAuthToken({role,scopes:requestedScopes,existing,now,rotatedAtMs:existing?now:void 0});return tokens[role]=next,device.tokens=tokens,state.pairedByDeviceId[device.deviceId]=device,await persistState(state,params.baseDir),next})}function resolveDeviceTokenUpdateContext(params){let device=getPairedDeviceFromState(params.state,params.deviceId);if(!device)return null;let role=normalizeRole(params.role);if(!role)return null;let tokens=cloneDeviceTokens(device);return{device,role,tokens,existing:tokens[role]}}async function rotateDeviceToken(params){return await withLock(async()=>{let state=await loadState(params.baseDir),context=resolveDeviceTokenUpdateContext({state,deviceId:params.deviceId,role:params.role});if(!context)return null;let{device,role,tokens,existing}=context,requestedScopes=normalizeDeviceAuthScopes(params.scopes??existing?.scopes??device.scopes),now=Date.now(),next=buildDeviceAuthToken({role,scopes:requestedScopes,existing,now,rotatedAtMs:now});return tokens[role]=next,device.tokens=tokens,params.scopes!==void 0&&(device.scopes=requestedScopes),state.pairedByDeviceId[device.deviceId]=device,await persistState(state,params.baseDir),next})}async function revokeDeviceToken(params){return await withLock(async()=>{let state=await loadState(params.baseDir),device=state.pairedByDeviceId[normalizeDeviceId(params.deviceId)];if(!device)return null;let role=normalizeRole(params.role);if(!role||!device.tokens?.[role])return null;let tokens={...device.tokens},entry={...tokens[role],revokedAtMs:Date.now()};return tokens[role]=entry,device.tokens=tokens,state.pairedByDeviceId[device.deviceId]=device,await persistState(state,params.baseDir),entry})}function redactPairedDevice(device){let{tokens,...rest}=device;return{...rest,tokens:summarizeDeviceTokens(tokens)}}const deviceHandlers={"device.pair.list":async({params,respond})=>{if(!validateDevicePairListParams(params)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid device.pair.list params: ${formatValidationErrors(validateDevicePairListParams.errors)}`));return}let list=await listDevicePairing();respond(!0,{pending:list.pending,paired:list.paired.map(device=>redactPairedDevice(device))},void 0)},"device.pair.approve":async({params,respond,context})=>{if(!validateDevicePairApproveParams(params)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid device.pair.approve params: ${formatValidationErrors(validateDevicePairApproveParams.errors)}`));return}let{requestId}=params,approved=await approveDevicePairing(requestId);if(!approved){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`unknown requestId`));return}context.logGateway.info(`device pairing approved device=${approved.device.deviceId} role=${approved.device.role??`unknown`}`),context.broadcast(`device.pair.resolved`,{requestId,deviceId:approved.device.deviceId,decision:`approved`,ts:Date.now()},{dropIfSlow:!0}),respond(!0,{requestId,device:redactPairedDevice(approved.device)},void 0)},"device.pair.reject":async({params,respond,context})=>{if(!validateDevicePairRejectParams(params)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid device.pair.reject params: ${formatValidationErrors(validateDevicePairRejectParams.errors)}`));return}let{requestId}=params,rejected=await rejectDevicePairing(requestId);if(!rejected){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`unknown requestId`));return}context.broadcast(`device.pair.resolved`,{requestId,deviceId:rejected.deviceId,decision:`rejected`,ts:Date.now()},{dropIfSlow:!0}),respond(!0,rejected,void 0)},"device.pair.remove":async({params,respond,context})=>{if(!validateDevicePairRemoveParams(params)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid device.pair.remove params: ${formatValidationErrors(validateDevicePairRemoveParams.errors)}`));return}let{deviceId}=params,removed=await removePairedDevice(deviceId);if(!removed){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`unknown deviceId`));return}context.logGateway.info(`device pairing removed device=${removed.deviceId}`),respond(!0,removed,void 0)},"device.token.rotate":async({params,respond,context})=>{if(!validateDeviceTokenRotateParams(params)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid device.token.rotate params: ${formatValidationErrors(validateDeviceTokenRotateParams.errors)}`));return}let{deviceId,role,scopes}=params,entry=await rotateDeviceToken({deviceId,role,scopes});if(!entry){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`unknown deviceId/role`));return}context.logGateway.info(`device token rotated device=${deviceId} role=${entry.role} scopes=${entry.scopes.join(`,`)}`),respond(!0,{deviceId,role:entry.role,token:entry.token,scopes:entry.scopes,rotatedAtMs:entry.rotatedAtMs??entry.createdAtMs},void 0)},"device.token.revoke":async({params,respond,context})=>{if(!validateDeviceTokenRevokeParams(params)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid device.token.revoke params: ${formatValidationErrors(validateDeviceTokenRevokeParams.errors)}`));return}let{deviceId,role}=params,entry=await revokeDeviceToken({deviceId,role});if(!entry){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`unknown deviceId/role`));return}context.logGateway.info(`device token revoked device=${deviceId} role=${entry.role}`),respond(!0,{deviceId,role:entry.role,revokedAtMs:entry.revokedAtMs??Date.now()},void 0)}};function requireApprovalsBaseHash(params,snapshot,respond){if(!snapshot.exists)return!0;if(!snapshot.hash)return respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`exec approvals base hash unavailable; re-run exec.approvals.get and retry`)),!1;let baseHash=resolveBaseHashParam(params);return baseHash?baseHash===snapshot.hash?!0:(respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`exec approvals changed since last load; re-run exec.approvals.get and retry`)),!1):(respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`exec approvals base hash required; re-run exec.approvals.get and retry`)),!1)}function redactExecApprovals(file){let socketPath=file.socket?.path?.trim();return{...file,socket:socketPath?{path:socketPath}:void 0}}function toExecApprovalsPayload(snapshot){return{path:snapshot.path,exists:snapshot.exists,hash:snapshot.hash,file:redactExecApprovals(snapshot.file)}}function resolveNodeIdOrRespond(nodeId,respond){return nodeId.trim()||(respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`nodeId required`)),null)}const execApprovalsHandlers={"exec.approvals.get":({params,respond})=>{assertValidParams(params,validateExecApprovalsGetParams,`exec.approvals.get`,respond)&&(ensureExecApprovals(),respond(!0,toExecApprovalsPayload(readExecApprovalsSnapshot()),void 0))},"exec.approvals.set":({params,respond})=>{if(!assertValidParams(params,validateExecApprovalsSetParams,`exec.approvals.set`,respond))return;ensureExecApprovals();let snapshot=readExecApprovalsSnapshot();if(!requireApprovalsBaseHash(params,snapshot,respond))return;let incoming=params.file;if(!incoming||typeof incoming!=`object`){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`exec approvals file is required`));return}saveExecApprovals(mergeExecApprovalsSocketDefaults({normalized:normalizeExecApprovals(incoming),current:snapshot.file})),respond(!0,toExecApprovalsPayload(readExecApprovalsSnapshot()),void 0)},"exec.approvals.node.get":async({params,respond,context})=>{if(!assertValidParams(params,validateExecApprovalsNodeGetParams,`exec.approvals.node.get`,respond))return;let{nodeId}=params,id=resolveNodeIdOrRespond(nodeId,respond);id&&await respondUnavailableOnThrow(respond,async()=>{let res=await context.nodeRegistry.invoke({nodeId:id,command:`system.execApprovals.get`,params:{}});respondUnavailableOnNodeInvokeError(respond,res)&&respond(!0,res.payloadJSON?safeParseJson(res.payloadJSON):res.payload,void 0)})},"exec.approvals.node.set":async({params,respond,context})=>{if(!assertValidParams(params,validateExecApprovalsNodeSetParams,`exec.approvals.node.set`,respond))return;let{nodeId,file,baseHash}=params,id=resolveNodeIdOrRespond(nodeId,respond);id&&await respondUnavailableOnThrow(respond,async()=>{let res=await context.nodeRegistry.invoke({nodeId:id,command:`system.execApprovals.set`,params:{file,baseHash}});respondUnavailableOnNodeInvokeError(respond,res)&&respond(!0,safeParseJson(res.payloadJSON??null),void 0)})}},healthHandlers={health:async({respond,context,params})=>{let{getHealthCache,refreshHealthSnapshot,logHealth}=context,wantsProbe=params?.probe===!0,now=Date.now(),cached=getHealthCache();if(!wantsProbe&&cached&&now-cached.ts<HEALTH_REFRESH_INTERVAL_MS){respond(!0,cached,void 0,{cached:!0}),refreshHealthSnapshot({probe:!1}).catch(err=>logHealth.error(`background health refresh failed: ${formatError(err)}`));return}try{respond(!0,await refreshHealthSnapshot({probe:wantsProbe}),void 0)}catch(err){respond(!1,void 0,errorShape(ErrorCodes.UNAVAILABLE,formatForLog(err)))}},status:async({respond,client})=>{respond(!0,await getStatusSummary({includeSensitive:(Array.isArray(client?.connect?.scopes)?client.connect.scopes:[]).includes(`operator.admin`)}),void 0)}},ROLLING_LOG_RE=/^builderforce-\d{4}-\d{2}-\d{2}\.log$/;function isRollingLogFile(file){return ROLLING_LOG_RE.test(path.basename(file))}async function resolveLogFile(file){if(await fs$1.stat(file).catch(()=>null)||!isRollingLogFile(file))return file;let dir=path.dirname(file),entries=await fs$1.readdir(dir,{withFileTypes:!0}).catch(()=>null);return entries?(await Promise.all(entries.filter(entry=>entry.isFile()&&ROLLING_LOG_RE.test(entry.name)).map(async entry=>{let fullPath=path.join(dir,entry.name),fileStat=await fs$1.stat(fullPath).catch(()=>null);return fileStat?{path:fullPath,mtimeMs:fileStat.mtimeMs}:null}))).filter(entry=>!!entry).toSorted((a,b)=>b.mtimeMs-a.mtimeMs)[0]?.path??file:file}async function readLogSlice(params){let stat=await fs$1.stat(params.file).catch(()=>null);if(!stat)return{cursor:0,size:0,lines:[],truncated:!1,reset:!1};let size=stat.size,maxBytes=clamp(params.maxBytes,1,1e6),limit=clamp(params.limit,1,5e3),cursor=typeof params.cursor==`number`&&Number.isFinite(params.cursor)?Math.max(0,Math.floor(params.cursor)):void 0,reset=!1,truncated=!1,start=0;if(cursor==null?(start=Math.max(0,size-maxBytes),truncated=start>0):cursor>size?(reset=!0,start=Math.max(0,size-maxBytes),truncated=start>0):(start=cursor,size-start>maxBytes&&(reset=!0,truncated=!0,start=Math.max(0,size-maxBytes))),size===0||size<=start)return{cursor:size,size,lines:[],truncated,reset};let handle=await fs$1.open(params.file,`r`);try{let prefix=``;if(start>0){let prefixBuf=Buffer.alloc(1),prefixRead=await handle.read(prefixBuf,0,1,start-1);prefix=prefixBuf.toString(`utf8`,0,prefixRead.bytesRead)}let length=Math.max(0,size-start),buffer=Buffer.alloc(length),readResult=await handle.read(buffer,0,length,start),lines=buffer.toString(`utf8`,0,readResult.bytesRead).split(`
|
|
16
16
|
`);return start>0&&prefix!==`
|
|
17
|
-
`&&(lines=lines.slice(1)),lines.length>0&&lines[lines.length-1]===``&&(lines=lines.slice(0,-1)),lines.length>limit&&(lines=lines.slice(lines.length-limit)),cursor=size,{cursor,size,lines,truncated,reset}}finally{await handle.close()}}const logsHandlers={"logs.tail":async({params,respond})=>{if(!validateLogsTailParams(params)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid logs.tail params: ${formatValidationErrors(validateLogsTailParams.errors)}`));return}let p=params,configuredFile=getResolvedLoggerSettings().file;try{let file=await resolveLogFile(configuredFile);respond(!0,{file,...await readLogSlice({file,cursor:p.cursor,limit:p.limit??500,maxBytes:p.maxBytes??25e4})},void 0)}catch(err){respond(!1,void 0,errorShape(ErrorCodes.UNAVAILABLE,`log read failed: ${String(err)}`))}}},modelsHandlers={"models.list":async({params,respond,context})=>{if(!validateModelsListParams(params)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid models.list params: ${formatValidationErrors(validateModelsListParams.errors)}`));return}try{let models=await context.loadGatewayModelCatalog(),cfg=loadConfig(),resolvedDefault=resolveConfiguredModelRef({cfg,defaultProvider:DEFAULT_PROVIDER,defaultModel:DEFAULT_MODEL}),allowed=buildAllowedModelSet({cfg,catalog:models,defaultProvider:resolvedDefault.provider,defaultModel:resolvedDefault.model}),visibleModels=allowed.allowAny?[...models]:[...allowed.allowedCatalog];visibleModels.some(entry=>entry.provider===`builderforcellm`&&entry.id===`auto`)||visibleModels.push({provider:`builderforcellm`,id:`auto`,name:`BuilderForceAgentsLLM Auto (free pool)`,contextWindow:262144,reasoning:!1,input:[`text`]}),respond(!0,{models:visibleModels},void 0)}catch(err){respond(!1,void 0,errorShape(ErrorCodes.UNAVAILABLE,String(err)))}}};function asRecord(value){return!value||typeof value!=`object`||Array.isArray(value)?null:value}function normalizeString(value){return typeof value==`string`&&value.trim()||null}function normalizeApprovalDecision(value){let s=normalizeString(value);return s===`allow-once`||s===`allow-always`?s:null}function clientHasApprovals(client){let scopes=Array.isArray(client?.connect?.scopes)?client?.connect?.scopes:[];return scopes.includes(`operator.admin`)||scopes.includes(`operator.approvals`)}function getCmdText(params){let raw=normalizeString(params.rawCommand);if(raw)return raw;if(Array.isArray(params.command)){let parts=params.command.map(v=>String(v));if(parts.length>0)return formatExecCommand(parts)}return``}function approvalMatchesRequest(params,record){if(record.request.host!==`node`)return!1;let cmdText=getCmdText(params);return!(!cmdText||record.request.command!==cmdText||(record.request.cwd??null)!==(normalizeString(params.cwd)??null)||(record.request.agentId??null)!==(normalizeString(params.agentId)??null)||(record.request.sessionKey??null)!==(normalizeString(params.sessionKey)??null))}function pickSystemRunParams(raw){let next={};for(let key of[`command`,`rawCommand`,`cwd`,`env`,`timeoutMs`,`needsScreenRecording`,`agentId`,`sessionKey`,`runId`])key in raw&&(next[key]=raw[key]);return next}function sanitizeSystemRunParamsForForwarding(opts){let obj=asRecord(opts.rawParams);if(!obj)return{ok:!0,params:opts.rawParams};let p=obj,argv=Array.isArray(p.command)?p.command.map(v=>String(v)):[],raw=normalizeString(p.rawCommand);if(raw){if(!Array.isArray(p.command)||argv.length===0)return{ok:!1,message:`rawCommand requires params.command`,details:{code:`MISSING_COMMAND`}};let validation=validateSystemRunCommandConsistency({argv,rawCommand:raw});if(!validation.ok)return{ok:!1,message:validation.message,details:validation.details??{code:`RAW_COMMAND_MISMATCH`}}}let approved=p.approved===!0,requestedDecision=normalizeApprovalDecision(p.approvalDecision),wantsApprovalOverride=approved||requestedDecision!==null,next=pickSystemRunParams(obj);if(!wantsApprovalOverride)return{ok:!0,params:next};let runId=normalizeString(p.runId);if(!runId)return{ok:!1,message:`approval override requires params.runId`,details:{code:`MISSING_RUN_ID`}};let manager=opts.execApprovalManager;if(!manager)return{ok:!1,message:`exec approvals unavailable`,details:{code:`APPROVALS_UNAVAILABLE`}};let snapshot=manager.getSnapshot(runId);if(!snapshot)return{ok:!1,message:`unknown or expired approval id`,details:{code:`UNKNOWN_APPROVAL_ID`,runId}};if((typeof opts.nowMs==`number`?opts.nowMs:Date.now())>snapshot.expiresAtMs)return{ok:!1,message:`approval expired`,details:{code:`APPROVAL_EXPIRED`,runId}};let snapshotDeviceId=snapshot.requestedByDeviceId??null,clientDeviceId=opts.client?.connect?.device?.id??null;if(snapshotDeviceId){if(snapshotDeviceId!==clientDeviceId)return{ok:!1,message:`approval id not valid for this device`,details:{code:`APPROVAL_DEVICE_MISMATCH`,runId}}}else if(snapshot.requestedByConnId&&snapshot.requestedByConnId!==(opts.client?.connId??null))return{ok:!1,message:`approval id not valid for this client`,details:{code:`APPROVAL_CLIENT_MISMATCH`,runId}};return approvalMatchesRequest(p,snapshot)?snapshot.decision===`allow-once`||snapshot.decision===`allow-always`?(next.approved=!0,next.approvalDecision=snapshot.decision,{ok:!0,params:next}):snapshot.resolvedAtMs!==void 0&&snapshot.decision===void 0&&snapshot.resolvedBy===null&&approved&&requestedDecision===`allow-once`&&clientHasApprovals(opts.client)?(next.approved=!0,next.approvalDecision=`allow-once`,{ok:!0,params:next}):{ok:!1,message:`approval required`,details:{code:`APPROVAL_REQUIRED`,runId}}:{ok:!1,message:`approval id does not match request`,details:{code:`APPROVAL_REQUEST_MISMATCH`,runId}}}function sanitizeNodeInvokeParamsForForwarding(opts){return opts.command===`system.run`?sanitizeSystemRunParamsForForwarding({rawParams:opts.rawParams,client:opts.client,execApprovalManager:opts.execApprovalManager}):{ok:!0,params:opts.rawParams}}function normalizeNodeInvokeResultParams(params){if(!params||typeof params!=`object`)return params;let normalized={...params};return normalized.payloadJSON===null?delete normalized.payloadJSON:normalized.payloadJSON!==void 0&&typeof normalized.payloadJSON!=`string`&&(normalized.payload===void 0&&(normalized.payload=normalized.payloadJSON),delete normalized.payloadJSON),normalized.error===null&&delete normalized.error,normalized}const handleNodeInvokeResult=async({params,respond,context,client})=>{let normalizedParams=normalizeNodeInvokeResultParams(params);if(!validateNodeInvokeResultParams(normalizedParams)){respondInvalidParams({respond,method:`node.invoke.result`,validator:validateNodeInvokeResultParams});return}let p=normalizedParams,callerNodeId=client?.connect?.device?.id??client?.connect?.client?.id;if(callerNodeId&&callerNodeId!==p.nodeId){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`nodeId mismatch`));return}if(!context.nodeRegistry.handleInvokeResult({id:p.id,nodeId:p.nodeId,ok:p.ok,payload:p.payload,payloadJSON:p.payloadJSON??null,error:p.error??null})){context.logGateway.debug(`late invoke result ignored: id=${p.id} node=${p.nodeId}`),respond(!0,{ok:!0,ignored:!0},void 0);return}respond(!0,{ok:!0},void 0)},nodeWakeById=new Map;function isNodeEntry(entry){return!!(entry.role===`node`||Array.isArray(entry.roles)&&entry.roles.includes(`node`))}async function delayMs(ms){await new Promise(resolve=>setTimeout(resolve,ms))}async function maybeWakeNodeWithApns(nodeId){let state=nodeWakeById.get(nodeId)??{lastWakeAtMs:0};if(nodeWakeById.set(nodeId,state),state.inFlight)return await state.inFlight;let now=Date.now();if(state.lastWakeAtMs>0&&now-state.lastWakeAtMs<15e3)return!0;state.inFlight=(async()=>{try{let registration=await loadApnsRegistration(nodeId);if(!registration)return!1;let auth=await resolveApnsAuthConfigFromEnv(process.env);if(!auth.ok)return!1;state.lastWakeAtMs=Date.now(),await sendApnsBackgroundWake({auth:auth.value,registration,nodeId,wakeReason:`node.invoke`})}catch{if(state.lastWakeAtMs===0)return!1}return!0})();try{return await state.inFlight}finally{state.inFlight=void 0}}async function waitForNodeReconnect(params){let timeoutMs=Math.max(250,params.timeoutMs??3e3),pollMs=Math.max(50,params.pollMs??150),deadline=Date.now()+timeoutMs;for(;Date.now()<deadline;){if(params.context.nodeRegistry.get(params.nodeId))return!0;await delayMs(pollMs)}return!!params.context.nodeRegistry.get(params.nodeId)}const nodeHandlers={"node.pair.request":async({params,respond,context})=>{if(!validateNodePairRequestParams(params)){respondInvalidParams({respond,method:`node.pair.request`,validator:validateNodePairRequestParams});return}let p=params;await respondUnavailableOnThrow(respond,async()=>{let result=await requestNodePairing({nodeId:p.nodeId,displayName:p.displayName,platform:p.platform,version:p.version,coreVersion:p.coreVersion,uiVersion:p.uiVersion,deviceFamily:p.deviceFamily,modelIdentifier:p.modelIdentifier,caps:p.caps,commands:p.commands,remoteIp:p.remoteIp,silent:p.silent});result.status===`pending`&&result.created&&context.broadcast(`node.pair.requested`,result.request,{dropIfSlow:!0}),respond(!0,result,void 0)})},"node.pair.list":async({params,respond})=>{if(!validateNodePairListParams(params)){respondInvalidParams({respond,method:`node.pair.list`,validator:validateNodePairListParams});return}await respondUnavailableOnThrow(respond,async()=>{respond(!0,await listNodePairing(),void 0)})},"node.pair.approve":async({params,respond,context})=>{if(!validateNodePairApproveParams(params)){respondInvalidParams({respond,method:`node.pair.approve`,validator:validateNodePairApproveParams});return}let{requestId}=params;await respondUnavailableOnThrow(respond,async()=>{let approved=await approveNodePairing(requestId);if(!approved){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`unknown requestId`));return}context.broadcast(`node.pair.resolved`,{requestId,nodeId:approved.node.nodeId,decision:`approved`,ts:Date.now()},{dropIfSlow:!0}),respond(!0,approved,void 0)})},"node.pair.reject":async({params,respond,context})=>{if(!validateNodePairRejectParams(params)){respondInvalidParams({respond,method:`node.pair.reject`,validator:validateNodePairRejectParams});return}let{requestId}=params;await respondUnavailableOnThrow(respond,async()=>{let rejected=await rejectNodePairing(requestId);if(!rejected){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`unknown requestId`));return}context.broadcast(`node.pair.resolved`,{requestId,nodeId:rejected.nodeId,decision:`rejected`,ts:Date.now()},{dropIfSlow:!0}),respond(!0,rejected,void 0)})},"node.pair.verify":async({params,respond})=>{if(!validateNodePairVerifyParams(params)){respondInvalidParams({respond,method:`node.pair.verify`,validator:validateNodePairVerifyParams});return}let{nodeId,token}=params;await respondUnavailableOnThrow(respond,async()=>{respond(!0,await verifyNodeToken(nodeId,token),void 0)})},"node.rename":async({params,respond})=>{if(!validateNodeRenameParams(params)){respondInvalidParams({respond,method:`node.rename`,validator:validateNodeRenameParams});return}let{nodeId,displayName}=params;await respondUnavailableOnThrow(respond,async()=>{let trimmed=displayName.trim();if(!trimmed){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`displayName required`));return}let updated=await renamePairedNode(nodeId,trimmed);if(!updated){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`unknown nodeId`));return}respond(!0,{nodeId:updated.nodeId,displayName:updated.displayName},void 0)})},"node.list":async({params,respond,context})=>{if(!validateNodeListParams(params)){respondInvalidParams({respond,method:`node.list`,validator:validateNodeListParams});return}await respondUnavailableOnThrow(respond,async()=>{let list=await listDevicePairing(),pairedById=new Map(list.paired.filter(entry=>isNodeEntry(entry)).map(entry=>[entry.deviceId,{nodeId:entry.deviceId,displayName:entry.displayName,platform:entry.platform,version:void 0,coreVersion:void 0,uiVersion:void 0,deviceFamily:void 0,modelIdentifier:void 0,remoteIp:entry.remoteIp,caps:[],commands:[],permissions:void 0}])),connected=context.nodeRegistry.listConnected(),connectedById=new Map(connected.map(n=>[n.nodeId,n])),nodes=[...new Set([...pairedById.keys(),...connectedById.keys()])].map(nodeId=>{let paired=pairedById.get(nodeId),live=connectedById.get(nodeId),caps=uniqueSortedStrings([...live?.caps??paired?.caps??[]]),commands=uniqueSortedStrings([...live?.commands??paired?.commands??[]]);return{nodeId,displayName:live?.displayName??paired?.displayName,platform:live?.platform??paired?.platform,version:live?.version??paired?.version,coreVersion:live?.coreVersion??paired?.coreVersion,uiVersion:live?.uiVersion??paired?.uiVersion,deviceFamily:live?.deviceFamily??paired?.deviceFamily,modelIdentifier:live?.modelIdentifier??paired?.modelIdentifier,remoteIp:live?.remoteIp??paired?.remoteIp,caps,commands,pathEnv:live?.pathEnv,permissions:live?.permissions??paired?.permissions,connectedAtMs:live?.connectedAtMs,paired:!!paired,connected:!!live}});nodes.sort((a,b)=>{if(a.connected!==b.connected)return a.connected?-1:1;let an=(a.displayName??a.nodeId).toLowerCase(),bn=(b.displayName??b.nodeId).toLowerCase();return an<bn?-1:an>bn?1:a.nodeId.localeCompare(b.nodeId)}),respond(!0,{ts:Date.now(),nodes},void 0)})},"node.describe":async({params,respond,context})=>{if(!validateNodeDescribeParams(params)){respondInvalidParams({respond,method:`node.describe`,validator:validateNodeDescribeParams});return}let{nodeId}=params,id=String(nodeId??``).trim();if(!id){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`nodeId required`));return}await respondUnavailableOnThrow(respond,async()=>{let paired=(await listDevicePairing()).paired.find(n=>n.deviceId===id&&isNodeEntry(n)),live=context.nodeRegistry.listConnected().find(n=>n.nodeId===id);if(!paired&&!live){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`unknown nodeId`));return}let caps=uniqueSortedStrings([...live?.caps??[]]),commands=uniqueSortedStrings([...live?.commands??[]]);respond(!0,{ts:Date.now(),nodeId:id,displayName:live?.displayName??paired?.displayName,platform:live?.platform??paired?.platform,version:live?.version,coreVersion:live?.coreVersion,uiVersion:live?.uiVersion,deviceFamily:live?.deviceFamily,modelIdentifier:live?.modelIdentifier,remoteIp:live?.remoteIp??paired?.remoteIp,caps,commands,pathEnv:live?.pathEnv,permissions:live?.permissions,connectedAtMs:live?.connectedAtMs,paired:!!paired,connected:!!live},void 0)})},"node.invoke":async({params,respond,context,client})=>{if(!validateNodeInvokeParams(params)){respondInvalidParams({respond,method:`node.invoke`,validator:validateNodeInvokeParams});return}let p=params,nodeId=String(p.nodeId??``).trim(),command=String(p.command??``).trim();if(!nodeId||!command){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`nodeId and command required`));return}if(command===`system.execApprovals.get`||command===`system.execApprovals.set`){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`node.invoke does not allow system.execApprovals.*; use exec.approvals.node.*`,{details:{command}}));return}await respondUnavailableOnThrow(respond,async()=>{let nodeSession=context.nodeRegistry.get(nodeId);if(!nodeSession&&(await maybeWakeNodeWithApns(nodeId)&&await waitForNodeReconnect({nodeId,context}),nodeSession=context.nodeRegistry.get(nodeId),!nodeSession)){respond(!1,void 0,errorShape(ErrorCodes.UNAVAILABLE,`node not connected`,{details:{code:`NOT_CONNECTED`}}));return}let allowlist=resolveNodeCommandAllowlist(loadConfig(),nodeSession),allowed=isNodeCommandAllowed({command,declaredCommands:nodeSession.commands,allowlist});if(!allowed.ok){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`node command not allowed`,{details:{reason:allowed.reason,command}}));return}let forwardedParams=sanitizeNodeInvokeParamsForForwarding({command,rawParams:p.params,client,execApprovalManager:context.execApprovalManager});if(!forwardedParams.ok){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,forwardedParams.message,{details:forwardedParams.details??null}));return}let res=await context.nodeRegistry.invoke({nodeId,command,params:forwardedParams.params,timeoutMs:p.timeoutMs,idempotencyKey:p.idempotencyKey});respondUnavailableOnNodeInvokeError(respond,res)&&respond(!0,{ok:!0,nodeId,command,payload:res.payloadJSON?safeParseJson(res.payloadJSON):res.payload,payloadJSON:res.payloadJSON??null},void 0)})},"node.invoke.result":handleNodeInvokeResult,"node.event":async({params,respond,context,client})=>{if(!validateNodeEventParams(params)){respondInvalidParams({respond,method:`node.event`,validator:validateNodeEventParams});return}let p=params,payloadJSON=typeof p.payloadJSON==`string`?p.payloadJSON:p.payload===void 0?null:JSON.stringify(p.payload);await respondUnavailableOnThrow(respond,async()=>{let{handleNodeEvent}=await import(`./server-node-events-CSsH-eIF.js`),nodeId=client?.connect?.device?.id??client?.connect?.client?.id??`node`;await handleNodeEvent({deps:context.deps,broadcast:context.broadcast,nodeSendToSession:context.nodeSendToSession,nodeSubscribe:context.nodeSubscribe,nodeUnsubscribe:context.nodeUnsubscribe,broadcastVoiceWakeChanged:context.broadcastVoiceWakeChanged,addChatRun:context.addChatRun,removeChatRun:context.removeChatRun,chatAbortControllers:context.chatAbortControllers,chatAbortedRuns:context.chatAbortedRuns,chatRunBuffers:context.chatRunBuffers,chatDeltaSentAt:context.chatDeltaSentAt,dedupe:context.dedupe,agentRunSeq:context.agentRunSeq,getHealthCache:context.getHealthCache,refreshHealthSnapshot:context.refreshHealthSnapshot,loadGatewayModelCatalog:context.loadGatewayModelCatalog,logGateway:{warn:context.logGateway.warn}},nodeId,{event:p.event,payloadJSON}),respond(!0,{ok:!0},void 0)})}};function normalizeOptionalString(value){if(typeof value!=`string`)return;let trimmed=value.trim();return trimmed.length>0?trimmed:void 0}const pushHandlers={"push.test":async({params,respond})=>{if(!validatePushTestParams(params)){respondInvalidParams({respond,method:`push.test`,validator:validatePushTestParams});return}let nodeId=String(params.nodeId??``).trim();if(!nodeId){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`nodeId required`));return}let title=normalizeOptionalString(params.title)??`BuilderForceAgents`,body=normalizeOptionalString(params.body)??`Push test for node ${nodeId}`;await respondUnavailableOnThrow(respond,async()=>{let registration=await loadApnsRegistration(nodeId);if(!registration){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`node ${nodeId} has no APNs registration (connect iOS node first)`));return}let auth=await resolveApnsAuthConfigFromEnv(process.env);if(!auth.ok){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,auth.error));return}let overrideEnvironment=normalizeApnsEnvironment(params.environment);respond(!0,await sendApnsAlert({auth:auth.value,registration:{...registration,environment:overrideEnvironment??registration.environment},nodeId,title,body}),void 0)})}},inflightByContext=new WeakMap,getInflightMap=context=>{let inflight=inflightByContext.get(context);return inflight||(inflight=new Map,inflightByContext.set(context,inflight)),inflight},sendHandlers={send:async({params,respond,context})=>{let p=params;if(!validateSendParams(p)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid send params: ${formatValidationErrors(validateSendParams.errors)}`));return}let request=p,idem=request.idempotencyKey,dedupeKey=`send:${idem}`,cached=context.dedupe.get(dedupeKey);if(cached){respond(cached.ok,cached.payload,cached.error,{cached:!0});return}let inflightMap=getInflightMap(context),inflight=inflightMap.get(dedupeKey);if(inflight){let result=await inflight,meta=result.meta?{...result.meta,cached:!0}:{cached:!0};respond(result.ok,result.payload,result.error,meta);return}let to=request.to.trim(),message=typeof request.message==`string`?request.message.trim():``,mediaUrl=typeof request.mediaUrl==`string`&&request.mediaUrl.trim().length>0?request.mediaUrl.trim():void 0,mediaUrls=Array.isArray(request.mediaUrls)?request.mediaUrls.map(entry=>typeof entry==`string`?entry.trim():``).filter(entry=>entry.length>0):void 0;if(!message&&!mediaUrl&&(mediaUrls?.length??0)===0){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid send params: text or media is required`));return}let channelInput=typeof request.channel==`string`?request.channel:void 0,normalizedChannel=channelInput?normalizeChannelId(channelInput):null;if(channelInput&&!normalizedChannel){if(channelInput.trim().toLowerCase()===`webchat`){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,"unsupported channel: webchat (internal-only). Use `chat.send` for WebChat UI messages or choose a deliverable channel."));return}respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`unsupported channel: ${channelInput}`));return}let channel=normalizedChannel??DEFAULT_CHAT_CHANNEL,accountId=typeof request.accountId==`string`&&request.accountId.trim().length?request.accountId.trim():void 0,threadId=typeof request.threadId==`string`&&request.threadId.trim().length?request.threadId.trim():void 0,outboundChannel=channel;if(!getChannelPlugin(channel)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`unsupported channel: ${channel}`));return}let work=(async()=>{try{let cfg=loadConfig(),resolved=resolveOutboundTarget({channel:outboundChannel,to,cfg,accountId,mode:`explicit`});if(!resolved.ok)return{ok:!1,error:errorShape(ErrorCodes.INVALID_REQUEST,String(resolved.error)),meta:{channel}};let outboundDeps=context.deps?createOutboundSendDeps(context.deps):void 0,mirrorPayloads=normalizeReplyPayloadsForDelivery([{text:message,mediaUrl,mediaUrls}]),mirrorText=mirrorPayloads.map(payload=>payload.text).filter(Boolean).join(`
|
|
17
|
+
`&&(lines=lines.slice(1)),lines.length>0&&lines[lines.length-1]===``&&(lines=lines.slice(0,-1)),lines.length>limit&&(lines=lines.slice(lines.length-limit)),cursor=size,{cursor,size,lines,truncated,reset}}finally{await handle.close()}}const logsHandlers={"logs.tail":async({params,respond})=>{if(!validateLogsTailParams(params)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid logs.tail params: ${formatValidationErrors(validateLogsTailParams.errors)}`));return}let p=params,configuredFile=getResolvedLoggerSettings().file;try{let file=await resolveLogFile(configuredFile);respond(!0,{file,...await readLogSlice({file,cursor:p.cursor,limit:p.limit??500,maxBytes:p.maxBytes??25e4})},void 0)}catch(err){respond(!1,void 0,errorShape(ErrorCodes.UNAVAILABLE,`log read failed: ${String(err)}`))}}},modelsHandlers={"models.list":async({params,respond,context})=>{if(!validateModelsListParams(params)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid models.list params: ${formatValidationErrors(validateModelsListParams.errors)}`));return}try{let models=await context.loadGatewayModelCatalog(),cfg=loadConfig(),resolvedDefault=resolveConfiguredModelRef({cfg,defaultProvider:DEFAULT_PROVIDER,defaultModel:DEFAULT_MODEL}),allowed=buildAllowedModelSet({cfg,catalog:models,defaultProvider:resolvedDefault.provider,defaultModel:resolvedDefault.model}),visibleModels=allowed.allowAny?[...models]:[...allowed.allowedCatalog];visibleModels.some(entry=>entry.provider===`builderforcellm`&&entry.id===`auto`)||visibleModels.push({provider:`builderforcellm`,id:`auto`,name:`BuilderForceAgentsLLM Auto (free pool)`,contextWindow:262144,reasoning:!1,input:[`text`]}),respond(!0,{models:visibleModels},void 0)}catch(err){respond(!1,void 0,errorShape(ErrorCodes.UNAVAILABLE,String(err)))}}};function asRecord(value){return!value||typeof value!=`object`||Array.isArray(value)?null:value}function normalizeString(value){return typeof value==`string`&&value.trim()||null}function normalizeApprovalDecision(value){let s=normalizeString(value);return s===`allow-once`||s===`allow-always`?s:null}function clientHasApprovals(client){let scopes=Array.isArray(client?.connect?.scopes)?client?.connect?.scopes:[];return scopes.includes(`operator.admin`)||scopes.includes(`operator.approvals`)}function getCmdText(params){let raw=normalizeString(params.rawCommand);if(raw)return raw;if(Array.isArray(params.command)){let parts=params.command.map(v=>String(v));if(parts.length>0)return formatExecCommand(parts)}return``}function approvalMatchesRequest(params,record){if(record.request.host!==`node`)return!1;let cmdText=getCmdText(params);return!(!cmdText||record.request.command!==cmdText||(record.request.cwd??null)!==(normalizeString(params.cwd)??null)||(record.request.agentId??null)!==(normalizeString(params.agentId)??null)||(record.request.sessionKey??null)!==(normalizeString(params.sessionKey)??null))}function pickSystemRunParams(raw){let next={};for(let key of[`command`,`rawCommand`,`cwd`,`env`,`timeoutMs`,`needsScreenRecording`,`agentId`,`sessionKey`,`runId`])key in raw&&(next[key]=raw[key]);return next}function sanitizeSystemRunParamsForForwarding(opts){let obj=asRecord(opts.rawParams);if(!obj)return{ok:!0,params:opts.rawParams};let p=obj,argv=Array.isArray(p.command)?p.command.map(v=>String(v)):[],raw=normalizeString(p.rawCommand);if(raw){if(!Array.isArray(p.command)||argv.length===0)return{ok:!1,message:`rawCommand requires params.command`,details:{code:`MISSING_COMMAND`}};let validation=validateSystemRunCommandConsistency({argv,rawCommand:raw});if(!validation.ok)return{ok:!1,message:validation.message,details:validation.details??{code:`RAW_COMMAND_MISMATCH`}}}let approved=p.approved===!0,requestedDecision=normalizeApprovalDecision(p.approvalDecision),wantsApprovalOverride=approved||requestedDecision!==null,next=pickSystemRunParams(obj);if(!wantsApprovalOverride)return{ok:!0,params:next};let runId=normalizeString(p.runId);if(!runId)return{ok:!1,message:`approval override requires params.runId`,details:{code:`MISSING_RUN_ID`}};let manager=opts.execApprovalManager;if(!manager)return{ok:!1,message:`exec approvals unavailable`,details:{code:`APPROVALS_UNAVAILABLE`}};let snapshot=manager.getSnapshot(runId);if(!snapshot)return{ok:!1,message:`unknown or expired approval id`,details:{code:`UNKNOWN_APPROVAL_ID`,runId}};if((typeof opts.nowMs==`number`?opts.nowMs:Date.now())>snapshot.expiresAtMs)return{ok:!1,message:`approval expired`,details:{code:`APPROVAL_EXPIRED`,runId}};let snapshotDeviceId=snapshot.requestedByDeviceId??null,clientDeviceId=opts.client?.connect?.device?.id??null;if(snapshotDeviceId){if(snapshotDeviceId!==clientDeviceId)return{ok:!1,message:`approval id not valid for this device`,details:{code:`APPROVAL_DEVICE_MISMATCH`,runId}}}else if(snapshot.requestedByConnId&&snapshot.requestedByConnId!==(opts.client?.connId??null))return{ok:!1,message:`approval id not valid for this client`,details:{code:`APPROVAL_CLIENT_MISMATCH`,runId}};return approvalMatchesRequest(p,snapshot)?snapshot.decision===`allow-once`||snapshot.decision===`allow-always`?(next.approved=!0,next.approvalDecision=snapshot.decision,{ok:!0,params:next}):snapshot.resolvedAtMs!==void 0&&snapshot.decision===void 0&&snapshot.resolvedBy===null&&approved&&requestedDecision===`allow-once`&&clientHasApprovals(opts.client)?(next.approved=!0,next.approvalDecision=`allow-once`,{ok:!0,params:next}):{ok:!1,message:`approval required`,details:{code:`APPROVAL_REQUIRED`,runId}}:{ok:!1,message:`approval id does not match request`,details:{code:`APPROVAL_REQUEST_MISMATCH`,runId}}}function sanitizeNodeInvokeParamsForForwarding(opts){return opts.command===`system.run`?sanitizeSystemRunParamsForForwarding({rawParams:opts.rawParams,client:opts.client,execApprovalManager:opts.execApprovalManager}):{ok:!0,params:opts.rawParams}}function normalizeNodeInvokeResultParams(params){if(!params||typeof params!=`object`)return params;let normalized={...params};return normalized.payloadJSON===null?delete normalized.payloadJSON:normalized.payloadJSON!==void 0&&typeof normalized.payloadJSON!=`string`&&(normalized.payload===void 0&&(normalized.payload=normalized.payloadJSON),delete normalized.payloadJSON),normalized.error===null&&delete normalized.error,normalized}const handleNodeInvokeResult=async({params,respond,context,client})=>{let normalizedParams=normalizeNodeInvokeResultParams(params);if(!validateNodeInvokeResultParams(normalizedParams)){respondInvalidParams({respond,method:`node.invoke.result`,validator:validateNodeInvokeResultParams});return}let p=normalizedParams,callerNodeId=client?.connect?.device?.id??client?.connect?.client?.id;if(callerNodeId&&callerNodeId!==p.nodeId){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`nodeId mismatch`));return}if(!context.nodeRegistry.handleInvokeResult({id:p.id,nodeId:p.nodeId,ok:p.ok,payload:p.payload,payloadJSON:p.payloadJSON??null,error:p.error??null})){context.logGateway.debug(`late invoke result ignored: id=${p.id} node=${p.nodeId}`),respond(!0,{ok:!0,ignored:!0},void 0);return}respond(!0,{ok:!0},void 0)},nodeWakeById=new Map;function isNodeEntry(entry){return!!(entry.role===`node`||Array.isArray(entry.roles)&&entry.roles.includes(`node`))}async function delayMs(ms){await new Promise(resolve=>setTimeout(resolve,ms))}async function maybeWakeNodeWithApns(nodeId){let state=nodeWakeById.get(nodeId)??{lastWakeAtMs:0};if(nodeWakeById.set(nodeId,state),state.inFlight)return await state.inFlight;let now=Date.now();if(state.lastWakeAtMs>0&&now-state.lastWakeAtMs<15e3)return!0;state.inFlight=(async()=>{try{let registration=await loadApnsRegistration(nodeId);if(!registration)return!1;let auth=await resolveApnsAuthConfigFromEnv(process.env);if(!auth.ok)return!1;state.lastWakeAtMs=Date.now(),await sendApnsBackgroundWake({auth:auth.value,registration,nodeId,wakeReason:`node.invoke`})}catch{if(state.lastWakeAtMs===0)return!1}return!0})();try{return await state.inFlight}finally{state.inFlight=void 0}}async function waitForNodeReconnect(params){let timeoutMs=Math.max(250,params.timeoutMs??3e3),pollMs=Math.max(50,params.pollMs??150),deadline=Date.now()+timeoutMs;for(;Date.now()<deadline;){if(params.context.nodeRegistry.get(params.nodeId))return!0;await delayMs(pollMs)}return!!params.context.nodeRegistry.get(params.nodeId)}const nodeHandlers={"node.pair.request":async({params,respond,context})=>{if(!validateNodePairRequestParams(params)){respondInvalidParams({respond,method:`node.pair.request`,validator:validateNodePairRequestParams});return}let p=params;await respondUnavailableOnThrow(respond,async()=>{let result=await requestNodePairing({nodeId:p.nodeId,displayName:p.displayName,platform:p.platform,version:p.version,coreVersion:p.coreVersion,uiVersion:p.uiVersion,deviceFamily:p.deviceFamily,modelIdentifier:p.modelIdentifier,caps:p.caps,commands:p.commands,remoteIp:p.remoteIp,silent:p.silent});result.status===`pending`&&result.created&&context.broadcast(`node.pair.requested`,result.request,{dropIfSlow:!0}),respond(!0,result,void 0)})},"node.pair.list":async({params,respond})=>{if(!validateNodePairListParams(params)){respondInvalidParams({respond,method:`node.pair.list`,validator:validateNodePairListParams});return}await respondUnavailableOnThrow(respond,async()=>{respond(!0,await listNodePairing(),void 0)})},"node.pair.approve":async({params,respond,context})=>{if(!validateNodePairApproveParams(params)){respondInvalidParams({respond,method:`node.pair.approve`,validator:validateNodePairApproveParams});return}let{requestId}=params;await respondUnavailableOnThrow(respond,async()=>{let approved=await approveNodePairing(requestId);if(!approved){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`unknown requestId`));return}context.broadcast(`node.pair.resolved`,{requestId,nodeId:approved.node.nodeId,decision:`approved`,ts:Date.now()},{dropIfSlow:!0}),respond(!0,approved,void 0)})},"node.pair.reject":async({params,respond,context})=>{if(!validateNodePairRejectParams(params)){respondInvalidParams({respond,method:`node.pair.reject`,validator:validateNodePairRejectParams});return}let{requestId}=params;await respondUnavailableOnThrow(respond,async()=>{let rejected=await rejectNodePairing(requestId);if(!rejected){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`unknown requestId`));return}context.broadcast(`node.pair.resolved`,{requestId,nodeId:rejected.nodeId,decision:`rejected`,ts:Date.now()},{dropIfSlow:!0}),respond(!0,rejected,void 0)})},"node.pair.verify":async({params,respond})=>{if(!validateNodePairVerifyParams(params)){respondInvalidParams({respond,method:`node.pair.verify`,validator:validateNodePairVerifyParams});return}let{nodeId,token}=params;await respondUnavailableOnThrow(respond,async()=>{respond(!0,await verifyNodeToken(nodeId,token),void 0)})},"node.rename":async({params,respond})=>{if(!validateNodeRenameParams(params)){respondInvalidParams({respond,method:`node.rename`,validator:validateNodeRenameParams});return}let{nodeId,displayName}=params;await respondUnavailableOnThrow(respond,async()=>{let trimmed=displayName.trim();if(!trimmed){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`displayName required`));return}let updated=await renamePairedNode(nodeId,trimmed);if(!updated){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`unknown nodeId`));return}respond(!0,{nodeId:updated.nodeId,displayName:updated.displayName},void 0)})},"node.list":async({params,respond,context})=>{if(!validateNodeListParams(params)){respondInvalidParams({respond,method:`node.list`,validator:validateNodeListParams});return}await respondUnavailableOnThrow(respond,async()=>{let list=await listDevicePairing(),pairedById=new Map(list.paired.filter(entry=>isNodeEntry(entry)).map(entry=>[entry.deviceId,{nodeId:entry.deviceId,displayName:entry.displayName,platform:entry.platform,version:void 0,coreVersion:void 0,uiVersion:void 0,deviceFamily:void 0,modelIdentifier:void 0,remoteIp:entry.remoteIp,caps:[],commands:[],permissions:void 0}])),connected=context.nodeRegistry.listConnected(),connectedById=new Map(connected.map(n=>[n.nodeId,n])),nodes=[...new Set([...pairedById.keys(),...connectedById.keys()])].map(nodeId=>{let paired=pairedById.get(nodeId),live=connectedById.get(nodeId),caps=uniqueSortedStrings([...live?.caps??paired?.caps??[]]),commands=uniqueSortedStrings([...live?.commands??paired?.commands??[]]);return{nodeId,displayName:live?.displayName??paired?.displayName,platform:live?.platform??paired?.platform,version:live?.version??paired?.version,coreVersion:live?.coreVersion??paired?.coreVersion,uiVersion:live?.uiVersion??paired?.uiVersion,deviceFamily:live?.deviceFamily??paired?.deviceFamily,modelIdentifier:live?.modelIdentifier??paired?.modelIdentifier,remoteIp:live?.remoteIp??paired?.remoteIp,caps,commands,pathEnv:live?.pathEnv,permissions:live?.permissions??paired?.permissions,connectedAtMs:live?.connectedAtMs,paired:!!paired,connected:!!live}});nodes.sort((a,b)=>{if(a.connected!==b.connected)return a.connected?-1:1;let an=(a.displayName??a.nodeId).toLowerCase(),bn=(b.displayName??b.nodeId).toLowerCase();return an<bn?-1:an>bn?1:a.nodeId.localeCompare(b.nodeId)}),respond(!0,{ts:Date.now(),nodes},void 0)})},"node.describe":async({params,respond,context})=>{if(!validateNodeDescribeParams(params)){respondInvalidParams({respond,method:`node.describe`,validator:validateNodeDescribeParams});return}let{nodeId}=params,id=String(nodeId??``).trim();if(!id){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`nodeId required`));return}await respondUnavailableOnThrow(respond,async()=>{let paired=(await listDevicePairing()).paired.find(n=>n.deviceId===id&&isNodeEntry(n)),live=context.nodeRegistry.listConnected().find(n=>n.nodeId===id);if(!paired&&!live){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`unknown nodeId`));return}let caps=uniqueSortedStrings([...live?.caps??[]]),commands=uniqueSortedStrings([...live?.commands??[]]);respond(!0,{ts:Date.now(),nodeId:id,displayName:live?.displayName??paired?.displayName,platform:live?.platform??paired?.platform,version:live?.version,coreVersion:live?.coreVersion,uiVersion:live?.uiVersion,deviceFamily:live?.deviceFamily,modelIdentifier:live?.modelIdentifier,remoteIp:live?.remoteIp??paired?.remoteIp,caps,commands,pathEnv:live?.pathEnv,permissions:live?.permissions,connectedAtMs:live?.connectedAtMs,paired:!!paired,connected:!!live},void 0)})},"node.invoke":async({params,respond,context,client})=>{if(!validateNodeInvokeParams(params)){respondInvalidParams({respond,method:`node.invoke`,validator:validateNodeInvokeParams});return}let p=params,nodeId=String(p.nodeId??``).trim(),command=String(p.command??``).trim();if(!nodeId||!command){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`nodeId and command required`));return}if(command===`system.execApprovals.get`||command===`system.execApprovals.set`){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`node.invoke does not allow system.execApprovals.*; use exec.approvals.node.*`,{details:{command}}));return}await respondUnavailableOnThrow(respond,async()=>{let nodeSession=context.nodeRegistry.get(nodeId);if(!nodeSession&&(await maybeWakeNodeWithApns(nodeId)&&await waitForNodeReconnect({nodeId,context}),nodeSession=context.nodeRegistry.get(nodeId),!nodeSession)){respond(!1,void 0,errorShape(ErrorCodes.UNAVAILABLE,`node not connected`,{details:{code:`NOT_CONNECTED`}}));return}let allowlist=resolveNodeCommandAllowlist(loadConfig(),nodeSession),allowed=isNodeCommandAllowed({command,declaredCommands:nodeSession.commands,allowlist});if(!allowed.ok){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`node command not allowed`,{details:{reason:allowed.reason,command}}));return}let forwardedParams=sanitizeNodeInvokeParamsForForwarding({command,rawParams:p.params,client,execApprovalManager:context.execApprovalManager});if(!forwardedParams.ok){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,forwardedParams.message,{details:forwardedParams.details??null}));return}let res=await context.nodeRegistry.invoke({nodeId,command,params:forwardedParams.params,timeoutMs:p.timeoutMs,idempotencyKey:p.idempotencyKey});respondUnavailableOnNodeInvokeError(respond,res)&&respond(!0,{ok:!0,nodeId,command,payload:res.payloadJSON?safeParseJson(res.payloadJSON):res.payload,payloadJSON:res.payloadJSON??null},void 0)})},"node.invoke.result":handleNodeInvokeResult,"node.event":async({params,respond,context,client})=>{if(!validateNodeEventParams(params)){respondInvalidParams({respond,method:`node.event`,validator:validateNodeEventParams});return}let p=params,payloadJSON=typeof p.payloadJSON==`string`?p.payloadJSON:p.payload===void 0?null:JSON.stringify(p.payload);await respondUnavailableOnThrow(respond,async()=>{let{handleNodeEvent}=await import(`./server-node-events-BZuSkcbo.js`),nodeId=client?.connect?.device?.id??client?.connect?.client?.id??`node`;await handleNodeEvent({deps:context.deps,broadcast:context.broadcast,nodeSendToSession:context.nodeSendToSession,nodeSubscribe:context.nodeSubscribe,nodeUnsubscribe:context.nodeUnsubscribe,broadcastVoiceWakeChanged:context.broadcastVoiceWakeChanged,addChatRun:context.addChatRun,removeChatRun:context.removeChatRun,chatAbortControllers:context.chatAbortControllers,chatAbortedRuns:context.chatAbortedRuns,chatRunBuffers:context.chatRunBuffers,chatDeltaSentAt:context.chatDeltaSentAt,dedupe:context.dedupe,agentRunSeq:context.agentRunSeq,getHealthCache:context.getHealthCache,refreshHealthSnapshot:context.refreshHealthSnapshot,loadGatewayModelCatalog:context.loadGatewayModelCatalog,logGateway:{warn:context.logGateway.warn}},nodeId,{event:p.event,payloadJSON}),respond(!0,{ok:!0},void 0)})}};function normalizeOptionalString(value){if(typeof value!=`string`)return;let trimmed=value.trim();return trimmed.length>0?trimmed:void 0}const pushHandlers={"push.test":async({params,respond})=>{if(!validatePushTestParams(params)){respondInvalidParams({respond,method:`push.test`,validator:validatePushTestParams});return}let nodeId=String(params.nodeId??``).trim();if(!nodeId){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`nodeId required`));return}let title=normalizeOptionalString(params.title)??`BuilderForceAgents`,body=normalizeOptionalString(params.body)??`Push test for node ${nodeId}`;await respondUnavailableOnThrow(respond,async()=>{let registration=await loadApnsRegistration(nodeId);if(!registration){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`node ${nodeId} has no APNs registration (connect iOS node first)`));return}let auth=await resolveApnsAuthConfigFromEnv(process.env);if(!auth.ok){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,auth.error));return}let overrideEnvironment=normalizeApnsEnvironment(params.environment);respond(!0,await sendApnsAlert({auth:auth.value,registration:{...registration,environment:overrideEnvironment??registration.environment},nodeId,title,body}),void 0)})}},inflightByContext=new WeakMap,getInflightMap=context=>{let inflight=inflightByContext.get(context);return inflight||(inflight=new Map,inflightByContext.set(context,inflight)),inflight},sendHandlers={send:async({params,respond,context})=>{let p=params;if(!validateSendParams(p)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid send params: ${formatValidationErrors(validateSendParams.errors)}`));return}let request=p,idem=request.idempotencyKey,dedupeKey=`send:${idem}`,cached=context.dedupe.get(dedupeKey);if(cached){respond(cached.ok,cached.payload,cached.error,{cached:!0});return}let inflightMap=getInflightMap(context),inflight=inflightMap.get(dedupeKey);if(inflight){let result=await inflight,meta=result.meta?{...result.meta,cached:!0}:{cached:!0};respond(result.ok,result.payload,result.error,meta);return}let to=request.to.trim(),message=typeof request.message==`string`?request.message.trim():``,mediaUrl=typeof request.mediaUrl==`string`&&request.mediaUrl.trim().length>0?request.mediaUrl.trim():void 0,mediaUrls=Array.isArray(request.mediaUrls)?request.mediaUrls.map(entry=>typeof entry==`string`?entry.trim():``).filter(entry=>entry.length>0):void 0;if(!message&&!mediaUrl&&(mediaUrls?.length??0)===0){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid send params: text or media is required`));return}let channelInput=typeof request.channel==`string`?request.channel:void 0,normalizedChannel=channelInput?normalizeChannelId(channelInput):null;if(channelInput&&!normalizedChannel){if(channelInput.trim().toLowerCase()===`webchat`){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,"unsupported channel: webchat (internal-only). Use `chat.send` for WebChat UI messages or choose a deliverable channel."));return}respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`unsupported channel: ${channelInput}`));return}let channel=normalizedChannel??DEFAULT_CHAT_CHANNEL,accountId=typeof request.accountId==`string`&&request.accountId.trim().length?request.accountId.trim():void 0,threadId=typeof request.threadId==`string`&&request.threadId.trim().length?request.threadId.trim():void 0,outboundChannel=channel;if(!getChannelPlugin(channel)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`unsupported channel: ${channel}`));return}let work=(async()=>{try{let cfg=loadConfig(),resolved=resolveOutboundTarget({channel:outboundChannel,to,cfg,accountId,mode:`explicit`});if(!resolved.ok)return{ok:!1,error:errorShape(ErrorCodes.INVALID_REQUEST,String(resolved.error)),meta:{channel}};let outboundDeps=context.deps?createOutboundSendDeps(context.deps):void 0,mirrorPayloads=normalizeReplyPayloadsForDelivery([{text:message,mediaUrl,mediaUrls}]),mirrorText=mirrorPayloads.map(payload=>payload.text).filter(Boolean).join(`
|
|
18
18
|
`),mirrorMediaUrls=mirrorPayloads.flatMap(payload=>payload.mediaUrls??(payload.mediaUrl?[payload.mediaUrl]:[])),providedSessionKey=typeof request.sessionKey==`string`&&request.sessionKey.trim()?request.sessionKey.trim().toLowerCase():void 0,derivedAgentId=resolveSessionAgentId({config:cfg}),derivedRoute=providedSessionKey?null:await resolveOutboundSessionRoute({cfg,channel,agentId:derivedAgentId,accountId,target:resolved.to,threadId});derivedRoute&&await ensureOutboundSessionEntry({cfg,agentId:derivedAgentId,channel,accountId,route:derivedRoute});let result=(await deliverOutboundPayloads({cfg,channel:outboundChannel,to:resolved.to,accountId,payloads:[{text:message,mediaUrl,mediaUrls}],agentId:providedSessionKey?resolveSessionAgentId({sessionKey:providedSessionKey,config:cfg}):derivedAgentId,gifPlayback:request.gifPlayback,threadId:threadId??null,deps:outboundDeps,mirror:providedSessionKey?{sessionKey:providedSessionKey,agentId:resolveSessionAgentId({sessionKey:providedSessionKey,config:cfg}),text:mirrorText||message,mediaUrls:mirrorMediaUrls.length>0?mirrorMediaUrls:void 0}:derivedRoute?{sessionKey:derivedRoute.sessionKey,agentId:derivedAgentId,text:mirrorText||message,mediaUrls:mirrorMediaUrls.length>0?mirrorMediaUrls:void 0}:void 0})).at(-1);if(!result)throw Error(`No delivery result`);let payload={runId:idem,messageId:result.messageId,channel};return`chatId`in result&&(payload.chatId=result.chatId),`channelId`in result&&(payload.channelId=result.channelId),`toJid`in result&&(payload.toJid=result.toJid),`conversationId`in result&&(payload.conversationId=result.conversationId),context.dedupe.set(dedupeKey,{ts:Date.now(),ok:!0,payload}),{ok:!0,payload,meta:{channel}}}catch(err){let error=errorShape(ErrorCodes.UNAVAILABLE,String(err));return context.dedupe.set(dedupeKey,{ts:Date.now(),ok:!1,error}),{ok:!1,error,meta:{channel,error:formatForLog(err)}}}})();inflightMap.set(dedupeKey,work);try{let result=await work;respond(result.ok,result.payload,result.error,result.meta)}finally{inflightMap.delete(dedupeKey)}},poll:async({params,respond,context})=>{let p=params;if(!validatePollParams(p)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid poll params: ${formatValidationErrors(validatePollParams.errors)}`));return}let request=p,idem=request.idempotencyKey,cached=context.dedupe.get(`poll:${idem}`);if(cached){respond(cached.ok,cached.payload,cached.error,{cached:!0});return}let to=request.to.trim(),channelInput=typeof request.channel==`string`?request.channel:void 0,normalizedChannel=channelInput?normalizeChannelId(channelInput):null;if(channelInput&&!normalizedChannel){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`unsupported poll channel: ${channelInput}`));return}let channel=normalizedChannel??DEFAULT_CHAT_CHANNEL;if(typeof request.durationSeconds==`number`&&channel!==`telegram`){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`durationSeconds is only supported for Telegram polls`));return}if(typeof request.isAnonymous==`boolean`&&channel!==`telegram`){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`isAnonymous is only supported for Telegram polls`));return}let poll={question:request.question,options:request.options,maxSelections:request.maxSelections,durationSeconds:request.durationSeconds,durationHours:request.durationHours},threadId=typeof request.threadId==`string`&&request.threadId.trim().length?request.threadId.trim():void 0,accountId=typeof request.accountId==`string`&&request.accountId.trim().length?request.accountId.trim():void 0;try{let outbound=getChannelPlugin(channel)?.outbound;if(!outbound?.sendPoll){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`unsupported poll channel: ${channel}`));return}let cfg=loadConfig(),resolved=resolveOutboundTarget({channel,to,cfg,accountId,mode:`explicit`});if(!resolved.ok){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,String(resolved.error)));return}let normalized=outbound.pollMaxOptions?normalizePollInput(poll,{maxOptions:outbound.pollMaxOptions}):normalizePollInput(poll),result=await outbound.sendPoll({cfg,to:resolved.to,poll:normalized,accountId,threadId,silent:request.silent,isAnonymous:request.isAnonymous}),payload={runId:idem,messageId:result.messageId,channel};result.toJid&&(payload.toJid=result.toJid),result.channelId&&(payload.channelId=result.channelId),result.conversationId&&(payload.conversationId=result.conversationId),result.pollId&&(payload.pollId=result.pollId),context.dedupe.set(`poll:${idem}`,{ts:Date.now(),ok:!0,payload}),respond(!0,payload,void 0,{channel})}catch(err){let error=errorShape(ErrorCodes.UNAVAILABLE,String(err));context.dedupe.set(`poll:${idem}`,{ts:Date.now(),ok:!1,error}),respond(!1,void 0,error,{channel,error:formatForLog(err)})}}};function collectSkillBins(entries){let bins=new Set;for(let entry of entries){let required=entry.metadata?.requires?.bins??[],anyBins=entry.metadata?.requires?.anyBins??[],install=entry.metadata?.install??[];for(let bin of required){let trimmed=bin.trim();trimmed&&bins.add(trimmed)}for(let bin of anyBins){let trimmed=bin.trim();trimmed&&bins.add(trimmed)}for(let spec of install){let specBins=spec?.bins??[];for(let bin of specBins){let trimmed=String(bin).trim();trimmed&&bins.add(trimmed)}}}return[...bins].toSorted()}const skillsHandlers={"skills.status":({params,respond})=>{if(!validateSkillsStatusParams(params)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid skills.status params: ${formatValidationErrors(validateSkillsStatusParams.errors)}`));return}let cfg=loadConfig(),agentIdRaw=typeof params?.agentId==`string`?params.agentId.trim():``,agentId=agentIdRaw?normalizeAgentId(agentIdRaw):resolveDefaultAgentId(cfg);if(agentIdRaw&&!listAgentIds(cfg).includes(agentId)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`unknown agent id "${agentIdRaw}"`));return}respond(!0,buildWorkspaceSkillStatus(resolveAgentWorkspaceDir(cfg,agentId),{config:cfg,eligibility:{remote:getRemoteSkillEligibility()}}),void 0)},"skills.bins":({params,respond})=>{if(!validateSkillsBinsParams(params)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid skills.bins params: ${formatValidationErrors(validateSkillsBinsParams.errors)}`));return}let cfg=loadConfig(),workspaceDirs=listAgentWorkspaceDirs(cfg),bins=new Set;for(let workspaceDir of workspaceDirs){let entries=loadWorkspaceSkillEntries(workspaceDir,{config:cfg});for(let bin of collectSkillBins(entries))bins.add(bin)}respond(!0,{bins:[...bins].toSorted()},void 0)},"skills.install":async({params,respond})=>{if(!validateSkillsInstallParams(params)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid skills.install params: ${formatValidationErrors(validateSkillsInstallParams.errors)}`));return}let p=params,cfg=loadConfig(),result=await installSkill({workspaceDir:resolveAgentWorkspaceDir(cfg,resolveDefaultAgentId(cfg)),skillName:p.name,installId:p.installId,timeoutMs:p.timeoutMs,config:cfg});respond(result.ok,result,result.ok?void 0:errorShape(ErrorCodes.UNAVAILABLE,result.message))},"skills.update":async({params,respond})=>{if(!validateSkillsUpdateParams(params)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid skills.update params: ${formatValidationErrors(validateSkillsUpdateParams.errors)}`));return}let p=params,cfg=loadConfig(),skills=cfg.skills?{...cfg.skills}:{},entries=skills.entries?{...skills.entries}:{},current=entries[p.skillKey]?{...entries[p.skillKey]}:{};if(typeof p.enabled==`boolean`&&(current.enabled=p.enabled),typeof p.apiKey==`string`){let trimmed=normalizeSecretInput(p.apiKey);trimmed?current.apiKey=trimmed:delete current.apiKey}if(p.env&&typeof p.env==`object`){let nextEnv=current.env?{...current.env}:{};for(let[key,value]of Object.entries(p.env)){let trimmedKey=key.trim();if(!trimmedKey)continue;let trimmedVal=value.trim();trimmedVal?nextEnv[trimmedKey]=trimmedVal:delete nextEnv[trimmedKey]}current.env=nextEnv}entries[p.skillKey]=current,skills.entries=entries,await writeConfigFile({...cfg,skills}),respond(!0,{ok:!0,skillKey:p.skillKey,config:current},void 0)}};function broadcastPresenceSnapshot(params){let presenceVersion=params.incrementPresenceVersion();return params.broadcast(`presence`,{presence:listSystemPresence()},{dropIfSlow:!0,stateVersion:{presence:presenceVersion,health:params.getHealthVersion()}}),presenceVersion}const systemHandlers={"last-heartbeat":({respond})=>{respond(!0,getLastHeartbeatEvent(),void 0)},"set-heartbeats":({params,respond})=>{let enabled=params.enabled;if(typeof enabled!=`boolean`){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid set-heartbeats params: enabled (boolean) required`));return}setHeartbeatsEnabled(enabled),respond(!0,{ok:!0,enabled},void 0)},"system-presence":({respond})=>{respond(!0,listSystemPresence(),void 0)},"system-event":({params,respond,context})=>{let text=typeof params.text==`string`?params.text.trim():``;if(!text){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`text required`));return}let sessionKey=resolveMainSessionKeyFromConfig(),deviceId=typeof params.deviceId==`string`?params.deviceId:void 0,instanceId=typeof params.instanceId==`string`?params.instanceId:void 0,host=typeof params.host==`string`?params.host:void 0,ip=typeof params.ip==`string`?params.ip:void 0,mode=typeof params.mode==`string`?params.mode:void 0,version=typeof params.version==`string`?params.version:void 0,platform=typeof params.platform==`string`?params.platform:void 0,deviceFamily=typeof params.deviceFamily==`string`?params.deviceFamily:void 0,modelIdentifier=typeof params.modelIdentifier==`string`?params.modelIdentifier:void 0,lastInputSeconds=typeof params.lastInputSeconds==`number`&&Number.isFinite(params.lastInputSeconds)?params.lastInputSeconds:void 0,reason=typeof params.reason==`string`?params.reason:void 0,presenceUpdate=updateSystemPresence({text,deviceId,instanceId,host,ip,mode,version,platform,deviceFamily,modelIdentifier,lastInputSeconds,reason,roles:Array.isArray(params.roles)&¶ms.roles.every(t=>typeof t==`string`)?params.roles:void 0,scopes:Array.isArray(params.scopes)&¶ms.scopes.every(t=>typeof t==`string`)?params.scopes:void 0,tags:Array.isArray(params.tags)&¶ms.tags.every(t=>typeof t==`string`)?params.tags:void 0});if(text.startsWith(`Node:`)){let next=presenceUpdate.next,changed=new Set(presenceUpdate.changedKeys),reasonValue=next.reason??reason,normalizedReason=(reasonValue??``).toLowerCase(),ignoreReason=normalizedReason.startsWith(`periodic`)||normalizedReason===`heartbeat`,hostChanged=changed.has(`host`),ipChanged=changed.has(`ip`),versionChanged=changed.has(`version`),modeChanged=changed.has(`mode`),reasonChanged=changed.has(`reason`)&&!ignoreReason;if(hostChanged||ipChanged||versionChanged||modeChanged||reasonChanged){let contextChanged=isSystemEventContextChanged(sessionKey,presenceUpdate.key),parts=[];if(contextChanged||hostChanged||ipChanged){let hostLabel=next.host?.trim()||`Unknown`,ipLabel=next.ip?.trim();parts.push(`Node: ${hostLabel}${ipLabel?` (${ipLabel})`:``}`)}versionChanged&&parts.push(`app ${next.version?.trim()||`unknown`}`),modeChanged&&parts.push(`mode ${next.mode?.trim()||`unknown`}`),reasonChanged&&parts.push(`reason ${reasonValue?.trim()||`event`}`);let deltaText=parts.join(` · `);deltaText&&enqueueSystemEvent(deltaText,{sessionKey,contextKey:presenceUpdate.key})}}else enqueueSystemEvent(text,{sessionKey});broadcastPresenceSnapshot({broadcast:context.broadcast,incrementPresenceVersion:context.incrementPresenceVersion,getHealthVersion:context.getHealthVersion}),respond(!0,{ok:!0},void 0)},"config.reload":async({respond,context})=>{let configReloader=context.configReloader;if(!configReloader?.trigger){respond(!1,void 0,errorShape(ErrorCodes.METHOD_NOT_FOUND,`config.reload not available`));return}try{await configReloader.trigger(),respond(!0,{ok:!0},void 0)}catch(err){respond(!1,void 0,errorShape(ErrorCodes.INTERNAL_ERROR,String(err)))}},"skills.reload":async({respond})=>{let{bumpSkillsSnapshotVersion}=await import(`./refresh-DjNwNrIM.js`);bumpSkillsSnapshotVersion({reason:`manual`}),respond(!0,{ok:!0},void 0)}},TALK_SECRETS_SCOPE=`operator.talk.secrets`;function canReadTalkSecrets(client){let scopes=Array.isArray(client?.connect?.scopes)?client.connect.scopes:[];return scopes.includes(`operator.admin`)||scopes.includes(TALK_SECRETS_SCOPE)}function normalizeTalkConfigSection(value){if(!value||typeof value!=`object`||Array.isArray(value))return;let source=value,talk={};if(typeof source.voiceId==`string`&&(talk.voiceId=source.voiceId),source.voiceAliases&&typeof source.voiceAliases==`object`&&!Array.isArray(source.voiceAliases)){let aliases={};for(let[alias,id]of Object.entries(source.voiceAliases))typeof id==`string`&&(aliases[alias]=id);Object.keys(aliases).length>0&&(talk.voiceAliases=aliases)}return typeof source.modelId==`string`&&(talk.modelId=source.modelId),typeof source.outputFormat==`string`&&(talk.outputFormat=source.outputFormat),typeof source.apiKey==`string`&&(talk.apiKey=source.apiKey),typeof source.interruptOnSpeech==`boolean`&&(talk.interruptOnSpeech=source.interruptOnSpeech),Object.keys(talk).length>0?talk:void 0}const talkHandlers={"talk.config":async({params,respond,client})=>{if(!validateTalkConfigParams(params)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid talk.config params: ${formatValidationErrors(validateTalkConfigParams.errors)}`));return}let includeSecrets=!!params.includeSecrets;if(includeSecrets&&!canReadTalkSecrets(client)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`missing scope: ${TALK_SECRETS_SCOPE}`));return}let snapshot=await readConfigFileSnapshot(),configPayload={},talk=normalizeTalkConfigSection(includeSecrets?snapshot.config.talk:redactConfigObject(snapshot.config.talk));talk&&(configPayload.talk=talk);let sessionMainKey=snapshot.config.session?.mainKey;typeof sessionMainKey==`string`&&(configPayload.session={mainKey:sessionMainKey});let seamColor=snapshot.config.ui?.seamColor;typeof seamColor==`string`&&(configPayload.ui={seamColor}),respond(!0,{config:configPayload},void 0)},"talk.mode":({params,respond,context,client,isWebchatConnect})=>{if(client&&isWebchatConnect(client.connect)&&!context.hasConnectedMobileNode()){respond(!1,void 0,errorShape(ErrorCodes.UNAVAILABLE,`talk disabled: no connected iOS/Android nodes`));return}if(!validateTalkModeParams(params)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid talk.mode params: ${formatValidationErrors(validateTalkModeParams.errors)}`));return}let payload={enabled:params.enabled,phase:params.phase??null,ts:Date.now()};context.broadcast(`talk.mode`,payload,{dropIfSlow:!0}),respond(!0,payload,void 0)}},ttsHandlers={"tts.status":async({respond})=>{try{let config=resolveTtsConfig(loadConfig()),prefsPath=resolveTtsPrefsPath(config),provider=getTtsProvider(config,prefsPath),autoMode=resolveTtsAutoMode({config,prefsPath}),fallbackProviders=resolveTtsProviderOrder(provider).slice(1).filter(candidate=>isTtsProviderConfigured(config,candidate));respond(!0,{enabled:isTtsEnabled(config,prefsPath),auto:autoMode,provider,fallbackProvider:fallbackProviders[0]??null,fallbackProviders,prefsPath,hasOpenAIKey:!!resolveTtsApiKey(config,`openai`),hasElevenLabsKey:!!resolveTtsApiKey(config,`elevenlabs`),edgeEnabled:isTtsProviderConfigured(config,`edge`)})}catch(err){respond(!1,void 0,errorShape(ErrorCodes.UNAVAILABLE,formatForLog(err)))}},"tts.enable":async({respond})=>{try{setTtsEnabled(resolveTtsPrefsPath(resolveTtsConfig(loadConfig())),!0),respond(!0,{enabled:!0})}catch(err){respond(!1,void 0,errorShape(ErrorCodes.UNAVAILABLE,formatForLog(err)))}},"tts.disable":async({respond})=>{try{setTtsEnabled(resolveTtsPrefsPath(resolveTtsConfig(loadConfig())),!1),respond(!0,{enabled:!1})}catch(err){respond(!1,void 0,errorShape(ErrorCodes.UNAVAILABLE,formatForLog(err)))}},"tts.convert":async({params,respond})=>{let text=typeof params.text==`string`?params.text.trim():``;if(!text){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`tts.convert requires text`));return}try{let result=await textToSpeech({text,cfg:loadConfig(),channel:typeof params.channel==`string`?params.channel.trim():void 0});if(result.success&&result.audioPath){respond(!0,{audioPath:result.audioPath,provider:result.provider,outputFormat:result.outputFormat,voiceCompatible:result.voiceCompatible});return}respond(!1,void 0,errorShape(ErrorCodes.UNAVAILABLE,result.error??`TTS conversion failed`))}catch(err){respond(!1,void 0,errorShape(ErrorCodes.UNAVAILABLE,formatForLog(err)))}},"tts.setProvider":async({params,respond})=>{let provider=typeof params.provider==`string`?params.provider.trim():``;if(provider!==`openai`&&provider!==`elevenlabs`&&provider!==`edge`){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`Invalid provider. Use openai, elevenlabs, or edge.`));return}try{setTtsProvider(resolveTtsPrefsPath(resolveTtsConfig(loadConfig())),provider),respond(!0,{provider})}catch(err){respond(!1,void 0,errorShape(ErrorCodes.UNAVAILABLE,formatForLog(err)))}},"tts.providers":async({respond})=>{try{let config=resolveTtsConfig(loadConfig()),prefsPath=resolveTtsPrefsPath(config);respond(!0,{providers:[{id:`openai`,name:`OpenAI`,configured:!!resolveTtsApiKey(config,`openai`),models:[...OPENAI_TTS_MODELS],voices:[...OPENAI_TTS_VOICES]},{id:`elevenlabs`,name:`ElevenLabs`,configured:!!resolveTtsApiKey(config,`elevenlabs`),models:[`eleven_multilingual_v2`,`eleven_turbo_v2_5`,`eleven_monolingual_v1`]},{id:`edge`,name:`Edge TTS`,configured:isTtsProviderConfigured(config,`edge`),models:[]}],active:getTtsProvider(config,prefsPath)})}catch(err){respond(!1,void 0,errorShape(ErrorCodes.UNAVAILABLE,formatForLog(err)))}}},updateHandlers={"update.run":async({params,respond})=>{if(!assertValidParams(params,validateUpdateRunParams,`update.run`,respond))return;let{sessionKey,note,restartDelayMs}=parseRestartRequestParams(params),{deliveryContext,threadId}=extractDeliveryInfo(sessionKey),timeoutMsRaw=params.timeoutMs,timeoutMs=typeof timeoutMsRaw==`number`&&Number.isFinite(timeoutMsRaw)?Math.max(1e3,Math.floor(timeoutMsRaw)):void 0,result;try{let configChannel=normalizeUpdateChannel(loadConfig().update?.channel);result=await runGatewayUpdate({timeoutMs,cwd:await resolveBuilderForceAgentsPackageRoot({moduleUrl:import.meta.url,argv1:process.argv[1],cwd:process.cwd()})??process.cwd(),argv1:process.argv[1],channel:configChannel??void 0})}catch(err){result={status:`error`,mode:`unknown`,reason:String(err),steps:[],durationMs:0}}let payload={kind:`update`,status:result.status,ts:Date.now(),sessionKey,deliveryContext,threadId,message:note??null,doctorHint:formatDoctorNonInteractiveHint(),stats:{mode:result.mode,root:result.root??void 0,before:result.before??null,after:result.after??null,steps:result.steps.map(step=>({name:step.name,command:step.command,cwd:step.cwd,durationMs:step.durationMs,log:{stdoutTail:step.stdoutTail??null,stderrTail:step.stderrTail??null,exitCode:step.exitCode??null}})),reason:result.reason??null,durationMs:result.durationMs}},sentinelPath=null;try{sentinelPath=await writeRestartSentinel(payload)}catch{sentinelPath=null}let restart=result.status===`ok`?scheduleGatewaySigusr1Restart({delayMs:restartDelayMs,reason:`update.run`}):null;respond(!0,{ok:result.status!==`error`,result,restart,sentinel:{path:sentinelPath,payload}},void 0)}};function buildUsageAggregateTail(params){return{byChannel:Array.from(params.byChannelMap.entries()).map(([channel,totals])=>({channel,totals})).toSorted((a,b)=>b.totals.totalCost-a.totals.totalCost),latency:params.latencyTotals.count>0?{count:params.latencyTotals.count,avgMs:params.latencyTotals.sum/params.latencyTotals.count,minMs:params.latencyTotals.min===1/0?0:params.latencyTotals.min,maxMs:params.latencyTotals.max,p95Ms:params.latencyTotals.p95Max}:void 0,dailyLatency:Array.from(params.dailyLatencyMap.values()).map(entry=>({date:entry.date,count:entry.count,avgMs:entry.count?entry.sum/entry.count:0,minMs:entry.min===1/0?0:entry.min,maxMs:entry.max,p95Ms:entry.p95Max})).toSorted((a,b)=>a.date.localeCompare(b.date)),modelDaily:Array.from(params.modelDailyMap.values()).toSorted((a,b)=>a.date.localeCompare(b.date)||b.cost-a.cost),daily:Array.from(params.dailyMap.values()).toSorted((a,b)=>a.date.localeCompare(b.date))}}const costUsageCache=new Map;function resolveSessionUsageFileOrRespond(key,respond){let config=loadConfig(),{entry,storePath}=loadSessionEntry(key),parsed=parseAgentSessionKey(key),agentId=parsed?.agentId,rawSessionId=parsed?.rest??key,sessionId=entry?.sessionId??rawSessionId,sessionFile;try{sessionFile=resolveSessionFilePath(sessionId,entry,resolveSessionFilePathOptions({storePath,agentId}))}catch{return respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`Invalid session key: ${key}`)),null}return{config,entry,agentId,sessionId,sessionFile}}const parseDateToMs=raw=>{if(typeof raw!=`string`||!raw.trim())return;let match=/^(\d{4})-(\d{2})-(\d{2})$/.exec(raw.trim());if(!match)return;let[,year,month,day]=match,ms=Date.UTC(parseInt(year),parseInt(month)-1,parseInt(day));if(!Number.isNaN(ms))return ms},parseDays=raw=>{if(typeof raw==`number`&&Number.isFinite(raw))return Math.floor(raw);if(typeof raw==`string`&&raw.trim()!==``){let parsed=Number(raw);if(Number.isFinite(parsed))return Math.floor(parsed)}},parseDateRange=params=>{let now=new Date,todayStartMs=Date.UTC(now.getUTCFullYear(),now.getUTCMonth(),now.getUTCDate()),todayEndMs=todayStartMs+1440*60*1e3-1,startMs=parseDateToMs(params.startDate),endMs=parseDateToMs(params.endDate);if(startMs!==void 0&&endMs!==void 0)return{startMs,endMs:endMs+1440*60*1e3-1};let days=parseDays(params.days);return days===void 0?{startMs:todayStartMs-696*60*60*1e3,endMs:todayEndMs}:{startMs:todayStartMs-(Math.max(1,days)-1)*24*60*60*1e3,endMs:todayEndMs}};function buildStoreBySessionId(store){let storeBySessionId=new Map;for(let[key,entry]of Object.entries(store))entry?.sessionId&&storeBySessionId.set(entry.sessionId,{key,entry});return storeBySessionId}async function discoverAllSessionsForUsage(params){let agents=listAgentsForGateway(params.config).agents;return(await Promise.all(agents.map(async agent=>(await discoverAllSessions({agentId:agent.id,startMs:params.startMs,endMs:params.endMs})).map(session=>({...session,agentId:agent.id}))))).flat().toSorted((a,b)=>b.mtime-a.mtime)}async function loadCostUsageSummaryCached(params){let cacheKey=`${params.startMs}-${params.endMs}`,now=Date.now(),cached=costUsageCache.get(cacheKey);if(cached?.summary&&cached.updatedAt&&now-cached.updatedAt<3e4)return cached.summary;if(cached?.inFlight)return cached.summary?cached.summary:await cached.inFlight;let entry=cached??{},inFlight=loadCostUsageSummary({startMs:params.startMs,endMs:params.endMs,config:params.config}).then(summary=>(costUsageCache.set(cacheKey,{summary,updatedAt:Date.now()}),summary)).catch(err=>{if(entry.summary)return entry.summary;throw err}).finally(()=>{let current=costUsageCache.get(cacheKey);current?.inFlight===inFlight&&(current.inFlight=void 0,costUsageCache.set(cacheKey,current))});return entry.inFlight=inFlight,costUsageCache.set(cacheKey,entry),entry.summary?entry.summary:await inFlight}const usageHandlers={"usage.status":async({respond})=>{respond(!0,await loadProviderUsageSummary(),void 0)},"usage.cost":async({respond,params})=>{let config=loadConfig(),{startMs,endMs}=parseDateRange({startDate:params?.startDate,endDate:params?.endDate,days:params?.days});respond(!0,await loadCostUsageSummaryCached({startMs,endMs,config}),void 0)},"sessions.usage":async({respond,params})=>{if(!validateSessionsUsageParams(params)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid sessions.usage params: ${formatValidationErrors(validateSessionsUsageParams.errors)}`));return}let p=params,config=loadConfig(),{startMs,endMs}=parseDateRange({startDate:p.startDate,endDate:p.endDate}),limit=typeof p.limit==`number`&&Number.isFinite(p.limit)?p.limit:50,includeContextWeight=p.includeContextWeight??!1,specificKey=typeof p.key==`string`?p.key.trim():null,{storePath,store}=loadCombinedSessionStoreForGateway(config),now=Date.now(),mergedEntries=[];if(specificKey){let parsed=parseAgentSessionKey(specificKey),agentIdFromKey=parsed?.agentId,keyRest=parsed?.rest??specificKey,storeBySessionId=buildStoreBySessionId(store),storeMatch=store[specificKey]?{key:specificKey,entry:store[specificKey]}:null,storeByIdMatch=storeBySessionId.get(keyRest)??null,resolvedStoreKey=storeMatch?.key??storeByIdMatch?.key??specificKey,storeEntry=storeMatch?.entry??storeByIdMatch?.entry,sessionId=storeEntry?.sessionId??keyRest,sessionFile;try{sessionFile=resolveSessionFilePath(sessionId,storeEntry,resolveSessionFilePathOptions({storePath:storePath===`(multiple)`?void 0:storePath,agentId:agentIdFromKey}))}catch{respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`Invalid session reference: ${specificKey}`));return}try{let stats=fs.statSync(sessionFile);stats.isFile()&&mergedEntries.push({key:resolvedStoreKey,sessionId,sessionFile,label:storeEntry?.label,updatedAt:storeEntry?.updatedAt??stats.mtimeMs,storeEntry})}catch{}}else{let discoveredSessions=await discoverAllSessionsForUsage({config,startMs,endMs}),storeBySessionId=buildStoreBySessionId(store);for(let discovered of discoveredSessions){let storeMatch=storeBySessionId.get(discovered.sessionId);storeMatch?mergedEntries.push({key:storeMatch.key,sessionId:discovered.sessionId,sessionFile:discovered.sessionFile,label:storeMatch.entry.label,updatedAt:storeMatch.entry.updatedAt??discovered.mtime,storeEntry:storeMatch.entry}):mergedEntries.push({key:`agent:${discovered.agentId}:${discovered.sessionId}`,sessionId:discovered.sessionId,sessionFile:discovered.sessionFile,label:void 0,updatedAt:discovered.mtime})}}mergedEntries.sort((a,b)=>b.updatedAt-a.updatedAt);let limitedEntries=mergedEntries.slice(0,limit),sessions=[],aggregateTotals={input:0,output:0,cacheRead:0,cacheWrite:0,totalTokens:0,totalCost:0,inputCost:0,outputCost:0,cacheReadCost:0,cacheWriteCost:0,missingCostEntries:0},aggregateMessages={total:0,user:0,assistant:0,toolCalls:0,toolResults:0,errors:0},toolAggregateMap=new Map,byModelMap=new Map,byProviderMap=new Map,byAgentMap=new Map,byChannelMap=new Map,dailyAggregateMap=new Map,latencyTotals={count:0,sum:0,min:1/0,max:0,p95Max:0},dailyLatencyMap=new Map,modelDailyMap=new Map,emptyTotals=()=>({input:0,output:0,cacheRead:0,cacheWrite:0,totalTokens:0,totalCost:0,inputCost:0,outputCost:0,cacheReadCost:0,cacheWriteCost:0,missingCostEntries:0}),mergeTotals=(target,source)=>{target.input+=source.input,target.output+=source.output,target.cacheRead+=source.cacheRead,target.cacheWrite+=source.cacheWrite,target.totalTokens+=source.totalTokens,target.totalCost+=source.totalCost,target.inputCost+=source.inputCost,target.outputCost+=source.outputCost,target.cacheReadCost+=source.cacheReadCost,target.cacheWriteCost+=source.cacheWriteCost,target.missingCostEntries+=source.missingCostEntries};for(let merged of limitedEntries){let agentId=parseAgentSessionKey(merged.key)?.agentId,usage=await loadSessionCostSummary({sessionId:merged.sessionId,sessionEntry:merged.storeEntry,sessionFile:merged.sessionFile,config,agentId,startMs,endMs});usage&&(aggregateTotals.input+=usage.input,aggregateTotals.output+=usage.output,aggregateTotals.cacheRead+=usage.cacheRead,aggregateTotals.cacheWrite+=usage.cacheWrite,aggregateTotals.totalTokens+=usage.totalTokens,aggregateTotals.totalCost+=usage.totalCost,aggregateTotals.inputCost+=usage.inputCost,aggregateTotals.outputCost+=usage.outputCost,aggregateTotals.cacheReadCost+=usage.cacheReadCost,aggregateTotals.cacheWriteCost+=usage.cacheWriteCost,aggregateTotals.missingCostEntries+=usage.missingCostEntries);let channel=merged.storeEntry?.channel??merged.storeEntry?.origin?.provider,chatType=merged.storeEntry?.chatType??merged.storeEntry?.origin?.chatType;if(usage){if(usage.messageCounts&&(aggregateMessages.total+=usage.messageCounts.total,aggregateMessages.user+=usage.messageCounts.user,aggregateMessages.assistant+=usage.messageCounts.assistant,aggregateMessages.toolCalls+=usage.messageCounts.toolCalls,aggregateMessages.toolResults+=usage.messageCounts.toolResults,aggregateMessages.errors+=usage.messageCounts.errors),usage.toolUsage)for(let tool of usage.toolUsage.tools)toolAggregateMap.set(tool.name,(toolAggregateMap.get(tool.name)??0)+tool.count);if(usage.modelUsage)for(let entry of usage.modelUsage){let modelKey=`${entry.provider??`unknown`}::${entry.model??`unknown`}`,modelExisting=byModelMap.get(modelKey)??{provider:entry.provider,model:entry.model,count:0,totals:emptyTotals()};modelExisting.count+=entry.count,mergeTotals(modelExisting.totals,entry.totals),byModelMap.set(modelKey,modelExisting);let providerKey=entry.provider??`unknown`,providerExisting=byProviderMap.get(providerKey)??{provider:entry.provider,model:void 0,count:0,totals:emptyTotals()};providerExisting.count+=entry.count,mergeTotals(providerExisting.totals,entry.totals),byProviderMap.set(providerKey,providerExisting)}if(usage.latency){let{count,avgMs,minMs,maxMs,p95Ms}=usage.latency;count>0&&(latencyTotals.count+=count,latencyTotals.sum+=avgMs*count,latencyTotals.min=Math.min(latencyTotals.min,minMs),latencyTotals.max=Math.max(latencyTotals.max,maxMs),latencyTotals.p95Max=Math.max(latencyTotals.p95Max,p95Ms))}if(usage.dailyLatency)for(let day of usage.dailyLatency){let existing=dailyLatencyMap.get(day.date)??{date:day.date,count:0,sum:0,min:1/0,max:0,p95Max:0};existing.count+=day.count,existing.sum+=day.avgMs*day.count,existing.min=Math.min(existing.min,day.minMs),existing.max=Math.max(existing.max,day.maxMs),existing.p95Max=Math.max(existing.p95Max,day.p95Ms),dailyLatencyMap.set(day.date,existing)}if(usage.dailyModelUsage)for(let entry of usage.dailyModelUsage){let key=`${entry.date}::${entry.provider??`unknown`}::${entry.model??`unknown`}`,existing=modelDailyMap.get(key)??{date:entry.date,provider:entry.provider,model:entry.model,tokens:0,cost:0,count:0};existing.tokens+=entry.tokens,existing.cost+=entry.cost,existing.count+=entry.count,modelDailyMap.set(key,existing)}if(agentId){let agentTotals=byAgentMap.get(agentId)??emptyTotals();mergeTotals(agentTotals,usage),byAgentMap.set(agentId,agentTotals)}if(channel){let channelTotals=byChannelMap.get(channel)??emptyTotals();mergeTotals(channelTotals,usage),byChannelMap.set(channel,channelTotals)}if(usage.dailyBreakdown)for(let day of usage.dailyBreakdown){let daily=dailyAggregateMap.get(day.date)??{date:day.date,tokens:0,cost:0,messages:0,toolCalls:0,errors:0};daily.tokens+=day.tokens,daily.cost+=day.cost,dailyAggregateMap.set(day.date,daily)}if(usage.dailyMessageCounts)for(let day of usage.dailyMessageCounts){let daily=dailyAggregateMap.get(day.date)??{date:day.date,tokens:0,cost:0,messages:0,toolCalls:0,errors:0};daily.messages+=day.total,daily.toolCalls+=day.toolCalls,daily.errors+=day.errors,dailyAggregateMap.set(day.date,daily)}}sessions.push({key:merged.key,label:merged.label,sessionId:merged.sessionId,updatedAt:merged.updatedAt,agentId,channel,chatType,origin:merged.storeEntry?.origin,modelOverride:merged.storeEntry?.modelOverride,providerOverride:merged.storeEntry?.providerOverride,modelProvider:merged.storeEntry?.modelProvider,model:merged.storeEntry?.model,usage,contextWeight:includeContextWeight?merged.storeEntry?.systemPromptReport??null:void 0})}let formatDateStr=ms=>{let d=new Date(ms);return`${d.getUTCFullYear()}-${String(d.getUTCMonth()+1).padStart(2,`0`)}-${String(d.getUTCDate()).padStart(2,`0`)}`},tail=buildUsageAggregateTail({byChannelMap,latencyTotals,dailyLatencyMap,modelDailyMap,dailyMap:dailyAggregateMap}),aggregates={messages:aggregateMessages,tools:{totalCalls:Array.from(toolAggregateMap.values()).reduce((sum,count)=>sum+count,0),uniqueTools:toolAggregateMap.size,tools:Array.from(toolAggregateMap.entries()).map(([name,count])=>({name,count})).toSorted((a,b)=>b.count-a.count)},byModel:Array.from(byModelMap.values()).toSorted((a,b)=>{let costDiff=b.totals.totalCost-a.totals.totalCost;return costDiff===0?b.totals.totalTokens-a.totals.totalTokens:costDiff}),byProvider:Array.from(byProviderMap.values()).toSorted((a,b)=>{let costDiff=b.totals.totalCost-a.totals.totalCost;return costDiff===0?b.totals.totalTokens-a.totals.totalTokens:costDiff}),byAgent:Array.from(byAgentMap.entries()).map(([id,totals])=>({agentId:id,totals})).toSorted((a,b)=>b.totals.totalCost-a.totals.totalCost),...tail};respond(!0,{updatedAt:now,startDate:formatDateStr(startMs),endDate:formatDateStr(endMs),sessions,totals:aggregateTotals,aggregates},void 0)},"sessions.usage.timeseries":async({respond,params})=>{let key=typeof params?.key==`string`?params.key.trim():null;if(!key){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`key is required for timeseries`));return}let resolved=resolveSessionUsageFileOrRespond(key,respond);if(!resolved)return;let{config,entry,agentId,sessionId,sessionFile}=resolved,timeseries=await loadSessionUsageTimeSeries({sessionId,sessionEntry:entry,sessionFile,config,agentId,maxPoints:200});if(!timeseries){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`No transcript found for session: ${key}`));return}respond(!0,timeseries,void 0)},"sessions.usage.logs":async({respond,params})=>{let key=typeof params?.key==`string`?params.key.trim():null;if(!key){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`key is required for logs`));return}let limit=typeof params?.limit==`number`&&Number.isFinite(params.limit)?Math.min(params.limit,1e3):200,resolved=resolveSessionUsageFileOrRespond(key,respond);if(!resolved)return;let{config,entry,agentId,sessionId,sessionFile}=resolved,{loadSessionLogs}=await import(`./session-cost-usage-D1twLjja.js`);respond(!0,{logs:await loadSessionLogs({sessionId,sessionEntry:entry,sessionFile,config,agentId,limit})??[]},void 0)}},voicewakeHandlers={"voicewake.get":async({respond})=>{try{respond(!0,{triggers:(await loadVoiceWakeConfig()).triggers})}catch(err){respond(!1,void 0,errorShape(ErrorCodes.UNAVAILABLE,formatForLog(err)))}},"voicewake.set":async({params,respond,context})=>{if(!Array.isArray(params.triggers)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`voicewake.set requires triggers: string[]`));return}try{let cfg=await setVoiceWakeTriggers(normalizeVoiceWakeTriggers(params.triggers));context.broadcastVoiceWakeChanged(cfg.triggers),respond(!0,{triggers:cfg.triggers})}catch(err){respond(!1,void 0,errorShape(ErrorCodes.UNAVAILABLE,formatForLog(err)))}}},WEB_LOGIN_METHODS=new Set([`web.login.start`,`web.login.wait`]),resolveWebLoginProvider=()=>listChannelPlugins().find(plugin=>(plugin.gatewayMethods??[]).some(method=>WEB_LOGIN_METHODS.has(method)))??null;function resolveAccountId(params){return typeof params.accountId==`string`?params.accountId:void 0}function respondProviderUnavailable(respond){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`web login provider is not available`))}function respondProviderUnsupported(respond,providerId){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`web login is not supported by provider ${providerId}`))}const webHandlers={"web.login.start":async({params,respond,context})=>{if(!validateWebLoginStartParams(params)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid web.login.start params: ${formatValidationErrors(validateWebLoginStartParams.errors)}`));return}try{let accountId=resolveAccountId(params),provider=resolveWebLoginProvider();if(!provider){respondProviderUnavailable(respond);return}if(await context.stopChannel(provider.id,accountId),!provider.gateway?.loginWithQrStart){respondProviderUnsupported(respond,provider.id);return}respond(!0,await provider.gateway.loginWithQrStart({force:!!params.force,timeoutMs:typeof params.timeoutMs==`number`?params.timeoutMs:void 0,verbose:!!params.verbose,accountId}),void 0)}catch(err){respond(!1,void 0,errorShape(ErrorCodes.UNAVAILABLE,formatForLog(err)))}},"web.login.wait":async({params,respond,context})=>{if(!validateWebLoginWaitParams(params)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid web.login.wait params: ${formatValidationErrors(validateWebLoginWaitParams.errors)}`));return}try{let accountId=resolveAccountId(params),provider=resolveWebLoginProvider();if(!provider){respondProviderUnavailable(respond);return}if(!provider.gateway?.loginWithQrWait){respondProviderUnsupported(respond,provider.id);return}let result=await provider.gateway.loginWithQrWait({timeoutMs:typeof params.timeoutMs==`number`?params.timeoutMs:void 0,accountId});result.connected&&await context.startChannel(provider.id,accountId),respond(!0,result,void 0)}catch(err){respond(!1,void 0,errorShape(ErrorCodes.UNAVAILABLE,formatForLog(err)))}}};function createDeferred(){let resolve,reject;return{promise:new Promise((res,rej)=>{resolve=res,reject=rej}),resolve,reject}}var WizardSessionPrompter=class{constructor(session){this.session=session}async intro(title){await this.prompt({type:`note`,title,message:``,executor:`client`})}async outro(message){await this.prompt({type:`note`,title:`Done`,message,executor:`client`})}async note(message,title){await this.prompt({type:`note`,title,message,executor:`client`})}async select(params){return await this.prompt({type:`select`,message:params.message,options:params.options.map(opt=>({value:opt.value,label:opt.label,hint:opt.hint})),initialValue:params.initialValue,executor:`client`})}async multiselect(params){let res=await this.prompt({type:`multiselect`,message:params.message,options:params.options.map(opt=>({value:opt.value,label:opt.label,hint:opt.hint})),initialValue:params.initialValues,executor:`client`});return Array.isArray(res)?res:[]}async text(params){let res=await this.prompt({type:`text`,message:params.message,initialValue:params.initialValue,placeholder:params.placeholder,executor:`client`}),value=res==null?``:typeof res==`string`?res:typeof res==`number`||typeof res==`boolean`||typeof res==`bigint`?String(res):``,error=params.validate?.(value);if(error)throw Error(error);return value}async confirm(params){return!!await this.prompt({type:`confirm`,message:params.message,initialValue:params.initialValue,executor:`client`})}progress(_label){return{update:_message=>{},stop:_message=>{}}}async prompt(step){return await this.session.awaitAnswer({...step,id:randomUUID()})}},WizardSession=class{constructor(runner){this.runner=runner,this.currentStep=null,this.stepDeferred=null,this.answerDeferred=new Map,this.status=`running`;let prompter=new WizardSessionPrompter(this);this.run(prompter)}async next(){if(this.currentStep)return{done:!1,step:this.currentStep,status:this.status};if(this.status!==`running`)return{done:!0,status:this.status,error:this.error};this.stepDeferred||=createDeferred();let step=await this.stepDeferred.promise;return step?{done:!1,step,status:this.status}:{done:!0,status:this.status,error:this.error}}async answer(stepId,value){let deferred=this.answerDeferred.get(stepId);if(!deferred)throw Error(`wizard: no pending step`);this.answerDeferred.delete(stepId),this.currentStep=null,deferred.resolve(value)}cancel(){if(this.status===`running`){this.status=`cancelled`,this.error=`cancelled`,this.currentStep=null;for(let[,deferred]of this.answerDeferred)deferred.reject(new WizardCancelledError);this.answerDeferred.clear(),this.resolveStep(null)}}pushStep(step){this.currentStep=step,this.resolveStep(step)}async run(prompter){try{await this.runner(prompter),this.status=`done`}catch(err){err instanceof WizardCancelledError?(this.status=`cancelled`,this.error=err.message):(this.status=`error`,this.error=String(err))}finally{this.resolveStep(null)}}async awaitAnswer(step){if(this.status!==`running`)throw Error(`wizard: session not running`);this.pushStep(step);let deferred=createDeferred();return this.answerDeferred.set(step.id,deferred),await deferred.promise}resolveStep(step){if(!this.stepDeferred)return;let deferred=this.stepDeferred;this.stepDeferred=null,deferred.resolve(step)}getStatus(){return this.status}getError(){return this.error}};function readWizardStatus(session){return{status:session.getStatus(),error:session.getError()}}function findWizardSessionOrRespond(params){return params.context.wizardSessions.get(params.sessionId)||(params.respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`wizard not found`)),null)}const wizardHandlers={"wizard.start":async({params,respond,context})=>{if(!assertValidParams(params,validateWizardStartParams,`wizard.start`,respond))return;if(context.findRunningWizard()){respond(!1,void 0,errorShape(ErrorCodes.UNAVAILABLE,`wizard already running`));return}let sessionId=randomUUID(),opts={mode:params.mode,workspace:typeof params.workspace==`string`?params.workspace:void 0},session=new WizardSession(prompter=>context.wizardRunner(opts,defaultRuntime,prompter));context.wizardSessions.set(sessionId,session);let result=await session.next();result.done&&context.purgeWizardSession(sessionId),respond(!0,{sessionId,...result},void 0)},"wizard.next":async({params,respond,context})=>{if(!assertValidParams(params,validateWizardNextParams,`wizard.next`,respond))return;let sessionId=params.sessionId,session=findWizardSessionOrRespond({context,respond,sessionId});if(!session)return;let answer=params.answer;if(answer){if(session.getStatus()!==`running`){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`wizard not running`));return}try{await session.answer(String(answer.stepId??``),answer.value)}catch(err){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,formatForLog(err)));return}}let result=await session.next();result.done&&context.purgeWizardSession(sessionId),respond(!0,result,void 0)},"wizard.cancel":({params,respond,context})=>{if(!assertValidParams(params,validateWizardCancelParams,`wizard.cancel`,respond))return;let sessionId=params.sessionId,session=findWizardSessionOrRespond({context,respond,sessionId});if(!session)return;session.cancel();let status=readWizardStatus(session);context.wizardSessions.delete(sessionId),respond(!0,status,void 0)},"wizard.status":({params,respond,context})=>{if(!assertValidParams(params,validateWizardStatusParams,`wizard.status`,respond))return;let sessionId=params.sessionId,session=findWizardSessionOrRespond({context,respond,sessionId});if(!session)return;let status=readWizardStatus(session);status.status!==`running`&&context.wizardSessions.delete(sessionId),respond(!0,status,void 0)}},WRITE_SCOPE=`operator.write`,APPROVAL_METHODS=new Set([`exec.approval.request`,`exec.approval.waitDecision`,`exec.approval.resolve`]),NODE_ROLE_METHODS=new Set([`node.invoke.result`,`node.event`,`skills.bins`]),PAIRING_METHODS=new Set([`node.pair.request`,`node.pair.list`,`node.pair.approve`,`node.pair.reject`,`node.pair.verify`,`device.pair.list`,`device.pair.approve`,`device.pair.reject`,`device.pair.remove`,`device.token.rotate`,`device.token.revoke`,`node.rename`]),ADMIN_METHOD_PREFIXES=[`exec.approvals.`],READ_METHODS=new Set([`health`,`logs.tail`,`channels.status`,`status`,`usage.status`,`usage.cost`,`tts.status`,`tts.providers`,`models.list`,`agents.list`,`agent.identity.get`,`skills.status`,`voicewake.get`,`sessions.list`,`sessions.preview`,`cron.list`,`cron.status`,`cron.runs`,`system-presence`,`last-heartbeat`,`node.list`,`node.describe`,`chat.history`,`config.get`,`talk.config`]),WRITE_METHODS=new Set([`send`,`agent`,`agent.wait`,`wake`,`talk.mode`,`tts.enable`,`tts.disable`,`tts.convert`,`tts.setProvider`,`voicewake.set`,`node.invoke`,`chat.send`,`chat.abort`,`browser.request`,`push.test`,`artifacts.sync`]);function authorizeGatewayMethod(method,client){if(!client?.connect)return null;let role=client.connect.role??`operator`,scopes=client.connect.scopes??[];return NODE_ROLE_METHODS.has(method)?role===`node`?null:errorShape(ErrorCodes.INVALID_REQUEST,`unauthorized role: ${role}`):role===`node`||role!==`operator`?errorShape(ErrorCodes.INVALID_REQUEST,`unauthorized role: ${role}`):scopes.includes(`operator.admin`)?null:APPROVAL_METHODS.has(method)&&!scopes.includes(`operator.approvals`)?errorShape(ErrorCodes.INVALID_REQUEST,`missing scope: operator.approvals`):PAIRING_METHODS.has(method)&&!scopes.includes(`operator.pairing`)?errorShape(ErrorCodes.INVALID_REQUEST,`missing scope: operator.pairing`):READ_METHODS.has(method)&&!(scopes.includes(`operator.read`)||scopes.includes(WRITE_SCOPE))?errorShape(ErrorCodes.INVALID_REQUEST,`missing scope: operator.read`):WRITE_METHODS.has(method)&&!scopes.includes(WRITE_SCOPE)?errorShape(ErrorCodes.INVALID_REQUEST,`missing scope: operator.write`):APPROVAL_METHODS.has(method)||PAIRING_METHODS.has(method)||READ_METHODS.has(method)||WRITE_METHODS.has(method)?null:(ADMIN_METHOD_PREFIXES.some(prefix=>method.startsWith(prefix))||method.startsWith(`config.`)||method.startsWith(`wizard.`)||method.startsWith(`update.`),errorShape(ErrorCodes.INVALID_REQUEST,`missing scope: operator.admin`))}const coreGatewayHandlers={...connectHandlers,...logsHandlers,...voicewakeHandlers,...healthHandlers,...channelsHandlers,...chatHandlers,...cronHandlers,...deviceHandlers,...execApprovalsHandlers,...webHandlers,...modelsHandlers,...configHandlers,...wizardHandlers,...talkHandlers,...ttsHandlers,...skillsHandlers,...sessionsHandlers,...systemHandlers,...updateHandlers,...nodeHandlers,...pushHandlers,...sendHandlers,...usageHandlers,...agentHandlers,...agentsHandlers,...browserHandlers,...artifactsHandlers};async function handleGatewayRequest(opts){let{req,respond,client,isWebchatConnect,context}=opts,authError=authorizeGatewayMethod(req.method,client);if(authError){respond(!1,void 0,authError);return}let handler=opts.extraHandlers?.[req.method]??coreGatewayHandlers[req.method];if(!handler){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`unknown method: ${req.method}`));return}await handler({req,params:req.params??{},client,isWebchatConnect,respond,context})}function createExecApprovalHandlers(manager,opts){return{"exec.approval.request":async({params,respond,context,client})=>{if(!validateExecApprovalRequestParams(params)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid exec.approval.request params: ${formatValidationErrors(validateExecApprovalRequestParams.errors)}`));return}let p=params,twoPhase=p.twoPhase===!0,timeoutMs=typeof p.timeoutMs==`number`?p.timeoutMs:DEFAULT_EXEC_APPROVAL_TIMEOUT_MS,explicitId=typeof p.id==`string`&&p.id.trim().length>0?p.id.trim():null;if(explicitId&&manager.getSnapshot(explicitId)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`approval id already pending`));return}let request={command:p.command,cwd:p.cwd??null,host:p.host??null,security:p.security??null,ask:p.ask??null,agentId:p.agentId??null,resolvedPath:p.resolvedPath??null,sessionKey:p.sessionKey??null},record=manager.create(request,timeoutMs,explicitId);record.requestedByConnId=client?.connId??null,record.requestedByDeviceId=client?.connect?.device?.id??null,record.requestedByClientId=client?.connect?.client?.id??null;let decisionPromise;try{decisionPromise=manager.register(record,timeoutMs)}catch(err){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`registration failed: ${String(err)}`));return}context.broadcast(`exec.approval.requested`,{id:record.id,request:record.request,createdAtMs:record.createdAtMs,expiresAtMs:record.expiresAtMs},{dropIfSlow:!0}),opts?.forwarder?.handleRequested({id:record.id,request:record.request,createdAtMs:record.createdAtMs,expiresAtMs:record.expiresAtMs}).catch(err=>{context.logGateway?.error?.(`exec approvals: forward request failed: ${String(err)}`)}),twoPhase&&respond(!0,{status:`accepted`,id:record.id,createdAtMs:record.createdAtMs,expiresAtMs:record.expiresAtMs},void 0);let decision=await decisionPromise;respond(!0,{id:record.id,decision,createdAtMs:record.createdAtMs,expiresAtMs:record.expiresAtMs},void 0)},"exec.approval.waitDecision":async({params,respond})=>{let p=params,id=typeof p.id==`string`?p.id.trim():``;if(!id){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`id is required`));return}let decisionPromise=manager.awaitDecision(id);if(!decisionPromise){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`approval expired or not found`));return}let snapshot=manager.getSnapshot(id);respond(!0,{id,decision:await decisionPromise,createdAtMs:snapshot?.createdAtMs,expiresAtMs:snapshot?.expiresAtMs},void 0)},"exec.approval.resolve":async({params,respond,client,context})=>{if(!validateExecApprovalResolveParams(params)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid exec.approval.resolve params: ${formatValidationErrors(validateExecApprovalResolveParams.errors)}`));return}let p=params,decision=p.decision;if(decision!==`allow-once`&&decision!==`allow-always`&&decision!==`deny`){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`invalid decision`));return}let resolvedBy=client?.connect?.client?.displayName??client?.connect?.client?.id;if(!manager.resolve(p.id,decision,resolvedBy??null)){respond(!1,void 0,errorShape(ErrorCodes.INVALID_REQUEST,`unknown approval id`));return}context.broadcast(`exec.approval.resolved`,{id:p.id,decision,resolvedBy,ts:Date.now()},{dropIfSlow:!0}),opts?.forwarder?.handleResolved({id:p.id,decision,resolvedBy,ts:Date.now()}).catch(err=>{context.logGateway?.error?.(`exec approvals: forward resolve failed: ${String(err)}`)}),respond(!0,{ok:!0},void 0)}}}const isMobilePlatform=platform=>{let p=typeof platform==`string`?platform.trim().toLowerCase():``;return p?p.startsWith(`ios`)||p.startsWith(`ipados`)||p.startsWith(`android`):!1};function hasConnectedMobileNode(registry){return registry.listConnected().some(n=>isMobilePlatform(n.platform))}async function loadGatewayModelCatalog(){return await loadModelCatalog({config:loadConfig()})}function createNodeSubscriptionManager(){let nodeSubscriptions=new Map,sessionSubscribers=new Map,toPayloadJSON=payload=>payload?JSON.stringify(payload):null;return{subscribe:(nodeId,sessionKey)=>{let normalizedNodeId=nodeId.trim(),normalizedSessionKey=sessionKey.trim();if(!normalizedNodeId||!normalizedSessionKey)return;let nodeSet=nodeSubscriptions.get(normalizedNodeId);if(nodeSet||(nodeSet=new Set,nodeSubscriptions.set(normalizedNodeId,nodeSet)),nodeSet.has(normalizedSessionKey))return;nodeSet.add(normalizedSessionKey);let sessionSet=sessionSubscribers.get(normalizedSessionKey);sessionSet||(sessionSet=new Set,sessionSubscribers.set(normalizedSessionKey,sessionSet)),sessionSet.add(normalizedNodeId)},unsubscribe:(nodeId,sessionKey)=>{let normalizedNodeId=nodeId.trim(),normalizedSessionKey=sessionKey.trim();if(!normalizedNodeId||!normalizedSessionKey)return;let nodeSet=nodeSubscriptions.get(normalizedNodeId);nodeSet?.delete(normalizedSessionKey),nodeSet?.size===0&&nodeSubscriptions.delete(normalizedNodeId);let sessionSet=sessionSubscribers.get(normalizedSessionKey);sessionSet?.delete(normalizedNodeId),sessionSet?.size===0&&sessionSubscribers.delete(normalizedSessionKey)},unsubscribeAll:nodeId=>{let normalizedNodeId=nodeId.trim(),nodeSet=nodeSubscriptions.get(normalizedNodeId);if(nodeSet){for(let sessionKey of nodeSet){let sessionSet=sessionSubscribers.get(sessionKey);sessionSet?.delete(normalizedNodeId),sessionSet?.size===0&&sessionSubscribers.delete(sessionKey)}nodeSubscriptions.delete(normalizedNodeId)}},sendToSession:(sessionKey,event,payload,sendEvent)=>{let normalizedSessionKey=sessionKey.trim();if(!normalizedSessionKey||!sendEvent)return;let subs=sessionSubscribers.get(normalizedSessionKey);if(!subs||subs.size===0)return;let payloadJSON=toPayloadJSON(payload);for(let nodeId of subs)sendEvent({nodeId,event,payloadJSON})},sendToAllSubscribed:(event,payload,sendEvent)=>{if(!sendEvent)return;let payloadJSON=toPayloadJSON(payload);for(let nodeId of nodeSubscriptions.keys())sendEvent({nodeId,event,payloadJSON})},sendToAllConnected:(event,payload,listConnected,sendEvent)=>{if(!sendEvent||!listConnected)return;let payloadJSON=toPayloadJSON(payload);for(let node of listConnected())sendEvent({nodeId:node.nodeId,event,payloadJSON})},clear:()=>{nodeSubscriptions.clear(),sessionSubscribers.clear()}}}function loadGatewayPlugins(params){let pluginRegistry=loadBuilderForceAgentsPlugins({config:params.cfg,workspaceDir:params.workspaceDir,logger:{info:msg=>params.log.info(msg),warn:msg=>params.log.warn(msg),error:msg=>params.log.error(msg),debug:msg=>params.log.debug(msg)},coreGatewayHandlers:params.coreGatewayHandlers}),pluginMethods=Object.keys(pluginRegistry.gatewayHandlers),gatewayMethods=Array.from(new Set([...params.baseMethods,...pluginMethods]));if(pluginRegistry.diagnostics.length>0)for(let diag of pluginRegistry.diagnostics){let details=[diag.pluginId?`plugin=${diag.pluginId}`:null,diag.source?`source=${diag.source}`:null].filter(entry=>!!entry).join(`, `),message=details?`[plugins] ${diag.message} (${details})`:`[plugins] ${diag.message}`;diag.level===`error`?params.log.error(message):params.log.info(message)}return{pluginRegistry,gatewayMethods}}async function startGmailWatcherWithLogs(params){if(isTruthyEnvValue(process.env.BUILDERFORCE_AGENTS_SKIP_GMAIL_WATCHER)){params.onSkipped?.();return}try{let gmailResult=await startGmailWatcher(params.cfg);if(gmailResult.started){params.log.info(`gmail watcher started`);return}gmailResult.reason&&gmailResult.reason!==`hooks not enabled`&&gmailResult.reason!==`no gmail account configured`&¶ms.log.warn(`gmail watcher not started: ${gmailResult.reason}`)}catch(err){params.log.error(`gmail watcher failed to start: ${String(err)}`)}}const hookPresetMappings={gmail:[{id:`gmail`,match:{path:`gmail`},action:`agent`,wakeMode:`now`,name:`Gmail`,sessionKey:`hook:gmail:{{messages[0].id}}`,messageTemplate:`New email from {{messages[0].from}}
|
|
19
19
|
Subject: {{messages[0].subject}}
|
|
20
20
|
{{messages[0].snippet}}
|