@seanhogg/builderforce-agents 2026.10.8 → 2026.10.10

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.
Files changed (98) hide show
  1. package/dist/{audio-preflight-hAkEddaf.js → audio-preflight-CBZJKBS8.js} +1 -1
  2. package/dist/build-info.json +3 -3
  3. package/dist/{builderforce-wxtgU9xu.js → builderforce-2EpP2M8q.js} +3 -3
  4. package/dist/{builderforce-BWCp-M9e.js → builderforce-Cyg20uU8.js} +3 -3
  5. package/dist/{builderforce-onboarding-DuUfZ6oL.js → builderforce-onboarding-C89jVb-9.js} +1 -1
  6. package/dist/{builderforce-onboarding-Dq6VUSKZ.js → builderforce-onboarding-D5A-wEs-.js} +1 -1
  7. package/dist/bundled/boot-md/handler.js +1 -1
  8. package/dist/bundled/session-memory/handler.js +1 -1
  9. package/dist/chrome-CtTMuhww.js +4 -0
  10. package/dist/{command-registry-D_LkOB4n.js → command-registry-CDcuHGpx.js} +1 -1
  11. package/dist/{command-registry-CiR8PUQY.js → command-registry-hHegQvBn.js} +1 -1
  12. package/dist/{completion-cli-C7munVvb.js → completion-cli-Bqr0W4L6.js} +1 -1
  13. package/dist/{completion-cli-CBES884A.js → completion-cli-Ch9ozmkg.js} +1 -1
  14. package/dist/{completion-cli-B72GX2so.js → completion-cli-Ck0FTqPT.js} +1 -1
  15. package/dist/{completion-cli-CijodCzU.js → completion-cli-Do4vXo1k.js} +1 -1
  16. package/dist/{doctor-completion-FErwMP3Y.js → doctor-completion-BjBTLcoC.js} +1 -1
  17. package/dist/{doctor-completion-Bv2ztEeW.js → doctor-completion-Ccs-JEvV.js} +1 -1
  18. package/dist/{embedded-DXDHduG1.js → embedded-BcHzh_y8.js} +6 -6
  19. package/dist/entry.js +1 -1
  20. package/dist/{gateway-cli-DpJjgVYH.js → gateway-cli-CiHNwzdS.js} +3 -3
  21. package/dist/{gateway-cli-U8RlUIuT.js → gateway-cli-z47dfosr.js} +3 -3
  22. package/dist/index.js +2 -2
  23. package/dist/llm-slug-generator.js +1 -1
  24. package/dist/{onboard-O2gyfB4L.js → onboard-D4uXN5Ec.js} +1 -1
  25. package/dist/{onboard-7JGHJRfj.js → onboard-cB37uVxy.js} +1 -1
  26. package/dist/{onboard-interactive-FWIy0HTu.js → onboard-interactive-CnXgQrpI.js} +1 -1
  27. package/dist/{onboard-interactive-DboEcFKf.js → onboard-interactive-CoFFuSJT.js} +1 -1
  28. package/dist/{onboard-interactive-Gl5J4kVC.js → onboard-interactive-gvfRcLOt.js} +1 -1
  29. package/dist/{onboard-interactive-DqpGicxB.js → onboard-interactive-vwqLS6pe.js} +1 -1
  30. package/dist/{onboarding-Ctq_bdkC.js → onboarding-B9GqKO5L.js} +2 -2
  31. package/dist/{onboarding-hPRXZReM.js → onboarding-DdKW5K8Y.js} +2 -2
  32. package/dist/{onboarding.finalize-Db6smxZL.js → onboarding.finalize-CcuO4Yxw.js} +1 -1
  33. package/dist/{onboarding.finalize-B4Tc4IDN.js → onboarding.finalize-D3mTpOdc.js} +1 -1
  34. package/dist/plugin-sdk/{accounts-Cy3WCbWg.js → accounts-BwreSNAR.js} +1 -1
  35. package/dist/plugin-sdk/{active-listener-DVWVNlT9.js → active-listener-DpQ7aGYd.js} +1 -1
  36. package/dist/plugin-sdk/{agent-scope-DgKN27hJ.js → agent-scope-BQByW0cD.js} +1 -1
  37. package/dist/plugin-sdk/{api-key-rotation-ftXf7mBZ.js → api-key-rotation-7YdImWrh.js} +1 -1
  38. package/dist/plugin-sdk/{audio-preflight-CfTmmeS-.js → audio-preflight-EbkaATDO.js} +1 -1
  39. package/dist/plugin-sdk/{auth-json-BrNBg87n.js → auth-json-DK6qod1_.js} +1 -1
  40. package/dist/plugin-sdk/{bindings-CH-YLOLC.js → bindings-CDEzl4kl.js} +1 -1
  41. package/dist/plugin-sdk/{channel-web-B6rg0Rbf.js → channel-web-D2KuONp0.js} +1 -1
  42. package/dist/plugin-sdk/{chrome-CuXP-hes.js → chrome-SOXFIkUM.js} +1 -1
  43. package/dist/plugin-sdk/{chunk-C94IAOuf.js → chunk-cW0POl22.js} +1 -1
  44. package/dist/plugin-sdk/{command-format-B3XMq_73.js → command-format-CAX9XFjI.js} +1 -1
  45. package/dist/plugin-sdk/{common-n0l_XN-S.js → common-BxEWhN2X.js} +1 -1
  46. package/dist/plugin-sdk/{config-DsXZsCkJ.js → config-v1EU9Ll8.js} +2 -2
  47. package/dist/plugin-sdk/{fetch-B-GxSYRO.js → fetch-DH0Y8iyO.js} +1 -1
  48. package/dist/plugin-sdk/index.js +1 -1
  49. package/dist/plugin-sdk/{login-_my8QwPP.js → login-d1zBgykF.js} +1 -1
  50. package/dist/plugin-sdk/{login-qr-BaePtXuG.js → login-qr-B6exvQnN.js} +1 -1
  51. package/dist/plugin-sdk/{manager-BsC-4ymy.js → manager-BH_bmGds.js} +1 -1
  52. package/dist/plugin-sdk/{markdown-tables-BUfhHgfs.js → markdown-tables-Epim9b-0.js} +1 -1
  53. package/dist/plugin-sdk/{message-channel-CuZ2xOAM.js → message-channel-sBPQc_-T.js} +1 -1
  54. package/dist/plugin-sdk/{model-catalog-yuiXVcmw.js → model-catalog-cXsza5GU.js} +1 -1
  55. package/dist/plugin-sdk/{model-selection-BtgvnqB5.js → model-selection-K82MAGlL.js} +1 -1
  56. package/dist/plugin-sdk/{outbound-D_attiyO.js → outbound-Chn_H1O7.js} +1 -1
  57. package/dist/plugin-sdk/{plugins-BdkC9v5E.js → plugins-CaUOZBVb.js} +1 -1
  58. package/dist/plugin-sdk/{pw-ai-A7Rathx6.js → pw-ai-BIiJF7ZD.js} +1 -1
  59. package/dist/plugin-sdk/{qmd-manager-Dxn0jCpE.js → qmd-manager-BRe5fGZw.js} +1 -1
  60. package/dist/plugin-sdk/{registry-CZHRcH-q.js → registry-DJq2Cvo9.js} +1 -1
  61. package/dist/plugin-sdk/{render-CuA_WRX5.js → render-BUCRXPIk.js} +1 -1
  62. package/dist/plugin-sdk/{replies-DmLfO-pg.js → replies-Cz5OD3qN.js} +1 -1
  63. package/dist/plugin-sdk/{reply-3-ne-N_7.js → reply-D5Uk7pUv.js} +9 -9
  64. package/dist/plugin-sdk/{reply-prefix-w7kAvH11.js → reply-prefix-CCymsmsP.js} +1 -1
  65. package/dist/plugin-sdk/{resolve-route-0sbvl4ZN.js → resolve-route-DN1J7Wyc.js} +1 -1
  66. package/dist/plugin-sdk/{runner-4UfrAQnx.js → runner-CYkuO7Fh.js} +4 -4
  67. package/dist/plugin-sdk/{session-BB-yfDWx.js → session-D5jHDo78.js} +1 -1
  68. package/dist/plugin-sdk/{sqlite-JjFgDV-H.js → sqlite-BlMLqMl8.js} +1 -1
  69. package/dist/plugin-sdk/{subsystem-D0Ril4rt.js → subsystem-COTa5Ly_.js} +1 -1
  70. package/dist/plugin-sdk/{tool-images-WRTP95FT.js → tool-images-DSpchb4x.js} +1 -1
  71. package/dist/plugin-sdk/{tool-loop-detection-sC_rhJfb.js → tool-loop-detection-BP6u-mbh.js} +1 -1
  72. package/dist/plugin-sdk/web-BbganhKi.js +1 -0
  73. package/dist/plugin-sdk/{whatsapp-actions-ThxQ5niy.js → whatsapp-actions-CZUqxmP1.js} +1 -1
  74. package/dist/{program-DHWSgdol.js → program-BgDciyOQ.js} +2 -2
  75. package/dist/{program-context-7XUznN5J.js → program-context-CpxTJP1m.js} +1 -1
  76. package/dist/{prompt-select-styled-Depbcbpw.js → prompt-select-styled-Bu7WPMzB.js} +1 -1
  77. package/dist/{prompt-select-styled-Cy70lEMU.js → prompt-select-styled-Qb0DubNy.js} +1 -1
  78. package/dist/{pw-ai-UGketqfG.js → pw-ai-CsJmJcNk.js} +1 -1
  79. package/dist/{register.maintenance-ohxXhvKX.js → register.maintenance-CPnm6L-m.js} +1 -1
  80. package/dist/{register.maintenance-BmnagkdH.js → register.maintenance-D8WmeEaD.js} +1 -1
  81. package/dist/{register.onboard-C2Cnd-e9.js → register.onboard-BoUicPRh.js} +1 -1
  82. package/dist/{register.onboard-FSaweh3A.js → register.onboard-DMfqe2nX.js} +1 -1
  83. package/dist/{register.setup-CyTZQLXP.js → register.setup-BK6OEvY3.js} +1 -1
  84. package/dist/{register.setup-Dk9hBOkZ.js → register.setup-CtcAR3JR.js} +1 -1
  85. package/dist/{register.subclis-lGgi7ATb.js → register.subclis-Dl6jPPsc.js} +1 -1
  86. package/dist/{register.subclis-DqO3Ciiv.js → register.subclis-EScCVgbV.js} +1 -1
  87. package/dist/{run-main-BipfHjUR.js → run-main-C3lmcvyV.js} +1 -1
  88. package/dist/{runner-B70PGCqP.js → runner-D7af_RBH.js} +3 -3
  89. package/dist/{tui-DHjIJOFN.js → tui-D2sTsa4p.js} +1 -1
  90. package/dist/{tui-C5ChWpBg.js → tui-DY2oYbxk.js} +1 -1
  91. package/dist/{tui-cli-BeFWcUWU.js → tui-cli-GW-qybY6.js} +1 -1
  92. package/dist/{tui-cli-wPseN93O.js → tui-cli-wn3DmvUG.js} +1 -1
  93. package/dist/{update-cli-CRkZnN_N.js → update-cli-CN0oxZ_A.js} +1 -1
  94. package/dist/{update-cli-DekV-CP_.js → update-cli-K5dGZmg8.js} +1 -1
  95. package/dist/{web-D44jKC1F.js → web-DPGGHIc_.js} +1 -1
  96. package/package.json +1 -1
  97. package/dist/chrome-Blk2Jftn.js +0 -4
  98. package/dist/plugin-sdk/web-CThgoHQp.js +0 -1
@@ -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-BHg-VHB4.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-Cv7CoWAs.js";import{E as truncateUtf16Safe,H as getChildLogger,L as colorize,N as setVerbose,R as isRich,S as shortenHomePath,U as getLogger,W as getResolvedLoggerSettings,n as clamp,s as ensureDir,t as CONFIG_DIR,u as isPlainObject,y as resolveUserPath,z as theme}from"./utils-BP60e80M.js";import{a as setConsoleSubsystemFilter,n as runtimeForLogger,o as setConsoleTimestampPrefix,p as defaultRuntime,t as createSubsystemLogger}from"./subsystem-C4b1Von0.js";import"./boolean-ssGoaBPk.js";import{n as logAcceptedEnvOption,t as isTruthyEnvValue}from"./env-BoE8QSib.js";import"./warning-filter-nSTjpMIH.js";import{B as resolveAllowedModelRef,H as resolveConfiguredModelRef,Ht as CURRENT_SESSION_VERSION,It as canUseToolDecision,J as resolveThinkingDefault,K as resolveSubagentConfiguredModelSelection,N as getModelRefStatus,O as isPidAlive,P as isCliProvider,Qt as normalizeSecretInput,U as resolveDefaultModelForAgent,Ut as SessionManager,W as resolveHooksGmailModel,_n as DEFAULT_PROVIDER,gn as DEFAULT_MODEL,hn as DEFAULT_CONTEXT_TOKENS,k as buildAllowedModelSet,rt as resolveFreetokenApiBase,st as resolveOllamaApiBase,zt as nativeComplete}from"./auth-profiles-C1VbcUOm.js";import{t as formatCliCommand}from"./command-format-DTMaGKs7.js";import"./src-DvWaTze9.js";import{i as logWarn,t as logDebug}from"./logger-wuOr7HKl.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-CksCYipj.js";import{s as matchesSkillFilter,t as resolveBuilderForceAgentsPackageRoot}from"./builderforce-root-DY1qbWNX.js";import{n as runExec,t as runCommandWithTimeout}from"./exec-COgsU9ql.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-CufEmNj_.js";import{t as normalizeBaseUrl}from"./normalize-base-url-D_sv6Zgt.js";import{i as readSharedEnvVar,t as isOfflineMode}from"./env-file-DeS6x2OL.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-HrLX5bhG.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-CohJffHG.js";import{s as isTestDefaultMemorySlotDisabled}from"./manifest-registry-009gLJ4l.js";import{t as migrateLegacyConfig}from"./config-toczWD3q.js";import"./model-discovery-C9Xm95uL.js";import{r as loadModelCatalog}from"./model-catalog-CiiFJX77.js";import{d as hasBinary}from"./frontmatter-CaY7feZm.js";import{i as loadWorkspaceSkillEntries,r as buildWorkspaceSkillSnapshot}from"./skills-D3MwwPOH.js";import"./plugin-skills-pSFUbhg_.js";import{t as buildWorkspaceSkillStatus}from"./skills-status-CGlKz1D1.js";import{a as registerSkillsChangeListener,i as getSkillsSnapshotVersion,n as bumpSkillsSnapshotVersion}from"./refresh-C4vwneXT.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-CGgp3zkQ.js";import{n as pickPrimaryTailnetIPv4,r as pickPrimaryTailnetIPv6}from"./tailnet-B0Q5E6lZ.js";import{n as callGateway,o as loadGatewayTlsRuntime$1}from"./call-DmAU4cRX.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-z5YRpR2d.js";import{c as pickPrimaryLanIPv4,d as resolveGatewayListenHosts,f as resolveHostName,i as isTrustedProxyAddress,l as resolveGatewayBindHost,n as isLoopbackHost,o as normalizeHostHeader,p as rawDataToString,r as isPrivateOrLoopbackAddress,t as isLoopbackAddress,u as resolveGatewayClientIp}from"./net-DtnXq2dW.js";import{i as normalizeInputProvenance}from"./input-provenance-Rnkkt19n.js";import{$ as resolveAnnounceTargetFromKey,$r as setCommandLaneConcurrency,A as sleepWithAbort,Ar as registerTeamMemoryContextBuilder,At as persistBrowserProxyFiles,B as createReplyDispatcher,Br as setTtsProvider,Bt as dispatchToRemoteAgentNode,Cn as verifyPairingToken,Cr as resolveUserTimezone,D as readJsonBodyWithLimit,Dn as readJsonFile,Dr as getSsmMemoryService,Dt as getHookType,E as handleSlackHttpRequest,En as createAsyncLock,Er as initLimbicSystemService,Et as detectSuspiciousPatterns,Fn as applyVerboseOverride,Fr as resolveTtsAutoMode,Ft as gitHistoryTool,Gn as extractFileContentFromSource,Gt as spawnSubagentDirect,Hn as DEFAULT_INPUT_IMAGE_MIMES,Hr as OPENAI_TTS_MODELS,Ht as loadHiredAgentsCached,In as parseVerboseOverride,Ir as resolveTtsConfig,It as workflowStatusTool,J as setCliSessionId,Jn as resolveInputFileLimits,Jt as getBuiltInAgentRoles,K as resolveCronStyleNow,Kn as extractImageContentFromSource,Kt as resolveRelayTaskModel,Ln as enqueueSystemEvent,Lr as resolveTtsPrefsPath,Lt as globalOrchestrator,Mr as isTtsEnabled,Mt as resolveApproval,Nr as isTtsProviderConfigured,Nt as semanticSearchTool,O as requestBodyErrorToText,On as writeJsonAtomic,Or as initSsmMemoryService,Ot as isExternalHookSession,P as buildHistoryContextFromEntries,Pn as applyModelOverrideToSessionEntry,Pr as resolveTtsApiKey,Pt as agentFleetTool,Q as readLatestAssistantReply,Qr as resetAllLanes,Qt as normalizeGroupActivation,Rn as isSystemEventContextChanged,Rr as resolveTtsProviderOrder,Rt as dispatchChunkToRemoteAgentNode,S as getPluginToolMeta,Sn as generatePairingToken,Sr as writeRestartSentinel,St as stripLegacyDeliveryFields,Tn as resolvePairingPaths,Tr as getLimbicSystemService,Tt as buildSafeExternalPrompt,Un as DEFAULT_INPUT_MAX_REDIRECTS,Ur as OPENAI_TTS_VOICES,Ut as projectKnowledgeTool,V as getTotalPendingReplies,Vn as DEFAULT_INPUT_IMAGE_MAX_BYTES,Vr as textToSpeech,Vt as fetchFleetEntries,W as BARE_SESSION_RESET_PROMPT,Wn as DEFAULT_INPUT_TIMEOUT_MS,Wt as codebaseSearchTool,Xn as resolveAgentTimeoutMs,Y as runCliAgent,Yr as getActiveTaskCount,Yt as registerPlatformPersonasAsRoles,Z as createBuilderForceAgentsTools,Zr as getTotalQueueSize,_ as getActiveEmbeddedRunCount,_n as rejectNodePairing,_r as formatDoctorNonInteractiveHint,_t as normalizePayloadToSystemText,ar as stopSubagentsForRequester,at as resolveOutboundTarget,b as buildDefaultToolPolicyPipelineSteps,bn as updatePairedNodeMetadata,br as summarizeRestartSentinel,bt as buildDeliveryFromLegacyPayload,cn as getRemoteSkillEligibility,cr as consumeGatewaySigusr1RestartAuthorization,ct as resetDirectoryCache,di as clearAgentRunContext,dn as refreshRemoteBinsForConnectedNodes,dr as isGatewaySigusr1RestartExternallyAllowed,dt as normalizeCronJobCreate,ei as waitForActiveTasks,fi as emitAgentEvent,fn as refreshRemoteNodeBins,fr as markGatewaySigusr1RestartHandled,ft as normalizeCronJobPatch,g as abortEmbeddedRun,gn as listNodePairing,gr as consumeRestartSentinel,gt as normalizeOptionalText,h as runEmbeddedAgent,hi as registerAgentRunContext,hn as approveNodePairing,hr as setPreRestartDeferralCheck,ht as normalizeOptionalSessionKey,i as initSubagentRegistry,ii as isDiagnosticsEnabled,in as requestHeartbeatNow,ir as isAbortTrigger,jr as getTtsProvider,jt as initApprovalGate,k as computeBackoff,kr as registerKnowledgeLoop,kt as applyBrowserProxyPaths,ln as primeRemoteSkillsCache,lr as deferGatewayRestartUntilIdle,m as clearSessionQueues,mi as onAgentEvent,mn as setSkillsRemoteRegistry,mr as setGatewaySigusr1RestartPolicy,mt as normalizeOptionalAgentId,n as countActiveDescendantRuns,ni as startDiagnosticHeartbeat,nt as resolveOutboundSessionRoute,o as listDescendantRunsForRequester,oi as DEFAULT_HEARTBEAT_ACK_MAX_CHARS,on as normalizeSendPolicy,ot as resolveSessionDeliveryTarget,p as runSubagentAnnounceFlow,pi as getAgentRunContext,pn as removeRemoteNodeInfo,pr as scheduleGatewaySigusr1Restart,pt as inferLegacyName,q as getCliSessionId,qn as normalizeMimeList,qr as runWithModelFallback,qt as findAgentRole,ri as stopDiagnosticHeartbeat,sn as resolveSendPolicy,ti as CommandLane,tr as formatZonedTimestamp,tt as ensureOutboundSessionEntry,ui as stripHeartbeatToken,un as recordRemoteNodeInfo,ur as emitGatewayRestart,ut as normalizeHttpWebhookUrl,v as waitForEmbeddedRunEnd,vn as renamePairedNode,vr as formatRestartSentinelMessage,vt as normalizeRequiredName,w as loadBuilderForceAgentsPlugins,wn as pruneExpiredPending,wr as buildAssignedCapabilityAppend,xn as verifyNodeToken,xt as hasLegacyDeliveryHints,y as applyToolPolicyPipeline,yn as requestNodePairing,yt as migrateLegacyCronPayload,z as dispatchInboundMessage,zr as setTtsEnabled,zt as dispatchResultToRemoteAgentNode}from"./subagent-registry-CyGxu3kP.js";import{A as canonicalizeMainSessionAlias,C as evaluateSessionFreshness,I as snapshotSessionOrigin,M as resolveExplicitAgentSessionKey,N as resolveMainSessionKey,P as resolveMainSessionKeyFromConfig,Q as deliveryContextFromSession,T as resolveSessionResetPolicy,X as cleanStaleLockFiles,_ as readSessionMessages,a as loadSessionStore,b as resolveSessionTranscriptCandidates,et as mergeDeliveryContext,g as capArrayByJsonBytes,h as archiveSessionTranscripts,j as resolveAgentMainSessionKey,m as archiveFileOnDisk,n as parseSessionThreadInfo,nt as normalizeSessionDeliveryFields,t as extractDeliveryInfo,u as updateSessionStore,v as readSessionPreviewItemsFromTranscript,x as stripEnvelopeFromMessages}from"./sessions-Bl1wwotX.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-CIUcwUP_.js";import{n as SILENT_REPLY_TOKEN,r as isSilentReplyText}from"./tokens-CFKkpUIu.js";import{n as listChannelPlugins,r as normalizeChannelId,t as getChannelPlugin}from"./plugins-1Mn6RiNf.js";import"./accounts-BkTLjSrD.js";import{t as buildChannelAccountBindings}from"./bindings-CKSDlQ1i.js";import"./send-BvroeIQ6.js";import"./send-CceNWtYE.js";import{n as createBrowserRouteDispatcher,r as getMachineDisplayName}from"./with-timeout-T07SJo4N.js";import{C as getGlobalHookRunner,T as runGlobalGatewayStopSafely,a as normalizeReplyPayloadsForDelivery,t as deliverOutboundPayloads}from"./deliver-BuZu68tp.js";import"./accounts-Cx82nj4E.js";import"./send-ByCVQQVz.js";import{c as detectMime}from"./image-ops-CotJhwRR.js";import"./redact-CgO7wehS.js";import{a as isErrno,n as formatErrorMessage}from"./errors-tAt19c1E.js";import{a as formatXHighModelHint,c as normalizeElevatedLevel,d as normalizeUsageDisplay,f as normalizeVerboseLevel,i as formatThinkingLevels,l as normalizeReasoningLevel,m as supportsXHighThinking,u as normalizeThinkLevel}from"./embedded-helpers-DK8_apW0.js";import{g as collectExplicitAllowlist,x as resolveToolProfilePolicy,y as mergeAlsoAllowPolicy}from"./sandbox-z9t_PRf9.js";import"./chrome-BnEbJV3D.js";import{i as enableTailscaleServe,n as disableTailscaleServe,o as getTailnetHostname,r as enableTailscaleFunnel,t as disableTailscaleFunnel}from"./tailscale-DV-yOmYe.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-ChecwOXS.js";import"./server-context-owOmmyUM.js";import"./routes-lclJHOYY.js";import"./paths-BnOjueoX.js";import{t as SsrFBlockedError}from"./ssrf-DJXLYZ0d.js";import"./store-DHD2IEgd.js";import{a as formatPortDiagnostics,n as inspectPortUsage,t as ensurePortAvailable}from"./ports-DTku9NSx.js";import{t as movePathToTrash}from"./trash-C3zmJ_O7.js";import"./accounts-DcoaLXKI.js";import{c as resolveStorePath,i as resolveSessionTranscriptPath,n as resolveSessionFilePath,r as resolveSessionFilePathOptions,s as resolveSessionTranscriptsDirForAgent}from"./paths-ClsbsPQP.js";import"./tool-images-CCpqFtrL.js";import{a as shouldIncludeHook,i as resolveHookConfig,n as loadWorkspaceHookEntries}from"./workspace-waBqRxiy.js";import{a as resolveAgentIdentity,n as createReplyPrefixOptions}from"./reply-prefix-Cg7AqaK0.js";import"./sqlite-CIGM1WKg.js";import{i as resolveMemoryBackendConfig,r as getMemorySearchManager}from"./memory-cli-ivAs7q7v.js";import"./manager-CRba8roB.js";import"./gemini-auth-CkD5jCPh.js";import"./retry-B151Hej5.js";import{a as jsonResult,t as ToolInputError}from"./common-BfwMxpLu.js";import{l as registerUnhandledRejectionHandler}from"./runner-DwWmciCt.js";import"./tool-display-Cs4hDP1f.js";import"./chunk-Dly7lM4r.js";import"./markdown-tables-B1Rx8hv6.js";import{t as fetchWithSsrFGuard}from"./fetch-guard-DnXqPKae.js";import"./fetch-Cn_THzz8.js";import"./ir-CSdQJPqu.js";import"./render-DlHYsbvQ.js";import"./builderforcellm-syscheck-CprBhARf.js";import{a as loadCombinedSessionStoreForGateway,c as resolveGatewaySessionStoreTarget,i as listSessionsFromStore,l as resolveSessionModelRef,o as loadSessionEntry,r as listAgentsForGateway,s as pruneLegacyStoreKeys,t as canonicalizeSpawnedByForAgent,u as lookupContextTokens}from"./session-utils-GMvum00v.js";import{a as resolveSubagentToolPolicy,i as resolveGroupToolPolicy,r as resolveEffectiveToolPolicy,u as listAgentWorkspaceDirs}from"./coding-tools.policy-NEPm7Mz1.js";import"./pairing-store-QDb6lhIU.js";import"./fetch-DnWD6ydH.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-D7ZPAZpt.js";import"./nodes-screen-D6GHv_S0.js";import{a as loadSessionUsageTimeSeries,c as hasNonzeroUsage,n as loadCostUsageSummary,r as loadSessionCostSummary,s as deriveSessionTotalTokens,t as discoverAllSessions}from"./session-cost-usage-S0nkbPoW.js";import{n as formatTokenCount,r as formatUsd}from"./usage-format-5sp5AMSu.js";import{t as loadProviderUsageSummary}from"./provider-usage-Bn4ZrnU7.js";import"./send-B_1BtyfA.js";import"./outbound-attachment-BaTYE4qp.js";import"./delivery-queue-Cp3t4Upn.js";import{d as savePersonaAssignment,f as initializeBuilderForceAgentsProject,t as appendKnowledgeMemory,u as loadPersonaAssignments}from"./project-context-D3Mx4maV.js";import{r as startBrowserControlServiceFromConfig,t as createBrowserControlContext}from"./control-service-CJuuqNOE.js";import{i as parseAbsoluteTimeMs,n as resolveCronStaggerMs,r as resolveDefaultCronStaggerMs,t as normalizeCronStaggerMs}from"./stagger-CRe77dWL.js";import{n as resolveMessageChannelSelection}from"./channel-selection-BLwXhb9t.js";import{n as normalizePollInput}from"./polls-BdfE-6dQ.js";import"./send-UFtylOiq.js";import"./resolve-route-DEIW5uKy.js";import{t as getChannelActivity}from"./channel-activity-DX36RadH.js";import"./tables-CojSfTth.js";import{t as formatDocsLink}from"./links-BKzP7VVP.js";import{n as runCommandWithRuntime}from"./cli-utils-C9pW69LF.js";import{t as formatHelpExamples}from"./help-format-CfFf-w62.js";import{n as withProgress}from"./progress-Cqb-jAjT.js";import"./replies-DbkT_5BV.js";import{C as normalizeControlUiBasePath,S as buildControlUiAvatarUrl,c as handleReset,w as resolveAssistantAvatarUrl,x as CONTROL_UI_AVATAR_PREFIX}from"./onboard-helpers-CckrS8_K.js";import"./prompt-style-BMWmaqSC.js";import"./pairing-labels-3j_iRYOO.js";import"./active-listener-Di9e1YAD.js";import"./mamba-state-engine-CV4nDcCk.js";import"./transformers-stream-Buj40qHl.js";import{i as onHeartbeatEvent,r as getLastHeartbeatEvent,t as resolveHeartbeatVisibility}from"./heartbeat-visibility-XUrlH-iZ.js";import{t as ensureBuilderForceAgentsCliOnPath}from"./path-env-Gmzpaha-.js";import{n as DEFAULT_GATEWAY_HTTP_TOOL_DENY}from"./dangerous-tools-C0tOMmbD.js";import{n as inheritOptionFromParent}from"./command-options-DbMbMxM2.js";import{t as buildChannelUiCatalog}from"./catalog-li4bSIE2.js";import{t as WizardCancelledError}from"./prompts-BP4e56X_.js";import{t as resolveChannelDefaultAccountId}from"./helpers-DPPVplyk.js";import{t as applyPluginAutoEnable}from"./plugin-auto-enable-BV9K9Vhr.js";import"./install-safe-path-ObPl6zIf.js";import"./skill-scanner-DEmbPsRh.js";import{t as buildChannelAccountSnapshot}from"./status-BXI_BTqV.js";import"./channels-status-issues-NLYb8w9i.js";import"./daemon-runtime-B4UjqdyJ.js";import"./runtime-guard-Bi8k55v9.js";import"./systemd-DdVd5Yet.js";import"./service-EKJG69M3.js";import"./lifecycle-core-BpMvDXy1.js";import"./diagnostics-DamNPi4e.js";import{t as parsePort$1}from"./parse-port-FgIKmqqb.js";import{n as addGatewayServiceCommands}from"./daemon-cli-DyVsMf8p.js";import"./table-BFCCZDsp.js";import{n as resolveWideAreaDiscoveryDomain,r as writeWideAreaGatewayZone}from"./widearea-dns-DvQozd9v.js";import{i as toOptionString,n as extractGatewayMiskeys,r as maybeExplainGatewayServiceStop,t as describeUnknownError}from"./shared-rsjJRWla.js";import{c as probeGateway,o as isNodeCommandAllowed,s as resolveNodeCommandAllowlist}from"./audit-DBjjjW93.js";import{t as discoverGatewayBeacons}from"./bonjour-discovery-CViQz7cm.js";import{n as getStatusSummary,r as pickGatewaySelfPresence}from"./status-BxeKmkVr.js";import{c as startHeartbeatRunner,i as styleHealthChannelLine,n as getHealthSnapshot,o as runHeartbeatOnce,s as setHeartbeatsEnabled,t as formatHealthChannelLines}from"./health-DVo8a9yg.js";import{n as createDefaultDeps,r as createOutboundSendDeps$1,t as createOutboundSendDeps}from"./outbound-send-deps-m6DqOma_.js";import{a as resolveControlUiRootSync,i as resolveControlUiRootOverrideSync,t as ensureControlUiAssetsBuilt}from"./control-ui-assets-BxgWcomx.js";import{h as normalizeUpdateChannel,l as DEFAULT_PACKAGE_CHANNEL,n as compareSemverStrings,o as resolveNpmChannelTag,t as checkUpdateStatus}from"./update-check-B0YqSZJr.js";import{t as runOnboardingWizard}from"./onboarding-Ctq_bdkC.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-CiD3rrVv.js";import{T as resolveGmailHookRuntimeConfig,_ as buildGogWatchServeArgs,i as ensureTailscaleEndpoint,v as buildGogWatchStartArgs}from"./gmail-setup-utils-CVafFKTa.js";import{a as pruneAgentConfig,i as loadAgentIdentity,r as findAgentEntryIndex,s as loadAgentIdentityFromWorkspace,t as applyAgentConfig}from"./agents.config-D6Yhwmnh.js";import{i as resolveAgentOutboundTarget,r as resolveAgentDeliveryPlan,t as agentCommand}from"./agent-wJmvciTM.js";import"./dm-policy-shared-CRZpjRv0.js";import"./node-service-77UF0ACm.js";import"./status.update-KYyRSDZY.js";import{n as validateSystemRunCommandConsistency,t as formatExecCommand}from"./system-run-command-rlCfXRWt.js";import{t as installSkill}from"./skills-install-DMHQRpIl.js";import{n as runGatewayUpdate,t as resolveAgentSessionDirs}from"./session-dirs-OxQuIvJW.js";import{n as syncBuilderForceAgentsDirectoryOnStartup,t as syncBuilderForceAgentsDirectory}from"./builderforce-directory-sync-DQ6u60yX.js";import{n as mergeBuilderforceContext,t as buildLocalMachineProfile}from"./builderforce-context-CyUg2pSn.js";import{a as emitWorkflowEnd,c as initTelemetry,i as emitTaskStart,l as setRelayHook,o as emitWorkflowStart,r as emitTaskEnd}from"./workflow-telemetry-DLEnm5TI.js";import{n as forceFreePortAndWait}from"./ports-6RmfZEmk.js";import{execFile,spawn,spawnSync}from"node:child_process";import os from"node:os";import path,{dirname,join,relative,sep}from"node:path";import*as fsSync from"node:fs";import fs,{constants}from"node:fs";import{promisify}from"node:util";import chalk from"chalk";import crypto,{createHash,randomUUID}from"node:crypto";import{fileURLToPath,pathToFileURL}from"node:url";import JSON5 from"json5";import{z}from"zod";import fs$1,{mkdir,readFile,readdir,writeFile}from"node:fs/promises";import chokidar from"chokidar";import{WebSocket as WebSocket$1,WebSocketServer}from"ws";import{Buffer as Buffer$1}from"node:buffer";import{Type}from"@sinclair/typebox";import net from"node:net";import{createServer}from"node:http";import{createServer as createServer$1}from"node:https";import{neutralLimbicState}from"@seanhogg/builderforce-memory-engine/limbic";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-BHg-VHB4.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-Cv7CoWAs.js";import{E as truncateUtf16Safe,H as getChildLogger,L as colorize,N as setVerbose,R as isRich,S as shortenHomePath,U as getLogger,W as getResolvedLoggerSettings,n as clamp,s as ensureDir,t as CONFIG_DIR,u as isPlainObject,y as resolveUserPath,z as theme}from"./utils-BP60e80M.js";import{a as setConsoleSubsystemFilter,n as runtimeForLogger,o as setConsoleTimestampPrefix,p as defaultRuntime,t as createSubsystemLogger}from"./subsystem-C4b1Von0.js";import"./boolean-ssGoaBPk.js";import{n as logAcceptedEnvOption,t as isTruthyEnvValue}from"./env-BoE8QSib.js";import"./warning-filter-nSTjpMIH.js";import{B as resolveAllowedModelRef,H as resolveConfiguredModelRef,Ht as CURRENT_SESSION_VERSION,It as canUseToolDecision,J as resolveThinkingDefault,K as resolveSubagentConfiguredModelSelection,N as getModelRefStatus,O as isPidAlive,P as isCliProvider,Qt as normalizeSecretInput,U as resolveDefaultModelForAgent,Ut as SessionManager,W as resolveHooksGmailModel,_n as DEFAULT_PROVIDER,gn as DEFAULT_MODEL,hn as DEFAULT_CONTEXT_TOKENS,k as buildAllowedModelSet,rt as resolveFreetokenApiBase,st as resolveOllamaApiBase,zt as nativeComplete}from"./auth-profiles-C1VbcUOm.js";import{t as formatCliCommand}from"./command-format-DTMaGKs7.js";import"./src-DvWaTze9.js";import{i as logWarn,t as logDebug}from"./logger-wuOr7HKl.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-CksCYipj.js";import{s as matchesSkillFilter,t as resolveBuilderForceAgentsPackageRoot}from"./builderforce-root-DY1qbWNX.js";import{n as runExec,t as runCommandWithTimeout}from"./exec-COgsU9ql.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-CufEmNj_.js";import{t as normalizeBaseUrl}from"./normalize-base-url-D_sv6Zgt.js";import{i as readSharedEnvVar,t as isOfflineMode}from"./env-file-DeS6x2OL.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-HrLX5bhG.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-CohJffHG.js";import{s as isTestDefaultMemorySlotDisabled}from"./manifest-registry-009gLJ4l.js";import{t as migrateLegacyConfig}from"./config-toczWD3q.js";import"./model-discovery-C9Xm95uL.js";import{r as loadModelCatalog}from"./model-catalog-CiiFJX77.js";import{d as hasBinary}from"./frontmatter-CaY7feZm.js";import{i as loadWorkspaceSkillEntries,r as buildWorkspaceSkillSnapshot}from"./skills-D3MwwPOH.js";import"./plugin-skills-pSFUbhg_.js";import{t as buildWorkspaceSkillStatus}from"./skills-status-CGlKz1D1.js";import{a as registerSkillsChangeListener,i as getSkillsSnapshotVersion,n as bumpSkillsSnapshotVersion}from"./refresh-C4vwneXT.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-CGgp3zkQ.js";import{n as pickPrimaryTailnetIPv4,r as pickPrimaryTailnetIPv6}from"./tailnet-B0Q5E6lZ.js";import{n as callGateway,o as loadGatewayTlsRuntime$1}from"./call-DmAU4cRX.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-z5YRpR2d.js";import{c as pickPrimaryLanIPv4,d as resolveGatewayListenHosts,f as resolveHostName,i as isTrustedProxyAddress,l as resolveGatewayBindHost,n as isLoopbackHost,o as normalizeHostHeader,p as rawDataToString,r as isPrivateOrLoopbackAddress,t as isLoopbackAddress,u as resolveGatewayClientIp}from"./net-DtnXq2dW.js";import{i as normalizeInputProvenance}from"./input-provenance-Rnkkt19n.js";import{$ as resolveAnnounceTargetFromKey,$r as setCommandLaneConcurrency,A as sleepWithAbort,Ar as registerTeamMemoryContextBuilder,At as persistBrowserProxyFiles,B as createReplyDispatcher,Br as setTtsProvider,Bt as dispatchToRemoteAgentNode,Cn as verifyPairingToken,Cr as resolveUserTimezone,D as readJsonBodyWithLimit,Dn as readJsonFile,Dr as getSsmMemoryService,Dt as getHookType,E as handleSlackHttpRequest,En as createAsyncLock,Er as initLimbicSystemService,Et as detectSuspiciousPatterns,Fn as applyVerboseOverride,Fr as resolveTtsAutoMode,Ft as gitHistoryTool,Gn as extractFileContentFromSource,Gt as spawnSubagentDirect,Hn as DEFAULT_INPUT_IMAGE_MIMES,Hr as OPENAI_TTS_MODELS,Ht as loadHiredAgentsCached,In as parseVerboseOverride,Ir as resolveTtsConfig,It as workflowStatusTool,J as setCliSessionId,Jn as resolveInputFileLimits,Jt as getBuiltInAgentRoles,K as resolveCronStyleNow,Kn as extractImageContentFromSource,Kt as resolveRelayTaskModel,Ln as enqueueSystemEvent,Lr as resolveTtsPrefsPath,Lt as globalOrchestrator,Mr as isTtsEnabled,Mt as resolveApproval,Nr as isTtsProviderConfigured,Nt as semanticSearchTool,O as requestBodyErrorToText,On as writeJsonAtomic,Or as initSsmMemoryService,Ot as isExternalHookSession,P as buildHistoryContextFromEntries,Pn as applyModelOverrideToSessionEntry,Pr as resolveTtsApiKey,Pt as agentFleetTool,Q as readLatestAssistantReply,Qr as resetAllLanes,Qt as normalizeGroupActivation,Rn as isSystemEventContextChanged,Rr as resolveTtsProviderOrder,Rt as dispatchChunkToRemoteAgentNode,S as getPluginToolMeta,Sn as generatePairingToken,Sr as writeRestartSentinel,St as stripLegacyDeliveryFields,Tn as resolvePairingPaths,Tr as getLimbicSystemService,Tt as buildSafeExternalPrompt,Un as DEFAULT_INPUT_MAX_REDIRECTS,Ur as OPENAI_TTS_VOICES,Ut as projectKnowledgeTool,V as getTotalPendingReplies,Vn as DEFAULT_INPUT_IMAGE_MAX_BYTES,Vr as textToSpeech,Vt as fetchFleetEntries,W as BARE_SESSION_RESET_PROMPT,Wn as DEFAULT_INPUT_TIMEOUT_MS,Wt as codebaseSearchTool,Xn as resolveAgentTimeoutMs,Y as runCliAgent,Yr as getActiveTaskCount,Yt as registerPlatformPersonasAsRoles,Z as createBuilderForceAgentsTools,Zr as getTotalQueueSize,_ as getActiveEmbeddedRunCount,_n as rejectNodePairing,_r as formatDoctorNonInteractiveHint,_t as normalizePayloadToSystemText,ar as stopSubagentsForRequester,at as resolveOutboundTarget,b as buildDefaultToolPolicyPipelineSteps,bn as updatePairedNodeMetadata,br as summarizeRestartSentinel,bt as buildDeliveryFromLegacyPayload,cn as getRemoteSkillEligibility,cr as consumeGatewaySigusr1RestartAuthorization,ct as resetDirectoryCache,di as clearAgentRunContext,dn as refreshRemoteBinsForConnectedNodes,dr as isGatewaySigusr1RestartExternallyAllowed,dt as normalizeCronJobCreate,ei as waitForActiveTasks,fi as emitAgentEvent,fn as refreshRemoteNodeBins,fr as markGatewaySigusr1RestartHandled,ft as normalizeCronJobPatch,g as abortEmbeddedRun,gn as listNodePairing,gr as consumeRestartSentinel,gt as normalizeOptionalText,h as runEmbeddedAgent,hi as registerAgentRunContext,hn as approveNodePairing,hr as setPreRestartDeferralCheck,ht as normalizeOptionalSessionKey,i as initSubagentRegistry,ii as isDiagnosticsEnabled,in as requestHeartbeatNow,ir as isAbortTrigger,jr as getTtsProvider,jt as initApprovalGate,k as computeBackoff,kr as registerKnowledgeLoop,kt as applyBrowserProxyPaths,ln as primeRemoteSkillsCache,lr as deferGatewayRestartUntilIdle,m as clearSessionQueues,mi as onAgentEvent,mn as setSkillsRemoteRegistry,mr as setGatewaySigusr1RestartPolicy,mt as normalizeOptionalAgentId,n as countActiveDescendantRuns,ni as startDiagnosticHeartbeat,nt as resolveOutboundSessionRoute,o as listDescendantRunsForRequester,oi as DEFAULT_HEARTBEAT_ACK_MAX_CHARS,on as normalizeSendPolicy,ot as resolveSessionDeliveryTarget,p as runSubagentAnnounceFlow,pi as getAgentRunContext,pn as removeRemoteNodeInfo,pr as scheduleGatewaySigusr1Restart,pt as inferLegacyName,q as getCliSessionId,qn as normalizeMimeList,qr as runWithModelFallback,qt as findAgentRole,ri as stopDiagnosticHeartbeat,sn as resolveSendPolicy,ti as CommandLane,tr as formatZonedTimestamp,tt as ensureOutboundSessionEntry,ui as stripHeartbeatToken,un as recordRemoteNodeInfo,ur as emitGatewayRestart,ut as normalizeHttpWebhookUrl,v as waitForEmbeddedRunEnd,vn as renamePairedNode,vr as formatRestartSentinelMessage,vt as normalizeRequiredName,w as loadBuilderForceAgentsPlugins,wn as pruneExpiredPending,wr as buildAssignedCapabilityAppend,xn as verifyNodeToken,xt as hasLegacyDeliveryHints,y as applyToolPolicyPipeline,yn as requestNodePairing,yt as migrateLegacyCronPayload,z as dispatchInboundMessage,zr as setTtsEnabled,zt as dispatchResultToRemoteAgentNode}from"./subagent-registry-CyGxu3kP.js";import{A as canonicalizeMainSessionAlias,C as evaluateSessionFreshness,I as snapshotSessionOrigin,M as resolveExplicitAgentSessionKey,N as resolveMainSessionKey,P as resolveMainSessionKeyFromConfig,Q as deliveryContextFromSession,T as resolveSessionResetPolicy,X as cleanStaleLockFiles,_ as readSessionMessages,a as loadSessionStore,b as resolveSessionTranscriptCandidates,et as mergeDeliveryContext,g as capArrayByJsonBytes,h as archiveSessionTranscripts,j as resolveAgentMainSessionKey,m as archiveFileOnDisk,n as parseSessionThreadInfo,nt as normalizeSessionDeliveryFields,t as extractDeliveryInfo,u as updateSessionStore,v as readSessionPreviewItemsFromTranscript,x as stripEnvelopeFromMessages}from"./sessions-Bl1wwotX.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-CIUcwUP_.js";import{n as SILENT_REPLY_TOKEN,r as isSilentReplyText}from"./tokens-CFKkpUIu.js";import{n as listChannelPlugins,r as normalizeChannelId,t as getChannelPlugin}from"./plugins-1Mn6RiNf.js";import"./accounts-BkTLjSrD.js";import{t as buildChannelAccountBindings}from"./bindings-CKSDlQ1i.js";import"./send-BvroeIQ6.js";import"./send-CceNWtYE.js";import{n as createBrowserRouteDispatcher,r as getMachineDisplayName}from"./with-timeout-T07SJo4N.js";import{C as getGlobalHookRunner,T as runGlobalGatewayStopSafely,a as normalizeReplyPayloadsForDelivery,t as deliverOutboundPayloads}from"./deliver-BuZu68tp.js";import"./accounts-Cx82nj4E.js";import"./send-ByCVQQVz.js";import{c as detectMime}from"./image-ops-CotJhwRR.js";import"./redact-CgO7wehS.js";import{a as isErrno,n as formatErrorMessage}from"./errors-tAt19c1E.js";import{a as formatXHighModelHint,c as normalizeElevatedLevel,d as normalizeUsageDisplay,f as normalizeVerboseLevel,i as formatThinkingLevels,l as normalizeReasoningLevel,m as supportsXHighThinking,u as normalizeThinkLevel}from"./embedded-helpers-DK8_apW0.js";import{g as collectExplicitAllowlist,x as resolveToolProfilePolicy,y as mergeAlsoAllowPolicy}from"./sandbox-z9t_PRf9.js";import"./chrome-BnEbJV3D.js";import{i as enableTailscaleServe,n as disableTailscaleServe,o as getTailnetHostname,r as enableTailscaleFunnel,t as disableTailscaleFunnel}from"./tailscale-DV-yOmYe.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-ChecwOXS.js";import"./server-context-owOmmyUM.js";import"./routes-lclJHOYY.js";import"./paths-BnOjueoX.js";import{t as SsrFBlockedError}from"./ssrf-DJXLYZ0d.js";import"./store-DHD2IEgd.js";import{a as formatPortDiagnostics,n as inspectPortUsage,t as ensurePortAvailable}from"./ports-DTku9NSx.js";import{t as movePathToTrash}from"./trash-C3zmJ_O7.js";import"./accounts-DcoaLXKI.js";import{c as resolveStorePath,i as resolveSessionTranscriptPath,n as resolveSessionFilePath,r as resolveSessionFilePathOptions,s as resolveSessionTranscriptsDirForAgent}from"./paths-ClsbsPQP.js";import"./tool-images-CCpqFtrL.js";import{a as shouldIncludeHook,i as resolveHookConfig,n as loadWorkspaceHookEntries}from"./workspace-waBqRxiy.js";import{a as resolveAgentIdentity,n as createReplyPrefixOptions}from"./reply-prefix-Cg7AqaK0.js";import"./sqlite-CIGM1WKg.js";import{i as resolveMemoryBackendConfig,r as getMemorySearchManager}from"./memory-cli-ivAs7q7v.js";import"./manager-CRba8roB.js";import"./gemini-auth-CkD5jCPh.js";import"./retry-B151Hej5.js";import{a as jsonResult,t as ToolInputError}from"./common-BfwMxpLu.js";import{l as registerUnhandledRejectionHandler}from"./runner-DwWmciCt.js";import"./tool-display-Cs4hDP1f.js";import"./chunk-Dly7lM4r.js";import"./markdown-tables-B1Rx8hv6.js";import{t as fetchWithSsrFGuard}from"./fetch-guard-DnXqPKae.js";import"./fetch-Cn_THzz8.js";import"./ir-CSdQJPqu.js";import"./render-DlHYsbvQ.js";import"./builderforcellm-syscheck-CprBhARf.js";import{a as loadCombinedSessionStoreForGateway,c as resolveGatewaySessionStoreTarget,i as listSessionsFromStore,l as resolveSessionModelRef,o as loadSessionEntry,r as listAgentsForGateway,s as pruneLegacyStoreKeys,t as canonicalizeSpawnedByForAgent,u as lookupContextTokens}from"./session-utils-GMvum00v.js";import{a as resolveSubagentToolPolicy,i as resolveGroupToolPolicy,r as resolveEffectiveToolPolicy,u as listAgentWorkspaceDirs}from"./coding-tools.policy-NEPm7Mz1.js";import"./pairing-store-QDb6lhIU.js";import"./fetch-DnWD6ydH.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-D7ZPAZpt.js";import"./nodes-screen-D6GHv_S0.js";import{a as loadSessionUsageTimeSeries,c as hasNonzeroUsage,n as loadCostUsageSummary,r as loadSessionCostSummary,s as deriveSessionTotalTokens,t as discoverAllSessions}from"./session-cost-usage-S0nkbPoW.js";import{n as formatTokenCount,r as formatUsd}from"./usage-format-5sp5AMSu.js";import{t as loadProviderUsageSummary}from"./provider-usage-Bn4ZrnU7.js";import"./send-B_1BtyfA.js";import"./outbound-attachment-BaTYE4qp.js";import"./delivery-queue-Cp3t4Upn.js";import{d as savePersonaAssignment,f as initializeBuilderForceAgentsProject,t as appendKnowledgeMemory,u as loadPersonaAssignments}from"./project-context-D3Mx4maV.js";import{r as startBrowserControlServiceFromConfig,t as createBrowserControlContext}from"./control-service-CJuuqNOE.js";import{i as parseAbsoluteTimeMs,n as resolveCronStaggerMs,r as resolveDefaultCronStaggerMs,t as normalizeCronStaggerMs}from"./stagger-CRe77dWL.js";import{n as resolveMessageChannelSelection}from"./channel-selection-BLwXhb9t.js";import{n as normalizePollInput}from"./polls-BdfE-6dQ.js";import"./send-UFtylOiq.js";import"./resolve-route-DEIW5uKy.js";import{t as getChannelActivity}from"./channel-activity-DX36RadH.js";import"./tables-CojSfTth.js";import{t as formatDocsLink}from"./links-BKzP7VVP.js";import{n as runCommandWithRuntime}from"./cli-utils-C9pW69LF.js";import{t as formatHelpExamples}from"./help-format-CfFf-w62.js";import{n as withProgress}from"./progress-Cqb-jAjT.js";import"./replies-DbkT_5BV.js";import{C as normalizeControlUiBasePath,S as buildControlUiAvatarUrl,c as handleReset,w as resolveAssistantAvatarUrl,x as CONTROL_UI_AVATAR_PREFIX}from"./onboard-helpers-CckrS8_K.js";import"./prompt-style-BMWmaqSC.js";import"./pairing-labels-3j_iRYOO.js";import"./active-listener-Di9e1YAD.js";import"./mamba-state-engine-CV4nDcCk.js";import"./transformers-stream-Buj40qHl.js";import{i as onHeartbeatEvent,r as getLastHeartbeatEvent,t as resolveHeartbeatVisibility}from"./heartbeat-visibility-XUrlH-iZ.js";import{t as ensureBuilderForceAgentsCliOnPath}from"./path-env-Gmzpaha-.js";import{n as DEFAULT_GATEWAY_HTTP_TOOL_DENY}from"./dangerous-tools-C0tOMmbD.js";import{n as inheritOptionFromParent}from"./command-options-DbMbMxM2.js";import{t as buildChannelUiCatalog}from"./catalog-li4bSIE2.js";import{t as WizardCancelledError}from"./prompts-BP4e56X_.js";import{t as resolveChannelDefaultAccountId}from"./helpers-DPPVplyk.js";import{t as applyPluginAutoEnable}from"./plugin-auto-enable-BV9K9Vhr.js";import"./install-safe-path-ObPl6zIf.js";import"./skill-scanner-DEmbPsRh.js";import{t as buildChannelAccountSnapshot}from"./status-BXI_BTqV.js";import"./channels-status-issues-NLYb8w9i.js";import"./daemon-runtime-B4UjqdyJ.js";import"./runtime-guard-Bi8k55v9.js";import"./systemd-DdVd5Yet.js";import"./service-EKJG69M3.js";import"./lifecycle-core-BpMvDXy1.js";import"./diagnostics-DamNPi4e.js";import{t as parsePort$1}from"./parse-port-FgIKmqqb.js";import{n as addGatewayServiceCommands}from"./daemon-cli-DyVsMf8p.js";import"./table-BFCCZDsp.js";import{n as resolveWideAreaDiscoveryDomain,r as writeWideAreaGatewayZone}from"./widearea-dns-DvQozd9v.js";import{i as toOptionString,n as extractGatewayMiskeys,r as maybeExplainGatewayServiceStop,t as describeUnknownError}from"./shared-rsjJRWla.js";import{c as probeGateway,o as isNodeCommandAllowed,s as resolveNodeCommandAllowlist}from"./audit-DBjjjW93.js";import{t as discoverGatewayBeacons}from"./bonjour-discovery-CViQz7cm.js";import{n as getStatusSummary,r as pickGatewaySelfPresence}from"./status-BxeKmkVr.js";import{c as startHeartbeatRunner,i as styleHealthChannelLine,n as getHealthSnapshot,o as runHeartbeatOnce,s as setHeartbeatsEnabled,t as formatHealthChannelLines}from"./health-DVo8a9yg.js";import{n as createDefaultDeps,r as createOutboundSendDeps$1,t as createOutboundSendDeps}from"./outbound-send-deps-m6DqOma_.js";import{a as resolveControlUiRootSync,i as resolveControlUiRootOverrideSync,t as ensureControlUiAssetsBuilt}from"./control-ui-assets-BxgWcomx.js";import{h as normalizeUpdateChannel,l as DEFAULT_PACKAGE_CHANNEL,n as compareSemverStrings,o as resolveNpmChannelTag,t as checkUpdateStatus}from"./update-check-B0YqSZJr.js";import{t as runOnboardingWizard}from"./onboarding-B9GqKO5L.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-CiD3rrVv.js";import{T as resolveGmailHookRuntimeConfig,_ as buildGogWatchServeArgs,i as ensureTailscaleEndpoint,v as buildGogWatchStartArgs}from"./gmail-setup-utils-CVafFKTa.js";import{a as pruneAgentConfig,i as loadAgentIdentity,r as findAgentEntryIndex,s as loadAgentIdentityFromWorkspace,t as applyAgentConfig}from"./agents.config-D6Yhwmnh.js";import{i as resolveAgentOutboundTarget,r as resolveAgentDeliveryPlan,t as agentCommand}from"./agent-wJmvciTM.js";import"./dm-policy-shared-CRZpjRv0.js";import"./node-service-77UF0ACm.js";import"./status.update-KYyRSDZY.js";import{n as validateSystemRunCommandConsistency,t as formatExecCommand}from"./system-run-command-rlCfXRWt.js";import{t as installSkill}from"./skills-install-DMHQRpIl.js";import{n as runGatewayUpdate,t as resolveAgentSessionDirs}from"./session-dirs-OxQuIvJW.js";import{n as syncBuilderForceAgentsDirectoryOnStartup,t as syncBuilderForceAgentsDirectory}from"./builderforce-directory-sync-DQ6u60yX.js";import{n as mergeBuilderforceContext,t as buildLocalMachineProfile}from"./builderforce-context-CyUg2pSn.js";import{a as emitWorkflowEnd,c as initTelemetry,i as emitTaskStart,l as setRelayHook,o as emitWorkflowStart,r as emitTaskEnd}from"./workflow-telemetry-DLEnm5TI.js";import{n as forceFreePortAndWait}from"./ports-6RmfZEmk.js";import{execFile,spawn,spawnSync}from"node:child_process";import os from"node:os";import path,{dirname,join,relative,sep}from"node:path";import*as fsSync from"node:fs";import fs,{constants}from"node:fs";import{promisify}from"node:util";import chalk from"chalk";import crypto,{createHash,randomUUID}from"node:crypto";import{fileURLToPath,pathToFileURL}from"node:url";import JSON5 from"json5";import{z}from"zod";import fs$1,{mkdir,readFile,readdir,writeFile}from"node:fs/promises";import chokidar from"chokidar";import{WebSocket as WebSocket$1,WebSocketServer}from"ws";import{Buffer as Buffer$1}from"node:buffer";import{Type}from"@sinclair/typebox";import net from"node:net";import{createServer}from"node:http";import{createServer as createServer$1}from"node:https";import{neutralLimbicState}from"@seanhogg/builderforce-memory-engine/limbic";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(`
@@ -183,7 +183,7 @@ Connection: close\r
183
183
  `)}async function runCodingDispatch(deps,dispatchId){let{http,git,agent}=deps,detail;try{detail=await http.fetchDispatchDetail(dispatchId)}catch(err){await http.reportResult(dispatchId,{status:`failed`,error:`fetch detail failed: ${errText(err)}`});return}if(!detail){await http.reportResult(dispatchId,{status:`failed`,error:`Dispatch detail not found`});return}if(!detail.repo){if(detail.workspace&&deps.fs){await runWorkspaceDispatch(deps,dispatchId,detail,detail.workspace,deps.fs);return}let reason=detail.workspace?`this runtime has no filesystem port, so the project workspace could not be used`:`this task's project has neither a connected git repository nor an IDE workspace`,r=await agent.run(`dispatch-${dispatchId}`,buildReasoningPrompt(detail,reason)),note=`\n\nNo files were written: ${reason}.`;await http.reportResult(dispatchId,r.ok?{status:`completed`,output:`${r.summary}${note}`.trim()}:{status:`failed`,error:r.summary});return}let repo=detail.repo,dir=deps.joinPath(deps.workspaceDir,`dispatch-${dispatchId}`),cloneUrl=`${deps.baseUrl.replace(/\/$/,``)}${repo.gitProxyPath}`,branch=`agent/${dispatchId.slice(0,8)}-${codingBranchSlug(detail.input??detail.role)}`,prep=await(deps.repoSync??createGitRepoSync(git)).prepare({dir,repo:{cloneUrl,defaultBranch:repo.defaultBranch},workBranch:branch,mode:`new-branch`});if(!prep.ok){await http.reportResult(dispatchId,{status:`failed`,error:`repo sync failed: ${prep.error}`});return}let agentResult=await agent.run(`dispatch-${dispatchId}`,buildCodingPrompt(detail,dir));if(!agentResult.ok){await http.reportResult(dispatchId,{status:`failed`,error:agentResult.summary||`Agent run failed`});return}let committed;try{committed=await git.commitAll(dir,commitMessage(detail))}catch(err){await http.reportResult(dispatchId,{status:`failed`,error:`commit failed: ${errText(err)}`});return}if(!committed.changed){await http.reportResult(dispatchId,{status:`completed`,output:`${agentResult.summary}\n\nNo file changes were produced; nothing to push.`.trim()});return}try{await git.push(dir,cloneUrl,branch)}catch(err){await http.reportResult(dispatchId,{status:`failed`,error:`push failed: ${errText(err)}`});return}let pr=null;try{pr=await http.openPullRequest(dispatchId,{branch,base:repo.defaultBranch??void 0,title:commitMessage(detail),body:agentResult.summary})}catch{pr=null}let output=pr?`${agentResult.summary}\n\nPushed ${branch} and opened PR #${pr.number}: ${pr.url}`.trim():`${agentResult.summary}\n\nPushed ${branch} (no PR opened — open one manually).`.trim();await http.reportResult(dispatchId,{status:`completed`,output})}function buildReasoningPrompt(detail,reason){return[`You are the "${detail.role}" agent. Complete the following task and return your result.`,...reason?[``,`NOTE: you have no writable working tree for this task (${reason}). You cannot`,`create files. Return the complete deliverable inline in your answer instead.`]:[],``,(detail.input??``).trim()||`No task description was provided.`].join(`
184
184
  `)}function buildWorkspacePrompt(detail,workspace,dir){return[`You are the "${detail.role}" coding agent. The project "${workspace.projectName}" is`,`checked out at:`,` ${dir}`,`This is the project's live IDE workspace. It is NOT a git repository: implement the`,`task by editing/creating files in that directory and nothing else. Do not run git.`,`Every file you leave behind is saved back to the project workspace when you finish,`,`so it opens in the IDE and runs in the preview.`,``,`TASK:`,(detail.input??``).trim()||`No task description was provided.`].join(`
185
185
  `)}async function runWorkspaceDispatch(deps,dispatchId,detail,workspace,fs){let{http,agent}=deps,dir=deps.joinPath(deps.workspaceDir,`dispatch-${dispatchId}`),tree=await http.fetchWorkspaceFiles(workspace.filesPath).catch(()=>null);if(!tree){await http.reportResult(dispatchId,{status:`failed`,error:`workspace fetch failed for project ${workspace.projectId}`});return}try{await fs.materialize(dir,tree.files)}catch(err){await http.reportResult(dispatchId,{status:`failed`,error:`workspace materialize failed: ${errText(err)}`});return}let before=new Map(tree.files.map(f=>[f.path,f.content])),agentResult=await agent.run(`dispatch-${dispatchId}`,buildWorkspacePrompt(detail,workspace,dir));if(!agentResult.ok){await http.reportResult(dispatchId,{status:`failed`,error:agentResult.summary||`Agent run failed`});return}let after;try{after=await fs.snapshot(dir)}catch(err){await http.reportResult(dispatchId,{status:`failed`,error:`workspace snapshot failed: ${errText(err)}`});return}let changes=diffWorkspace(before,after,tree.truncated);if(changes.writes.length===0&&changes.deletes.length===0){await http.reportResult(dispatchId,{status:`completed`,output:`${agentResult.summary}\n\nNo file changes were produced; nothing to save.`.trim()});return}let pushed=await http.pushWorkspaceChanges(workspace.filesPath,{taskId:detail.taskId,agent:detail.role,writes:changes.writes,deletes:changes.deletes}).catch(()=>null);if(!pushed){await http.reportResult(dispatchId,{status:`failed`,error:`workspace save failed for project ${workspace.projectId}`});return}let rejected=pushed.rejected.length?`\n\n${pushed.rejected.length} file(s) were rejected: ${pushed.rejected.map(r=>`${r.path} (${r.reason})`).join(`; `)}`:``,removed=pushed.deleted?` and removed ${pushed.deleted}`:``;await http.reportResult(dispatchId,{status:`completed`,output:`${agentResult.summary}\n\nSaved ${pushed.written} file(s)${removed} to the "${workspace.projectName}" workspace (no git repo is connected, so no branch `+`or PR was created).${rejected}`.trim()})}function diffWorkspace(before,after,truncated){let writes=[],seen=new Set;for(let file of after)seen.add(file.path),before.get(file.path)!==file.content&&writes.push(file);return{writes,deletes:truncated?[]:[...before.keys()].filter(p=>!seen.has(p))}}function commitMessage(detail){let first=(detail.input??``).trim().split(`
186
- `)[0]?.slice(0,72);return first?`feat: ${first}`:`chore: agent changes for ${detail.role}`}function errText(err){return err instanceof Error?err.message:String(err)}var RelayHeartbeat=class{constructor(opts){this.opts=opts,this.timer=null}schedule(){this.clear(),this.sendOnce(),this.timer=setInterval(()=>void this.sendOnce(),24e4)}clear(){this.timer!==null&&(clearInterval(this.timer),this.timer=null)}async sendOnce(){try{let machineProfile=buildLocalMachineProfile({workspaceDirectory:this.opts.workspaceDir,rootInstallDirectory:process.cwd(),gatewayPort:18789,tunnelUrl:process.env.BUILDERFORCE_AGENTS_PUBLIC_TUNNEL_URL,tunnelStatus:process.env.BUILDERFORCE_AGENTS_PUBLIC_TUNNEL_URL?`connected`:`none`});await fetch(this.opts.heartbeatUrl,{method:`PATCH`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${this.opts.apiKey}`},body:JSON.stringify({capabilities:[`chat`,`tasks`,`relay`,`remote-dispatch`],machineProfile}),signal:AbortSignal.timeout(1e4)})}catch(err){logDebug(`[builderforce-relay] heartbeat failed: ${String(err)}`)}}},RelayLogPoller=class{constructor(getClient,send,getExecutionId=()=>null){this.getClient=getClient,this.send=send,this.getExecutionId=getExecutionId,this.timer=null}start(resetCursor=!1){resetCursor&&(this.cursor=void 0),this.timer===null&&(this.pollOnce(),this.timer=setInterval(()=>void this.pollOnce(),2e3))}clear(){this.timer!==null&&(clearInterval(this.timer),this.timer=null)}mapLine(line){let fallback={ts:new Date().toISOString(),level:`info`,message:line};try{let parsed=JSON.parse(line),level=typeof parsed?._meta?.logLevelName==`string`?parsed._meta.logLevelName.toLowerCase():`info`,message=typeof parsed?.[1]==`string`?parsed[1]:typeof parsed?.message==`string`?parsed.message:typeof parsed?.[0]==`string`?parsed[0]:line;return{ts:typeof parsed?.time==`string`?parsed.time:fallback.ts,level,message}}catch{return fallback}}async pollOnce(){let client=this.getClient();if(client)try{let res=await client.request(`logs.tail`,{cursor:this.cursor,limit:500,maxBytes:25e4});typeof res.cursor==`number`&&Number.isFinite(res.cursor)&&(this.cursor=res.cursor);let lines=Array.isArray(res.lines)?res.lines.filter(line=>typeof line==`string`):[],executionId=this.getExecutionId();for(let line of lines){let mapped=this.mapLine(line);this.send({type:`log`,level:mapped.level,message:mapped.message,ts:mapped.ts,...executionId==null?{}:{executionId}})}}catch(err){logDebug(`[builderforce-relay] logs.tail failed: ${String(err)}`)}}},RelayPresencePoller=class{constructor(getClient,send){this.getClient=getClient,this.send=send,this.timer=null}start(){this.timer===null&&(this.pollOnce(),this.timer=setInterval(()=>void this.pollOnce(),5e3))}clear(){this.timer!==null&&(clearInterval(this.timer),this.timer=null)}async pollOnce(){let client=this.getClient();if(client)try{let res=await client.request(`system-presence`,{}),entries=Array.isArray(res)?res:[];this.send({type:`presence.snapshot`,entries})}catch(err){logDebug(`[builderforce-relay] system-presence failed: ${String(err)}`)}}};function normalizeSteeringText(text){return(typeof text==`string`?text.trim():``)||null}function buildSteeringMessage(text){return{type:`user`,message:{role:`user`,content:text},parent_tool_use_id:null}}function createSteeringChannel(){let queue=[],isClosed=!1,wake=null,notify=()=>{let w=wake;wake=null,w?.()};return{push(text){let normalized=normalizeSteeringText(text);return!normalized||isClosed?!1:(queue.push(normalized),notify(),!0)},pending:()=>queue.length,closed:()=>isClosed,close(){isClosed||(isClosed=!0,notify())},async*messages(initial,onApplied){for(yield buildSteeringMessage(initial);;){if(queue.length){let text=queue.shift();onApplied?.(text),yield buildSteeringMessage(text);continue}if(isClosed)return;await new Promise(resolve=>{wake=resolve})}}}}function lateSteerFromFrame(msg){let text=normalizeSteeringText(msg.text);if(!text)return null;let messageId=typeof msg.messageId==`number`&&Number.isSafeInteger(msg.messageId)&&msg.messageId>0?msg.messageId:void 0;return messageId==null?{text}:{messageId,text}}function createLateSteerRegistry(){let held=new Map;return{open(executionId){held.has(executionId)||held.set(executionId,[])},hold(executionId,steer){let list=held.get(executionId);return list?(list.push(steer),!0):!1},drain(executionId){let list=held.get(executionId)??[];return held.delete(executionId),list}}}function buildLateSteerReport(executionId,reason,steers){return{executionId,reason,steers:[...steers]}}function num(v){return typeof v==`number`&&Number.isFinite(v)?v:0}function mapSdkMessage(msg){if(!msg||typeof msg!=`object`)return[];let m=msg;switch(typeof m.type==`string`?m.type:``){case`assistant`:{let message=m.message,blocks=Array.isArray(message?.content)?message.content:[],out=[];for(let b of blocks)b?.type===`text`&&typeof b.text==`string`&&b.text.length>0?out.push({kind:`assistant_text`,text:b.text}):b?.type===`tool_use`&&out.push({kind:`tool_use`,toolName:typeof b.name==`string`?b.name:`unknown`,toolUseId:typeof b.id==`string`?b.id:``,args:b.input??{}});return out}case`result`:{let usage=m.usage??{};return[{kind:`result`,ok:!(m.subtype===`error`||m.is_error===!0),text:typeof m.result==`string`?m.result:``,inputTokens:num(usage.input_tokens),outputTokens:num(usage.output_tokens)}]}case`system`:return[{kind:`system`,subtype:typeof m.subtype==`string`?m.subtype:``}];default:return[]}}const SDK_MEMORY_SERVER=`builderforce_memory`,SDK_MEMORY_TOOLS=`mcp__${SDK_MEMORY_SERVER}__*`;function ssmMemoryBackend(mod,svc){class SsmMemoryBackend extends mod.MemoryStoreBackend{async remember(input){if(input.ttlMs)return super.remember(input);await svc.commitFact(input.key,input.content,{tags:input.tags,importance:input.importance})}}return new SsmMemoryBackend(svc.memory,svc.runtime)}async function buildSdkMemoryServer(){let svc=getSsmMemoryService();if(!svc)return null;try{let mod=await import(`./dist-oLWoUqeb.js`);return await mod.createMemoryMcpServer(ssmMemoryBackend(mod,svc),{name:SDK_MEMORY_SERVER})}catch(err){return logDebug(`[v2-runner] memory tools unavailable: ${String(err)}`),null}}const SDK_TOOLS=[`Read`,`Write`,`Edit`,`Bash`,`Glob`,`Grep`,`Task`];function allowedToolsAfterGates(gates,extraTools=[]){let blocked=(gates??[]).filter(g=>g.effect===`block`&&!(g.paths&&g.paths.length));if(blocked.some(g=>!g.tool||g.tool===`*`))return[];let blockedNames=new Set(blocked.map(g=>(g.tool??``).toLowerCase()));return[...SDK_TOOLS,...extraTools].filter(t=>!blockedNames.has(t.toLowerCase()))}function buildGatewayHeaders(params){let parts=[`x-builderforce-surface: ${params.surface?.trim()||`on_prem`}`];return params.executionId!=null&&Number.isFinite(params.executionId)&&parts.push(`x-builderforce-execution-id: ${params.executionId}`),parts.join(`, `)}async function runClaudeAgentSdkV2(params,sinks){let finalText=``,ok=!0,sawResult=!1,preamble=[renderPolicyDirectives(params.policyGates),params.appendSystemPrompt?.trim()].filter(Boolean).join(`
186
+ `)[0]?.slice(0,72);return first?`feat: ${first}`:`chore: agent changes for ${detail.role}`}function errText(err){return err instanceof Error?err.message:String(err)}var RelayHeartbeat=class{constructor(opts){this.opts=opts,this.timer=null}schedule(){this.clear(),this.sendOnce(),this.timer=setInterval(()=>void this.sendOnce(),24e4)}clear(){this.timer!==null&&(clearInterval(this.timer),this.timer=null)}async sendOnce(){try{let machineProfile=buildLocalMachineProfile({workspaceDirectory:this.opts.workspaceDir,rootInstallDirectory:process.cwd(),gatewayPort:18789,tunnelUrl:process.env.BUILDERFORCE_AGENTS_PUBLIC_TUNNEL_URL,tunnelStatus:process.env.BUILDERFORCE_AGENTS_PUBLIC_TUNNEL_URL?`connected`:`none`});await fetch(this.opts.heartbeatUrl,{method:`PATCH`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${this.opts.apiKey}`},body:JSON.stringify({capabilities:[`chat`,`tasks`,`relay`,`remote-dispatch`],machineProfile}),signal:AbortSignal.timeout(1e4)})}catch(err){logDebug(`[builderforce-relay] heartbeat failed: ${String(err)}`)}}},RelayLogPoller=class{constructor(getClient,send,getExecutionId=()=>null){this.getClient=getClient,this.send=send,this.getExecutionId=getExecutionId,this.timer=null}start(resetCursor=!1){resetCursor&&(this.cursor=void 0),this.timer===null&&(this.pollOnce(),this.timer=setInterval(()=>void this.pollOnce(),2e3))}clear(){this.timer!==null&&(clearInterval(this.timer),this.timer=null)}mapLine(line){let fallback={ts:new Date().toISOString(),level:`info`,message:line};try{let parsed=JSON.parse(line),level=typeof parsed?._meta?.logLevelName==`string`?parsed._meta.logLevelName.toLowerCase():`info`,message=typeof parsed?.[1]==`string`?parsed[1]:typeof parsed?.message==`string`?parsed.message:typeof parsed?.[0]==`string`?parsed[0]:line;return{ts:typeof parsed?.time==`string`?parsed.time:fallback.ts,level,message}}catch{return fallback}}async pollOnce(){let client=this.getClient();if(client)try{let res=await client.request(`logs.tail`,{cursor:this.cursor,limit:500,maxBytes:25e4});typeof res.cursor==`number`&&Number.isFinite(res.cursor)&&(this.cursor=res.cursor);let lines=Array.isArray(res.lines)?res.lines.filter(line=>typeof line==`string`):[],executionId=this.getExecutionId();for(let line of lines){let mapped=this.mapLine(line);this.send({type:`log`,level:mapped.level,message:mapped.message,ts:mapped.ts,...executionId==null?{}:{executionId}})}}catch(err){logDebug(`[builderforce-relay] logs.tail failed: ${String(err)}`)}}},RelayPresencePoller=class{constructor(getClient,send){this.getClient=getClient,this.send=send,this.timer=null}start(){this.timer===null&&(this.pollOnce(),this.timer=setInterval(()=>void this.pollOnce(),5e3))}clear(){this.timer!==null&&(clearInterval(this.timer),this.timer=null)}async pollOnce(){let client=this.getClient();if(client)try{let res=await client.request(`system-presence`,{}),entries=Array.isArray(res)?res:[];this.send({type:`presence.snapshot`,entries})}catch(err){logDebug(`[builderforce-relay] system-presence failed: ${String(err)}`)}}};function normalizeSteeringText(text){return(typeof text==`string`?text.trim():``)||null}function buildSteeringMessage(text){return{type:`user`,message:{role:`user`,content:text},parent_tool_use_id:null}}function createSteeringChannel(){let queue=[],isClosed=!1,wake=null,notify=()=>{let w=wake;wake=null,w?.()};return{push(text){let normalized=normalizeSteeringText(text);return!normalized||isClosed?!1:(queue.push(normalized),notify(),!0)},pending:()=>queue.length,closed:()=>isClosed,close(){isClosed||(isClosed=!0,notify())},async*messages(initial,onApplied){for(yield buildSteeringMessage(initial);;){if(queue.length){let text=queue.shift();onApplied?.(text),yield buildSteeringMessage(text);continue}if(isClosed)return;await new Promise(resolve=>{wake=resolve})}}}}function lateSteerFromFrame(msg){let text=normalizeSteeringText(msg.text);if(!text)return null;let messageId=typeof msg.messageId==`number`&&Number.isSafeInteger(msg.messageId)&&msg.messageId>0?msg.messageId:void 0;return messageId==null?{text}:{messageId,text}}function createLateSteerRegistry(){let held=new Map;return{open(executionId){held.has(executionId)||held.set(executionId,[])},hold(executionId,steer){let list=held.get(executionId);return list?(list.push(steer),!0):!1},drain(executionId){let list=held.get(executionId)??[];return held.delete(executionId),list}}}function buildLateSteerReport(executionId,reason,steers){return{executionId,reason,steers:[...steers]}}let fallbackCounter=0;function defaultId(){let c=globalThis.crypto;return c?.randomUUID?c.randomUUID():(fallbackCounter+=1,`ob-${Date.now().toString(36)}-${fallbackCounter.toString(36)}-${Math.random().toString(36).slice(2,10)}`)}function batchIdempotencyKey(batch){let head=batch[0];return head?head.batch??head.id:void 0}function isPermanentHttpFailure(error){let status=error?.status;return typeof status==`number`?status>=400&&status<500&&![401,408,409,425,429].includes(status):!1}const bySeq=(a,b)=>a.seq-b.seq;function sendable(e,scope){return scope===void 0||e.scope===void 0||e.scope===scope}function takeBatch(l,scope,upTo,maxItems){let due=e=>e.seq<=upTo&&sendable(e,scope),start=l.entries.findIndex(due);if(start<0)return null;let head=l.entries[start],n=0,at=i=>l.entries[start+i];if(head.batch)for(;at(n)&&at(n).batch===head.batch;)n+=1;else for(;at(n)&&n<maxItems&&!at(n).batch&&due(at(n));)n+=1;let batch=l.entries.splice(start,n),sealed=!head.batch;if(sealed)for(let e of batch)e.batch=head.id,scope!==void 0&&(e.scope=scope);return{batch,sealed}}function sendContext(batch){let head=batch[0];return{idempotencyKey:batchIdempotencyKey(batch),ids:batch.map(e=>e.id),...head.scope===void 0?{}:{scope:head.scope}}}function drainContext(taken,scope,newId){return{idempotencyKey:batchIdempotencyKey(taken)??newId(),ids:taken.map(e=>e.id),...scope?{scope}:{}}}function createOutbox(opts){let maxItems=Math.max(1,opts.maxItems??25),maxWaitMs=opts.maxWaitMs??5e3,retry=opts.retry?{baseMs:opts.retry.baseMs??1e3,maxMs:opts.retry.maxMs??3e5,isPermanent:opts.retry.isPermanent??isPermanentHttpFailure}:null,store=opts.store??null,maxEntries=Math.max(maxItems,opts.maxEntries??(retry||store?1e3:1/0)),newId=opts.newId??defaultId,lanes=new Map,lastSeq=0,dropped=0,closed=!1,isOnline=()=>opts.online?.isOnline()??!0,lane=key=>{let l=lanes.get(key);return l||(l={entries:[],timer:null,retryTimer:null,attempt:0,inFlight:0,tail:Promise.resolve()},lanes.set(key,l)),l},nextSeq=()=>(lastSeq=Math.max(lastSeq+1,Date.now()*1e3),lastSeq),loaded=store?Promise.resolve().then(()=>store.load()).then(entries=>{for(let e of entries)lane(e.key).entries.push(e),lastSeq=Math.max(lastSeq,e.seq);for(let l of lanes.values())l.entries.sort(bySeq)},error=>opts.onStoreError?.(error)):Promise.resolve(),writes=loaded,persist=op=>{store&&(writes=writes.then(()=>op(store)).catch(error=>opts.onStoreError?.(error)))},drop=(key,entries,reason)=>{if(entries.length===0)return;dropped+=entries.length;let ids=entries.map(e=>e.id);persist(s=>s.remove(ids)),opts.onDrop?.({key,count:entries.length,reason})},enforceBound=()=>{let total=0;for(let l of lanes.values())total+=l.entries.length;for(;total>maxEntries;){let oldestKey,oldest;for(let[k,l]of lanes){let head=l.entries[0];head&&(!oldest||head.seq<oldest.entries[0].seq)&&(oldest=l,oldestKey=k)}if(!oldest)return;drop(oldestKey,oldest.entries.splice(0,1),`overflow`),--total}},currentScope=()=>opts.scope?opts.scope():void 0,take=(l,scope,upTo)=>{let next=takeBatch(l,scope,upTo,maxItems);return next?(next.sealed&&persist(s=>s.put(next.batch)),next.batch):null},clearTimer=l=>{l.timer!==null&&clearTimeout(l.timer),l.timer=null},clearRetry=l=>{l.retryTimer!==null&&clearTimeout(l.retryTimer),l.retryTimer=null},scheduleRetry=(key,l)=>{if(!retry||closed||l.retryTimer!==null)return;l.attempt+=1;let delay=Math.min(retry.maxMs,retry.baseMs*2**(l.attempt-1)),jittered=Math.round(delay*(.8+Math.random()*.4));l.retryTimer=setTimeout(()=>{l.retryTimer=null,flushKey(key,{final:!1,probe:!0})},jittered)},armTimer=(key,l)=>{l.timer!==null||maxWaitMs<=0||(l.timer=setTimeout(()=>{l.timer=null,flushKey(key,{final:!1,auto:!0})},maxWaitMs))},requeue=(l,entries)=>{l.entries.unshift(...entries),l.entries.sort(bySeq)},sendBatch=async(key,l,batch,final)=>{let items=batch.map(e=>e.item),ctx=sendContext(batch),ids=ctx.ids;l.inFlight+=batch.length;try{return await opts.send(key,opts.coalesce?opts.coalesce(items):items,{final,...ctx}),l.inFlight-=batch.length,l.attempt=0,persist(s=>s.remove(ids)),!0}catch(error){return l.inFlight-=batch.length,opts.onError?.(error,key),retry&&!retry.isPermanent(error)?(requeue(l,batch),scheduleRetry(key,l),!1):(drop(key,batch,retry?`rejected`:`failed`),!0)}},flushKey=(key,mode)=>{let l=lanes.get(key);if(!l)return Promise.resolve();let upTo=mode.probe?1/0:lastSeq;if(mode.final){let scope=currentScope();if(!isOnline()||scope===null)return Promise.resolve();clearTimer(l);let batches=[];for(let b=take(l,scope,upTo);b;b=take(l,scope,upTo))batches.push(b);return Promise.all(batches.map(b=>sendBatch(key,l,b,!0))).then(()=>void 0)}let run=l.tail.then(async()=>{if(await loaded,mode.auto&&l.retryTimer!==null)return;if(mode.auto&&!isOnline()){scheduleRetry(key,l);return}!mode.auto&&l.retryTimer!==null&&clearRetry(l);let scope=currentScope();if(scope===null){scheduleRetry(key,l);return}clearTimer(l);for(let batch=take(l,scope,upTo);batch;batch=take(l,scope,upTo))if(!await sendBatch(key,l,batch,!1))return;l.entries.length>0&&armTimer(key,l)});return l.tail=run,run},flushAll=final=>Promise.all([...lanes.keys()].map(k=>flushKey(k,{final}))).then(()=>void 0),unsubscribe=opts.online?.subscribe(online=>{if(!(!online||closed)){for(let l of lanes.values())clearRetry(l),l.attempt=0;flushAll(!1)}});return store&&loaded.then(()=>{enforceBound();for(let[k,l]of lanes)l.entries.length>0&&flushKey(k,{final:!1,auto:!0})}),{enqueue(key,item){let l=lane(key),scope=currentScope(),entry={id:newId(),key,item,seq:nextSeq(),...scope?{scope}:{}};return l.entries.push(entry),persist(s=>s.put([entry])),enforceBound(),l.entries.reduce((n,e)=>e.batch?n:n+1,0)>=maxItems?flushKey(key,{final:!1,auto:!0}):armTimer(key,l),entry.id},async flush(key,flushOpts){let final=flushOpts?.final??!1;return key===void 0?flushAll(final):flushKey(key,{final})},drainWith(key,request){let l=lane(key),run=l.tail.then(async()=>{await loaded,clearTimer(l);let scope=currentScope(),taken=[];if(scope!==null){let parked=[];for(let e of l.entries)(sendable(e,scope)?taken:parked).push(e);l.entries=parked}let items=taken.map(e=>e.item),ctx=drainContext(taken,scope,newId),ids=ctx.ids;l.inFlight+=taken.length;try{let result=await request(opts.coalesce&&items.length?opts.coalesce(items):items,ctx);return l.inFlight-=taken.length,taken.length&&persist(s=>s.remove(ids)),result}catch(error){throw l.inFlight-=taken.length,retry?requeue(l,taken):drop(key,taken,`failed`),error}});return l.tail=run.catch(()=>void 0),run},size(key){if(key!==void 0)return lanes.get(key)?.entries.length??0;let n=0;for(let l of lanes.values())n+=l.entries.length;return n},stats(){let queued=0,inFlight=0;for(let l of lanes.values())queued+=l.entries.length,inFlight+=l.inFlight;return{queued,inFlight,dropped}},ready:()=>loaded.then(()=>writes),close(){closed=!0,unsubscribe?.();for(let l of lanes.values())clearTimer(l),clearRetry(l)}}}function toWire(event){return{executionId:event.executionId,runId:event.executionId==null?void 0:`exec-${event.executionId}`,sessionKey:`main`,toolCallId:event.toolCallId,toolName:event.toolName,category:event.category,args:event.args,result:event.result,ts:new Date().toISOString()}}function createToolAuditPersister(opts){let doFetch=opts.fetchImpl??fetch,post=body=>doFetch(opts.url,{method:`POST`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${opts.apiKey}`},body:JSON.stringify(body),signal:AbortSignal.timeout(1e4)}),outbox=createOutbox({maxItems:25,maxWaitMs:1500,maxEntries:500,send:async(_key,items)=>{if(items.length===1){await post(items[0]);return}if((await post({events:items})).status===400)for(let item of items)await post(item)},onError:error=>opts.onError(error),onDrop:drop=>{drop.reason!==`failed`&&opts.onError(Error(`tool-audit queue dropped ${drop.count} event(s) (${drop.reason})`))}});return{emit:event=>{let wire=toWire(event);opts.sendLive?.({type:`tool.audit`,...wire})||outbox.enqueue(`tool-audit`,wire)},persist:event=>{outbox.enqueue(`tool-audit`,toWire(event))},flush:flushOpts=>outbox.flush(void 0,flushOpts),close:()=>outbox.close()}}function coalesceRemoteChunks(items){let out=[];for(let item of items){let last=out[out.length-1];last&&last.correlationId===item.correlationId&&last.callbackAgentNodeId===item.callbackAgentNodeId?last.piece+=item.piece:out.push({...item})}return out}function createRemoteChunkQueue(dispatch,onError){return createOutbox({maxItems:1e4,maxWaitMs:250,coalesce:coalesceRemoteChunks,send:async(_session,chunks)=>{for(let chunk of chunks)await dispatch(chunk)},onError:error=>onError(error)})}function num(v){return typeof v==`number`&&Number.isFinite(v)?v:0}function mapSdkMessage(msg){if(!msg||typeof msg!=`object`)return[];let m=msg;switch(typeof m.type==`string`?m.type:``){case`assistant`:{let message=m.message,blocks=Array.isArray(message?.content)?message.content:[],out=[];for(let b of blocks)b?.type===`text`&&typeof b.text==`string`&&b.text.length>0?out.push({kind:`assistant_text`,text:b.text}):b?.type===`tool_use`&&out.push({kind:`tool_use`,toolName:typeof b.name==`string`?b.name:`unknown`,toolUseId:typeof b.id==`string`?b.id:``,args:b.input??{}});return out}case`result`:{let usage=m.usage??{};return[{kind:`result`,ok:!(m.subtype===`error`||m.is_error===!0),text:typeof m.result==`string`?m.result:``,inputTokens:num(usage.input_tokens),outputTokens:num(usage.output_tokens)}]}case`system`:return[{kind:`system`,subtype:typeof m.subtype==`string`?m.subtype:``}];default:return[]}}const SDK_MEMORY_SERVER=`builderforce_memory`,SDK_MEMORY_TOOLS=`mcp__${SDK_MEMORY_SERVER}__*`;function ssmMemoryBackend(mod,svc){class SsmMemoryBackend extends mod.MemoryStoreBackend{async remember(input){if(input.ttlMs)return super.remember(input);await svc.commitFact(input.key,input.content,{tags:input.tags,importance:input.importance})}}return new SsmMemoryBackend(svc.memory,svc.runtime)}async function buildSdkMemoryServer(){let svc=getSsmMemoryService();if(!svc)return null;try{let mod=await import(`./dist-oLWoUqeb.js`);return await mod.createMemoryMcpServer(ssmMemoryBackend(mod,svc),{name:SDK_MEMORY_SERVER})}catch(err){return logDebug(`[v2-runner] memory tools unavailable: ${String(err)}`),null}}const SDK_TOOLS=[`Read`,`Write`,`Edit`,`Bash`,`Glob`,`Grep`,`Task`];function allowedToolsAfterGates(gates,extraTools=[]){let blocked=(gates??[]).filter(g=>g.effect===`block`&&!(g.paths&&g.paths.length));if(blocked.some(g=>!g.tool||g.tool===`*`))return[];let blockedNames=new Set(blocked.map(g=>(g.tool??``).toLowerCase()));return[...SDK_TOOLS,...extraTools].filter(t=>!blockedNames.has(t.toLowerCase()))}function buildGatewayHeaders(params){let parts=[`x-builderforce-surface: ${params.surface?.trim()||`on_prem`}`];return params.executionId!=null&&Number.isFinite(params.executionId)&&parts.push(`x-builderforce-execution-id: ${params.executionId}`),parts.join(`, `)}async function runClaudeAgentSdkV2(params,sinks){let finalText=``,ok=!0,sawResult=!1,preamble=[renderPolicyDirectives(params.policyGates),params.appendSystemPrompt?.trim()].filter(Boolean).join(`
187
187
 
188
188
  `),steering=params.steering??createSteeringChannel(),memory=await buildSdkMemoryServer(),initialPrompt=preamble?`${preamble}
189
189
 
@@ -192,7 +192,7 @@ Connection: close\r
192
192
  ${params.prompt}`:params.prompt;try{let stream=query({prompt:steering.messages(initialPrompt,text=>sinks.onSteerApplied?.(text)),options:{...params.model?{model:params.model}:{},cwd:params.cwd,...params.policyGates?.length?{permissionMode:`default`,canUseTool:async(toolName,input)=>canUseToolDecision(params.policyGates,toolName,input)}:{permissionMode:`bypassPermissions`},allowedTools:allowedToolsAfterGates(params.policyGates,memory?[SDK_MEMORY_TOOLS]:[]),...memory?{mcpServers:{[SDK_MEMORY_SERVER]:memory}}:{},...params.abortController?{abortController:params.abortController}:{},env:{...process.env,ANTHROPIC_BASE_URL:params.anthropicBaseUrl,ANTHROPIC_API_KEY:params.gatewayAuthKey,ANTHROPIC_CUSTOM_HEADERS:buildGatewayHeaders(params)},stderr:data=>logDebug(`[v2-runner] ${data}`)}});for await(let msg of stream)for(let ev of mapSdkMessage(msg))ev.kind===`assistant_text`?sinks.onAssistantText(ev.text):ev.kind===`tool_use`?sinks.onToolUse(ev.toolName,ev.toolUseId,ev.args):ev.kind===`result`&&(sawResult=!0,ok=ev.ok,finalText=ev.text,sinks.onResult(ev.ok,ev.text,{inputTokens:ev.inputTokens,outputTokens:ev.outputTokens}),steering.pending()===0&&steering.close());sawResult||(ok=!1,finalText||=`(agent ended without a result)`,sinks.onResult(!1,finalText,{inputTokens:0,outputTokens:0}))}catch(err){ok=!1,finalText=err instanceof Error?err.message:String(err),logWarn(`[v2-runner] failed: ${finalText}`),sinks.onResult(!1,finalText,{inputTokens:0,outputTokens:0})}finally{steering.close()}return{ok,text:finalText}}var ClaudeSdkAgentEngine=class{constructor(deps){this.deps=deps,this.id=CURRENT_ENGINE_ID}async run(input){let r=await runClaudeAgentSdkV2({prompt:input.userContent,model:input.model,cwd:this.deps.cwd,anthropicBaseUrl:this.deps.anthropicBaseUrl,gatewayAuthKey:this.deps.gatewayAuthKey,appendSystemPrompt:input.systemPrompt,...input.policy?.gates?{policyGates:[...input.policy.gates]}:{},...this.deps.surface?{surface:this.deps.surface}:{},...this.deps.executionId==null?{}:{executionId:this.deps.executionId},abortController:this.deps.abortController,...this.deps.steering?{steering:this.deps.steering}:{}},this.deps.sinks);return{ok:r.ok,output:r.text,cancelled:this.deps.abortController.signal.aborted,finished:!0}}};const pExecFile=promisify(execFile);function taskWorkspaceDir(baseDir,taskId){return path.join(baseDir,`.builderforce`,`tasks`,String(taskId))}function buildTaskCloneUrl(baseUrl,agentNodeId,repoId){return`${baseUrl.replace(/\/+$/,``)}/api/agent-hosts/${agentNodeId}/git-proxy/${repoId}`}function taskBranchName(taskId){return`builderforce/task-${taskId}`}function parseGitPorcelain(porcelain,agent){let out=[];for(let raw of porcelain.split(`
193
193
  `)){if(raw.length<4)continue;let x=raw[0],y=raw[1],pathPart=raw.slice(3),arrow=pathPart.indexOf(` -> `);arrow>=0&&(pathPart=pathPart.slice(arrow+4));let filePath=pathPart.trim().replace(/^"|"$/g,``);if(!filePath)continue;let change;change=x===`?`||x===`A`?`created`:x===`D`||y===`D`?`deleted`:`modified`,out.push({path:filePath,change,agent})}return out}async function detectTaskChanges(dir,agent){try{let{stdout}=await pExecFile(`git`,[`-C`,dir,`status`,`--porcelain`],{maxBuffer:8*1024*1024});return parseGitPorcelain(stdout,agent)}catch{return[]}}async function removeTaskWorkspace(baseDir,taskId){return removeWorkspaceDir(taskWorkspaceDir(baseDir,taskId))}async function removeWorkspaceDir(dir){try{return await fs$1.rm(dir,{recursive:!0,force:!0}),!0}catch{return!1}}const TASK_TERMINAL_STATES=[`done`,`failed`,`cancelled`,`aborted`];function releasesTaskWorkspace(state){return TASK_TERMINAL_STATES.includes(state)}async function releaseTaskWorkspaceOnTerminal(args){if(!releasesTaskWorkspace(args.state))return{released:!1,preserved:!1};let preserved=!1;try{args.preserve&&(await args.preserve(),preserved=!0)}catch{}return{released:await removeTaskWorkspace(args.baseDir,args.taskId),preserved}}async function sweepStaleTaskWorkspaces(baseDir,opts){let maxAgeMs=opts?.maxAgeMs??864e5,nowMs=opts?.nowMs??Date.now(),active=new Set([...opts?.activeTaskIds??[]].map(String)),tasksRoot=path.join(baseDir,`.builderforce`,`tasks`),removed=[],entries;try{entries=await fs$1.readdir(tasksRoot)}catch{return{removed}}for(let entry of entries){if(active.has(entry))continue;let dir=path.join(tasksRoot,entry);try{let stat=await fs$1.stat(dir);if(!stat.isDirectory()||nowMs-stat.mtimeMs<maxAgeMs||!await removeWorkspaceDir(dir))continue;removed.push(dir)}catch{}}return{removed}}async function isCloned(dir){try{return await pExecFile(`git`,[`-C`,dir,`rev-parse`,`--is-inside-work-tree`]),!0}catch{return!1}}function extractChatText(message){if(!message||typeof message!=`object`)return``;let msg=message;if(typeof msg.text==`string`)return msg.text;if(!Array.isArray(msg.content))return``;let parts=[];for(let block of msg.content){if(!block||typeof block!=`object`)continue;let text=block.text;typeof text==`string`&&text.trim().length>0&&parts.push(text)}return parts.join(`
194
194
  `).trim()}function extractChatRole(message){return!message||typeof message!=`object`?`assistant`:message.role===`user`?`user`:`assistant`}var BuilderforceRelayService=class{resolveEngine(engineId){let current={id:CURRENT_ENGINE_ID,run:(d,p)=>this.runV2Engine(d,p)};return resolveEngineById({[current.id]:current},engineId)}dispatchTaskFromRelay(payload){let message=[`[Builderforce ${payload.sourceType}] ${payload.title}`,payload.description?``:void 0,payload.description,payload.executionId==null?void 0:``,payload.executionId==null?void 0:`Execution ID: ${payload.executionId}`,payload.taskId==null?void 0:`Task ID: ${payload.taskId}`].filter(line=>typeof line==`string`).join(`
195
- `).trim();if(!message)return;payload.executionId!=null&&(this.pendingExecutionId=payload.executionId,this.reportExecutionState(payload.executionId,`running`));let engine=this.resolveEngine(payload.engine),runEngine=()=>{engine.run(payload,message)};payload.artifacts?this.syncAssignedCapabilities(payload.artifacts,payload.executionId,payload.taskId).finally(runEngine):runEngine()}async syncAssignedCapabilities(artifacts,executionId,taskId){try{await this.gatewayClient?.request(`artifacts.sync`,{artifacts,executionId,taskId})}catch(err){logWarn(`[builderforce] artifacts.sync failed: ${String(err)}`)}let skills=artifacts.skills??[],personas=artifacts.personas??[],content=artifacts.content??[];if(!(skills.length||personas.length||content.length))return;let summary={skills,personas,content};this.sendToRelay({type:`tool.audit`,sessionKey:`main`,toolName:`capabilities.load`,category:`context`,args:summary,ts:new Date().toISOString()}),this.persistToolAudit({executionId,toolName:`capabilities.load`,category:`context`,args:summary}),logWarn(`[builderforce] capabilities.load: ${personas.length} persona(s), ${skills.length} skill(s), ${content.length} content`)}async ensureTaskWorkspace(taskId,repo){let baseDir=this.opts.workspaceDir??process.cwd(),cwd=taskId==null?baseDir:taskWorkspaceDir(baseDir,taskId);if(await fs$1.mkdir(cwd,{recursive:!0}).catch(()=>{}),repo?.repoId&&taskId!=null){let repoSync=createGitRepoSync(makeCodingGit({apiKey:this.opts.apiKey})),cloneUrl=buildTaskCloneUrl(normalizeBaseUrl(this.opts.baseUrl),this.opts.agentNodeId,repo.repoId),prep=await repoSync.prepare({dir:cwd,repo:{cloneUrl,defaultBranch:repo.defaultBranch??null},workBranch:taskBranchName(taskId),mode:`ticket-branch`});prep.ok?prep.preservedLocalChanges&&logWarn(`[builderforce] task ${taskId}: preserved uncommitted WIP, skipped refresh`):logWarn(`[builderforce] task ${taskId} repo sync failed: ${prep.error}`)}return cwd}async commitAndPushTicketBranch(taskId,repo,title,agentLabel){let dir=taskWorkspaceDir(this.opts.workspaceDir??process.cwd(),taskId);if(!await isCloned(dir))return;let git=makeCodingGit({apiKey:this.opts.apiKey}),branch=taskBranchName(taskId);try{let{changed}=await git.commitAll(dir,`BuilderForce: task ${taskId} — ${title} (by ${agentLabel})`.trim());if(!changed)return;let base=normalizeBaseUrl(this.opts.baseUrl);await git.push(dir,buildTaskCloneUrl(base,this.opts.agentNodeId,repo.repoId),branch),await fetch(`${base}/api/agent-hosts/${this.opts.agentNodeId}/tasks/${taskId}/pull-request`,{method:`POST`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${this.opts.apiKey}`},body:JSON.stringify({branch,base:repo.defaultBranch??void 0,title}),signal:AbortSignal.timeout(3e4)}).catch(()=>{}),logWarn(`[builderforce] task ${taskId}: pushed pending changes to ${branch}`)}catch(err){logWarn(`[builderforce] task ${taskId} commit/push failed: ${String(err)}`)}}async emitTaskChanges(cwd,agentLabel,executionId,taskId){for(let ch of await detectTaskChanges(cwd,agentLabel))this.sendToRelay({type:`file.change`,executionId,taskId,path:ch.path,change:ch.change,agent:ch.agent,ts:new Date().toISOString()})}async runV2Engine(payload,prompt){let agentLabel=payload.agentLabel?.trim()||`BuilderForce-V2`,sinks={onAssistantText:text=>{this.sendToRelay({type:`chat.message`,role:`assistant`,text,session:`main`}),this.persistToolAudit({executionId:payload.executionId,toolName:`agent.message`,category:`message`,result:text})},onToolUse:(toolName,toolCallId,args)=>{this.sendToRelay({type:`tool.audit`,sessionKey:`main`,toolName,toolCallId,category:`v2`,args,ts:new Date().toISOString()}),this.persistToolAudit({executionId:payload.executionId,toolName,toolCallId,category:`v2`,args})},onResult:()=>{},onSteerApplied:text=>{let detail={text};this.sendToRelay({type:`tool.audit`,sessionKey:`main`,toolName:`steer.applied`,category:`message`,args:detail,ts:new Date().toISOString()}),this.persistToolAudit({executionId:payload.executionId,toolName:`steer.applied`,category:`message`,args:detail,result:text.slice(0,280)})}},cwd=await this.ensureTaskWorkspace(payload.taskId,payload.repo),appendSystemPrompt=await buildAssignedCapabilityAppend(),abortController=new AbortController,steering=createSteeringChannel();payload.executionId!=null&&(this.v2Aborts.set(payload.executionId,abortController),this.v2Steering.set(payload.executionId,steering),this.lateSteers.open(payload.executionId));let engine=new ClaudeSdkAgentEngine({cwd,anthropicBaseUrl:`${normalizeBaseUrl(this.opts.baseUrl)}/llm`,gatewayAuthKey:this.opts.apiKey,surface:`on_prem`,...payload.executionId==null?{}:{executionId:payload.executionId},abortController,steering,sinks}),terminal=null;try{let result;try{let run=await engine.run({systemPrompt:appendSystemPrompt,userContent:prompt,model:payload.model??await resolveRelayTaskModel({prompt}),signal:abortController.signal,...payload.policyGates?.length?{policy:{gates:payload.policyGates}}:{}});result={ok:run.ok,text:run.output}}finally{steering.close(),payload.executionId!=null&&(this.v2Aborts.delete(payload.executionId),this.v2Steering.delete(payload.executionId))}if(abortController.signal.aborted){await this.emitTaskChanges(cwd,agentLabel,payload.executionId,payload.taskId),terminal=`cancelled`;return}await this.emitTaskChanges(cwd,agentLabel,payload.executionId,payload.taskId),payload.taskId!=null&&payload.repo?.repoId&&await this.commitAndPushTicketBranch(payload.taskId,payload.repo,payload.title??`Task ${payload.taskId}`,agentLabel),payload.executionId!=null&&await this.reportExecutionState(payload.executionId,result.ok?`completed`:`failed`,result.ok?{result:result.text}:{errorMessage:result.text}),result.ok||(terminal=`failed`)}catch(err){let message=err instanceof Error?err.message:String(err);logWarn(`[builderforce] V2 run failed: ${message}`),terminal=`aborted`,payload.executionId!=null&&await this.reportExecutionState(payload.executionId,`failed`,{errorMessage:message})}finally{if(payload.taskId!=null&&terminal&&await this.releaseTaskWorkspace(terminal,{taskId:payload.taskId,...payload.title?{title:payload.title}:{},...payload.repo?.repoId?{repoId:payload.repo.repoId}:{},defaultBranch:payload.repo?.defaultBranch??null}),payload.executionId!=null){let late=this.lateSteers.drain(payload.executionId);late.length>0&&this.reportLateSteers(payload.executionId,`run_finishing`,late)}}}async finalizeTask(payload){await this.releaseTaskWorkspace(`done`,payload)}async releaseTaskWorkspace(state,payload){let baseDir=this.opts.workspaceDir??process.cwd(),dir=taskWorkspaceDir(baseDir,payload.taskId),repoId=payload.repoId,preserve=repoId?async()=>{await isCloned(dir)&&await this.commitAndPushTicketBranch(payload.taskId,{repoId,defaultBranch:payload.defaultBranch??null},payload.title??`Task ${payload.taskId}`,`BuilderForce`)}:void 0;(await releaseTaskWorkspaceOnTerminal({baseDir,taskId:payload.taskId,state,...preserve?{preserve}:{}})).released||logWarn(`[builderforce] task ${payload.taskId}: workspace release (${state}) did not complete`)}async handleAgentDispatch(dispatchId){let workspaceDir=this.opts.workspaceDir??process.cwd();try{await runCodingDispatch({http:makeCodingHttp({baseUrl:this.opts.baseUrl,agentNodeId:this.opts.agentNodeId,apiKey:this.opts.apiKey}),git:makeCodingGit({apiKey:this.opts.apiKey}),fs:makeCodingFs(),agent:makeCodingAgent(()=>this.gatewayClient),baseUrl:normalizeBaseUrl(this.opts.baseUrl),workspaceDir,joinPath:(...parts)=>path.join(...parts)},dispatchId)}catch(err){logWarn(`[builderforce] agent_dispatch ${dispatchId} failed: ${String(err)}`)}}async persistToolAudit(event){let url=`${normalizeBaseUrl(this.opts.baseUrl)}/api/agent-hosts/${this.opts.agentNodeId}/tool-audit`;try{await fetch(url,{method:`POST`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${this.opts.apiKey}`},body:JSON.stringify({executionId:event.executionId,runId:event.executionId==null?void 0:`exec-${event.executionId}`,sessionKey:`main`,toolCallId:event.toolCallId,toolName:event.toolName,category:event.category,args:event.args,result:event.result,ts:new Date().toISOString()}),signal:AbortSignal.timeout(1e4)})}catch(err){logDebug(`[builderforce-relay] tool-audit persist failed: ${String(err)}`)}}async reportLateSteers(executionId,reason,steers){let url=`${normalizeBaseUrl(this.opts.baseUrl)}/api/agent-hosts/${this.opts.agentNodeId}/late-steers`,handled=!1;try{let res=await fetch(url,{method:`POST`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${this.opts.apiKey}`},body:JSON.stringify(buildLateSteerReport(executionId,reason,steers)),signal:AbortSignal.timeout(15e3)});if(res.ok){let body=await res.json().catch(()=>null);handled=typeof body?.outcome?.kind==`string`&&body.outcome.kind!==`none`}}catch(err){logDebug(`[builderforce-relay] late-steer report failed: ${String(err)}`)}if(!handled)for(let steer of steers)this.persistToolAudit({executionId,toolName:`steer.dropped`,category:`message`,args:{text:steer.text,reason},result:`This message arrived after the run's last turn and could not be handed back for a follow-up run; send it again as a follow-up.`})}async reportExecutionState(executionId,status,extra){let url=`${normalizeBaseUrl(this.opts.baseUrl)}/api/agent-hosts/${this.opts.agentNodeId}/executions/${executionId}/state`;try{await fetch(url,{method:`PATCH`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${this.opts.apiKey}`},body:JSON.stringify({status,...extra}),signal:AbortSignal.timeout(1e4)}),logDebug(`[builderforce-relay] execution ${executionId} → ${status}`)}catch(err){logDebug(`[builderforce-relay] execution state report failed: ${String(err)}`)}}constructor(opts){this.opts=opts,this.ws=null,this.closed=!1,this.backoffMs=1e3,this.gatewayClient=null,this.pendingExecutionId=null,this.v2Aborts=new Map,this.v2Steering=new Map,this.lateSteers=createLateSteerRegistry(),this.pendingRemoteCorrelations=new Map,this.remoteChunkFlush=new Map,this.remoteDispatchOpts=null,this.upstreamWsUrl=`${normalizeBaseUrl(opts.baseUrl).replace(/^https:/,`wss:`).replace(/^http:/,`ws:`)}/api/agent-hosts/${opts.agentNodeId}/upstream`,this.heartbeatHttpUrl=`${normalizeBaseUrl(opts.baseUrl)}/api/agent-hosts/${opts.agentNodeId}/heartbeat`,this.assignmentContextUrl=`${normalizeBaseUrl(opts.baseUrl)}/api/agent-hosts/${opts.agentNodeId}/assignment-context`,this.gatewayWsUrl=opts.gatewayUrl??`ws://127.0.0.1:18789`,this.heartbeat=new RelayHeartbeat({heartbeatUrl:this.heartbeatHttpUrl,apiKey:opts.apiKey,workspaceDir:opts.workspaceDir}),this.logPoller=new RelayLogPoller(()=>this.gatewayClient,msg=>this.sendToRelay(msg),()=>this.pendingExecutionId),this.presencePoller=new RelayPresencePoller(()=>this.gatewayClient,msg=>this.sendToRelay(msg))}setRemoteDispatchOptions(opts){this.remoteDispatchOpts=opts}async fetchRemoteContext(remoteAgentNodeId){if(!this.opts.workspaceDir)return;let url=`${normalizeBaseUrl(this.opts.baseUrl)}/api/agent-hosts/${encodeURIComponent(remoteAgentNodeId)}/context-bundle`,bundle;try{let res=await fetch(url,{headers:{Authorization:`Bearer ${this.opts.apiKey}`},signal:AbortSignal.timeout(15e3)});if(!res.ok){logDebug(`[builderforce-relay] context-bundle for agentNode ${remoteAgentNodeId} failed: ${res.status}`);return}bundle=await res.json()}catch(err){logDebug(`[builderforce-relay] fetchRemoteContext error: ${String(err)}`);return}if(!Array.isArray(bundle.files)||bundle.files.length===0)return;let targetDir=path.join(this.opts.workspaceDir,`.builderForceAgents`,`remote-context`,remoteAgentNodeId);for(let file of bundle.files){if(typeof file.path!=`string`||typeof file.content!=`string`)continue;let safeName=file.path.replace(/\\/g,`/`).replace(/^[./]+/,``).replace(/\.\.\//g,``);if(!safeName)continue;let destPath=path.join(targetDir,safeName),existingSha=null;try{let existing=await fs$1.readFile(destPath,`utf-8`);existingSha=createHash(`sha256`).update(existing,`utf-8`).digest(`hex`)}catch{}existingSha!==file.sha256&&(await fs$1.mkdir(path.dirname(destPath),{recursive:!0}),await fs$1.writeFile(destPath,file.content,`utf-8`),logDebug(`[builderforce-relay] wrote remote context file: ${safeName}`))}}start(){this.closed||(setRelayHook((event,payload)=>{this.sendToRelay({type:`event`,event,payload})}),sweepStaleTaskWorkspaces(this.opts.workspaceDir??process.cwd(),{activeTaskIds:[]}).then(({removed})=>{removed.length&&logWarn(`[builderforce] swept ${removed.length} stale ticket workspace(s)`)}).catch(()=>{}),this.connectUpstream(),this.connectLocalGateway(),this.startRemoteResultTracking())}stop(){this.closed=!0,setRelayHook(null),this.heartbeat.clear(),this.logPoller.clear(),this.presencePoller.clear(),this.ws?.close(1e3,`stopped`),this.ws=null,this.gatewayClient?.stop(),this.gatewayClient=null;for(let entry of this.remoteChunkFlush.values())entry.timer&&clearTimeout(entry.timer);this.remoteChunkFlush.clear()}startRemoteResultTracking(){onAgentEvent(evt=>{if(this.closed||evt.stream!==`lifecycle`)return;let phase=evt.data.phase;if(phase!==`end`&&phase!==`error`)return;let sessionKey=evt.sessionKey??``,correlation=this.pendingRemoteCorrelations.get(sessionKey);if(!correlation)return;this.flushRemoteChunk(sessionKey),this.pendingRemoteCorrelations.delete(sessionKey);let errorVal=evt.data.error,errorStr=typeof errorVal==`string`?errorVal:`unknown error`,fallback=typeof evt.data.summary==`string`?evt.data.summary:phase===`error`?`Remote task failed: ${errorStr}`:`Remote task completed on agentNode ${this.opts.agentNodeId}`,resultText=correlation.accumulated.trim()||fallback;this.remoteDispatchOpts&&dispatchResultToRemoteAgentNode(this.remoteDispatchOpts,correlation.callbackAgentNodeId,correlation.correlationId,resultText)})}captureRemoteOutput(sessionKey,piece,replace=!1){let corr=this.pendingRemoteCorrelations.get(sessionKey);if(!(!corr||!piece)){if(replace){if(corr.accumulated)return;corr.accumulated=piece}else corr.accumulated+=piece;this.enqueueRemoteChunk(sessionKey,piece)}}enqueueRemoteChunk(sessionKey,piece){if(!piece)return;let existing=this.remoteChunkFlush.get(sessionKey);if(existing){existing.buf+=piece;return}let entry={buf:piece,timer:setTimeout(()=>this.flushRemoteChunk(sessionKey),250)};this.remoteChunkFlush.set(sessionKey,entry)}flushRemoteChunk(sessionKey){let entry=this.remoteChunkFlush.get(sessionKey);this.remoteChunkFlush.delete(sessionKey),entry?.timer&&clearTimeout(entry.timer);let chunk=entry?.buf??``;if(!chunk)return;let corr=this.pendingRemoteCorrelations.get(sessionKey);!corr||!this.remoteDispatchOpts||dispatchChunkToRemoteAgentNode(this.remoteDispatchOpts,corr.callbackAgentNodeId,corr.correlationId,chunk)}connectUpstream(){if(this.closed)return;let ws=new WebSocket$1(this.upstreamWsUrl,{headers:{Authorization:`Bearer ${this.opts.apiKey}`}});this.ws=ws,ws.on(`open`,()=>{logWarn(`[builderforce-relay] upstream connected`),this.backoffMs=1e3,this.heartbeat.schedule(),this.syncAssignmentContext(`ws-open`)}),ws.on(`message`,raw=>{try{let rawText=typeof raw==`string`?raw:raw instanceof Buffer?raw.toString(`utf-8`):Array.isArray(raw)?Buffer.concat(raw).toString(`utf-8`):raw instanceof ArrayBuffer?Buffer.from(new Uint8Array(raw)).toString(`utf-8`):``,msg=JSON.parse(rawText);this.handleRelayMessage(msg)}catch{}}),ws.on(`close`,()=>{this.ws===ws&&(this.ws=null,this.heartbeat.clear(),logWarn(`[builderforce-relay] upstream disconnected — reconnecting…`),this.scheduleReconnect())}),ws.on(`error`,err=>{logWarn(`[builderforce-relay] upstream error: ${String(err)}`)})}handleRelayMessage(msg){let type=typeof msg.type==`string`?msg.type:``;switch(type){case`relay_connected`:logDebug(`[builderforce-relay] relay acknowledged connection`);break;case`ping`:break;case`chat`:{let message=typeof msg.message==`string`?msg.message:``,session=typeof msg.session==`string`?msg.session:`main`;this.gatewayClient?.request(`chat.send`,{sessionKey:session,message,idempotencyKey:randomUUID()}).catch(err=>{logDebug(`[builderforce-relay] chat.send failed: ${String(err)}`)});break}case`chat.abort`:this.gatewayClient?.request(`chat.abort`,{}).catch(()=>{});break;case`session.new`:this.gatewayClient?.request(`chat.new`,{}).catch(()=>{});break;case`logs.subscribe`:this.logPoller.start(!0);break;case`presence.subscribe`:this.presencePoller.start();break;case`rpc.call`:{let requestId=typeof msg.requestId==`string`&&msg.requestId.trim().length>0?msg.requestId:randomUUID(),method=typeof msg.method==`string`?msg.method.trim():``,params=msg.params&&typeof msg.params==`object`&&!Array.isArray(msg.params)?msg.params:{};if(!method){this.sendToRelay({type:`rpc.error`,requestId,method,error:`method required`});break}this.gatewayClient?.request(method,params).then(result=>{this.sendToRelay({type:`rpc.result`,requestId,method,result})}).catch(err=>{this.sendToRelay({type:`rpc.error`,requestId,method,error:String(err)})});break}case`host.egress.request`:{let requestId=typeof msg.requestId==`string`?msg.requestId:``;if(!requestId)break;performHostEgress({requestId,method:typeof msg.method==`string`?msg.method:`POST`,url:typeof msg.url==`string`?msg.url:void 0,headers:msg.headers&&typeof msg.headers==`object`&&!Array.isArray(msg.headers)?msg.headers:{},body:typeof msg.body==`string`?msg.body:null},{...this.opts.ollamaLocalOrigin?{allowedLocalOrigin:this.opts.ollamaLocalOrigin}:{},...this.opts.freetokenLocalOrigin?{allowedFreetokenOrigin:this.opts.freetokenLocalOrigin}:{}}).then(frame=>{this.sendToRelay(frame)});break}case`remote.task`:{let task=typeof msg.task==`string`?msg.task:``,fromAgentNodeId=typeof msg.fromAgentNodeId==`string`?msg.fromAgentNodeId:`unknown`,correlationId=typeof msg.correlationId==`string`?msg.correlationId:``,callbackAgentNodeId=typeof msg.callbackAgentNodeId==`string`?msg.callbackAgentNodeId:``,callbackBaseUrl=typeof msg.callbackBaseUrl==`string`?msg.callbackBaseUrl:``;if(!task)break;logDebug(`[builderforce-relay] remote task from agentNode ${fromAgentNodeId}: ${task.slice(0,80)}…`);let sessionKey=correlationId?`remote-${correlationId}`:`main`;correlationId&&callbackAgentNodeId&&this.pendingRemoteCorrelations.set(sessionKey,{correlationId,callbackAgentNodeId,callbackBaseUrl,accumulated:``}),this.gatewayClient?.request(`chat.send`,{sessionKey,message:`[Remote task from agentNode ${fromAgentNodeId}]\n\n${task}`,idempotencyKey:`remote-${fromAgentNodeId}-${correlationId||Date.now()}`}).catch(err=>{logDebug(`[builderforce-relay] remote.task dispatch failed: ${String(err)}`)});break}case`remote.task.result`:case`remote.result`:case`remote.task.chunk`:case`remote.result.chunk`:{let parsed=parseRemoteCallbackFrame(msg);if(!parsed)break;if(parsed.kind===`chunk`){let delivered=pushRemoteResultChunk(parsed.correlationId,parsed.chunk);delivered&&parsed.chunk&&this.sendToRelay({type:`chat.delta`,delta:parsed.chunk,session:`remote-${parsed.correlationId}`}),logDebug(`[builderforce-relay] remote.task.chunk ${parsed.correlationId}: ${delivered?`delivered`:`no waiter`}`);break}let resolved=resolveRemoteResult(parsed.correlationId,parsed.result);logDebug(`[builderforce-relay] remote.task.result ${parsed.correlationId}: ${resolved?`resolved`:`no pending callback`}`);break}case`task.assign`:case`task.broadcast`:{let taskRecord=msg.task&&typeof msg.task==`object`?msg.task:null,title=typeof taskRecord?.title==`string`?taskRecord.title.trim():``,description=typeof taskRecord?.description==`string`?taskRecord.description.trim():``,executionId=typeof msg.executionId==`number`&&Number.isFinite(msg.executionId)?msg.executionId:void 0,taskId=typeof msg.taskId==`number`&&Number.isFinite(msg.taskId)?msg.taskId:void 0,rawArtifacts=msg.artifacts&&typeof msg.artifacts==`object`?msg.artifacts:void 0,artifacts=rawArtifacts?{skills:Array.isArray(rawArtifacts.skills)?rawArtifacts.skills:void 0,personas:Array.isArray(rawArtifacts.personas)?rawArtifacts.personas:void 0,content:Array.isArray(rawArtifacts.content)?rawArtifacts.content:void 0}:void 0;if(!title&&!description){logWarn(`[builderforce] received ${type} without task content`);break}let engine=typeof msg.engine==`string`?msg.engine:CURRENT_ENGINE_ID,model,policyGates=[];try{let p=typeof msg.payload==`string`?JSON.parse(msg.payload):null;p&&typeof p.model==`string`&&p.model.trim()&&(model=p.model.trim()),p&&(policyGates=coercePolicyGates(p.policyGates))}catch{}let repoRaw=msg.repo&&typeof msg.repo==`object`?msg.repo:null,repo=repoRaw&&typeof repoRaw.repoId==`string`?{repoId:repoRaw.repoId,defaultBranch:typeof repoRaw.defaultBranch==`string`?repoRaw.defaultBranch:null}:void 0,agentLabel=typeof msg.agentLabel==`string`?msg.agentLabel:void 0;logWarn(`[builderforce] received ${type}${taskId==null?``:` task=${taskId}`}${executionId==null?``:` execution=${executionId}`} engine=${engine}`),this.dispatchTaskFromRelay({sourceType:type,title:title||`Assigned task`,description:description||void 0,executionId,taskId,artifacts,engine,model,repo,agentLabel,...policyGates.length?{policyGates}:{}}),this.syncAssignmentContext(type);break}case`execution.message`:{let executionId=typeof msg.executionId==`number`&&Number.isFinite(msg.executionId)?msg.executionId:void 0,channel=executionId==null?void 0:this.v2Steering.get(executionId);if(channel&&channel.push(msg.text))break;let steer=lateSteerFromFrame(msg);if(executionId==null||!steer)break;if(this.lateSteers.hold(executionId,steer)){logWarn(`[builderforce] steer for execution ${executionId} arrived after the run's last turn — it will continue as a follow-up run`);break}logWarn(`[builderforce] steer for execution ${executionId} has no live V2 run on this host — handing it back for a follow-up run`),this.reportLateSteers(executionId,`no_live_run`,[steer]);break}case`execution.cancel`:{let executionId=typeof msg.executionId==`number`&&Number.isFinite(msg.executionId)?msg.executionId:void 0;if(logWarn(`[builderforce] cancel execution ${executionId??`?`}`),executionId!=null){let ctrl=this.v2Aborts.get(executionId);if(ctrl)try{ctrl.abort()}catch{}}this.gatewayClient?.request(`chat.abort`,{}).catch(()=>{});break}case`task.finalize`:{let finalizeTaskId=typeof msg.taskId==`number`&&Number.isFinite(msg.taskId)?msg.taskId:void 0;if(finalizeTaskId==null)break;let repoRaw=msg.repo&&typeof msg.repo==`object`?msg.repo:null;this.finalizeTask({taskId:finalizeTaskId,title:typeof msg.title==`string`?msg.title:void 0,repoId:repoRaw&&typeof repoRaw.repoId==`string`?repoRaw.repoId:void 0,defaultBranch:repoRaw&&typeof repoRaw.defaultBranch==`string`?repoRaw.defaultBranch:null});break}case`agent_dispatch`:{let dispatchId=typeof msg.dispatchId==`string`?msg.dispatchId:``;if(!dispatchId){logWarn(`[builderforce] agent_dispatch without dispatchId`);break}logWarn(`[builderforce] received agent_dispatch dispatch=${dispatchId}`),this.handleAgentDispatch(dispatchId);break}case`approval.decision`:{let approvalId=typeof msg.approvalId==`string`?msg.approvalId:``,decision=typeof msg.status==`string`?msg.status:``,responseText=typeof msg.responseText==`string`?msg.responseText:void 0;approvalId&&(decision===`approved`||decision===`rejected`||decision===`answered`)&&(logWarn(`[builderforce-relay] approval.decision ${approvalId}: ${decision}`),resolveApproval(approvalId,decision,responseText));break}default:break}}sendToRelay(msg){this.ws?.readyState===WebSocket$1.OPEN&&this.ws.send(JSON.stringify(msg))}scheduleReconnect(){if(this.closed)return;let delay=this.backoffMs;this.backoffMs=Math.min(this.backoffMs*2,3e4),setTimeout(()=>this.connectUpstream(),delay).unref()}connectLocalGateway(){let gw=new GatewayClient({url:this.gatewayWsUrl,onEvent:evt=>this.handleGatewayEvent(evt),onConnectError:err=>{logDebug(`[builderforce-relay] local gateway connect error: ${String(err)}`)}});this.gatewayClient=gw,gw.start()}handleGatewayEvent(evt){if(evt.event!==`chat`)return;let p=evt.payload,legacy=evt.payload;if(p){if(legacy&&typeof legacy.state==`string`){let session=legacy.sessionKey??`main`;if(legacy.state===`final`){let text=extractChatText(legacy.message),role=extractChatRole(legacy.message);if(text&&this.sendToRelay({type:`chat.message`,role,text,session}),resolveCodingSession(session,{ok:!0,text}))return;if(this.pendingExecutionId!=null){let eid=this.pendingExecutionId;this.pendingExecutionId=null,this.reportExecutionState(eid,`completed`,{result:text||void 0})}return}if(legacy.state===`error`){let text=legacy.errorMessage?.trim();if(text&&this.sendToRelay({type:`chat.message`,role:`assistant`,text:`[error] ${text}`,session}),resolveCodingSession(session,{ok:!1,text:text??`agent error`}))return;if(this.pendingExecutionId!=null){let eid=this.pendingExecutionId;this.pendingExecutionId=null,this.reportExecutionState(eid,`failed`,{errorMessage:text||void 0})}return}}switch(p.type){case`delta`:{let session=p.sessionKey??`main`,delta=p.delta??``;this.sendToRelay({type:`chat.delta`,delta,session}),this.captureRemoteOutput(session,delta);break}case`message`:{let session=p.sessionKey??`main`,text=p.text??``;this.sendToRelay({type:`chat.message`,role:p.role??`assistant`,text,session}),this.captureRemoteOutput(session,text,!0);break}case`tool_use`:this.sendToRelay({type:`tool.start`,toolCallId:p.toolCallId,toolName:p.toolName,toolInput:p.toolInput,session:p.sessionKey??`main`});break;case`tool_result`:this.sendToRelay({type:`tool.result`,toolCallId:p.toolCallId,toolResult:p.toolResult,session:p.sessionKey??`main`});break;case`abort`:this.sendToRelay({type:`chat.abort`,session:p.sessionKey??`main`});break;default:break}}}async syncAssignmentContext(reason){if(this.opts.workspaceDir)try{let response=await fetch(this.assignmentContextUrl,{method:`GET`,headers:{Authorization:`Bearer ${this.opts.apiKey}`},signal:AbortSignal.timeout(1e4)});if(!response.ok){logDebug(`[builderforce-relay] assignment-context ${reason} failed: ${response.status}`);return}let assignmentContext=await response.json(),context=await loadProjectContext(this.opts.workspaceDir);if(!context)return;let machineProfile=buildLocalMachineProfile({workspaceDirectory:this.opts.workspaceDir,rootInstallDirectory:process.cwd(),gatewayPort:18789,tunnelUrl:process.env.BUILDERFORCE_AGENTS_PUBLIC_TUNNEL_URL,tunnelStatus:process.env.BUILDERFORCE_AGENTS_PUBLIC_TUNNEL_URL?`connected`:`none`}),builderforce=mergeBuilderforceContext({existing:context.builderforce,assignmentContext,fallback:{instanceId:this.opts.agentNodeId,url:this.opts.baseUrl},machineProfile});await updateProjectContextFields(this.opts.workspaceDir,{builderforce})}catch(err){logDebug(`[builderforce-relay] assignment-context ${reason} failed: ${String(err)}`)}}};function transportKindForTarget(target){return target.startsWith(`remote:`)?`remote`:`local`}var CompositeAgentTransport=class{constructor(transports){this.transports=transports}has(kind){return!!this.transports[kind]}async discover(requiredCapabilities=[]){return(await Promise.all(Object.values(this.transports).map(t=>t.discover(requiredCapabilities)))).flat()}async dispatch(payload){let kind=transportKindForTarget(payload.target),transport=this.transports[kind];return transport?transport.dispatch(payload):{status:`failed`,error:kind===`remote`?`Remote dispatch not configured — set BUILDERFORCE_API_KEY and builderforce.instanceId.`:`Local dispatch not configured.`}}};function nextCronDate(expr,after){let parts=expr.trim().split(/\s+/);if(parts.length!==5)return null;let[mE,hE,,,]=parts;return(base=>{let d=new Date(base);d.setSeconds(0,0);let matchField=(val,field)=>{if(field===`*`)return!0;if(field.startsWith(`*/`)){let step=Number(field.slice(2));return Number.isFinite(step)&&step>0&&val%step===0}return val===Number(field)};for(let i=0;i<1440;i++)if(d.setMinutes(d.getMinutes()+1),matchField(d.getMinutes(),mE)&&matchField(d.getHours(),hE))return d;return null})(after)}var CronPollerService=class{constructor(opts){this.opts=opts,this.timers=new Map,this.jobs=[],this.pollTimer=null,this.closed=!1,this.gatewayClient=new GatewayClient({url:opts.gatewayUrl??`ws://127.0.0.1:18789`,onEvent:()=>{},onConnectError:()=>{}})}async start(){if(isOfflineMode()){logDebug(`[cron-poller] offline mode — skipping control-plane polling`);return}this.gatewayClient.start(),await this.fetchAndSchedule(),this.pollTimer=setInterval(()=>void this.fetchAndSchedule(),300*1e3)}stop(){this.closed=!0,this.pollTimer&&=(clearInterval(this.pollTimer),null);for(let timer of this.timers.values())clearTimeout(timer);this.timers.clear(),this.gatewayClient.stop()}async fetchAndSchedule(){let url=`${normalizeBaseUrl(this.opts.baseUrl)}/api/agent-hosts/${this.opts.agentNodeId}/cron`;try{let res=await fetch(url,{headers:{Authorization:`Bearer ${this.opts.apiKey}`},signal:AbortSignal.timeout(1e4)});if(!res.ok){logWarn(`[cron-poller] fetch failed: ${res.status}`);return}this.jobs=((await res.json()).jobs??[]).filter(j=>j.enabled),logDebug(`[cron-poller] loaded ${this.jobs.length} enabled job(s)`),this.rescheduleAll()}catch(err){logWarn(`[cron-poller] fetch error: ${String(err)}`)}}rescheduleAll(){for(let timer of this.timers.values())clearTimeout(timer);this.timers.clear();let now=new Date;for(let job of this.jobs){let next=nextCronDate(job.schedule,now);if(!next){logWarn(`[cron-poller] job "${job.name}" has unparseable schedule: ${job.schedule}`);continue}let delay=next.getTime()-Date.now();logDebug(`[cron-poller] job "${job.name}" next run in ${Math.round(delay/1e3)}s`);let timer=setTimeout(()=>void this.fireJob(job),delay);this.timers.set(job.id,timer)}}async fireJob(job){if(this.closed)return;logWarn(`[cron-poller] firing job "${job.name}" (${job.id})`);let lastStatus=`success`;try{let sessionKey=job.projectAgentId==null?`main`:`project-agent-${job.projectAgentId}`,agentLine=job.projectAgentId==null?``:`\nProject agent: #${job.projectAgentId}`;await this.gatewayClient.request(`chat.send`,{sessionKey,message:`[Scheduled job: ${job.name}]\n\nRun cron task: ${job.name}${job.taskId==null?``:` (task #${job.taskId})`}${agentLine}`,idempotencyKey:`cron-${job.id}-${Date.now()}`})}catch(err){logWarn(`[cron-poller] job "${job.name}" dispatch failed: ${String(err)}`),lastStatus=`error`}this.patchJobStatus(job.id,lastStatus);let next=nextCronDate(job.schedule,new Date);if(next&&!this.closed){let delay=next.getTime()-Date.now(),timer=setTimeout(()=>void this.fireJob(job),delay);this.timers.set(job.id,timer)}}async patchJobStatus(jobId,status){let url=`${normalizeBaseUrl(this.opts.baseUrl)}/api/agent-hosts/${this.opts.agentNodeId}/cron/${jobId}`;try{await fetch(url,{method:`PATCH`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${this.opts.apiKey}`},body:JSON.stringify({lastRunAt:new Date().toISOString(),lastStatus:status}),signal:AbortSignal.timeout(1e4)})}catch(err){logDebug(`[cron-poller] status patch failed for job ${jobId}: ${String(err)}`)}}},GatewayLlmService=class{constructor(opts){this.opts=opts}async complete(req){let messages=[];req.system&&messages.push({role:`system`,content:req.system}),messages.push({role:`user`,content:req.prompt});try{return(await nativeComplete(this.opts,{messages,...req.model?{model:req.model}:{},...req.temperature==null?{}:{temperature:req.temperature},...req.provider?{extra:{provider:req.provider}}:{}},AbortSignal.timeout(12e4))).content}catch(err){return logDebug(`[gateway-llm] complete failed: ${String(err)}`),`[llm] request failed: ${err instanceof Error?err.message:String(err)}`}}};function authHeaders$1(cfg){return{Authorization:`Bearer ${cfg.apiKey}`,"X-AgentHost-Id":String(cfg.agentHostId)}}function clampLearnWeight(weight){return Math.max(.05,Math.min(1,typeof weight==`number`&&weight>0?weight:.6))}async function contributeProjectEvermindFromText(cfg,text,prompt,weight){let trimmed=(text??``).trim();if(trimmed.length<20)return{ok:!1,reason:`text too short`};let promptTrimmed=(prompt??``).trim(),learnWeight=clampLearnWeight(weight);try{let res=await fetch(`${cfg.gatewayUrl}/api/agent/projects/${cfg.projectId}/evermind/learn-text`,{method:`POST`,headers:{...authHeaders$1(cfg),"Content-Type":`application/json`},body:JSON.stringify({text:trimmed.slice(0,cfg.maxChars??8e3),...promptTrimmed?{prompt:promptTrimmed.slice(0,cfg.maxChars??8e3)}:{},weight:learnWeight})}),body=await res.json().catch(()=>({}));return res.ok?{ok:!0,...typeof body.baseVersion==`number`?{version:body.baseVersion}:{}}:{ok:!1,reason:typeof body.error==`string`?body.error:`learn-text ${res.status}`}}catch(err){return{ok:!1,reason:String(err)}}}async function loadDeltaEngine(){try{let mod=await Function(`m`,`return import(m)`)(`@seanhogg/builderforce-memory-engine`);return!mod?.EvermindModelPackage||!mod.BPETokenizer||typeof mod.adaptAndDiff!=`function`||typeof mod.buildDeltaLearnPayload!=`function`||typeof mod.MAX_DELTA_B64_CHARS!=`number`?null:mod}catch{return null}}function buildDeltaPayload(engine,base,text,weight,label){let pkg=engine.EvermindModelPackage.fromBlob(base.model);if(pkg.manifest.modelType!==`evermind-lm`)return null;let tok=new engine.BPETokenizer;tok.loadFromObjects(base.tokenizer.vocab,base.tokenizer.merges);let adapted=engine.adaptAndDiff(pkg,tok,text);return adapted?engine.buildDeltaLearnPayload(adapted.diff,base.version,weight,label):null}function agentBase(cfg){return`${cfg.gatewayUrl}/api/agent/projects/${cfg.projectId}/evermind`}async function fetchHeadVersion(cfg){try{let res=await fetch(`${agentBase(cfg)}/head`,{headers:authHeaders$1(cfg)});if(!res.ok)return null;let body=await res.json().catch(()=>({})),version=typeof body.version==`number`?body.version:0;return version<=0?null:{version,frozen:body.mode===`offline-frozen`}}catch{return null}}async function fetchBase(cfg,version){try{let q=`?version=${version}`,[modelRes,tokRes]=await Promise.all([fetch(`${agentBase(cfg)}/model${q}`,{headers:authHeaders$1(cfg)}),fetch(`${agentBase(cfg)}/tokenizer${q}`,{headers:authHeaders$1(cfg)})]);if(!modelRes.ok||!tokRes.ok)return null;let model=await modelRes.arrayBuffer(),tokenizer=await tokRes.json();return!tokenizer?.vocab||!Array.isArray(tokenizer.merges)?null:{version,model,tokenizer:{vocab:tokenizer.vocab,merges:tokenizer.merges}}}catch{return null}}async function pushDelta(cfg,payload){try{let res=await fetch(`${agentBase(cfg)}/learn`,{method:`POST`,headers:{...authHeaders$1(cfg),"Content-Type":`application/json`},body:JSON.stringify(payload)}),body=await res.json().catch(()=>({}));return res.ok?{ok:!0,version:payload.baseVersion}:res.status===409&&typeof body.headVersion==`number`?{ok:!1,staleHeadVersion:body.headVersion,reason:`stale base`}:res.status===409&&body.code===`evermind_inherited_read_only`?{ok:!1,terminal:!0,reason:typeof body.error==`string`?body.error:`this build inherits project ${String(body.inheritedFromProjectId??`?`)}'s Evermind`}:{ok:!1,reason:typeof body.error==`string`?body.error:`learn ${res.status}`}}catch(err){return{ok:!1,reason:String(err)}}}async function contributeProjectEvermindFromDelta(cfg,text,prompt,weight,deps){let trimmed=(text??``).trim();if(trimmed.length<20)return{ok:!1,reason:`text too short`};let learnWeight=clampLearnWeight(weight),toText=async reason=>({...await contributeProjectEvermindFromText(cfg,trimmed,prompt,learnWeight),delta:!1,fellBackToText:!0,reason}),engine=await(deps?.loadEngine??loadDeltaEngine)();if(!engine)return toText(`engine unavailable`);let head=await fetchHeadVersion(cfg);if(!head||head.frozen)return toText(head?`offline-frozen`:`no seeded head`);let label=(prompt??``).trim()||void 0;for(let attempt=0,baseVersion=head.version;attempt<2;attempt++){let base=await fetchBase(cfg,baseVersion);if(!base)return toText(`base artifact unavailable`);let payload;try{payload=buildDeltaPayload(engine,base,trimmed,learnWeight,label)}catch(err){return toText(`adapt failed: ${String(err)}`)}if(!payload)return toText(`nothing trainable in this run`);if(payload.diff.length>engine.MAX_DELTA_B64_CHARS)return toText(`delta exceeds the gateway's size cap`);let outcome=await pushDelta(cfg,payload);if(outcome.ok)return{ok:!0,delta:!0,version:outcome.version??baseVersion,...attempt>0?{rebased:!0}:{}};if(outcome.staleHeadVersion&&outcome.staleHeadVersion!==baseVersion){baseVersion=outcome.staleHeadVersion;continue}return outcome.terminal?{ok:!1,reason:outcome.reason??`delta rejected`}:toText(outcome.reason??`delta rejected`)}return toText(`lost the rebase race twice`)}function authHeaders(cfg){return{Authorization:`Bearer ${cfg.apiKey}`,"X-AgentHost-Id":String(cfg.agentHostId)}}async function pushProjectFact(cfg,key,content){if(!key.trim()||!content.trim())return!1;try{return(await fetch(`${cfg.gatewayUrl}/api/agent/projects/${cfg.projectId}/facts`,{method:`POST`,headers:{...authHeaders(cfg),"Content-Type":`application/json`},body:JSON.stringify({key:key.slice(0,255),content,source:`onprem`})})).ok}catch{return!1}}async function recallSharedProjectFacts(cfg,query,limit=6){try{let qs=new URLSearchParams;query&&qs.set(`query`,query),qs.set(`limit`,String(limit));let res=await fetch(`${cfg.gatewayUrl}/api/agent/projects/${cfg.projectId}/facts?${qs.toString()}`,{headers:authHeaders(cfg)});if(!res.ok)return[];let j=await res.json();return Array.isArray(j.facts)?j.facts:[]}catch{return[]}}const DEFAULT_BUILDERFORCE_URL=`https://api.builderforce.ai`;function deltaPathEnabled(){let raw=(process.env.BUILDERFORCE_EVERMIND_DELTA??``).trim().toLowerCase();return raw===`1`||raw===`true`||raw===`yes`}function buildKnowledgeMemoryEntry(params){return buildKnowledgeMemoryEntry$1({sessionKey:params.sessionKey,ts:params.ts,activity:params.acc?{created:params.acc.filesCreated,edited:params.acc.filesEdited,tools:params.acc.toolNames}:void 0})}var KnowledgeLoopService=class{constructor(opts){this.opts=opts,this.runs=new Map,this.unsub=null}start(){this.unsub||(registerKnowledgeLoop(this),registerTeamMemoryContextBuilder(async()=>{let typed=await this.pullTeamMemory(5);if(!typed||typed.length===0)return``;let lines=[`[Team Memory Context]`];for(let entry of typed){let who=entry.agentNodeId?`agentNode:${entry.agentNodeId}`:`unknown`,when=entry.timestamp?` (${entry.timestamp.slice(0,10)})`:``;lines.push(`- [${who}${when}] ${entry.summary??``}`)}lines.push(`[End Team Memory Context]`);let cfg=this.projectEvermindConfig();if(cfg){let facts=await recallSharedProjectFacts(cfg,void 0,6);if(facts.length>0){lines.push(`[Project memory — durable facts recalled for this project]`);for(let f of facts)lines.push(`- ${f.content}`)}}return lines.join(`
195
+ `).trim();if(!message)return;payload.executionId!=null&&(this.pendingExecutionId=payload.executionId,this.reportExecutionState(payload.executionId,`running`));let engine=this.resolveEngine(payload.engine),runEngine=()=>{engine.run(payload,message)};payload.artifacts?this.syncAssignedCapabilities(payload.artifacts,payload.executionId,payload.taskId).finally(runEngine):runEngine()}async syncAssignedCapabilities(artifacts,executionId,taskId){try{await this.gatewayClient?.request(`artifacts.sync`,{artifacts,executionId,taskId})}catch(err){logWarn(`[builderforce] artifacts.sync failed: ${String(err)}`)}let skills=artifacts.skills??[],personas=artifacts.personas??[],content=artifacts.content??[];if(!(skills.length||personas.length||content.length))return;let summary={skills,personas,content};this.toolAudit.emit({executionId,toolName:`capabilities.load`,category:`context`,args:summary}),logWarn(`[builderforce] capabilities.load: ${personas.length} persona(s), ${skills.length} skill(s), ${content.length} content`)}async ensureTaskWorkspace(taskId,repo){let baseDir=this.opts.workspaceDir??process.cwd(),cwd=taskId==null?baseDir:taskWorkspaceDir(baseDir,taskId);if(await fs$1.mkdir(cwd,{recursive:!0}).catch(()=>{}),repo?.repoId&&taskId!=null){let repoSync=createGitRepoSync(makeCodingGit({apiKey:this.opts.apiKey})),cloneUrl=buildTaskCloneUrl(normalizeBaseUrl(this.opts.baseUrl),this.opts.agentNodeId,repo.repoId),prep=await repoSync.prepare({dir:cwd,repo:{cloneUrl,defaultBranch:repo.defaultBranch??null},workBranch:taskBranchName(taskId),mode:`ticket-branch`});prep.ok?prep.preservedLocalChanges&&logWarn(`[builderforce] task ${taskId}: preserved uncommitted WIP, skipped refresh`):logWarn(`[builderforce] task ${taskId} repo sync failed: ${prep.error}`)}return cwd}async commitAndPushTicketBranch(taskId,repo,title,agentLabel){let dir=taskWorkspaceDir(this.opts.workspaceDir??process.cwd(),taskId);if(!await isCloned(dir))return;let git=makeCodingGit({apiKey:this.opts.apiKey}),branch=taskBranchName(taskId);try{let{changed}=await git.commitAll(dir,`BuilderForce: task ${taskId} — ${title} (by ${agentLabel})`.trim());if(!changed)return;let base=normalizeBaseUrl(this.opts.baseUrl);await git.push(dir,buildTaskCloneUrl(base,this.opts.agentNodeId,repo.repoId),branch),await fetch(`${base}/api/agent-hosts/${this.opts.agentNodeId}/tasks/${taskId}/pull-request`,{method:`POST`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${this.opts.apiKey}`},body:JSON.stringify({branch,base:repo.defaultBranch??void 0,title}),signal:AbortSignal.timeout(3e4)}).catch(()=>{}),logWarn(`[builderforce] task ${taskId}: pushed pending changes to ${branch}`)}catch(err){logWarn(`[builderforce] task ${taskId} commit/push failed: ${String(err)}`)}}async emitTaskChanges(cwd,agentLabel,executionId,taskId){for(let ch of await detectTaskChanges(cwd,agentLabel))this.sendToRelay({type:`file.change`,executionId,taskId,path:ch.path,change:ch.change,agent:ch.agent,ts:new Date().toISOString()})}async runV2Engine(payload,prompt){let agentLabel=payload.agentLabel?.trim()||`BuilderForce-V2`,sinks={onAssistantText:text=>{this.sendToRelay({type:`chat.message`,role:`assistant`,text,session:`main`}),this.persistToolAudit({executionId:payload.executionId,toolName:`agent.message`,category:`message`,result:text})},onToolUse:(toolName,toolCallId,args)=>{this.toolAudit.emit({executionId:payload.executionId,toolName,toolCallId,category:`v2`,args})},onResult:()=>{},onSteerApplied:text=>{let detail={text};this.toolAudit.emit({executionId:payload.executionId,toolName:`steer.applied`,category:`message`,args:detail,result:text.slice(0,280)})}},cwd=await this.ensureTaskWorkspace(payload.taskId,payload.repo),appendSystemPrompt=await buildAssignedCapabilityAppend(),abortController=new AbortController,steering=createSteeringChannel();payload.executionId!=null&&(this.v2Aborts.set(payload.executionId,abortController),this.v2Steering.set(payload.executionId,steering),this.lateSteers.open(payload.executionId));let engine=new ClaudeSdkAgentEngine({cwd,anthropicBaseUrl:`${normalizeBaseUrl(this.opts.baseUrl)}/llm`,gatewayAuthKey:this.opts.apiKey,surface:`on_prem`,...payload.executionId==null?{}:{executionId:payload.executionId},abortController,steering,sinks}),terminal=null;try{let result;try{let run=await engine.run({systemPrompt:appendSystemPrompt,userContent:prompt,model:payload.model??await resolveRelayTaskModel({prompt}),signal:abortController.signal,...payload.policyGates?.length?{policy:{gates:payload.policyGates}}:{}});result={ok:run.ok,text:run.output}}finally{steering.close(),payload.executionId!=null&&(this.v2Aborts.delete(payload.executionId),this.v2Steering.delete(payload.executionId)),await this.toolAudit.flush()}if(abortController.signal.aborted){await this.emitTaskChanges(cwd,agentLabel,payload.executionId,payload.taskId),terminal=`cancelled`;return}await this.emitTaskChanges(cwd,agentLabel,payload.executionId,payload.taskId),payload.taskId!=null&&payload.repo?.repoId&&await this.commitAndPushTicketBranch(payload.taskId,payload.repo,payload.title??`Task ${payload.taskId}`,agentLabel),payload.executionId!=null&&await this.reportExecutionState(payload.executionId,result.ok?`completed`:`failed`,result.ok?{result:result.text}:{errorMessage:result.text}),result.ok||(terminal=`failed`)}catch(err){let message=err instanceof Error?err.message:String(err);logWarn(`[builderforce] V2 run failed: ${message}`),terminal=`aborted`,payload.executionId!=null&&await this.reportExecutionState(payload.executionId,`failed`,{errorMessage:message})}finally{if(payload.taskId!=null&&terminal&&await this.releaseTaskWorkspace(terminal,{taskId:payload.taskId,...payload.title?{title:payload.title}:{},...payload.repo?.repoId?{repoId:payload.repo.repoId}:{},defaultBranch:payload.repo?.defaultBranch??null}),payload.executionId!=null){let late=this.lateSteers.drain(payload.executionId);late.length>0&&this.reportLateSteers(payload.executionId,`run_finishing`,late)}}}async finalizeTask(payload){await this.releaseTaskWorkspace(`done`,payload)}async releaseTaskWorkspace(state,payload){let baseDir=this.opts.workspaceDir??process.cwd(),dir=taskWorkspaceDir(baseDir,payload.taskId),repoId=payload.repoId,preserve=repoId?async()=>{await isCloned(dir)&&await this.commitAndPushTicketBranch(payload.taskId,{repoId,defaultBranch:payload.defaultBranch??null},payload.title??`Task ${payload.taskId}`,`BuilderForce`)}:void 0;(await releaseTaskWorkspaceOnTerminal({baseDir,taskId:payload.taskId,state,...preserve?{preserve}:{}})).released||logWarn(`[builderforce] task ${payload.taskId}: workspace release (${state}) did not complete`)}async handleAgentDispatch(dispatchId){let workspaceDir=this.opts.workspaceDir??process.cwd();try{await runCodingDispatch({http:makeCodingHttp({baseUrl:this.opts.baseUrl,agentNodeId:this.opts.agentNodeId,apiKey:this.opts.apiKey}),git:makeCodingGit({apiKey:this.opts.apiKey}),fs:makeCodingFs(),agent:makeCodingAgent(()=>this.gatewayClient),baseUrl:normalizeBaseUrl(this.opts.baseUrl),workspaceDir,joinPath:(...parts)=>path.join(...parts)},dispatchId)}catch(err){logWarn(`[builderforce] agent_dispatch ${dispatchId} failed: ${String(err)}`)}}persistToolAudit(event){this.toolAudit.persist(event)}async reportLateSteers(executionId,reason,steers){let url=`${normalizeBaseUrl(this.opts.baseUrl)}/api/agent-hosts/${this.opts.agentNodeId}/late-steers`,handled=!1;try{let res=await fetch(url,{method:`POST`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${this.opts.apiKey}`},body:JSON.stringify(buildLateSteerReport(executionId,reason,steers)),signal:AbortSignal.timeout(15e3)});if(res.ok){let body=await res.json().catch(()=>null);handled=typeof body?.outcome?.kind==`string`&&body.outcome.kind!==`none`}}catch(err){logDebug(`[builderforce-relay] late-steer report failed: ${String(err)}`)}if(!handled)for(let steer of steers)this.persistToolAudit({executionId,toolName:`steer.dropped`,category:`message`,args:{text:steer.text,reason},result:`This message arrived after the run's last turn and could not be handed back for a follow-up run; send it again as a follow-up.`})}async reportExecutionState(executionId,status,extra){let url=`${normalizeBaseUrl(this.opts.baseUrl)}/api/agent-hosts/${this.opts.agentNodeId}/executions/${executionId}/state`;try{await fetch(url,{method:`PATCH`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${this.opts.apiKey}`},body:JSON.stringify({status,...extra}),signal:AbortSignal.timeout(1e4)}),logDebug(`[builderforce-relay] execution ${executionId} → ${status}`)}catch(err){logDebug(`[builderforce-relay] execution state report failed: ${String(err)}`)}}constructor(opts){this.opts=opts,this.ws=null,this.closed=!1,this.backoffMs=1e3,this.gatewayClient=null,this.pendingExecutionId=null,this.v2Aborts=new Map,this.v2Steering=new Map,this.lateSteers=createLateSteerRegistry(),this.pendingRemoteCorrelations=new Map,this.remoteDispatchOpts=null,this.remoteChunks=createRemoteChunkQueue(chunk=>this.remoteDispatchOpts?dispatchChunkToRemoteAgentNode(this.remoteDispatchOpts,chunk.callbackAgentNodeId,chunk.correlationId,chunk.piece):Promise.resolve(),err=>logDebug(`[builderforce-relay] remote chunk dispatch failed: ${String(err)}`)),this.upstreamWsUrl=`${normalizeBaseUrl(opts.baseUrl).replace(/^https:/,`wss:`).replace(/^http:/,`ws:`)}/api/agent-hosts/${opts.agentNodeId}/upstream`,this.heartbeatHttpUrl=`${normalizeBaseUrl(opts.baseUrl)}/api/agent-hosts/${opts.agentNodeId}/heartbeat`,this.assignmentContextUrl=`${normalizeBaseUrl(opts.baseUrl)}/api/agent-hosts/${opts.agentNodeId}/assignment-context`,this.gatewayWsUrl=opts.gatewayUrl??`ws://127.0.0.1:18789`,this.toolAudit=createToolAuditPersister({url:`${normalizeBaseUrl(opts.baseUrl)}/api/agent-hosts/${opts.agentNodeId}/tool-audit`,apiKey:opts.apiKey,onError:err=>logDebug(`[builderforce-relay] tool-audit persist failed: ${String(err)}`),sendLive:frame=>this.trySendToRelay(frame)}),this.heartbeat=new RelayHeartbeat({heartbeatUrl:this.heartbeatHttpUrl,apiKey:opts.apiKey,workspaceDir:opts.workspaceDir}),this.logPoller=new RelayLogPoller(()=>this.gatewayClient,msg=>this.sendToRelay(msg),()=>this.pendingExecutionId),this.presencePoller=new RelayPresencePoller(()=>this.gatewayClient,msg=>this.sendToRelay(msg))}setRemoteDispatchOptions(opts){this.remoteDispatchOpts=opts}async fetchRemoteContext(remoteAgentNodeId){if(!this.opts.workspaceDir)return;let url=`${normalizeBaseUrl(this.opts.baseUrl)}/api/agent-hosts/${encodeURIComponent(remoteAgentNodeId)}/context-bundle`,bundle;try{let res=await fetch(url,{headers:{Authorization:`Bearer ${this.opts.apiKey}`},signal:AbortSignal.timeout(15e3)});if(!res.ok){logDebug(`[builderforce-relay] context-bundle for agentNode ${remoteAgentNodeId} failed: ${res.status}`);return}bundle=await res.json()}catch(err){logDebug(`[builderforce-relay] fetchRemoteContext error: ${String(err)}`);return}if(!Array.isArray(bundle.files)||bundle.files.length===0)return;let targetDir=path.join(this.opts.workspaceDir,`.builderForceAgents`,`remote-context`,remoteAgentNodeId);for(let file of bundle.files){if(typeof file.path!=`string`||typeof file.content!=`string`)continue;let safeName=file.path.replace(/\\/g,`/`).replace(/^[./]+/,``).replace(/\.\.\//g,``);if(!safeName)continue;let destPath=path.join(targetDir,safeName),existingSha=null;try{let existing=await fs$1.readFile(destPath,`utf-8`);existingSha=createHash(`sha256`).update(existing,`utf-8`).digest(`hex`)}catch{}existingSha!==file.sha256&&(await fs$1.mkdir(path.dirname(destPath),{recursive:!0}),await fs$1.writeFile(destPath,file.content,`utf-8`),logDebug(`[builderforce-relay] wrote remote context file: ${safeName}`))}}start(){this.closed||(setRelayHook((event,payload)=>{this.sendToRelay({type:`event`,event,payload})}),sweepStaleTaskWorkspaces(this.opts.workspaceDir??process.cwd(),{activeTaskIds:[]}).then(({removed})=>{removed.length&&logWarn(`[builderforce] swept ${removed.length} stale ticket workspace(s)`)}).catch(()=>{}),this.connectUpstream(),this.connectLocalGateway(),this.startRemoteResultTracking())}stop(){this.closed=!0,setRelayHook(null),this.heartbeat.clear(),this.logPoller.clear(),this.presencePoller.clear(),this.ws?.close(1e3,`stopped`),this.ws=null,this.gatewayClient?.stop(),this.gatewayClient=null,this.remoteChunks.close(),this.toolAudit.flush({final:!0}),this.toolAudit.close()}startRemoteResultTracking(){onAgentEvent(evt=>{if(this.closed||evt.stream!==`lifecycle`)return;let phase=evt.data.phase;if(phase!==`end`&&phase!==`error`)return;let sessionKey=evt.sessionKey??``,correlation=this.pendingRemoteCorrelations.get(sessionKey);if(!correlation)return;let chunksSent=this.remoteChunks.flush(sessionKey);this.pendingRemoteCorrelations.delete(sessionKey);let errorVal=evt.data.error,errorStr=typeof errorVal==`string`?errorVal:`unknown error`,fallback=typeof evt.data.summary==`string`?evt.data.summary:phase===`error`?`Remote task failed: ${errorStr}`:`Remote task completed on agentNode ${this.opts.agentNodeId}`,resultText=correlation.accumulated.trim()||fallback;chunksSent.then(()=>{this.remoteDispatchOpts&&dispatchResultToRemoteAgentNode(this.remoteDispatchOpts,correlation.callbackAgentNodeId,correlation.correlationId,resultText)})})}captureRemoteOutput(sessionKey,piece,replace=!1){let corr=this.pendingRemoteCorrelations.get(sessionKey);if(!(!corr||!piece)){if(replace){if(corr.accumulated)return;corr.accumulated=piece}else corr.accumulated+=piece;this.remoteChunks.enqueue(sessionKey,{callbackAgentNodeId:corr.callbackAgentNodeId,correlationId:corr.correlationId,piece})}}connectUpstream(){if(this.closed)return;let ws=new WebSocket$1(this.upstreamWsUrl,{headers:{Authorization:`Bearer ${this.opts.apiKey}`}});this.ws=ws,ws.on(`open`,()=>{logWarn(`[builderforce-relay] upstream connected`),this.backoffMs=1e3,this.heartbeat.schedule(),this.syncAssignmentContext(`ws-open`)}),ws.on(`message`,raw=>{try{let rawText=typeof raw==`string`?raw:raw instanceof Buffer?raw.toString(`utf-8`):Array.isArray(raw)?Buffer.concat(raw).toString(`utf-8`):raw instanceof ArrayBuffer?Buffer.from(new Uint8Array(raw)).toString(`utf-8`):``,msg=JSON.parse(rawText);this.handleRelayMessage(msg)}catch{}}),ws.on(`close`,()=>{this.ws===ws&&(this.ws=null,this.heartbeat.clear(),logWarn(`[builderforce-relay] upstream disconnected — reconnecting…`),this.scheduleReconnect())}),ws.on(`error`,err=>{logWarn(`[builderforce-relay] upstream error: ${String(err)}`)})}handleRelayMessage(msg){let type=typeof msg.type==`string`?msg.type:``;switch(type){case`relay_connected`:logDebug(`[builderforce-relay] relay acknowledged connection`);break;case`ping`:break;case`chat`:{let message=typeof msg.message==`string`?msg.message:``,session=typeof msg.session==`string`?msg.session:`main`;this.gatewayClient?.request(`chat.send`,{sessionKey:session,message,idempotencyKey:randomUUID()}).catch(err=>{logDebug(`[builderforce-relay] chat.send failed: ${String(err)}`)});break}case`chat.abort`:this.gatewayClient?.request(`chat.abort`,{}).catch(()=>{});break;case`session.new`:this.gatewayClient?.request(`chat.new`,{}).catch(()=>{});break;case`logs.subscribe`:this.logPoller.start(!0);break;case`presence.subscribe`:this.presencePoller.start();break;case`rpc.call`:{let requestId=typeof msg.requestId==`string`&&msg.requestId.trim().length>0?msg.requestId:randomUUID(),method=typeof msg.method==`string`?msg.method.trim():``,params=msg.params&&typeof msg.params==`object`&&!Array.isArray(msg.params)?msg.params:{};if(!method){this.sendToRelay({type:`rpc.error`,requestId,method,error:`method required`});break}this.gatewayClient?.request(method,params).then(result=>{this.sendToRelay({type:`rpc.result`,requestId,method,result})}).catch(err=>{this.sendToRelay({type:`rpc.error`,requestId,method,error:String(err)})});break}case`host.egress.request`:{let requestId=typeof msg.requestId==`string`?msg.requestId:``;if(!requestId)break;performHostEgress({requestId,method:typeof msg.method==`string`?msg.method:`POST`,url:typeof msg.url==`string`?msg.url:void 0,headers:msg.headers&&typeof msg.headers==`object`&&!Array.isArray(msg.headers)?msg.headers:{},body:typeof msg.body==`string`?msg.body:null},{...this.opts.ollamaLocalOrigin?{allowedLocalOrigin:this.opts.ollamaLocalOrigin}:{},...this.opts.freetokenLocalOrigin?{allowedFreetokenOrigin:this.opts.freetokenLocalOrigin}:{}}).then(frame=>{this.sendToRelay(frame)});break}case`remote.task`:{let task=typeof msg.task==`string`?msg.task:``,fromAgentNodeId=typeof msg.fromAgentNodeId==`string`?msg.fromAgentNodeId:`unknown`,correlationId=typeof msg.correlationId==`string`?msg.correlationId:``,callbackAgentNodeId=typeof msg.callbackAgentNodeId==`string`?msg.callbackAgentNodeId:``,callbackBaseUrl=typeof msg.callbackBaseUrl==`string`?msg.callbackBaseUrl:``;if(!task)break;logDebug(`[builderforce-relay] remote task from agentNode ${fromAgentNodeId}: ${task.slice(0,80)}…`);let sessionKey=correlationId?`remote-${correlationId}`:`main`;correlationId&&callbackAgentNodeId&&this.pendingRemoteCorrelations.set(sessionKey,{correlationId,callbackAgentNodeId,callbackBaseUrl,accumulated:``}),this.gatewayClient?.request(`chat.send`,{sessionKey,message:`[Remote task from agentNode ${fromAgentNodeId}]\n\n${task}`,idempotencyKey:`remote-${fromAgentNodeId}-${correlationId||Date.now()}`}).catch(err=>{logDebug(`[builderforce-relay] remote.task dispatch failed: ${String(err)}`)});break}case`remote.task.result`:case`remote.result`:case`remote.task.chunk`:case`remote.result.chunk`:{let parsed=parseRemoteCallbackFrame(msg);if(!parsed)break;if(parsed.kind===`chunk`){let delivered=pushRemoteResultChunk(parsed.correlationId,parsed.chunk);delivered&&parsed.chunk&&this.sendToRelay({type:`chat.delta`,delta:parsed.chunk,session:`remote-${parsed.correlationId}`}),logDebug(`[builderforce-relay] remote.task.chunk ${parsed.correlationId}: ${delivered?`delivered`:`no waiter`}`);break}let resolved=resolveRemoteResult(parsed.correlationId,parsed.result);logDebug(`[builderforce-relay] remote.task.result ${parsed.correlationId}: ${resolved?`resolved`:`no pending callback`}`);break}case`task.assign`:case`task.broadcast`:{let taskRecord=msg.task&&typeof msg.task==`object`?msg.task:null,title=typeof taskRecord?.title==`string`?taskRecord.title.trim():``,description=typeof taskRecord?.description==`string`?taskRecord.description.trim():``,executionId=typeof msg.executionId==`number`&&Number.isFinite(msg.executionId)?msg.executionId:void 0,taskId=typeof msg.taskId==`number`&&Number.isFinite(msg.taskId)?msg.taskId:void 0,rawArtifacts=msg.artifacts&&typeof msg.artifacts==`object`?msg.artifacts:void 0,artifacts=rawArtifacts?{skills:Array.isArray(rawArtifacts.skills)?rawArtifacts.skills:void 0,personas:Array.isArray(rawArtifacts.personas)?rawArtifacts.personas:void 0,content:Array.isArray(rawArtifacts.content)?rawArtifacts.content:void 0}:void 0;if(!title&&!description){logWarn(`[builderforce] received ${type} without task content`);break}let engine=typeof msg.engine==`string`?msg.engine:CURRENT_ENGINE_ID,model,policyGates=[];try{let p=typeof msg.payload==`string`?JSON.parse(msg.payload):null;p&&typeof p.model==`string`&&p.model.trim()&&(model=p.model.trim()),p&&(policyGates=coercePolicyGates(p.policyGates))}catch{}let repoRaw=msg.repo&&typeof msg.repo==`object`?msg.repo:null,repo=repoRaw&&typeof repoRaw.repoId==`string`?{repoId:repoRaw.repoId,defaultBranch:typeof repoRaw.defaultBranch==`string`?repoRaw.defaultBranch:null}:void 0,agentLabel=typeof msg.agentLabel==`string`?msg.agentLabel:void 0;logWarn(`[builderforce] received ${type}${taskId==null?``:` task=${taskId}`}${executionId==null?``:` execution=${executionId}`} engine=${engine}`),this.dispatchTaskFromRelay({sourceType:type,title:title||`Assigned task`,description:description||void 0,executionId,taskId,artifacts,engine,model,repo,agentLabel,...policyGates.length?{policyGates}:{}}),this.syncAssignmentContext(type);break}case`execution.message`:{let executionId=typeof msg.executionId==`number`&&Number.isFinite(msg.executionId)?msg.executionId:void 0,channel=executionId==null?void 0:this.v2Steering.get(executionId);if(channel&&channel.push(msg.text))break;let steer=lateSteerFromFrame(msg);if(executionId==null||!steer)break;if(this.lateSteers.hold(executionId,steer)){logWarn(`[builderforce] steer for execution ${executionId} arrived after the run's last turn — it will continue as a follow-up run`);break}logWarn(`[builderforce] steer for execution ${executionId} has no live V2 run on this host — handing it back for a follow-up run`),this.reportLateSteers(executionId,`no_live_run`,[steer]);break}case`execution.cancel`:{let executionId=typeof msg.executionId==`number`&&Number.isFinite(msg.executionId)?msg.executionId:void 0;if(logWarn(`[builderforce] cancel execution ${executionId??`?`}`),executionId!=null){let ctrl=this.v2Aborts.get(executionId);if(ctrl)try{ctrl.abort()}catch{}}this.gatewayClient?.request(`chat.abort`,{}).catch(()=>{});break}case`task.finalize`:{let finalizeTaskId=typeof msg.taskId==`number`&&Number.isFinite(msg.taskId)?msg.taskId:void 0;if(finalizeTaskId==null)break;let repoRaw=msg.repo&&typeof msg.repo==`object`?msg.repo:null;this.finalizeTask({taskId:finalizeTaskId,title:typeof msg.title==`string`?msg.title:void 0,repoId:repoRaw&&typeof repoRaw.repoId==`string`?repoRaw.repoId:void 0,defaultBranch:repoRaw&&typeof repoRaw.defaultBranch==`string`?repoRaw.defaultBranch:null});break}case`agent_dispatch`:{let dispatchId=typeof msg.dispatchId==`string`?msg.dispatchId:``;if(!dispatchId){logWarn(`[builderforce] agent_dispatch without dispatchId`);break}logWarn(`[builderforce] received agent_dispatch dispatch=${dispatchId}`),this.handleAgentDispatch(dispatchId);break}case`approval.decision`:{let approvalId=typeof msg.approvalId==`string`?msg.approvalId:``,decision=typeof msg.status==`string`?msg.status:``,responseText=typeof msg.responseText==`string`?msg.responseText:void 0;approvalId&&(decision===`approved`||decision===`rejected`||decision===`answered`)&&(logWarn(`[builderforce-relay] approval.decision ${approvalId}: ${decision}`),resolveApproval(approvalId,decision,responseText));break}default:break}}sendToRelay(msg){this.trySendToRelay(msg)}trySendToRelay(msg){if(this.ws?.readyState!==WebSocket$1.OPEN)return!1;try{return this.ws.send(JSON.stringify(msg)),!0}catch(err){return logDebug(`[builderforce-relay] relay send failed: ${String(err)}`),!1}}scheduleReconnect(){if(this.closed)return;let delay=this.backoffMs;this.backoffMs=Math.min(this.backoffMs*2,3e4),setTimeout(()=>this.connectUpstream(),delay).unref()}connectLocalGateway(){let gw=new GatewayClient({url:this.gatewayWsUrl,onEvent:evt=>this.handleGatewayEvent(evt),onConnectError:err=>{logDebug(`[builderforce-relay] local gateway connect error: ${String(err)}`)}});this.gatewayClient=gw,gw.start()}handleGatewayEvent(evt){if(evt.event!==`chat`)return;let p=evt.payload,legacy=evt.payload;if(p){if(legacy&&typeof legacy.state==`string`){let session=legacy.sessionKey??`main`;if(legacy.state===`final`){let text=extractChatText(legacy.message),role=extractChatRole(legacy.message);if(text&&this.sendToRelay({type:`chat.message`,role,text,session}),resolveCodingSession(session,{ok:!0,text}))return;if(this.pendingExecutionId!=null){let eid=this.pendingExecutionId;this.pendingExecutionId=null,this.reportExecutionState(eid,`completed`,{result:text||void 0})}return}if(legacy.state===`error`){let text=legacy.errorMessage?.trim();if(text&&this.sendToRelay({type:`chat.message`,role:`assistant`,text:`[error] ${text}`,session}),resolveCodingSession(session,{ok:!1,text:text??`agent error`}))return;if(this.pendingExecutionId!=null){let eid=this.pendingExecutionId;this.pendingExecutionId=null,this.reportExecutionState(eid,`failed`,{errorMessage:text||void 0})}return}}switch(p.type){case`delta`:{let session=p.sessionKey??`main`,delta=p.delta??``;this.sendToRelay({type:`chat.delta`,delta,session}),this.captureRemoteOutput(session,delta);break}case`message`:{let session=p.sessionKey??`main`,text=p.text??``;this.sendToRelay({type:`chat.message`,role:p.role??`assistant`,text,session}),this.captureRemoteOutput(session,text,!0);break}case`tool_use`:this.sendToRelay({type:`tool.start`,toolCallId:p.toolCallId,toolName:p.toolName,toolInput:p.toolInput,session:p.sessionKey??`main`});break;case`tool_result`:this.sendToRelay({type:`tool.result`,toolCallId:p.toolCallId,toolResult:p.toolResult,session:p.sessionKey??`main`});break;case`abort`:this.sendToRelay({type:`chat.abort`,session:p.sessionKey??`main`});break;default:break}}}async syncAssignmentContext(reason){if(this.opts.workspaceDir)try{let response=await fetch(this.assignmentContextUrl,{method:`GET`,headers:{Authorization:`Bearer ${this.opts.apiKey}`},signal:AbortSignal.timeout(1e4)});if(!response.ok){logDebug(`[builderforce-relay] assignment-context ${reason} failed: ${response.status}`);return}let assignmentContext=await response.json(),context=await loadProjectContext(this.opts.workspaceDir);if(!context)return;let machineProfile=buildLocalMachineProfile({workspaceDirectory:this.opts.workspaceDir,rootInstallDirectory:process.cwd(),gatewayPort:18789,tunnelUrl:process.env.BUILDERFORCE_AGENTS_PUBLIC_TUNNEL_URL,tunnelStatus:process.env.BUILDERFORCE_AGENTS_PUBLIC_TUNNEL_URL?`connected`:`none`}),builderforce=mergeBuilderforceContext({existing:context.builderforce,assignmentContext,fallback:{instanceId:this.opts.agentNodeId,url:this.opts.baseUrl},machineProfile});await updateProjectContextFields(this.opts.workspaceDir,{builderforce})}catch(err){logDebug(`[builderforce-relay] assignment-context ${reason} failed: ${String(err)}`)}}};function transportKindForTarget(target){return target.startsWith(`remote:`)?`remote`:`local`}var CompositeAgentTransport=class{constructor(transports){this.transports=transports}has(kind){return!!this.transports[kind]}async discover(requiredCapabilities=[]){return(await Promise.all(Object.values(this.transports).map(t=>t.discover(requiredCapabilities)))).flat()}async dispatch(payload){let kind=transportKindForTarget(payload.target),transport=this.transports[kind];return transport?transport.dispatch(payload):{status:`failed`,error:kind===`remote`?`Remote dispatch not configured — set BUILDERFORCE_API_KEY and builderforce.instanceId.`:`Local dispatch not configured.`}}};function nextCronDate(expr,after){let parts=expr.trim().split(/\s+/);if(parts.length!==5)return null;let[mE,hE,,,]=parts;return(base=>{let d=new Date(base);d.setSeconds(0,0);let matchField=(val,field)=>{if(field===`*`)return!0;if(field.startsWith(`*/`)){let step=Number(field.slice(2));return Number.isFinite(step)&&step>0&&val%step===0}return val===Number(field)};for(let i=0;i<1440;i++)if(d.setMinutes(d.getMinutes()+1),matchField(d.getMinutes(),mE)&&matchField(d.getHours(),hE))return d;return null})(after)}var CronPollerService=class{constructor(opts){this.opts=opts,this.timers=new Map,this.jobs=[],this.pollTimer=null,this.closed=!1,this.gatewayClient=new GatewayClient({url:opts.gatewayUrl??`ws://127.0.0.1:18789`,onEvent:()=>{},onConnectError:()=>{}})}async start(){if(isOfflineMode()){logDebug(`[cron-poller] offline mode — skipping control-plane polling`);return}this.gatewayClient.start(),await this.fetchAndSchedule(),this.pollTimer=setInterval(()=>void this.fetchAndSchedule(),300*1e3)}stop(){this.closed=!0,this.pollTimer&&=(clearInterval(this.pollTimer),null);for(let timer of this.timers.values())clearTimeout(timer);this.timers.clear(),this.gatewayClient.stop()}async fetchAndSchedule(){let url=`${normalizeBaseUrl(this.opts.baseUrl)}/api/agent-hosts/${this.opts.agentNodeId}/cron`;try{let res=await fetch(url,{headers:{Authorization:`Bearer ${this.opts.apiKey}`},signal:AbortSignal.timeout(1e4)});if(!res.ok){logWarn(`[cron-poller] fetch failed: ${res.status}`);return}this.jobs=((await res.json()).jobs??[]).filter(j=>j.enabled),logDebug(`[cron-poller] loaded ${this.jobs.length} enabled job(s)`),this.rescheduleAll()}catch(err){logWarn(`[cron-poller] fetch error: ${String(err)}`)}}rescheduleAll(){for(let timer of this.timers.values())clearTimeout(timer);this.timers.clear();let now=new Date;for(let job of this.jobs){let next=nextCronDate(job.schedule,now);if(!next){logWarn(`[cron-poller] job "${job.name}" has unparseable schedule: ${job.schedule}`);continue}let delay=next.getTime()-Date.now();logDebug(`[cron-poller] job "${job.name}" next run in ${Math.round(delay/1e3)}s`);let timer=setTimeout(()=>void this.fireJob(job),delay);this.timers.set(job.id,timer)}}async fireJob(job){if(this.closed)return;logWarn(`[cron-poller] firing job "${job.name}" (${job.id})`);let lastStatus=`success`;try{let sessionKey=job.projectAgentId==null?`main`:`project-agent-${job.projectAgentId}`,agentLine=job.projectAgentId==null?``:`\nProject agent: #${job.projectAgentId}`;await this.gatewayClient.request(`chat.send`,{sessionKey,message:`[Scheduled job: ${job.name}]\n\nRun cron task: ${job.name}${job.taskId==null?``:` (task #${job.taskId})`}${agentLine}`,idempotencyKey:`cron-${job.id}-${Date.now()}`})}catch(err){logWarn(`[cron-poller] job "${job.name}" dispatch failed: ${String(err)}`),lastStatus=`error`}this.patchJobStatus(job.id,lastStatus);let next=nextCronDate(job.schedule,new Date);if(next&&!this.closed){let delay=next.getTime()-Date.now(),timer=setTimeout(()=>void this.fireJob(job),delay);this.timers.set(job.id,timer)}}async patchJobStatus(jobId,status){let url=`${normalizeBaseUrl(this.opts.baseUrl)}/api/agent-hosts/${this.opts.agentNodeId}/cron/${jobId}`;try{await fetch(url,{method:`PATCH`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${this.opts.apiKey}`},body:JSON.stringify({lastRunAt:new Date().toISOString(),lastStatus:status}),signal:AbortSignal.timeout(1e4)})}catch(err){logDebug(`[cron-poller] status patch failed for job ${jobId}: ${String(err)}`)}}},GatewayLlmService=class{constructor(opts){this.opts=opts}async complete(req){let messages=[];req.system&&messages.push({role:`system`,content:req.system}),messages.push({role:`user`,content:req.prompt});try{return(await nativeComplete(this.opts,{messages,...req.model?{model:req.model}:{},...req.temperature==null?{}:{temperature:req.temperature},...req.provider?{extra:{provider:req.provider}}:{}},AbortSignal.timeout(12e4))).content}catch(err){return logDebug(`[gateway-llm] complete failed: ${String(err)}`),`[llm] request failed: ${err instanceof Error?err.message:String(err)}`}}};function authHeaders$1(cfg){return{Authorization:`Bearer ${cfg.apiKey}`,"X-AgentHost-Id":String(cfg.agentHostId)}}function clampLearnWeight(weight){return Math.max(.05,Math.min(1,typeof weight==`number`&&weight>0?weight:.6))}async function contributeProjectEvermindFromText(cfg,text,prompt,weight){let trimmed=(text??``).trim();if(trimmed.length<20)return{ok:!1,reason:`text too short`};let promptTrimmed=(prompt??``).trim(),learnWeight=clampLearnWeight(weight);try{let res=await fetch(`${cfg.gatewayUrl}/api/agent/projects/${cfg.projectId}/evermind/learn-text`,{method:`POST`,headers:{...authHeaders$1(cfg),"Content-Type":`application/json`},body:JSON.stringify({text:trimmed.slice(0,cfg.maxChars??8e3),...promptTrimmed?{prompt:promptTrimmed.slice(0,cfg.maxChars??8e3)}:{},weight:learnWeight})}),body=await res.json().catch(()=>({}));return res.ok?{ok:!0,...typeof body.baseVersion==`number`?{version:body.baseVersion}:{}}:{ok:!1,reason:typeof body.error==`string`?body.error:`learn-text ${res.status}`}}catch(err){return{ok:!1,reason:String(err)}}}async function loadDeltaEngine(){try{let mod=await Function(`m`,`return import(m)`)(`@seanhogg/builderforce-memory-engine`);return!mod?.EvermindModelPackage||!mod.BPETokenizer||typeof mod.adaptAndDiff!=`function`||typeof mod.buildDeltaLearnPayload!=`function`||typeof mod.MAX_DELTA_B64_CHARS!=`number`?null:mod}catch{return null}}function buildDeltaPayload(engine,base,text,weight,label){let pkg=engine.EvermindModelPackage.fromBlob(base.model);if(pkg.manifest.modelType!==`evermind-lm`)return null;let tok=new engine.BPETokenizer;tok.loadFromObjects(base.tokenizer.vocab,base.tokenizer.merges);let adapted=engine.adaptAndDiff(pkg,tok,text);return adapted?engine.buildDeltaLearnPayload(adapted.diff,base.version,weight,label):null}function agentBase(cfg){return`${cfg.gatewayUrl}/api/agent/projects/${cfg.projectId}/evermind`}async function fetchHeadVersion(cfg){try{let res=await fetch(`${agentBase(cfg)}/head`,{headers:authHeaders$1(cfg)});if(!res.ok)return null;let body=await res.json().catch(()=>({})),version=typeof body.version==`number`?body.version:0;return version<=0?null:{version,frozen:body.mode===`offline-frozen`}}catch{return null}}async function fetchBase(cfg,version){try{let q=`?version=${version}`,[modelRes,tokRes]=await Promise.all([fetch(`${agentBase(cfg)}/model${q}`,{headers:authHeaders$1(cfg)}),fetch(`${agentBase(cfg)}/tokenizer${q}`,{headers:authHeaders$1(cfg)})]);if(!modelRes.ok||!tokRes.ok)return null;let model=await modelRes.arrayBuffer(),tokenizer=await tokRes.json();return!tokenizer?.vocab||!Array.isArray(tokenizer.merges)?null:{version,model,tokenizer:{vocab:tokenizer.vocab,merges:tokenizer.merges}}}catch{return null}}async function pushDelta(cfg,payload){try{let res=await fetch(`${agentBase(cfg)}/learn`,{method:`POST`,headers:{...authHeaders$1(cfg),"Content-Type":`application/json`},body:JSON.stringify(payload)}),body=await res.json().catch(()=>({}));return res.ok?{ok:!0,version:payload.baseVersion}:res.status===409&&typeof body.headVersion==`number`?{ok:!1,staleHeadVersion:body.headVersion,reason:`stale base`}:res.status===409&&body.code===`evermind_inherited_read_only`?{ok:!1,terminal:!0,reason:typeof body.error==`string`?body.error:`this build inherits project ${String(body.inheritedFromProjectId??`?`)}'s Evermind`}:{ok:!1,reason:typeof body.error==`string`?body.error:`learn ${res.status}`}}catch(err){return{ok:!1,reason:String(err)}}}async function contributeProjectEvermindFromDelta(cfg,text,prompt,weight,deps){let trimmed=(text??``).trim();if(trimmed.length<20)return{ok:!1,reason:`text too short`};let learnWeight=clampLearnWeight(weight),toText=async reason=>({...await contributeProjectEvermindFromText(cfg,trimmed,prompt,learnWeight),delta:!1,fellBackToText:!0,reason}),engine=await(deps?.loadEngine??loadDeltaEngine)();if(!engine)return toText(`engine unavailable`);let head=await fetchHeadVersion(cfg);if(!head||head.frozen)return toText(head?`offline-frozen`:`no seeded head`);let label=(prompt??``).trim()||void 0;for(let attempt=0,baseVersion=head.version;attempt<2;attempt++){let base=await fetchBase(cfg,baseVersion);if(!base)return toText(`base artifact unavailable`);let payload;try{payload=buildDeltaPayload(engine,base,trimmed,learnWeight,label)}catch(err){return toText(`adapt failed: ${String(err)}`)}if(!payload)return toText(`nothing trainable in this run`);if(payload.diff.length>engine.MAX_DELTA_B64_CHARS)return toText(`delta exceeds the gateway's size cap`);let outcome=await pushDelta(cfg,payload);if(outcome.ok)return{ok:!0,delta:!0,version:outcome.version??baseVersion,...attempt>0?{rebased:!0}:{}};if(outcome.staleHeadVersion&&outcome.staleHeadVersion!==baseVersion){baseVersion=outcome.staleHeadVersion;continue}return outcome.terminal?{ok:!1,reason:outcome.reason??`delta rejected`}:toText(outcome.reason??`delta rejected`)}return toText(`lost the rebase race twice`)}function authHeaders(cfg){return{Authorization:`Bearer ${cfg.apiKey}`,"X-AgentHost-Id":String(cfg.agentHostId)}}async function pushProjectFact(cfg,key,content){if(!key.trim()||!content.trim())return!1;try{return(await fetch(`${cfg.gatewayUrl}/api/agent/projects/${cfg.projectId}/facts`,{method:`POST`,headers:{...authHeaders(cfg),"Content-Type":`application/json`},body:JSON.stringify({key:key.slice(0,255),content,source:`onprem`})})).ok}catch{return!1}}async function recallSharedProjectFacts(cfg,query,limit=6){try{let qs=new URLSearchParams;query&&qs.set(`query`,query),qs.set(`limit`,String(limit));let res=await fetch(`${cfg.gatewayUrl}/api/agent/projects/${cfg.projectId}/facts?${qs.toString()}`,{headers:authHeaders(cfg)});if(!res.ok)return[];let j=await res.json();return Array.isArray(j.facts)?j.facts:[]}catch{return[]}}const DEFAULT_BUILDERFORCE_URL=`https://api.builderforce.ai`;function deltaPathEnabled(){let raw=(process.env.BUILDERFORCE_EVERMIND_DELTA??``).trim().toLowerCase();return raw===`1`||raw===`true`||raw===`yes`}function buildKnowledgeMemoryEntry(params){return buildKnowledgeMemoryEntry$1({sessionKey:params.sessionKey,ts:params.ts,activity:params.acc?{created:params.acc.filesCreated,edited:params.acc.filesEdited,tools:params.acc.toolNames}:void 0})}var KnowledgeLoopService=class{constructor(opts){this.opts=opts,this.runs=new Map,this.unsub=null}start(){this.unsub||(registerKnowledgeLoop(this),registerTeamMemoryContextBuilder(async()=>{let typed=await this.pullTeamMemory(5);if(!typed||typed.length===0)return``;let lines=[`[Team Memory Context]`];for(let entry of typed){let who=entry.agentNodeId?`agentNode:${entry.agentNodeId}`:`unknown`,when=entry.timestamp?` (${entry.timestamp.slice(0,10)})`:``;lines.push(`- [${who}${when}] ${entry.summary??``}`)}lines.push(`[End Team Memory Context]`);let cfg=this.projectEvermindConfig();if(cfg){let facts=await recallSharedProjectFacts(cfg,void 0,6);if(facts.length>0){lines.push(`[Project memory — durable facts recalled for this project]`);for(let f of facts)lines.push(`- ${f.content}`)}}return lines.join(`
196
196
  `)+`
197
197
  `}),this.unsub=onAgentEvent(evt=>{this.unsub&&(evt.stream===`tool`&&this.accumulate(evt.runId,evt.sessionKey??`unknown`,evt.data),evt.stream===`lifecycle`&&typeof evt.data.phase==`string`&&(evt.data.phase===`end`||evt.data.phase===`error`)&&this.onRunComplete(evt.runId,evt.sessionKey??`unknown`))}),logDebug(`[knowledge-loop] started`))}stop(){this.unsub&&=(this.unsub(),null),this.runs.clear();let ssmSvc=getSsmMemoryService();ssmSvc&&ssmSvc.flush().catch(err=>{logDebug(`[ssm-memory] flush on stop failed: ${String(err)}`)}),logDebug(`[knowledge-loop] stopped`)}accumulate(runId,sessionKey,data){if(!this.runs.has(runId)){let prompt=getAgentRunContext(runId)?.prompt;this.runs.set(runId,{sessionKey,filesCreated:[],filesEdited:[],toolNames:[],...prompt?{prompt}:{}})}let acc=this.runs.get(runId),toolName=typeof data.toolName==`string`?data.toolName:null;toolName&&acc.toolNames.push(toolName);let filePath=typeof data.path==`string`?data.path:null;filePath&&(toolName===`create`||toolName===`write`?acc.filesCreated.push(filePath):toolName===`edit`&&acc.filesEdited.push(filePath))}async onRunComplete(runId,sessionKey){let acc=this.runs.get(runId);this.runs.delete(runId);let created=acc?[...new Set(acc.filesCreated)]:[],edited=acc?[...new Set(acc.filesEdited)]:[],summary=deriveActivitySummary({created,edited,tools:acc?[...new Set(acc.toolNames)]:[]}),entry=buildKnowledgeMemoryEntry({ts:new Date().toISOString(),sessionKey,acc});if(!entry)return;try{await appendKnowledgeMemory(this.opts.workspaceDir,entry)}catch(err){logDebug(`[knowledge-loop] failed to write memory entry: ${String(err)}`)}let ssmSvc=getSsmMemoryService();if(ssmSvc&&summary){try{await ssmSvc.remember(runId,summary,{tags:[`activity`],importance:.6})}catch(err){logDebug(`[ssm-memory] remember() failed: ${String(err)}`)}try{await ssmSvc.learn((entry??summary).trim())}catch(err){logDebug(`[ssm-memory] learn() failed: ${String(err)}`)}for(let{file,action}of[...created.map(file=>({file,action:`created`})),...edited.map(file=>({file,action:`edited`}))])try{let factContent=`${file} was ${action} — ${summary}`;await ssmSvc.commitFact(`file:${file}`,factContent,{tags:[`file-state`],importance:.55});let cfg=this.projectEvermindConfig();cfg&&pushProjectFact(cfg,`file:${file}`,factContent)}catch(err){logDebug(`[ssm-memory] commitFact() failed for ${file}: ${String(err)}`)}this.pushMemoryToMesh(runId,summary,[`activity`])}this.contributeToProjectEvermind((entry??summary??``).trim(),acc?.prompt,created.length+edited.length>0),await this.syncIfConfigured()}projectEvermindConfig(){let{apiKey,baseUrl,agentNodeId,projectId}=this.opts,hostId=Number(agentNodeId);return!apiKey||!Number.isInteger(hostId)||hostId<=0||!projectId?null:{gatewayUrl:baseUrl??DEFAULT_BUILDERFORCE_URL,apiKey,agentHostId:hostId,projectId:Number(projectId),deltaPath:deltaPathEnabled()}}async contributeToProjectEvermind(text,prompt,producedChanges=!1){let cfg=this.projectEvermindConfig();if(!(!cfg||text.length<20))try{let weight=producedChanges?.7:.4,res=cfg.deltaPath?await contributeProjectEvermindFromDelta(cfg,text,prompt,weight):await contributeProjectEvermindFromText(cfg,text,prompt,weight);res.ok?logDebug(`[project-evermind] contributed (base v${res.version})`):logDebug(`[project-evermind] skipped: ${res.reason}`)}catch(err){logDebug(`[project-evermind] contribution error: ${String(err)}`)}}async syncIfConfigured(){let{apiKey,baseUrl,agentNodeId,workspaceDir,projectId}=this.opts;if(!apiKey||!agentNodeId)return;let syncParams={workspaceDir,apiKey,baseUrl:baseUrl??DEFAULT_BUILDERFORCE_URL,agentNodeId,projectId};try{await syncBuilderForceAgentsDirectory(syncParams),logDebug(`[knowledge-loop] .builderforce/ synced to Builderforce`)}catch(err){logDebug(`[knowledge-loop] sync failed: ${String(err)}`)}}async pushMemoryToMesh(runId,summary,tags){let{apiKey,baseUrl,agentNodeId}=this.opts;if(!apiKey||!agentNodeId)return;let url=`${normalizeBaseUrl(baseUrl??DEFAULT_BUILDERFORCE_URL)}/api/teams/memory`,payload={agentNodeId,runId,summary,tags:tags??[],timestamp:new Date().toISOString()};try{await fetch(url,{method:`POST`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${apiKey}`,"X-AgentHost-Id":String(agentNodeId)},body:JSON.stringify(payload),signal:AbortSignal.timeout(1e4)}),logDebug(`[knowledge-loop] pushed memory to mesh: ${summary.slice(0,60)}`)}catch(err){logDebug(`[knowledge-loop] pushMemoryToMesh failed: ${String(err)}`)}}async pullTeamMemory(limit=20){let{apiKey,baseUrl,workspaceDir}=this.opts,cacheFile=path.join(workspaceDir,KNOWLEDGE_DIRS.root,KNOWLEDGE_DIRS.memory,`team-memory.json`);try{let raw=await fs$1.readFile(cacheFile,`utf-8`),cached=JSON.parse(raw);if(Date.now()-cached.ts<3e5)return cached.entries}catch{}if(!apiKey)return[];let url=`${normalizeBaseUrl(baseUrl??DEFAULT_BUILDERFORCE_URL)}/api/teams/memory?limit=${limit}`;try{let res=await fetch(url,{headers:{Authorization:`Bearer ${apiKey}`},signal:AbortSignal.timeout(1e4)});if(!res.ok)return logDebug(`[knowledge-loop] pullTeamMemory HTTP ${res.status}`),[];let data=await res.json(),entries=Array.isArray(data.entries)?data.entries:[];try{await fs$1.mkdir(path.dirname(cacheFile),{recursive:!0}),await fs$1.writeFile(cacheFile,JSON.stringify({ts:Date.now(),entries}),`utf-8`)}catch{}return entries}catch(err){return logDebug(`[knowledge-loop] pullTeamMemory failed: ${String(err)}`),[]}}};function stripLocalPrefix(target){return target.startsWith(`local:`)?target.slice(6):target}function listLocalRoles(){let builtins=getBuiltInAgentRoles(),seen=new Set(builtins.map(r=>r.name)),personas=[];for(let persona of globalPersonaRegistry.listAll()){if(seen.has(persona.name))continue;let role=findAgentRole(persona.name);role&&(personas.push(role),seen.add(persona.name))}return[...builtins,...personas]}function roleToEntry(role){return{id:role.name,name:role.name,online:!0,capabilities:role.capabilities??[],kind:`local`}}var LocalAgentTransport=class{constructor(opts){this.opts=opts}async discover(requiredCapabilities=[]){let all=listLocalRoles().map(roleToEntry);return requiredCapabilities.length===0?all:all.filter(entry=>requiredCapabilities.every(cap=>entry.capabilities.includes(cap)))}async dispatch(payload){let stripped=stripLocalPrefix(payload.target),targetId=stripped,inlineCaps=parseAutoTarget(stripped);if(inlineCaps!==null){let requiredCaps=inlineCaps.length>0?inlineCaps:payload.requiredCapabilities??[],picked=(await this.discover(requiredCaps))[0];if(!picked)return{status:`failed`,error:requiredCaps.length>0?`No local role satisfies required capabilities: ${requiredCaps.join(`, `)}`:`No local roles registered`};targetId=picked.id}let roleConfig=findAgentRole(targetId);if(!roleConfig)return{status:`failed`,error:`Unknown agent role: ${targetId}. Define it in .builderforce/personas/ or use a built-in role.`,targetId};let spawnResult=await spawnSubagentDirect({task:payload.input,label:targetId,agentId:targetId,roleConfig},this.opts.getContext());if(spawnResult.status!==`accepted`)return{status:`failed`,error:spawnResult.error||`Failed to spawn subagent`,targetId};let timeoutMs=payload.timeoutMs??this.opts.defaultTimeoutMs??6e5;try{let output=await this.opts.localResultBroker.awaitResult(spawnResult.runId??``,spawnResult.childSessionKey??``,timeoutMs);return{status:`accepted`,targetId,output,...spawnResult.childSessionKey?{childSessionKey:spawnResult.childSessionKey}:{}}}catch(err){return logDebug(`[local-agent-transport] awaitResult timed out / failed for runId=${spawnResult.runId}, childSessionKey=${spawnResult.childSessionKey}: ${String(err)}`),{status:`failed`,error:`Subagent result not received for "${targetId}": ${String(err)}`,targetId}}}};function extractText(content){if(typeof content==`string`)return content.trim();if(Array.isArray(content))return content.filter(b=>typeof b==`object`&&!!b).map(b=>typeof b.text==`string`?b.text:``).filter(Boolean).join(`
198
198
  `).trim();if(typeof content==`object`&&content){let obj=content;if(typeof obj.text==`string`)return obj.text.trim();if(typeof obj.output==`string`)return obj.output.trim();if(typeof obj.content==`string`)return obj.content.trim()}return``}async function readSubagentOutput(sessionKey){try{let history=await callGateway({method:`chat.history`,params:{sessionKey,limit:50},timeoutMs:1e4}),messages=Array.isArray(history?.messages)?history.messages:[];for(let i=messages.length-1;i>=0;i--){let msg=messages[i];if(!msg||typeof msg!=`object`)continue;let m=msg;if(m.role!==`assistant`)continue;let text=extractText(m.content??m.text);if(text)return text}}catch(err){logDebug(`[local-result-broker] chat.history failed for ${sessionKey}: ${String(err)}`)}return``}function awaitLocalSubagentResult(runId,childSessionKey,timeoutMs=6e5){return!runId||!childSessionKey?(logDebug(`[local-result-broker] awaitLocalSubagentResult called with empty runId or sessionKey`),Promise.resolve(``)):new Promise(resolve=>{let settled=!1,deadline=setTimeout(()=>{settled||(settled=!0,stop(),logDebug(`[local-result-broker] timed out waiting for runId=${runId} after ${timeoutMs}ms`),resolve(``))},timeoutMs),stop=onAgentEvent(evt=>{if(settled||evt.runId!==runId)return;let phase=typeof evt.data?.phase==`string`?evt.data.phase:null;phase!==`end`&&phase!==`error`||(settled=!0,clearTimeout(deadline),stop(),readSubagentOutput(childSessionKey).then(resolve).catch(()=>resolve(``)))})})}var WorkflowTelemetryAdapter=class{init(opts){initTelemetry(opts)}emitWorkflowStart(workflowId,description){emitWorkflowStart(workflowId,description)}emitWorkflowEnd(workflowId,failed){emitWorkflowEnd(workflowId,failed)}emitTaskStart(workflowId,taskId,agentRole,description){emitTaskStart(workflowId,taskId,agentRole,description)}emitTaskEnd(workflowId,taskId,agentRole,startedAt,error,metrics){emitTaskEnd(workflowId,taskId,agentRole,startedAt,error,metrics)}},SsmMemoryAdapter=class{async buildTeamMemoryContext(){return getSsmMemoryService()?.buildTeamMemoryContext()??Promise.resolve(``)}async recallSimilar(query,limit){return getSsmMemoryService()?.recallSimilar(query,limit)??Promise.resolve([])}async store(key,content){await getSsmMemoryService()?.remember(key,content)}async ingest(source,namespace){let svc=getSsmMemoryService();if(!svc)return 0;let ns=namespace?.trim()||`kb`,chunks=source.split(/\n\s*\n/).map(s=>s.trim()).filter(Boolean),effective=chunks.length>0?chunks:[source.trim()].filter(Boolean),i=0;for(let chunk of effective)await svc.remember(`${ns}:${i}`,chunk,{tags:[ns,`knowledge`]}),i+=1;return await svc.learn(source),effective.length}async train(opts){let svc=getSsmMemoryService();if(!svc)return`[train] SSM memory service unavailable — "${opts.model}" not trained`;let epochs=Number.isFinite(opts.epochs)&&opts.epochs>0?Math.floor(opts.epochs):1,batch=Array.from({length:epochs},()=>opts.dataset);return await svc.distillAndSave(batch),`[train] adapted "${opts.model}" over ${epochs} epoch(s) on the supplied dataset and saved a checkpoint`}},LimbicSystemAdapter=class{async appraise(event){let svc=getLimbicSystemService();return svc?svc.appraise(event):neutralLimbicState()}snapshot(){return getLimbicSystemService()?.snapshot()??neutralLimbicState()}tick(opts){return getLimbicSystemService()?.tick(opts)??neutralLimbicState()}attention(){return getLimbicSystemService()?.attention()??.7}compile(){return getLimbicSystemService()?.compile()??{directives:[],params:{}}}async train(){return await getLimbicSystemService()?.train?.()??null}},LocalResultBrokerAdapter=class{async awaitResult(runId,childSessionKey,timeoutMs){return awaitLocalSubagentResult(runId,childSessionKey,timeoutMs)}};const EXPORTABLE_SOURCES=new Set([`user-global`,`project-local`]);function toPersonaDefinitions(plugins){return plugins.filter(p=>EXPORTABLE_SOURCES.has(p.source)).map(p=>{let def={id:p.name,name:p.name};return p.description&&(def.description=p.description),p.persona?.voice&&(def.voice=p.persona.voice),p.persona?.perspective&&(def.perspective=p.persona.perspective),p.outputFormat?.outputPrefix&&(def.outputPrefix=p.outputFormat.outputPrefix),p.capabilities?.length&&(def.capabilities=[...p.capabilities]),def})}async function syncPersonasToBuilderforce(opts,personas){if(personas.length===0)return!0;let url=`${opts.baseUrl.replace(/\/$/,``)}/api/agent-hosts/${opts.agentNodeId}/personas`;try{let res=await fetch(url,{method:`PUT`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${opts.apiKey}`},body:JSON.stringify({personas}),signal:AbortSignal.timeout(15e3)});return res.ok?(logDebug(`[persona-sync] pushed ${personas.length} personas`),!0):(logDebug(`[persona-sync] push failed: HTTP ${res.status}`),!1)}catch(err){return logDebug(`[persona-sync] push error: ${String(err)}`),!1}}async function fetchPlatformPersonas(opts){let url=`${opts.baseUrl.replace(/\/$/,``)}/api/agent-hosts/${opts.agentNodeId}/platform-personas`;try{let res=await fetch(url,{headers:{Authorization:`Bearer ${opts.apiKey}`},signal:AbortSignal.timeout(1e4)});if(!res.ok)return logDebug(`[platform-persona-sync] fetch failed: HTTP ${res.status}`),[];let data=await res.json();return Array.isArray(data.personas)?data.personas:[]}catch(err){return logDebug(`[platform-persona-sync] fetch error: ${String(err)}`),[]}}async function pushProjectContextToBuilderforce(opts,context){if(!context.governance)return!0;let url=`${opts.baseUrl.replace(/\/$/,``)}/api/agent-hosts/${opts.agentNodeId}/project-context`;try{let res=await fetch(url,{method:`PATCH`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${opts.apiKey}`},body:JSON.stringify(context),signal:AbortSignal.timeout(15e3)});return res.ok?(logDebug(`[project-context-push] pushed governance context for project ${context.projectId}`),!0):(logDebug(`[project-context-push] failed: HTTP ${res.status}`),!1)}catch(err){return logDebug(`[project-context-push] error: ${String(err)}`),!1}}async function fetchQuotaStatus(opts){let url=`${opts.baseUrl.replace(/\/$/,``)}/api/agent-hosts/${opts.agentNodeId}/quota`;try{let res=await fetch(url,{headers:{Authorization:`Bearer ${opts.apiKey}`},signal:AbortSignal.timeout(1e4)});if(!res.ok)return logDebug(`[quota-monitor] fetch failed: HTTP ${res.status}`),null;let data=await res.json(),threshold=opts.warnThreshold??.8,pctUsed=data.budgetTokens&&data.budgetTokens>0?data.totalTokens/data.budgetTokens:void 0,nearLimit=pctUsed===void 0?!1:pctUsed>=threshold;return{...data,pctUsed,nearLimit}}catch(err){return logDebug(`[quota-monitor] fetch error: ${String(err)}`),null}}async function checkAndWarnQuota(opts){let quota=await fetchQuotaStatus(opts);if(quota)if(quota.nearLimit){let pct=quota.pctUsed==null?``:` (${Math.round(quota.pctUsed*100)}% of budget)`;logWarn(`[quota-monitor] WARNING: token usage is approaching budget limit — ${quota.totalTokens.toLocaleString()} tokens used in the last 30 days${pct}. Review usage in the Builderforce portal.`)}else logDebug(`[quota-monitor] ${quota.totalTokens.toLocaleString()} tokens used in last 30 days`)}let loadedSkills=[];async function fetchAndLoadSkills(opts){let url=`${opts.baseUrl.replace(/\/$/,``)}/api/agent-hosts/${opts.agentNodeId}/skills`;try{let res=await fetch(url,{headers:{Authorization:`Bearer ${opts.apiKey}`},signal:AbortSignal.timeout(15e3)});if(!res.ok){logWarn(`[skill-registry] fetch failed: ${res.status}`);return}loadedSkills=((await res.json()).skills??[]).map(s=>({skillSlug:s.skill_id,name:s.name,description:s.description,source:s.metadata?.source===`agentNode`?`agentNode`:`tenant`})),loadedSkills.length>0?logDebug(`[skill-registry] loaded ${loadedSkills.length} skill(s): ${loadedSkills.map(s=>s.skillSlug).join(`, `)}`):logDebug(`[skill-registry] no skills assigned to this agentNode`)}catch(err){logWarn(`[skill-registry] fetch error: ${String(err)}`)}}function parseNodeInput(input){if(!input)return{};try{let v=JSON.parse(input);return{kind:v.kind,config:v.config}}catch{return{}}}function parseDeps(raw){if(!raw)return[];try{let v=JSON.parse(raw);return Array.isArray(v)?v.filter(x=>typeof x==`string`):[]}catch{return[]}}var WorkflowPollerService=class{constructor(opts){this.opts=opts,this.pollTimer=null,this.closed=!1,this.busy=!1}start(){if(isOfflineMode()){logDebug(`[workflow-poller] offline mode — skipping control-plane polling`);return}let interval=this.opts.intervalMs??15e3;this.tick(),this.pollTimer=setInterval(()=>void this.tick(),interval)}stop(){this.closed=!0,this.pollTimer&&=(clearInterval(this.pollTimer),null)}authHeaders(extra){return{Authorization:`Bearer ${this.opts.apiKey}`,"X-AgentHost-Id":this.opts.agentNodeId,...extra}}async tick(){if(!(this.closed||this.busy)){this.busy=!0;try{let claim=await this.claim();if(!claim?.workflow)return;await this.runClaimed(claim.workflow.id,claim.tasks??[])}catch(err){logWarn(`[workflow-poller] tick error: ${String(err)}`)}finally{this.busy=!1}}}async claim(){let url=`${normalizeBaseUrl(this.opts.baseUrl)}/api/workflows/claim`;try{let res=await fetch(url,{method:`POST`,headers:this.authHeaders(),signal:AbortSignal.timeout(1e4)});return res.ok?await res.json():(res.status!==401&&logWarn(`[workflow-poller] claim failed: ${res.status}`),null)}catch(err){return logDebug(`[workflow-poller] claim error: ${String(err)}`),null}}async runClaimed(workflowId,tasks){logWarn(`[workflow-poller] executing workflow ${workflowId} (${tasks.length} task(s))`);let specs=tasks.map(t=>{let{kind,config}=parseNodeInput(t.input);return{id:t.id,agentRole:t.agentRole,description:t.description,input:t.description,dependsOn:parseDeps(t.dependsOn),nodeType:kind&&kind!==`agent`?kind:void 0,config}});globalOrchestrator.createWorkflowFromTasks(workflowId,specs);let failed=!1;try{await globalOrchestrator.executeWorkflow(workflowId,this.opts.getContext())}catch(err){failed=!0,logWarn(`[workflow-poller] workflow ${workflowId} failed: ${String(err)}`)}let wf=globalOrchestrator.getWorkflowStatus(workflowId),reportTasks=wf?Array.from(wf.tasks.values()).map(task=>({id:task.id,status:task.status,output:task.output,error:task.error})):[],status=failed||wf?.status===`failed`?`failed`:`completed`;await this.reportResult(workflowId,reportTasks,status)}async reportResult(workflowId,tasks,status){let url=`${normalizeBaseUrl(this.opts.baseUrl)}/api/workflows/${workflowId}/host-result`;try{await fetch(url,{method:`POST`,headers:this.authHeaders({"Content-Type":`application/json`}),body:JSON.stringify({tasks,status}),signal:AbortSignal.timeout(1e4)})}catch(err){logWarn(`[workflow-poller] result report failed for ${workflowId}: ${String(err)}`)}}};const log$1=createSubsystemLogger(`plugins`);function createPluginLogger(){return{info:msg=>log$1.info(msg),warn:msg=>log$1.warn(msg),error:msg=>log$1.error(msg),debug:msg=>log$1.debug(msg)}}function createServiceContext(params){return{config:params.config,workspaceDir:params.workspaceDir,stateDir:STATE_DIR,logger:createPluginLogger()}}async function startPluginServices(params){let running=[],serviceContext=createServiceContext({config:params.config,workspaceDir:params.workspaceDir});for(let entry of params.registry.services){let service=entry.service;try{await service.start(serviceContext),running.push({id:service.id,stop:service.stop?()=>service.stop?.(serviceContext):void 0})}catch(err){log$1.error(`plugin service failed (${service.id}): ${String(err)}`)}}return{stop:async()=>{for(let entry of running.toReversed())if(entry.stop)try{await entry.stop()}catch(err){log$1.warn(`plugin service stop failed (${entry.id}): ${String(err)}`)}}}}async function scheduleRestartSentinelWake(_params){let sentinel=await consumeRestartSentinel();if(!sentinel)return;let payload=sentinel.payload,sessionKey=payload.sessionKey?.trim(),message=formatRestartSentinelMessage(payload),summary=summarizeRestartSentinel(payload);if(!sessionKey){enqueueSystemEvent(message,{sessionKey:resolveMainSessionKeyFromConfig()});return}let{baseSessionKey,threadId:sessionThreadId}=parseSessionThreadInfo(sessionKey),{cfg,entry}=loadSessionEntry(sessionKey),parsedTarget=resolveAnnounceTargetFromKey(baseSessionKey??sessionKey),sentinelContext=payload.deliveryContext,sessionDeliveryContext=deliveryContextFromSession(entry);if(!sessionDeliveryContext&&baseSessionKey&&baseSessionKey!==sessionKey){let{entry:baseEntry}=loadSessionEntry(baseSessionKey);sessionDeliveryContext=deliveryContextFromSession(baseEntry)}let origin=mergeDeliveryContext(sentinelContext,mergeDeliveryContext(sessionDeliveryContext,parsedTarget??void 0)),channelRaw=origin?.channel,channel=channelRaw?normalizeChannelId(channelRaw):null,to=origin?.to;if(!channel||!to){enqueueSystemEvent(message,{sessionKey});return}let resolved=resolveOutboundTarget({channel,to,cfg,accountId:origin?.accountId,mode:`implicit`});if(!resolved.ok){enqueueSystemEvent(message,{sessionKey});return}let threadId=payload.threadId??parsedTarget?.threadId??sessionThreadId??(origin?.threadId==null?void 0:String(origin.threadId));try{await deliverOutboundPayloads({cfg,channel,to:resolved.to,accountId:origin?.accountId,threadId,payloads:[{text:message}],agentId:resolveSessionAgentId({sessionKey,config:cfg}),bestEffort:!0})}catch(err){enqueueSystemEvent(`${summary}\n${String(err)}`,{sessionKey})}}function shouldWakeFromRestartSentinel(){return!process.env.VITEST&&!0}async function startGatewayMemoryBackend(params){let agentIds=listAgentIds(params.cfg);for(let agentId of agentIds){let resolved=resolveMemoryBackendConfig({cfg:params.cfg,agentId});if(resolved.backend!==`qmd`||!resolved.qmd)continue;let{manager,error}=await getMemorySearchManager({cfg:params.cfg,agentId});if(!manager){params.log.warn(`qmd memory startup initialization failed for agent "${agentId}": ${error??`unknown error`}`);continue}params.log.info?.(`qmd memory startup initialization armed for agent "${agentId}"`)}}async function cleanStaleSessions(params){try{let sessionDirs=await resolveAgentSessionDirs(resolveStateDir(process.env));for(let sessionsDir of sessionDirs)await cleanStaleLockFiles({sessionsDir,staleMs:18e5,removeStale:!0,log:{warn:message=>params.log.warn(message)}})}catch(err){params.log.warn(`session lock cleanup failed on startup: ${String(err)}`)}}async function startOrchestrator(params){globalOrchestrator.setProjectRoot(params.defaultWorkspaceDir);let localTransport=new LocalAgentTransport({getContext:()=>globalOrchestrator.currentSpawnContext(),localResultBroker:new LocalResultBrokerAdapter});globalOrchestrator.configure({telemetry:new WorkflowTelemetryAdapter,agentTransport:new CompositeAgentTransport({local:localTransport})});let incompleteWorkflows=await globalOrchestrator.loadPersistedWorkflows();if(incompleteWorkflows.length>0){params.log.warn(`[orchestrator] ${incompleteWorkflows.length} incomplete workflow(s) restored: ${incompleteWorkflows.join(`, `)}`);try{let resumed=await globalOrchestrator.resumeAllIncomplete(globalOrchestrator.currentSpawnContext());resumed.length>0&&params.log.warn(`[orchestrator] auto-resumed ${resumed.length} workflow(s): ${resumed.join(`, `)}`)}catch(err){params.log.warn(`[orchestrator] auto-resume failed: ${String(err)}`)}}}async function startBrowserControl(params){try{return await startBrowserControlServerIfEnabled()}catch(err){return params.logBrowser.error(`server failed to start: ${String(err)}`),null}}async function startHooks(params){if(await startGmailWatcherWithLogs({cfg:params.cfg,log:params.logHooks}),params.cfg.hooks?.gmail?.model){let hooksModelRef=resolveHooksGmailModel({cfg:params.cfg,defaultProvider:DEFAULT_PROVIDER});if(hooksModelRef){let{provider:defaultProvider,model:defaultModel}=resolveConfiguredModelRef({cfg:params.cfg,defaultProvider:DEFAULT_PROVIDER,defaultModel:DEFAULT_MODEL}),catalog=await loadModelCatalog({config:params.cfg}),status=getModelRefStatus({cfg:params.cfg,catalog,ref:hooksModelRef,defaultProvider,defaultModel});status.allowed||params.logHooks.warn(`hooks.gmail.model "${status.key}" not in agents.defaults.models allowlist (will use primary instead)`),status.inCatalog||params.logHooks.warn(`hooks.gmail.model "${status.key}" not in the model catalog (may fail at runtime)`)}}try{clearInternalHooks();let loadedCount=await loadInternalHooks(params.cfg,params.defaultWorkspaceDir);loadedCount>0&&params.logHooks.info(`loaded ${loadedCount} internal hook handler${loadedCount>1?`s`:``}`)}catch(err){params.logHooks.error(`failed to load hooks: ${String(err)}`)}params.cfg.hooks?.internal?.enabled&&triggerInternalHook(createInternalHookEvent(`gateway`,`startup`,`gateway:startup`,{cfg:params.cfg,deps:params.deps,workspaceDir:params.defaultWorkspaceDir}))}async function startMessageChannels(params){if(isTruthyEnvValue(process.env.BUILDERFORCE_AGENTS_SKIP_CHANNELS)||isTruthyEnvValue(process.env.BUILDERFORCE_AGENTS_SKIP_PROVIDERS)){params.logChannels.info(`skipping channel start (BUILDERFORCE_AGENTS_SKIP_CHANNELS=1 or BUILDERFORCE_AGENTS_SKIP_PROVIDERS=1)`);return}try{await params.startChannels()}catch(err){params.logChannels.error(`channel startup failed: ${String(err)}`)}}async function startPlugins(params){try{return await startPluginServices({registry:params.pluginRegistry,config:params.cfg,workspaceDir:params.defaultWorkspaceDir})}catch(err){return params.log.warn(`plugin services failed to start: ${String(err)}`),null}}function startMemoryBackend(params){startGatewayMemoryBackend({cfg:params.cfg,log:params.log}).catch(err=>{params.log.warn(`qmd memory startup initialization failed: ${String(err)}`)}),initSsmMemoryService({checkpointPath:`${params.defaultWorkspaceDir}/.builderforce/model.bin`,modelSize:`small`}).then(svc=>{svc&&(params.log.warn(`[ssm-memory] hippocampus layer started (gpu=${svc.gpuAvailable})`),globalOrchestrator.configure({memoryService:new SsmMemoryAdapter}))}).catch(err=>{params.log.warn(`[ssm-memory] startup failed: ${String(err)}`)}),initLimbicSystemService({checkpointPath:`${params.defaultWorkspaceDir}/.builderforce/limbic.bin`}).then(svc=>{params.log.warn(`[limbic] affective layer started (model=${svc.modelAvailable}, gpu=${svc.gpuAvailable})`),globalOrchestrator.configure({limbicSystem:new LimbicSystemAdapter})}).catch(err=>{params.log.warn(`[limbic] startup failed: ${String(err)}`)})}function startLocalKnowledgeLoop(params){let knowledgeLoop=new KnowledgeLoopService({workspaceDir:params.defaultWorkspaceDir,apiKey:null,agentNodeId:null});return knowledgeLoop.start(),params.log.warn(`[knowledge-loop] started (local-only)`),knowledgeLoop}async function startBuilderforceServices(params){let relay=null,knowledgeLoop=null;if(isOfflineMode()){params.log.warn(`[builderforce] offline mode — BUILDERFORCE_OFFLINE set; all control-plane syncs disabled (relay, cron/workflow pollers, fleet/directory sync, hired-agents/persona sync, knowledge-loop upstream, remote dispatch). Local agent loop + local model inference + local MCP/dev tools remain active.`);try{knowledgeLoop=startLocalKnowledgeLoop(params)}catch(err){params.log.warn(`[builderforce/knowledge-loop] offline startup failed: ${String(err)}`)}return{relay,knowledgeLoop}}try{let apiKey=readSharedEnvVar(`BUILDERFORCE_API_KEY`),baseUrl=readSharedEnvVar(`BUILDERFORCE_URL`)??`https://api.builderforce.ai`;if(!apiKey)return params.log.warn(`[builderforce] standalone mode — BUILDERFORCE_API_KEY not set; Builderforce connection and agent-to-agent dispatch are disabled. Set BUILDERFORCE_API_KEY in ~/.builderforce/.env to enable them.`),{relay,knowledgeLoop};let ctx=await loadProjectContext(params.defaultWorkspaceDir),agentNodeId=ctx?.builderforce?.instanceId,projectId=ctx?.builderforce?.projectId?Number(ctx.builderforce.projectId):void 0;if(agentNodeId){globalOrchestrator.setProjectRoot(params.defaultWorkspaceDir,String(agentNodeId),baseUrl,apiKey),initApprovalGate({baseUrl,agentNodeId:String(agentNodeId),apiKey});let ollamaProviderConfig=params.cfg.models?.providers?.ollama,ollamaLocalOrigin=ollamaProviderConfig?resolveOllamaApiBase(ollamaProviderConfig.baseUrl):void 0,freetokenProviderConfig=params.cfg.models?.providers?.freetoken,freetokenLocalOrigin=freetokenProviderConfig?resolveFreetokenApiBase(freetokenProviderConfig.baseUrl):void 0;relay=new BuilderforceRelayService({baseUrl,agentNodeId:String(agentNodeId),apiKey,workspaceDir:params.defaultWorkspaceDir,...ollamaLocalOrigin?{ollamaLocalOrigin}:{},...freetokenLocalOrigin?{freetokenLocalOrigin}:{}}),relay.start(),params.log.warn(`[builderforce] relay started for agentNode ${agentNodeId}`),relay.setRemoteDispatchOptions({baseUrl,myAgentNodeId:String(agentNodeId),apiKey});let relayRef=relay,stopRelay=()=>{try{relayRef.stop()}catch{}};process.once(`SIGTERM`,stopRelay),process.once(`SIGINT`,stopRelay),fetchPlatformPersonas({baseUrl,agentNodeId:String(agentNodeId),apiKey}).then(personas=>{personas.length>0&&(params.log.warn(`[platform-personas] loaded ${personas.length} platform persona(s)`),registerPlatformPersonasAsRoles(personas))});let exportedPersonas=toPersonaDefinitions(globalPersonaRegistry.listAll());syncPersonasToBuilderforce({baseUrl,agentNodeId:String(agentNodeId),apiKey},exportedPersonas).then(ok=>{ok&&exportedPersonas.length>0&&params.log.warn(`[persona-sync] pushed ${exportedPersonas.length} custom persona(s)`)}),loadHiredAgentsCached({baseUrl,agentNodeId:String(agentNodeId),apiKey}).then(agents=>{agents.length>0&&params.log.warn(`[hired-agents] registered ${agents.length} hired agent role(s)`)}),checkAndWarnQuota({baseUrl,agentNodeId:String(agentNodeId),apiKey}),(async()=>{try{ctx?.builderforce?.projectId&&ctx.description&&await pushProjectContextToBuilderforce({baseUrl,agentNodeId:String(agentNodeId),apiKey},{projectId:Number(ctx.builderforce.projectId),governance:ctx.description})}catch(err){params.log.warn(`[project-context-push] failed: ${String(err)}`)}})(),fetchAndLoadSkills({baseUrl,agentNodeId:String(agentNodeId),apiKey}),new CronPollerService({baseUrl,agentNodeId:String(agentNodeId),apiKey}).start(),params.log.warn(`[cron-poller] started`),syncBuilderForceAgentsDirectoryOnStartup({workspaceDir:params.defaultWorkspaceDir,log:params.log});let localTransport=new LocalAgentTransport({getContext:()=>globalOrchestrator.currentSpawnContext(),localResultBroker:new LocalResultBrokerAdapter}),remoteTransport=new BuilderforceAgentTransport({baseUrl,myAgentNodeId:String(agentNodeId),apiKey});globalOrchestrator.configure({agentTransport:new CompositeAgentTransport({local:localTransport,remote:remoteTransport}),relayService:relay}),new WorkflowPollerService({baseUrl,agentNodeId:String(agentNodeId),apiKey,getContext:()=>globalOrchestrator.currentSpawnContext()}).start(),params.log.warn(`[workflow-poller] started`),globalOrchestrator.configure({llmService:new GatewayLlmService({baseUrl,apiKey})})}knowledgeLoop=new KnowledgeLoopService({workspaceDir:params.defaultWorkspaceDir,apiKey,baseUrl,agentNodeId:agentNodeId?String(agentNodeId):null,projectId}),knowledgeLoop.start(),params.log.warn(`[knowledge-loop] started`)}catch(err){params.log.warn(`[builderforce/knowledge-loop] startup failed: ${String(err)}`)}return{relay,knowledgeLoop}}async function startGatewaySidecars(params){await cleanStaleSessions(params),await startOrchestrator(params);let browserControl=await startBrowserControl(params);await startHooks(params),await startMessageChannels(params);let pluginServices=await startPlugins(params);startMemoryBackend(params),shouldWakeFromRestartSentinel()&&scheduleRestartSentinelWake({deps:params.deps});let{relay:builderforceRelay,knowledgeLoop}=await startBuilderforceServices(params);return{browserControl,pluginServices,builderforceRelay,knowledgeLoop}}async function startGatewayTailscaleExposure(params){if(params.tailscaleMode===`off`)return null;try{params.tailscaleMode===`serve`?await enableTailscaleServe(params.port):await enableTailscaleFunnel(params.port);let host=await getTailnetHostname().catch(()=>null);if(host){let uiPath=params.controlUiBasePath?`${params.controlUiBasePath}/`:`/`;params.logTailscale.info(`${params.tailscaleMode} enabled: https://${host}${uiPath} (WS via wss://${host})`)}else params.logTailscale.info(`${params.tailscaleMode} enabled`)}catch(err){params.logTailscale.warn(`${params.tailscaleMode} failed: ${err instanceof Error?err.message:String(err)}`)}return params.resetOnExit?async()=>{try{params.tailscaleMode===`serve`?await disableTailscaleServe():await disableTailscaleFunnel()}catch(err){params.logTailscale.warn(`${params.tailscaleMode} cleanup failed: ${err instanceof Error?err.message:String(err)}`)}}:null}function createWizardSessionTracker(){let wizardSessions=new Map;return{wizardSessions,findRunningWizard:()=>{for(let[id,session]of wizardSessions)if(session.getStatus()===`running`)return id;return null},purgeWizardSession:id=>{let session=wizardSessions.get(id);session&&session.getStatus()!==`running`&&wizardSessions.delete(id)}}}const normalizeHost=(value,rejectLoopback)=>{if(!value)return``;let trimmed=value.trim();return!trimmed||rejectLoopback&&isLoopbackHost(trimmed)?``:trimmed},parseHostHeader=value=>{if(!value)return{host:``};try{let parsed=new URL(`http://${String(value).trim()}`),portRaw=parsed.port.trim(),port=portRaw?Number.parseInt(portRaw,10):void 0;return{host:parsed.hostname,port:Number.isFinite(port)?port:void 0}}catch{return{host:``}}},parseForwardedProto=value=>Array.isArray(value)?value[0]:value;function resolveCanvasHostUrl(params){let port=params.canvasPort;if(!port)return;let scheme=params.scheme??(parseForwardedProto(params.forwardedProto)?.trim()===`https`?`https`:`http`),override=normalizeHost(params.hostOverride,!0),parsedRequestHost=parseHostHeader(params.requestHost),requestHost=normalizeHost(parsedRequestHost.host,!!override),localAddress=normalizeHost(params.localAddress,!!(override||requestHost)),host=override||requestHost||localAddress;if(!host)return;let exposedPort=port;return!override&&requestHost&&port===18789&&(parsedRequestHost.port&&parsedRequestHost.port>0?exposedPort=parsedRequestHost.port:scheme===`https`?exposedPort=443:scheme===`http`&&(exposedPort=80)),`${scheme}://${host.includes(`:`)?`[${host}]`:host}:${exposedPort}`}function parseOrigin(originRaw){let trimmed=(originRaw??``).trim();if(!trimmed||trimmed===`null`)return null;try{let url=new URL(trimmed);return{origin:url.origin.toLowerCase(),host:url.host.toLowerCase(),hostname:url.hostname.toLowerCase()}}catch{return null}}function checkBrowserOrigin(params){let parsedOrigin=parseOrigin(params.origin);if(!parsedOrigin)return{ok:!1,reason:`origin missing or invalid`};if((params.allowedOrigins??[]).map(value=>value.trim().toLowerCase()).filter(Boolean).includes(parsedOrigin.origin))return{ok:!0};let requestHost=normalizeHostHeader(params.requestHost);if(requestHost&&parsedOrigin.host===requestHost)return{ok:!0};let requestHostname=resolveHostName(requestHost);return isLoopbackHost(parsedOrigin.hostname)&&isLoopbackHost(requestHostname)?{ok:!0}:{ok:!1,reason:`origin not allowed`}}function formatGatewayAuthFailureMessage(params){let{authMode,authProvided,reason,client}=params,isCli=isGatewayCliClient(client),isControlUi=client?.id===GATEWAY_CLIENT_IDS.CONTROL_UI,isWebchat=isWebchatClient(client),tokenHint=isCli?`set gateway.remote.token to match gateway.auth.token`:isControlUi||isWebchat?`open the dashboard URL and paste the token in Control UI settings`:`provide gateway auth token`,passwordHint=isCli?`set gateway.remote.password to match gateway.auth.password`:isControlUi||isWebchat?`enter the password in Control UI settings`:`provide gateway auth password`;switch(reason){case`token_missing`:return`unauthorized: gateway token missing (${tokenHint})`;case`token_mismatch`:return`unauthorized: gateway token mismatch (${tokenHint})`;case`token_missing_config`:return`unauthorized: gateway token not configured on gateway (set gateway.auth.token)`;case`password_missing`:return`unauthorized: gateway password missing (${passwordHint})`;case`password_mismatch`:return`unauthorized: gateway password mismatch (${passwordHint})`;case`password_missing_config`:return`unauthorized: gateway password not configured on gateway (set gateway.auth.password)`;case`tailscale_user_missing`:return`unauthorized: tailscale identity missing (use Tailscale Serve auth or gateway token/password)`;case`tailscale_proxy_missing`:return`unauthorized: tailscale proxy headers missing (use Tailscale Serve or gateway token/password)`;case`tailscale_whois_failed`:return`unauthorized: tailscale identity check failed (use Tailscale Serve auth or gateway token/password)`;case`tailscale_user_mismatch`:return`unauthorized: tailscale identity mismatch (use Tailscale Serve auth or gateway token/password)`;case`rate_limited`:return`unauthorized: too many failed authentication attempts (retry later)`;case`device_token_mismatch`:return`unauthorized: device token mismatch (rotate/reissue device token)`;default:break}return authMode===`token`&&authProvided===`none`?`unauthorized: gateway token missing (${tokenHint})`:authMode===`password`&&authProvided===`none`?`unauthorized: gateway password missing (${passwordHint})`:`unauthorized`}function attachGatewayWsMessageHandler(params){let{socket,upgradeReq,connId,remoteAddr,forwardedFor,realIp,requestHost,requestOrigin,requestUserAgent,canvasHostUrl,connectNonce,resolvedAuth,rateLimiter,gatewayMethods,events,extraHandlers,buildRequestContext,send,close,isClosed,clearHandshakeTimer,getClient,setClient,setHandshakeState,setCloseCause,setLastFrameMeta,logGateway,logHealth,logWsControl}=params,configSnapshot=loadConfig(),trustedProxies=configSnapshot.gateway?.trustedProxies??[],clientIp=resolveGatewayClientIp({remoteAddr,forwardedFor,realIp,trustedProxies}),hasProxyHeaders=!!(forwardedFor||realIp),remoteIsTrustedProxy=isTrustedProxyAddress(remoteAddr,trustedProxies),hasUntrustedProxyHeaders=hasProxyHeaders&&!remoteIsTrustedProxy,hostName=resolveHostName(requestHost),hostIsLocalish=isLoopbackHost(hostName)||hostName.endsWith(`.ts.net`),isLocalClient=isLocalDirectRequest(upgradeReq,trustedProxies),reportedClientIp=isLocalClient||hasUntrustedProxyHeaders?void 0:clientIp&&!isLoopbackAddress(clientIp)?clientIp:void 0;hasUntrustedProxyHeaders&&logWsControl.warn(`Proxy headers detected from untrusted address. Connection will not be treated as local. Configure gateway.trustedProxies to restore local client detection behind your proxy.`),!hostIsLocalish&&isLoopbackAddress(remoteAddr)&&!hasProxyHeaders&&logWsControl.warn(`Loopback connection with non-local Host header. Treating it as remote. If you're behind a reverse proxy, set gateway.trustedProxies and forward X-Forwarded-For/X-Real-IP.`);let isWebchatConnect=p=>isWebchatClient(p?.client);socket.on(`message`,async data=>{if(isClosed())return;let text=rawDataToString(data);try{let parsed=JSON.parse(text),frameType=parsed&&typeof parsed==`object`&&`type`in parsed&&typeof parsed.type==`string`?String(parsed.type):void 0,frameMethod=parsed&&typeof parsed==`object`&&`method`in parsed&&typeof parsed.method==`string`?String(parsed.method):void 0,frameId=parsed&&typeof parsed==`object`&&`id`in parsed&&typeof parsed.id==`string`?String(parsed.id):void 0;(frameType||frameMethod||frameId)&&setLastFrameMeta({type:frameType,method:frameMethod,id:frameId});let client=getClient();if(!client){let isRequestFrame=validateRequestFrame(parsed);if(!isRequestFrame||parsed.method!==`connect`||!validateConnectParams(parsed.params)){let handshakeError=isRequestFrame?parsed.method===`connect`?`invalid connect params: ${formatValidationErrors(validateConnectParams.errors)}`:`invalid handshake: first request must be connect`:`invalid request frame`;setHandshakeState(`failed`),setCloseCause(`invalid-handshake`,{frameType,frameMethod,frameId,handshakeError}),isRequestFrame?send({type:`res`,id:parsed.id,ok:!1,error:errorShape(ErrorCodes.INVALID_REQUEST,handshakeError)}):logWsControl.warn(`invalid handshake conn=${connId} remote=${remoteAddr??`?`} fwd=${forwardedFor??`n/a`} origin=${requestOrigin??`n/a`} host=${requestHost??`n/a`} ua=${requestUserAgent??`n/a`}`);let closeReason=truncateCloseReason(handshakeError||`invalid handshake`);isRequestFrame?queueMicrotask(()=>close(1008,closeReason)):close(1008,closeReason);return}let frame=parsed,connectParams=frame.params,clientLabel=connectParams.client.displayName??connectParams.client.id,clientMeta={client:connectParams.client.id,clientDisplayName:connectParams.client.displayName,mode:connectParams.client.mode,version:connectParams.client.version},markHandshakeFailure=(cause,meta)=>{setHandshakeState(`failed`),setCloseCause(cause,{...meta,...clientMeta})},sendHandshakeErrorResponse=(code,message,options)=>{send({type:`res`,id:frame.id,ok:!1,error:errorShape(code,message,options)})},{minProtocol,maxProtocol}=connectParams;if(maxProtocol<PROTOCOL_VERSION||minProtocol>PROTOCOL_VERSION){markHandshakeFailure(`protocol-mismatch`,{minProtocol,maxProtocol,expectedProtocol:PROTOCOL_VERSION}),logWsControl.warn(`protocol mismatch conn=${connId} remote=${remoteAddr??`?`} client=${clientLabel} ${connectParams.client.mode} v${connectParams.client.version}`),sendHandshakeErrorResponse(ErrorCodes.INVALID_REQUEST,`protocol mismatch`,{details:{expectedProtocol:PROTOCOL_VERSION}}),close(1002,`protocol mismatch`);return}let roleRaw=connectParams.role??`operator`,role=roleRaw===`operator`||roleRaw===`node`?roleRaw:null;if(!role){markHandshakeFailure(`invalid-role`,{role:roleRaw}),sendHandshakeErrorResponse(ErrorCodes.INVALID_REQUEST,`invalid role`),close(1008,`invalid role`);return}let scopes=Array.isArray(connectParams.scopes)?connectParams.scopes:[];connectParams.role=role,connectParams.scopes=scopes;let isControlUi=connectParams.client.id===GATEWAY_CLIENT_IDS.CONTROL_UI,isWebchat=isWebchatConnect(connectParams);if(isControlUi||isWebchat){let originCheck=checkBrowserOrigin({requestHost,origin:requestOrigin,allowedOrigins:configSnapshot.gateway?.controlUi?.allowedOrigins});if(!originCheck.ok){let errorMessage=`origin not allowed (open the Control UI from the gateway host or allow it in gateway.controlUi.allowedOrigins)`;markHandshakeFailure(`origin-mismatch`,{origin:requestOrigin??`n/a`,host:requestHost??`n/a`,reason:originCheck.reason}),sendHandshakeErrorResponse(ErrorCodes.INVALID_REQUEST,errorMessage),close(1008,truncateCloseReason(errorMessage));return}}let deviceRaw=connectParams.device,devicePublicKey=null,hasTokenAuth=!!connectParams.auth?.token,hasPasswordAuth=!!connectParams.auth?.password,hasSharedAuth=hasTokenAuth||hasPasswordAuth,allowInsecureControlUi=isControlUi&&configSnapshot.gateway?.controlUi?.allowInsecureAuth===!0,disableControlUiDeviceAuth=isControlUi&&configSnapshot.gateway?.controlUi?.dangerouslyDisableDeviceAuth===!0,allowControlUiBypass=allowInsecureControlUi||disableControlUiDeviceAuth,device=disableControlUiDeviceAuth?null:deviceRaw,hasDeviceTokenCandidate=!!(connectParams.auth?.token&&device),authResult=await authorizeGatewayConnect({auth:resolvedAuth,connectAuth:connectParams.auth,req:upgradeReq,trustedProxies,rateLimiter:hasDeviceTokenCandidate?void 0:rateLimiter,clientIp,rateLimitScope:AUTH_RATE_LIMIT_SCOPE_SHARED_SECRET});if(hasDeviceTokenCandidate&&authResult.ok&&rateLimiter&&(authResult.method===`token`||authResult.method===`password`)){let sharedRateCheck=rateLimiter.check(clientIp,AUTH_RATE_LIMIT_SCOPE_SHARED_SECRET);sharedRateCheck.allowed?rateLimiter.reset(clientIp,AUTH_RATE_LIMIT_SCOPE_SHARED_SECRET):authResult={ok:!1,reason:`rate_limited`,rateLimited:!0,retryAfterMs:sharedRateCheck.retryAfterMs}}let authOk=authResult.ok,authMethod=authResult.method??(resolvedAuth.mode===`password`?`password`:`token`),sharedAuthResult=hasSharedAuth?await authorizeGatewayConnect({auth:{...resolvedAuth,allowTailscale:!1},connectAuth:connectParams.auth,req:upgradeReq,trustedProxies,rateLimitScope:AUTH_RATE_LIMIT_SCOPE_SHARED_SECRET}):null,sharedAuthOk=sharedAuthResult?.ok===!0&&(sharedAuthResult.method===`token`||sharedAuthResult.method===`password`),rejectUnauthorized=failedAuth=>{markHandshakeFailure(`unauthorized`,{authMode:resolvedAuth.mode,authProvided:connectParams.auth?.token?`token`:connectParams.auth?.password?`password`:`none`,authReason:failedAuth.reason,allowTailscale:resolvedAuth.allowTailscale}),logWsControl.warn(`unauthorized conn=${connId} remote=${remoteAddr??`?`} client=${clientLabel} ${connectParams.client.mode} v${connectParams.client.version} reason=${failedAuth.reason??`unknown`}`);let authProvided=connectParams.auth?.token?`token`:connectParams.auth?.password?`password`:`none`,authMessage=formatGatewayAuthFailureMessage({authMode:resolvedAuth.mode,authProvided,reason:failedAuth.reason,client:connectParams.client});sendHandshakeErrorResponse(ErrorCodes.INVALID_REQUEST,authMessage),close(1008,truncateCloseReason(authMessage))};if(!device){scopes.length>0&&!allowControlUiBypass&&(scopes=[],connectParams.scopes=scopes);let canSkipDevice=sharedAuthOk;if(isControlUi&&!allowControlUiBypass){let errorMessage=`control ui requires HTTPS or localhost (secure context)`;markHandshakeFailure(`control-ui-insecure-auth`),sendHandshakeErrorResponse(ErrorCodes.INVALID_REQUEST,errorMessage),close(1008,errorMessage);return}if(!canSkipDevice){if(!authOk&&hasSharedAuth){rejectUnauthorized(authResult);return}markHandshakeFailure(`device-required`),sendHandshakeErrorResponse(ErrorCodes.NOT_PAIRED,`device identity required`),close(1008,`device identity required`);return}}if(device){let derivedId=deriveDeviceIdFromPublicKey(device.publicKey);if(!derivedId||derivedId!==device.id){setHandshakeState(`failed`),setCloseCause(`device-auth-invalid`,{reason:`device-id-mismatch`,client:connectParams.client.id,deviceId:device.id}),send({type:`res`,id:frame.id,ok:!1,error:errorShape(ErrorCodes.INVALID_REQUEST,`device identity mismatch`)}),close(1008,`device identity mismatch`);return}let signedAt=device.signedAt;if(typeof signedAt!=`number`||Math.abs(Date.now()-signedAt)>6e5){setHandshakeState(`failed`),setCloseCause(`device-auth-invalid`,{reason:`device-signature-stale`,client:connectParams.client.id,deviceId:device.id}),send({type:`res`,id:frame.id,ok:!1,error:errorShape(ErrorCodes.INVALID_REQUEST,`device signature expired`)}),close(1008,`device signature expired`);return}let nonceRequired=!isLocalClient,providedNonce=typeof device.nonce==`string`?device.nonce.trim():``;if(nonceRequired&&!providedNonce){setHandshakeState(`failed`),setCloseCause(`device-auth-invalid`,{reason:`device-nonce-missing`,client:connectParams.client.id,deviceId:device.id}),send({type:`res`,id:frame.id,ok:!1,error:errorShape(ErrorCodes.INVALID_REQUEST,`device nonce required`)}),close(1008,`device nonce required`);return}if(providedNonce&&providedNonce!==connectNonce){setHandshakeState(`failed`),setCloseCause(`device-auth-invalid`,{reason:`device-nonce-mismatch`,client:connectParams.client.id,deviceId:device.id}),send({type:`res`,id:frame.id,ok:!1,error:errorShape(ErrorCodes.INVALID_REQUEST,`device nonce mismatch`)}),close(1008,`device nonce mismatch`);return}let payload=buildDeviceAuthPayload({deviceId:device.id,clientId:connectParams.client.id,clientMode:connectParams.client.mode,role,scopes,signedAtMs:signedAt,token:connectParams.auth?.token??null,nonce:providedNonce||void 0,version:providedNonce?`v2`:`v1`}),rejectDeviceSignatureInvalid=()=>{setHandshakeState(`failed`),setCloseCause(`device-auth-invalid`,{reason:`device-signature`,client:connectParams.client.id,deviceId:device.id}),send({type:`res`,id:frame.id,ok:!1,error:errorShape(ErrorCodes.INVALID_REQUEST,`device signature invalid`)}),close(1008,`device signature invalid`)},signatureOk=verifyDeviceSignature(device.publicKey,payload,device.signature);if(!signatureOk&&!nonceRequired&&!providedNonce){let legacyPayload=buildDeviceAuthPayload({deviceId:device.id,clientId:connectParams.client.id,clientMode:connectParams.client.mode,role,scopes,signedAtMs:signedAt,token:connectParams.auth?.token??null,version:`v1`});if(!verifyDeviceSignature(device.publicKey,legacyPayload,device.signature)){rejectDeviceSignatureInvalid();return}}else if(!signatureOk){rejectDeviceSignatureInvalid();return}if(devicePublicKey=normalizeDevicePublicKeyBase64Url(device.publicKey),!devicePublicKey){setHandshakeState(`failed`),setCloseCause(`device-auth-invalid`,{reason:`device-public-key`,client:connectParams.client.id,deviceId:device.id}),send({type:`res`,id:frame.id,ok:!1,error:errorShape(ErrorCodes.INVALID_REQUEST,`device public key invalid`)}),close(1008,`device public key invalid`);return}}if(!authOk&&connectParams.auth?.token&&device){if(rateLimiter){let deviceRateCheck=rateLimiter.check(clientIp,AUTH_RATE_LIMIT_SCOPE_DEVICE_TOKEN);deviceRateCheck.allowed||(authResult={ok:!1,reason:`rate_limited`,rateLimited:!0,retryAfterMs:deviceRateCheck.retryAfterMs})}authResult.rateLimited||((await verifyDeviceToken({deviceId:device.id,token:connectParams.auth.token,role,scopes})).ok?(authOk=!0,authMethod=`device-token`,rateLimiter?.reset(clientIp,AUTH_RATE_LIMIT_SCOPE_DEVICE_TOKEN)):(authResult={ok:!1,reason:`device_token_mismatch`},rateLimiter?.recordFailure(clientIp,AUTH_RATE_LIMIT_SCOPE_DEVICE_TOKEN)))}if(!authOk){rejectUnauthorized(authResult);return}if(device&&devicePublicKey&&!(allowControlUiBypass&&sharedAuthOk)){let requirePairing=async(reason,_paired)=>{let pairing=await requestDevicePairing({deviceId:device.id,publicKey:devicePublicKey,displayName:connectParams.client.displayName,platform:connectParams.client.platform,clientId:connectParams.client.id,clientMode:connectParams.client.mode,role,scopes,remoteIp:reportedClientIp,silent:isLocalClient}),context=buildRequestContext();if(pairing.request.silent===!0){let approved=await approveDevicePairing(pairing.request.requestId);approved&&(logGateway.info(`device pairing auto-approved device=${approved.device.deviceId} role=${approved.device.role??`unknown`}`),context.broadcast(`device.pair.resolved`,{requestId:pairing.request.requestId,deviceId:approved.device.deviceId,decision:`approved`,ts:Date.now()},{dropIfSlow:!0}))}else pairing.created&&context.broadcast(`device.pair.requested`,pairing.request,{dropIfSlow:!0});return pairing.request.silent===!0?!0:(setHandshakeState(`failed`),setCloseCause(`pairing-required`,{deviceId:device.id,requestId:pairing.request.requestId,reason}),send({type:`res`,id:frame.id,ok:!1,error:errorShape(ErrorCodes.NOT_PAIRED,`pairing required`,{details:{requestId:pairing.request.requestId}})}),close(1008,`pairing required`),!1)},paired=await getPairedDevice(device.id);if(paired?.publicKey!==devicePublicKey){if(!await requirePairing(`not-paired`))return}else{let allowedRoles=new Set(Array.isArray(paired.roles)?paired.roles:paired.role?[paired.role]:[]);if(allowedRoles.size===0){if(!await requirePairing(`role-upgrade`,paired))return}else if(!allowedRoles.has(role)&&!await requirePairing(`role-upgrade`,paired))return;let pairedScopes=Array.isArray(paired.scopes)?paired.scopes:[];if(scopes.length>0)if(pairedScopes.length===0){if(!await requirePairing(`scope-upgrade`,paired))return}else{let allowedScopes=new Set(pairedScopes);if(scopes.find(scope=>!allowedScopes.has(scope))&&!await requirePairing(`scope-upgrade`,paired))return}await updatePairedDeviceMetadata(device.id,{displayName:connectParams.client.displayName,platform:connectParams.client.platform,clientId:connectParams.client.id,clientMode:connectParams.client.mode,role,scopes,remoteIp:reportedClientIp})}}let deviceToken=device?await ensureDeviceToken({deviceId:device.id,role,scopes}):null;if(role===`node`){let allowlist=resolveNodeCommandAllowlist(loadConfig(),{platform:connectParams.client.platform,deviceFamily:connectParams.client.deviceFamily});connectParams.commands=(Array.isArray(connectParams.commands)?connectParams.commands:[]).map(cmd=>cmd.trim()).filter(cmd=>cmd.length>0&&allowlist.has(cmd))}let shouldTrackPresence=!isGatewayCliClient(connectParams.client),clientId=connectParams.client.id,instanceId=connectParams.client.instanceId,presenceKey=shouldTrackPresence?device?.id??instanceId??connId:void 0;logWs(`in`,`connect`,{connId,client:connectParams.client.id,clientDisplayName:connectParams.client.displayName,version:connectParams.client.version,mode:connectParams.client.mode,clientId,platform:connectParams.client.platform,auth:authMethod}),isWebchatConnect(connectParams)&&logWsControl.info(`webchat connected conn=${connId} remote=${remoteAddr??`?`} client=${clientLabel} ${connectParams.client.mode} v${connectParams.client.version}`),presenceKey&&(upsertPresence(presenceKey,{host:connectParams.client.displayName??connectParams.client.id??os.hostname(),ip:isLocalClient?void 0:reportedClientIp,version:connectParams.client.version,platform:connectParams.client.platform,deviceFamily:connectParams.client.deviceFamily,modelIdentifier:connectParams.client.modelIdentifier,mode:connectParams.client.mode,deviceId:device?.id,roles:[role],scopes,instanceId:device?.id??instanceId,reason:`connect`}),incrementPresenceVersion());let snapshot=buildGatewaySnapshot(),cachedHealth=getHealthCache();cachedHealth&&(snapshot.health=cachedHealth,snapshot.stateVersion.health=getHealthVersion());let helloOk={type:`hello-ok`,protocol:PROTOCOL_VERSION,server:{version:resolveRuntimeServiceVersion(process.env,`dev`),commit:process.env.GIT_COMMIT,host:os.hostname(),connId},features:{methods:gatewayMethods,events},snapshot,canvasHostUrl,auth:deviceToken?{deviceToken:deviceToken.token,role:deviceToken.role,scopes:deviceToken.scopes,issuedAtMs:deviceToken.rotatedAtMs??deviceToken.createdAtMs}:void 0,policy:{maxPayload:MAX_PAYLOAD_BYTES,maxBufferedBytes:MAX_BUFFERED_BYTES,tickIntervalMs:TICK_INTERVAL_MS}};clearHandshakeTimer();let nextClient={socket,connect:connectParams,connId,presenceKey,clientIp:reportedClientIp};if(setClient(nextClient),setHandshakeState(`connected`),role===`node`){let context=buildRequestContext(),nodeSession=context.nodeRegistry.register(nextClient,{remoteIp:reportedClientIp}),instanceIdRaw=connectParams.client.instanceId,instanceId=typeof instanceIdRaw==`string`?instanceIdRaw.trim():``,nodeIdsForPairing=new Set([nodeSession.nodeId]);instanceId&&nodeIdsForPairing.add(instanceId);for(let nodeId of nodeIdsForPairing)updatePairedNodeMetadata(nodeId,{lastConnectedAtMs:nodeSession.connectedAtMs}).catch(err=>logGateway.warn(`failed to record last connect for ${nodeId}: ${formatForLog(err)}`));recordRemoteNodeInfo({nodeId:nodeSession.nodeId,displayName:nodeSession.displayName,platform:nodeSession.platform,deviceFamily:nodeSession.deviceFamily,commands:nodeSession.commands,remoteIp:nodeSession.remoteIp}),refreshRemoteNodeBins({nodeId:nodeSession.nodeId,platform:nodeSession.platform,deviceFamily:nodeSession.deviceFamily,commands:nodeSession.commands,cfg:loadConfig()}).catch(err=>logGateway.warn(`remote bin probe failed for ${nodeSession.nodeId}: ${formatForLog(err)}`)),loadVoiceWakeConfig().then(cfg=>{context.nodeRegistry.sendEvent(nodeSession.nodeId,`voicewake.changed`,{triggers:cfg.triggers})}).catch(err=>logGateway.warn(`voicewake snapshot failed for ${nodeSession.nodeId}: ${formatForLog(err)}`))}logWs(`out`,`hello-ok`,{connId,methods:gatewayMethods.length,events:events.length,presence:snapshot.presence.length,stateVersion:snapshot.stateVersion.presence}),send({type:`res`,id:frame.id,ok:!0,payload:helloOk}),refreshGatewayHealthSnapshot({probe:!0}).catch(err=>logHealth.error(`post-connect health refresh failed: ${formatError(err)}`));return}if(!validateRequestFrame(parsed)){send({type:`res`,id:parsed?.id??`invalid`,ok:!1,error:errorShape(ErrorCodes.INVALID_REQUEST,`invalid request frame: ${formatValidationErrors(validateRequestFrame.errors)}`)});return}let req=parsed;logWs(`in`,`req`,{connId,id:req.id,method:req.method});let respond=(ok,payload,error,meta)=>{send({type:`res`,id:req.id,ok,payload,error}),logWs(`out`,`res`,{connId,id:req.id,ok,method:req.method,errorCode:error?.code,errorMessage:error?.message,...meta})};(async()=>{await handleGatewayRequest({req,respond,client,isWebchatConnect,extraHandlers,context:buildRequestContext()})})().catch(err=>{logGateway.error(`request handler failed: ${formatForLog(err)}`),respond(!1,void 0,errorShape(ErrorCodes.UNAVAILABLE,formatForLog(err)))})}catch(err){logGateway.error(`parse/handle error: ${String(err)}`),logWs(`out`,`parse-error`,{connId,error:formatForLog(err)}),getClient()||close()}})}const LOG_HEADER_FORMAT_REGEX=/\p{Cf}/gu;function replaceControlChars(value){let cleaned=``;for(let char of value){let codePoint=char.codePointAt(0);if(codePoint!==void 0&&(codePoint<=31||codePoint>=127&&codePoint<=159)){cleaned+=` `;continue}cleaned+=char}return cleaned}const sanitizeLogValue=value=>{if(!value)return;let cleaned=replaceControlChars(value).replace(LOG_HEADER_FORMAT_REGEX,` `).replace(/\s+/g,` `).trim();if(cleaned)return cleaned.length<=300?cleaned:truncateUtf16Safe(cleaned,300)};function attachGatewayWsConnectionHandler(params){let{wss,clients,port,gatewayHost,canvasHostEnabled,canvasHostServerPort,resolvedAuth,rateLimiter,gatewayMethods,events,logGateway,logHealth,logWsControl,extraHandlers,broadcast,buildRequestContext}=params;wss.on(`connection`,(socket,upgradeReq)=>{let client=null,closed=!1,openedAt=Date.now(),connId=randomUUID(),remoteAddr=socket._socket?.remoteAddress,headerValue=value=>Array.isArray(value)?value[0]:value,requestHost=headerValue(upgradeReq.headers.host),requestOrigin=headerValue(upgradeReq.headers.origin),requestUserAgent=headerValue(upgradeReq.headers[`user-agent`]),forwardedFor=headerValue(upgradeReq.headers[`x-forwarded-for`]),realIp=headerValue(upgradeReq.headers[`x-real-ip`]),canvasHostUrl=resolveCanvasHostUrl({canvasPort:canvasHostServerPort??(canvasHostEnabled?port:void 0),hostOverride:canvasHostServerPort&&gatewayHost&&gatewayHost!==`0.0.0.0`&&gatewayHost!==`::`?gatewayHost:void 0,requestHost:upgradeReq.headers.host,forwardedProto:upgradeReq.headers[`x-forwarded-proto`],localAddress:upgradeReq.socket?.localAddress});logWs(`in`,`open`,{connId,remoteAddr});let handshakeState=`pending`,closeCause,closeMeta={},lastFrameType,lastFrameMethod,lastFrameId,setCloseCause=(cause,meta)=>{closeCause||=cause,meta&&Object.keys(meta).length>0&&(closeMeta={...closeMeta,...meta})},setLastFrameMeta=meta=>{(meta.type||meta.method||meta.id)&&(lastFrameType=meta.type??lastFrameType,lastFrameMethod=meta.method??lastFrameMethod,lastFrameId=meta.id??lastFrameId)},send=obj=>{try{socket.send(JSON.stringify(obj))}catch{}},connectNonce=randomUUID();send({type:`event`,event:`connect.challenge`,payload:{nonce:connectNonce,ts:Date.now()}});let close=(code=1e3,reason)=>{if(!closed){closed=!0,clearTimeout(handshakeTimer),client&&clients.delete(client);try{socket.close(code,reason)}catch{}}};socket.once(`error`,err=>{logWsControl.warn(`error conn=${connId} remote=${remoteAddr??`?`}: ${formatError(err)}`),close()});let isNoisySwiftPmHelperClose=(userAgent,remote)=>!!(userAgent?.toLowerCase().includes(`swiftpm-testing-helper`)&&isLoopbackAddress(remote));socket.once(`close`,(code,reason)=>{let durationMs=Date.now()-openedAt,logForwardedFor=sanitizeLogValue(forwardedFor),logOrigin=sanitizeLogValue(requestOrigin),logHost=sanitizeLogValue(requestHost),logUserAgent=sanitizeLogValue(requestUserAgent),logReason=sanitizeLogValue(reason?.toString()),closeContext={cause:closeCause,handshake:handshakeState,durationMs,lastFrameType,lastFrameMethod,lastFrameId,host:logHost,origin:logOrigin,userAgent:logUserAgent,forwardedFor:logForwardedFor,...closeMeta};if(client||(isNoisySwiftPmHelperClose(requestUserAgent,remoteAddr)?logWsControl.debug:logWsControl.warn)(`closed before connect conn=${connId} remote=${remoteAddr??`?`} fwd=${logForwardedFor||`n/a`} origin=${logOrigin||`n/a`} host=${logHost||`n/a`} ua=${logUserAgent||`n/a`} code=${code??`n/a`} reason=${logReason||`n/a`}`,closeContext),client&&isWebchatClient(client.connect.client)&&logWsControl.info(`webchat disconnected code=${code} reason=${logReason||`n/a`} conn=${connId}`),client?.presenceKey&&(upsertPresence(client.presenceKey,{reason:`disconnect`}),broadcastPresenceSnapshot({broadcast,incrementPresenceVersion,getHealthVersion})),client?.connect?.role===`node`){let context=buildRequestContext(),nodeId=context.nodeRegistry.unregister(connId);nodeId&&(removeRemoteNodeInfo(nodeId),context.nodeUnsubscribeAll(nodeId))}logWs(`out`,`close`,{connId,code,reason:logReason,durationMs,cause:closeCause,handshake:handshakeState,lastFrameType,lastFrameMethod,lastFrameId}),close()});let handshakeTimeoutMs=getHandshakeTimeoutMs(),handshakeTimer=setTimeout(()=>{client||(handshakeState=`failed`,setCloseCause(`handshake-timeout`,{handshakeMs:Date.now()-openedAt}),logWsControl.warn(`handshake timeout conn=${connId} remote=${remoteAddr??`?`}`),close())},handshakeTimeoutMs);attachGatewayWsMessageHandler({socket,upgradeReq,connId,remoteAddr,forwardedFor,realIp,requestHost,requestOrigin,requestUserAgent,canvasHostUrl,connectNonce,resolvedAuth,rateLimiter,gatewayMethods,events,extraHandlers,buildRequestContext,send,close,isClosed:()=>closed,clearHandshakeTimer:()=>clearTimeout(handshakeTimer),getClient:()=>client,setClient:next=>{client=next,clients.add(next)},setHandshakeState:next=>{handshakeState=next},setCloseCause,setLastFrameMeta,logGateway,logHealth,logWsControl})})}function attachGatewayWsHandlers(params){attachGatewayWsConnectionHandler({wss:params.wss,clients:params.clients,port:params.port,gatewayHost:params.gatewayHost,canvasHostEnabled:params.canvasHostEnabled,canvasHostServerPort:params.canvasHostServerPort,resolvedAuth:params.resolvedAuth,rateLimiter:params.rateLimiter,gatewayMethods:params.gatewayMethods,events:params.events,logGateway:params.logGateway,logHealth:params.logHealth,logWsControl:params.logWsControl,extraHandlers:params.extraHandlers,broadcast:params.broadcast,buildRequestContext:()=>params.context})}async function loadGatewayTlsRuntime(cfg,log){return await loadGatewayTlsRuntime$1(cfg,log)}ensureBuilderForceAgentsCliOnPath();const log=createSubsystemLogger(`gateway`),logCanvas=log.child(`canvas`),logDiscovery=log.child(`discovery`),logTailscale=log.child(`tailscale`),logChannels=log.child(`channels`),logBrowser=log.child(`browser`),logHealth=log.child(`health`),logCron=log.child(`cron`),logReload=log.child(`reload`),logHooks=log.child(`hooks`),logPlugins=log.child(`plugins`),logWsControl=log.child(`ws`),gatewayRuntime=runtimeForLogger(log),canvasRuntime=runtimeForLogger(logCanvas);async function startGatewayServer(port=18789,opts={}){let minimalTestGateway=process.env.VITEST===`1`&&process.env.BUILDERFORCE_AGENTS_TEST_MINIMAL_GATEWAY===`1`;process.env.BUILDERFORCE_AGENTS_GATEWAY_PORT=String(port),logAcceptedEnvOption({key:`BUILDERFORCE_AGENTS_RAW_STREAM`,description:`raw stream logging enabled`}),logAcceptedEnvOption({key:`BUILDERFORCE_AGENTS_RAW_STREAM_PATH`,description:`raw stream log path override`});let configSnapshot=await readConfigFileSnapshot();if(configSnapshot.legacyIssues.length>0){if(isNixMode)throw Error(`Legacy config entries detected while running in Nix mode. Update your Nix config to the latest schema and restart.`);let{config:migrated,changes}=migrateLegacyConfig(configSnapshot.parsed);if(!migrated)throw Error(`Legacy config entries detected but auto-migration failed. Run "${formatCliCommand(`builderforce doctor`)}" to migrate.`);await writeConfigFile(migrated),changes.length>0&&log.info(`gateway: migrated legacy config entries:\n${changes.map(entry=>`- ${entry}`).join(`